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

龙哥盟 / 2024-10-13 / 原文

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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

权衡:偏差还是差异

原文:https://towardsdatascience.com/tradeoff-bias-or-variance-1409eec38caf?source=collection_archive---------16-----------------------

Photo by Afif Kusuma on Unsplash

什么是偏差方差权衡?

我从小就喜欢射箭。也许是因为我是一个历史迷,或者是因为这是一项优雅而危险的运动。射箭与偏差和方差权衡有什么关系?

上图展示了一个很好的例子。如果我们想象一个射手射击一个目标,他们击中靶心的能力证明了他们的准确性。然而,能够反复击中靶心向我们展示了精确性。我不知道你怎么想,但如果我在战争中,我会希望我的小队精确无误,能够在不同的场景和环境中多次击中目标,而不是让一个士兵一生中只有一次运气好,击中了靶心。

精确是我们构建和微调模型的目标。

B ias 方差权衡是数据科学家在开发有效和有用的模型时面临的一个非常真实和常见的问题。当谈到偏差方差权衡时,我们只是在谈论我们的模型对看不见的数据执行的灵活性。

等等!在我们前进之前,我们需要知道如何测量偏差和方差。这就是均方差(MSE)发挥作用的时候。

source

MSE 是我们的预测值和真实值之间的均方差。这将为我们提供一种方法来观察我们的模型是具有高方差还是低方差。那么 MSE 如何向我们展示模型是否表现良好呢?当我们的模型表现良好时,我们的 MSE 将会很低,这表明我们的预测非常接近真实值。否则我们的 MSE 会很大,表明我们的预测与真实值不太接近。重要的是要记住 MSE 总是正的,数字越小越好。本质上,我们使用 MSE 来确定模型有效预测未知数据的能力。

偏差和方差

好吧!现在我们已经有了 MSE,让我们来谈谈偏差和方差。

什么是偏见?

B ias 是我们的预测值和真实值之间的平均差值。我们应该将偏差视为准确性,它是指测量值与标准值或已知值的接近程度。这就好比一个弓箭手射中了靶心。虽然这似乎是任何数据科学家都想努力实现的目标,但高偏见实际上可能会伤害我们。它对特定数据的定制非常严格,当处理稍有不同的数据时,它不知道该怎么办。高偏差将导致我们的模型对看不见的数据预测不佳。我们的目标是降低训练数据的偏差,以便我们的模型能够更好地预测其他数据。

什么是方差?

方差是我们模型中的变化量。它表明了我们的模型概括数据的能力。我更愿意将此视为精度,或者两个或多个测量值相互之间的接近程度和频率。偏差是精确的,方差是精确的或能够重复预测分布中的值。

source

权衡

如果我们认为偏差是准确的能力,方差是精确的能力,我们可以保证我们会有一个好的模型。我们这样做的方式被称为偏差方差权衡。我们正在做的是调整我们的模型,使我们的训练数据得分 MSE 接近我们的测试数据得分 MSE。如果在我们的训练或测试数据中,我们有 MSE 值不接近的分数,那么我们需要权衡。当我们说“权衡”时,我们指的是参数调整,我们在偏差和方差之间“交易”。当我们有很多参数时,我们的模型在预测时会变得过于复杂、低效和不精确。当我们减少我们的模型用于生成预测的参数数量,以便我们的训练和测试 MSE 分数将更接近值时,就会出现权衡。然而,我们不希望我们的模型变得过于简单,否则我们最终会得到如上图所示的低偏差高方差的情况。

一个弓箭手想要磨练技能,让他们以最高的效率和效力射箭。然而,射手需要在某些方面做出妥协,才能有效地发挥作用。例如,灵巧和力量是重要的,但是过度补偿其中任何一个都会影响射手反复击中目标的能力。弓箭手想要流畅的拉和放,所以拉弓弦所需的力量就是所有需要的力量。

作为数据科学家,我们必须使用我们的判断和直觉来为我们的模型确定一个可接受的平衡。我们必须在可用的参数中进行选择,这样我们可以降低模型的复杂性,但不会剥夺模型有效执行的能力。因此,在我们的模型中,我们希望平衡参数与它对我们想要预测的值的重要性之间的关系。

TLDR

本文旨在帮助更好地理解什么是偏差和方差权衡,以及为什么它很重要。要吸收的信息很多,但是简短而甜蜜的可以用记住这四个要点来概括。

  • 偏差:模型预测 Y 的好坏
  • 方差:模型概括数据的好坏程度
  • 随着偏差减少,方差增加
  • 调整我们的参数将帮助我们平衡我们的模型分数

美联储会议纪要的交易信号?

原文:https://towardsdatascience.com/trading-signal-from-fed-minutes-4c2def891134?source=collection_archive---------24-----------------------

即使延迟 3 周,美联储会议纪要还能成为交易信号吗?

社交网络情绪以及新闻情绪已经被广泛用于实时驱动市场运动。数十家公司已经建立了用于交易目的的实时情绪分析 feed。然而,我发现在分析美联储 FOMC(联邦公开市场委员会)会议记录时有一个缺口。

背景

FOMC 是美联储中负责直接与市场打交道的部门。当美联储想要实施 QE(量化宽松)时,实际操作的是 FOMC。有了如此强大的支持,市场先生密切关注每次会议的新闻稿也就不足为奇了。然而,“市场先生”对美联储操作的反应最多只有几天,他失去了记忆,转而关注非农就业数据、PMI、GDP 等。

美联储负责两个重要目标

  • 将通货膨胀率保持在目标水平(2%)
  • 最大化就业率

这些目标对经济有长期影响。然后,我开始怀疑 FOMC 会议纪要中的情绪实际上是否对经济有更长期的影响。

FOMC 会议召开后,会产生三个关键文件,会议记录和文字记录。当会议在日结束时,一份声明(2019 年 9 月)发布,这是市场先生对 FOMC 的任何行动/不行动做出反应和调整的时候。三周后,会议纪要( Sep 2019 )发布,包括会议期间的一些关键讨论。而五年后,FOMC 会议的完整抄本(2013 年 12 月)将会发布。

当我看这三份文件时,新闻声明太短,很容易用人工分析。它没有给出为什么得出这个结论的背景。完整的记录是在第一次会议后的 5 年后。考虑到整个经济周期只持续 5 年左右。很难想象它作为交易信号会有多大价值。这让我仔细看了一下会议记录。

把会议记录排好

通过回顾所有会议记录的完整历史,我发现 FOMC 最初的会议记录确实非常短,其中许多会议记录的长度与当前的新闻稿相似。看看这份 1937 年 6 月的 FOMC 会议记录。

早些年,它们只有 PDF 格式,所以我使用 Tika-python(包装 Tesseract OCR)从 PDF 中提取文本。首先,我绘制了所有会议记录的平均字数和平均句子数。会议记录可以追溯到 1936 年,但我发现它提供的信息不多,所以被忽略了。正如我们所见,随着时间的推移,美联储变得非常罗嗦,特别是在 2008 年次贷危机之后。

然后,我使用了一个快速情感分析库 TextBlob 来快速检查它是否随时间波动足够大。根据之前的文本分析经验,专业文章往往在情绪上有小的变化。

在这里,我绘制了每一分钟的原始情绪。我们可以看到,纪要字数在 2500 以下或者 1970 年以前的,情绪是很嘈杂的。我们可以看到,情绪的整体范围很小,在 0.05 和 0.1 之间波动,而整个范围是-1 和 1。在这种原始情绪下,图表非常嘈杂,很难观察到任何总体趋势。因此,我设置了一个 10 分钟的滚动窗口,计算他们的情绪均值。

随着我们消除情绪中的噪音,一些有趣的趋势出现了。我们可以看到一些明显的趋势。1973 年和 1979 年的石油危机已经在市场情绪中得到反映,次贷危机也是如此。

我们可以看到原文中有很多杂音,这是因为与政策无关的文字破坏了统计数据。这可能是会议的与会者名单、投票说明等。因此,我使用了路标,让我们只关注政策文本。(参见黄色高亮部分)

在文本裁剪之后,已经执行了标准的 NLP 预处理工作,如词汇化,这导致情感的更平滑的结果。

装满市场

我用标准普尔 500 作为一般市场的代表,因为它覆盖了广泛的行业,不像道琼斯和纳斯达克。感谢雅虎!金融,我能够加载它的日常历史追溯到 1950 年(部分原因是我从 1950 年开始分析)。

https://www.macrotrends.net/2324/sp-500-historical-chart-data

然而,我们只对任何给定日期后的短期回报感兴趣。最好的替代方法是使用一段时间内每日回报的累积积。下图显示了平滑情绪与过去 200 个交易日(一年大约 250 天)的累计回报。这两者之间似乎有某种关联。

在我们进行进一步的分析之前,我们可能想改变一下我们用来分析金融文本的字典。因为 TextBlob 中包含的模式库主要来源于互联网、新闻和社交网络。它可能不是金融文本分析的最佳库。有一个图书馆叫《拉夫兰和麦克唐纳词典》,是从美国 10K 年度报告中摘录的。在这种情况下,它可能是一个更相关的库,市场之间的相关性与它相符。

为了形象化,我想立刻说出情绪是否与市场相关。此外,我想将市场向前和向后移动,以检查移动后的相关性。这将告诉我信号是领先还是落后于市场。

为了实现这一目标,我们需要将时间序列移动多个步骤,并绘制许多图表,这些图表看起来可能会让人不知所措。

这个助手方法通过将市场来回移动多个步骤并重新计算两个时间序列之间的相关性来解决这个问题。在这样做的同时,我们还计算了它需要的 p 值,以使相关性具有统计显著性。因此,此图结合了三个不同的图表。

  1. 标准普尔 500 回报叠加美联储情绪(上图)
  2. 移动市场 N 步后,标准普尔 500 和美联储情绪之间的相关性(下图蓝色柱线)
  3. 具有统计意义的相关 p 值。如果红色柱高于蓝色柱,这意味着相关性太低,没有统计学意义。(在下面用红色条标出)

在这种特殊情况下,我们可以立即看出,与市场相比,情绪是一个滞后的指标。在市场延迟 5 个周期后,相关性达到稳定。换句话说,会议纪要中的情绪需要大约 6 -7 个月的延迟才能完全适应市场的反应。基于这一点,我们可以说市场确实非常有效。

我们能做得更好吗?

看到情绪不是市场的领先指标,令人非常失望,但并不令人惊讶。让我们拿出 NLP 处理中的一把更大的枪——LDA(潜在狄利克雷分配),主题抽取模型。它允许我们基于单词袋方法提取抽象概念。

最初,我们在文章和它的单词包之间有一个映射。

Can’t remember where I got this from, but it’s really nice illustration!

LDA 允许我们指定我们认为有多少主题。它试图在单词和我们的文章之间插入一个额外的层,以降低文章和单词之间的连接复杂性。

因此,这创造了一些抽象的概念,将相关的单词分组到主题中。这些主题中的每一个都可以计算为不同单词的权重之和。例如,主题可以表述为:

0.047“利率”+ 0.024“市场”+ 0.016“期限”+ 0.015“下降”+ 0.015“国库券”+ 0.014“利息”

现在的问题变成了,我如何决定我应该使用多少主题。虽然 LDA 能够创建主题,但它并不真正了解每个主题是关于什么的。在这里,我使用 pyLDAvis 库来可视化主题建模结果,减少不同主题之间的重叠,试图拥有一个相同大小的主题。经过几次反复试验和错误,我选定了一个看起来像这样的模型。

最后,我让 LDA 创建了 6 个不同的主题,因为它有一个相对均等的主题分布和大部分重叠的主题。然而,这仍然没有解决知道每个主题是关于什么的问题。

为此,我打印出了每个主题排名靠前的句子,并试图了解这个主题试图描述的内容。

主题 1:

Short-term market interest rates declined substantially on balance  over the meeting interval: in private short-term markets, yields fell 2 to 3-1/2 percentage points; in the Treasury bill market, yields fell some what less, about 3/4 to 2 percentage points, as the Treasury raised large  amounts of new money through bill auctions and heavy seasonal issuance of  cash management bills.

话题 2:

M1 comprises demand deposits at commercial banks and thrift institutions, currency in circulation, travellers checks, negotiable orders of withdrawal (NOW) and automatic transfer service (ATS) accounts at banks and thrift institutions, and credit union share draft accounts.

通过对所有主题进行这一练习,我已经给出了主题的名称,并打印出了它们的前 10 个关键词。

斗牛中的最后一剑

最后,我们已经到了可以将每个主题中的情绪与市场相对照的地步。

对于利率,很难看出情绪和市场之间有多大的相关性,但感觉利率情绪的重大转变将导致市场大幅波动,但方向不太清楚。因为相关性在 2000 年之后似乎是正的,但在 2000 年之前是负相关的。

就经济前景而言,这种情绪肯定与市场走势存在一定的相关性。然而,随着时间的推移,它不是很稳定,有时它领先市场,有时它滞后。但相关性似乎在 0 个周期后趋于平稳,即总体上滞后于市场。

就 FOMC 政策而言,这看起来很像一个经济前景话题。它并没有明确指出信号是超前还是滞后。

随着国际贸易和劳动力/国内市场,情绪肯定落后于市场。这种相关性表明,市场的全面影响只是在大约 7 次会议之后,即在将近一年的延迟之后,才完全反映在市场情绪中。这可能是由于我在情感分析中使用的平滑操作。我已经在 10 次会议上缓和了这种情绪。

最有趣的图表是货币供应话题。它与市场有微弱但有意义的负相关性,在市场情绪开始赶上趋势之前的 3 次会议。即使在过去 10 次会议中情绪平稳后,这一领先信号仍然有效。我相信这是一个事实,公开市场操作是一个持续的过程,超越了市场先生的记忆广度。因此,在接下来的几个月里,市场并没有完全消化后续操作。

希望这项工作能给你带来一些如何进行情感或一般文本分析的想法。欢迎在下面留言或直接联系我。

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

用 Python 构建金融交易工具箱:简单移动平均线

原文:https://towardsdatascience.com/trading-toolbox-01-sma-7b8e16bd9388?source=collection_archive---------6-----------------------

交易工具箱

Photo by Markus Spiske on Unsplash

Python 凭借其强大的数据分析包熊猫,席卷了金融市场分析领域。它使研究人员能够进行复杂的分析,而这曾经需要专用的昂贵的软件包。

在这篇文章中,我们将使用 Python 和熊猫涉水金融市场分析。我们将绘制一个市场价格序列,并添加一个基本指标。在接下来的文章中,我们将通过构建一个完整的工具箱来学习如何游泳,这个工具箱可以用来创建交易股票或其他金融资产的系统。

我们将要实现的大多数概念属于一个被称为技术分析的领域,这是一个旨在通过分析交易活动产生的数据(如价格和交易量)来评估投资和识别机会的学科。

介绍移动平均线

移动平均线是最简单的技术指标之一,但它可以以许多不同的方式使用和组合,为交易系统和投资决策框架提供支柱。

移动平均线,作为所有的技术指标,是基于金融工具的价格序列。在我们的例子中,我们考虑在纽约证券交易所交易的交易所交易基金 (ETF)的 SPDR 的& P 500 ETF 信托(代码:SPY)的每日价格序列。这只 ETF 模仿了标准普尔 500 指数的表现。我们希望使用移动平均线来做出投资决策——决定何时买入或卖出 SPY 的股票。

有不同种类的移动平均线。最常用的三种是:

  • 简单移动平均线
  • 线性加权移动平均
  • 指数平滑移动平均

本帖中的例子将集中在简单移动平均线(SMA) 。它的构造非常简单:我们首先定义一个长度为 n 的滚动窗口(在我们的例子中是几天——让我们使用 n=5 )。然后,我们从第 5 天开始,考虑从第 1 天到第 5 天(包括在内)的所有价格。我们计算这些价格的算术平均值(将它们相加并除以 5):这就是第 5 天的 SMA 值。然后,我们继续到第 6 天,我们取出第 1 天的价格,包括第 6 天的价格,并计算下一个 SMA。我们不断重复这个过程,直到我们达到系列中的最后一个价格。参见表格:

您已经注意到我们的移动平均线的前 4 个值没有被计算:直到第 5 天才有足够的天数来填充 5 天的窗口。

直观的例子

让我们将这个概念付诸实践,并使用 Python、 pandas 和 Matplotlib 创建一些实际的例子。我假设您至少有一些基本的 Python 知识,并且知道什么是数据帧和序列对象。如果不是这样,你可以在这里找到温柔的介绍。我还建议你用一个笔记本来跟随下面的代码。在这里你可以找到一个方便的 Jupyter 教程。但是,您总是以自己喜欢的方式执行代码,通过 IDE 或交互式提示符。我们首先加载所需的库并检查它们的版本:

import pandas as pd
import matplotlib.pyplot as plt

如果您正在使用 Jupyter ,最好在笔记本中显示图表:

%matplotlib inline

在这种情况下,你可以省略本文所有代码中的所有plt.show()语句。

接下来,我们将数据加载到数据帧中。我已经从雅虎获得了一个每日间谍数据的 CSV 文件。财务。你可以在这里下载我的 CSV 文件。

datafile = 'data/SPY.csv'#This creates a dataframe from the CSV file:
data = pd.read_csv(datafile, index_col = 'Date')data

Jupyter 中的输出显示了我们的数据:

我们的数据框架总共有六列,分别代表开盘价、最高价、最低价、收盘价、调整后收盘价和成交量。为了简单起见,在我们的例子中,我们将只使用调整后的收盘价。这是反映股息、股票分割和其他影响股票回报的公司事件的价格系列。

#This selects the 'Adj Close' column
close = data['Adj Close']#This converts the date strings in the index into pandas datetime format:
close.index = pd.to_datetime(close.index)close

输出:

Date
2014-08-20    180.141846
2014-08-21    180.667160
2014-08-22    180.386368
2014-08-25    181.301010
2014-08-26    181.418716
                 ...    
2019-08-13    292.549988
2019-08-14    283.899994
2019-08-15    284.649994
2019-08-16    288.850006
2019-08-19    292.329987
Name: Adj Close, Length: 1258, dtype: float64

我们可以很容易地绘制价格系列,以便直观地观察:

close.plot()plt.show()

如果你正在使用 Jupyter ,记住你可以在这里和下一行代码中删除plt.show()行。我们得到:

close.plot() output in Jupyter

熊猫让计算 50 天移动平均线变得容易。使用滚动()方法,我们设置了一个 50 天的窗口,在此窗口上,我们使用均值()方法计算算术平均值:

sma50 = close.rolling(window=50).mean()sma50

我们得到:

Date
2014-08-20           NaN
2014-08-21           NaN
2014-08-22           NaN
2014-08-25           NaN
2014-08-26           NaN
                 ...    
2019-08-13    293.540820
2019-08-14    293.635375
2019-08-15    293.696567
2019-08-16    293.805137
2019-08-19    293.926582
Name: Adj Close, Length: 1258, dtype: float64

正如我们所料,序列的前 49 个值为空:

sma50.iloc[45:52]

显示:

Date
2014-10-23           NaN
2014-10-24           NaN
2014-10-27           NaN
2014-10-28           NaN
2014-10-29    178.725250
2014-10-30    178.750461
2014-10-31    178.806655
Name: Adj Close, dtype: float64

我们现在可以在图表上画出我们的第一条均线。为了改善外观,我们可以使用预定义的样式:

plt.style.use('fivethirtyeight')

你可以尝试不同的风格,看看这里有什么。我们现在可以绘制图表了:

#The size for our chart:
plt.figure(figsize = (12,6))#Plotting price and SMA lines:
plt.plot(close, label='SPY Adj Close', linewidth = 2)
plt.plot(sma50, label='50 day rolling SMA', linewidth = 1.5)#Adding title and labeles on the axes, making legend visible:
plt.xlabel('Date')
plt.ylabel('Adjusted closing price ($)')
plt.title('Price with a single Simple Moving Average')
plt.legend()plt.show()

这是我们的移动平均线与价格的关系图:

使用一个移动平均线

我们的简单移动平均线做得很好,它平滑了价格运动,帮助我们直观地识别趋势:当平均线向上攀升时,我们有上升趋势。当均线向下时,我们处于下跌趋势。

我们能做的不止这些:用一条均线就能产生交易信号。当收盘价从下方移动到均线上方时,我们有买入信号:

同样,当价格从上方穿过移动平均线时,就会产生卖出信号:

绘制两个平均值并选择日期范围

让我们比较两个不同长度的移动平均线,分别是 20 天和 50 天:

sma20 = close.rolling(window=20).mean()plt.figure(figsize = (12,6))#Plotting price with two SMAs:
plt.plot(close, label='SPY Adj Close', linewidth = 2)
plt.plot(sma20, label='20 day rolling SMA', linewidth = 1.5)
plt.plot(sma50, label='50 day rolling SMA', linewidth = 1.5)plt.xlabel('Date')
plt.ylabel('Adjusted closing price ($)')
plt.title('Price with Two Simple Moving Averages')
plt.legend()plt.show()

我们的图表现在变得有点拥挤:如果能够放大我们选择的日期范围就好了。我们可以使用一个 plt.xlim() 指令(例如plt.xlim('2017-01-01','2018-12-31'):试着把它添加到上面的代码中)。然而,我想探索一条不同的路线:建立一个新的数据框架,包括价格和移动平均线:

priceSma_df = pd.DataFrame({
      'Adj Close' : close,
      'SMA 20' : sma20,
      'SMA 50' : sma50
     })priceSma_df

将我们的所有系列放在一个数据框架中,可以轻松创建快照图:

priceSma_df.plot()plt.show()

虽然使用 dataframe own plot() 方法创建一个 snap plot 很方便,但是我更喜欢使用单独的函数调用来定制我的图表。将我们的所有系列放在一个数据框架中的另一个好处是,我们可以轻松选择一个日期范围(例如,包括 2017 年和 2018 年的日期)并仅绘制该范围内的数据:

plt.figure(figsize = (12,6))#Plotting price and two SMAs with a specified date range:
plt.plot(priceSma_df['2017':'2018']['Adj Close'], label='SPY Adj Close', linewidth = 2)
plt.plot(priceSma_df['2017':'2018']['SMA 20'], label='20 days rolling SMA', linewidth = 1.5)
plt.plot(priceSma_df['2017':'2018']['SMA 50'], label='50 days rolling SMA', linewidth = 1.5)plt.xlabel('Date')
plt.ylabel('Adjusted closing price ($)')
plt.title('Price with Two Simple Moving Averages - Selected Date Range')
plt.legend()plt.show()

Dates between 2017 and 2018 included

按日期范围对数据进行切片是 pandas 的一大特色。以下所有语句都有效:

  • priceSma_df['2017-04-01':'2017-06-15']:由两个特定日期定义的范围
  • priceSma_df['2017-01]:某月价格
  • priceSma_df['2017]:某一年的价格

使用两个移动平均线

通过合并两条均线,我们可以使用一种叫做双交叉法的技术。在这种情况下,只要短均线从下方穿过长均线,就会产生买入信号。类似地,当短均线从上方穿过长均线时,就会产生卖出信号:

Trading signals with two SMAs

与只使用一条均线和价格的技术相比,双交叉方法产生的拉锯更少。另一方面,它可以产生具有一定延迟的信号。

使用三条移动平均线

如果我们可以一起使用两条均线,为什么不可以用三条呢?

sma200 = close.rolling(window=200).mean()priceSma_df['SMA 200'] = sma200priceSma_df

#Our start and end dates:
start = '2016'
end = '2019'plt.figure(figsize = (12,6))#Plotting price and three SMAs with start and end dates:
plt.plot(priceSma_df[start:end]['Adj Close'], label='SPY Adj Close', linewidth = 2)
plt.plot(priceSma_df[start:end]['SMA 20'], label='20 day rolling SMA', linewidth = 1.5)
plt.plot(priceSma_df[start:end]['SMA 50'], label='50 day rolling SMA', linewidth = 1.5)
plt.plot(priceSma_df[start:end]['SMA 200'], label='200 day rolling SMA', linewidth = 1.5)plt.xlabel('Date')
plt.ylabel('Adjusted closing price ($)')
plt.title('Price with Three Simple Moving Averages')
plt.legend()plt.show()

Three SMAs — dates from 2016 to 2018 included

你可以看到长期 200 SMA 如何帮助我们以一种非常平稳的方式识别趋势。

这就给我们带来了三重交叉法。我们使用的移动平均线的长度分别为 20、50 和 200 天,在分析师中广泛使用。当 20 日均线从下方穿过 50 日均线时,我们可以选择考虑买入信号,但只有当两条均线都在 200 日均线上方时。所有出现在 200 均线以下的买入交叉都将被忽略。

Crosses above the 200 SMAs

A cross below the 200 SMAs

本文中的例子只是结合不同长度的价格和移动平均线产生的许多可能性中的一部分。此外,价格和移动平均线可以与其他可用的技术指标或我们可以自己创建的指标相结合。Python 和 pandas 提供了研究和构建盈利交易系统所需的所有能力和灵活性。

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

Python 交易工具箱:加权和指数移动平均线

原文:https://towardsdatascience.com/trading-toolbox-02-wma-ema-62c22205e2a9?source=collection_archive---------1-----------------------

交易工具箱

Photo by M. B. M. on Unsplash

在金融交易工具箱系列的第一篇文章(用 Python 构建金融交易工具箱:简单移动平均线)中,我们讨论了如何计算简单移动平均线,将其添加到价格系列图中,并将其用于投资和交易决策。简单移动平均线只是几种移动平均线中的一种,可以应用于价格序列来建立交易系统或投资决策框架。其中,金融市场中常用的另外两种移动平均线是:

  • 加权移动平均( WMA )
  • 指数移动平均线(均线)

在本文中,我们将探讨如何计算这两个平均值,以及如何确保结果与我们需要实现的定义相匹配。

加权移动平均

在某些应用中,简单移动平均线的一个限制是,它对窗口中包含的每个每日价格给予相同的权重。例如,在 10 天移动平均线中,最近的一天接收与窗口中的第一天相同的权重:每个价格接收 10%的权重。

与简单移动平均线相比,线性加权移动平均线(或简称为加权移动平均线、 WMA ),给予最近价格的权重更大,随着时间的推移逐渐减小。在 10 天加权平均中,第 10 天的价格乘以 10,第 9 天乘以 9,第 8 天乘以 8,以此类推。总数将除以权重的总和(在本例中为:55)。在这个特定的例子中,最近的价格获得总权重的大约 18.2%,第二个最近的价格获得 16.4%,等等,直到窗口中最早的价格获得权重的 0.02%。

让我们用 Python 中的一个例子来实践这一点。除了 pandas 和 Matplotlib,我们还将使用 NumPy:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

我们为图表应用一种样式。如果你正在使用 Jupyter ,添加%matplotlib inline指令是个好主意(在创建图表时跳过plt.show()):

plt.style.use('fivethirtyeight')

在接下来的例子中,我们将使用来自StockCharts.com 文章的价格数据。这是一篇关于均线的优秀教育文章,我推荐阅读。那篇文章中使用的价格序列可以属于任何股票或金融工具,并且将服务于我们的说明目的。

我修改了原始的 Excel 表格,加入了 10 天 WMA 的计算,因为已经包含了均线的计算。您可以访问我的 Google Sheets 文件并在此下载 CSV 格式的数据。

在对数据建模时,从模型的简单实现开始总是一个好的做法,我们可以用它来确保最终实现的结果是正确的。

我们首先将数据加载到数据框中:

datafile = 'cs-movavg.csv'data = pd.read_csv(datafile, index_col = 'Date')
data.index = pd.to_datetime(data.index)# We can drop the old index column:
data = data.drop(columns='Unnamed: 0')data

我们现在只考虑价格和 10 天 WMA 柱,以后再看均线。

当谈到线性加权移动平均线时, pandas 库没有现成的方法来计算它们。然而,它提供了一个非常强大和灵活的方法:.apply()这个方法允许我们创建任何自定义函数并将其传递给一个滚动窗口:这就是我们将如何计算我们的加权移动平均值。为了计算 10 天 WMA ,我们首先创建一个权重数组——从 1 到 10 的整数:

weights = np.arange(1,11) #this creates an array with integers 1 to 10 includedweights

看起来像是:

array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

接下来,使用.apply()方法,我们通过自己的函数(a lambda 函数)计算滚动窗口中权重和价格的 点积 (窗口中的价格将乘以相应的权重,然后求和),然后除以权重之和:

wma10 = data['Price'].rolling(10).apply(lambda prices: np.dot(prices, weights)/weights.sum(), raw=True)wma10.head(20)

这给出了:

现在,我们想将我们的 WMA 与通过电子表格获得的进行比较。为此,我们可以在数据框中添加一个‘我们的 10 天 WMA’列。为了便于直观比较,我们可以使用 NumPy 的.round()方法将 WMA 级数四舍五入到三位小数。然后,我们选择要显示的价格和 WMA 列:

data['Our 10-day WMA'] = np.round(wma10, decimals=3)data[['Price', '10-day WMA', 'Our 10-day WMA']].head(20)

显示:

这两根 WMA 柱子看起来一样。第三位小数有一些差异,但我们可以将其归因于舍入误差,并得出结论,我们的 WMA 实现是正确的。在实际应用中,如果我们想要更严格,我们应该计算两列之间的差异,并检查它们是否太大。现在,我们保持事情简单,我们可以满足于视觉检查。

在剧情中比较我们新创造的 WMA 和熟悉的 SMA 会很有趣:

sma10 = data['Price'].rolling(10).mean()plt.figure(figsize = (12,6))plt.plot(data['Price'], label="Price")
plt.plot(wma10, label="10-Day WMA")
plt.plot(sma10, label="10-Day SMA")plt.xlabel("Date")
plt.ylabel("Price")
plt.legend()plt.show()

这表明:

正如我们所看到的,这两个平均值平滑了价格运动。WMA 比 SMA 更具反应性,更贴近价格:我们预计,因为 WMA 更重视最近的价格观察。此外,两个移动平均线系列都从第 10 天开始:第一天有足够的可用数据来计算平均值。

加权移动平均线可能不如它的指数兄弟那样为人所知。然而,当我们试图构建原创解决方案时,它可能是我们工具箱中的一个额外项目。在 Python 中实现 WMA 迫使我们寻找一种使用.apply()创建定制移动平均线的方法:这种技术也可以用于实现新的和原始的移动平均线。

指数移动平均线

与加权移动平均线类似,指数移动平均线( EMA )赋予最近的价格观察值更大的权重。虽然它对过去的数据赋予较小的权重,但它是基于一个递归公式,该公式在其计算中包括我们价格系列中所有过去的数据。

时间 t 的均线计算方法是当前价格乘以平滑因子 alpha (小于 1 的正数)加上𝑡−1 时间的均线乘以 1 减去 alpha 。它基本上是介于之前的均线和当前价格之间的一个值:

平滑因子𝛼(α)定义为:

其中𝑛是我们跨度中的天数。因此, 10 日均线会有一个平滑因子:

Pandas 包含了一个计算任意时间序列的均线移动平均线的方法:[.ewm()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html).这个方法会满足我们的需求并计算出符合我们定义的平均值吗?让我们来测试一下:

ema10 = data['Price'].ewm(span=10).mean()ema10.head(10)

这给出了:

我们想将这个 EMA 系列与电子表格中的相比较:

data['Our 10-day EMA'] = np.round(ema10, decimals=3)data[['Price', '10-day EMA', 'Our 10-day EMA']].head(20)

结果是:

正如你已经注意到的,我们这里有一个问题:我们刚刚计算的 10 天均线和下载的电子表格中计算的不一致。一个从第 10 天开始,另一个从第 1 天开始。此外,这些值并不完全匹配。

我们的计算错了吗?还是提供的电子表格中的计算有误?都不是:这两个系列对应着两种不同的均线定义。更具体地说,用来计算均线的公式是一样的。改变的只是初始值的使用。

如果我们仔细看看 StockCharts.com网页上的指数移动平均线的定义,我们可以注意到一个重要的细节:他们在第 10 天开始计算 10 天移动平均线,忽略前几天,并用其 10 天移动平均线替换第 10 天的价格。这与我们直接使用.ewm()方法计算均线时使用的定义不同。

以下代码行创建了一个新的修改后的价格序列,其中前 9 个价格(当 SMA 不可用时)被替换为 NaN ,第 10 个日期的价格成为其 10 天 SMA:

modPrice = data['Price'].copy()
modPrice.iloc[0:10] = sma10[0:10]modPrice.head(20)

我们可以用这个修改后的价格序列来计算第二版的 EWM。通过查看文档,我们可以注意到.ewm()方法有一个调整参数,默认为。该参数调整权重以考虑开始期间的不平衡(如果您需要更多详细信息,请参见 熊猫文档中的指数加权窗口部分)。

如果我们想用修改后的价格序列模拟电子表格中的均线,我们不需要这个调整。我们接着设定adjust=False:

ema10alt = modPrice.ewm(span=10, adjust=False).mean()

这个新计算的均线会和电子表格中计算的一致吗?让我们来看看:

data['Our 2nd 10-Day EMA'] = np.round(ema10alt, decimals=3)data[['Price', '10-day EMA', 'Our 10-day EMA', 'Our 2nd 10-Day EMA']].head(20)

现在,我们做得好多了。我们得到了一个与电子表格中计算的相匹配的均线序列。

我们最终得到了两个不同版本的 EMA:

  1. ema10:这个版本使用简单的.ewm()方法,从我们的价格历史开始,但不符合电子表格中使用的定义。
  2. ema10alt:这个版本从第 10 天开始(初始值等于 10 天的 SMA),符合我们电子表格上的定义。

哪个最好用?答案是:这取决于我们的应用程序和构建我们的系统需要什么。如果我们需要一个从第一天开始的均线系列,那么我们应该选择第一个。另一方面,如果我们需要将我们的平均值与其他没有初始日值的平均值(如 SMA)结合使用,那么第二种方法可能是最好的。

第二种 EMA 在金融市场分析师中广泛使用:如果我们需要实现一个已经存在的系统,我们需要小心使用正确的定义。否则,结果可能不是我们所期望的,并可能使我们所有工作的准确性受到质疑。在任何情况下,这两个平均值之间的数字差异都很小,对我们交易或投资决策系统的影响仅限于最初几天。

让我们来看看迄今为止图表中使用的所有移动平均线:

plt.figure(figsize = (12,6))plt.plot(data['Price'], label="Price")
plt.plot(wma10, label="10-Day WMA")
plt.plot(sma10, label="10-Day SMA")
plt.plot(ema10, label="10-Day EMA-1")
plt.plot(ema10alt, label="10-Day EMA-2")plt.xlabel("Date")
plt.ylabel("Price")
plt.legend()plt.show()

在所有均线中, WMA 似乎反应更快,价格贴得更近,而 SMA 反应更滞后。两个版本的均线往往会重叠,主要是在最后几天。

我希望这篇文章对你有用。引入加权移动平均有助于我们学习和实现基于特定定义的自定义平均。使用指数移动平均线让我们有机会强调,确保我们用来处理价格序列的任何函数与我们对任何给定任务的定义相匹配是多么重要。

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

传统人工智能与现代人工智能。

原文:https://towardsdatascience.com/traditional-ai-vs-modern-ai-5117b469a0c9?source=collection_archive---------9-----------------------

人工智能的进化和“未来人工智能”的新浪潮。

source shutterstock.com

今天的 AI

毫无疑问,今天最大的流行语是人工智能或 AI。包括 Gartner、麦肯锡和普华永道在内的大多数知名研究机构都用令人惊叹的统计数据和未来预测美化了人工智能的未来。这里是普华永道的报告(2018),其中预测到 2030 年,人工智能将为全球经济贡献 15.7 万亿美元。总体生产率& GDP 将分别增长 55%和 14%。正如美国总统唐纳德·j·特朗普签署的那样,这项行政命令可以迅速证明人工智能在美国的重要性。

source

“齐心协力,我们可以利用世界上最具创新性的技术,让我们的政府更好地为美国人民服务。”
迈克尔·克拉特西奥斯
美国首席技术官(
来源 )

我们在日常生活中有几个例子,我们甚至没有注意到就利用了人工智能。这包括谷歌地图、Gmail 中的智能回复(2018+)、facebook 图片标签(2015 年左右)、youtube/ 网飞视频推荐(2016+)等。也有一些惊人的新闻报道概述了人工智能的意义和范围;像这个 (2019)诺瓦克·德约科维奇在温网决赛中使用人工智能,或者看看这个网站(2019 年推出)100%假的图片,看起来 100%真实的人利用深度神经网络(深度学习)。这个清单还在继续。

传统人工智能(1950 年至 2008 年)

“人工智能”一词是 1956 年在达特茅斯的一次历史性会议上创造的。在人工智能发展的早期阶段,科学家和媒体炒作围绕人工智能突破的可能性提出了乌托邦式的主张。一些科学家明确表示,在未来 20 年内,机器将做人类可能做的一切事情做的事情。

“人类能做的任何工作,机器都能做。”

1965 年——赫伯特·西蒙

70 years history of AI by Awais Bajwa

自那以后,人工智能的发展经历了许多起伏。1973 年,英国政府在调查后发表了一份名为 Lighthill report 的报告,并查封了许多主要人工智能研究大学的资金。当时突出的人工智能方法是专家系统和模糊逻辑,Prolog 和 Lisp 是 C/C++中编程语言的首选。专家系统的第一次重大突破发生在 80 年代,第一个杰出的专家系统 SID 问世了。后来,在人工智能领域出现了一些其他的挫折,随后是 IBM 的另一个突破,它的超级计算机“深蓝”在 1997 年的纽约市打败了世界冠军加里·卡斯帕罗夫。由于人工智能的概念在当时被视为失败,IBM 声称它没有在深蓝中使用人工智能,这引起了一些有趣的讨论。

请注意,所有的突破都发生在过去的 8-10 年里。反向传播算法是深度学习/神经网络的核心,于 1986 年首次推出。问题是“为什么在过去的 8-10 年(即 2009-2019 年)里,AI 已经存在了 70 多年?”。

为了得到答案,让我们跳到当前的“现代人工智能”时代。

现代人工智能 (2008+)

“数据科学”这个术语是 Linkedin &脸书的两位数据团队领导在 2008 年初创造的。( DJ 帕特尔 & 杰夫哈默巴赫)。计算机科学的这个新领域引入了高级分析,利用了统计学、概率、线性代数&多元微积分。2012 年末,人工智能领域出现了真正的突破,在一场历史性的 ImageNet 竞赛中,一个基于 CNN 的名为 AlexNet 的提交作品远远超过了所有其他竞争对手,错误率比亚军低 10.8 %。这是现代人工智能的到来,并被认为是人工智能世界新一轮繁荣的触发器。获胜的一个主要原因是利用图形处理单元 (GPU) 来训练神经网络架构。2015 年晚些时候,脸书的人工智能领袖 Yann LeCun 与其他“人工智能教父”一起努力推动深度学习及其可能性今天,多家云供应商正在为“现代人工智能”提供基于云的 GPU,而在更早的时候,他们的采用从来都不是一个选项。

GPU 从 CPU 到 GPU 的转换确实改变了游戏。它革新了技术,重新定义了计算能力和并行处理。由于高级数学计算,AI 需要高速计算能力。尤其是因为在过去的十年中,生成的数据量呈指数级增长。

因此,全世界的人工智能研究呈指数增长,在撰写本文时,人工智能研究论文的数量约为 100 篇/天

因此,我们对之前的问题有了答案:

"为什么在 AI 已经存在 70 多年的最近 8-10 年(即 2009-2019 年)里?”。

答案:数据的巨大增长,更快更便宜的处理“GPU”,以及快节奏的人工智能研究。

source

未来的人工智能浪潮

谷歌很仁慈,让员工把 20%的时间分配在自己的抱负和好玩的项目上。2015 年,谷歌搜索过滤器团队的成员亚历山大·莫尔德温采夫(Alexander Mordvintsev)开发了一个神经网络程序,作为一种爱好,它以梦幻般的迷幻外观震惊了他的同事。而这个项目被 Google 命名为深梦。这个项目是实验的结果,同时训练一个神经网络,并在一定范围内发挥激活功能。但即使在今天,人工智能最大的一个谜是,我们没有真正理解人工智能在内部做出决策的准确性,或者神经网络如何在 back-pro p 中学习推理。用外行人的话说,人工智能的实际推理或做出决策的偏好是一个谜,它被称为“人工智能的黑箱”

XAI

人工智能努力的新浪潮之一是打破这个黑箱,并获得决策过程的逻辑解释。这个新概念现在被称为“可解释的人工智能”或“XAI”。一旦 XAI 成功,人工智能社区将迎来新一轮人工智能浪潮。更强大和更有弹性的人工智能框架将成为可能,包括对人工智能过程和未来增长模式的可预测理解。

小数据

主要的人工智能突破正在深度学习领域发生,在深度学习中,神经网络对海量数据有着超级渴望。例如,为了训练一个模型来识别一只猫,需要输入大约 10 万张猫/非猫图像,以获得与人眼大致相当的猫的完美分类。另一个正在迅速发展的研究领域是用更少的数据集快速学习,并利用概率框架。这个新概念被称为“小数据”研究领域是“如何用更少量的数据训练你的机器学习模型,并得到准确的预测。”在人工智能领域,这是一个巨大的机会,预计将带来未来创新的前景。

未来人工智能研究的另外两个领域是在“无监督学习”“****强化学习领域取得重大进展。”我们可以通过迁移学习利用现有知识,并通过一些强化学习生成人工创建的采样数据,例如通过 GAN 网络模型。

关键要点

传统人工智能理论上已经有 70 年的历史了,但在过去的 8-10 年里已经获得了巨大的发展势头(现代人工智能)。这些现代人工智能突破促进了数据的指数级增长、快速研究和云上“按需付费”模式的廉价计算能力。

未来的 AI 浪潮是打破“AI 黑箱”,理解机器学习模型做出的决策和预测的推理。未来人工智能浪潮的另一个主要领域是从有限的数据集或“小数据”中学习。

感谢您阅读本文,希望对您有所帮助。请随时分享您的反馈,并提出您可能有的任何问题。我的 LinkedIn:Awais Bajwa

纽约市的交通事故——线性回归研究

原文:https://towardsdatascience.com/traffic-accidents-in-new-york-city-a-linear-regression-study-3af7159ef088?source=collection_archive---------25-----------------------

Photo by Phil Hauser on Unsplash

问题陈述

纽约市是美国最大的城市,也是世界第 28 大城市,人口约 860 万。这些人口加上每年超过 6000 英里的道路和大量的游客,确保了具有挑战性的交通状况。作为纽约市的一名司机,知道什么时候最有可能发生车祸是有益的,这样你就可以尽量避免在那个时候开车。这个时间是在上午还是下午的高峰时间?深夜还是凌晨?或者说,一天中的时间和交通事故之间没有真正的相关性吗?

数据争论

为了回答这些问题,这个项目利用了两个数据集,都可以从纽约市数据仓库获得。第一个是 NYPD 机动车碰撞-碰撞数据集,该数据集由 158 万行数据组成,详细说明了日期、时间、位置(街道名称、交叉街道和经纬度坐标)、成因、事故中涉及的车辆类型和数量以及受伤人数。

[## 机动车碰撞事故|纽约市公开数据

编辑描述

data.cityofnewyork.us](https://data.cityofnewyork.us/Public-Safety/NYPD-Motor-Vehicle-Collisions-Crashes/h9gi-nx95)

Format of the minimally processed accident DataFrame

第二个数据集是交通量计数(2014–2018)数据集。该数据集包含位置、交通方向和每小时记录的车辆数量。

[## 交通量统计(2014-2018) |纽约市开放数据

编辑描述

data.cityofnewyork.us](https://data.cityofnewyork.us/Transportation/Traffic-Volume-Counts-2014-2018-/ertz-hr4r)

Format of the minimally processed traffic volume DataFrame

在这项研究中。我们要问的问题广泛涉及整个纽约的所有事故,因此不需要事故的具体地点或车辆数量。我们将转换和汇总事故(和计数),给出每小时的计数。事故数据集中的每个条目都与一个事故有关,因此我们可以按日期和时间进行排序,并将它们聚合起来以获得计数。交通量数据已经按小时和天进行了分类,我们只需对这些特征进行分类,并对所有不同道路的观测数据进行计数。

体积数据

通过上面的链接下载的. csv 文件中的体积数据被导入到 pandas 数据帧中。这些数据是以杂乱的格式提供的——每个小时都是包含计数的单独一列。单独的小时列被合并成一个时间列,每个时间跨度减少到一个小时,表示小时窗口的开始。

Final format of the traffic volume DataFrame. All data has been aggregated by hour

因为我们对全市的交通感兴趣,所以每天和每个小时都被聚合起来,以提供一个包含日期、时间和车辆数量的新数据帧。这是之前使用的数据集。

Average traffic volume for each hour across the entire dataset showing a peak in traffic volume at 8 am and again at 5pm, corresponding to morning and evening rush hours

事故数据

事故数据被导入,列标题以类似于体积数据的方式转换。数据集中的每条线代表向 NYPD 报告的事故的时间和位置。

Time course of the total number of accidents per month

通过按日期和小时分组并对结果行进行计数,生成了一个新的数据帧。这给出了与交通量数据格式相似的数据帧:交通量;日期;小时;和事故计数。

探索性数据分析

体积数据

对体积数据的初步研究表明,值> 0 的计数非常稀少,这在原始数据格式中并不明显。大约 73%的条目是 0 值。当排除所有 0 值时,计数直方图显示最小的箱包含最多的计数。每个聚类的开始日期和结束日期是通过遍历日期并检查计数是否存在来确定的。一旦定义了日期区域,超过每天 25,000 次计数的任意阈值的值将被复制到新的数据帧中。这提供了 7,944 个交通量数据点用于与交通事故数据相结合。

Time course of the number of counts over time. Regions of high counts are separated by low or zero count periods. The orange line corresponds to the threshold that was set for data that was used in this study

绘制每天的小时计数显示了双峰分布,这是可以预期的,因为交通流量通常在每天早晚高峰时达到两次峰值。

事故数据

事故数据也按日期和时间分组,并创建一个新的数据框架,记录日期和时间,包括记录的事故数量。绘制这些数据会导致与交通量数据有些相似的双峰分布。

既然我们已经以我们想要的形式获得了两个数据集,我们就可以使用两个数据集都有计数数据的所有日期和时间。体积数据是限制数据,并且基于阈值选择以提供 7,944 个数据点。为了获得相应小时的体积数据的事故数据,我们执行了体积数据与事故数据的内部合并,只保留包含匹配日期和时间的行。

Final form of the DataFrame containing combined traffic volume and accident counts

快速检查显示,我们的最终数据帧包含日期、时间、体积和事故列,以及 7,944 行。以这种方式按小时对事故数据进行分组导致将 179,026 个单独的事故聚集到 7,944 个每小时的时间点。

由于车流量和交通事故的计数相差悬殊(这是好事!)每小时最大值的分数通过将每小时计数除以每小时最大计数来计算。这使得数据集之间可以进行直接比较。当重叠时,交通和事故数据显示类似的模式。

Left — overlay of the fraction of max traffic volume and accident data showing similar trends. Right — scatter plot of the fraction max volume verses fraction max accidents.

当我们将这些未转换的数据相互作图时,我们观察到一种大致线性的关系。观察到这一点,我们提出了这个问题;我们能不能用一个线性回归模型来代表整个纽约的交通事故和交通流量之间的关系。线性回归可以说是可用的最简单的模型之一

我们建立了一个线性回归模型,看看它在复制数据方面有多有效。这个模型也允许正则化来确定重要的系数。这些系数虽然对确定回归线很重要,但也可以表明一天中事故风险增加或减少的时段。考虑到这是计数数据,我们还可以建立泊松回归模型进行比较。

模型结构

在这项工作中,我们采用了一个丰富的数据集,并随着时间的推移将其提取为简单的计数。线性回归可以说是最简单的机器学习算法之一,所以我们将把它应用到我们的问题中,看看一个简单模型的预测能力如何。

1.线性回归

现在我们有了一个包含日期、时间、体积计数和事故计数的数据框架,我们可以开始构建我们的模型了。为了回答我们的第一个问题,事故数量仅仅是交通量的函数吗?我们忽略了日期和时间,仅将模型拟合到交通量。我们使用在 scikit-learn 中实现的普通最小二乘(OLS)线性回归模型。五重交叉验证(CV)的结果给出了 0.07 的平均 R 值,表明事故数量与交通量本身没有太大的相关性。

我们尝试的第二个模型是另一个 OLS 线性回归,这一次数据按小时聚合,每个小时用虚拟变量表示。该日期也由对应于数据集中第一个日期之后的天数的整数表示。该模型表现得更好,平均 5 倍 CV R 值为 0.63。考虑到数据取自纽约市所有的事故,交通量仅从统计的街道子集推断,这是相当了不起的。

残差图显示它们以 0 为中心,但模式应该是完全随机的。这些值向较大的 X 值呈扇形散开,表明它们存在一些异方差。预测值的直方图显示它们再次以零为中心,有一些向左倾斜。

左上图显示了实际小时事故的分布与正态分布。在大多数情况下,数据遵循正态分布,从数据偏离左手边的对角线可以看出左偏斜。右图显示了预测的事故分布与正态分布的对比。上限值偏离对角线可能表明模型分散不足。

2.泊松回归

泊松回归是另一种广义线性模型,用于对计数数据建模。交通流量和交通事故是计数数据的示例,即只能是非负整数值的数据。例如,发生-3 次或 1.5 次事故是没有意义的。泊松回归的一个假设是响应变量 Y 遵循泊松分布。我们再次在 statsmodel 模块中使用广义线性模型。将泊松回归应用于我们的数据,我们立即看到 chi2 值为 1.86e4。如果数据遵循泊松分布,方差将等于均值,从而使 chi2 值更接近 1。显然,这不是该数据的最佳模型。我们可以尝试负二项式回归,它是泊松模型的一种推广,具有一个宽松的要求,即方差不必等于均值。

3.负二项式回归

负二项式模型类似于泊松模型,增加了一个变量α,以降低严格的方差要求。泊松回归过程中发现的λ值用于确定最佳 alpha 值(有关教程,请参见:https://towardsdatascience . com/negative-binomial-regression-f 99031 bb 25 b 4)。发现α值为 0.071,当使用该值进行负二项式回归时,结果模型显示出统计显著性,这改进了泊松回归的模型。

4.套索回归

我们感兴趣的第二个问题是,是否在一天中的某个特定时间发生事故的风险更高。测试这一点的一种可能方式是使用正则化来执行特征选择。为此,我们将 L1 正则化应用于线性回归。Lasso 或 L1 正则化将不重要的系数缩小到 0,从而为更简洁的模型选择最重要的特征。通过将 lasso 正则化应用于我们的线性模型,最慢接近 0 的特征对于模型的拟合是最重要的。我们选择α值为 0.001、0.25 和 0.5。应用较高的 alpha 值会将更多的系数减少到 0。应用 0.25 的 alpha 值,R 值减少到 0.52。24 个小时系数中有 7 个降低到 0,表明这些对模型的拟合最不重要。其余系数中,最高值出现在下午 2-6 点,峰值出现在下午 4 点,其次是上午 8 点。

这些系数很好地对应了早晚高峰时间。不出所料,交通量的系数在 5.6e-5 处为最小值,这与仅拟合交通量时模型的 R 值较差相一致。如果我们观察 lasso 回归的概率图,我们会发现尽管 R 值降低了,但数据还是具有更正态的分布。

评估模型

将每个回归的测试集的预测与一天的事故数据进行比较,可以发现所有模型都显示出非常一致的预测。这些模型似乎再现了总体趋势,但普遍高估了事故数量。预测中的偏差,至少对于线性和 lasso 回归,反映在它们适度的 R 值中。同样显而易见的是,lasso 回归具有较低的 R 值,因为它在特定区域而不是整体上失去了预测能力。

Overlay of predicted accidents on accidents per hour for a selected day

当我们对测试集中所有每小时的事故计数进行平均并将模型与之进行比较时,我们当然会看到极好的一致性,这表明模型捕捉到了数据的平均属性。

Overlay of predicted accidents on average accidents per hour

结论

3.5 年内的 179,026 起事故按小时汇总,并与交通量数据相匹配,以提供包含 7,944 个每小时数据点的最终数据集。

线性回归表明,交通量本身是纽约市交通事故的不良预测因素。进一步 L1 正则化强调的回归系数显示,下午 4 点是最有可能发生事故的时间。

这种模式的局限性包括:

  • 从道路子集推断整个纽约都会区的交通量。为了提高模型的准确性,参与统计的街道可以与事故数据相匹配,而不是在整个 302 平方英里的城市中进行概化。
  • 交通量数据中观察到的计数可变性表明测量不一致,因此可能导致计数不准确。
  • 按小时汇总不考虑交通模式的波动,例如正常交通的季节性或月度变化。

考虑这些因素中的任何一点都可以提高我们模型的准确性。

基于卷积神经网络的交通标志检测

原文:https://towardsdatascience.com/traffic-sign-detection-using-convolutional-neural-network-660fb32fe90e?source=collection_archive---------5-----------------------

我们将建立一个 CNN 模型,以检测交通标志。

CNN Model

如果你想从事计算机视觉领域的职业,学习卷积神经网络或 ConvNets 或 CNN 是非常重要的。CNN 有助于直接在图像上运行神经网络,并且比许多深度神经网络更有效和准确。与其他模型相比,ConvNet 模型在图像上的训练更容易、更快。

如果你不熟悉 ConvNet 的基础知识,你可以从这里学习。

我们将使用keras包来建立 CNN 模型。

获取数据集

德国交通标志检测数据集在此提供。该数据集由 43 个不同类别的 39209 幅图像组成。这些图像在这些类别之间分布不均匀,因此该模型可以比其他类别更准确地预测一些类别。

我们可以用各种图像修改技术填充数据集,如旋转、颜色失真或模糊图像。我们将在原始数据集上训练模型,并将查看模型的准确性。然后,我们将添加更多的数据,使每个类均匀,并检查模型的准确性。

数据预处理

CNN 模型的局限性之一是它们不能在不同维度的图像上进行训练。因此,数据集中必须有相同维度的图像。

我们将检查数据集的所有图像的尺寸,以便我们可以将图像处理成具有相似的尺寸。在该数据集中,图像具有从 16163 到 1281283 的非常动态的尺寸范围,因此不能直接传递给 ConvNet 模型。

我们需要将图像压缩或插值成一维图像。不,为了压缩大部分数据,不要过度拉伸图像,我们需要确定两者之间的维度,并保持图像数据的最大准确性。我决定用 64643 的尺寸。

我们将使用[opencv](https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_setup/py_intro/py_intro.html)包将图像转换成给定的尺寸。

import cv2def resize_cv(img):
    return cv2.resize(img, (64, 64), interpolation = cv2.INTER_AREA)

cv2opencv的一个包。[resize](https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.html?highlight=resize#scaling)方法将图像变换到给定的维度。在这里,我们将图像转换为 64*64 的尺寸。插值将定义您想要使用哪种类型的技术来拉伸或压缩图像。Opencv 提供了 5 种类型的插值技术,基于它们用来评估结果图像的像素值的方法。技法有 [INTER_AREA, INTER_NEAREST, INTER_LINEAR, INTER_CUBIC, INTER_LANCZOS4](https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#resize)。我们将使用INTER_AREA插值技术,它更适合图像抽取,但对于外推技术,它类似于INTER_NEAREST。我们可以使用INTER_CUBIC,但是它需要很高的计算能力,所以我们不会使用它。

数据加载

上面我们学习了如何预处理图像。现在,我们将加载数据集,并在决定的维度中转换它们。

该数据集总共包括 43 个类。换句话说,该数据集中有 43 种不同类型的交通标志,每个标志都有自己的文件夹,由不同大小和清晰度的图像组成。数据集中总共有 39209 幅图像。

我们可以绘制不同交通标志的图像数量直方图。

import seaborn as sns
fig = sns.distplot(output, kde=False, bins = 43, hist = True, hist_kws=dict(edgecolor="black", linewidth=2))
fig.set(title = "Traffic signs frequency graph",
        xlabel = "ClassId",
        ylabel = "Frequency")

Traffic signs frequency graph

ClassId 是为每个唯一的交通标志指定的唯一 Id。

正如我们从图表中看到的,数据集并不包含每个类别的等量图像,因此,该模型在检测某些交通标志时可能会比其他交通标志更准确。

我们可以通过使用旋转或扭曲技术改变图像来使数据集一致,但我们将在其他时间这样做。

由于数据集被划分到多个文件夹中,并且图像的命名不一致,我们将通过将(64643)维中的所有图像转换到一个列表list_image 中,并将它相似的交通标志转换到另一个列表output中来加载所有图像。我们将使用imread读取图像。

list_images = []
output = []
for dir in os.listdir(data_dir):
    if dir == '.DS_Store' :
        continue

    inner_dir = os.path.join(data_dir, dir)
    csv_file = pd.read_csv(os.path.join(inner_dir,"GT-" + dir + '.csv'), sep=';')
    for row in csv_file.iterrows() :
        img_path = os.path.join(inner_dir, row[1].Filename)
        img = imread(img_path)
        img = img[row[1]['Roi.X1']:row[1]['Roi.X2'],row[1]['Roi.Y1']:row[1]['Roi.Y2'],:]
        img = resize_cv(img)
        list_images.append(img)
        output.append(row[1].ClassId)

data_dir是数据集所在目录的路径。

数据集已加载,现在我们需要将其分为训练集和测试集。也在验证集中。但是如果我们直接分割,那么模型将不会得到所有交通标志的训练,因为数据集不是随机的。所以,首先我们将随机化数据集。

input_array = np.stack(list_images)import keras
train_y = keras.utils.np_utils.to_categorical(output)randomize = np.arange(len(input_array))
np.random.shuffle(randomize)
x = input_array[randomize]
y = train_y[randomize]

我们可以看到,我已经将输出数组转换为分类输出,因为模型将以这种方式返回。

现在,分割数据集。我们将以 60:20:20 的比例将数据集分别拆分为训练数据集、验证数据集和测试数据集。

split_size = int(x.shape[0]*0.6)
train_x, val_x = x[:split_size], x[split_size:]
train1_y, val_y = y[:split_size], y[split_size:]split_size = int(val_x.shape[0]*0.5)
val_x, test_x = val_x[:split_size], val_x[split_size:]
val_y, test_y = val_y[:split_size], val_y[split_size:]

训练模型

from keras.layers import Dense, Dropout, Flatten, Input
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import BatchNormalization
from keras.optimizers import Adam
from keras.models import Sequentialhidden_num_units = 2048
hidden_num_units1 = 1024
hidden_num_units2 = 128
output_num_units = 43epochs = 10
batch_size = 16
pool_size = (2, 2)
#list_images /= 255.0
input_shape = Input(shape=(32, 32,3))model = Sequential([Conv2D(16, (3, 3), activation='relu', input_shape=(64,64,3), padding='same'),
 BatchNormalization(),Conv2D(16, (3, 3), activation='relu', padding='same'),
 BatchNormalization(),
 MaxPooling2D(pool_size=pool_size),
 Dropout(0.2),

 Conv2D(32, (3, 3), activation='relu', padding='same'),
 BatchNormalization(),

 Conv2D(32, (3, 3), activation='relu', padding='same'),
 BatchNormalization(),
 MaxPooling2D(pool_size=pool_size),
 Dropout(0.2),

 Conv2D(64, (3, 3), activation='relu', padding='same'),
 BatchNormalization(),

 Conv2D(64, (3, 3), activation='relu', padding='same'),
 BatchNormalization(),
 MaxPooling2D(pool_size=pool_size),
 Dropout(0.2),Flatten(),Dense(units=hidden_num_units, activation='relu'),
 Dropout(0.3),
 Dense(units=hidden_num_units1, activation='relu'),
 Dropout(0.3),
 Dense(units=hidden_num_units2, activation='relu'),
 Dropout(0.3),
 Dense(units=output_num_units, input_dim=hidden_num_units, activation='softmax'),
])model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=1e-4), metrics=['accuracy'])trained_model_conv = model.fit(train_x.reshape(-1,64,64,3), train1_y, epochs=epochs, batch_size=batch_size, validation_data=(val_x, val_y))

我们已经使用了keras包。

对于了解每一层的意义你可以阅读 这篇博客

评估模型

model.evaluate(test_x, test_y)

该模型得到评估,你可以找到 99%的准确性。

预测结果

pred = model.predict_classes(test_x)

您可以预测每个图像的类别,并验证模型的工作方式。

你可以在这里 找到整个工作 代码。

制作:风的轨迹

原文:https://towardsdatascience.com/trails-of-wind-39967f07a67f?source=collection_archive---------17-----------------------

我们如何创建了一个机场跑道全球建筑的地图,结果是一个风的地图。

这篇文章是由大卫·埃尔斯什、斯特芬·汉斯奇和萨沙·科莱合作完成的。

[## 风的轨迹——机场跑道的建筑

空中旅行已经存在了一百多年。自成立以来,数以千计的机场跑道已经…

trailsofwind.figures.cc](https://trailsofwind.figures.cc/)

当在飞机上飞行时,人造建筑以及它们如何改变地球的面貌令人叹为观止。鸟瞰图为人类如何与景观互动提供了一个全新的视角,利用每个山谷建造村庄,在森林周围塑造田野,在山路上修建高速公路。然而,一些最大的人造建筑是航空旅行本身所需要的:机场。但是为什么它们被建成现在的样子,跑道的方向是如何确定的呢?

在做了一些研究后,我们发现大多数机场跑道都建在该地区的平均风向上,以防止侧风着陆,这对飞机和乘客都是危险的。在风向非常不规则的地区,跑道通常被设计成不同的方向,以确保运行过程的平稳。这就是为什么在这样的地区,机场不仅有平行的跑道,还会根据风向的变化形成不同的形状,比如三角形和正方形。

机场跑道形状

我们的结论是,机场的方位和巨大数量理论上可以提供一个地区的大致风向信息,因为机场在其建筑中反映了风向。

数据探索

工具 JupiterLab,牛郎星

[## 开放数据@我们的机场

对于更密集的工作,我们有一个 CSV 格式的所有机场、国家和地区的数据转储,我们更新…

ourairports.com](http://ourairports.com/data/)

在寻找合适的记录时,我们看到了 我们的报告 页面。它包含了世界上所有机场的广泛集合,还提供了进一步的信息,如乘客频率、高于的海拔和低于海平面以及另一个具有关于跑道(长度、宽度、表面等)的详细参考的数据集。).在移除了不相关的数据,如直升机场关闭的机场没有坐标的跑道之后,我们将跑道数据集与机场数据集进行了比较。****

如您所见,数据集中的许多跑道都没有地理配准,这就是大量跑道无法显示的原因。由此导致的许多机场的缺乏在南美、非洲和巴布亚新几内亚尤为明显。

在使用 follow 初步可视化跑道以查看数据集中偏离的跑道线后,我们手动消除了错误。

跑道在长度和宽度方面有很大的不同,在大多数情况下遵循在机场降落的飞机类型的规格。一种类型的飞机起飞所需的跑道长度取决于各种属性,如重量、空气动力学、发动机和当地气压,对于一架 A380(见第 130 页)来说,长度在几百米到几千米之间。

这个可视化的数据集显示,跑道的宽度比长度有更清晰的结构。

为了比较跑道方向,统一显示它们是很重要的。我们用 Geographiclib 计算了跑道端点坐标之间的中点,并计算了相对于南北轴的旋转角度,以便稍后在地图上投影这些线。

计算出各自的角度后,是时候看看全球跑道的方向了。因此,我们将方位减少到几乎 179°的半圆,以避免重复计算角度(因为着陆带可以从两侧飞行),并给出更清晰的表示。

这里引人注目的是跑道朝向磁北极的高架方向。在南北轴(0°)和东西轴(90°)可以看到明显增加的数量,较小的峰值在 45°和-45°处。

为了在 web 应用程序中进一步使用,所有不重要的信息都被删除并导出到最终的 JSON 文件中。坐标点四舍五入到小数点后六位数,以减小文件大小。

设计

工具 Sketchapp,Mapbox Studio

为了可视化我们的发现,我们需要一个交互式的世界地图,它将跑道绘制成可比较的线条,并给出各个跑道的详细视图。

Mapbox Studio Interface

Mapbox Studio 提供了用您自己的设计来设计 Openstreet 地图数据的可能性,以及添加额外的外部地图数据和字体的可能性。为了可视化实际的地图,我们的挑战是使地图尽可能简单,同时提供适当的方向信息。

应该表示以下元素。

  • 跑道
  • 滑行道
  • 立面模型
  • 街道
  • 国家边界
  • 机场名称
  • 国际航空运输协会机场代码

由三个字母组成的国际航空运输协会-机场代码用于准确识别机场。类似于国家的 ISO 代码。

这也用于设计机场机票,我们想把它放在微型网站的侧边栏中。在这些票的帮助下,可以讲述一个带有相应的可视化、图例和插图的故事。

在完整的桌面版本中,用户可以在地图上自由导航,也可以在侧边栏中滚动讲故事。在智能手机版本中,地图用于在滚动浏览故事的同时显示我们探索的本质,因为地图上许多线条的表示非常注重性能,并且导航有限。为了在移动设备上提供更好的用户体验,重点应该是故事而不是免费导航。

在探险中还有许多其他有趣的发现。然而,为了保持故事简短切题,我们在我们的社交媒体账户中发布了有趣的事实作为预尝,而不是用太多的信息塞满网站。

编码

主要工具 React.js,D3.js,Mapbox GL,Typescript,React Waypoints

我们的微型网站的基础是 react-map-gl,一个绑定到 Mapbox GL JS 的 react,它允许我们显示我们自己在 Mapbox Designstudio 中创建的地图设计。地图上的画布覆盖使线条的实际可视化成为可能。

为了在缩放时使线条变小并消失,我们使用了 D3 提供的缩放功能。

React Waypoints 提供了在滚动侧边栏时触发某些事件的可能性,以便使用 react-map-gl 提供的 fly to 插值器飞到地图的区域。

虽然在 Sketchapp 中有两个侧边栏图形被设计并导出为静态 SVG,但所有跑道的分布表示必须通过编程来创建。为了不超出南北轴上的计数范围,对数标度是必要的。同时,可视化应该与地图直接联系起来理解,这就是为什么线的径向表示似乎是最合适的,能够直接在地图上读取角度。

结论

像往常一样,我们会在项目上花更多的时间来展示更多有趣的事实和见解。

未来,我们希望直接从 OpenStreetMap 中提取跑道数据,以增加显示机场的数量。此外,可以添加一个带有一些过滤器的微型网站,以便根据某些标准搜索跑道。为了提高性能,还可以为显示的行编写自己的着色器。

我们乐于分享我们的知识,并一直在寻找新的挑战和跨学科的项目和合作伙伴。

我们将非常高兴收到您的反馈。

使用 Pytorch 训练线条分割模型

原文:https://towardsdatascience.com/train-a-lines-segmentation-model-using-pytorch-34d4adab8296?source=collection_archive---------9-----------------------

让我们从确定我们想要解决的问题开始,这个问题是由这个项目激发的。

给定包含文本行的图像,返回该图像的像素标签,每个像素属于背景或手写行。

项目结构

它由 5 个主要部分组成,一个用于笔记本,一个用于共享 python 代码、数据集、Google Cloud 脚本,一个用于保存模型权重。

在一个生产项目中,您可能会有更多像webapi这样的目录。

我还选择使用pipenv而不是condavirtualenv来管理我的 python 环境。我最近才从conda切换到pipenv,我发现它在任何地方都能一如既往地正常工作。

对于 GPU 培训,我使用了一个谷歌云实例和一个 T4 英伟达 GPU。Bash 脚本管理实例的生命周期,从最初创建到启动、连接和停止。

数据

数据集在raw目录中的[toml](https://en.wikipedia.org/wiki/TOML)文件中描述,一个toml文件基本上由键、值对组成。git 忽略了data下的其他目录,因为它们将包含实际的完整数据集下载。

笔记本电脑

我使用笔记本进行探索,并将其作为构建、清理数据集和构建培训基本管道所需代码的高级容器。

Python 文件

src目录下,我保存了可以在不同笔记本之间共享和重用的代码。遵循良好的软件工程实践是快速正确完成工作的关键,在 ML 代码中发现和识别 bug 是非常困难的。这就是为什么你要从小处着手,并经常重申。

python 环境

您可以使用以下命令使用 linuxbrew 或 macbrew 在 Linux 或 mac 上安装pipenv:

brew install pipenv

然后您可以使用pipenv install SOMETHING从您的项目目录中下载您的依赖项。

数据集

我将使用这个旧的学术数据集作为基础来构建线条分割数据集,以训练一个 UNet 小型网络来检测手写线条。

数据集中的原始图像如下所示,它们还带有定义边界框的 XML 文件。

notebooks/01-explore-iam-dataset.ipynb我下载了数据集,解压后用 XML 文件中的数据叠加了一些随机图像。

接下来,我裁剪图像并生成遮罩图像来匹配新的尺寸。遮罩图像是我们将用于训练最终模型的地面真实图像。

最后,我将数据分为训练、有效和测试

网络

因为我们没有很多数据可用于训练,所以我使用了一个基于 Keras 实现的迷你版本的 UNet 架构。

使用这个巨大的库,我可以通过一个特定输入大小的前馈来可视化网络。

培训渠道

既然我们已经准备好了数据,并且定义了我们想要训练的网络,那么是时候建立一个基本的训练管道了。

首先是定义一个火炬dataset,并使用DataLoader遍历它

from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils class FormsDataset(Dataset): def __init__(self, images, masks, num_classes: int, transforms=None):
        self.images = images
        self.masks = masks
        self.num_classes = num_classes
        self.transforms = transforms

    def __getitem__(self, idx):
        image = self.images[idx]
        image = image.astype(np.float32)
        image = np.expand_dims(image, -1)
        image = image / 255
        if self.transforms:
            image = self.transforms(image)

        mask = self.masks[idx]
        mask = mask.astype(np.float32)
        mask = mask / 255
        mask[mask > .7] = 1
        mask[mask <= .7] = 0
        if self.transforms:
            mask = self.transforms(mask)

        return image, mask

    def __len__(self):
        return len(self.images)train_dataset = FormsDataset(train_images, train_masks, number_of_classes, get_transformations(True))
train_data_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
print(f'Train dataset has {len(train_data_loader)} batches of size {batch_size}')

接下来,我定义训练循环

# Use gpu for training if available else use cpu
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')# Here is the loss and optimizer definition
criterion = torch.nn.NLLLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)# The training loop
total_steps = len(train_data_loader)
print(f"{epochs} epochs, {total_steps} total_steps per epoch")for epoch in range(epochs):
    for i, (images, masks) in enumerate(train_data_loader, 1):
        images = images.to(device)
        masks = masks.type(torch.LongTensor)
        masks = masks.reshape(masks.shape[0], masks.shape[2], masks.shape[3])
        masks = masks.to(device)

        # Forward pass
        outputs = model(images)
        softmax = F.log_softmax(outputs, dim=1)
        loss = criterion(softmax, masks)

        # Backward and optimize
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if (i) % 100 == 0:
            print (f"Epoch [{epoch + 1}/{epochs}], Step [{i}/{total_steps}], Loss: {loss.item():4f}")

以下是最终的预测

你可以点击查看 TF2 支持的 Keras 项目。

谢谢你能走到这一步。我想说的最后一点是,不幸的是,大多数可用的在线材料要么提供了糟糕的建议,要么非常基本,它们实际上没有提供多少价值,有些是完全错误的。有一些很棒的资源,比如他们的 60 分钟闪电战系列(T1)和很棒的 T2 API 文档(T3)。还有这个小抄和这个伟大的 GitHub 回购。

如果你喜欢阅读这篇文章,或者觉得它有帮助,我很乐意收到你的来信,给我留言或者在 Twitter 上关注我,当我发布新内容时,你会得到通知。

训练自定义数据集掩码 RCNN

原文:https://towardsdatascience.com/train-custom-dataset-mask-rcnn-6407846598db?source=collection_archive---------11-----------------------

在 Mask RCNN 模型上轻松训练自定义数据集的教程:终于轮到你了!

如何使用自定义数据集训练掩膜 RCNN 模型的分步说明。

要求

首先简单地克隆下面的库,它是一个单独类分段的演示。(我们也将涵盖多个类别)。

git clone [https://github.com/miki998/Custom_Train_MaskRCNN](https://github.com/miki998/Custom_Train_MaskRCNN)

正如 README.md 中提到的,需要安装一个 mrcnn 库,这个库不是标准的。您只需要做以下事情:

git clone [https://github.com/matterport/Mask_RCNN.git](https://github.com/matterport/Mask_RCNN.git)
cd Mask_RCNN
python setup.py install
cd ../
rm -rf Mask_RCNN

最重要的是,需要一个起始权重,当然你可以编写自己的随机初始化器,但是在我们的例子中,我们决定简单地选择原作者给出的缺省值. h5。要得到重量,你可以从我的驱动器上得到。

cd weights
wget [https://drive.google.com/open?id=1h62_fPkdrBufw1xCaeGwm2SgLWVtFHFQ](https://drive.google.com/open?id=1h62_fPkdrBufw1xCaeGwm2SgLWVtFHFQ)
cd ../

用法(指训练脚本)

在克隆存储库之后,您应该得到如下结构。所有要进行的修改都在 train.py 文件中,因此使用您最喜欢的文本编辑器,您只需编辑然后添加数据集。

从第 65 行到第 74 行,简单地修改 category 变量和它的类名,以匹配您的数据集(下面是最初编写的内容):

# define 81 classes that the coco model knowns about
Category = 'food'class_names = [‘bread-wholemeal’, ‘potatoes-steamed’, ‘broccoli’, ‘butter’, ‘hard-cheese’, ‘water’, ‘banana’, ‘wine-white’, ‘bread-white’, ‘apple’, ‘pizza-margherita-baked’, ‘salad-leaf-salad-green’, ‘zucchini’, ‘water-mineral’, ‘coffee-with-caffeine’, ‘avocado’, ‘tomato’, ‘dark-chocolate’, ‘white-coffee-with-caffeine’, ‘egg’, ‘mixed-salad-chopped-without-sauce’, ‘sweet-pepper’, ‘mixed-vegetables’, ‘mayonnaise’, ‘rice’, ‘chips-french-fries’, ‘carrot’, ‘tomato-sauce’, ‘cucumber’, ‘wine-red’, ‘cheese’, ‘strawberries’, ‘espresso-with-caffeine’, ‘tea’, ‘chicken’, ‘jam’, ‘leaf-spinach’, ‘pasta-spaghetti’, ‘french-beans’, ‘bread-whole-wheat’]

额外注意:显然,如果你想改变超参数,如学习每张图片或批量大小的 GPU 的步骤/ nb,这里是如何做到这一点。

class CustomConfig(Config): """Configuration for training on the toy  dataset.    Derives from the base Config class and overrides some values.    """   

# Give the configuration a recognizable name    NAME = category     # We use a GPU with 12GB memory, which can fit two images. # Adjust down if you use a smaller GPU.   
IMAGES_PER_GPU = 1 # Number of classes (including background)   
NUM_CLASSES = 1 + len(class_names)  
# Background + toy # Number of training steps per epoch    
STEPS_PER_EPOCH = 100 # Skip detections with < 90% confidence    
DETECTION_MIN_CONFIDENCE = 0.9

你只需要改变写在 train.py 这一部分的参数,更多的参数,你可以查看 matterport 的 github:https://github.com/matterport/Mask_RCNN

最后,在将您自己的数据集放入数据集文件夹(检查文件夹内部以了解要放入的内容及其格式)后,运行以下命令开始训练:

python3 train.py train --dataset=./dataset --weights=coco

输入以下命令后,您应该会看到下图:

非常感谢您的阅读,敬请关注更多有趣的文章!你可以随时联系我获取更多的信息,或者如果你想在这个问题上合作。另外,点击这个链接(指向联盟计划)真的会帮我解决问题!您只需完成一些快速任务(只需等待和激活通知),所有这些将真正帮助我了解更多未来的硬件相关内容!

使用 AMD GPU 和 Keras 训练神经网络

原文:https://towardsdatascience.com/train-neural-networks-using-amd-gpus-and-keras-37189c453878?source=collection_archive---------6-----------------------

ROCm 平台入门

AMD 正在开发一个新的高性能计算平台,称为 ROCm。它的目标是创建一个通用的开源环境,能够与 Nvidia(使用 CUDA)和 AMD GPUs 接口(进一步信息)。

本教程将解释如何设置一个神经网络环境,在一个或多个配置中使用 AMD GPUs。

在软件方面:我们将能够使用 Docker 在 ROCm 内核上运行 Tensorflow v1.12.0 作为 Keras 的后端。

安装和部署 ROCm 需要特定的硬件/软件配置。

硬件要求

官方文档(ROCm v2.1)建议采用以下硬件解决方案。

支持的 CPU

当前支持 PCIe Gen3 + PCIe 原子处理器的 CPU 有:

  • AMD 锐龙 CPUs
  • AMD 锐龙 APU 中的 CPU:
  • AMD 锐龙线程处理器
  • AMD EPYC CPU;
  • 英特尔至强 E7 v3 或更新的 CPUs
  • 英特尔至强 E5 v3 或更新的 CPUs
  • 英特尔至强 E3 v3 或更新的 CPUs
  • 英特尔酷睿 i7 v4(i7–4xxx)、酷睿 i5 v4(i5–4xxx)、酷睿 i3 v4(i3–4xxx)或更新的 CPU(即 Haswell 系列或更新的产品)。
  • 一些 Ivy Bridge-E 系统

支持的 GPU

ROCm 官方支持使用以下芯片的 AMD GPUs:

  • GFX8 GPUs
  • “斐济”芯片,如 AMD 公司的镭龙 R9 Fury X 和镭龙本能 MI8
  • “北极星 10”芯片,如在 AMD 镭龙 RX 480/580 和镭龙本能军情六处
  • “北极星 11”芯片,如 AMD 镭龙 RX 470/570 和镭龙专业 WX 4100
  • “北极星 12”芯片,如 AMD 公司的镭龙 RX 550 和镭龙 RX 540
  • GFX9 GPUs
  • “织女星 10”芯片,如 AMD 公司的镭龙 RX 织女星 64 和镭龙本能 MI25
  • “织女星 7 纳米”芯片(镭龙本能 MI50,镭龙七)

软件要求

在软件方面,ROCm 的当前版本(v2.1)仅在基于 Linux 的系统中受支持。

ROCm 2.1.x 平台支持以下操作系统:

Ubuntu 16.04.x 和 18.04.x(版本 16.04.3 和更新版本或内核 4.13 和更新版本)

CentOS 7.4、7.5 和 7.6(使用 devtoolset-7 运行时支持)

RHEL 7.4、7.5 和 7.6(使用 devtoolset-7 运行时支持)

测试设置

作者使用了以下硬件/软件配置来测试和验证环境:

硬件

  • CPU:英特尔至强 E5–2630 l
  • 内存:2 个 8 GB
  • 主板:微星 X99A 金环版
  • GPU: 2 个 RX480 8GB + 1 个 RX580 4GB
  • 固态硬盘:三星 850 Evo (256 GB)
  • 硬盘:WDC 1TB

软件

  • 操作系统:LTS Ubuntu 18.04

ROCm 安装

为了让一切正常工作,建议在全新安装的操作系统中开始安装过程。以下步骤参照 Ubuntu 18.04 LTS 操作系统,其他操作系统请参照官方文档。

第一步是安装 ROCm 内核和依赖项:

更新你的系统

打开一个新的终端CTRL + ALT + T

sudo apt update
sudo apt dist-upgrade
sudo apt install libnuma-dev
sudo reboot

添加 ROCm apt 库

要下载和安装 ROCm stack,需要添加相关的存储库:

wget -qO - http://repo.radeon.com/rocm/apt/debian/rocm.gpg.key | sudo apt-key add -echo 'deb [arch=amd64] http://repo.radeon.com/rocm/apt/debian/ xenial main' | sudo tee /etc/apt/sources.list.d/rocm.list

安装 ROCm

现在需要更新 apt 库列表并安装rocm-dkms元包:

sudo apt update
sudo apt install rocm-dkms

设置权限

官方文档建议使用当前用户创建一个新的video组来访问 GPU 资源。

首先,检查系统中的组,发出:

groups

然后将您自己添加到视频群组:

sudo usermod -a -G video $LOGNAME

您可能希望确保您添加到系统中的任何未来用户都被默认放入“视频”组。为此,您可以运行以下命令:

echo 'ADD_EXTRA_GROUPS=1' | sudo tee -a /etc/adduser.conf
echo 'EXTRA_GROUPS=video' | sudo tee -a /etc/adduser.conf

然后重新启动系统:

reboot

测试 ROCm 堆栈

现在建议发出以下命令来测试 ROCm 安装。

打开一个新的终端CTRL + ALT + T,发出以下命令:

/opt/rocm/bin/rocminfo

输出应该如下所示:链接

然后复核签发:

/opt/rocm/opencl/bin/x86_64/clinfo

输出应该是这样的:链接

官方文档最后建议将 ROCm 二进制文件添加到 PATH:

echo 'export PATH=$PATH:/opt/rocm/bin:/opt/rocm/profiler/bin:/opt/rocm/opencl/bin/x86_64' | sudo tee -a /etc/profile.d/rocm.sh

恭喜你!ROCm 已正确安装在您的系统中,并且命令:

rocm-smi

应该显示您的硬件信息和统计数据:

rocm-smi command output

提示: 看看rocm-smi -h命令,探索更多的功能和 OC 工具

张量流 Docker

让 ROCm + Tensorflow 后端工作的最快、最可靠的方法是使用 AMD 开发者提供的 docker 镜像。

安装 Docker CE

首先,需要安装 Docker。为此,请遵循 Ubuntu 系统的说明:

[## 获取 Ubuntu 的 Docker CE

要在 Ubuntu 上开始使用 Docker CE,请确保您满足先决条件,然后安装 Docker。先决条件…

docs.docker.com](https://docs.docker.com/install/linux/docker-ce/ubuntu/)

提示 :为了避免插入sudo docker <command>而不是docker <command> ,向非根用户提供访问权限是很有用的:将 Docker 作为非根用户管理。

拉 ROCm 张量流图像

现在该拉 AMD 开发者提供的 Tensorflow docker 了。

打开新的终端CTRL + ALT + T并发布:

docker pull rocm/tensorflow

几分钟后,映像将被安装到您的系统中,准备就绪。

创造一个持久的空间

由于 docker 容器的短暂性,一旦 Docker 会话关闭,所有的修改和存储的文件都将随容器一起删除。

因此,在物理驱动器中创建一个永久空间来存储文件和笔记本是非常有用的。更简单的方法是创建一个文件夹,用 docker 容器初始化。为此,发出以下命令:

mkdir /home/$LOGNAME/tf_docker_share

该命令将创建一个名为tf_docker_share的文件夹,用于存储和查看 docker 中创建的数据。

起始码头工人

现在,在新的容器会话中执行图像。只需发送以下命令:

docker run -i -t \
--network=host \
--device=/dev/kfd \
--device=/dev/dri \
--group-add video \
--cap-add=SYS_PTRACE \
--security-opt seccomp=unconfined \
--workdir=/tf_docker_share \
-v $HOME/tf_docker_share:/tf_docker_share rocm/tensorflow:latest /bin/bash

docker 正在目录/tf_docker_share上执行,您应该看到类似于:

这意味着你现在正在 Tensorflow-ROCm 虚拟系统中运行。

安装 Jupyter

Jupyter 是一个非常有用的工具,用于神经网络的开发、调试和测试。不幸的是,它目前没有默认安装在由 ROCm 团队发布的 tensor flow-ROCm Docker image 上。因此需要手动安装 Jupyter。

为此,在 Tensorflow-ROCm 虚拟系统提示符下,

1.发出以下命令:

pip3 install jupyter

它会将 Jupyter 包安装到虚拟系统中。让这个终端开着。

2.打开一个新的端子CTRL + ALT + T

找到发出命令的CONTAINER ID:

docker ps

应该会出现一个类似如下的表格:

Container ID on the left

第一列表示被执行容器的容器 ID 。复制它,因为下一步需要它。

3.是时候提交了,永久地写入图像的修改。从同一个终端,执行:

docker commit <container-id> rocm/tensorflow:<tag>

其中tag值是任意名称,例如personal

4.要再次检查图像是否已正确生成,请从同一终端发出以下命令:

docker images

这应该会生成如下所示的表格:

值得注意的是,在本教程的剩余部分,我们将引用这个新生成的图像。

使用新的docker run命令,看起来像:

docker run -i -t \
--network=host \
--device=/dev/kfd \
--device=/dev/dri \
--group-add video \
--cap-add=SYS_PTRACE \
--security-opt seccomp=unconfined \
--workdir=/tf_docker_share \
-v $HOME/tf_docker_share:/tf_docker_share rocm/tensorflow:<tag> /bin/bash

同样,tag的值是任意的,例如personal

进入 Jupyter 笔记本电脑环境

我们终于可以进入木星的环境了。在其中,我们将使用 Tensorflow v1.12 作为后端,Keras 作为前端,创建第一个神经网络。

清洁

首先关闭所有先前执行的 Docker 容器。

  1. 检查已经打开的容器:
docker ps

2.关闭所有码头集装箱:

docker container stop <container-id1> <container-id2> ... <container-idn>

3.关闭所有已经打开的终端。

执行 Jupyter

让我们打开一个新的终端CTRL + ALT + T:

  1. 运行一个新的 Docker 容器(personal标签将被默认使用):
docker run -i -t \
--network=host \
--device=/dev/kfd \
--device=/dev/dri \
--group-add video \
--cap-add=SYS_PTRACE \
--security-opt seccomp=unconfined \
--workdir=/tf_docker_share \
-v $HOME/tf_docker_share:/tf_docker_share rocm/tensorflow:personal /bin/bash

您应该登录 Tensorflow-ROCm docker 容器提示符。

Logged into docker container

2.执行 Jupyter 笔记本:

jupyter notebook --allow-root --port=8889

应该会出现一个新的浏览器窗口,如下所示:

Jupyter root directory

如果新标签没有自动出现,在浏览器上,返回到执行jupyter notebook命令的终端。在底部,有一个链接(在上面按下CTRL + left mouse button)然后,浏览器中的一个新标签会将你重定向到 Jupyter 根目录。

Typical Jupyter notebook output. The example link is on the bottom

用 Keras 训练神经网络

在本教程的最后一部分,我们将在 MNIST 数据集上训练一个简单的神经网络。我们将首先建立一个完全连接的神经网络。

全连接神经网络

让我们创建一个新的笔记本,从 Jupyter 根目录的右上角菜单中选择 Python3

The upper-right menu in Jupyter explorer

一个新的 Jupiter 笔记本应该会在新的浏览器选项卡中弹出。通过点击窗口左上角的Untitled将其重命名为fc_network

Notebook renaming

让我们检查 Tensorflow 后端。在第一个单元格中插入:

import tensorflow as tf; print(tf.__version__)

然后按SHIFT + ENTER执行。输出应该类似于:

Tensorflow V1.12.0

我们用的是 Tensorflow v1.12.0。

让我们导入一些有用的函数,接下来使用:

from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.utils import to_categorical

让我们设置批量大小、时期和类的数量。

batch_size = 128
num_classes = 10
epochs = 10

我们现在将下载并预处理输入,将它们加载到系统内存中。

# the data, split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')# convert class vectors to binary class matrices
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)

是时候定义神经网络架构了:

model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))

我们将使用一个非常简单的双层全连接网络,每层有 512 个神经元。它还包括神经元连接 20%的下降概率,以防止过度拟合。

让我们来看看网络架构的一些见解:

model.summary()

Network architecture

尽管问题很简单,但我们有相当多的参数需要训练(大约 700.000),这也意味着相当大的计算功耗。卷积神经网络将解决降低计算复杂性的问题。

现在,编译模型:

model.compile(loss='categorical_crossentropy',
              optimizer=RMSprop(),
              metrics=['accuracy'])

并开始训练:

history = model.fit(x_train, y_train,
                    batch_size=batch_size,
                    epochs=epochs,
                    verbose=1,
                    validation_data=(x_test, y_test))

Training process

神经网络已经在单个 RX 480 上以相当高的 47us/step 进行了训练。相比之下,Nvidia Tesla K80 达到了 43us/step,但贵了 10 倍。

多 GPU 训练

作为一个额外的步骤,如果您的系统有多个 GPU,可以利用 Keras 功能,以减少培训时间,在不同的 GPU 之间分割批处理。

为此,首先需要通过声明一个环境变量来指定用于训练的 GPU 数量(将以下命令放在单个单元上并执行):

!export HIP_VISIBLE_DEVICES=0,1,...

从 0 到…的数字定义了用于训练的 GPU。如果您想禁用 GPU 加速,只需:

!export HIP_VISIBLE_DEVICES=-1

还需要添加multi_gpu_model功能。

举个例子,如果你有 3 个 GPU,前面的代码会相应地修改。

结论

本教程到此结束。下一步将在 MNIST 数据集上测试卷积神经网络。比较单个和多个 GPU 的性能。

这里相关的是,AMD GPUs 在计算负载下表现相当好,而价格只是它的一小部分。GPU 市场正在快速变化,ROCm 为研究人员、工程师和初创公司提供了非常强大的开源工具,可以采用,从而降低了硬件设备的前期成本。

条乘 条乘

请随意评论这篇文章,以提高他的质量和效果。

从头开始训练卷积神经网络

原文:https://towardsdatascience.com/training-a-convolutional-neural-network-from-scratch-2235c2a25754?source=collection_archive---------0-----------------------

一个为 CNN 派生反向传播并在 Python 中从头实现它的简单演练。

在这篇文章中,我们将深入探讨大多数卷积神经网络(CNN)介绍所缺乏的东西:如何训练 CNN ,包括推导梯度,从头实现反向投影(仅使用 numpy ),并最终建立一个完整的训练管道!

这篇文章假设你对 CNN 有基本的了解。我对 CNN 的介绍涵盖了你需要知道的一切,所以我强烈建议你先读一下。如果你来这里是因为你已经读过了,欢迎回来!

这篇文章的部分内容也假设了多变量微积分的基础知识。如果你想的话,你可以跳过这些章节,但是我建议即使你不理解所有的内容,也要阅读它们。当我们得到结果时,我们将逐步编写代码,即使是表面的理解也会有所帮助。

1.搭建舞台

系好安全带。是时候进入状态了。

我们将继续我对 CNN 的介绍。我们用 CNN 来解决 MNIST 手写数字分类问题:

Sample images from the MNIST dataset

我们的(简单的)CNN 由一个 Conv 层、一个 Max 池层和一个 Softmax 层组成。这是我们 CNN 的图表:

Our CNN takes a 28x28 grayscale MNIST image and outputs 10 probabilities, 1 for each digit.

我们写了 3 个类,每层一个:Conv3x3MaxPoolSoftmax。每个类都实现了一个forward()方法,我们用它来构建 CNN 的前向传递:

你可以在你的浏览器 中查看代码或者 运行 CNN。在 Github 上也有。

这是我们 CNN 现在的输出:

*MNIST CNN initialized!
[Step 100] Past 100 steps: Average Loss 2.302 | Accuracy: 11%
[Step 200] Past 100 steps: Average Loss 2.302 | Accuracy: 8%
[Step 300] Past 100 steps: Average Loss 2.302 | Accuracy: 3%
[Step 400] Past 100 steps: Average Loss 2.302 | Accuracy: 12%*

显然,我们想做到 10%以上的准确率…让我们给 CNN 一个教训。

2.培训概述

训练神经网络通常包括两个阶段:

  1. 前向阶段,输入完全通过网络。
  2. 反向阶段,其中梯度被反向传播(反向传播)并且权重被更新。

我们将遵循这种模式来训练我们的 CNN。我们还将使用两个主要的特定于实现的想法:

  • 在向前阶段,每一层将缓存向后阶段所需的任何数据(如输入、中间值等)。这意味着任何反向阶段之前必须有相应的正向阶段。
  • 在反向阶段,每一层将接收一个梯度,并且返回一个梯度。它将接收关于其输出* (∂L / ∂out)的损耗梯度,并返回关于其输入 (∂L / ∂in).)的损耗梯度*

这两个想法将有助于保持我们的培训实施干净和有组织。了解原因的最佳方式可能是查看代码。训练我们的 CNN 最终会是这样的:

看到那看起来多漂亮多干净了吗?现在想象建立一个有 50 层而不是 3 层的网络——拥有好的系统更有价值。

3.反向投影:Softmax

我们将从结尾开始,然后朝着开头前进,因为这就是反向传播的工作方式。首先,回忆一下交叉熵损失:

其中 p_c 是正确类别 c 的预测概率(换句话说,我们当前图像实际上是多少位)。

想要更长的解释?阅读我的 CNN 简介的 交叉熵损失 部分。

我们需要计算的第一件事是 Softmax 层的反向相位∂L / ∂out_s 的输入,其中 out_s 是 Softmax 层的输出:10 个概率的向量。这很简单,因为只有 p_i 出现在损耗方程中:

Reminder: c is the correct class.

这是你在上面看到的初始梯度:

我们几乎已经准备好实现我们的第一个反向阶段——我们只需要首先执行我们之前讨论过的正向阶段缓存:

我们在这里缓存了 3 个对实现后向阶段有用的东西:

  • 在变平之前input的形状。**
  • 后的input 我们把它压平。
  • 总计,是传递给 softmax 激活的值。

这样一来,我们就可以开始推导反投影阶段的梯度了。我们已经导出了 Softmax 反向阶段的输入:∂L / ∂out_s。关于∂L / ∂out_s,我们可以利用的一个事实是只有正确的类* c 才是非零的。这意味着除了 out_s(c)之外,我们可以忽略任何东西!*

首先,让我们计算 out_s(c)相对于总数的梯度(传递给 softmax 激活的值)。设 t_i 为第 I 类的总和,那么我们可以写出 _s(c)为:

你应该从我的 CNN 教程的 Softmax 部分认出了上面的等式。

现在,考虑某个类 k,使得 k 不是 c,我们可以将 out_s(c)重写为:

并使用链式法则推导出:

记住,这是假设 k 不等于 c。现在让我们对 c 进行推导,这次使用商法则:

唷。这是整篇文章中最难的部分——从这里开始只会变得更容易!让我们开始实现它:

还记得∂L / ∂out_s 只对正确的类 c 是非零的吗?我们通过在d_L_d_out中寻找非零梯度来开始寻找 c。一旦我们发现了这一点,我们就可以使用上面得出的结果来计算梯度∂out_s(i) / ∂t ( d_out_d_totals):

我们继续吧。我们最终想要损失相对于权重、偏差和输入的梯度:

  • 我们将使用权重梯度,∂L / ∂w,来更新我们的层的权重。
  • 我们将使用偏差梯度∂L / ∂b 来更新图层的偏差。
  • 我们将从我们的backprop()方法返回输入渐变,∂L / ∂input,这样下一层可以使用它。这是我们在培训概述部分谈到的回报梯度!

为了计算这 3 个损失梯度,我们首先需要导出另外 3 个结果:总数相对于权重、偏差和输入的梯度。这里的相关等式是:**

这些渐变很容易!

将所有东西放在一起:

将它写入代码就不那么简单了:

首先,我们预计算d_L_d_t,因为我们将多次使用它。然后,我们计算每个梯度:

  • **d_L_d_w**:我们需要 2d 数组来做矩阵乘法(@),但是d_t_d_wd_L_d_t是 1d 数组。 np.newaxis 让我们很容易地创建一个新的长度为 1 的轴,所以我们最终将维度为(input_len,1)和(1,nodes)的矩阵相乘。因此,d_L_d_w的最终结果将具有 shape ( input_lennodes),与self.weights相同!
  • **d_L_d_b**:这个很简单,因为d_t_d_b是 1。
  • **d_L_d_inputs**:我们将维度为(input_lennodes)和(nodes,1)的矩阵相乘,得到长度为input_len的结果。

试着做上面计算的小例子,特别是 *d_L_d_w* *d_L_d_inputs* 的矩阵乘法。这是理解为什么这段代码能正确计算梯度的最好方法。

随着所有的梯度计算,所有剩下的是实际训练 Softmax 层!我们将使用随机梯度下降(SGD)来更新权重和偏差,就像我们在我的神经网络简介中所做的那样,然后返回d_L_d_inputs:

注意,我们添加了一个learn_rate参数来控制我们更新权重的速度。此外,在返回d_L_d_inputs之前,我们必须reshape(),因为我们在向前传球时拉平了输入:

整形为last_input_shape确保该层返回其输入的渐变,格式与输入最初提供给它的格式相同。

试驾:Softmax Backprop

我们已经完成了我们的第一个反向投影实现!让我们快速测试一下,看看它有什么好的。我们将从我的CNN 简介开始实现一个train()方法:

运行此命令会得到类似于以下内容的结果:

*MNIST CNN initialized!
[Step 100] Past 100 steps: Average Loss 2.239 | Accuracy: 18%
[Step 200] Past 100 steps: Average Loss 2.140 | Accuracy: 32%
[Step 300] Past 100 steps: Average Loss 1.998 | Accuracy: 48%
[Step 400] Past 100 steps: Average Loss 1.861 | Accuracy: 59%
[Step 500] Past 100 steps: Average Loss 1.789 | Accuracy: 56%
[Step 600] Past 100 steps: Average Loss 1.809 | Accuracy: 48%
[Step 700] Past 100 steps: Average Loss 1.718 | Accuracy: 63%
[Step 800] Past 100 steps: Average Loss 1.588 | Accuracy: 69%
[Step 900] Past 100 steps: Average Loss 1.509 | Accuracy: 71%
[Step 1000] Past 100 steps: Average Loss 1.481 | Accuracy: 70%*

损失在下降,准确性在上升——我们的 CNN 已经在学习了!

4.反向推进:最大池化

Max Pooling 层不能被训练,因为它实际上没有任何权重,但是我们仍然需要为它实现一个方法来计算梯度。我们将从再次添加前向阶段缓存开始。这次我们需要缓存的只是输入:

在向前传递期间,最大池层通过在 2x2 块上选取最大值来获取输入体积并将其宽度和高度尺寸减半。反向过程则相反:我们将通过将每个梯度值分配给来加倍损失梯度的宽度和高度,其中原始最大值是其对应的 2x2 块中的

这里有一个例子。考虑最大池层的这个前进阶段:

An example forward phase that transforms a 4x4 input to a 2x2 output

同一层的反向阶段将如下所示:

An example backward phase that transforms a 2x2 gradient to a 4x4 gradient

每个渐变值都被分配到原始最大值所在的位置,其他值为零。

为什么最大池层的反向阶段是这样工作的?思考一下∂L / ∂inputs 直觉上应该是什么样子。不是其 2x2 块中最大值的输入像素对损失的边际影响为零,因为稍微改变该值根本不会改变输出!换句话说,对于非最大像素,∂L / ∂inputs = 0。另一方面,最大值的输入像素会将其值传递给输出,因此∂output / ∂input = 1,意味着∂L / ∂input = ∂L / ∂output.

我们可以使用我在 CNN 简介中写的助手方法很快实现这一点。我将再次把它包括在内作为提醒:

对于每个过滤器中每个 2×2 图像区域中的每个像素,如果它是正向传递期间的最大值,我们将梯度从d_L_d_out复制到d_L_d_input

就是这样!我们的最后一层。

5.背景:Conv

我们终于来了:通过 Conv 层反向传播是训练 CNN 的核心。前向阶段缓存很简单:

提醒一下我们的实现:为了简单起见, 我们假设 conv 层的输入是一个 2d 数组 。这只对我们有用,因为我们把它作为网络的第一层。如果我们正在构建一个需要多次使用 *Conv3x3* 的更大的网络,我们必须使输入成为一个 3d 数组。

我们主要对 conv 图层中滤镜的损耗梯度感兴趣,因为我们需要它来更新我们的滤镜权重。我们已经有了∂L / ∂out 的 conv 层,所以我们只需要∂out / ∂filters。为了计算,我们问自己:改变过滤器的重量会如何影响 conv 层的输出?

事实是改变任何滤波器权重都会影响该滤波器的整个输出图像,因为在卷积期间每个输出像素使用每个像素权重。为了更容易理解,让我们一次只考虑一个输出像素:修改一个滤镜会如何改变一个特定输出像素的输出?

这里有一个超级简单的例子来帮助思考这个问题:

A 3x3 image (left) convolved with a 3x3 filter (middle) to produce a 1x1 output (right)

我们将一个 3×3 图像与一个全零 3×3 滤波器进行卷积,产生 1×1 输出。如果我们将中央过滤器的重量增加 1 会怎么样?输出将增加中心图像值 80:

类似地,将任何其他过滤器权重增加 1 将使输出增加相应图像像素的值!这表明特定输出像素相对于特定滤波器权重的导数就是相应的图像像素值。计算证实了这一点:

我们可以将所有这些放在一起,找出特定滤波器权重的损耗梯度:

我们已经准备好为我们的 conv 层实现反向投影了!

我们通过迭代每个图像区域/滤波器并递增地构建损失梯度来应用我们导出的方程。一旦我们涵盖了所有内容,我们就像以前一样使用 SGD 更新self.filters。请注意解释我们为什么要返回的注释——输入损耗梯度的推导与我们刚才所做的非常相似,留给读者作为练习:)。

就这样,我们结束了!我们已经通过我们的 CNN 实现了一个完整的向后传递。是时候测试一下了…

6.训练 CNN

我们将训练 CNN 几个时期,在训练过程中跟踪它的进展,然后在单独的测试集上测试它。以下是完整的代码:

运行代码的输出示例:

*MNIST CNN initialized!
--- Epoch 1 ---
[Step 100] Past 100 steps: Average Loss 2.254 | Accuracy: 18%
[Step 200] Past 100 steps: Average Loss 2.167 | Accuracy: 30%
[Step 300] Past 100 steps: Average Loss 1.676 | Accuracy: 52%
[Step 400] Past 100 steps: Average Loss 1.212 | Accuracy: 63%
[Step 500] Past 100 steps: Average Loss 0.949 | Accuracy: 72%
[Step 600] Past 100 steps: Average Loss 0.848 | Accuracy: 74%
[Step 700] Past 100 steps: Average Loss 0.954 | Accuracy: 68%
[Step 800] Past 100 steps: Average Loss 0.671 | Accuracy: 81%
[Step 900] Past 100 steps: Average Loss 0.923 | Accuracy: 67%
[Step 1000] Past 100 steps: Average Loss 0.571 | Accuracy: 83%
--- Epoch 2 ---
[Step 100] Past 100 steps: Average Loss 0.447 | Accuracy: 89%
[Step 200] Past 100 steps: Average Loss 0.401 | Accuracy: 86%
[Step 300] Past 100 steps: Average Loss 0.608 | Accuracy: 81%
[Step 400] Past 100 steps: Average Loss 0.511 | Accuracy: 83%
[Step 500] Past 100 steps: Average Loss 0.584 | Accuracy: 89%
[Step 600] Past 100 steps: Average Loss 0.782 | Accuracy: 72%
[Step 700] Past 100 steps: Average Loss 0.397 | Accuracy: 84%
[Step 800] Past 100 steps: Average Loss 0.560 | Accuracy: 80%
[Step 900] Past 100 steps: Average Loss 0.356 | Accuracy: 92%
[Step 1000] Past 100 steps: Average Loss 0.576 | Accuracy: 85%
--- Epoch 3 ---
[Step 100] Past 100 steps: Average Loss 0.367 | Accuracy: 89%
[Step 200] Past 100 steps: Average Loss 0.370 | Accuracy: 89%
[Step 300] Past 100 steps: Average Loss 0.464 | Accuracy: 84%
[Step 400] Past 100 steps: Average Loss 0.254 | Accuracy: 95%
[Step 500] Past 100 steps: Average Loss 0.366 | Accuracy: 89%
[Step 600] Past 100 steps: Average Loss 0.493 | Accuracy: 89%
[Step 700] Past 100 steps: Average Loss 0.390 | Accuracy: 91%
[Step 800] Past 100 steps: Average Loss 0.459 | Accuracy: 87%
[Step 900] Past 100 steps: Average Loss 0.316 | Accuracy: 92%
[Step 1000] Past 100 steps: Average Loss 0.460 | Accuracy: 87%

--- Testing the CNN ---
Test Loss: 0.5979384893783474
Test Accuracy: 0.78*

我们的代码有效!仅在 3000 个训练步骤中,我们就从一个损失 2.3、准确率 10%的模型,变成了损失 0.6、准确率 78%的模型。

想自己尝试或修改这段代码吗? 在浏览器中运行本 CNN在 Github 上也有。

为了节省时间,我们在这个例子中只使用了整个 MNIST 数据集的一个子集——我们的 CNN 实现不是特别快。如果我们真的想训练一个 MNIST CNN,我们会使用一个 ML 库,比如 Keras 。为了展示我们 CNN 的强大,我使用 Keras 来实现和训练我们刚刚从头构建的完全相同的* CNN:*

完整的* MNIST 数据集(60k 训练图像)上运行该代码会得到如下结果:*

*Epoch 1
loss: 0.2433 - acc: 0.9276 - val_loss: 0.1176 - val_acc: 0.9634
Epoch 2
loss: 0.1184 - acc: 0.9648 - val_loss: 0.0936 - val_acc: 0.9721
Epoch 3
loss: 0.0930 - acc: 0.9721 - val_loss: 0.0778 - val_acc: 0.9744*

我们用这个简单的 CNN 实现了 97.4% 的测试准确率!有了更好的 CNN 架构,我们可以进一步改进——在这个官方的 Keras MNIST CNN 示例中,他们在 12 个时期后达到了 99.25% 的测试准确度。这个真的准确度好。

这篇帖子的所有代码都可以在Github上获得。**

现在怎么办?

我们完了!在这篇文章中,我们做了一个完整的演练如何训练一个卷积神经网络。然而,这仅仅是开始。您还可以做更多的事情:

  • 使用适当的 ML 库,如 Tensorflow 、 Keras 或 PyTorch ,尝试更大/更好的 CNN。
  • 了解如何将批处理规范化用于 CNN。
  • 了解数据扩充如何用于改善图像训练集。
  • 阅读 ImageNet 项目及其著名的计算机视觉竞赛 ImageNet 大规模视觉识别挑战赛( ILSVRC )。

最初发表于【https://victorzhou.com】

用 PyTorch 训练神经网络

原文:https://towardsdatascience.com/training-a-neural-network-using-pytorch-72ab708da210?source=collection_archive---------6-----------------------

“一知半解是一件危险的事情;(亚历山大·波普)深饮或尝不出皮耶里的春天

Human brain vs Neural network (image source here)

所以在之前的文章中,我们已经建立了一个非常简单和“幼稚”的神经网络,它不知道将输入映射到输出的函数。为了使它更加智能,我们将通过向它显示“真实数据”的例子来训练网络,然后调整网络参数(权重和偏差)。简而言之,我们在调整模型参数(权重和偏差)的同时,通过迭代训练数据集来提高精确度。

为了找到这些参数,我们需要知道我们的网络对真实输出的预测有多差。为此,我们将计算cost,也称为loss function

成本

Costloss function是我们预测误差的度量。通过相对于网络参数最小化loss,我们可以找到loss最小的状态,并且网络能够以高精度预测正确的标签。我们使用一个叫做gradient descent的过程找到这个minimum loss。在处检查不同种类的cost功能

梯度下降

梯度下降需要成本函数。我们需要这个cost函数,因为我们需要将其最小化,以便获得高预测精度。GD 的全部意义在于最小化cost函数。该算法的目标是到达最低值error value的过程。为了在成本函数中得到最低的error value(相对于一个权重),我们需要调整模型的参数。那么,我们需要调整参数到什么程度呢?我们可以使用calculus找到它。使用calculus我们知道函数的slope是关于值的函数的derivativegradient是损失函数的斜率,指向变化最快的方向。

在上反向传播

Gradient Descent对于单层网络来说实施起来很简单,但是对于多层网络来说,实施起来更复杂和更深入。多层网络的训练是通过反向传播完成的,这实际上是微积分中链式法则的应用。如果我们把一个两层网络转换成一个图形表示,这是最容易理解的。

image source: udacity course material

向前传球

在向前传递中,数据和操作是自下而上的。

步骤 1: 我们通过线性变换**𝐿1**将输入**𝑥**传递给权重**𝑊1**和偏差**𝑏1**

****第二步:然后输出经过 sigmoid 运算**𝑆**和另一个线性变换𝐿2

第三步:最后我们计算ℓ.的损失

我们用这个损失来衡量网络的预测有多糟糕。目标是调整weightsbiases以最小化损失。

偶数道次

为了用梯度下降来训练权重,我们通过网络反向传播损失的梯度。

每个操作在输入和输出之间都有一些梯度。

当我们向后发送梯度时,我们将引入的梯度与操作的梯度相乘。

从数学上来说,这实际上就是用链式法则计算损耗相对于重量的梯度。

我们使用这个梯度和一些学习速率α来更新我们的权重。

学习率α被设置为使得权重更新步长足够小,使得迭代方法稳定在最小值。

点击了解更多关于 backprop 的信息

PyTorch 的损失

PyTorch 提供了损失,如交叉熵损失 nn.CrossEntropyLoss。对于像 MNIST 这样的分类问题,我们使用 softmax 函数来预测分类概率。

为了计算loss,我们首先定义criterion,然后传入网络的output,并修正标签。

nn.CrossEntropyLoss标准将nn.LogSoftmax()nn.NLLLoss()组合在一个类中。

输入应该包含每个类的分数。

也就是说,我们需要将网络的原始输出传递给损耗,而不是 softmax 函数的输出。这种原始输出通常被称为*logits**scores* 我们使用logits是因为softmax给出的概率通常非常接近于zeroone,但浮点数不能准确地表示接近 0 或 1 的值(在此阅读更多信息)。通常最好避免用概率进行计算,通常我们使用对数概率。

亲笔签名

Torch 提供了一个名为autograd的模块来自动计算张量的。这是一种计算导数的引擎。它记录在梯度激活张量上执行的所有操作的图形,并创建一个非循环图形,称为动态计算图形。该图的是输入张量,而是输出张量。****

Autograd的工作原理是跟踪在张量上执行的操作,然后通过这些操作向后前进,计算沿途的梯度。**

为了确保 PyTorch 跟踪张量上的操作并计算梯度,我们需要设置requires_grad = True。我们可以用torch.no_grad()关闭代码块的渐变。

训练网络

最后,我们需要一个optimizer来更新梯度权重。我们从 PyTorch 的[optim](https://pytorch.org/docs/stable/optim.html) 包中得到这些。例如,我们可以通过optim.SGD使用随机梯度下降。

训练神经网络的过程:

  • 通过网络向前传递
  • 使用网络输出来计算损耗
  • loss.backward()对网络进行反向遍历,以计算梯度
  • 使用优化器更新权重

我们将准备用于训练的数据:

**import torch
from torch import nn
import torch.nn.functional as F
from torchvision import datasets, transforms# Define a transform to normalize the data
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize((0.5,), (0.5,)),
                              ])# Download and load the training data
trainset = datasets.MNIST('~/.pytorch/MNIST_data/', download=True, train=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)**

用真实数据训练:

在一些术语中,一次遍历整个数据集被称为*epoch*。所以这里我们将循环通过trainloader来获得我们的训练批次。对于每一批,我们将进行一次训练,计算损失,进行一次反向训练,并更新权重。

**model = nn.Sequential(nn.Linear(784, 128),
                      nn.ReLU(),
                      nn.Linear(128, 64),
                      nn.ReLU(),
                      nn.Linear(64, 10),
                      nn.LogSoftmax(dim=1))# Define the loss
criterion = nn.NLLLoss()# Optimizers require the parameters to optimize and a learning rate
optimizer = optim.SGD(model.parameters(), lr=0.003)epochs = 5
for e in range(epochs):
    running_loss = 0
    for images, labels in trainloader:
        # Flatten MNIST images into a 784 long vector
        images = images.view(images.shape[0], -1)

        # Training pass
        optimizer.zero_grad()

        output = model(images)
        loss = criterion(output, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
    else:
        print(f"Training loss: {running_loss/len(trainloader)}")**

N 注:optimizer.zero_grad():当我们用相同的参数进行多次反向传递时,梯度就会累积。这意味着我们需要在每次训练过程中将梯度归零,否则我们将保留以前训练批次的梯度。

看吧!训练损失在每一个时期都在下降。

随着网络的训练,我们可以检查它的预测。

Prediction result after training

现在我们的网络是辉煌的!它能准确预测我们图像中的数字。是不是很酷?

声明:本文基于我在 facebook-udacity 奖学金挑战项目中的学习。

用迁移学习训练情绪检测器

原文:https://towardsdatascience.com/training-an-emotion-detector-with-transfer-learning-91dea84adeed?source=collection_archive---------10-----------------------

在这篇博文中,我们将讨论如何使用预先训练的计算机视觉模型、迁移学习以及使用谷歌图像创建自定义数据集的巧妙方法来快速创建情绪检测器。

注意:特定任务的代码片段包含在本文中,但是要重新创建结果,你应该参考代码库。

Figure 1. Applying the trained emotion detection model on the cast of Friends

让我们得到一些数据

在任何机器学习任务中,要做的第一件事就是收集数据。我们需要的是成千上万张带有面部表情标签的图像。公开的 FER 数据集 [1]是一个很好的起点,有 28,709 张带标签的图片。我们将使用他们标签的子集作为我们的目标情绪:

  • 愤怒的
  • 厌恶的
  • 幸福的
  • 悲哀的
  • 惊讶的

但是,由于这些图像的分辨率只有 48 x 48,因此最好也有一个具有更丰富功能的数据集。为此,我们将使用Google _ Images _ downloadpython 包从 Google Images 中查询和抓取数据。

这种方法的好处是:( a)它从“野外”检索成千上万的图像,( b)我们可以使用查询中的关键字自动标记图像。

当查询谷歌图片时,通常你在结果列表中走得越远,它们就变得越不相关。这意味着我们应该为每次查询返回的图像数量设定一个限制。

为了增加图像的数量,可以使用同义词对每种情感执行几个查询。例如,除了“快乐”,我们还可以查询“微笑”、“愉快”和“兴高采烈”。

大部分的查询应该被结构化为“人脸”。事实证明,如果在查询中不包含“人类”,那么大部分图片都是表情符号😊

下面的代码片段显示了我们如何配置图像抓取器并检索最多 1000 个“快乐”图像。

这里需要注意一些事情:

  1. 要使用这个库,必须下载 chrome 驱动程序。详见本页。
  2. Google Images 限制了返回的项目数量(通常少于 1000 个)

太好了,我们现在有两个不同来源的面部表情标签了!

寻找面孔

在我们训练情绪检测器之前,我们首先必须能够定位每张图像中的人脸。由于目标是从面部表情中对情绪进行分类,因此只保留我们找到的面部并丢弃所有其他(大部分不相关)特征是有意义的。

幸运的是,有一些开源库提供了预先训练好的人脸检测模型。对于这个项目,我们将使用 facenet-pytorch 库,它提供了一个在 VGGFace2 和 CASIA-Webface 数据集上预先训练的多任务 CNN [2]。

下面的代码片段显示了我们如何加载预训练的 MTCNN 模型,并使用它来为图像中的每个人脸找到一个边界框。

这有两个应用:

  1. 为了训练,我们将把我们的图像过滤成只有一张脸的图像(查询到的有多张脸的图像可能与目标情感不太相关),然后使用得到的边界框从图像中裁剪出该脸。
  2. 在情感分类器被训练后,人脸检测模型将被用于从一幅图像中提取所有人脸,并将它们分别馈送给模型(例如,参见图 1 )。

一旦人脸从每张图像中分离出来,它就会被调整到标准形状,然后转换成单通道灰度图像(见图 2 )。后一步是确保模型将专注于实际的面部表情,而不是学习颜色可能带来的任何偏见。

例如,“sad”查询更可能包含已经是黑白的图像。强制所有图像为灰度将消除这种偏见。

Figure 2. The first step crops the face from the raw image using an open-source, pre-trained face detection model. The second step resizes the image and transforms it to grayscale.

准备基础模型

由于我们没有大型数据集,我们应该避免从头开始训练我们的分类器。正如大多数计算机视觉转移学习任务中常见的那样,我们将继续对 ImageNet 上预先训练的模型进行微调,ImageNet 是一个数据集,包含数百万张来自一千个不同标签的图像。

这里的目标是通过给它的参数一个好的起点,使我们的模型更容易训练。它可以利用从 ImageNet 学到的现有特征提取器,并调整它们来完成这项新任务。

对 ImageNet 预训练模型的一个警告是,它们期望它们的输入是 RGB 图像。我们可以通过将图像转换为三通道灰度图像来回避这个问题。虽然这可行,但不是最佳的,因为我们将模型外推至新的特征空间(ImageNet 不包含灰度图像)。

相反,让我们用一个随机初始化的单通道卷积层替换模型中的第一个(三通道)卷积层。我们将使用 Resnet-50 [3]作为我们的模型。

下一步是微调这个模型,以便在给定灰度输入时,它使用彩色输入模拟原始模型的输出。图 3 中概述了培训流程。

Figure 3. Fine-tuning Resnet-50 using grayscale versions of ImageNet

这里,RGB 图像作为输入被馈送到预训练的 Resnet-50 模型。该图像还被转换为灰度,并作为输入馈送到修改后的“Gray Resnet-50”,其中第一卷积层现在接受单通道输入。

然后,两个输出嵌入通过 L2 损失函数。尽管有大量的计算在进行,反向传播步骤中唯一更新的参数是“Gray Resnet”模型中的第一个单通道卷积层。

这个过程是无人监督的,这意味着我们可以在任何数据集上微调模型,而不用担心找到标签。我最终使用同一个谷歌图片抓取器为每个标签下载了 10 张图片。所有 1000 个 ImageNet 标签见该资源。

图 4 在两幅不同的图像上比较原始模型和修改后的版本,每幅图像都有彩色和灰度版本。对于有金翅雀的那一对,“灰色 Resnet”模型对这只鸟是金翅雀的信心较低,因为它看不到这只鸟与众不同的黄色羽毛。

对于有疣猪的那一对,“灰色 Resnet”模型比原始模型对其预测有更高的信心。作为一种推测,这可能是因为原始模型专注于皮毛的颜色(疣猪和公猪有相似的棕色皮毛),而“灰色 Resnet”可以专注于结构差异。

Figure 4. The top-3 predicted labels of the original Resnet and the “Gray Resnet” model for two pairs of images.

这一微调步骤的目标是建立一个预训练模型,该模型较少关注颜色,而更多关注形状和结构。

面部训练

现在我们有了基本模型,让我们应用迁移学习对情绪进行分类!这将涉及我们的预训练“灰色 Resnet”模型的两个阶段的微调。

第一阶段涉及对 FER 数据集的微调。这将作为在“野生”数据上训练模型之前的中间步骤。由于影像的分辨率较低(48 x 48),我们希望模型能够从 FER 数据集中识别简单的要素。

第二阶段从第一阶段获取模型,然后根据“野生”数据进一步微调它。这里,模型将扩展先前的表示,以从“野生”数据中存在的更丰富的特征中学习。

在实践中,我发现,当所有的参数都允许训练时,FER 微调模型达到了最佳的验证分数。另一方面,当除了最后 11 层之外的所有层都被冻结时,对“野生”数据进行微调的模型获得了最好的分数(参见下面的代码,了解如何使用初始化的 Resnet-50 来实现这一点的示例)。

在第二阶段不允许训练整个模型的原因是因为在“野生”数据集中的例子较少。考虑到其大容量,如果在该阶段允许训练其所有参数,则该模型将更容易过度拟合。

下面的图 5 显示了 80:20 列车测试分割的 FER 数据的验证结果。该模型的总体准确度为 87.2%,并且似乎该模型发现“高兴”和“惊讶”情绪最成功。另一方面,该模型在区分“愤怒”和“悲伤”方面最为费力。也许这是因为这两种情绪通常都包含皱眉。

Figure 5. Evaluation metrics on the FER images

下面的图 6 显示了 70:30 训练测试分割的“野生”谷歌图像数据的验证结果。

Figure 6. Evaluation metrics on the scraped Google Images

乍看之下,该模型的性能似乎有所下降,因为整体精度已降至 63.9%。这是因为我们模型的特征空间已经改变了。这个“野生”数据集中的图像更加多样和嘈杂,使得它们比科学的 FER 基准更难分类。事实上,直接应用来自 FER 数据(第一阶段)的模型,而不对“野生”数据进行微调,其准确度低于 51%。

应用训练好的模型

现在模型已经训练好了,让我们找点乐子,试着把它应用到不同的图像上。

图 1 中,情绪检测器被应用到《老友记》的演员阵容中(为了方便起见,下面复制了这张图片)。这张图片突出了模型如何在“快乐”和“悲伤”的面孔之间做出决定。特别是,有更多曲线和露出牙齿的笑容比没有曲线和牙齿的笑容更能让人对“开心”产生更高的信心。

Figure 1. Applying the trained emotion detection model on the cast of Friends

在下面的图 7 中,该模型被应用于哈利波特角色。这里我们有五种目标情绪的例子。

Figure 7. Detecting emotions expressed by Harry Potter characters

我们甚至可以扩展这一模型,通过找到人脸并对每一帧中的情绪进行分类,来检测视频中的情绪(见下面的图 8 )。这个模型似乎把我做出的悲伤表情和惊讶混淆了,然而,这可能是因为我不擅长做出悲伤表情:)

Figure 8. Applying the emotion detector on a video

不足为奇的是,当目标情绪被强烈表现出来,并与更复杂/混合的面部表情斗争时,该模型似乎工作得很好。这可能是因为谷歌图片更有可能返回强烈表达的情感,因为它们与查询更相关。

结束语

我开始这个项目是为了通过利用大量现有的开源工作来创造一些有趣的东西。这样做让我能够快速旋转项目的重要部分,这反过来又让我能够专注于学习这些部分是如何工作的,以及我可以将它们粘合在一起的最佳方式。

请注意,根据从 Google Images scraper 返回的数据量,花一些时间手动检查结果可能是个好主意。例如,在我的例子中,返回了 5000 多张图片,我花了大约 30 分钟浏览数据并删除任何错误标记/无意义的图片。

改进项目的一些潜在方法包括:

  1. 使用预训练的面部检测模型作为基础模型(而不是 ImageNet)
  2. 对微调步骤进行更多的实验(例如,应该允许训练多少层?)
  3. 使用与面部图像串联的面部标志数据/模型

代码库:【https://github.com/martin-chobanyan/emotion】T2

参考

[1] I. J. Goodfellow,D. Erhan,P. L. Carrier,A .库维尔,M. Mirza,B. Hamner,W. Cukierski,Y. Tang,D. Thaler,D.-H. Lee 等人,“表征学习中的挑战:关于三次机器学习竞赛的报告”,国际神经信息处理会议。施普林格,2013

[2]蔡、、、和杨百奇."基于多任务级联卷积网络的联合头部姿态估计用于人脸对齐." 2018 年第 24 届国际模式识别大会(ICPR) ,2018

[3]何、、、、任、。"图像识别的深度剩余学习." 2016 年 IEEE 计算机视觉与模式识别大会(CVPR) ,2016

浏览器中的机器学习:为自定义图像分类训练和服务 Mobilenet 模型

原文:https://towardsdatascience.com/training-custom-image-classification-model-on-the-browser-with-tensorflow-js-and-angular-f1796ed24934?source=collection_archive---------19-----------------------

Photo by Louis Hansel on Unsplash

Tensorflow.js

有几种方法可以微调深度学习模型,但在 web 浏览器上使用 WebGL 加速是我们不久前经历的事情,引入了 Tensorflow.js 。我将使用 Tensorflow.js 与 Angular 一起构建一个 Web 应用程序,该应用程序在 Mobilenet 和 Kaggle 数据集的帮助下训练卷积神经网络来检测疟疾感染的细胞,该数据集包含 27.558 个感染和未感染的细胞图像。

演示 WebApp

访问现场演示应用程序查看运行中的代码。该应用程序在 Google Chrome 浏览器中运行没有任何问题。

访问我的 GitHub repositor y 获取该项目的完整代码。您可以在此存储库的资产文件夹中找到图像,以及将图像加载到浏览器所需的 CSV 文件。您应该解压缩这些图像,并将它们放入您正在处理的 Angular 项目的 assets 文件夹中。

作为基础模型的 Mobilenet

正如我上面提到的,我将使用“mobilenet”作为自定义图像分类器的基础模型。预训练的“mobilenet”模型,兼容 tensorflow.js,相对较小(20MB),可以直接从 Google API 存储文件夹下载。

未感染和寄生细胞,这是我想用我们的定制模型分类的两个类别,而原始的“mobilenet”模型被训练来分类 1000 个不同的对象。

我将使用除最后 5 层之外的所有“mobilenet”层,并在这个截断模型的顶部添加一个具有 2 个单元和 softmax 激活的密集层,以使修改后的模型适合我们的分类任务。

我不会训练所有的层,因为这将需要大量的时间和计算能力。这对于我们的情况也是不必要的,因为我们使用预先训练的模型,该模型已经学习了许多表示。相反,我将冻结大多数层,只保留最后 2 层可训练。

疟疾细胞图像的预处理

在开始编码之前,我们必须考虑如何在训练期间将图像输入到我们的定制模型中。mobilenet 模型需要特定的图像大小(224x224x3)和图像预处理操作,我们必须对图像应用相同的预处理,然后才能将它们提供给我们的模型。此外,为了不使我们的模型偏向一个类,我们必须在训练时期为每个类提供相同数量的图像。

Photo by Paweł Czerwiński on Unsplash

Angular WebApp 正在初始化

在我们清楚了模型和数据集之后,是时候使用 Angular 命令行界面来初始化 Angular web 应用程序了。

npm install -g @angular/cli
ng new TFJS-CustomImageClassification
cd TFJS-CustomImageClassification

然后我会使用' nmp '包管理器来安装 tensorflow.js 库。为了完善 web 应用程序,我将使用角状材料类。

TFJS-CustomImageClassification **npm install @tensorflow/tfjs --save** TFJS-CustomImageClassification **ng add @angular/material**

生成基于自定义 Mobilenet 的模型

首先,让我们开始编码,生成一个函数来修改预训练的模型,以便我们可以使用这个修改后的模型来完成我们的特定任务,即对感染疟疾的图像进行分类。由于我不想从头开始训练模型,我将冻结所有层,除了我需要重新训练微调模型的层。

//-------------------------------------------------------------
// modifies the pre-trained mobilenet to detect malaria infected
// cells, freezes layers to train only the last couple of layers
//-------------------------------------------------------------
async getModifiedMobilenet()
{
 *const* trainableLayers=     ['denseModified','conv_pw_13_bn','conv_pw_13','conv_dw_13_bn','conv _dw_13'];
 *const* mobilenet =  await
 tf.loadLayersModel('https://storage.googleapis.com/tfjs- models/tfjs/mobilenet_v1_0.25_224/model.json');*console*.log('Mobilenet model is loaded')
 *const* x=mobilenet.getLayer('global_average_pooling2d_1');
 *const* predictions= <tf.SymbolicTensor> tf.layers.dense({units: 2,  activation: 'softmax',name: 'denseModified'}).apply(x.output); 
 *let* mobilenetModified = tf.model({inputs: mobilenet.input, outputs:  predictions, name: 'modelModified' });
 *console*.log('Mobilenet model is modified')mobilenetModified =
 this.freezeModelLayers(trainableLayers,mobilenetModified)
 *console*.log('ModifiedMobilenet model layers are freezed')mobilenetModified.compile({loss: categoricalCrossentropy,  optimizer: tf.train.adam(1e-3), metrics:   ['accuracy','crossentropy']});mobilenet.dispose();
 x.dispose();
 return mobilenetModified
}
//-------------------------------------------------------------
// freezes mobilenet layers to make them untrainable
// just keeps final layers trainable with argument trainableLayers
//-------------------------------------------------------------freezeModelLayers(*trainableLayers*,*mobilenetModified*)
{
 for (*const* layer of mobilenetModified.layers)
 {
  layer.trainable = false;
  for (*const* tobeTrained of trainableLayers)
  {
    if (layer.name.indexOf(tobeTrained) === 0)
     {
      layer.trainable = true;
      break;
     }
   }
  }
 return mobilenetModified;
}

Photo by Toa Heftiba on Unsplash

准备培训数据

为了训练该模型,我们需要 224×224×3 形状张量和另一个包含 1,0 值的 1 维张量中的未感染和感染细胞图像来指示图像的类别。我要做的是读取包含图像 src 和类信息的 CSV 文件,然后生成 HTMLImageElement 以在浏览器中查看它们。Capture()函数然后将获取图像 id,以便从浏览器上的图像生成所需的图像张量。请注意,我们必须预处理图像张量,因为 mobilenet 需要标准化的输入。老实说,我在这里使用的数据管道并不是正确的方式,因为我是一次将整块图像数据加载到内存中。使用 tf.fitDataset 并在需要时迭代使用内存会好得多。

//-------------------------------------------------------------
// this function generate input and target tensors for the training
// input tensor is produced from 224x224x3 image in HTMLImageElement
// target tensor shape2 is produced from the class definition
//-------------------------------------------------------------
generateData (*trainData*,*batchSize*)
{
  *const* imageTensors = [];
  *const* targetTensors = [];*let* allTextLines = this.csvContent.split(/\r|\n|\r/);
  *const* csvSeparator = ',';
  *const* csvSeparator_2 = '.';for ( *let* i = 0; i < batchSize; i++)
  {
    // split content based on comma
    *const* cols: *string*[] = allTextLines[i].split(csvSeparator);
    *console*.log(cols[0].split(csvSeparator_2)[0])if (cols[0].split(csvSeparator_2)[1]=="png")
    {
     *const* imageTensor = this.capture(i);
      *let* targetTensor   =tf.tensor1d([this.label_x1[i],this.label_x2[i]]);
      targetTensor.print();
      imageTensors.push(imageTensor);
      targetTensors.push(targetTensor);
    }
  }
  *const* images = tf.stack(imageTensors);
  *const* targets = tf.stack(targetTensors);
  return {images, targets};
}
//-------------------------------------------------------------
// converts images in HTMLImageElement into the tensors
// takes Image Id in HTML as argument
//-------------------------------------------------------------
capture(*imgId*)
{
  // Reads the image as a Tensor from the <image> element.
  this.picture = <HTMLImageElement> document.getElementById(imgId);
  *const* trainImage = tf.browser.fromPixels(this.picture);
  // Normalize the image between -1 and 1\. The image comes in  between  0-255, so we divide by 127 and subtract 1.
  *const* trainim =  trainImage.toFloat().div(tf.scalar(127)).sub(tf.scalar(1));
  return trainim;
}

Cell Images listed in Web App

微调模型

当我们准备好数据和模型时,现在是时候对模型进行微调,以便它可以对感染疟疾的细胞图像进行分类。为了减少训练过程的时间,我将总共使用 120 幅图像,5 个时期的训练过程,每个时期包含 24 幅图像。损失函数为' 类别交叉熵 ''一个 坝优化器 ' 用于学习率值相对较小的训练。我使用 Keras 提供的“on batchend回调函数将每个历元的训练指标写入控制台。一旦训练完成,我们必须释放张量来释放内存。最后一步,我们将把训练好的模型保存到我们的本地存储器中,以便以后用于推理。

async fineTuneModifiedModel(*model*,*images*,*targets*)
{
  *function* onBatchEnd(*batch*, *logs*)
  {
    *console*.log('Accuracy', logs.acc);
    *console*.log('CrossEntropy', logs.ce);
    *console*.log('All', logs);
  }
  *console*.log('Finetuning the model...');

  await model.fit(images, targets,
  {
    epochs: 5,
    batchSize: 24,
    validationSplit: 0.2,
    callbacks: {onBatchEnd}
    }).then(*info* *=>* {
    *console*.log
    *console*.log('Final accuracy', info.history.acc);
    *console*.log('Cross entropy', info.ce);
    *console*.log('All', info);
    *console*.log('All', info.history['acc'][0]);

    for ( *let* k = 0; k < 5; k++)
    {
      this.traningMetrics.push({acc: 0, ce: 0 , loss: 0});
      this.traningMetrics[k].acc=info.history['acc'][k];
      this.traningMetrics[k].ce=info.history['ce'][k];
      this.traningMetrics[k].loss=info.history['loss'][k];
    }
    images.dispose();
    targets.dispose();
    model.dispose();
  });
}

Photo by Kym MacKinnon on Unsplash

完整代码

访问 my GitHub repositor y 获取该项目的完整代码。您可以在这个存储库的 assets 文件夹中找到图像,以及将图像加载到浏览器所需的 CSV 文件。您应该解压缩这些图像,并将它们放入您正在处理的 Angular 项目的 assets 文件夹中。

演示 WebApp

访问现场演示应用查看运行中的代码。该应用程序在 Google Chrome 浏览器中运行没有任何问题。

训练数据,是什么?谁在做?

原文:https://towardsdatascience.com/training-data-what-is-it-whos-doing-it-b1710eca4dfd?source=collection_archive---------29-----------------------

半魔法半机器半人类?这是什么?

最著名的是“土耳其人”,上面的两张照片展示了沃尔夫冈·冯·肯佩兰在 1770 年的创作。它是在他试图给当时的奥地利女皇留下深刻印象时亮相的, 机器似乎有能力在那个时期下棋并击败一些最聪明的头脑。 它有会动的眼睛和手臂,如果对手拖得太久,它会敲击桌子。那些与这种机制对弈并输给它的对手包括拿破仑·波拿巴、埃德加·爱伦·坡、本杰明·富兰克林以及当时许多其他国际象棋大师。

土耳其人是那个时代的工程奇迹:一个人被机器打败了。这个想法本身扰乱了遇到这个神秘机器的群众,并引起了他们的惊奇。有数百本关于其功能的书籍和理论出版,激发了无数不同的发明。今天被认为是“计算之父”的查尔斯·巴贝奇在 1819 年伦敦比赛后,受到启发,开始思考机械计算机;这导致了他的数字可编程计算机的概念。

但是这个令人惊叹的机械奇观对于它的工作原理有许多怀疑者和不相信者,最著名的是埃德加·爱伦·坡。嗯…,埃德加没有错。

他提议,在为观众做开场演示时,桌子上有足够的空间让一个人隐藏和移动。

土耳其人仍然能够击败许多棋手的原因是,当时大多数有天赋的棋手无法仅靠下棋谋生,所以可以把它视为一种兼职骗局。

这与今天有什么关系?Mturk.com(MechanicalTurk)

Amazon Mechanical Turk 是一个"众包市场,让个人和企业更容易将他们的流程和工作外包给分散的员工,他们可以虚拟地执行这些任务。它基本上是一个让人类修复或手动输入计算机程序难以完成的任务的平台。这可以是任何事情,从插入收据中的数据,到找到度假租赁的地址。上图和下图显示了业务平台和员工对所有可用任务/工作的看法,以及工资。Mturk 对机器学习工作流和所有类型的业务处理外包都有很大的应用;想一想按需分配微任务。

等等,谁在做这项工作?人工智能还是人类?

关于这个平台,我想到了两个问题。难道人工智能程序不应该足够智能来计算这些看起来如此简单的任务吗?还是说 Mturk 更像是一个训练那些人工智能的平台?

更好地了解人工智能和培训数据

在不深入了解人工智能的情况下,一个简单的理解是“算法流水线”。将人工智能周围的所有气泡视为输入系统的算法,这使它变得智能。

它从特定领域获取数据,执行一系列计算,并给出预测。传统算法和人工智能算法的一个关键区别是,一个是手动编程的,而另一个是自我学习的。所有这一切都是由于训练数据的缘故,它可以根据成千上万的例子区分输入和输出。

什么样的训练数据?

与 Mturk 目的相关,干净且有标签的数据是非常理想的。来自真实世界的原始数据是杂乱的,通常需要人类对其进行分类,因此算法知道要“训练”什么,人工智能系统知道要“学习”什么。即使有一个好的系统,有时事情也不会像预期的那样完美,因为没有考虑到现实生活中的影响。所以当这种情况发生时,把任务交给更聪明的东西:人类。

科技公司有一条双向道,让公众了解他们的技术背后实际是什么。谷歌的军用无人机 A.I. 公开了他们如何使用来自众包数据标签公司 CrowdFlower 的“低薪工人”,后者更名为“Figure Figure 8”。公司也可能走上欺骗的道路,就像软件公司 Expensify 所做的那样。Expensify 是一家自动化公司,致力于处理编写各种费用报告的繁琐任务,开发了他们的下一个“惊人的”SmartScan 技术来处理它。但在现实中,就像惊人的“土耳其人”欺骗一样,它在幕后秘密地只是人类:许多实际上是 Mturk 工人!

别再说 Mturk 了,你一直在帮助训练人工智能

谷歌验证码:

你知道那些小测试网站必须确保你是一个人,而不是像那些骗人的机器人一样撒谎?嗯,谷歌使用它的验证码作为收集有用数据的一个很好的方式。想想你不得不说出的那些奇怪而模糊的话;您的正确答案可以帮助使用 Google vision 和书籍进行字符识别。那些不均匀和歪斜的数字呢?这听起来像是谷歌街景和帮助确认地址的一个很好的应用程序。我觉得谷歌的验证码最近主要集中在那些小方块上,在那里你可以从选择的图像中挑选出汽车、交通灯或街道标志。我会发现谷歌不太可能不将这些数据用于他们的自动驾驶汽车项目 Waymo。

脸书:

社交网络 goliath 拥有世界上最先进的面部识别系统之一。每个人都有许多照片,他们或他们的朋友会在里面贴上自己的标签。

  • 他们拥有开发一个伟大的系统所需的所有数据,该系统可以在你发布图片时自动标记你朋友的脸。
  • 数据积累与输入成本为 0 美元,因为用户已经这样做了。

我们是谷歌的试验品,还是任何人的?

谷歌的深度传感研究团队需要大量的镜头,移动相机从多个角度观察静态空间。你从哪里得到的?当然,2016 年至 2017 年期间的病毒人体模型挑战。

  • 该团队使用 2000 个 Youtube 挑战视频来训练他们的人工智能模型,以从运动视频中预测深度。

人工智能的神奇之处在于它是如何建立在人类智能的基础上的,但通常会设法超越它,超越人们认为可能的事情。训练数据是一个系统运行得如何的关键组成部分,可以通过互联网大量获得:这是今天人工智能繁荣的重要推动力。不要忘记,目前对你可以用作训练数据的内容没有“严格的”版权限制,…就目前而言。

作品引用:

[## 谷歌雇佣零工经济工人来提高人工智能在有争议的…

世界各地数百万零工经济工作者现在在所谓的人群工作者网站上谋生——这些工作属于…

theintercept.com](https://theintercept.com/2019/02/04/google-ai-project-maven-figure-eight/) [## 当人工智能需要人类助手时

多年来,亚马逊的机械土耳其人(mTurk)在科技界已经是一种公开的秘密,在这个地方,初出茅庐的…

www.theverge.com](https://www.theverge.com/2019/6/12/18661657/amazon-mturk-google-captcha-robot-ai-artificial-intelligence-mechanical-turk-humans) [## 亚马逊土耳其机械公司

获得全球化、按需、24x7 的劳动力亚马逊土耳其机器人是一个众包市场,它使…

www.mturk.com](https://www.mturk.com/) [## 清理人工智能周围的水。

大数据还是大炒作?

towardsdatascience.com](/clearing-the-water-around-a-i-5ca596dad1b9) [## Expensify 的“智能”扫描技术得到了人类的秘密协助

Expensify 是一家软件公司,它自动化了编写费用报告的痛苦任务。它使用…

qz.com](https://qz.com/1141695/startup-expensifys-smart-scanning-technology-used-humans-hired-on-amazon-mechanical-turk/)

批量训练:如何拆分数据?

原文:https://towardsdatascience.com/training-on-batch-how-to-split-data-effectively-3234f3918b07?source=collection_archive---------39-----------------------

三种将你的数据分割成批的方法,比较时间&内存效率和代码质量。

介绍

随着数据量的增加,训练机器学习模型的一种常见方法是对批处理应用所谓的训练。这种方法包括将数据集分割成一系列较小的数据块,一次一个地传递给模型。

在本帖中,我们将提出三个想法来拆分批量数据集:

  • 创造了一个“大”张量,
  • 用 HDF5 加载部分数据,
  • python 生成器。

出于说明的目的,我们将假设该模型是一个基于声音的检测器,但本文中的分析是通用的。尽管这个例子是作为一种特殊情况来设计的,但这里讨论的步骤本质上是对数据进行分割、预处理迭代。它符合普通程序。不管图像文件、来自 SQL 查询的表或 HTTP 响应的数据是什么,我们主要关心的是过程。

具体来说,我们将从以下几个方面比较我们的方法:

  • 代码质量,
  • 内存占用,
  • 时间效率。

什么是批?

形式上,批处理被理解为输入输出对(X[i], y[i]),是数据的子集。由于我们的模型是一个基于声音的检测器,它期望一个经过处理的音频序列作为输入,并返回某个事件发生的概率。很自然,在我们的例子中,该批次包括:

  • X[t] -表示在时间窗口内采样的处理过的音轨的矩阵,以及
  • y[t] -表示事件存在的二元标签,

其中t表示时间窗(图 1。).

Figure 1. An example of data input. Top: simple binary label (random), middle: raw audio channel (mono), bottom: spectrogram represented as naural logarithm of the spectrum. The vertical lines represent slicing of the sequence into batches of 1 second length.

光谱图

至于声谱图,你可以把它看作是一种描述每首“曲子”在音轨中所占比重的方式。例如,当演奏低音吉他时,声谱图会显示更集中在频谱较低一侧的高强度。相反,对于女高音歌手,我们会观察到相反的情况。通过这种“编码”,谱图自然地代表了模型的有用特征。

比较想法

作为我们比较的一个共同前提,让我们简单定义以下导入和常量。

from scipy.signal import spectrogram
from os.path import join
from math import ceil
import numpy as np

FILENAME = 'test'
FILEPATH = 'data'
CHANNEL  = 0        # mono track only
SAMPLING = 8000     # sampling rate (audio at 8k samples per s)
NFREQS   = 512      # 512 frequencies for the spectrogram
NTIMES   = 400      # 400 time-points for the spectrogram
SLEN     = 1        # 1 second of audio for a batch

N = lambda x: (x - x.mean())/x.std() # normalization

filename = join(FILEPATH, FILENAME)

这里的数字有些随意。我们决定采用最低采样率(其他常见值为 16k 和 22.4k fps),并让每个X组块成为 512 个频率通道的频谱图,该频谱图是使用沿时间轴的 400 个数据点从 1 的非重叠音频序列计算的。换句话说,每一批将是一对一个 512 乘 400 的矩阵,加上一个二进制标签。

想法 1——一个“大”张量

模型的输入是一个二维张量。由于最后一步涉及批次的迭代,因此增加张量的秩并为批次计数保留第三维是有意义的。因此,整个过程可以概括如下:

  1. 加载x-数据。
  2. 加载y标签。
  3. Xy分批切片。
  4. 提取每一批的特征(这里是谱图)。
  5. X[t]y[t]放在一起。

为什么这不是个好主意?让我们看一个实现的例子。

def create_X_tensor(audio, fs, slen=SLEN, bsize=(NFREQS, NTIMES)):
    X = np.zeros((n_batches, bsize[0], bsize[1]))

    for bn in range(n_batches):
        aslice = slice(bn*slen*fs, (bn + 1)*slen*fs)
        *_, spec = spectrogram(
                N(audio(aslice)), 
                fs       = fs, 
                nperseg  = int(fs/bsize[1]),
                noverlap = 0,
                nfft     = bsize[0])
        X[bn, :, :spec.shape[1]] = spec
    return np.log(X + 1e-6) # to avoid -Inf

def get_batch(X, y, bn):
    return X[bn, :, :], y[bn]

if __name__ == '__main__':
    audio = np.load(filename + '.npy')[:, CHANNEL]
    label = np.load(filename + '-lbl.npy')

    X = create_X_tensor(audio, SAMPLING)
    for t in range(X.shape[0]):
        batch = get_batch(X, y, t)
        print ('Batch #{}, shape={}, label={}'.format(
            t, X.shape, y[i]))

这种方法的本质可以被描述为现在全部加载,以后再担心。

虽然创建X一个自包含的数据块可以被视为一个优点,但这种方法也有缺点:

  1. 我们将所有数据导入 RAM,不管 RAM 是否能存储这些数据。
  2. 我们使用第一维度X进行批次计数。然而,这仅仅是基于一个惯例。如果下一次有人决定应该是最后一次呢?
  3. 尽管X.shape[0]准确地告诉我们有多少批次,我们仍然需要创建一个辅助变量t来帮助我们跟踪批次。这个设计强制模型训练代码遵守这个决定。
  4. 最后,它要求定义get_batch函数。其唯一目的是选择Xy的子集,并将它们整理在一起。它看起来充其量是不受欢迎的。

想法 2——使用 HDF5 加载批次

让我们从消除最可怕的问题开始,即将所有数据加载到 RAM 中。如果数据来自一个文件,那么只加载它的一部分并对这些部分进行操作是有意义的。

使用来自熊猫的 [read_csv](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)skiprowsnrows参数,可以加载. csv 文件的片段。然而,由于 CSV 格式对于存储声音数据来说相当不切实际,分层数据格式(HDF5) 是更好的选择。这种格式允许我们存储多个类似 numpy 的数组,并以类似 numpy 的方式访问它们。

这里,我们假设文件包含名为'audio''label'的固有数据集。更多信息请查看 Python h5py 库。

def get_batch(filepath, t, slen=SLEN, bsize=(NFREQS, NTIMES)):
    with h5.File(filepath + '.h5', 'r') as f:
        fs    = f['audio'].attrs['sampling_rate']
        audio = f['audio'][t*slen*fs:(t + 1)*slen*fs, CHANNEL]
        label = f['label'][t]

    *_, spec = spectrogram(
            N(audio),
            fs          = fs,
            nperseg     = int(fs/bsize[1]),
            noverlap    = 0,
            nfft        = bsize[0])
    X = np.zeros((bsize[0] // 2 + 1, bsize[1]))
    X[:, :spec.shape[1]] = spec
    return np.log(X + 1e-6), label

def get_number_of_batches(filepath):
    with h5.File(filepath + '.h5', 'r') as f:
        fs = f['audio'].attrs['sampling_rate']
        sp = f['audio'].shape[0]
    return ceil(sp/fs)

if __name__ == '__main__':
    n_batches = get_number_of_batches(filename)
    for t in range(n_batches):
        batch = get_batch(filename, t)
        print ('Batch #{}, shape={}, label={}'.format(
            i, batch[0].shape, batch[1]))

希望我们的数据现在是可管理的(如果以前不是的话)!此外,在整体质量方面,我们也取得了一些进步:

  1. 我们去掉了之前的get_batch函数,用一个更有意义的函数取而代之。它计算什么是必要的,并传递数据。简单。
  2. 我们的X张量不再需要人为修改。
  3. 事实上,通过将get_batch(X, y, t)改为get_batch(filename, t),我们抽象出了对数据集的访问,并从名称空间中移除了Xy
  4. 数据集也变成了一个单独的文件。我们不需要从两个不同的文件中获取数据和标签。
  5. 我们不需要提供fs(采样率)参数。得益于 HDF5 中所谓的属性,它可以成为数据集文件的一部分。

尽管有这些优点,我们仍然有两个…不便之处。

因为新的get_batch不记得状态。我们必须像以前一样使用循环来控制t。然而,由于get_batch中没有机制来告诉循环需要多大(除了添加第三个输出参数,这很奇怪),我们需要事先检查数据的大小。除了向get_batch添加第三个输出(这会使这个函数变得很奇怪)之外,它还要求我们创建第二个函数:get_number_of_batches

不幸的是,它并没有使解决方案尽可能优雅。如果我们只是将get_batch转换成一种能够保持状态的形式,我们可以做得更好。

想法 3——发电机

让我们来识别模式。我们只对一个接一个地访问、处理和传递数据片段感兴趣。我们不需要一下子全部用完。

对于这些机会,Python 有一个特殊的构造,即生成器。生成器是返回生成器迭代器的函数,迭代器不是急切地执行计算,而是在那时传递一点结果,等待被要求继续。完美,对吧?

生成器迭代器可以通过三种方式构建:

  • 通过类似于列表理解的表达:例如(i for i in iterable),但是使用()而不是[]
  • 发电机功能——用yield代替return,或
  • 来自定义自定义__iter__(或__getitem__)和__next__方法的类对象(见文档)。

在这里,使用yield自然符合我们需要做的事情。

def get_batches(filepath, slen=SLEN, bsize=(NFREQS, NTIMES)):
    with h5.File(filepath + '.h5', 'r') as f:
        fs = f['audio'].attrs['sampling_rate']
        n_batches = ceil(f['audio'].shape[0]/fs)

        for t in range(n_batches):
            audio = f['audio'][t*slen*fs:(t + 1)*slen*fs, CHANNEL]
            label = f['label'][t]
            *_, spec = spectrogram(
                    N(audio),
                    fs          = fs,
                    nperseg     = int(fs/bsize[1]),
                    noverlap    = 0,
                    nfft        = bsize[0])
            X = np.zeros((bsize[0] // 2 + 1, bsize[1]))
            X[:, :spec.shape[1]] = spec
            yield np.log(X + 1e-6), label

if __name__ == '__main__':
    for b in get_batches(filename):
        print ('shape={}, label={}'.format(b[0].shape, b[1]))

该循环现在位于函数内部。由于有了yield语句,只有在get_batches被调用t - 1次后才会返回(X[t], y[t])对。模型训练代码不需要管理循环的状态。该函数会记住调用之间的状态,允许用户迭代批处理,而不是使用一些人工的批处理索引。

将生成器迭代器比作包含数据的容器是很有用的。随着每一次迭代中批次的删除,容器在某个时候变空了。因此,索引和停止条件都不是必需的。数据被消耗,直到不再有数据,过程停止。

性能:时间和记忆

我们有意从讨论代码质量开始,因为它与我们的解决方案的发展方式紧密相关。然而,考虑资源限制同样重要,尤其是当数据量增长时。

图二。显示使用上述三种不同方法交付批次所需的时间。如我们所见,处理和移交数据所需的时间几乎相同。无论我们是加载所有要处理的数据,然后对其进行切片,还是从头开始一点一点地加载和处理,获得解决方案的总时间几乎是相等的。当然,这可能是拥有 SSD 的结果,SSD 允许更快地访问数据。尽管如此,所选择的策略似乎对整体时间性能没有什么影响。

Figure 2. Time performance comparison. The red-solid line refers to timing both loading the data to the memory and performing the computation. The red-dotted line times only the loop, where slices are delivered, assuming that data was precomputed. The green-dotted line refers to loading batches from HDF5 file and the blue-dashed-dotted line implements a generator. Comparing the red lines, we can see that just accessing of the data once it is in the RAM is almost for free. When data is local, the differences between the other cases are minimal, anyway.

当查看图 3 时,可以观察到更多的差异。考虑到第一种方法,它是所有方法中对内存需求最大的,会产生长达 1 小时的音频样本。相反,当分块加载数据时,分配的 RAM 由批处理大小决定,使我们安全地低于限制。

Figure 3. Memory consumption comparison, expressed in terms of the percentage of the available RAM being consumed by the python script, evaluated using: (env)$ python idea.py & top -b -n 10 > capture.log; cat capture.log | egrep python > analysis.log, and post-processed.

令人惊讶的是(或者不是),第二种和第三种方法之间没有明显的区别。该图告诉我们,选择或不选择实现生成器迭代器对我们的解决方案的内存占用没有影响。

这是很重要的一点。通常鼓励使用生成器作为更有效的解决方案,以节省时间和内存。相反,该图显示,就资源而言,生成器本身并不能提供更好的解决方案。重要的是我们访问资源的速度有多快,我们一次能处理多少数据。

使用 HDF5 文件被证明是有效的,因为我们可以非常快速地访问数据,并且足够灵活,我们不需要一次加载所有数据。同时,生成器的实现提高了代码的可读性和质量。虽然我们也可以将第一种方法构建成生成器的形式,但这没有任何意义,因为如果不能加载少量数据,生成器只会改进语法。因此,最好的方法似乎是同时使用加载部分数据和生成器,这由第三种方法表示。

结束语

在这篇文章中,我们介绍了三种不同的方法来分割和处理我们的数据。我们比较了每种方法的性能和整体代码质量。我们也说过,生成器本身并不能提高代码的效率。最终的性能由时间和内存约束决定,但是,生成器可以使解决方案更加优雅。

你觉得哪个解决方案最有吸引力?

还会有更多…

我计划把文章带到下一个层次,并提供简短的视频教程。

如果您想了解关于视频和未来文章的更新,订阅我的 简讯 。你也可以通过填写表格让我知道你的期望。回头见!

原载于https://zerowithdot.com

使用员工的幸福指数预测工作场所的生产力

原文:https://towardsdatascience.com/training-regression-models-bfd779a73a60?source=collection_archive---------17-----------------------

训练回归模型

Y 你已经观察到,在过去的几年里,快乐的员工是你公司的主要利润来源,在这些年里,你记下了所有员工的快乐指数和他们的工作效率。现在你有大量的员工数据躺在 excel 文件中,你最近听说 “数据是新的石油。将会胜出的公司正在使用数学。”——凯文·普兰克,安德玛创始人兼 CEO,2016。

您想知道是否也可以通过某种方式匹配这些数据来预测新员工的生产力,这些数据基于他们的幸福指数。这样你就能更容易地找出效率最低的员工(然后假设解雇他们——只是假设)。如果是这样的话,干杯!🎉—因为这篇博文将向你介绍一种机器学习算法(回归)来构建这个 AI 应用!

这篇博文的目的是…📚

提供训练回归模型的完整见解

目标观众是… 🗣 🗣 🗣

任何人都在寻找回归背后的数学的深入而易懂的解释

本教程结束时…🔚

你将会对回归的本质有一个完整的了解😃你对 ML 的理解将会提高👍是的,你将能够识别出你效率最低的员工!

现在是路线图…..🚵

里程碑# 1 : 什么是回归,它与分类有何不同?

里程碑# 2.1 : 训练回归模型——决定损失函数作为回归模型的评价指标

里程碑# 2.2 : 训练回归模型——梯度下降

里程碑# 2.3 : 训练回归模型——使用梯度下降 完成简单回归模型的遍历

里程碑# 3 : 利用训练好的回归模型进行智能预测!

里程碑# 4: 最后是结束语……

让我们开始吧!

什么是回归,它与分类有何不同?

在定义回归之前,让我们先定义连续变量和离散变量。

连续变量

连续变量是可以从它的无限可能值集中取任何值的变量——可能值的数量简直是数不清的。

离散变量

离散变量是可以从其有限的可能值集中取任何值的变量,可能值的数量是可数的。

区分分类和回归

在上述讨论的背景下,我们现在可以清楚地区分分类和回归。分类是从一组有限的值(显然是我们在训练中得到的值)中预测一个值(即一个类),而回归是从一组无限的可能值中预测一个值。例如,预测个人体重的模型是回归模型,因为其预测体重值有无限种可能性。一个人的体重可能是 12.0 千克或 12.01 千克或 12.21 千克,这种可能性是无限的,因此是一个回归模型。

举几个例子来进一步阐明分类的区别&回归

Classification & Regression Examples

里程碑 1 达成!👍

训练回归模型——决定损失函数作为回归模型的评估指标

假设我们有一个员工幸福指数和员工生产力的训练数据集,将它们绘制成下图。

该图显示了训练数据的基本模式是两个变量之间的线性关系。因此,训练一个广义回归模型将对这个线性关系/函数建模,即在许多可能的线中找到一条最佳拟合线。在此之后,一个看不见的数据点(测试时间示例)将根据在训练阶段学习的线性函数/趋势预测其值。

训练回归模型的摘要概述

假设我们已经知道一条线将很好地适合给定的数据集。为了对给定数据集的直线建模,我们现在需要找到梯度(m)和 y 轴截距(c)的最佳值。因此,在培训期间,我们试图学习 m 和 c 的最佳可能值。一旦我们有了这些值,我们就可以简单地将给定幸福指数(即 x)的值代入学习的等式,并预测其对应的员工生产率,即 y。

Weights/Thetas — Learning Parameters

如果我们简单地使用准确性作为评估标准来评估我们模型的性能会怎么样?

假设我们训练了一个回归模型,现在我们需要评估它在测试集(理想情况下是验证集)上有多好。因此,我们将所有验证集数据点(x 值)插入到线性函数中,并预测它们对应的 y 值。

使用准确性作为回归模型的评估标准将总是导致训练、验证和测试集的准确性为 0!为什么?因为实际上来说,预测值可以非常接近真实的连续值,但很难与真实标签的完全相等。因此,由于预测标签和真实标签不匹配,准确性将始终为零。

Using Accuracy as Evaluation Metric for Regression

上面的例子表明,虽然预测值接近实际值,但并不完全相等,精度完全为 0。因此,使用准确性作为评估回归模型的评估标准是不明智的。我们需要定义另一个评估指标来评估我们模型的性能。

决定回归模型的评估标准

我们需要一个评估指标,以反映我们的训练模型的有效性,即如何推广。它不应该仅仅因为预测值和实际值不完全匹配就输出零值。相反,它应该能够以某种方式证明我们的最佳可能模型与理想模型(一个具有所有理想θ/权重的函数,但这在现实生活场景中几乎不可能)相比有多好。

定义 L1- 损失函数为评估度量

Notations for Loss Function

L1 — Loss Function

更小的损失值
如果预测值与实际值之间的总差值相对较小,则总误差/损失将是更小的值,因此表示模型良好。

更大的损失值
如果实际值和预测值之间的差异很大,损失函数的总误差/值也会相对较大,这也意味着模型没有被很好地训练。

作为均方误差的损失函数

L2 Loss Function

L2 损失/均方误差/二次损失—都是一样的

训练回归模型的目标 训练回归模型的目标是找到那些损失函数最小的权重值,即预测值和真实标签之间的差异尽可能最小。

为什么预测标签和真实标签永远不会完全匹配?

达到里程碑 2.1!👍 👍1️⃣

很多吗?休息一下再回来!

梯度下降算法

到目前为止,我们假设我们已经有了回归模型的权重。但是,实际上是找到这些权重的最佳可能值的过程说明了损失值的最小化。这一发现过程就是众所周知的算法“梯度下降”发挥作用的地方,如下所述。

梯度下降——直觉

假设你只是随机降落在一座山上,并且你是盲折叠。你的目标是尽快到达山脚。你会怎么做?一个可能的解决办法是向最陡的方向下降/移动,并在没有到达山脚时继续这样做。

下降时,你特别注意一些事情,以确保你确实到达了基点

  1. 因为你的目标是尽可能快地到达基点,所以你决定在开始的几个下降步骤中迈出更大的步伐。
  2. 因为你还想确保一旦你到达了更接近基地的地方,跳到任何上升点的机会就被最小化了。因此,你决定在后面的下降步骤中采取较小的跳跃,以确保在接近基点时不会偏离基点。

Gradient Descent — Intuition

梯度下降——数学观点

训练回归模型的目的是通过以与我们下降到山的底部时相同的方式收敛函数,找到/学习将最小化 L2 损失的权重。

定义梯度下降伪代码

深入探究 L2 损失的偏导数— 2.1.1

更新权重值— 2.1.2

Updating Weights to Minimize Loss

里程碑 2.2 达成!👍 👍2️⃣

训练回归模型——对梯度下降的完整遍历

现在我们已经熟悉了梯度下降的工作原理,让我们借助几个例子来进一步阐明它。

Gradient Descent Walk-through

上面例子中的一些假设

为了上面的例子,我们确实假设了一些事情。下图将这些假设与现实世界的情景进行了比较。

Example Assumptions

达到里程碑 2.3!👍 👍3️⃣

这标志着您的第二个里程碑已经完成!👍 ️👍

只要再多一点点,你就完成了!

使用训练好的回归模型进行智能预测!

一旦我们在训练阶段训练/调整了权重,对给定测试示例的预测就非常简单了——只需计算训练权重和给定测试示例特征的点积。

下图进一步阐明了这一点…

Generating Predictions at Run Time

里程碑 3 实现!👍 ️👍👍️

转到结论部分…..

1.调整学习率

Learning Rate — Hyperparameter

2 。为什么在培训中使用 1 的附加功能

Additional Training Feature of 1's

3.梯度下降需要特征归一化

应在数据预处理步骤中对要素进行范围归一化。否则,训练预测很可能会受到具有极端正值/负值的特征的影响。由于特征值确实会影响其对应的导数,极值可能会使学习过程变得更长,或者函数可能不会很好地收敛到基点——学习变得困难。因此,将你的特征标准化通常是个好主意。

4.用 L2 损失代替 L1 损失

你可能会奇怪,为什么我们不利用 L1 损失,而不是 L2 损失。其原因是 L1 损失的导数在 X=0 处未定义,梯度下降假设损失函数在任何地方都可以微分。因此,我们通常不喜欢使用 L1 损失。

5.关于梯度下降收敛的一点注记

达到里程碑 4!👍 👍 👍 👍

不要再做什么聪明的事情了!

你现在可以着手建立你自己的人工智能模型来预测你的员工的生产力!

这篇博文到此为止!

如果您有任何想法、意见或问题,欢迎在下面评论或联系📞跟我上LinkedIn

在 Google Colab 上训练 RetinaNet 从 KTH 手工工具数据集中检测钳子、锤子和螺丝刀。

原文:https://towardsdatascience.com/training-retinanet-to-detect-pliers-4dd47eb8b226?source=collection_archive---------18-----------------------

在本文中,RetinaNet 在 Google Colab 中接受了检测钳子、锤子和螺丝刀工具的训练。该数据集取自一个名为 KTH 手工工具数据集的开放来源。它包括三种类型的手工具的图像:锤子,钳子和螺丝刀在不同的照明和不同的位置。

Example of images of KTH Handtool Dataset [https://www.nada.kth.se/cas/data/handtool/].

Jupyter 文章的笔记本代码可以在我的 github 中的中找到。

首先在本地从源下载数据集(解压文件并重命名为 KTH _ 手工具 _ 数据集),然后将文件夹下载到 google drive。之后,我们应该将 google disc 安装到 google colab:

**from** **google.colab** **import** drive
drive.mount('/content/drive')

其次,需要准备数据来训练 RetinaNet:初始数据集中的所有图像都应该保存在不同的文件夹中,每个图像都有相关的边界框。为了训练 RetinaNet,我们需要创建一个 CSV 文件:该文件中的每一行都应该包含来自数据集的图像文件的名称、每个对象的边界框坐标以及该对象的类名。下面的脚本解析所有的文件夹(有 3 个文件夹是蓝色、白色和棕色背景的图片)。

要解析的第一个文件夹是“Blue_background”。此文件夹与“棕色 _ 背景”或“白色 _ 背景”的区别在于,带有乐器的文件夹不包含“Kinect”和“网络摄像头”子文件夹。

**from** **bs4** **import** BeautifulSoup
**import** **os**
**import** **csv**

folder = '/content/drive/My Drive/KTH_Handtool_Dataset'
subfolder = ['Blue_background']
in_subfolder = ['Artificial', 'Cloudy', 'Directed']
instruments = ['hammer1', 'hammer2', 'hammer3', 'plier1', 'plier2', 'plier3', 'screw1', 'screw2', 'screw3']

**with** open('train.csv', mode='w') **as** file:
  writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)  
  **for** folder_name **in** subfolder:
    **for** in_folder_name **in** in_subfolder:
      **for** instrument **in** instruments:
        directory_name = os.path.join(folder, folder_name, 'rgb', in_folder_name, instrument)
        directory_name_xml = os.path.join(folder, folder_name, 'bboxes', in_folder_name, instrument)
        **for** filename **in** os.listdir(directory_name_xml):
          label = instrument
          filename_jpg = filename[:-4] + '.jpg'
          filename_str = os.path.join(directory_name, filename_jpg)
          handler = open(os.path.join(directory_name_xml, filename)).read()
          soup = BeautifulSoup(handler, "xml")
          xmin = int(soup.xmin.string)
          xmax = int(soup.xmax.string)
          ymin = int(soup.ymin.string)
          ymax = int(soup.ymax.string)
          row = [filename_str, xmin, ymin, xmax, ymax, label]
          writer.writerow(row)

参数文件夹-存储所有数据的目录(提取的 KTH _ 手工具 _ 数据集文件夹的父目录)。

对于“白色 _ 背景”和“棕色 _ 背景”,脚本应该不同,因为它们在乐器的文件夹中包含子文件夹“Kinect”和“网络摄像头”(“锤子 1”、“锤子 2”、“锤子 3”、“plier1”、“plier2”、“plier3”、“screw1”、“screw2”、“screw3”)。我添加了这一行来包含这些文件夹

**for** sub_instrument **in** sub_instruments:

另一个诀窍是,kinect 的“rgb”文件夹和“bbox”文件夹有不同的名称:在一些文件夹中是“Kinect”,在另一些文件夹中是“Kinect”,因此我决定用不同的方法来解析图像目录(“rgb”文件夹)和边框目录(“bbox”文件夹)。字典用于更改名称:

dict_instr = {'Kinect': 'kinect'}

下一步:如果名称“kinect”不在 xml path 文件夹中,则它会变成小写的“Kinect”:

dir_name_xml = os.path.join(folder, folder_name, 'bbox', in_folder_name, instrument)
          **if** sub_instrument **not** **in** os.listdir(dir_name_xml):
            sub_instrument = dict_instr[sub_instrument]

结果,“棕色背景”和“白色背景”的脚本如下:

subfolder = ['Brown_background', 'White_background']
sub_instruments = ['Kinect', 'webcam']
dict_instr = {'Kinect': 'kinect'}

*# open file to write to the end of a file*
**with** open('train.csv', mode='a') **as** file:
  writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)  
  **for** folder_name **in** subfolder:
    **for** in_folder_name **in** in_subfolder:
      **for** instrument **in** instruments:
        **for** sub_instrument **in** sub_instruments:
          directory_name = os.path.join(folder, folder_name, 'rgb', in_folder_name, instrument, sub_instrument)
          dir_name_xml = os.path.join(folder, folder_name, 'bbox', in_folder_name, instrument)
          **if** sub_instrument **not** **in** os.listdir(dir_name_xml):
            sub_instrument = dict_instr[sub_instrument]
          directory_name_xml = os.path.join(dir_name_xml, sub_instrument)
          **for** filename **in** os.listdir(directory_name_xml):
            label = instrument
            filename_jpg = filename[:-4] + '.jpg'
            filename_str = os.path.join(directory_name, filename_jpg)
            handler = open(os.path.join(directory_name_xml, filename)).read()
            soup = BeautifulSoup(handler, "xml")
            xmin = int(soup.xmin.string)
            xmax = int(soup.xmax.string)
            ymin = int(soup.ymin.string)
            ymax = int(soup.ymax.string)
            row = [filename_str, xmin, ymin, xmax, ymax, label]
            writer.writerow(row)

运行上面的代码后,我们应该进行预处理,因为一些 xml 文件没有相关的图像:

**import** **pandas** **as** **pd**
**import** **os.path**

list_indexes_to_drop = []
data = pd.read_csv("train.csv", header=**None**)
**with** open('train_new.csv', mode='a') **as** file:
  **for** i **in** range(len(data)):
    fname = data.iloc[i, 0]
    **if** **not** os.path.isfile(fname):
      list_indexes_to_drop.append(i)

data = data.drop(data.index[list_indexes_to_drop])
data.to_csv(path_or_buf='train.csv', index=**False**, header=**None**)

预处理后,数据应该被分割。CSV 文件中的所有元素都被随机打乱

data = pd.read_csv("train.csv", header=**None**)
data = data.sample(frac=1).reset_index(drop=**True**)

然后,通过下一个代码将数据分为训练集(80%)和测试集(20%)。

amount_80 = int(0.8*len(data))
train_data = data[:amount_80]
test_data = data[amount_80:]print(len(train_data))
print(len(test_data))

我们应该将 train_data 保存为 train_annotations.csv:

train_data.to_csv(path_or_buf='train_annotations', index=False)

下一步是从网站上下载用于训练神经网络的权重,并将其放入“权重”文件夹中:

!mkdir weights
!wget -O /content/weights/resnet50_coco_best_v2.h5 https://github.com/fizyr/keras-retinanet/releases/download/0.5.1/resnet50_coco_best_v2.1.0.h5

我们还应该创建文件夹“快照”, RetinaNet 将在训练期间保存重量,以及“tensorboard ”,其中将解决关于训练的信息:

!mkdir /content/drive/My\ Drive/kth_article/snapshots
!mkdir /content/drive/My\ Drive/kth_article/tensorboard

下一步是创建 csv 文件“classes.csv”(包含仪器名称):

dict_classes = {
    'hammer1': 0,
    'hammer2': 1,
    'hammer3': 2,
    'plier1': 3,
    'plier2': 4,
    'plier3': 5,
    'screw1': 6,
    'screw2': 7,
    'screw3': 8
}
**with** open('classes.csv', mode='w') **as** file:
  writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
  **for** key, val **in** dict_classes.items():  
    row = [key, val]
    print(row)
    writer.writerow(row)

我们还需要安装 RetinaNet:

!cd ~!git clone [https://github.com/fizyr/keras-retinanet](https://github.com/fizyr/keras-retinanet)
%cd keras-retinanet!git checkout 42068ef9e406602d92a1afe2ee7d470f7e9860df!python setup.py install
!python setup.py build_ext --inplace

我们需要返回到父目录:

%cd ..

下一个脚本用于训练神经网络:

!retinanet-train --weights /weights/resnet50_coco_best_v2.h5 \
--batch-size 4 --steps 4001 --epochs 20 \
--snapshot-path snapshots --tensorboard-dir tensorboard \
csv train_annotations.csv classes.csv

train_annotations.csv :包含来自训练数据的所有图像的信息的文件,每个图像的格式应按照以下模板制作:< path_to_image >,< xmin >,< ymin >,< xmax >,< ymax >,< label >,其中 xmin,ymin,xmax,ymax 为以像素为单位的包围盒,label 为 a

labels.csv :带有类标签的文件,后面应该是模板:< class_name >,< id >

经过 3 个纪元的训练,我们会得到一些准确性。我们可以在训练数据上验证模型。另一种选择是在一些真实图像上测试准确性:

Image of real plier image (IKEA plier).

要在验证集上测试模型,我们需要将权重转换为测试格式:

!retinanet-convert-model snapshots/resnet50_csv_03.h5 weights/resnet50_csv_03.h5

要检查测试集的结果:

!retinanet-evaluate csv val_annotations.csv classes.csv weights/resnet50_csv_03.h5

我们可以看到,在测试集上,经过多次训练后的结果已经很好了,平均精度为 66%:

116 instances of class hammer1 with average precision: 0.7571
113 instances of class hammer2 with average precision: 0.6968
110 instances of class hammer3 with average precision: 0.8040
123 instances of class plier1 with average precision: 0.5229
119 instances of class plier2 with average precision: 0.5567
122 instances of class plier3 with average precision: 0.8953
126 instances of class screw1 with average precision: 0.4729
152 instances of class screw2 with average precision: 0.5130
131 instances of class screw3 with average precision: 0.7651
mAP: 0.6649

同时,在真实环境中也不太好:为了检查它,我们可以在我们的图像上运行 Retinanet 的预测。

*# show images inline*
%matplotlib inline

*# automatically reload modules when they have changed*
%load_ext autoreload
%autoreload 2

*# import keras*
**import** **keras**

*# import keras_retinanet*
**from** **keras_retinanet** **import** models
**from** **keras_retinanet.utils.image** **import** read_image_bgr, preprocess_image, resize_image
**from** **keras_retinanet.utils.visualization** **import** draw_box, draw_caption
**from** **keras_retinanet.utils.colors** **import** label_color
*#from keras_retinanet.keras_retinanet.utils.gpu import setup_gpu*

*# import miscellaneous modules*
**import** **matplotlib.pyplot** **as** **plt**
**import** **cv2**
**import** **os**
**import** **numpy** **as** **np**
**import** **time**

*# use this to change which GPU to use*
gpu = 0

*# set the modified tf session as backend in keras*
*#setup_gpu(gpu)*

*# adjust this to point to your downloaded/trained model*
*# models can be downloaded here: https://github.com/fizyr/keras-retinanet/releases*
model_path = os.path.join('..', 'weights', 'resnet50_csv_04.h5')

model = models.load_model(model_path, backbone_name='resnet50')

*# if the model is not converted to an inference model, use the line below*
*# see: https://github.com/fizyr/keras-retinanet#converting-a-training-model-to-inference-model*
*#model = models.convert_model(model)*

*#print(model.summary())*

*# load label to names mapping for visualization purposes*
labels_to_names = {
    0: 'hammer1', 
    1: 'hammer2',
    3: 'hammer3',
    4: 'plier1',
    5: 'plier2',
    6: 'plier3',
    7: 'screw1',
    8: 'screw2',
    9: 'screw3'}

*# load image*
image = read_image_bgr('/content/img.jpg')

*# copy to draw on*
draw = image.copy()
draw = cv2.cvtColor(draw, cv2.COLOR_BGR2RGB)

*# preprocess image for network*
image = preprocess_image(image)
image, scale = resize_image(image)

*# process image*
start = time.time()
boxes, scores, labels = model.predict_on_batch(np.expand_dims(image, axis=0))
print("processing time: ", time.time() - start)

*# correct for image scale*
boxes /= scale

*# visualize detections*
**for** box, score, label **in** zip(boxes[0], scores[0], labels[0]):
    *# scores are sorted so we can break*
    **if** score < 0.21:
        **break**

    color = label_color(label)

    b = box.astype(int)
    draw_box(draw, b, color=color)

    caption = "**{}** **{:.3f}**".format(labels_to_names[label], score)
    draw_caption(draw, b, caption)

plt.figure(figsize=(15, 15))
plt.axis('off')
plt.imshow(draw)
plt.show()

我取了 21%的阈值,所以模型预测仪器的准确率是 22%。

Retinanet prediction on a real photo after 4 epochs of training on KTH_Dataset.

我们可以进一步训练模型以改进模型,并且训练模型超过 4 个时期。

结论。

本文是研究的一部分,我们想要创建一个模型,它可以识别视频中的乐器。我们使用 KTH 手工工具数据集来提高模型的准确性。实验表明,额外的图像改善了对象检测。可以对模型进行一些改进(可以使用额外的数据集来改进仪器检测,可以进行更多的时期训练)。

参考文献

  1. 密集物体探测的焦点损失
  2. Keras-retinanet
  3. 介绍如何在 Keras 中实现 Retinanet,以便在自定义数据集上进行多目标检测
  4. h 手动工具数据集

训练机器人打网球

原文:https://towardsdatascience.com/training-two-agents-to-play-tennis-8285ebfaec5f?source=collection_archive---------9-----------------------

多智能体合作与竞争的深度强化学习

2018 年 12 月 26 日由 托马斯·特雷西 ,原载 发布于 Github

Photo credit: Ulf Hoffmann

这篇文章探索了我在 Udacity 的深度强化学习纳米学位的最终项目中的工作。我的目标是帮助其他机器学习(ML)学生和专业人士,他们正处于在强化学习(RL)中建立直觉的早期阶段。

尽管如此,请记住,我的职业是产品经理(不是工程师或数据科学家)。因此,接下来的内容是对这个项目中 RL 概念和算法的半技术性但可接近的解释。如果下面提到的任何内容不准确,或者如果你有建设性的反馈,我很乐意听到。

我对这个项目的 Github 回购可以在这里找到。该项目的原始 Udacity 源回购位于这里。

大图:为什么 RL 很重要

为了让人工智能(AI)发挥其全部潜力, AI 系统需要与人类和其他智能体进行有效的交互。已经有这样的环境,其中这种类型的代理人-人和代理人-代理人的互动正在大规模发生,例如股票市场。更多的环境就在眼前,比如一旦完全自动驾驶汽车推出,我们的道路。

沿着这条道路的一步是训练人工智能代理在合作和竞争的环境中与其他代理交互。强化学习(RL)是人工智能的一个子领域,被证明是有前途的。RL 不同于其他类型的机器学习方法,因为 RL 代理是面向目标的。也就是说,RL 算法使用奖励函数(也称为目标函数)来“强化”某些行为。例如,一个吃豆人特工每吃一个小球可以获得+1 点的奖励,如果与鬼魂相撞可以获得-100 点的奖励。通过试图最大化其累积回报,吃豆人代理最终学会了——通过反复试错——如何区分好的行动和坏的行动。

Image credit: pixelart.com

OpenAI 已经公开发布了一套大型虚拟环境,用于训练和测试 RL 代理。这刺激了 RL 领域的大量研究和创新。然而,最初的进展大部分是在单代理领域,在那里没有必要建立预测其他行为者行为的模型。因此,传统的 RL 方法(如 Q-Learning)不太适合于复杂的环境,在这种环境中,多个代理不断地交互并进化它们的策略。

不幸的是,传统的强化学习方法,如 Q 学习或策略梯度,不适合多智能体环境。一个问题是,随着训练的进行,每个代理的策略都在变化,并且从任何单个代理的角度来看,环境变得不稳定,这种情况无法用代理自身策略的变化来解释。这提出了学习稳定性的挑战,并阻止了直接使用过去的经验重放,这对于稳定深度 Q 学习是至关重要的。另一方面,当需要多个代理的协调时,策略梯度方法通常表现出非常高的方差。或者,可以使用基于模型的策略优化,它可以通过反向传播学习最优策略,但这需要世界动力学的可微分模型和关于代理之间交互的假设。从优化的角度来看,将这些方法应用于竞争环境也是具有挑战性的,众所周知的对抗性训练方法的不稳定性就证明了这一点。

——Lowe 和 Wu 等,【多主体行动者】混合合作竞争环境

哇,那是一口。本质上,我们需要的(也是本项目所探索的)是一个通用框架,允许多个代理在合作和竞争环境中从他们自己的观察中学习。代理之间没有任何通信,也没有对其他代理的行为建模。然而,这个项目中的每个代理都通过观察自己的行为和其他代理的行为来学习。每个观察包括:之前的游戏状态,代理的动作,奖励,以及之后的游戏状态(s, a, r, sʹ)

合作和竞争环境的新方法正在迅速发展。我不会在这篇文章中进一步探索它们,但我建议查看一下 OpenAI Five 和 DeepMind AlphaStar 。

该项目的目标

这个项目的目标是训练两个 RL 特工打网球。在真正的网球比赛中,每个球员的目标都是保持球在比赛中。而且,当你有两个势均力敌的对手时,你往往会看到球员在网上来回击球的相当长的交换。

环境

我们将使用与 Unity ML-Agents GitHub 页面上的网球环境相似但不相同的环境。

在这个环境中,两个代理人控制球拍将球拍过球网。如果代理人将球击过网,则获得+0.1 的奖励。如果一个代理人让一个球落地,或者把球打到界外,就得到-0.01 的奖励。因此,每个代理的目标是保持球在比赛中。

观察空间由对应于球和球拍的位置和速度的 8 个变量组成。每个代理接收它自己的本地观察。两个连续的动作是可用的,对应于移向(或远离)网,和跳跃。

任务是情节性的,为了解决环境问题,代理人必须获得+0.5 的平均分数(超过 100 个连续情节,在两个代理人身上取最大值后)。

具体来说,

  • 每集之后,我们将每个代理人收到的奖励相加(不打折),得到每个代理人的分数。这产生了两个可能不同的分数。然后我们取这两个分数中的最大值。
  • 这为每集产生一个单一的分数。
  • 当这些分数的平均值(超过 100 集)至少为+0.5 时,环境被视为已解决。

这是两个半训练有素的代理在这种环境中交互的例子。

方法

以下是在构建解决这种环境的代理时所采取的高级步骤。

  1. 使用随机行动策略建立性能基线。
  2. 选择一个合适的算法并开始实现它。
  3. 运行实验,进行修改,并重新训练代理,直到达到性能阈值。

声明:我最终达成了一个很好的解决方案;然而,结果并不一致。我的“最佳”结果只有在我多次重新运行模型时才是可重复的。如果你只运行模型一次(甚至 3-5 次),它可能不会收敛。而且,在最初的实现过程中,我在搜索一组可靠的超参数时,至少运行了 30 次模型。如果您想尝试不同的方法,我强烈建议实现一个更加系统化的方法来进行超参数调优(我没有这样做,但希望我做了)。

建立基线

在构建学习代理之前,我首先测试了在每个时间步随机选择动作(一致)的代理。

运行随机代理几次会得到从 0 到 0.02 的分数。显然,如果这些代理人需要达到连续 100 集以上 0.5 的平均分,那么随机选择动作是行不通的。然而,当您观察代理随机行动时,很明显这些类型的零星行动在培训过程的早期是有用的。也就是说,它们可以帮助代理探索动作空间,以找到一些好的与坏的动作的信号。当我们实现奥恩斯坦-乌伦贝克过程和ε噪声衰减时,这个观点将会发挥作用。

实现学习算法

首先,我们需要做出一些高层架构决策。首先,我们需要确定哪种类型的算法最适合网球环境。

基于策略的方法与基于价值的方法

与 Udacity 深度 RL 项目中的第一个项目的“导航”环境相比,网球环境有两个关键区别:

  1. 多重代理。网球环境有两个不同的代理,而导航项目只有一个代理。
  2. 连续动作空间。动作空间现在是连续的(而不是离散的),这允许每个代理执行更复杂和精确的动作。尽管每个网球代理只能向前、向后或跳跃,但控制这些运动的可能动作值是无限的。然而,导航项目中的代理仅限于四个离散的动作:向左、向右、向前、向后。

鉴于这种环境的额外复杂性,我们用于导航项目的基于值的方法并不合适,即深度 Q 网络(DQN)算法。最重要的是,我们需要一种算法,让网球经纪人能够充分利用其运动范围和力量。为此,我们需要探索一种不同的算法,叫做基于策略的方法

以下是基于策略的方法的一些优势:

  • 连续动作空间。基于策略的方法非常适合连续的行动空间。
  • 随机政策基于值和基于策略的方法都可以学习确定性策略。但是,基于策略的方法也可以学习真正的随机策略。
  • 简约。基于策略的方法直接学习最优策略,而不必维护单独的价值函数估计。在基于价值的方法中,主体利用其对环境的经验来维持对最佳行动价值函数的估计,并由此导出最佳策略。这个中间步骤需要存储大量的附加数据,因为您需要考虑所有可能的动作值。即使你把动作空间离散化,可能的动作数量也会变得很大。并且,使用 DQN 来确定在连续或高维空间内最大化动作值函数的动作需要在每个时间步长进行复杂的优化过程。

多代理深度确定性策略梯度

谷歌 Deepmind 的研究人员在本文、深度强化学习的连续控制中概述了最初的 DDPG 算法,我对其进行了扩展以创建 MADDPG 版本。在这篇论文中,作者提出了“一种使用深度函数逼近器的无模型、脱离策略的行动者-批评家算法,该算法可以在高维、连续的动作空间中学习策略。”他们强调,DDPG 可以被视为深度 Q 学习对连续任务的延伸。

对于 DDPG 基金会,我用这个普通的单一代理人 DDPG 作为模板。然后,为了使这个算法适用于网球环境中的多个竞争代理,我实现了由 Lowe 和 Wu 以及来自 OpenAI、加州大学伯克利分校和麦吉尔大学的其他研究人员在本文、中讨论的组件。最值得注意的是,我实现了他们的 actor-critic 方法的变体(见图 1),我将在下一节中讨论它。

最后,我基于 Udacity 课堂和课程中涉及的其他概念,进一步试验了 DDPG 算法的组件。我的算法实现(包括各种定制)将在下面讨论。

Figure 1: Multi-agent decentralized actor with centralized critic (Lowe and Wu et al).

演员-评论家方法

行动者-批评家方法利用了基于政策和基于价值的方法的优势。

使用基于政策的方法,代理人(行动者)通过直接估计最优政策和通过梯度上升最大化回报来学习如何行动。同时,采用基于价值的方法,代理人(评论家)学习如何估计不同状态-行为对的价值(即,未来累积报酬)。演员-评论家方法结合了这两种方法,以加速学习过程。演员-评论家代理也比基于价值的代理更稳定,同时比基于策略的代理需要更少的训练样本。

这个实现的独特之处在于 Lowe 和 Wu 的论文中的中的分散的参与者和集中的批评家方法。传统的行动者-批评家方法对每个代理都有一个独立的批评家,而这种方法利用一个批评家来接收来自所有代理的动作和状态观察作为输入。这些额外的信息使培训变得更加容易,并允许集中培训和分散执行。每个代理仍然根据自己对环境的独特观察采取行动。

你可以在源代码的maddpg_agent.py中找到作为Agent()类的一部分实现的演员-评论家逻辑。演员兼评论家的模型可以通过他们各自的Actor()Critic()类在这里在models.py找到。

注意:正如我们在上一个项目连续控制:训练一组机械臂中使用双 Q 学习一样,我们再次利用本地和目标网络来提高稳定性。这里一组参数 w 用于选择最佳动作,另一组参数 用于评估该动作。在这个项目中,本地和目标网络是为演员和评论家分别实现的。

探索与开发

一个挑战是在代理仍在学习最优策略时选择采取哪种行动。代理应该根据目前观察到的奖励选择行动吗?或者,代理人应该尝试新的行动,以期获得更高的报酬吗?这就是所谓的探索与开发的困境。

在之前的导航项目中,我通过实现 𝛆-greedy 算法解决了这个问题。该算法允许代理系统地管理探索与开发的权衡。代理通过选择一个具有一定概率ε𝛜.的随机动作来“探索”与此同时,智能体继续“利用”它对环境的了解,根据概率确定性策略选择动作(1-𝛜).

然而,这种方法对控制网球经纪人不起作用。原因是动作不再是简单方向的离散集合(即,上、下、左、右)。驱动手臂运动的动作是不同大小和方向的力。如果我们将探索机制建立在随机均匀采样的基础上,方向作用的平均值将为零,从而相互抵消。这可能导致系统振荡,但没有取得太大进展。

相反,我们将使用奥恩斯坦-乌伦贝克过程,正如之前提到的谷歌 DeepMind 的论文中所建议的那样(见第 4 页底部)。奥恩斯坦-乌伦贝克过程在每个时间步长向动作值添加一定量的噪声。这种噪声与先前的噪声相关,因此倾向于在相同的方向停留更长的时间,而不会自我抵消。这允许代理保持速度并以更大的连续性探索动作空间。

你可以在源代码的maddpg_agent.py中的OUNoise()类的中找到实现的奥恩斯坦-乌伦贝克过程。

总共有五个超参数与这个噪声过程相关。

奥恩斯坦-乌伦贝克过程本身有三个决定噪声特性和幅度的超参数:

  • :长期运行的意思
  • θ:均值回复的速度
  • :波动率参数

其中,我只调了 sigma。在运行了几个实验之后,我将 sigma 从 0.3 降低到 0.2。噪音波动性的降低似乎有助于模型收敛。

还要注意,有一个ε参数用于随时间衰减噪声水平。这种衰减机制确保在训练过程中更早地引入更多的噪声(即,更高的探索),并且随着代理获得更多的经验(即,更高的开发),噪声随着时间而降低。ε的初始值及其衰减率是在实验过程中调整的两个超参数。

你可以在源代码的maddpg_agent.py中的Agent.act() 方法中找到这里实现的ε衰变过程。而ε衰减在这里作为学习步骤的一部分被执行。

最终噪声参数设置如下:

*OU_SIGMA = 0.2   # Ornstein-Uhlenbeck noise parameter, volatility
OU_THETA = 0.15  # OU noise parameter, speed of mean reversion
EPS_START = 5.0  # initial value for epsilon in noise decay process
EPS_EP_END = 300 # episode to end the noise decay process
EPS_FINAL = 0    # final value for epsilon after decay*

重要提示:注意 EPS_START 参数设置为 5.0。在几十次实验中,我将这个参数设置为 1.0,就像我在以前的项目中一样。但是,我很难让这个模型收敛,即使收敛了,也收敛得很慢(> 1500 集)。经过多次反复试验,我意识到代理人在过程早期发现信号有些困难(例如,大多数情节得分等于零)。通过提高奥恩斯坦-乌伦贝克(OU)过程的噪声输出,它鼓励了对动作空间的积极探索,因此提高了信号被检测到的机会(即,与球接触)。一旦噪音衰减到零,这个额外的信号似乎可以提高以后训练中的学习。

学习间隔

在我实现的最初几个版本中,代理每集只执行一次学习迭代。虽然最好的模型有这个设置,但这似乎是一种运气。总的来说,我发现每集进行多次学习会产生更快的收敛和更高的分数。这确实使训练变慢了,但这是一个值得的权衡。最后,我实现了一个间隔,在这个间隔中,每集都执行学习步骤。作为每个学习步骤的一部分,算法然后从缓冲器中采样经验,并运行Agent.learn()方法 10 次。

*LEARN_EVERY = 1  # learning interval (no. of episodes)
LEARN_NUM = 5    # number of passes per learning step*

你可以在源代码的maddpg_agent.py中的Agent.step()方法中找到这里实现的学习区间。

渐变剪辑

在我实现的早期版本中,我很难让我的代理学习。或者说,它会开始学习,但随后变得非常不稳定,要么停滞,要么崩溃。

我怀疑原因之一是过大的梯度。不幸的是,我无法找到一种简单的方法来研究这个问题,尽管我确信在 PyTorch 中有一些方法可以做到这一点。如果没有这项调查,我假设仅仅经过 50-100 集的训练,我的 critic 模型中的许多权重就变得相当大了。由于我每集都要运行多次学习过程,这只会让问题变得更糟。

杰森·布朗利在这篇文章中用通俗的语言描述了渐变爆炸的问题。本质上,你的网的每一层都放大了它接收到的梯度。当网络的较低层积累了巨大的梯度时,这就成了一个问题,使得它们各自的权重更新太大,以至于模型无法学习任何东西。

为了解决这个问题,我使用torch . nn . utils . clip _ grad _ norm函数实现了渐变剪辑。我将函数设置为将梯度的范数“裁剪”为 1,因此对参数更新的大小设置了上限,并防止它们呈指数增长。一旦实现了这一改变,我的模型变得更加稳定,我的代理开始以更快的速度学习。

你可以在源代码的ddpg_agent.py中的Agent.learn()方法的“update critic”部分找到实现的渐变。

请注意,该函数在反向传递之后、优化步骤之前应用。

*# Compute critic loss
Q_expected = self.critic_local(states, actions)
critic_loss = F.mse_loss(Q_expected, Q_targets)# Minimize the loss
self.critic_optimizer.zero_grad()
critic_loss.backward()
torch.nn.utils.clip_grad_norm_(self.critic_local.parameters(), 1)
self.critic_optimizer.step()*

体验回放

经验重放允许 RL 代理从过去的经验中学习。

与之前的项目一样,该算法使用一个重放缓冲区来收集经验。当每个代理与环境交互时,体验被存储在单个重放缓冲器中。这些经验然后被中心评论家利用,因此允许代理从彼此的经验中学习。

重放缓冲区包含一个带有状态、动作、奖励和下一个状态(s, a, r, sʹ)的经验元组集合。作为学习步骤的一部分,批评家从这个缓冲区中取样。经验是随机抽样的,所以数据是不相关的。这防止了动作值灾难性地振荡或发散,因为一个简单的算法可能由于连续经验元组之间的相关性而变得有偏差。

此外,经验重放通过重复提高学习。通过对数据进行多次传递,我们的代理有多次机会从单个经验元组中学习。这对于环境中不常出现的状态-动作对特别有用。

重放缓冲区的实现可以在源代码的maddpg_agent.py文件中找到这里是。

结果

一旦上述所有组件就绪,代理就能够解决网球环境问题。同样,绩效目标是在 100 集内至少+0.5 的平均奖励,在给定的一集内从任一代理处获得最好的分数。

这里是一段视频,展示的是训练有素的特工打几分。

下图显示了最终的训练结果。表现最好的代理人能够在 607 集中解决环境问题,最高得分为 5.2,最高移动平均值为 0.927。完整的结果和步骤可以在 Tennis.ipynb Jupyter 笔记本中找到。

未来的改进

  • 解决稳定性问题以产生更一致的结果。我的“最佳”结果只有在您多次运行该模型时才能重现。如果只运行一次(甚至 3-5 次),模型可能不会收敛。在搜索一组好的超参数时,我至少运行了 30 次模型,因此,实施一种更系统的方法(如网格搜索)可能会有所帮助。否则,需要更多的研究来找到更稳定的算法或对当前的 DDPG 算法进行修改。
  • 增加优先经验回放*。优先重放不是随机选择经验元组,而是基于与误差大小相关的优先级值来选择经验。这可以通过增加稀有或重要的经验向量被采样的概率来改进学习。*
  • 批量正常化。我没有在这个项目中使用批处理规范化,但我可能应该这样做。在过去构建卷积神经网络(CNN)时,我曾多次使用批量归一化来压缩像素值。但是,我没有想到会是这个项目。批处理规范化曾在 Google DeepMind 论文中使用,并在我的其他项目实现中被证明非常有用。与上面提到的爆炸梯度问题类似,对大输入值和模型参数运行计算会抑制学习。批量标准化通过在整个模型中以及不同的环境和单元中将特征缩放到相同的范围内来解决这个问题。除了将每个维度标准化为具有单位均值和方差之外,值的范围通常要小得多,通常在 0 到 1 之间。在我的之前的项目训练连续控制的机械臂的源代码model.py内,你可以找到为演员实现的这里和为评论家实现的这里这里。这大大提高了模型的性能和稳定性。

接触

我希望你觉得这很有用。同样,如果你有任何反馈,我很想听听。欢迎在评论中发表。

如果你想讨论其他合作或职业机会,你可以在 LinkedIn 上找到我或者在这里查看我的作品集。

使用 Google BERT 训练弱标签、多标签数据:对来自 Westeros 和 Essos 的文档进行分类

原文:https://towardsdatascience.com/training-weakly-labelled-multilabel-data-with-google-bert-classifying-documents-from-westeros-a2dda03e506e?source=collection_archive---------9-----------------------

背景知识:Google BERT,NLP 的一些知识

简介

关于自然语言处理背景下的文本分类的论文大多处理整齐标记的数据,这些数据仅适合于一类(单标记多分类问题;例如,图像包含或不包含猫)。

然而在现实世界中,我们经常不得不处理带有弱标签的数据,这不仅是因为 1)缺少标记数据的人力,而且 2)我们的问题通常是多标签的——一个文档有多个标签。(例如,图像可以有猫和狗)

此外,不同公司的分析师通常有非常具体的内部相关类别,这些类别无法整齐地归入商业 NLP APIs,如 Google Cloud ML。

我是 NLP 项目团队的一员,为一家金融机构做多标签文本分类。

我们在 NDA 之下,所以我不能透露我们在为哪家公司工作,或者具体的任务,所以我使用乔治·R·R·马丁的系列丛书中的名字来匿名化我的数据,并希望给你一个有趣的学习例子。

我将根据“火与冰之歌”虚构的宇宙给出一个问题描述,然后继续讨论我如何使用 Google BERT 来解决这个问题。

问题描述

想象以下场景:

你是一名来自亚夏地的巫师,手持一面被称为“电脑”的神奇黑镜。国王之手 韦赛里斯二世坦格利安 已经联系你帮助他。每天,他和他的工作人员都会收到涵盖维斯特洛和埃索斯所有政治实体的文件;大部分文件来自官方法庭,格式相似,但也包括其他来源,如信件和间谍报告。

最终,国王之手想要做的是做出决定来维护王国的和平与繁荣,但是他和他的工作人员需要花费大量的时间来通读所有这些文件并将它们汇编成报告。

手和他的工作人员已经为你分类并验证了文件的样本,而用你的电脑,你可以神奇地获得一个文件样本,尽管没有来自烈酒的标签,名字像“Guugle”、“B'eeng”和“阿雅 Huu”。你还可以接触到一个名叫伯特的傀儡,他已经接受了超过六百万种交流方式的训练。

国王之手给你一定的时间来制作原型模型。随后,他会将您在“实时”数据上的结果与他自己的员工在相同数据上的表现进行比较。

基本上我们有:

  1. 文档包含的不同标签的列表。(大房子,自由城市,其他派别)文件可以涵盖一个以上的类别。
  2. 一个由人类验证的小样本(国王的手和他的杖)
  3. 访问没有标签的附加文档(抓取在线数据)

我们将在“实时”数据上对国王之手及其幕僚进行测试。

机器学习方法

希望上面给了你一个有趣的比喻,来说明我们的问题,不要太混乱。

我是这样处理这个问题的:

按照吴恩达的指导方针,我们应该拥有训练、验证和测试数据集。

在最好的情况下,数据集应该彼此相似,但如果这不可能,我们至少应该让验证集与测试集相似。然后,我们在训练集上训练和调整超参数,以便在最终将其应用于测试集之前,在验证集上进行评估时获得良好的结果。

在这种情况下,我从 web 上搜集了大量文档,使用标题中的关键字作为弱标签。

例如,当我为史塔克家族搜集文件时,我会在 bing 上搜索“domain:" varys . com " intitle:" Brandon Stark " ',并将其视为“史塔克家族”的弱标签。

然后,我从收集的所有 HTML 和 PDF 文件中提取字符串,并将其全部放入一个大的数据帧中。之后,我在抓取的文本上对 BERT 进行了微调,以使 BERT 模型在“政治”语言上得到微调。

第一次接近 :

在这一点上,我最初的方法只是将整个文档作为一个整体输入并标记到 BERT 中,让它截断最终超过 512 个单词块标记的文档,并用我的单个弱标签标记该文档。

请记住,由于我刮的方式,每个文档只有一个弱标签,例如“史塔克家族”,但文档本身也可能提到“兰尼斯特家族”等等。

基本上,与“阴性”样本相比,我的每个标签只有很少的阳性样本,而事实上,很多“阴性”样本都是假阴性。在 1 万份文件中,从我搜集的数据来看,可能有 100 份被贴上了“豪斯·斯塔克”的标签,但实际上,剩下的 9900 份文件中,有很多可能也包含了有关“豪斯·斯塔克”的信息。

为了解决这个问题,在我的损失函数中( sigmoid 与二元交叉熵损失)我增加了阳性样本的权重。(pos_weight in PyTorch)凭直觉,我用* pos_weight 重要性来对待每个阳性样本。如果 pos_weight 为 10,那么我认为阳性样本的价值是“阴性”样本的 10 倍。

我优化的指标是 F1 综合得分,稍微偏向于回忆。

通过这种方法,我在验证集上获得了大约 0.35 的 F1 分数——F1 分数在训练 BERT 分类器的大约 5-6 个时期后趋于平稳。

这不是很好,比我的合作伙伴使用的使用 tf-idf 的经典机器学习算法还要差。

第二种方法 :

在这一点上,我认为截断的文本和缺少标签是使用 BERT 的一个巨大限制。

我创建了一个空间规则匹配器脚本,为每个标签匹配关键字。比如史塔克家,我会包括“史塔克、临冬城、布兰·史塔克、罗柏·史塔克”等等。只要匹配器选择了其中一个关键词,我就会用“1”标记该文章的类别(例如“House Stark”)。

然后,我根据原始字符串“\n”将文本分割成单独的段落,并对分割的文本运行规则匹配器脚本。

最后,我为这个特定的分类任务微调了我的 BERT 模型。

本质上,我是在用关键词训练 BERT 模型,并希望它能获得比关键词本身更多的上下文信息。

使用这种方法,我的 F1 分数在验证集上达到了大约 0.50,这比纯粹的“仅规则匹配器”模型要高。所以模型确实获得了额外的信息!

肯定还有改进的空间——在这一点上,我只将我朋友的性能与基于 tf-idf 的方法相匹配,坦率地说,仅仅为了获得与更老、计算成本更低的模型相匹配的值而训练 BERT 是浪费时间。

在这一点上,我认为要获得规则匹配器无法捕获的额外人类特征,我只需在验证集本身上微调模型,因为这是由人类专家手工标记的。

我这样做了,当它最终进入概念验证测试时,BERT matcher 本身确实产生了超过 tf-idf 模型的 F1 分数(大约 0.68)。

然而,最终我们实际上发现 BERT 模型和 tf-idf 模型的集合产生了甚至更好的 F1 分数。

学习要点和改进途径

查看博客和讨论板,并与我的一些同行交谈,我发现人们正在以不同的方式使用 BERT。本文描述了两个主要部分:1)将“冻结”的权重作为一个特性用于下游任务,2)解冻权重并针对特定任务对其进行微调。在论文中,它们被表示为冰(❄️) ️and 火(🔥)分别。

我选择了火🔥我认为那篇论文证明了伯特用这种方法确实比用冰❄️方法表现得更好。我怀疑这可能是由于伯特在❄️方法中失去了理解上下文的能力。

在上面的任务中,当在验证集上微调模型时,我也简单地使用了默认的 BERT 方法输入文本——也就是说,它涉及到截断超过最大序列长度的文本。

最近的一篇中文论文提到,结合文档的开头和结尾有助于提高他们对长文档的分数。我计划在模型的未来迭代中实现这一点。

我也一直在研究通气管,它可以帮助你为弱标签创建一个概率模型,只要你有一些“黄金标准”,人类验证的数据与之比较。

结论

在现实世界中,带标签的数据是一种奢侈品,你必须想办法在机器学习任务中使用弱标签。在特定领域语言上训练 BERT 模型,然后在基于关键字的“弱标签”上对其进行微调,最后在人类验证的数据集上对其进行微调,似乎可以产生超过传统 NLP 模型的结果。

使用 BlazingText 在 AWS SageMaker 上训练单词嵌入

原文:https://towardsdatascience.com/training-word-embeddings-on-aws-sagemaker-using-blazingtext-93d0a0838212?source=collection_archive---------21-----------------------

在最近的文章中,我们探索了如何创建专业葡萄酒评论中所含信息的数字表示。这样做的一个重要步骤是在专业葡萄酒评论的语料库上训练 Word2Vec 模型,以获得大约 1000 个独特和频繁出现的葡萄酒描述符的单词嵌入。

在本文中,我们将探索如何使用 BlazingText 算法在 AWS SageMaker 中训练 Word2Vec 模型,并随后在 S3 中创建一个包含训练好的描述符单词嵌入的 CSV 文件。

我们的起点是从官方葡萄酒爱好者网站刮来的 18 万篇专业葡萄酒评论。这是我们的语料库。我们获取每篇葡萄酒评论中的文本描述,并经历几个文本规范化的步骤(将文本转换为小写,删除停用词和特殊字符,添加二元和三元组)。我们可以在 SageMaker 笔记本中完成所有必要的文本规范化步骤(代码见这里)。

现在,我们准备训练我们的 Word2Vec 模型。方便的是,SageMaker 提供了一个名为 BlazingText 的 Word2Vec 模型的内置优化实现。在我们构建 BlazingText 模型时,有很棒的示例笔记本可供我们参考。

首先,我们需要确保我们的标准化训练数据已经作为一个 txt 文件保存在 S3,语料库中的每一句话都在一个新行上。这是 BlazingText 算法期望的输入格式。我们需要设置模型文件的输出位置,设置我们的训练作业将运行的区域,并创建一个将为我们启动训练作业的估计器对象。

现在,我们可以配置培训工作的细节。我们分两步来做:首先,我们设置培训资源的规格。对于我们的培训工作,ml.c4.2xl 实例类型已经足够了。每个实例类型的资源可以在这里找到,t 他的链接可以帮你找到相关的价格标签。

我们还需要设置 BlazingText 模型的超参数。我们只想保留语料库中出现至少 5 次的单词。出现频率低于这一频率的单词可能不够常见,无法以任何形式的准确度来计算单词嵌入。我们将单词嵌入的维度设置为 300,这是单词嵌入维度的一个相当常见的选择。我们还使用 batch_skipgram 方法,该方法支持跨多个 CPU 节点的分布式训练。虽然对于我们的目的来说,分布式训练可能有些矫枉过正(我们的语料库只有几百万个单词),但如果您正在处理更大的语料库,这是一个值得指出的特性。

接下来,我们设置一个训练通道,以字典的形式将我们的训练数据填加到 BlazingText 算法中。剩下要做的就是通过运行。拟合方法。

SageMaker 将自动启动和关闭用于训练模型的实例。随后,我们还可以选择部署我们刚刚培训的模型。然而,这有必要吗?最终,我们只对完整语料库中相对较小的单词子集的单词嵌入感兴趣。我们真正关心的葡萄酒描述符大约有 1000 个。此外,我们将不会利用 BlazingText 算法提供的分类功能。因此,我们从训练好的模型中提取相关的葡萄酒描述词嵌入,并将其保存在 S3 桶中就足够了。

这种方法将允许我们在需要时访问这些单词嵌入,而不必承担在 SageMaker 端点中托管模型的成本。

我们可以运行下面的代码来访问我们的训练模型。

上面代码片段中的最后一行打开包含我们模型的 tarfile。我们看到它由三项组成:

vectors.bin
vectors.txt
eval.json

我们最感兴趣的是 vectors.txt 文件,这是一个带有经过训练的单词嵌入的文本文件。我们可以运行下面的代码从中提取相关的单词嵌入。txt 文件,并将它们保存在 CSV 文件中。

我们的 CSV 文件具有以下结构:

太好了!我们有我们需要的。

使用您的自定义数据集在 PyTorch 中训练 Yolo 进行对象检测——简单的方法

原文:https://towardsdatascience.com/training-yolo-for-object-detection-in-pytorch-with-your-custom-dataset-the-simple-way-1aa6f56cf7d9?source=collection_archive---------2-----------------------

在之前的故事中,我展示了如何使用预先训练好的 Yolo 网络进行 物体检测和跟踪 。现在,我想向您展示如何使用由您自己的图像组成的自定义数据集来重新训练 Yolo。

对于这个故事,我将使用我自己为 DARPA SubT 挑战训练物体探测器的例子。挑战包括在隧道网络中检测 9 个不同的对象——它们是非常具体的对象,而不是标准 Yolo 模型中包含的常规对象。对于这个例子,我假设只有 3 个对象类。

有几种方法可以做到这一点,根据官方规范,您可以在培训脚本中定义图像、配置、注释和其他数据文件的位置,但这里有一种更简单且组织良好的方法,仍然遵循 Yolo 的最佳实践。

文件夹结构

首先,您需要将所有的训练图像放在一起,使用这个文件夹结构(文件夹名称用斜体)来表示:

*Main Folder*
--- *data*
    --- *dataset name*
        --- *images*
            --- img1.jpg
            --- img2.jpg
            ..........
        --- *labels*
            --- img1.txt
            --- img2.txt
            ..........
        --- train.txt
        --- val.txt

现在让我们看看这些文件应该是什么样子的(除了那些显而易见的图像文件)。

首先,注释文件。你需要一个。每个图像的 txt 文件(相同的名称,不同的扩展名,单独的文件夹)。每个文件只包含一行,格式如下:

class x y width height

例如,一个文件(用于类 1)可以是:

1 0.351466 0.427083 0.367168 0.570486

请注意,坐标和大小是整个图像大小的一部分。例如,如果文件是 600x600px,坐标(200,300)将表示为(0.333333,0.5)。

train.txtval.txt 包含训练和验证图像列表,每行一个,路径完整。例如,在我的系统上,这样一个文件的前两行是:

/datadrive/Alphapilot/data/alpha/images/IMG_6723.JPG
/datadrive/Alphapilot/data/alpha/images/IMG_6682.JPG

我使用下面的程序生成 2 个文件,基于 90%训练/ 10%验证分割:

import glob
import os
import numpy as np
import syscurrent_dir = "./data/artifacts/images"
split_pct = 10  # 10% validation set
file_train = open("data/artifacts/train.txt", "w")  
file_val = open("data/artifacts/val.txt", "w")  
counter = 1  
index_test = round(100 / split_pct)  
for fullpath in glob.iglob(os.path.join(current_dir, "*.JPG")):  
  title, ext = os.path.splitext(os.path.basename(fullpath))
  if counter == index_test:
    counter = 1
    file_val.write(current_dir + "/" + title + '.JPG' + "\n")
  else:
    file_train.write(current_dir + "/" + title + '.JPG' + "\n")
    counter = counter + 1
file_train.close()
file_val.close()

创建注释文件

现在你会问如何得到?txt 注释文件。嗯,我使用的是修改版的 BBOX 工具,它包含在 Github repo 中。它的工作方式是这样的:你将训练图像放在每个班级的不同文件夹中。查看 LoadDir 函数下的文件夹结构(或者根据您的情况进行修改)——在我的示例中,我有两个文件夹,“forboxing”用于图像,而“newlabels”用于生成的注释,在“forboxing”下有每个类的子文件夹(“0”、“1”等)。您必须修改文件顶部的self.imgclass属性,并为每个类单独运行它。这一程序使一切都快了一点。使用工具本身是非常直观的——你只需在每一帧中的对象周围画一个方框,然后转到下一帧。

配置文件

现在来看看 config/ 文件夹中的配置文件。首先, coco.data 会是这样的:

classes = 3
train=data/alpha/train.txt
valid=data/alpha/val.txt
names=config/coco.names
backup=backup/

我认为这是不言自明的。backup 参数没有使用,但似乎是必需的。这个 coco.names 文件非常简单,它应该列出类的名称,每行一个(对于注释文件,第一个对应于 0,第二个对应于 1,依此类推)。在我的例子中,文件包含三个类:

DRILL
EXTINGUISHER
RANDY

现在,配置文件中最重要的是 yolov3.cfg 。这是一个很大的文件,但以下是您必须更改的主要内容:

在第一个[net]部分,调整batch值和subdivisions以适合您的 GPU 内存。批量越大,训练越好,越快,但占用的内存也越多。对于一个 11Gb 内存的 Nvidia GPU 来说,一批 16 和 1 细分就不错了。也可以在这里调整learning_rate

现在,最重要的是classes和最后一层filters的值(因为如果设置不正确,你的训练计划将会失败)。而且你要在文件中的三个不同的地方做。如果你搜索这个文件,你会发现 3 个[yolo]部分。在这个部分中,将classes设置为模型中的类的数量。您还必须更改[yolo]正上方的[卷积]部分中的filters值。该值等于:

filters = (classes + 5) x 3

所以对于我的 3 个类,有 24 个过滤器。注意,这只适用于 Yolo V3。V2 有一个不同的公式。

运行培训脚本

现在你已经为真正的训练做好了准备!训练程序(来自 Github repo )是标准的 Yolo 脚本。在 config 部分,设置所需的 epochs 数,确保文件夹路径正确,然后运行。根据训练图像的数量和您的硬件,这可能需要几个小时到一天以上的时间。

该脚本将在每个纪元后保存…抓取最后一个文件并将其放回您的配置文件夹中,然后它就可以在您的自定义数据集上进行对象检测了!关于如何运行检测功能的细节在前面的故事中有介绍,PyTorch 中的对象检测和跟踪。

这个故事中引用的所有代码都可以在我的 Github repo 中获得。

Chris Fotache 是一名人工智能研究员,在新泽西州工作。他涵盖了与我们生活中的人工智能、Python 编程、机器学习、计算机视觉、自然语言处理、机器人等相关的主题。

用机器学习转录活棋第 1 部分

原文:https://towardsdatascience.com/transcribe-live-chess-with-machine-learning-part-1-928f73306e1f?source=collection_archive---------11-----------------------

在第 1 部分中,我们将在 Unity 中创建一个合成数据集,并在 Keras 中训练一个模型来转录象棋位置的图像。

Live and Digital Representations of the Staring Position

介绍

你玩过真人象棋吗?棋子的触感、检查的口头声明,以及对手偷偷瞄你的国王,最终形成一种在线游戏无法比拟的令人兴奋和身临其境的体验。然而,总的来说(OTB ),国际象棋对于严肃的棋手来说有一个明显的缺点:游戏不会自动转录。游戏必须用笔和纸或国际象棋应用程序手动转录或记录(比赛中不允许)。这种方法不仅乏味而且容易出错,最重要的是:它剥夺了游戏的乐趣。

正如您可能从标题中猜到的那样,我提出了一个替代解决方案。玩家可以使用计算机“观看”游戏,并从实时视频中自动转录移动序列,而不是手动转录游戏中的每个移动。在这个博客系列中,我将向您展示如何使用机器学习和计算机视觉中的常见和高级技术将这一想法转化为现实。每一篇后续文章都将着眼于这个问题更加困难的方面,并逐一解决它们。

入门指南

像任何机器学习问题一样,定义问题(从实时视频中自动转录移动序列)后的第一步是定义输入和输出。输入是视频数据,它由一系列随时间变化的图像和可选的音频组成。输出是通常以 PGN 格式记录的游戏的移动序列。从输入和输出中移除排序依赖性,我们留下了对应于一个国际象棋位置的图像(因为移动只是一系列国际象棋位置的增量压缩)。虽然这种方法忽略了位置的状态成分,例如 castling 和 en passant,但它形成了一个更容易的学习目标,并且这些省略可以在以后计算。因此,简化的输入和输出分别是图像和位置。位置通常用 FEN 符号编码,这个项目将使用这种约定。

Image Input for the Model

FEN: r4rk1/2pp1p1p/p3p1p1/1p3b2/3P1R2/1BP1P3/PP4PP/R1B3K1

构建数据集

构建数据集的第一步是确定数据采集策略。该项目的战略选项包括:

  • 使用现有的大量国际象棋视频
  • 手动拍摄实况象棋视频
  • 众包具有激励结构的现场视频拍摄
  • 生成国际象棋位置的合成数据集

第四个选项有一个前三个选项所没有的独特属性:它不需要人工标记,因为我们可以同时生成输入和输出对。另一个微妙的好处是,它允许我们更有效地控制输入数据,并防止模型偏向典型的片段排列或位置模式。让我们使用 Unity 继续这个方法。

Branding Asset of Unity

Unity 是一个 3D 游戏引擎和开发环境,可以创建逼真的 3D 环境。使用 C#脚本可以对环境进行编程访问。如果你不熟悉 Unity,使用他们优秀的教程很容易上手。在 Unity 中,我们需要完成以下任务:

  • 创建一套国际象棋和棋盘
  • 将摄像机置于一个良好的观察位置
  • 生成随机板
  • 使用相机的视图拍摄截图

Free Chess Asset in Unity

第一个任务可以通过简单地从 Unity 的资产商店下载预制资产来完成。使用 Unity 的编辑器,将摄像机定位在一个能很好地看到电路板的位置也是很简单的。生成随机板的代码如下所示。它的策略“HalfEmptyRandomDistribution”,给每个方块 1/2 的空概率和 1/2 的被随机棋子占据的概率(从黑王到白卒)。没有选择完全随机的分布,因为大量的大块会导致摄像机视角的高度视觉遮挡。在这种情况下,我们将避免使用 FIDE 象棋数据库分布,因为它会使我们的模型偏向典型位置。

生成随机棋盘后,下一步是以编程方式移动棋子。A1 和 H8 的位置是使用 Unity 编辑器手动记录的,其他正方形位置的计算如下所示:

以下是 Unity 编辑的观点:

现在,从相机的角度生成截图。下面是生成屏幕截图的代码。使用主板的 FEN 符号(用“/”替换“-”)将字节返回并写入文件。

在我们在一个目录中生成大约 10,000 张图像并将其压缩后,我们就有了一个预先标记的数据集。

设计模型

ImageNet 是大多数 CNN 架构接受训练的数据集,它有 1000 个分类作为可能的输出。然而,唯一国际象棋位置的数量为 13⁶⁴,这使得标准影像分类输出图层不可行。解决这个问题的方法是使用对象检测在图像中定位棋盘和棋子,然后使用 3D 透视变换计算它们在棋盘上的位置。虽然取得了一定的成功,但这种方法的主要缺点是它需要一种算法来解析模型的输出并构建棋位。更优雅的做法是让模型来做工作,直接学习位置。

首先,让我们简化这个问题:如何从一幅图像中预测哪块占据 A1 方块。正方形可以被十二个不同的棋子中的一个占据,也可以是空的,所以有十三种可能性。使用 Tensorflow 2.0 和 Keras,我们的模型伪代码如下所示:

这段代码利用了来自 Tensorflow Hub 的 MobilenetV2 副本的迁移学习,并允许通过将变量“可训练”设置为 True 来微调这些层。此外,该代码对 MobilenetV2 进行了微调,因为它的上层过滤器被训练来检测与 ImageNet 分类相关的模式。例如,它有像人类、自行车和树木这样的分类,这些分类检测面部、轮胎和树枝的模式,这些在我们的数据集中都是不需要的。所以,我们可以用更有用的过滤器来代替它们。通过现在关注一个正方形,我们已经有效地将该问题转化为伴随着 softmax 激活和分类交叉熵损失函数的图像分类问题。最后,为了扩展我们的模型来检测多个方块,代码使用了 Keras 的 functional API,它指定了 64 个输出。我们预测所有方块的模型伪代码现在看起来像这样:

这种型号符合我们的要求。现在是时候训练它了。

训练模型

为了训练我们的模型,输入和输出数据必须以 Keras 接受的格式加载。因此,原始的国际象棋图像使用 MobileNet 的预处理器转换成张量。对于基本事实输出,我们从文件名中解析 FEN 编码,并将其格式化为 64 个输出。这是我们的 Keras 生成器类:

有了正确格式的数据,模型就可以开始训练。使用 Colab 的内置 GPU 进行培训需要几个小时。

Data Science Adaptation of Famous xkcd Sketch

使用 Tensorboard ,我们可以查看我们的学习曲线(蓝色的确认损失)。

损失函数持续下降(图像为对数标度),这表明,至少在数学上,模型正在学习。评估模型真实性能的最好方法是用一个看不见的例子来测试它。

Model Prediction Visualized

该模型正确预测了 64 个方块中的 63 个,准确率约为 98%。这种精确度证明了我们的模型架构是合理的。虽然我们可以对我们的模型进行微调,使其更加精确,但是无论如何,我们将在第 2 部分中升级我们的模型,所以可以安全地继续了。(注意:你可能会注意到 A1 实际上应该是一个深色的正方形。Unity 资产被错误地旋转了 90 度,但我发现这个错误时已经来不及重做数据集了。我们将在第 2 部分讨论如何正确对齐电路板。)

结论

我们完成了什么?

  • 使用统一的 10,000 张 3D 象棋位置的标记图像构建数据集
  • 使用 Keras 功能 API 和 64 个输出层设计了一个模型来学习这些数据
  • 训练模型,直到它达到人类水平的性能

在第 2 部分中,我们将解决我们在第 1 部分中跳过的一个问题,即:由于棋盘固有的对称性,它的位置是不明确的。我们还会用各种各样的物件、木板、灯光、背景和摄像机角度来扩充我们的数据集。最后,我们将向我们的数据集添加一些手动标记的真实世界数据,并在看不见的真实世界图像上尝试我们的模型。

Colab 笔记本:【http://bit.ly/2STzn0G】T2

用于时间序列预测的迁移学习

原文:https://towardsdatascience.com/transfer-learning-for-time-series-prediction-4697f061f000?source=collection_archive---------7-----------------------

LSTM 递归神经网络被证明是时间序列预测任务的一个很好的选择,然而该算法依赖于我们有足够的来自同一分布的训练和测试数据的假设。挑战在于时间序列数据通常表现出时变特征,这可能导致新旧数据之间的很大差异。在这篇博客中,我们想测试迁移学习和模型的一般领域训练在多大程度上有助于解决上述问题。

迁移学习(migration learning)是通过从相关任务中迁移已经学习过的知识来提高新任务中的学习。 第十一章:迁移学习,机器学习应用研究手册,2009。

学习迁移有几种方法,它们的区别在于可迁移的知识。在这篇博客中,我们将使用参数传递方法:

  1. 我们将在基线数据集(作为源域)上建立一个模型,然后转移训练过的权重,作为要在目标域上训练的模型的初始化(标准转移学习)。
  2. 我们将在来自两个源(源和目标域)的组合时间序列数据上构建一个模型到一个一般域中,在一般域数据上“预训练”该模型,仅在一个目标域上调整该模型,并将后一个模型的性能与仅在一般域和目标数据上训练的另外两个模型进行比较。

这里是 GitHub 链接到项目的仓库。

我们用下面显示的随机噪声生成 6 个合成时间序列。

The generated synthetic time series

现在我们有了我们的实验时间序列,让我们在第一个时间序列上训练一个模型,并把它作为一个源任务。这是代表模型拟合和评估流程的流程图。

因为 LSTM 网络期望输入/输出序列,在阶段 2 中,我们以如下方式将缩放的序列转换成 X(输入)和 Y(输出)序列:

为了找到模型的合适架构和超参数值,进行了网格搜索,结果得到了具有以下配置的模型:

具有 100 和 50 个神经元的 2 个 LSTM 层(无脱落)

学习率=0.00004 的 Adam 优化器

输入序列的长度是在自相关图(相关图)的帮助下确定的,因为它显示了相对于时间滞后的序列中的重复模式。

Correlogram of Sine Wave

在生成正弦波的情况下,所需的输入(滚动窗口)大小约为 70(因为模式从那里开始重复),这一选择也通过在一些其他候选值上运行网格搜索来证明。以下是模型训练和评估结果:

Training and Validation Loss per Epoch

Baseline model prediction results

MSE = 0.1

图上的预测对应于模型的 50 倍预测,该预测是这样迭代完成的:

  1. X_test(用于测试的输入数据集)中的第一个可用序列用于预测序列的下一个值,例如 f(x1,…x10 )=x11
  2. 预测值 x11 被附加到 x2,…,x9 序列以形成新的序列,并且我们使用 x2,…,x11 预测 x12。
  3. 第二步重复用户定义的次数(n_ahead-1)

迁移学习

现在我们有了一个训练好的模型,我们可以开始试验知识转移是否有助于在目标领域(除了 Sine 之外的所有其他系列)获得更好的执行模型。我们进行了两项独立的试验:

1)在目标序列的最后 100 个数据点上训练 2 个模型(有和没有迁移学习),并预测 10 个超前值

2)在目标系列的整个数据集(2000 点)上训练 2 个模型,并预测 50 个提前值。

这背后的直觉是看迁移学习在数据稀缺的情况下是否有帮助。

以下是 RMSE 实验的结果:

RMSE results from the predictions

以下是一些结果的可视化。

Positive example of Transfer Learning on Cosine series

Negative example of Transfer Learning on Absolute Sine series

从 RMSE 的结果中,我们可以得出结论,一般来说,迁移学习有助于一半情况下的提高,但是如果我们仔细观察,我们可以注意到在目标领域缺乏数据时,它在 3/5 的情况下是有帮助的。

常规和域内调整

正如开头所解释的,这里我们将安装 3 个模型:

  1. 预调优—基于通用域数据
  2. tuned——既在一般领域上,然后在目标领域上传递知识和拟合
  3. 仅针对目标—顾名思义,此功能仅适用于目标域

时间序列被附加在一起形成一个通用的领域数据集。

以下是与上一节相似的实验结果:

RMSE results from the predictions

我们可以看到,在“调整”的情况下,所提出的方法只提高了一次性能。可以预料,目标领域的训练比其他两种情况表现更好,而“预调优”的情况在 10 种情况中有 3 种表现更好。

以下是一些结果的可视化。

Positive example of “Pre-tuned” case outperformance

Positive example of “Tuned” case outperformance.

结论

基于所获得的结果,迁移学习似乎在缺乏时间序列数据的情况下以及当我们对类似任务有微调的模型时是有用的。

至于模型的一般领域调优,需要进一步探索,以发现是否有其他组合技术可以提高“调优”模型的性能。

自然语言处理中的迁移学习

原文:https://towardsdatascience.com/transfer-learning-in-nlp-fecc59f546e4?source=collection_archive---------12-----------------------

使用已经训练好的健壮模型在更短的时间内完成 NLP 任务,并使用更少的资源。

首先什么是迁移学习?最近,我们变得非常擅长用非常好的训练模型预测非常准确的结果。但是考虑到大多数机器学习任务都是特定领域的,经过训练的模型通常无法概括出它从未见过的条件。现实世界不像训练过的数据集,它包含大量杂乱的数据,在这种情况下模型会做出错误的预测。将预训练模型的知识转移到新条件中的能力通常被称为迁移学习。

迁移学习已经在计算机视觉中大量使用,主要是因为在大量数据中训练的非常好的预训练模型的可用性。

Pan and Yang (2010)

深度学习是训练数据密集型的。如果你没有超过 10,000 个例子,深度学习可能根本不在讨论范围内。类似的过程也存在于自然语言处理中。例如,一个简单的 word2vec 模型可以通过上下文(如用于语言学习的向量)通过序列预测单词,它可以通过来自其他输入的向量基于上下文产生这些模式。

对于这些类型的数据集,深度学习并不总是最好的方法。极端的训练要求、巨大的计算时间,以及最重要的是,费用使得这些深度学习输入对于许多环境来说遥不可及。

迁移学习如何解决这个问题?

每个人都有问题,但不是每个人都有数据。与小数据相比,大数据实际上不是什么大问题。迁移学习是从一种语境到另一种语境的应用。因此,应用来自一个模型的知识可以通过采用现有参数来解决“小”数据问题,从而帮助减少训练时间和深度学习问题。

例如,使用深度学习来教算法识别老虎对于这样一个小任务来说太耗费人力了。相反,转移现有的模型,例如输入的高级概念,如“多大?怎么条纹?什么颜色?”会给你很高的激活度,因为这些问题中的每一个都对应着一幅老虎的图像。输入特征和目标之间的关系变得更加直接,训练能力和总计算数据更少。

迁移学习的一般优势:

迁移学习然后以三种不同的方式解决深度学习问题。

  • 使用预训练数据简化训练要求
  • 更小的内存需求
  • 大大缩短了目标模型培训时间——几秒钟而不是几天

用例中的优势:

对于计算机视觉,我们在数百万数据上有一套非常好的训练有素的模型,它们可以很容易地用于执行对象识别任务。我们可以用 20 行代码构建健壮且非常精确的模型。只需导入一个预训练的模型并微调几层就能得到我们想要的结果。

对于 NLP,过程更复杂。视觉数据输入往往更具体,组成视觉特征的组件更通用,而金融训练集不会转移到生物医学模型。总的来说,对于什么是好的源模型还没有达成一致。但是 NLP 中有许多地方可以利用迁移学习来优化深度学习的一般过程。

比如语言建模,简单来说就是预测序列中下一个单词的任务。给定部分句子“我原以为我会准时到达,但却在 5 分钟后到达”,对读者来说,下一个单词显然是“迟到”的同义词。有效地解决这一任务不仅需要理解语言结构(名词跟随形容词,动词有主语和宾语等)。)还包括根据广泛的上下文线索做出决定的能力(“late”在我们的例子中是填补空白的明智选择,因为前面的文本提供了说话者正在谈论时间的线索。)此外,语言建模具有不需要带标签的训练数据的期望属性。原始文本在每一个可以想象的领域都是丰富的。这两个特性使得语言建模非常适合学习可归纳的基本模型。

自然语言处理中的迁移学习可以分为三个方面。a)源和目标设置是否处理相同的任务;以及 b)源和目标域的性质;以及 c)学习任务的顺序。

A taxonomy for transfer learning in NLP (Ruder, 2019).

将知识转移到语义相似/相同但数据集不同的任务。

  • 源任务-用于二元情感分类的大型数据集
  • 目标任务(T)——用于二元情感分类的小数据集

将知识转移到语义不同但共享相同神经网络架构的任务,以便可以转移神经参数。

  • 源任务 -用于二元情感分类的大型数据集
  • 目标任务(T) —用于 6 向问题分类的小数据集(例如,位置、时间和数量)

当我们处理不同的语言和用户需求时,自然语言处理中的迁移学习有一定的局限性。例如,大多数模型是为英语语言训练的,由于不同的语言语法结构,在不同的语言中使用相同的模型是相当困难的。对于自定义 NER 任务来说也很困难,因为我们需要提取非通用的自定义实体。

迁移学习的几种方法

参数初始化(INIT)。

INIT 方法首先在 S 上训练网络,然后直接使用调整后的参数为 T 初始化网络。转移后,我们可以固定目标域的参数,即微调 t 的参数

多任务学习(MULT)

另一方面,MULT 在两个领域同时训练样本。

Multi Task Learning

组合(MULT+初始)

我们首先在源域 S 上预训练参数初始化,然后同时训练 S 和 T。

一些受欢迎的型号有:

1.工程与后勤管理局

( E 嵌入来自 L 语言 Mo dels)

ELMo 的方法是使用 LSTM 来回学习语言模型。使用时间输入我们的文本在这个模型中,并删除不同层的隐藏状态,给出每一层应该有多重要的权重。这取决于我们使用的工作。ELMo 每一层中的隐藏状态就像每一层中的表示是不同的。

从右到左,从训练双向 LSTM 开始,实现 ELMo 的隐藏状态
(图片来自 ELMo 的幻灯片

ELMo 的使用被认为是上下文嵌入,比单词嵌入要好。总的来说,ELMo 的表现也考虑到了背景。例如,在明文嵌入中,单词 bank 表示银行,bank 表示银行,这是一个向量。相同,但是因为 ELMo 是接收到 LSTM 的整个消息的模型,所以它的表示也根据传入的消息而变化。在使用中,在嵌入层中添加上下文嵌入作为输入,如下图所示

ELMo 在各种任务中的上下文嵌入
(图片来自 ELMo 幻灯片

当使用 ELMo 时,我们还发现它能够更好地帮助测试各种数据集中的结果

使用 ELMo
改进了测试结果(图片来自 NLP 的 ImageNet 博客时刻已经到来)。

2.乌尔菲特

(U通用L语言M模型 Fi, Ne- ,t Uning)。

这个 ULMFiT 基于 AWD-LSTM,是当今语言建模的最佳 LSTM。当 ULMFiT 了解到语言模型可以用于各种任务时,只需保留较低的部分并改变顶层,但实现可能需要两个以上的微调步骤。从训练语言模型开始,然后逐渐训练真实的工作,比如训练成为一个分类器。

在这个调整过程中,有一些建议是应该做的。区别性微调是不同层次的微调。因为每一层的模型是在不同级别上的表示,并且应该使用倾斜的三角形学习率,以便能够在开始时收敛到一个好的值,然后逐渐调整到后来的值,并且在最后的调整中,例如,训练成为分类器,应该逐个调整权重。未修改层中的权重将首先被冻结。(意思是保持原来的值)

a) ULMFiT training for general language models (b) and then training for a specific language model
© and then actually training for that work (Picture from ULMFiT paper )

开放式变压器

去年,推出了自我关注过程和变压器模型。今年,它被更广泛地使用,例如在故事生成或萨根以及我们将讨论的 OpenAI Transformer 和 BERT 中。为了自我关注和变形金刚的事。ThAIKeras 写了一篇文章,有兴趣的可以在这里阅读。

至于 OpenAI Transformer,Transformer 的解码器端是屏蔽了自我关注的。用于学习语言模型。然后,在其他应用中使用时,您可以按如下方式将前馈神经网络连接到顶部。

Examples of the use of OpenAI Transformer in text classification
( The Illustrated BERT, ELMo, and co. (How NLP Cracked Transfer Learning) blog ).

伯特

(BI 方向En 编码器R表示来自T变压器)。

对于这个最新的伯特模型已经决定使用自我关注充分或者是变压器编码器。但是在过去的语言模型学习中,有一些限制阻止了它的使用。双向 LSTM 或完全自我关注,因为语言建模是对下一个单词的预测,该单词必须在一个方向上追逐传入的消息,如果从另一个方向追逐或使用所有消息将相当于看到正确的答案。在 BERT 的学习中,问题从语言模型变成了掩蔽语言模型,即随机关闭几个单词。然后给出预测这个单词的模型,比如完形填空或者允许我们猜测空格中单词的测试

用完形填空题进行伯特训练
(图片来自插图伯特、埃尔莫等人(NLP 如何破解迁移学习)博客)

此外,伯特还将学习句子之间的关系。为了更好地理解信息的含义,通过输入两个句子,然后 BERT 预测这两个句子是否相连。

Training with two sentences (picture from The Illustrated BERT, ELMo, and co. (How NLP Cracked Transfer Learning) blog ).

这四种模式可以总结如下:

  • ELMo:
    学习任务:语言建模
    架构:Bi-LSTM
  • 学习任务:语言建模
    建筑:AWD-LSTM
  • OpenAI Transformer:
    学习任务:语言建模
    架构:Transformer(解码器)
  • BERT:
    学习任务:完形填空和句子预测
    架构:Transformer(解码器)

这是迁移学习如何应用于自然语言处理领域的概述。自然语言处理中的迁移学习可以很好地解决某些领域中的某些问题,但是要在所有语言的所有一般自然语言处理任务中被认为是一个好的解决方案还有很长的路要走。随着 NLP 领域的大玩家引入新模型,我很高兴看到这如何应用于各种用例以及未来的发展。

推文姿态分类的自然语言处理中的迁移学习

原文:https://towardsdatascience.com/transfer-learning-in-nlp-for-tweet-stance-classification-8ab014da8dde?source=collection_archive---------6-----------------------

自然语言处理中两种迁移学习方法的比较:针对涉及 Twitter 数据的多类分类任务的:ulm fit和【OpenAI GPT】

A wordcloud of an interesting Tweet dataset analyzed in this post

2018 年是自然语言处理(NLP)领域非常令人兴奋的一年,特别是对于迁移学习——一种不是从零开始训练模型的技术,我们使用在大型数据集上预先训练的模型,然后针对特定的自然语言任务对它们进行微调。 Sebastian Ruder 在他的文章“ NLP 的 ImageNet 时刻已经到来”中提供了迁移学习的过去和当前状态的精彩描述,解释了为什么这是 NLP 中目前如此热门的领域——他的文章是必读的

最近,诸如 ULMFiT 、 OpenAI GPT、 ELMo 和 Google AI 的 BERT 等方法已经通过在预训练期间使用语言建模彻底改变了 NLP 中的迁移学习领域,这极大地改善了自然语言理解中各种任务的最新水平。可以说,语言建模的使用(并非没有局限性)是计算机在语言语义理解方面取得巨大进步的主要原因之一。

上面提到的迁移学习方法的一个有趣的方面是,它们使用在格式良好的大规模精选数据集上预先训练的语言模型,这些数据集包括具有清晰语法的完整句子(如维基百科文章和10 亿字基准)。自然出现的问题是——这种预先训练的语言模型能在多大程度上推广到来自不同分布的自然语言任务,如推特?

这篇文章的目标

在这篇文章中,我们将讨论和比较两种现代迁移学习方法——ulm fit和 OpenAI 的GPT("GgenerativePre-Training "),并展示如何相对容易地对它们进行微调,以执行不同分布的分类任务——在这种情况下,对推文的立场进行分类。

我们的目标是开发一种建模方法,帮助回答以下问题:

  • 我们微调过的语言模型(和分类器)是否概括了 Tweets 的非结构化和杂乱的语言语法?
  • 我们能否通过针对每个型号的最小特定任务定制有限的计算资源实现合理的准确性(与 2016 年的基准测试结果相当)?
  • 基于所使用的模型架构,分类结果如何变化?

下面显示的结果的所有代码和数据都可以在这个 GitHub repo 中找到。

为什么是乌尔姆菲特和开放 GPT?

这两种特定的迁移学习方法被选作这个项目,因为它们在如何使用语言建模来执行无监督的预训练,以及随后的监督微调步骤方面非常相似(它们都是半监督方法)。但是它们也不同,因为它们使用不同的网络架构来实现通用化。ULMFiT 使用 3 层双 LSTM 架构,而 OpenAI 方法使用变压器网络。

对 ULMFiT 和 OpenAI 的 GPT 的完整描述对于这篇文章来说太长了,但是这篇文章很好地强调了这两种模型架构的技术细节以及它们的重要性,所以请务必阅读它!

背景

在进入推文姿态分类的迁移学习的细节之前,让我们澄清一些术语,以理解为什么迁移学习在最近大幅提高了各种自然语言任务的最新水平。

从经典的单词嵌入继续

历史上,预先训练的单词嵌入技术,如 word2vec 和 GloVe ,在 NLP 中大量使用,以在训练新任务之前初始化神经网络的第一层。这些是浅层表示(单层权重,称为嵌入)。来自单词嵌入的任何先验知识只存在于网络的第一层——对于新的目标任务,整个网络仍然需要从头开始训练。

为了从单词序列(例如在自然语言中看到的那些)中获取含义,利用单词嵌入的模型仍然需要大量的数据来消除大量单词的歧义,并从全新的、看不见的词汇中“学习”。如本文稍后讨论的基准测试结果所示,通过单词嵌入传递知识所需的数据量可能巨大,这可能导致非常大的计算成本。在整个 2018 年,强大的预训练语言模型的出现表明,使用从大型文本语料库的预训练中获得的知识,可以更深入地理解新任务的语言语义和结构,特别是对于长序列。

语言建模

语言模型试图通过分层表示来学习自然语言的结构,因此既包含低级特征(单词表示),也包含高级特征(语义)。语言建模的一个关键特征是它是生成性的,这意味着它的目标是在给定前一个单词序列的情况下预测下一个单词。它能够做到这一点,因为语言模型通常是以无监督的方式在非常大的数据集上训练的,因此该模型可以以比单词嵌入更深入的方式“学习”语言的句法特征。

在他的文章中,Sebastian Ruder 做了一个非常优雅的工作,强调了为什么语言建模对于广泛的自然语言处理任务如此强大。未标记的语言数据相对容易获得(它可以以大型文本语料库的形式免费获得),因此通过向语言模型提供足够大的数据集,现在可以对数十亿个单词进行无监督的预训练,同时融入更深入的语言语法知识。

半监督学习

NLP 中的迁移学习现在通常是作为一个多步骤的过程来完成的——其中一个整个网络首先以一种无监督的方式进行预训练,目标是语言建模。在此之后,该模型然后使用监督方法(使用一些标记的数据)在新的任务上进行微调,然后可以用于文本分类等任务。这种无监督预训练(使用语言建模)和监督微调的结合被称为 半监督学习,也是我们在这篇文章中用来解决推文立场分类问题的方法。

使用的数据集

本文中使用的推文数据集来自 this SemEval 2016 共享任务,其中包含与以下五个主题相关的推文:

  • 无神论
  • 气候变化令人担忧
  • 女权运动
  • 希拉里·克林顿
  • 堕胎合法化

提供的标签数据由目标主题、与之相关的推文以及推文对目标的姿态组成。这些数据已经分为一个训练集(包含 2914 条推文)和一个测试集(包含 1249 条推文)。立场可以是三个标签之一:“赞成”、“反对”和“都不是”,因此这是一个多类数据集。

Example training data (randomly sampled)

检测姿态的挑战

立场检测是观点挖掘的一个子类,其任务是自动确定一段文本的作者是支持给定目标的还是反对给定目标的。考虑以下两条推文:

我们不是从父母那里继承了地球,而是从我们的孩子那里借来的

据我所知,阿尔·戈尔是政治家,不是科学家。

对于人类观察者来说,很明显两条推特都与气候变化话题相关,并且都表达了对气候变化话题的特定立场。然而,对于机器来说,检测这种姿态是一个多方面的难题。推文的非正式和非结构化语法,加上机器缺乏人类拥有的适当的上下文意识和历史知识(例如,知道阿尔·戈尔是谁),使这成为机器学习算法的一个挑战性问题。此外,为推特姿态收集大量标记数据以训练机器学习算法既昂贵又繁琐。开发深度学习方法变得越来越有必要,这些方法可以在有限的训练数据量下工作,但仍能产生有用的见解。

立场和情绪是不一样的!

姿态检测与情感分析相关,但并不相同。在情感分析中,我们感兴趣的是一段文字是正面的、负面的还是中性的,这仅仅是基于所用语言的内容。典型地,对于情感分析,正面或负面语言的选择与文本的整体情感相关。

然而,一段文本的立场是相对于目标主题定义的,并且可以独立于是否使用了肯定或否定的语言。目标(表达意见的主题)可能会或可能不会在实际文本中直接提及,文本中提及的任何实体可能会或可能不会是意见的实际目标。下面是来自任务创建者论文的一个例子。

话题 : 堕胎合法化

推文 :怀孕的不只是会走路的保温箱。他们也有权利!

姿态 : 恩宠

在上面的例子中,由于这个话题被称为“堕胎合法化”,这条推文可以被解释为对这个话题有利。如果它被称为“反堕胎运动”,它的立场将会是反对这个话题。从这个例子中可以清楚地看出,推文中使用的语言在情绪上只是大致积极的;然而,这种情绪与它是支持还是反对这个话题没有关系。

阶级不平衡

下表显示了与数据集中的每个主题相关的推文数量。这 2,914 条推文在每个主题上的分布是不均衡的,每个主题的每个类别的推文数量也有很大差异。要探索分布情况并更详细地检查推文,请查看由任务创建者提供的完全交互式可视化。

****

Source: SemEval-2016 Stance Dataset

观察这种分布,立场分类任务似乎非常具有挑战性——不仅数据集很小(总共有几千个训练样本,每个主题的最少 395 条到最多 689 条推文),而且样本中还存在显著的类别不平衡。例如,主题“气候变化是一个问题”有较大比例的训练样本被分类为“赞成”,而有非常小的比例(不到 4% )被分类为“反对”。另一方面,主题“无神论”有很大一部分样本被归类为“反对”。

任何姿态分类的建模方法都必须能够捕捉到这种等级不平衡,包括目标等级内和之间的**

使用的评估指标

为了评估分类性能,任务的创建者使用一个宏观平均的 F 值,这是两个主要类别“支持”和“反对”的精度和召回率的调和平均值*。这里的给出了在情感分类中如何使用精确度和召回率的例子。一般来说,精确度和召回率是不一致的,因此 F-score 提供了一个很好的方法来洞察分类器的性能。虽然我们在评估中不包括第三类“两者都不是”,但是它被隐含地考虑,因为系统必须正确地预测所有三类以避免在前两类中的任何一类中受到严重惩罚。*****

为了评估 F 分数,任务创建者提供了一个 perl 脚本(其用法将在后面的章节中描述)——我们需要做的就是以一种评估脚本可以读取的方式形成我们的姿态分类器的预测输出。然后可以将获得的宏观平均 F 值与其他模型的结果进行比较。

用于比较的基准结果:MITRE

2016 年这项任务的获奖作品来自 MITRE 团队,他们在本文中描述了他们的分类方法。为了检测姿态,MITRE 使用了一个递归神经网络(RNN)模型,该模型分为 4 层,如下图所示。第一层包含一次性编码的标记(即文本中的单词),这些标记通过称为“投影层”的 256 嵌入层进行投影。然后将输出序列输入到“循环层”(包含 128 个 LSTM 单元),其输出连接到一个 128 维的整流线性单元(ReLUs)层,压降为 90%。最终的输出层是一个 3 维 softmax 层,代表每个输出类别:支持、反对和无。

Image credit: MITRE’s submission to SemEval 2016

MITRE 还应用了迁移学习(通过使用单词嵌入)来重用来自预训练模型的 Tweet 语法的先验知识。这是通过如下所述的多步骤预培训流程实现的:

  1. 预训练投影层:使用 word2vec 跳格法从 256 维单词嵌入中初始化投影层的权重。为了做到这一点, MITRE 从 Twitter 的公共流媒体 API 中提取了 218,179,858 条英文推文,然后在这个未标记的数据集上执行弱监督学习(在清理推文并将其小写后)。为了了解复合短语的意思,他们然后应用word 2 phase来识别由多达四个单词组成的短语。在抽样的 2.18 亿条推文中,使用了 537,366 个词汇项目(在语料库中出现了至少 100 次)。
  2. 预训练递归层:MITRE 网络的第二层由 128 个 LSTM 单元组成,使用标签预测辅助任务的远程监控,用预训练的权重初始化。首先,自动识别了 197 个与所考虑的五个主题相关的标签(使用单词嵌入空间的最近邻搜索)。然后,从总共 2.18 亿条推文中提取了 298,973 条推文,其中至少包含这 197 个标签中的一个,并训练网络来调整单词嵌入和递归层。像以前一样,Tweets 是小写的,在标记化之前去掉了所有的标签和短语。

结果:MITRE

MITRE 获得的每个主题和班级的未公开测试数据的 F 分数如下所示。请注意,对于主题类“气候变化(反对)”,F 值为零,这意味着他们的模型没有预测到来自测试集的任何反对气候变化的推文。然而,来自气候变化主题的训练数据中,只有 3.8% 属于“反对”类(这相当于只有 15 个训练样本!),因此,由于完全缺乏训练样本,该模型可能缺少该特定类的上下文是有意义的。

Data source: MITRE’s paper submitted to SemEval 2016

正如在他们的论文中提到的,MITRE 获得了(所有主题的平均值)0.68 的宏观 F 值。这是 2016 年向比赛提交结果的所有 19 名参赛者中的最好成绩。

MITRE 使用的方法是一个相当复杂的多步预训练过程,使用单词嵌入,需要使用非常大的未标记数据集(数亿个样本),对原始数据进行大量清理,并为网络中的每一层单独进行预训练。大量手工制作的步骤主要是因为 word2vec 嵌入的限制(这是当时 NLP 中预先训练模型的主要方法)。

方法 1: ULMFiT

ULMFiT 已经完全在fastai库的 v1 中实现了(参见他们的 GitHub repo 上的[fastai.text](https://github.com/fastai/fastai/tree/master/fastai/text))。fastai的版本 1 是建立在 PyTorch v1 之上的,所以对 PyTorch 对象有一些了解有利于入门。在这篇文章中,我们将介绍一些fastai开发的技术,这些技术使得迁移学习变得非常方便,即使对于深度学习经验相对较少的人来说也是如此。

培训步骤

如原论文所述,ULMFiT 由三个阶段组成。

  1. 在捕捉高级自然语言特征的通用领域语料库上训练语言模型
  2. 在目标任务数据上微调预先训练的语言模型
  3. 在目标任务数据上微调分类器

Image source: ULMFiT paper by Jeremy Howard and Sebastian Ruder

在推文姿态分类过程中,我们只执行步骤 2 和 3 。第一步是一个无人监督的预训练步骤,并且真的计算量很大——这就是为什么fastai将这些模型公之于众,以便其他人可以从他们的工作中受益。我们依靠预先训练的语言模型的能力来捕捉我们可能遇到的任何目标文本(英语)中的长期依赖性。**

这部分的所有代码都可以在 Jupyter 笔记本【ul mfit . ipynb】中找到。为了简洁起见,在这篇文章中只讨论了该方法的关键元素——请随意浏览完整的笔记本和这个项目的主 GitHub repo以深入了解对 Tweet 立场进行分类的工作代码。

ULMFiT 中的新学习技术

ULMFit 论文中的以下新技术使其即使在不同分布的看不见的数据上也能很好地推广。建议阅读全文深入了解,但下面给出一个总结。

  • 判别微调:模型的每一层捕捉不同类型的信息。因此,不同地微调每一层的学习率是有意义的,这是在 ULMFiT 中基于广泛的经验测试和实施更新完成的。根据经验发现,首先只微调最后一层(其他层冻结),然后解冻所有层,并在语言模型微调期间对所有其他层应用降低 2.6 倍的学习速率,在大多数情况下效果良好。**
  • 单周期学习率策略:在微调阶段,我们应用单周期学习率,该策略来自 Leslie Smith 的报告。这是对已经存在很长时间的循环学习率策略的修改,但是单周期策略允许更大的初始学习率(比如max_LR = 1e-03),但是在最后一个时期将其降低几个数量级。这似乎提供了更高的最终精度。请注意,这并不意味着我们运行它一个时期—1-cycle 中的“1”意味着它只是在我们指定的最大时期之前的一个时期循环学习率。在 ULMFiT 实施中,这一单周期策略已被调整,并被称为倾斜三角学习率
  • 逐步解冻:分类时,不是一次性微调所有图层,而是将图层“冻结”,先微调最后一层,再微调它之前的下一层,依此类推。这避免了被称为灾难性遗忘的现象(通过丢失从语言模型中获得的所有先验知识)。**
  • 串联池:池是神经网络的一个组件,用于聚合学习到的特征,并减少大型网络的整体计算负担。如果你好奇的话,本文中的很好地介绍了 LSTMs 中应用的池技术。在 ULMFiT 中,由于输入文本可能包含数百或数千个单词,如果我们只考虑 LSTM 中的最后一个隐藏状态,信息可能会丢失。为了避免这种信息丢失,最后一个时间步的隐藏状态被连接两者在 GPU 存储器中能够容纳的尽可能多的时间步上隐藏状态的最大池和平均池表示。

乌尔姆菲特语言模型

ULMFiT 的预训练语言模型是在 Stephen Merity 的 Wikitext 103 数据集上训练的。 fast.ai 提供了一个 API ,在微调之前,可以方便轻松地为任何目标任务加载这个预训练模型(以及一些用于测试的标准数据集)。关于 Wikitext 103 需要注意的主要事情是,它由从维基百科中提取的 1.03 亿个标记的预处理子集组成。数据集保留了原始大小写(在为语言模型定型之前,它不是小写的),并且包括所有标点符号和数字。该数据集中包含的文本数据类型包括来自完整维基百科文章的句子,因此希望语言模型能够从相对复杂的句子中捕获并保留一些长期依赖关系。

为 ULMFiT 预处理推文数据

原始 Tweets 可能包含一些任意的非英语字符,所以在加载到语言模型之前,我们会注意这一点。请注意,这仅删除了非英语字符,但不会做任何其他类型的积极预处理(如小写或删除整个单词或标签)。我们保留原始数据中的全部信息,并让语言模型来完成繁重的工作。

fast.ai中实现的 ULMFiT 框架可以很好地处理 Pandas 数据帧,所以所有数据都使用pandas.read_csv读入并存储为一个数据帧。

**train_orig = pd.read_csv(path/trainfile, delimiter='\t', header=0, encoding = "latin-1")**

然后,我们通过应用一个简单的清理函数来确保 Tweets 只包含 ASCII 字符。

**def clean_ascii(text):
    # function to remove non-ASCII chars from data
    return ''.join(i for i in text if ord(i) < 128)train_orig['Tweet'] = train_orig['Tweet'].apply(clean_ascii)**

Training data stored in a Pandas DataFrame

ULMFiT 只需要姿态和文本数据(即 Tweets)用于语言模型微调和分类步骤,因此我们将它们存储在相关的数据帧中,并将干净的数据写出到一个csv文件中..

**train = pd.concat([train_orig['Stance'], train_orig['Tweet']], axis=1)
# Write train to csv
train.to_csv(path/'train.csv', index=False, header=False))**

Clean training data ready to be loaded into ULMFiT

ULMFiT 中的语言模型微调

这是训练的第一阶段,我们使用预训练的语言模型权重(Wikitext 103),并用提供的 2,914 条推文的训练数据对其进行微调。

公布的 Jupyter notebook(ulmfit . ipynb)详细描述了使用 ulm fit 时由fastai在幕后执行的预处理。读者可以在 Jupyter 的笔记本上找到更多的代码和 API 细节。

在我们的例子中,我们为我们的语言模型微调步骤指定了最小词频 1,这告诉 ULMFiT 只对 Tweets 中使用唯一标记出现多次的单词进行标记化——在标记化期间,所有出现一次的单词都被赋予标签<unk>。对于如何和为什么以这种方式完成标记化的非常详细的历史描述,这个 fastai 课程文档页面包含了一些非常有用的信息。

**data_lm = TextLMDataBunch.from_csv(path, 'train.csv', min_freq=1)**

Tokenized and tagged Tweets using ULMFiT + spaCy

在查看标记化的推文时,我们可以看到它们看起来与原始形式明显不同。fastai.text使用的标记化技术相当先进,是杰瑞米·霍华德和 [fastai](https://github.com/cedrickchee/knowledge/blob/master/courses/fast.ai/deep-learning-part-2/2018-edition/lesson-10-transfer-learning-nlp.md) 团队经过个月的开发获得的,因此使用了相当多的技巧从文本中捕捉语义。

注意,我们而不是将文本转换为小写并删除停用词(这是 NLP 中常见的预标记化方法,直到最近),这将导致大量信息的丢失,而模型可以使用这些信息来收集对新任务词汇的理解。相反,如上所示,许多添加的标签被应用于每个单词,以便丢失最少的信息。所有标点符号、标签和特殊字符也会被保留。**

比如xxmaj记号【来源】表示单词有大写。“The”将被标记为“xxmaj the”。全大写的单词,如“我在喊”,被标记为“xxup i xxup am xxup shouting”。该方法仍然使用 spaCy 的底层标记器(包括一个围绕 spaCy 的多线程包装器来加速),但以一种非常智能的方式添加标签。这平衡了捕获语义含义和减少整体标记的数量——因此它既强大又高效。有关 ULMFiT 的fastai实现生成的所有令牌标签的完整列表,请参见这里的源代码。

找到最佳学习速率:我们定义了一个学习者对象,该学习者对象使用了标记化的语言模型数据,这些数据被组织成用于 GPU 的批处理,并为其提供一个预训练的语言模型,如下所示。fastai.train 【来源】提供了一个方便的实用程序来搜索一系列学习率,以找到最适合我们数据集的学习率。这个想法是,我们的优化函数需要使用一个学习率,该学习率至少比损失开始发散的点低一个数量级。

**learn = language_model_learner(data_lm, pretrained_model=URLs.WT103_1,
        drop_mult=0.1)learn.lr_find(start_lr=1e-8, end_lr=1e2)
learn.recorder.plot()**

Result of the “learning rate finder” (lr_find) as implemented in fastai.train

根据 ULMFiT 论文应用区别性微调,我们运行语言模型微调步骤,直到确认损失下降到低值(接近 0.3)。

**learn = language_model_learner(data_lm, pretrained_model=URLs.WT103_1, 
                               drop_mult=0.5)
# Run one epoch with lower layers 
learn.fit_one_cycle(cyc_len=1, max_lr=1e-3, moms=(0.8, 0.7))# Run for many epochs with all layers unfrozen
learn.unfreeze()
learn.fit_one_cycle(cyc_len=20, max_lr=1e-3, moms=(0.8, 0.7))**

然后,该微调的编码器层的权重被保存以在分类阶段使用。

**# Save the fine-tuned encoder
learn.save_encoder('ft_enc')**

微调分类器

这一步包括创建一个分类器对象[ source ],一旦我们将模型重新训练为分类器,它就可以预测一个类标签。此任务仍使用相同的网络结构-输出图层的定义方式考虑了我们希望在数据中预测的类的数量。

找到分类器的最佳学习速率:和之前一样,像之前一样运行lr_find方法来找到分类器的最佳学习速率。

**# Classifier databunch
data_clas = TextClasDataBunch.from_csv(path, 'train_topic.csv',
            vocab=data_lm.train_ds.vocab, min_freq=1, bs=32)# Classifier learner 
learn = text_classifier_learner(data_clas, drop_mult=0.5)
learn.load_encoder('ft_enc')
learn.freeze()learn.lr_find(start_lr=1e-8, end_lr=1e2)
learn.recorder.plot()**

Result of the “learning rate finder” (lr_find) as implemented in fastai.train

精心训练分类器:在分类过程中,我们首先定义一个分类器学习器对象,按照 ULMFiT 论文的建议每次运行一个历元,逐步解冻层。这有助于我们获得比一次训练所有层更好的分类精度。**

**learn = text_classifier_learner(data_clas, drop_mult=0.5)
learn.load_encoder('ft_enc')
learn.freeze()learn.fit_one_cycle(cyc_len=1, max_lr=1e-3, moms=(0.8, 0.7))**

**learn.freeze_to(-2)
learn.fit_one_cycle(1, slice(1e-4,1e-2), moms=(0.8,0.7))**

**learn.freeze_to(-3)
learn.fit_one_cycle(1, slice(1e-5,5e-3), moms=(0.8,0.7))**

**learn.unfreeze()
learn.fit_one_cycle(4, slice(1e-5,1e-3), moms=(0.8,0.7))**

分类器的确认损失比语言模型高得多,语言模型可能与数据集相关联。因为存在显著的类别不平衡,所以在训练期间大量的标签预计会被错误地预测。具体到这个 Twitter 数据集,这个问题可能比我们在最先进的例子(如 IMDb)中看到的更严重。

使用分类器预测姿态

我们读入测试集,并将其存储在 Pandas 数据帧中,如图所示。

**test = pd.read_csv(path/testfile, delimiter='\t', header=0,
       encoding="latin-1")
test = test.drop(['ID'], axis=1)**

然后,我们可以应用我们的分类器学习者的predict方法来预测姿态。

**test_pred['Stance'] = test_pred['Tweet'].apply(lambda row: str(learn.predict(row)[0]))# Output to a text file for comparison with the gold reference
test_pred.to_csv(path/'eval'/'predicted.txt', sep='\t', index=True,
                 header=['Target', 'Tweet', 'Stance'], index_label='ID')**

评估我们来自 ULMFiT 的预测

由任务创建者提供的perl脚本在输出和黄金参考文件(也由创建者提供)上运行,以产生一个宏 F 值,然后我们可以将它与 MITRE 的基准结果进行比较。

**cd eval/
perl eval.pl gold.txt predicted.txt**

Best obtained result using ULMFiT

使用 ULMFiT 的最佳模型参数

使用 ULMFiT 在所有主题中获得的最佳平均宏观 F 值为 0.65 ,使用以下方法和参数获得:

  • 扩充的 Twitter 词汇上微调语言模型:这是通过从 Kaggle 下载Twitter sensing 140 数据集,并将其词汇的子集(200,000 个单词)提供给语言模型微调步骤来完成的。这个步骤在 Jupyter 笔记本 [ulmfit.ipynb](https://github.com/prrao87/tweet-stance-prediction/blob/master/ulmfit.ipynb)中有详细说明。完整的 Kaggle Twitter 数据集有 160 万条推文,这可能需要几个小时来微调语言模型(即使是在英伟达 P100 GPU 上)——所以只有 20 万个单词的子集被用于增强语言模型微调步骤。**
  • 训练 5 个不同的分类器(即在分类过程中为每个主题执行单独的训练任务),然后将输出结果与黄金参考进行比较——这是一种类似于 MITRE 在 2016 年的最佳结果中使用的技术,并在他们的论文中进行了解释。**
  • 语言模型微调步骤的最佳学习速率1e-03
  • 分类器在1e-051e-03范围内的最佳学习速率,逐渐解冻

方法二:开放 GPT

OpenAI GPT,正如在他们的论文中所描述的,是对谷歌大脑 2017 年论文《注意力是你所需要的全部》中著名变形金刚的改编。

Image credit: Google Brain’s “Attention is All You Need” paper

谷歌大脑的原始版本使用了相同的编码器-解码器 6 层堆栈,而 GPT 使用的是 12 层解码器专用堆栈。每层有两个子层,由多头自注意机制和全连接(位置式)前馈网络组成。OpenAI 用于迁移学习的 transformer 架构的完整描述在他们的论文中给出。

这一节的所有代码都可以在 Jupyter 笔记本【transformer . ipynb】中找到。和以前一样,为了简洁起见,在这篇文章中只讨论了模型的关键元素——请随意浏览完整的笔记本和这个项目的主 GitHub repo 以深入了解分类推文的工作代码。

培训步骤

以下步骤用于训练 OpenAI 变压器:

  1. 无监督的预训练:transformer 语言模型以无监督的方式在谷歌图书语料库的几千本图书上进行训练,预训练的权重在 OpenAI GitHub repo 上公开以供他人使用。
  2. 监督微调:我们可以根据监督的目标任务调整参数。输入通过预先训练的模型传递,以获得最终变压器块的激活。

第一步(无监督的预训练)是非常昂贵的,由 OpenAI(他在 8 个 GPU 上训练了一个月的模型!)—幸运的是,我们可以使用下载的预训练模型权重,并直接进行监督微调步骤。**

开放 GPT 的 PyTorch 实现

注意:虽然最初的 OpenAI transformer 是在 tensor flow[GitHub source]中实现的,但是为了这个项目,我们使用了open ai GPT的 PyTorch 端口,这要感谢 HuggingFace 的人们所做的惊人工作。这是为了让我们能够与 ULMFiT 的fastai实现(也是基于 PyTorch 的)进行更一致的比较,更不用说使用单一框架维护和分发代码的便利性了。

OpenAI GPT 论文中介绍的新技术

为了执行领域外的目标任务,GPT 将语言建模作为微调的附加目标,这有助于广义学习,正如在他们的论文中所描述的。该辅助语言建模目标由如下所示的加权参数指定。

其中,L1、L2 和 L3 分别是语言建模目标、特定任务目标和组合目标的可能性。

转换器已经被证明是一个非常强大的语言建模工具,特别是在机器翻译中,这要归功于它的“自我关注机制”。这篇文章非常直观和形象地解释了转换器如何适用于捕获更长范围的语言结构(使用掩蔽的自我注意)。需要注意的一个关键点是,OpenAI GPT 使用了 12 层的纯解码器结构,有 12 个注意头和一个 768- 维度状态。另一个关键点是,每个迷你批次能够采样最多 512 个连续令牌,根据 OpenAI 作者的说法,这允许转换器实现比基于 LSTM 的方法更长范围的上下文。

特定于任务的输入转换:

OpenAI 将他们的转换器设计成任务不可知的,并且能够推广到一系列自然语言任务。为了实现这一点,他们允许自定义“特定任务的头部”的定义,如上图所示。特定于任务的 head 作用于基本 transformer 语言模型之上,并在model_pytorch.py中的DoubleHeadModel类中定义(参见 GitHub repo )。**

HuggingFace 最初写的 GPTpy torch port是为了一个选择题分类问题(ROCStories)。对于这个 Tweet stance detection 任务,我们使用 OpenAI 论文中提到的准则为分类任务头编写一个自定义输入转换,这样我们就可以用一个开始符号填充每个文本(在我们的例子中表示每个 Tweet ),并对它们进行令牌化,以便输入到编码器层。这是按如下方式完成的。

注意,在上面的分类输入转换函数中,我们需要做的就是为编码器指定开始标记,然后将文本附加到这个开始标记上。对于其他变量,我们保持与原始 PyTorch 代码相同的张量维数。

为 OpenAI GPT 预处理推文数据

训练脚本的数据加载器定义如下。就像 ULMFiT 的情况一样,我们清理数据以删除任何非 ASCII 字符(以避免编码步骤中的问题)。然后,数据存储为 Numpy 数组。

为了将数据提供给分类转换,我们使用scikit-learntrain_test_split实用程序将数据分成训练集、验证集和测试集。

使用上面的代码,我们将训练 Tweet ( trX)存储在它的数字化姿态(trY)旁边。我们将数据作为 Numpy 数组(不是 DataFrame 列)输入到train_stance.py的 PyTorch 数据加载器中。下面是输入数据的一个例子,它是按照转换器的要求进行整形的。立场“0”对应“反对”,1 对应“赞成”,2 对应“都不赞成”。就像在 ULMFiT 中一样,原始数据中的任何信息都不会被删除——我们依赖语言模型目标来识别看不见的单词之间的句法关系(一旦模型进行了微调)。

**Plenty of stem cells without baby smashing, by the way. #SemST 0Is there a breeze i can catch Lakefront or will I die of a heat stroke there as well? #heatstroke #SemST 1Road to #Paris2015 "#ADP2015 co-chairs' new tool will be presented on July 24th" @manupulgarvidal at @UN_PGA event on #SemST 2Are the same people who are red faced and frothing over abortion also against the death penalty? Just wondering... #deathpenalty #SemST 1DID YOU KNOW: The 2nd Amendment is in place 'cause politicians ignore the #CONSTITUTION. #PJNET #SOT #tcot #bcot #ccot #2ndAmendment #SemST 0I Appreciate almighty God for waking me up diz beautiful day + giving me brilliant ideas to grow my #Hustle #SemST 0Speaking from the heart is rarely wise especially if you have a retarded heart like most feminists.   #GamerGate #SemST 0@Shy_Buffy welcome little sister! Love you! #SemST 2@GregAbbott_TX which god? Yours? not mine. oh wait i don't have one. #LoveWins #SemST 1**

微调语言模型和分类器

在 OpenAI GPT 中,语言模型和分类器微调都是同时进行的,这要归功于它使用多头注意力的并行化架构。这使得运行训练循环非常容易,因此许多实验是可能的。

下面的命令用于运行 3 个时期的训练循环,这是我们所有实验中使用的。请参阅 Jupyter 笔记本( transformer.ipynb )和文件[train_stance.py](https://github.com/prrao87/tweet-stance-prediction/blob/master/transformer-openai/train_stance.py)了解关于默认参数和各种实验运行的更多详细信息。

**python3 train_stance.py --dataset stance --desc stance --submit --data_dir ../data --submission_dir default --n_iter 3**

训练脚本的输出被提供给另一个脚本parse_output.py,它以一种可以被perl脚本评估为由任务创建者提供的的方式形成输出。

评估我们的 GPT 模型的预测

评估perl脚本在输出和黄金参考文件(也由创建者提供)上运行,以生成一个宏 F 值,然后我们可以将它与 MITRE 的基准测试结果进行比较。

**cd eval/
perl eval.pl gold.txt predicted.txt**

Best obtained result using the OpenAI Transformer

使用 OpenAI GPT 的最佳模型参数

从 GPT 获得的所有主题的最佳宏观 F 值 0.69 是使用以下方法和参数获得的:

  • 微调语言模型只是提供了训练推文(其中 2914 条)。transformer 模型能够在 3 个时期内快速推广到 Tweet 数据,并且能够获得良好的宏观 F 值,而无需以任何方式增加输入数据。
  • 一次为所有主题训练一个 单个分类器(即,在整个训练数据集上运行训练循环)——人们注意到,当试图仅在单个主题(其具有< 500 个训练样本)上训练转换器时,存在显著的过度拟合,其中验证准确度下降到远低于 70%。这可能是因为转换器具有高维嵌入层(768 维),需要足够的训练数据量来避免过度拟合。**
  • 根据 OpenAI 论文,语言建模加权函数(lambda)为 0.5。
  • 所有层(包括分类层)的漏失为 0.1,再次按照 OpenAI 论文。

总的来说,微调 dropout、语言建模目标的权重和更改一些其他默认参数(如随机种子)对提高宏观 F 分数没有什么帮助。一般来说,transformer 很快就能产生好的结果,并且只需要对任务头输入转换进行一些基本的定制。

结果分析

在这一节中,我们将通过我们的两种方法:乌尔菲特和 GPT 获得的 F 分数与 MITRE 的基准结果进行比较。

总体 F 分数

当我们同时考虑所有五个主题的宏观 F 值时,OpenAI GPT 显示出产生了最好的结果。

Best results compared with the benchmark from MITRE

这个结果值得注意的是,ULMFiT 和 OpenAI GPT 都利用了在非常不同的发行版(分别是维基百科和谷歌图书)上训练的预训练语言模型,而 MITRE 使用了在大规模 Twitter 数据集上预训练的嵌入(类似发行版)。

很明显,在预训练和微调期间利用语言模型作为训练信号有其优势。尽管推文在语法上要非正式得多,序列长度也比书籍语料库中的平均句子短,但在这两种情况下,预先训练的模型都能够根据对目标数据的一些语法理解进行归纳和预测。

主题方面的 F 分数

下图比较了我们两种方法与 MITRE 方法的 F 值(支持)和 F 值(反对),这次是基于每个主题。查看这些结果,可以再次清楚地看到,OpenAI GPT 在大多数主题上明显优于 ULMFiT,这解释了为什么总体 F 分数较高。

Comparison of topic-wise F-scores from ULMFiT and the OpenAI transformer vs. MITRE’s

transformer 在所有主题上都做得很好,不管它是预测“赞成”还是“反对”类。

一个非常有趣的观察是,乌尔菲特和米特都对“气候变化是一个问题(反对)”做出了零的预测,而 GPT 却能够对这种情况做出一些正确的预测。进一步检查训练数据(如本文前面所示),这是同一个班级,我们有很少个训练样本(只有 15 个)。).值得注意的是,在如此少的训练示例下,transformer 能够获得一些上下文,并且仍然将一些预测分配给该类。从它在许多其他差异很大的类中的良好表现来看,这不像是侥幸!****

交叉列表结果:我们的与黄金参考

我们统计两个模型在每个类别中做出的总预测,并将其与任务创建者提供的黄金参考集(即“绝对真理”)中的标签进行交叉制表。

********

在这些表中,沿主对角线的元素表示正确预测的标签,非对角线元素表示分类器误入歧途的位置。很明显,这两种方法都相当好地预测了大多数类别,ULMFiT 在“反对”类别中做出了更全面的正确预测,而 transformer 在“支持”和“都不支持”类别中做出了更正确的预测。

我们可以看看训练数据分布,看看是否可以得出额外的推论。在训练数据中,属于“反对”类的推文要多得多(下图)。即使每个主题只有很少的训练样本,transformer 似乎也能够在少数类中实现更广泛的整体上下文。

Distribution of classes (overall) from original training data

词汇扩充的效果

当我们仅在原始训练集(2914 条推文)上微调语言模型时,ULMFiT 产生了相对较差的总体平均 F 分数(低于 0.55 )。只有当我们用来自ka ggle sensition 140 数据集的 200,000 条推文扩充语言模型时,ULMFiT 才产生了与 MITRE 基准测试结果相当的总体 F 值。ULMFiT 中 bi-lstm 的语言模型微调似乎需要比 transformer 更多的数据来概括****

我们的 GPT 模型在微调阶段不需要扩充词汇。事实上,它甚至能够在少数类中实现良好的推广,这似乎表明它在有限的训练样本中实现了对 Twitter 语法的更好的总体理解。所有这些看起来非常有趣,值得在更多样化的数据集上进一步研究。

序列长度的影响

众所周知,ULMFiT 在各种文本分类基准数据集(如 IMDb 和 AG News )上产生了一流的准确度。所有这些基准数据集的共同主题是,它们具有真正的序列长度(一些评论/新闻文章长达数百字),因此很明显,ULMFiT 使用的语言模型对长序列进行了很好的微调。另一方面,推文有 140 个字符的硬性限制,与电影评论或新闻文章的完整句子相比,这是相当小的序列。**

正如在 ULMFiT 论文中所描述的,当一个文档包含数百或数千个单词时,分类器使用“级联池”来帮助识别长序列中的上下文。为了避免在真正长的序列的情况下丢失信息,最后一个时间步的隐藏状态与隐藏状态的最大池和平均池表示相连接,如下所示。

Concatenated pooling: H is the vector of all hidden states

在这项研究中,这两种方法的模型架构都没有改变,但是,使用两种(最大值或平均值)表示中的一种来改变隐藏状态的表示可能有助于 ULMFiT 更好地推广到更小的序列,如 Tweets 的这种情况。

原始形式的 GPT(带有分类任务头)似乎没有推广到推特语法的问题,即使它是在也可能有长序列的书籍语料库上预先训练的。可能是变压器的自我注意机制和高维自我注意层能够适应变化的序列长度,同时学习 Tweet 语法的方面比隐藏层中具有 concat pooling 的 LSTMs 更好。这些是深刻的概念,可以更详细地研究。

语言模型调整的效果

在 ULMFiT 中,语言模型微调是训练分类器之前的必要步骤。在语言模型微调步骤中包含一个扩充的 Tweet 词汇表似乎可以让模型更好地理解 Tweet 语法,这似乎可以提高它的性能。在微调过程中,改变学习率、动力和辍学确实对 F 分数有微小但可忽略的总体影响。

在 OpenAI GPT 中,语言模型与使用加权参数的分类器同时被微调,通过按照下面的等式指定的辅助语言模型目标。

在 transformer 的情况下,当语言模型微调目标关闭(即lambda=0)时,平均宏观 F 值明显变得更差(低于 0.6)。因此,我们可以推断,预训练模型的权重本身不足以捕捉推特的语法,语言模型的微调确实有助于我们的模型更好地推广到推特数据。在我们的实验中,将lambda增加到非常高的值(5)或非常低的值(0.1)也没有提高 F 分数,所以我们的 Twitter 数据可能有一些特定的东西使lambda值 0.5 成为最佳值。有趣的是,当应用于完全不同的数据集时,LM 系数的其他值(lambda)是否有利。

训练数据大小的影响

ULMFiT 能够在每个单个主题上产生良好的分类性能(为此我们只有不到 500 个样本进行训练)。事实上,我们使用 ULMFiT 的最佳结果是通过在每个主题的基础上训练五个不同的 分类器获得的(尽管有一些数据扩充)。这是有意义的,因为 ULMFiT 已经被证明在非常有限的训练样本上产生了优秀的迁移学习性能(少至 100!).因此,在我们有非常少量的标记训练样本的情况下,ULMFiT 将是尝试迁移学习的一个好选择,至少对于分类任务来说是这样。****

另一方面,transformer 需要至少几千个训练样本才能很好地进行归纳,避免过度拟合。OpenAI 论文显示了从5000550000训练样本的一系列任务的良好结果。变压器在自注意头中有 786 维,在前馈网络中有 3072 维内部状态;因此,当我们的训练样本少于 1,000 个时,具有高维数的模型似乎会记住训练数据,并大量过度拟合数据(验证准确率降至 70%以下)。

预训练语言模型和架构的效果

两种语言模型都在不同的文本语料库(Wikitext 103 和 Google Books)上进行了预训练。此外,ULMFiT 使用 3 层双 LSTM 架构,而 OpenAI 使用变压器网络。Yoav Goldberg 关于这个话题的推文提供了一些思考。

根据我们的 Tweet 立场分类结果,当从相对少量的训练样本中学习有限上下文的特定情况语法时,transformer 似乎有好处——这可能更多地与 transformer 架构有关,而不是使用预训练的语言模型。然而,在两种架构上都有更一致的语言模型之前,很难说哪一种对结果的影响更大。

结论

在这个项目中,我们研究了两种强大的迁移学习方法(ULMFiT 和 OpenAI GPT)中使用的技术,用于一个来自不同分布的新任务(Tweets 的姿态检测)。我们为两个独立的基于 PyTorch 的框架开发了一个训练和分类管道,并将姿态评估的宏观 F 分数与 2016 年 MITRE 的最佳结果进行了比较。

这两种方法都实现了良好的性能和良好的通用性,只需对模型进行最少的定制,并且可以在合理的时间内进行微调(在单个特斯拉 P100 GPU 上,这两种方法总共需要大约一个小时)。这两种方法都被证明可以使迁移学习变得非常容易,并且可以用相对较小的学习曲线和相对较少的额外代码行来实现。

虽然在这种情况下,我们能够使用 OpenAI GPT 在几乎所有主题上获得更好的 F 分数,但这并不意味着基于 transformer 的模型对于这种分类任务来说总是更好的工具。这在很大程度上取决于数据的性质和所使用的语言模型,以及模型架构。 可以有许多更好的方法来微调模型 进行分类,更好的超参数选择(或模型定制)可以帮助进一步改善结果——只是不可能在这个项目中尝试所有的方法。

看起来,GPT transformer 的任务不可知和高度并行化的架构使其能够在针对该 Tweet stance 任务的 2-3 个训练周期内轻松实现快速泛化;然而,GPT 容易过度拟合,尤其是当我们的训练样本少于 1000 个时。ULMFiT 在使用非常小的数据集(少于 500 个训练样本)实现良好性能方面肯定要好得多;然而,它似乎需要在语言模型微调阶段增加训练数据的词汇(考虑到这个特定的 Tweet 分类任务包含与预训练语言模型非常不同的数据)。**

总的来说,在 NLP 中研究深度学习是一个非常令人兴奋的时刻,像这样强大的迁移学习技术的出现将有望在不久的将来为更广泛的实践者群体打开深度学习的应用!

2019 年 3 月 24 日编辑:自从 2019 年 2 月 OpenAI 发布 GPT-2 后,区分各种版本的变形金刚模型变得更加重要,所以之前提到的“OpenAI 变形金刚”现在更新为“GPT”,这是他们 2018 年论文中的变形金刚模型。

承认

这项工作是作为最终课程项目的一部分完成的,在这个项目中,我的同事安德鲁和阿布舍克为想法的产生以及数据清理和实验代码做出了重大贡献。他们(包括我自己)欢迎任何反馈/评论。

另外,如果你喜欢这篇文章,请在 LinkedIn 和 Twitter 上联系我!

关于所用硬件的说明

GitHub repo 中显示的所有笔记本和代码都是在一台配备了 NVIDIA GPU 的机器上运行的,整个培训过程大约需要 1 个小时(针对 ULMFiT ),在 P100 GPU 上不到一个小时(针对 transformer)——在一台纯 CPU 机器上运行相同的代码可能需要更长的时间!

迁移学习变得容易:编码一种强大的技术— Exxact

原文:https://towardsdatascience.com/transfer-learning-made-easy-coding-a-powerful-technique-exxact-f0f92baf4fb2?source=collection_archive---------36-----------------------

:仅由第一个神经网络看到的前 5 类图像。

但我们实际上感兴趣的是为最后 5 类图像建立一个神经网络——狗、青蛙、马、羊、卡车

:最后 5 类图像,仅由第二神经网络看到。

接下来,我们定义两组/两种类型的层:特征(卷积)和分类(密集)。

同样,不要担心这些代码片段的实现细节。你可以从 Keras 包的任何标准教程中了解细节。想法是理解概念。

要素图层:

feature_layers = [ Conv2D(filters, kernel_size, padding='valid', input_shape=input_shape), Activation('relu'), Conv2D(filters, kernel_size), Activation('relu'), MaxPooling2D(pool_size=pool_size), Dropout(0.25), Flatten(), ]

密集分类层:

classification_layers = [ Dense(128), Activation('relu'), Dropout(0.25), Dense(num_classes), Activation('softmax') ]

接下来,我们通过将特征 _ 层分类 _ 层堆叠在一起来创建完整的模型。

model_1 = Sequential(feature_layers + classification_layers)

然后,我们定义一个用于训练模型的函数(未示出),并且只训练模型一定数量的时期,以达到足够好的性能:

train_model(model_1, (x_train_lt5, y_train_lt5), (x_test_lt5, y_test_lt5), num_classes)

我们可以展示网络的准确性是如何随着训练时期而发展的:

:训练第一个网络时,验证各代的集合精度。

接下来,我们冻结特征层并重建模型

这种特征层的冻结是迁移学习的核心。这允许重新使用预训练的模型进行分类任务,因为用户可以在预训练的要素图层之上堆叠新的全连接图层,并获得良好的性能。

我们将创建一个名为 model_2 的全新模型,其中不可训练 特征 _ 图层可训练如下图所示:分类 _ 图层

for l in feature_layers: l.trainable = False model_2 = Sequential(feature_layers + classification_layers)

:第二网络的模型概要,显示了固定的和可训练的权重。固定权重直接从第一网络传输。

现在,我们训练第二个模型,观察它如何花费更少的总时间,仍然获得相同或更高的性能

train_model(model_2, (x_train_gte5, y_train_gte5),(x_test_gte5, y_test_gte5), num_classes)

第二个模型的准确性甚至高于第一个模型,尽管情况可能并非总是如此,并且取决于模型架构和数据集。

:在训练第二网络时,验证各时期的集合精度。

训练两个模型所需的时间如下所示:

:两个网络的训练时间。

我们取得了什么成就?

model_2 不仅比 model_1 训练得更快,它还以更高的基线精度开始,并在相同的时期数和相同的超参数(学习率、优化器、批量等)下实现了更好的最终精度。).并且在 model_1 没有看到的图像上实现了这种训练。

这意味着,尽管 model_1 是在飞机、汽车、鸟、猫、鹿的图像上训练的,但它学习到的权重在转移到 model_2 时,帮助 model_2 在完全不同类别的图像上实现了出色的分类性能——狗、青蛙、马、羊、或卡车

是不是很神奇?你现在可以用这么少的代码来构建这种迁移学习。同样,整个代码是开源的,在这里可以找到

原载于 2019 年 10 月 23 日https://blog.exxactcorp.com**

迁移学习:当你可以微调时为什么要训练?

原文:https://towardsdatascience.com/transfer-learning-picking-the-right-pre-trained-model-for-your-problem-bac69b488d16?source=collection_archive---------5-----------------------

PyTorch 迁移学习概述

在本帖中,我们将简要了解什么是迁移学习,以及如何最好地利用它提供的巨大潜力。让我们先从第一个问题开始。

什么是迁移学习?

迁移学习是使用预先训练好的模型来解决深度学习问题的艺术。预训练模型只不过是别人根据一些数据建立和训练的深度学习模型,以解决一些问题。

迁移学习是一种机器学习技术,在这种技术中,您使用预先训练的神经网络来解决与网络最初被训练来解决的问题类似的问题。例如,你可以重新利用为识别狗的品种而建立的深度学习模型来对狗和猫进行分类,而不是建立自己的模型。这可以省去你寻找有效的神经网络结构的痛苦、你花在训练上的时间、建立大量训练数据的麻烦,并保证良好的结果。你可以花很长时间想出一个 50 层的 CNN 来完美地区分你的猫和你的狗,或者你可以简单地重新利用在线提供的许多预先训练好的图像分类模型中的一个。现在,让我们看看这种重新定位到底包括什么。

使用预训练模型的三种不同方式

主要有三种不同的方式可以重新调整预训练模型。他们是,

  1. 特征提取。
  2. 复制预训练网络的架构。
  3. 冻结一些层,训练其他层。

特征提取:我们在这里需要做的就是改变输出层,给出猫和狗的概率(或者你的模型试图分类的类别数量),而不是最初训练的数千个类别。当我们尝试训练模型的数据与预训练模型最初训练的数据非常相似,并且我们的数据集很小时,这是理想的使用方法。这种机制被称为固定特征提取。我们仅重新训练我们添加的新输出层,并保留所有其他层的权重。

复制预训练网络的架构:在这里,我们定义一个与预训练模型具有相同架构的模型,该模型在执行与我们试图实现的任务相似的任务时表现出优异的结果,并从头开始训练它。我们丢弃预训练模型中每一层的权重,并根据我们的数据重新训练整个模型。当我们有大量数据要训练,但它与预训练模型训练的数据不太相似时,我们会采用这种方法。

冻结一些层,训练其他层:我们可以选择冻结预训练模型的最初 k 层,只训练最上面的 n-k 层。我们保持初始模型的权重与预训练模型的权重相同且不变,并在我们的数据上重新训练更高层。当我们的数据集很小并且数据相似性也很低时,采用这种方法。较低层关注可以从数据中提取的最基本的信息,因此这可以用于另一个问题,因为基本级别的信息通常是相同的。例如,构成一只狗的图片的相同曲线和边缘可以构成一个微小的癌细胞。

另一种常见的情况是数据相似性很高,数据集也很大。在这种情况下,我们保留模型的架构和模型的初始权重。然后,我们重新训练整个模型,以更新预训练模型的权重,从而更好地适应我们的具体问题。这是使用迁移学习的理想情况。

下图显示了随着数据集的大小和数据相似性的变化,应遵循的方法。

PyTorch 中的迁移学习

PyTorch 简单来说就是 Numpy 和 Keras 的私生子。即使您不熟悉 PyTorch,理解下面的代码也不会有问题。

PyTorch 中 torchvision.models 模块下有八种不同的预训练模型。它们是:

  1. Alex net
  2. VGG
  3. ResNet
  4. 挤压网
  5. 丹塞尼
  6. 盗梦空间 v3
  7. 谷歌网
  8. 洗牌网 v2

这些都是为图像分类而构建的卷积神经网络,在 ImageNet 数据集上进行训练。ImageNet 是一个根据 WordNet 层次结构组织的图像数据库,包含 14,197,122 幅图像,分属 21841 个类别。

由于 PyTorch 中所有预训练的模型都是在相同的数据集上为相同的任务训练的,所以我们选择哪一个都没有关系。让我们挑选 ResNet 网络,看看如何在我们前面讨论的不同场景中使用它。

用于图像识别的 ResNet 或深度残差学习在 pytorch、resnet-18、resnet-34、resnet-50、resnet-101 和 resnet-152 上有五个版本。

让我们从火炬视觉下载 ResNet-18。

**import** torchvision.models **as** models
model **=** models**.**resnet18(pretrained=True)

这是我们刚刚下载的模型的样子。

ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer4): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=512, out_features=1000, bias=True)
)

现在,让我们看看如何针对四个不同的问题训练这个模型。

数据集很小,数据相似度很高

考虑这个 kaggle 数据集。这包括猫的图像和其他非猫的图像。它有 209 个训练和 50 个像素为 64643 的测试图像。这显然是一个非常小的数据集来建立一个可靠的图像分类模型,但我们知道 ResNet 是在大量的动物和猫图像上训练的,所以我们可以使用 ResNet 作为固定的特征提取器来解决我们的猫与非猫问题。

num_ftrs = model.fc.in_features
num_ftrs

出局:512

model.fc.out_features

出局:1000

我们需要冻结所有网络,除了最后一层。我们需要设置 requires_grad = False 来冻结参数,这样梯度就不会反向计算()。默认情况下,新构造的模块的参数 requires_grad=True。

**for** param **in** model.parameters(): param.requires_grad = **False**

因为我们只需要最后一层给出两个概率,即图像是猫还是不是猫,所以让我们重新定义最后一层中输出特征的数量。

model.fc = nn.Linear(num_ftrs, 2)

这是我们模型的新架构。

ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer4): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=512, out_features=2, bias=True)
)

我们现在要做的就是训练模型的最后一层,我们将能够使用我们重新设计的 vgg16 来预测一幅图像是否是一只猫,只需要很少的数据和训练时间。

数据量小,数据相似度很低

考虑这个来自 kaggle 的数据集,犬球虫病寄生虫的图像。该数据集包含犬等孢菌和等孢菌的图像和标签。卵囊,一种感染狗肠道的球虫寄生虫。它是由萨格勒布兽医学院发明的。它包含了总共 341 张这两种寄生虫的图片。

Coccidiosis in Dogs

这个数据集很小,并且不属于 Imagenet 中的类别,VGG16 就是在 Imagenet 上训练的。在这种情况下,我们保留预训练模型的架构,冻结较低层并保留其权重,然后训练较低层更新其权重以适应我们的问题。

count = 0**for** child **in** model.children(): count+=1print(count)

出局:10

ResNet18 总共有 10 层。让我们冻结前 6 层。

count = 0**for** child **in** model.children(): count+=1
  **if** count **<** 7: **for** param **in** child.parameters():
        param.requires_grad = **False**

现在我们已经冻结了前 6 层,让我们重新定义最终的输出层,只给出 2 个输出而不是 1000。

model.fc = nn.Linear(num_ftrs, 2)

这是更新后的架构。

ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer4): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=512, out_features=2, bias=True)
)

现在,训练该模型将更新最后 4 层的权重,以正确区分犬等孢菌和等孢菌。卵囊寄生虫。

数据集规模很大,但数据相似度很低

考虑来自 kaggle,皮肤癌 MNIST: HAM10000
的这个数据集,其是色素性病变的多源皮肤镜图像的大集合,其具有属于 7 个不同类别的超过 10015 个皮肤镜图像,即光化性角化病和上皮内癌/鲍恩氏病( akiec )、基底细胞癌( bcc )、良性角化病样病变( bkl )、皮肤纤维瘤( df )、黑色素瘤( mel 【T10 这不是我们能在 Imagenet 中找到的那种数据。

在这里,我们只保留模型架构,而不保留预训练模型的权重。让我们重新定义输出层,将项目分为 7 个类别。

model.fc = nn.Linear(num_ftrs, 7)

在没有 GPU 的机器上训练这个模型需要几个小时,但是如果你运行它足够长的时间,你仍然会得到好的结果,而不需要定义你自己的模型架构。

数据量大,数据相似度高

考虑来自 kaggle 的 flowers 数据集。它包含了从 data flicr、google images、yandex images 等网站收集的 4242 幅花卉图片。图片分为五类:洋甘菊、郁金香、玫瑰、向日葵、蒲公英。每个班级大约有 800 张照片。动植物图像是 ImageNet 的一大部分。

这是应用迁移学习的理想情况。我们保留预训练模型的架构和每层的权重,并训练模型更新权重以匹配我们的特定问题。

model.fc = nn.Linear(num_ftrs, 5)
best_model_wts = copy.deepcopy(model.state_dict())

我们复制预训练模型的权重,并初始化我们的模型。我们使用我们的训练和测试阶段来更新这些权重。

for epoch in range(num_epochs):

      print(‘Epoch {}/{}’.format(epoch, num_epochs — 1))
      print(‘-’ * 10) for phase in [‘train’, ‘test’]:

      if phase == 'train':
         scheduler.step()
         model.train()  
      else:
         model.eval() running_loss = 0.0
      running_corrects = 0 for inputs, labels in dataloaders[phase]:

         inputs = inputs.to(device)
         labels = labels.to(device)
         optimizer.zero_grad() with torch.set_grad_enabled(phase == ‘train’):

               outputs = model(inputs)
               _, preds = torch.max(outputs, 1)
              loss = criterion(outputs, labels)

              if phase == ‘train’:
                  loss.backward()
                  optimizer.step() running_loss += loss.item() * inputs.size(0)
         running_corrects += torch.sum(preds == labels.data)

      epoch_loss = running_loss / dataset_sizes[phase]
      epoch_acc = running_corrects.double() / dataset_sizes[phase] print(‘{} Loss: {:.4f} Acc: {:.4f}’.format(
                            phase, epoch_loss, epoch_acc))

      if phase == ‘test’ and epoch_acc > best_acc:
          best_acc = epoch_acc
          best_model_wts = copy.deepcopy(model.state_dict())print(‘Best val Acc: {:4f}’.format(best_acc))
model.load_state_dict(best_model_wts)

这种模型也需要几个小时来训练,但即使只训练一个时期,也会产生很好的效果。

遵循相同的原则,您可以使用任何其他平台中的任何其他预训练网络来执行迁移学习。Resnet 和 pytorch 是为本文随机挑选的。任何其他 CNN 都会给出类似的结果。希望这能让你在用计算机视觉解决现实世界的问题时省下几个小时的痛苦。

使用 ELMO 嵌入的迁移学习

原文:https://towardsdatascience.com/transfer-learning-using-elmo-embedding-c4a7e415103c?source=collection_archive---------8-----------------------

去年,“自然语言处理”的主要发展是关于迁移学习的。基本上,迁移学习是在大规模数据集上训练模型,然后使用预训练的模型来处理另一个目标任务的学习的过程。迁移学习在自然语言处理领域变得很流行,这要归功于不同算法的最新性能,如 ULMFiT、Skip-Gram、Elmo、BERT 等。

由 Allen NLP 开发的 Elmo embedding 是 Tensorflow Hub 上提供的最先进的预训练模型。Elmo 嵌入从双向 LSTM 的内部状态中学习,并表示输入文本的上下文特征。在各种各样的 NLP 任务中,它已经被证明优于先前存在的预训练单词嵌入,如 word2vec 和 glove。这些任务中的一些是问题回答命名实体提取情感分析

使用 Tensorflow-hub 的 Elmo 嵌入

[## sambit 9238/深度学习

深度学习技术在自然语言处理、计算机视觉等领域的实现。-sambit 9238/深度学习

github.com](https://github.com/sambit9238/Deep-Learning/blob/master/elmo_embedding_tfhub.ipynb)

tensorflow-hub 中有一个预先训练好的 Elmo 嵌入模块。该模块支持原始文本字符串或标记化文本字符串作为输入。该模块输出每个 LSTM 层的固定嵌入、3 个层的可学习集合以及输入的固定平均汇集向量表示(对于句子)。要先使用这个模块,让我们把它下载到本地。

#download the model to local so it can be used again and again
!mkdir module/module_elmo2
# Download the module, and uncompress it to the destination folder. 
!curl -L "https://tfhub.dev/google/elmo/2?tf-hub-format=compressed" | tar -zxvC module/module_elmo2

该模块展示了用于层聚合的 4 个可训练标量权重。输出字典包含:

  • **word_emb**:基于字符的具有形状的单词表示**[batch_size, max_length, 512]**
  • **lstm_outputs1**:第一个 LSTM 潜州用形**[batch_size, max_length, 1024]**
  • **lstm_outputs2**:形状**[batch_size, max_length, 1024]**的第二个 LSTM 潜州。
  • **elmo**:3 层的加权和,其中权重是可训练的。这个张量有形状**[batch_size, max_length, 1024]**
  • **default**:形状**[batch_size, 1024]**的所有语境化单词表示的固定均值池。

要传递原始字符串作为输入:

elmo = hub.Module("module/module_elmo2/", trainable=**False**)
embeddings = elmo(
["the cat is on the mat", "what are you doing in evening"],
signature="default",
as_dict=**True**)["elmo"]
**with** tf.Session() **as** session:
    session.run([tf.global_variables_initializer(), tf.tables_initializer()])
    message_embeddings = session.run(embeddings)

输出消息嵌入的形状为(2,6,1024),因为有两个最大长度为 6 个单词的句子,并且为每个单词生成长度为 1024 的 1D 向量。它在内部根据空格对其进行标记。如果提供了一个少于 6 个单词的字符串,它会在内部向其追加空格。

我们还可以向模块提供标记化的字符串,如下所示:

elmo = hub.Module("sentence_wise_email/module/module_elmo2/", trainable=**False**)
tokens_input = [["the", "cat", "is", "on", "the", "mat"],
["what", "are", "you", "doing", "in", "evening"]]
tokens_length = [6, 5]
embeddings = elmo(
inputs={
"tokens": tokens_input,
"sequence_len": tokens_length
},
signature="tokens",
as_dict=**True**)["elmo"]
**with** tf.Session() **as** session:
    session.run([tf.global_variables_initializer(), tf.tables_initializer()])
    message_embeddings = session.run(embeddings)

输出将是相似的。

当对多个输入使用 in REST API 或 backend,而不是为每个调用初始化会话(这是一种开销)时,一种有效的方法是:

**def** embed_elmo2(module):
    **with** tf.Graph().as_default():
        sentences = tf.placeholder(tf.string)
        embed = hub.Module(module)
        embeddings = embed(sentences)
        session = tf.train.MonitoredSession()
    **return** **lambda** x: session.run(embeddings, {sentences: x})

embed_fn = embed_elmo2('module/module_elmo2')
embed_fn(["i am sambit"]).shape

这里,默认情况下,它为每个句子输出大小为 1024 的向量,这是所有上下文化单词表示的固定均值池。通常在分类器中使用它时,我们可以使用这个输出。

ELMO 嵌入一个简单的神经网络分类器

数据输入

我们将使用首次共和党辩论 Twitter 情绪数据,其中包含 2016 年首次共和党总统辩论的约 14K 条推文。我们正在制作一个二元分类器,因此将忽略带有中性情绪的推文。

df =  pd.read_csv("sentence_wise_email/Sentiment.csv",encoding="latin")
df = df[df["sentiment"]!="Neutral"]
df.loc[df["sentiment"]=='Negative',"sentiment"]=0
df.loc[df["sentiment"]=='Positive',"sentiment"]=1

数据处理

我们将对数据进行一些清理,比如处理像“I'll”、“It's”等缩写。我们还将删除数字、链接、标点符号和电子邮件地址。(名字也应该被删除,但在这里没有这样做,因为这个模型实际上是为其他目的开发的,在这种情况下我懒得更改:-))

**import** **re**
**def** cleanText(text):
    text = text.strip().replace("**\n**", " ").replace("**\r**", " ")
    text = replace_contraction(text)
    text = replace_links(text, "link")
    text = remove_numbers(text)
    text = re.sub(r'[,!@#$%^&*)(|/><";:.?**\'\\**}{]',"",text)
    text = text.lower()
    **return** text
X = np.array(df["text"].apply(cleanText))
y = np.array(df["sentiment"])

分类器模型构建

首先,需要为此导入必要的模块。然后,我们需要创建一个函数,对输入执行预训练的 Elmo 嵌入。

embed = hub.Module("module/module_elmo2")
**def** ELMoEmbedding(x):
    **return** embed(tf.squeeze(tf.cast(x, tf.string)), signature="default", as_dict=**True**)["default"]

然后,我们需要构建架构。这里我们使用高级 keras api 来构建它,因为它更容易使用。我们使用函数方法来建立一个简单的前馈神经网络以及正则化来避免过度拟合。

**def** build_model(): 
    input_text = Input(shape=(1,), dtype="string")
    embedding = Lambda(ELMoEmbedding, output_shape=(1024, ))(input_text)
    dense = Dense(256, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001))(embedding)
    pred = Dense(1, activation='sigmoid')(dense)
    model = Model(inputs=[input_text], outputs=pred)
    model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
    **return** model
model_elmo = build_model()

模型总结为:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         (None, 1)                 0         
_________________________________________________________________
lambda_2 (Lambda)            (None, 1024)              0         
_________________________________________________________________
dense_3 (Dense)              (None, 256)               262400    
_________________________________________________________________
dense_4 (Dense)              (None, 1)                 257       
=================================================================
Total params: 262,657
Trainable params: 262,657
Non-trainable params: 0
_________________________________________________________________

现在,既然模型架构(已编译)和数据都准备好了,是时候开始训练和保存已训练的权重了。

**with** tf.Session() **as** session:
    K.set_session(session)
    session.run(tf.global_variables_initializer())  
    session.run(tf.tables_initializer())
    history = model_elmo.fit(X, y, epochs=5, batch_size=256, validation_split = 0.2)
    model_elmo.save_weights('./model_elmo_weights.h5')

为了查看在训练时关于准确度和损失函数的学习是如何进行的,我们可以画一个图:

**import** **matplotlib.pyplot** **as** **plt**
%matplotlib inline

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)

plt.plot(epochs, acc, 'g', label='Training Acc')
plt.plot(epochs, val_acc, 'b', label='Validation Acc')
plt.title('Training and validation Acc')
plt.xlabel('Epochs')
plt.ylabel('Acc')
plt.legend()

plt.show()

似乎在第四纪元后,精确度没有太大的变化。你也可以画出同样的损失值。为了更好地了解模型何时达到其目的地,它必须接受更多时期的训练(这意味着增加成本,因为它是非常计算密集型的,需要 GPU 😃。

用训练好的模型进行预测

现在,为了使用训练好的模型进行预测,我们需要首先处理文本并对其进行排列。

new_text =  ['RT @FrankLuntz: Before the #GOPDebate, 14 focus groupers said they did not have favorable view of Trump.',
             'Chris Wallace(D) to be the 2nd worst partisan pontificating asshole "moderating" #GOPDebate @megynkelly'
            ]
#the texts should go through clean text also
new_text_pr = np.array(new_text, dtype=object)[:, np.newaxis]

现在我们可以开始一个 tensorflow 会话,我们将首先调用模型架构,然后从保存的文件中加载权重。调用 predict API 调用,会给我们每个文本的情感概率。分数越少,句子中嵌入的负面情绪越多。

**with** tf.Session() **as** session:
    K.set_session(session)
    session.run(tf.global_variables_initializer())  
    session.run(tf.tables_initializer())
    model_elmo = build_model() 
    model_elmo.load_weights('./model_elmo_weights.h5')
    **import** **time**
    t = time.time()
    predicts = model_elmo.predict(new_text_pr)
    print("time: ", time.time() - t)
    print(predicts)

输出是:

time:  0.6370120048522949
[[0.17122008]
 [0.3037635 ]]

我打印了时间只是为了显示需要多少时间,在特斯拉 k80 gpu 中两句话用了 0.63 秒。在 i5 处理器 cpu 中,耗时 14.3 秒。由于这是一个计算非常密集的过程,尤其是由于 Elmo 嵌入的高度复杂的架构,因此需要实时使用加速器。

如果你在上面的训练中看到,我们在 Elmo 嵌入上实现了 0.8094 的准确度,而使用预训练的 word2vec、glove 和在线嵌入,准确度分别为 0.7821、0.7432 和 0.7213。这些是 5 个时期后相同数据处理的结果。

Train on 8583 samples, validate on 2146 samples
Epoch 1/5
8583/8583 [==============================] - 63s 7ms/step - loss: 0.8087 - acc: 0.7853 - val_loss: 0.6919 - val_acc: 0.7819
Epoch 2/5
8583/8583 [==============================] - 62s 7ms/step - loss: 0.6015 - acc: 0.8265 - val_loss: 0.6359 - val_acc: 0.7651
Epoch 3/5
8583/8583 [==============================] - 62s 7ms/step - loss: 0.5377 - acc: 0.8371 - val_loss: 0.5407 - val_acc: 0.8169
Epoch 4/5
8583/8583 [==============================] - 62s 7ms/step - loss: 0.4946 - acc: 0.8401 - val_loss: 0.5016 - val_acc: 0.8071
Epoch 5/5
8583/8583 [==============================] - 63s 7ms/step - loss: 0.4836 - acc: 0.8396 - val_loss: 0.4995 - val_acc: 0.8094

https://tfhub.dev/google/elmo/2

[## 深层语境化的词汇表征

我们介绍了一种新的深度上下文化的单词表示,它模拟了(1)单词的复杂特征…

arxiv.org](https://arxiv.org/abs/1802.05365) [## 下游和语言探测任务中句子嵌入的评估

尽管新的句子嵌入方法发展速度很快,但要找到全面的句子嵌入方法仍然具有挑战性

arxiv.org](https://arxiv.org/abs/1806.06259)

用一个小数据集进行迁移学习——“nanos gigantum humeris insidentes”

原文:https://towardsdatascience.com/transfer-learning-with-a-small-data-set-nanos-gigantum-humeris-insidentes-e1a7ed6404a7?source=collection_archive---------19-----------------------

尝试不同的架构— VGG16、Resnet50 和 InceptionV3 —以增强您的模型(使用 TensorFlow 和 Keras)

Image by Myriam Zilles from Pixabay

一个常见的 TL 场景是使用一个在大型数据集上训练的 ConvNet 来对一个具有 相似但更小的 数据集的域进行分类(其他场景的一个很好的总结可以在 这里 找到)。这种情况下,可接受的方法是将 ConvNet 用作固定特征提取器,或者对 ConvNet 进行微调。在实践中,这不是一个“非此即彼”的情况,而是一个范围,可以从最“严格”的即插即用方法(只有最后一个 FC 层从 ConvNet(顶部)中删除,并由适合新任务的线性分类器替换)到一些更“宽松”的方法(我们训练一些 ConvNet 层或冻结它们或两者的任何其他组合)变化。

有多篇文章详细描述了上述内容,但当我尝试实施这些原则时,我总是会产生以下问题:

  1. 我应该选择哪种 ConvNet 我如何将架构与我的具体任务相匹配?在大多数情况下,架构似乎是从框架可用选项中任意选择的。
  2. 什么是什么是相似**——这两个都是相对名词。与 ImageNet 相比,我的数据集可能总是很小,或者说小与我选择的架构的大小有关?相似性也是一样, ImageNet 有一千个类别,如果我想只对人类进行分类,这些域有多相似?

如果你想直接进入代码和实验文档,它们就在这里。

手头的任务

在我之前的一个项目中,我使用了一个简单的 CNN 模型进行二进制图像分类。这项任务是对 2 张特定的人脸进行分类,因此数据集很小(大约 1350 张图片)。结果很好,但不是很好,大约 0.9 的精确度。我没有选择通过扩大数据集来改进它,因为它是从有限的信息资源建立的。我将尝试使用这个测试用例来回答上面的问题。使用三个预先训练好的 conv net—vgg 16、 ResNet50 和 InceptionV3 —让我们检查案例,并在实施迁移学习时建立一些实践的基本规则,提出一些见解。

Freeze all layers, replace top.

VGG16 —纯真年代

VGG16 基本上是一堆 Conv 层堆叠在另一个之上——这是最类似于我的简单的 CNN。让我们首先尝试最简单的方法:我们将按原样使用它, ImageNet 的所有预训练权重,冻结所有层,删除最后一个 FC 层( ImageNet 有一个 1000 类别分类器),并用二进制分类器替换它。

Freeze all layer — accuracy

Freeze all layers — loss

我的假设是,由于我的领域——人脸图像——与 ImageNet 领域——各种物体的图像——非常相似,所以即使是最高层的特征也与我的任务相关。但是,唉,我们看到了一些损失的趋同,但还不足以帮助准确性有意义。这是为什么呢?在我们试图回答这个问题之前,让我们做另一个实验。这次我们将重新训练整个网络,没有预先训练的重量。

Train all layers — loss

Train all layers — accuracy

尽管如此,损耗在某个点上停滞不前,精度也停滞不前。好了,现在让我们试着理解为什么。我能想到的可能原因:

  1. 数据集太小
  2. 数据集与 ImageNet 不相似
  3. 建筑不适合。

我不认为我的数据太小(1 ),因为在这个架构中没有比我的简单 CNN 更多的可训练参数。可能是数据域不相似(2),至少在上层是如此,这需要测试。或者可能是建筑(3)。这是类似于我的,但它堆栈更多的 Conv 层,这可能会导致不同的问题。

让我们试着决定关于解释(2)。我将冻结一些较低的图层,试图保留低级别特征,并训练较高的图层,试图使它们适合我的数据。

Freeze lower, train higher, replace top.

让我们冻结前六层(前两层)并训练其余部分。请注意,微调的方法是只训练顶部,然后解冻所需的层并重新训练。

Freeze 6 first, train the rest — loss

嗯,这并没有改善事情。我也尝试了其他层,但没有改善,你可以在这里找到我所有的实验。

Freeze 6 first, train the rest — accuracy

好吧,所以不是大小(1),不是相似(2),一定是架构(3)。我仍然不能解释为什么,但我可以试着证明它。让我们试试另一个,比较一下结果。

ResNet50 —残值

剩余网络是为了解决可能影响我的 VGG 模型的深层网络问题而创建的。我们将经历我们在 VGG 使用的相同过程,我们将从冻结所有层开始,并根据结果继续。

Freeze all layers — loss

终于有些进展了。训练精度约为 0.97,看起来模型终于学到了一些东西。验证精度为 0.5

Freeze all layers — accuracy

看起来,因为我只训练顶部,我可能非常适合我的训练设置。让我们继续解冻所有图层,就像我们对 VGG 做的那样,看看是否有帮助。

我将重新初始化模型,这次我不会冻结任何东西。

**

Train all layers — accuracy

这里发生了什么?在大约 21 个时期后的某个时间点,验证损失下降,准确性跃升至 0.91,这与我用简单的 CNN 得到的结果大致相同,比 VGG 好得多。要指出的另一个要点是,尽管网络被完全重新训练,但初始权重是“ ImageNet ”权重,而不是随机的。这一点很重要,也可能是这个模型得以提升的原因。

在所有这些实验之后,我想在这里说明的一点是:

选择正确的架构是利用迁移学习的关键部分

我现在和我原来的 CNN 模式有分歧,但是迁移学习的好处在哪里?我能从 ResNet 中挤出更多的果汁吗,或者我应该尝试另一种架构?我试着只冻结模型的一部分,甚至移除一些上层,但是还没有太大进展。我想我会继续关注盗梦空间架构,看看事情会不会变得更顺利

InceptionV3 —分而治之

Inception 是 CNN 分类器的又一次进化。这里我将使用 V3,它不是最新的版本,但仍然是非常先进的。

Freeze all layers — accuracy

我很快运行了两个实验,就像我对前两个架构所做的那样——冻结所有层和释放所有层——在这两个实验中,我在验证集上得到了大约 0.7,与 ResNet 结果非常相似,但趋势仍然不乐观。

Train all layers — accuracy

我想尝试一些新的东西:Inception 是一个非常大的网络,让我们尝试删除部分层,只使用网络的一部分——具体来说,我将删除 Conv 层的较高堆栈,并训练较低的层。

Inception v1

动机现在很清楚了——使用网络的底层功能,并针对我的问题进行微调。我不得不说这是一个反复试验的游戏,但是有一些逻辑。如果你看左边的初始架构,你会看到它是由连接的块构成的。因此,在这些点之一“剖析”网络并插入分类器是有意义的。甚至好像是专门为它设计的。意识到这一点使得试错游戏变得容易多了。因此,我要做的是找到分割网络的最佳模块,并尝试从该点进行微调。

经过一些试验后,我发现使用“_ 5”——这是级联层的名称,您可以看到,当使用 model.summary() 方法时——会给出最好的结果。一些更多的参数优化,我得到了大约 0.97 的验证精度。

这是一个很大的改进,似乎盗梦空间架构最适合我的任务,或者可能是我迄今为止使用的最先进的,我还不能排除这个结论。在我总结之前,让我们尝试另一个调整:上次实验的最佳纪元是 50 个中的第 11 个。从那里开始,验证慢慢下降,这是过度拟合的迹象。假设我们已经尝试了所有的参数调整,让我们尝试解冻一些层。我们用 ResNet 试过,效果不太好,也许盗梦空间架构会更宽容一些。我将解冻从“混合 _4”到“混合 _5”的所有层,这意味着一个级联堆栈。这将使新模型的上层能够根据新数据进行训练,并有望提高准确性。

Freeze lower, unfreeze middle, remove higher, replace top.

验证准确率目前最高~0.98。

我们设法改进了我们需要的部分,去掉了其他部分。TL 已经证明了自己是有用的,但是上面所有的实验都花费了大量的时间。

让我们想想下一个项目有什么可以改进的。有什么可以抵扣的?

  1. 根据您的需求选择正确的架构—下次我会从最新最好的开始,它可能有最好的机会。
  2. 只拿你需要的 —试着理解架构——至少是高层次的知识——你不需要阅读每一篇文章,但要确保你理解它的优点,尤其是它的缺点。
  3. 优化参数作为最后一步 —节省大量时间和迭代
  4. 记录你的实验 — 这是一个节省时间和跟踪工作的好方法,你可以通过下面的代码找到我所有的实验。

请分享你的想法,代码和文档都在这里。在 Medium 或 Twitter 上关注我的博客文章更新!

PySpark 中基于迁移学习的多类图像分类

原文:https://towardsdatascience.com/transfer-learning-with-pyspark-729d49604d45?source=collection_archive---------4-----------------------

src: Photo by Pixabay from Pexels

Apache Spark 深度学习管道的计算机视觉问题的简短演示。

介绍

在本文中,我们将使用 Keras (TensorFlow 后端)、PySpark 和深度学习管道库来构建一个端到端的深度学习计算机视觉解决方案,用于在 Spark 集群上运行的多类图像分类问题。Spark 是一个强大的开源分布式分析引擎,可以高速处理大量数据。PySpark 是用于 Spark 的 Python API,它允许我们使用 Python 编程语言并利用 Apache Spark 的强大功能。

在本文中,我们将主要使用深度学习管道 (DLP) ,这是一个高级深度学习框架,通过 Spark MLlib 管道 API 来促进常见的深度学习工作流。它目前通过 TensorFlow 后端支持 TensorFlow 和 Keras。在本文中,我们将使用这个 DLP 构建一个将在 Spark 集群上运行的多类图像分类器。要设置好一切,请遵循本 安装说明

[## 深度学习管道—数据块文档

深度学习管道库包含在 Databricks Runtime ML 中,这是一个机器学习运行时,它提供了一个…

docs.databricks.com](https://docs.databricks.com/applications/deep-learning/single-node-training/deep-learning-pipelines.html)

该库来自 Databricks ,并利用 Spark 的两个最强方面:

  1. 本着 Spark 和 Spark MLlib 的精神,它提供了易于使用的 API,可以在非常少的几行代码中实现深度学习。
  2. 它使用 Spark 强大的分布式引擎在海量数据集上扩展深度学习。

我的目标是用 DLP 将深度学习整合到 PySpark 管道中。我在本地机器上使用 Jupyter Notebook 运行整个项目来构建原型。然而,我发现把这个原型放在一起有点困难,所以我希望其他人会发现这篇文章很有用。我将把这个项目分成几个步骤。有些步骤是不言自明的,但对于其他步骤,我会尽可能解释清楚,让它变得不那么痛苦。如果你只想看有解释和代码的笔记本,你可以直接去 GitHub 。

计划

  • 迁移学习:深度学习管道的简短直觉(来自数据块
  • 数据集:引入多类图像数据。
  • 建模:建立模型,训练。
  • 评估:使用各种评估指标评估模型性能。

迁移学习

迁移学习是机器学习中的一种技术,通常专注于保存在解决一个问题时获得的知识(权重和偏差),并进一步将其应用于不同但相关的问题。

深度学习管道提供对图像执行迁移学习的实用程序,这是开始使用深度学习的最快方法之一。借助 特征器的概念, 深度学习管道能够在 Spark-Cluster 上实现快速迁移学习。目前,它为迁移学习提供了以下神经网络:

  • InceptionV3
  • 例外
  • ResNet50
  • VGG16
  • VGG19

出于演示的目的,我们将只研究 InceptionV3 模型。你可以在这里阅读这款的技术细节。

以下示例结合了 Spark 中的 InceptionV3 模型和多项式逻辑回归。来自深度学习管道的一个名为 DeepImageFeaturizer 的实用函数自动剥离预训练神经网络的最后一层,并使用所有先前层的输出作为逻辑回归算法的特征

数据集

孟加拉文字有十个数字(表示从 0 到 9 的数字的字母或符号)。大于 9 的数字用孟加拉语书写,使用基数为 10 的位置数字系统。

我们选择numtab作为我们数据集的来源。这是孟加拉手写数字数据的集合。该数据集包含来自 2,700 多个贡献者的 85,000 多个数字。但是这里我们不打算处理整个数据集,而是随机选择每一类的 50 张图片。

Fig 1: Each Folder Contains 50 Images [ Classes (0 to 9) ]

让我们看看上面十个文件夹里都有什么。出于演示目的,我将下面显示的每个图像重命名为其对应的类标签。

Fig 2: Bengali Handwritten Digit

首先,我们将所有图像加载到 SparkData Frame。然后我们建立模型并训练它。之后,我们将评估我们训练好的模型的性能。

加载图像

数据集(从 0 到 9)包含近 500 个手写孟加拉数字(每类 50 个图像)。这里,我们手动将每个图像加载到带有目标列的 spark 数据帧中。在加载了整个数据集之后,我们将训练集和最终测试集随机分成 8:2 的比例。

我们的目标是用训练数据集训练模型,最后用测试数据集评估模型的性能。

# necessary import 
from pyspark.sql import SparkSession
from pyspark.ml.image import ImageSchema
from pyspark.sql.functions import lit
from functools import reduce
# create a spark session
spark = SparkSession.builder.appName('DigitRecog').getOrCreate()
# loaded image
zero = ImageSchema.readImages("0").withColumn("label", lit(0))
one = ImageSchema.readImages("1").withColumn("label", lit(1))
two = ImageSchema.readImages("2").withColumn("label", lit(2))
three = ImageSchema.readImages("3").withColumn("label", lit(3))
four = ImageSchema.readImages("4").withColumn("label", lit(4))
five = ImageSchema.readImages("5").withColumn("label", lit(5))
six = ImageSchema.readImages("6").withColumn("label", lit(6))
seven = ImageSchema.readImages("7").withColumn("label", lit(7))
eight = ImageSchema.readImages("8").withColumn("label", lit(8))
nine = ImageSchema.readImages("9").withColumn("label", lit(9))
dataframes = [zero, one, two, three,four,
             five, six, seven, eight, nine]
# merge data frame
df = reduce(lambda first, second: first.union(second), dataframes)
# repartition dataframe 
df = df.repartition(200)
# split the data-frame
train, test = df.randomSplit([0.8, 0.2], 42)

在这里,我们可以对火花数据帧进行各种探索性的数据分析。我们还可以查看数据框的模式。

df.printSchema()
root
 |-- image: struct (nullable = true)
 |    |-- origin: string (nullable = true)
 |    |-- height: integer (nullable = false)
 |    |-- width: integer (nullable = false)
 |    |-- nChannels: integer (nullable = false)
 |    |-- mode: integer (nullable = false)
 |    |-- data: binary (nullable = false)
 |-- label: integer (nullable = false)

我们也可以使用将 Spark-DataFrame 转换成 Pandas-DataFrame。托潘达斯()。****

模特培训

这里我们结合 Spark 中的 InceptionV3 模型和 logistic 回归deepimagefeaturezer自动剥离预训练神经网络的最后一层,并使用所有先前层的输出作为逻辑回归算法的特征。

由于 logistic 回归是一种简单快速的算法,所以这种迁移学习训练能够快速收敛。

from pyspark.ml.evaluation import MulticlassClassificationEvaluator
from pyspark.ml.classification import LogisticRegression
from pyspark.ml import Pipeline
from sparkdl import DeepImageFeaturizer
# model: InceptionV3
# extracting feature from images
featurizer = DeepImageFeaturizer(inputCol="image",
                                 outputCol="features",
                                 modelName="InceptionV3")
# used as a multi class classifier
lr = LogisticRegression(maxIter=5, regParam=0.03, 
                        elasticNetParam=0.5, labelCol="label")
# define a pipeline model
sparkdn = Pipeline(stages=[featurizer, lr])
spark_model = sparkdn.fit(train) # start fitting or training

估价

现在,是时候评估模型性能了。我们现在要评估四个评估指标,比如测试数据集上的得分、精确度、召回率和准确度。

from pyspark.ml.evaluation import MulticlassClassificationEvaluator
# evaluate the model with test set
evaluator = MulticlassClassificationEvaluator() 
tx_test = spark_model.transform(test)
print('F1-Score ', evaluator.evaluate(
                          tx_test, 
                          {evaluator.metricName: 'f1'})
)
print('Precision ', evaluator.evaluate(
                          tx_test,
                          {evaluator.metricName: 'weightedPrecision'})
)
print('Recall ', evaluator.evaluate(
                          tx_test, 
                          {evaluator.metricName: 'weightedRecall'})
)
print('Accuracy ', evaluator.evaluate(
                          tx_test, 
                          {evaluator.metricName: 'accuracy'})
)

这里我们得到了结果。到现在都很有希望。

F1-Score  0.8111782234361806
Precision  0.8422058244785519
Recall  0.8090909090909091
Accuracy  0.8090909090909091

混乱矩阵

这里,我们将使用混淆矩阵总结分类模型的性能。

import matplotlib.pyplot as plt
import numpy as np
import itertools
def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.GnBu):
      plt.imshow(cm, interpolation='nearest', cmap=cmap)
      plt.title(title)
      tick_marks = np.arange(len(classes))
      plt.xticks(tick_marks, classes, rotation=45)
      plt.yticks(tick_marks, classes)
      fmt = '.2f' if normalize else 'd'
      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] > thresh else "black")

      plt.tight_layout()
      plt.ylabel('True label')
      plt.xlabel('Predicted label')

为此,我们需要将 Spark-DataFrame 转换为 Pandas-DataFrame 首先是和然后是调用带有预测标签的混淆矩阵。

from sklearn.metrics import confusion_matrix

y_true = tx_test.select("label")
y_true = y_true.toPandas()

y_pred = tx_test.select("prediction")
y_pred = y_pred.toPandas()

cnf_matrix = confusion_matrix(y_true, y_pred,labels=range(10))

让我们来想象一下混淆矩阵****

import seaborn as sns
%matplotlib inline

sns.set_style("darkgrid")
plt.figure(figsize=(7,7))
plt.grid(False)

# call pre defined function
plot_confusion_matrix(cnf_matrix, classes=range(10))

Fig 3: Confusion Matrix for 10 Bengali Digits (0 to 9)

分类报告

在这里我们还可以通过评估矩阵得到每个类的分类报告。

from sklearn.metrics import classification_report

target_names = ["Class {}".format(i) for i in range(10)]
print(classification_report(y_true, y_pred, target_names = target_names))

它将更好地展示每个类别标签预测的模型性能。

precision  recall   f1-score   support Class 0       1.00      0.92      0.96        13
     Class 1       0.57      1.00      0.73         8
     Class 2       0.64      1.00      0.78         7
     Class 3       0.88      0.70      0.78        10
     Class 4       0.90      1.00      0.95         9
     Class 5       0.67      0.83      0.74        12
     Class 6       0.83      0.62      0.71         8
     Class 7       1.00      0.80      0.89        10
     Class 8       1.00      0.80      0.89        20
     Class 9       0.70      0.54      0.61        13 micro avg       0.81      0.81      0.81       110
   macro avg       0.82      0.82      0.80       110
weighted avg       0.84      0.81      0.81       110

ROC AUC 得分

我们也来找一下这个模型的 ROC AUC 评分点。我在这里找到了下面这段来自 h 的代码。

from sklearn.metrics import roc_curve, auc, roc_auc_score
from sklearn.preprocessing import LabelBinarizer

def multiclass_roc_auc_score(y_test, y_pred, average="macro"):
    lb = LabelBinarizer()
    lb.fit(y_test)
    y_test = lb.transform(y_test)
    y_pred = lb.transform(y_pred)
    return roc_auc_score(y_test, y_pred, average=average)

print('ROC AUC score:', multiclass_roc_auc_score(y_true,y_pred))

它的得分为 0.901。****

预测样本

让我们来看看它的一些预测,与真正的标签相比较。

# all columns after transformations
print(tx_test.columns)

# see some predicted output
tx_test.select('image', "prediction", "label").show()

并且,结果将如下所示

['image', 'label', 'features', 'rawPrediction', 'probability', 'prediction']
+------------------+----------+--------+
|       image      |prediction|  label |
+------------------+----------+--------+
|[file:/home/i...|       1.0|    1|
|[file:/home/i...|       8.0|    8|
|[file:/home/i...|       9.0|    9|
|[file:/home/i...|       1.0|    8|
|[file:/home/i...|       1.0|    1|
|[file:/home/i...|       1.0|    9|
|[file:/home/i...|       0.0|    0|
|[file:/home/i...|       2.0|    9|
|[file:/home/i...|       8.0|    8|
|[file:/home/i...|       9.0|    9|
|[file:/home/i...|       0.0|    0|
|[file:/home/i...|       4.0|    0|
|[file:/home/i...|       5.0|    9|
|[file:/home/i...|       1.0|    1|
|[file:/home/i...|       9.0|    9|
|[file:/home/i...|       9.0|    9|
|[file:/home/i...|       1.0|    1|
|[file:/home/i...|       1.0|    1|
|[file:/home/i...|       9.0|    9|
|[file:/home/i...|       3.0|    6|
+--------------------+----------+-----+
only showing top 20 rows

尾注

虽然我们已经使用了一个ImageNet权重,但是我们的模型在识别手写数字方面表现得非常好。此外,为了更好的泛化,我们也没有执行任何图像处理任务。此外,与 ImageNet 数据集相比,该模型是在非常少量的数据上训练的。****

在一个非常高的层次上,每个 Spark 应用程序都由一个驱动程序组成,该程序在一个集群上启动各种并行操作。驱动程序包含我们的应用程序的主要功能,定义集群上的分布式数据集,然后对它们应用操作。

这是一个独立的应用程序,我们首先将应用程序链接到 Spark,然后在我们的程序中导入 Spark 包,并使用 SparkSession 创建一个 SparkContext 。虽然我们在单台机器上工作,但是我们可以将同一个 shell 连接到一个集群,并行训练数据。

但是,您可以从下面的链接获得今天演示的源代码,也可以关注我的 GitHub 以获取未来的代码更新。😃

**** [## innat/迁移-学习-PySpark

计算机视觉问题的一个有前途的解决方案,结合了最先进的技术:深度…

github.com](https://github.com/innat/Transfer-Learning-PySpark)****

下一步是什么?

接下来,我们将使用 Spark 进行分布式超参数调整 ,并将尝试自定义 Keras 模型和一些新的具有挑战性的示例。取得联系:)

打招呼上: 邮箱|LinkedIn|Quora|GitHub|推特|insta gram

相关技术

  • 配有 Keras & PySpark 的分布式 DL—Elephas
  • Apache Spark 的分布式深度学习库— BigDL
  • 到阿帕奇火花星团的张量流— 张量流 OnSpark

参考

  • Databricks: 深度学习指南
  • Apache Spark: PySpark 机器学习

用 TF 2.0 迁移学习

原文:https://towardsdatascience.com/transfer-learning-with-tf-2-0-ff960901046d?source=collection_archive---------10-----------------------

站在巨人的肩膀上

Photo by Scott Blake on Unsplash

迁移学习是这样一个过程:采用一个已在相似域的数据集上训练过的模型,然后通过添加层来扩展该模型,以根据您的数据进行预测。

已训练的模型(称为预训练模型)存在于 TensorFlow 库中。这些人通常在 Imagenet 大规模视觉识别挑战(Imagenet)可用的图像上接受训练。该挑战赛提供了 120 万张图片,可分为 1000 个类别。

预训练模型的主要优势在于,它们是在这些图像上使用我们通常无法获得或购买成本过高的硬件进行训练的。这些模型通常有一个最终层,将输出分成 1000 个不同的类别。

在迁移学习中,你要做的是选择一个模型,然后冻结权重。然后向模型中添加新的层,并训练权重,直到收敛。

TensorFlow 中有各种预训练的模型,如 VGG,我们将利用这些模型。让我们从安装 TF 2.0 和导入必要的库开始。

Install TensorFlow 2.0

接下来,我们需要为我们的图像和模型定义一些常量。这些细节包括我们在最终图层中想要的类的数量,以及颜色通道的数量和图像的尺寸。

我们现在准备创建我们的基础模型,这是没有最终层的预训练模型。我们将可训练值设置为 false,以防止在训练期间更新权重。

打印基础模型将显示架构。然后,我们可以继续向基础模型添加新层。我们可以为此使用函数式 API。

就这样,我们有了一个可以用来训练的模型。不要忘记,您需要通过创建一个生成器来将您的图像转换成正确的格式,以便进行培训。我喜欢用 Python 处理文件名列表(文件)和它们所属的类(类别)。有了这两个列表,下面的代码将创建您的生成器。

Image input pipeline

然后,您可以继续编译和训练您的模型。

然后,您可以检查培训的结果,并进行修改以进行改进。你应该改变steps_per_epochepochs。您应该选择您的优化器并配置学习率。您可能还想携带我们的数据增强功能,使您的训练数据更加可靠。

练习愉快。

使用 Python 的 Matplotlib 将灰度图像转换为 RGB

原文:https://towardsdatascience.com/transform-grayscale-images-to-rgb-using-pythons-matplotlib-6a0625d992dd?source=collection_archive---------12-----------------------

了解图像数据结构,同时为计算机视觉和深度学习管道添加两个维度

R, G, & B — Arabic numeral ‘3’

数据预处理对于计算机视觉应用至关重要,将灰度图像正确转换为当前深度学习框架所期望的 RGB 格式是一项必不可少的技术。那是什么意思?

理解彩色图像结构

大多数彩色照片由三个互锁的数组组成,每个数组负责红色、绿色或蓝色值(因此是 RGB ),每个数组中的整数值代表一个像素值。同时,黑白或灰度照片只有一个通道,从一个阵列中读取。

使用 matplotlib 库,我们来看一幅彩色(RGB)图像:

img = plt.imread('whales/547b59eec.jpg')
plt.imshow(img)
print(img.shape)
(525, 1050, 3)

matplotlib.plot.shape 调用的输出告诉我们,图像的高度为 525 像素,宽度为 1050 像素,有三个这样大小的数组(通道)。

A whale image, from a recent kaggle competition

img对象是<类‘numpy . ndarray’>,所以让我们看看每一层的形状和值:

#values
print(img[524][1049][2])
198print(img[524][1049])
[155 177 198]print(img[524])
[[ 68 107 140]
 [ 76 115 148]
 [ 76 115 148]
 [ 75 114 147]
 ...
 [171 196 216]
 [171 193 214]
 [171 193 214]
 [155 177 198]]

好了,上面的打印命令告诉我们这个由 1050 列(宽)和 525 行(高)组成的图像是什么?

首先,我们看最后一个像素的值,在最后一列的最后一行和最后一个通道:198。这告诉我们该文件很可能使用 0 到 255 之间的值。

接下来,我们查看所有三个通道中该像素的值:[155,177,198]。这些是该像素的红色、绿色和蓝色值。

为了好玩,我们可以跨所有层和所有行查看最后一行的值。

了解灰度图像结构

灰度图像只有一个通道!就是这样!

问题是

引用 Pytorch 文档:所有预训练的模型都期望输入图像以相同的方式标准化,即小批量的 3 通道 RGB 形状图像(3 x H x W)...

因此,试图通过许多依赖于从标准商品模型(如 Resnet18 或-34)进行转移学习的计算机视觉/深度学习管道来摄取灰度将导致各种错误。

解决方案

给灰度添加两个额外的通道!有很多方法可以做到这一点,所以我的方法如下:将第一层复制到一个新的 3D 阵列的新层中,从而生成一个彩色图像(黑白的,所以它仍然是 B&W)。

我将使用来自阿拉伯手写数字数据集的一个正方形图像作为例子。形状为(28, 28),确认为单通道图像。

matplotlib defaults grayscales as above

因为我想把它输入到一个基于 Resnet34 的模型中,所以我需要三个通道。

显而易见(但不太正确)的方法是添加两个相同大小的零数组:

dim = np.zeros((28,28))R = np.stack((O,dim, dim), axis=2)

O是我们最初的阵列。我们可以很容易地将两个相同形状的零阵列相加,但我们将得到一个红色为主的图像:

three channels, all values in channel 1

哎呦!我们希望在所有渠道中填充相同的值。不过,在此之前,让我们看看,如果我们将原始数组滚动通过每种非完全 RGB 的可能性,会发生什么:

R, G, B

RG, RB, GB

好了,这是 RGB:

Finally!

仅此而已。

附加代码在我的 github 上:www.github.com/matthewarthur。我的 LinkedIn 是 https://www.linkedin.com/in/matt-a-8208aaa/的。打个招呼。

笔记

[1]https://pytorch.org/docs/stable/torchvision/models.html

[2]https://www . cs . Virginia . edu/~ Vicente/recognition/notebooks/image _ processing _ lab . html

[3]numpy 中的索引在这里详细介绍:https://docs . scipy . org/doc/numpy-1 . 10 . 0/user/basics . Indexing . html

变形金刚——你需要的只是关注

原文:https://towardsdatascience.com/transformer-attention-is-all-you-need-1e455701fdd9?source=collection_archive---------5-----------------------

通过自我注意和位置编码改进 Seq2Seq 建模的方法

在之前的帖子中,我们讨论了基于注意力的 seq2seq 模型以及它们诞生背后的逻辑。计划是创建一个差不多的 PyTorch 实现故事,但是结果是,PyTorch 文档提供了一个极好的过程这里。所以在这里,我开始我计划中的下一个项目——变压器——,它的工作原理是自我关注

让我们对基于注意力的模型做一个两行的回顾。它的主要思想是,它接受一个输入序列和与之相关的所有隐藏状态,在输出的每个实例中,它决定输入的哪一部分是有用的,并随后基于此决定输出。通过在编码器和解码器中使用 RNNs 或 LSTMs 中的任一个来捕获顺序性质。

在注意力是你所需要的全部论文中,作者已经表明,这种顺序性质可以通过仅使用注意力机制来捕捉——而不使用 LSTMs 或 RNNs。

在这篇文章中,我们将遵循与上一篇文章相似的结构,从黑盒开始,慢慢地一个接一个地理解每个组件,从而增加整个架构的清晰度。学完本课程后,您将会很好地掌握变压器网络的每个组件,以及它们如何帮助您获得想要的结果。

先修课程:关于注意力网络和其他基于编解码器的模型的基础知识。神经网络和标准化技术。

变压器黑匣子:

Seq2Seq Model

让我们首先了解注意力模型和变压器模型之间的基本异同。两者都旨在使用编码器-解码器方法实现相同的结果。编码器将原始输入序列转换成隐藏状态向量形式的潜在表示。解码器试图使用这个潜在表示来预测输出序列。但是基于 RNN 的方法有一个固有的缺陷。由于顺序计算的基本限制,不可能并行化网络,这使得难以在长序列上训练。这反过来限制了训练时可以使用的批量大小。这已经被变形金刚缓解了,我们很快就会知道怎么做。所以让我们开始吧。

(我想指出,这篇文章有一点额外的阅读和较少的图片,但我会确保阅读尽可能简单。)

背景

transformer 架构继续使用编码器-解码器框架,这是原始注意力网络的一部分——给定一个输入序列,基于上下文创建它的编码,并将基于上下文的编码解码为输出序列。

除了不能并行化的问题之外,致力于改进的另一个重要原因是基于注意力的模型会无意中给序列中更靠近位置的元素更高的权重。虽然这在理解句子各部分的语法结构的意义上可能是有意义的,但是很难找到句子中相距很远的单词之间的关系。

变压器架构

像上一篇文章一样,我们将逐步达到自我关注模型,从基本架构开始,慢慢达到完整的转换器。

如所见,它遵循编码器-解码器设计,同时用自关注层替换 LSTMs,并且使用位置编码来识别顺序性质。需要记住的重要一点是,所有这些组件都是由全连接(FC)层构成的。由于整个架构都是 FC 层,因此很容易将其并行化。

因此,我们现在有以下疑问:

  1. 输入序列是如何设计的?
  2. 使用位置编码是如何处理顺序性质的?
  3. 什么是自我关注?
  4. 什么是图层规范化?
  5. 前馈神经网络的设计是怎样的?
  6. 自我注意层和被掩盖的自我注意层有什么区别?
  7. Enc-Dec 关注层是什么?

随着我们对每个问题的澄清,这个模型将变得更加清晰。

输入序列

给定一系列记号 x1x2x3 ,输入序列对应于这些记号中的每一个的嵌入。这种嵌入可以像一键编码一样简单。例如,在句子的情况下, x1x2x3 将对应于句子中的单词。输入的 seq 可以是这些单词中每一个的一键 enc。

位置编码

由于这种新的编码器-解码器架构中没有解释数据顺序性质的组件,因此我们需要注入一些关于序列中令牌的相对或绝对位置的信息。这是位置编码模块的任务。

忽略数学公式,给定标记 x 在位置 i 的嵌入,第I位置的位置编码被添加到该嵌入中。这种位置的注入是这样完成的,使得每个位置编码都不同于任何其他的位置编码。位置 enc 的每个维度对应于一个正弦波长,最终 enc 是这些正弦波在第点的值。

自我关注

正如《你所需要的只是关注》一书的作者所描述的那样,

自我注意,有时称为内部注意,是一种为了计算序列的表示而将单个序列的不同位置相关联的注意机制。

这一层的目的是根据序列中的所有其他单词对一个单词进行编码。它将一个单词的编码与另一个单词的编码进行比较,并给出一个新的编码。完成这项工作的方法有点复杂,我将尽量把它分解开来。

给定一个嵌入 x ,它从中学习三个独立的更小的嵌入——查询、键和值。它们有相同的维数。我所说的学习是指在训练阶段Wq、Wk、Wv 矩阵是基于反向传播的损失来学习的。 x 与这三个矩阵相乘得到查询、键和值嵌入。

为了理解这些术语,让我们把这些词看作有生命的实体。每个单词都想知道其他每个单词对它的重视程度,然后创建一个更好的自身版本来代表这种重视程度。

假设 x1 想知道它相对于 x2 的值。所以就要'查询* ' x2x2 将以其自身的“关键字”的形式提供答案,然后通过与查询进行点积,该答案可用于获得表示其对 x1 的重视程度的分数。因为两者大小相同,所以这将是一个单一的数字。这一步将对每个单词执行。*

现在, x1 将获取所有这些分数并执行 softmax,以确保分数有界,同时还确保分数之间的相对差异得以保持。(还有将 softmax 之前的分数除以 d_model 的平方根的步骤——嵌入维度——以确保在 d_model 是大数的情况下分数太大的情况下梯度稳定。)

这个评分和 softmax 任务由每个单词对照所有其他单词来执行。上图描绘了整个解释的画面,现在会更容易理解。

x1 现在将使用该分数和相应单词的“”来获得其自身相对于该单词的新值。如果单词与 x1 不相关,那么分数将会很小,并且相应的将会作为该分数的一个因子而减少,并且类似地,重要单词将会得到其的分数支持。

最后,字 x1 将通过对接收到的值求和来为自己创建新的。这将是这个词的新嵌入。

但是自我关注层比这要复杂一点。transformer 架构为这一层增加了多头关注。一旦这个概念清晰了,我们将会更接近最终的变压器设计。

多头注意力

使用相同的原始 x1x2 等来学习多个这样的查询、关键字和值集合。嵌入。自关注步骤分别在每个集合上执行,新嵌入v’1v’2等。为每个集合创建。然后将这些连接起来,并与另一个学习矩阵 Z (其被联合训练)相乘,这将这些多个嵌入减少为针对x’1x’2等的单个嵌入。这就是为什么这被称为多头注意力,每个 v '代表自我注意力模型的一个头。

这种设计的直观原因是每个头在不同的上下文中查看原始嵌入,因为每个 Q、K、V 矩阵在开始时被随机初始化,然后基于训练期间反向传播的损失被修改。因此最终的嵌入是在同时考虑各种上下文的情况下学习的。

因此,在自我关注这一节的最后,我们看到自我关注层将位置注入的原始嵌入形式作为输入,并输出更多的上下文感知嵌入。这样,我们就解决了上述问题中最困难的部分。

图层规范化

Normalization Techniques[2]

图层归一化的关键特征是它对所有特征的输入进行归一化,不同于批量归一化,批量归一化对所有特征进行归一化。批量定额的缺陷在于它对批量大小施加了一个下限。在层规范中,统计数据是跨每个特征计算的,并且独立于其他示例。实验证明,它的性能更好。**

在变形金刚中,层标准化是通过残差完成的,允许它保留来自前一层的某种形式的信息。

前馈神经网络

每个编码器和解码器模块包含一个前馈神经网络。它由两个线性层组成,其间有一个 relu 激活。它被分别且相同地应用于每个位置。因此,它的输入是一组嵌入x’1x’2等等。并且输出是另一组嵌入 x''1x''2 等。映射到整个语言共有的另一个潜在空间。

这样,网络的编码器端就应该清楚了。现在,我们只剩下两个问题,我们开始时的问题——掩盖的自我注意和编码注意。

伪装的自我关注

在任何位置,一个词可能既依赖于它前面的词,也依赖于它后面的词。在《我看见 ______ 在追一只老鼠》中。我们会直观地填写 cat,因为这是最有可能的一个。因此,在对一个单词进行编码时,它需要知道整个句子中的所有内容。这就是为什么在自我关注层中,查询是用所有单词对所有单词进行的。但是在解码时,当试图预测句子中的下一个单词时(这就是为什么我们对解码器输入使用移位的输入序列),逻辑上,它不应该知道在我们试图预测的单词之后出现的单词是什么。因此,所有这些嵌入都通过乘以 0 来屏蔽,使它们中的任何值都变成 0,并且仅基于使用它之前的单词创建的嵌入来进行预测。

这种屏蔽与输出嵌入偏移一个位置的事实相结合,确保了位置 I 的预测只能依赖于小于 I 的位置处的已知输出。

编码器-解码器注意

如果你仔细观察上面的网络,来自编码器模块的输入来自这一层的编码器。在此之前,解码器已经使用了从先前的预测中可以获得的任何信息,并且学习了那些单词的新嵌入。在这一层,它使用编码器来更好地理解上下文和原始序列中的完整句子。它是怎么做到的?

解码器利用原始序列中单词的编码嵌入来查询所有现有单词,这些单词携带位置信息以及上下文信息。新的嵌入现在被注入该信息,并且输出序列现在基于该信息被预测。

至此,我们已经弄清楚了 transformer 架构,但是还有一个部分我还没有指定。

编码器-解码器堆栈

这是我们到目前为止拥有的变压器的架构。我们需要注意的是,编码器的输出是原始嵌入的改进版本。因此,我们应该能够通过添加更多来进一步改进它。这是变压器网络最终设计中要考虑的一点。

最初的架构有 4 个这样的编码器和解码器。只有最终编码器的输出被用作解码器输入。

结论

我们从变压器的基本设计开始,在单个编码器和解码器集中包含不同的层。然后,我们了解了每一层如何工作的细节。在此期间,我们还讨论了自我关注层的多头架构。一旦编码器和解码器都清楚了,我们就进入架构的最后一部分,编码器-解码器堆栈。

这就完成了变压器架构的详细设计。我希望这有所有的细节,需要理解完整的图片。基于变换器的网络的最普遍的例子之一是用于自然语言处理任务的 BERT 模型。

我还没有涉及网络的训练和预测细节,因为这将需要另一个完整的帖子,这对我来说很容易是更有趣和复杂的部分。在下一篇文章中,我将讲述我们如何使用变形金刚来处理图像和无监督学习的任务。

我希望你觉得这很有用并且容易理解。如果有任何更正或任何形式的反馈,我希望收到您的来信。请在这里评论,让我知道或发电子邮件给我@ catchpranay@gmail.com

参考资料:

[1]瓦斯瓦尼、阿希什等人,“你所需要的只是注意力。”(2017),神经信息处理系统进展。2017.

[2]吴,庾信,,何。“分组规范化。”(2018),《欧洲计算机视觉会议论文集(ECCV)* 。2018.*

* [## 第 1 天和第 2 天:注意— Seq2Seq 型号

序列对序列(abrv。Seq2Seq)模型是深度学习模型,已经在一些任务中取得了很大的成功,比如…

medium.com](https://medium.com/@catchpranay/day-1-2-attention-seq2seq-models-65df3f49e263) [## 翻译与序列到序列网络和注意力- PyTorch 教程 1.1.0…

类似于字符级 RNN 教程中使用的字符编码,我们将用一个…

pytorch.org](https://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html) [## 什么是变压器?

机器学习中的变压器和序列对序列学习介绍

medium.com](https://medium.com/inside-machine-learning/what-is-a-transformer-d07dd1fbec04) [## 图示的变压器

讨论:黑客新闻(65 分,4 条评论),Reddit r/MachineLearning (29 分,3 条评论)翻译…

jalammar.github.io](https://jalammar.github.io/illustrated-transformer/) [## 深度学习中的规范化方法综述

深度学习中的规范化一直是热门话题。获得正确的标准化可能是…

mlexplained.com](https://mlexplained.com/2018/11/30/an-overview-of-normalization-methods-in-deep-learning/)*

Transformer-XL 解释:将 Transformer 和 RNNs 结合成一个最先进的语言模型

原文:https://towardsdatascience.com/transformer-xl-explained-combining-transformers-and-rnns-into-a-state-of-the-art-language-model-c0cfe9e5a924?source=collection_archive---------4-----------------------

“Transformer-XL:固定长度上下文之外的注意力语言模型”摘要

语言建模已经成为一种重要的 NLP 技术,这要归功于它能够应用于各种 NLP 任务,例如机器翻译和主题分类。今天,有两种主要的语言建模架构——递归神经网络(RNNs)和转换器。前者逐个处理输入的单词或字符,以了解它们之间的关系,而后者接收一段标记,并使用注意机制立即了解它们之间的依赖关系。

尽管这两种体系结构都取得了令人印象深刻的成就,但它们的主要限制是捕获长期依赖,例如,使用文档开头的重要单词来预测后续部分中的单词。谷歌和卡耐基梅隆大学的一篇新论文“Transformer-XL :固定长度上下文之外的专注语言模型”结合了这两种方法。新模型在输入数据的每个片段上使用转换器的注意力模块,并使用递归机制来学习连续片段之间的依赖性。

Transformer-XL 在多种语言建模数据集上实现了最先进的(SOTA)结果,如 enwik8(单词级)和 text8(字符级),同时在推理过程中明显快于之前的 SOTA Transformer 架构(300x-1800x)。

背景——变形金刚

一种流行的语言建模方法是递归神经网络(RNNs),因为它们可以很好地捕捉单词之间的依赖关系,特别是在使用像 LSTM 这样的模块时。然而,由于消失梯度,rnn 往往很慢,并且它们学习长期依赖性的能力仍然有限。

2017 年发明的变形金刚,引入了一种新方法——注意力模块。注意力模块不是一个接一个地处理令牌,而是接收一段令牌,并使用三个学习到的权重矩阵(查询、关键字和值)一次性学习所有令牌之间的依赖关系,这三个权重矩阵形成了注意力头。Transformer 网络由多个层组成,每个层都有几个注意力头(和附加层),用于学习令牌之间的不同关系。

与许多 NLP 模型一样,输入标记首先被嵌入到向量中。由于注意力模块中的并发处理,该模型还需要添加关于标记顺序的信息,这一步骤称为位置编码,有助于网络了解它们的位置。一般来说,这个步骤是用正弦函数完成的,该函数根据令牌的位置生成一个矢量,而不需要任何学习参数。

An example of a single Attention Head on a single token (E1). Its output is calculated using its Query vector, and the Key and Value vectors of all tokens (In the chart we show only one additional token E2) — The Query and the Key define the weight of each token, and the output is the weighted sum of all Value vectors.

注意:关于变形金刚的深入评论可以在 Jay Alammar 伟大的博客文章中找到。

虽然最初的转换器用于机器翻译(带有编码器-解码器机制), Al-Rfou 等人提出了一种语言建模的架构。它的目标是根据其先前的字符预测一个段中的字符,例如,它使用 X1Xn-1 预测字符 Xn ,而右边的下一个字符被屏蔽(见下图)。这种 64 层的变压器模型限于 512 个字符的相对较短的输入,因此它将输入分割成段,并分别从每个段中学习。为了在评估中处理较长的输入,它通过在每一步中将输入移动一位来一次预测一个字符。

Training and Evaluation of the vanilla Transformer language model. Source: Transformer-XL

在流行的基准测试(enwik8 和 text8)中,该模型优于 RNN 模型,但是,它仍然有两个缺点:

  1. 有限的上下文相关性-字符之间的最大相关性距离受限于输入的长度。例如,模型不能“使用”几个句子前出现的一个单词。
  2. 上下文分段—对于长度超过 512 个字符的文本,该长度的每个片段都是从头开始单独训练的。因此,对于每个片段的第一个标记以及片段之间,根本不存在上下文(依赖性)。这导致低效的训练,并可能影响模型性能。

Transformer-XL 的工作原理

Transformer-XL 在很大程度上依赖于 vanilla Transformer (Al-Rfou 等人),但引入了两种创新技术——递归机制相对位置编码——来克服 vanilla 的缺点。相对于普通转换器的另一个优点是,它可以用于单词级和字符级语言建模。

重现机制

重现机制的目标是通过使用来自先前分段的信息来实现长期依赖性。与普通版本类似,Transformer-XL 处理第一段标记,但保留隐藏层的输出。当处理下面的段时,每个隐藏层接收两个输入:

  1. 该段的前一个隐藏层的输出,如普通版本(下图中的灰色箭头)。
  2. 前一段(绿色箭头)中的前一个隐藏层的输出,允许模型创建长期依赖关系。

从技术上讲,这两个输入被连接起来,然后用于计算当前段(的当前层的当前头)的键和值矩阵。这种添加为网络提供了关于每个令牌的权重(重要性)的更多信息,但是它没有改变值矩阵。

Training and Evaluation of the Transformer-XL language model. Source: Transformer-XL

通过以相同的方式(在 GPU 存储器的限制下)使用来自几个先前段的信息,甚至仅在评估期间,可以扩展该概念以包含更长的依赖性。

递归机制的另一个优点是其评估速度——在每一步中,它可以前进整个段(而不是像普通版本中那样前进一个令牌),并使用先前段的数据来预测当前段令牌。

相对位置编码

递归机制也带来了新的挑战—原始的位置编码分别处理每个段,因此,来自不同段的令牌具有相同的位置编码。例如,第一段和第二段的第一个标记将具有相同的编码,尽管它们的位置和重要性不同(来自第一段的标记可能较低)。这种混淆可能会错误地影响网络。

相反,本文提出了一种新的位置编码,它是每个注意模块的一部分,而不是仅在第一层之前对位置进行编码,并且基于标记之间的相对距离而不是它们的绝对位置。从技术上来说,它扩展了注意力头部得分(Qi Kj)的简单相乘,以包括四个部分:

  1. 内容权重-原始分数,当然没有添加原始位置编码。
  2. 相对于当前内容的位置偏差(Qi)。它使用类似的正弦函数来接收记号之间的距离(例如 i-j ,而不是当前记号的绝对位置。
  3. 学习的全局内容偏差-该模型添加了调整其他令牌内容(Kj)的重要性的学习向量。
  4. 学习的全局偏差-另一个学习的向量,其仅基于记号之间的距离来调整重要性(例如,最后的先前单词可能比先前段落中的单词更重要)。

结果

作者比较了该模型在单词级和字符级数据集上的性能,并将其与其他著名模型(RNNs 和 Transformers)进行了比较。Transformer-XL 在几个不同的数据集基准上取得了最先进的(SOTA)结果:

  1. 在大型词级数据集 WikiText-103 上,18 层 Transformer-XL (257M 参数)达到了 18.3 的困惑度,而之前的 SOTABaevski&Auli达到了 20.5。
  2. 在字符级数据集 enwik8 上,12 层 Transformer-XL 达到了每字符 1.06 位(bpc),与之前由 Al-Rfou 等人使用六倍多参数的 SOTA 结果相似。24 层 Transformer-XL 实现了 0.99 bpc 的新 SOTA。
  3. 有趣的是,该模型还在只有短期依存关系的数据集上实现了 SOTA 结果-10 亿个单词只有单个句子-以及在小数据集- Penn Treebank 只有 100 万个令牌。这表明该模型在这些情况下也可能是有效的。

在下面的图表中可以看到递归机制和相对位置编码的好处。它比较了不同上下文长度(注意头中使用的先前标记的数量)的无重现或新编码的困惑分数。完整的 Transformer-XL 明显优于其他产品,并且能够利用更长期的依赖性。此外,它还能够捕获比 RNN 更长的依赖关系(长 80%)。

Transformer-XL ablation study. Source: Transformer-XL

最后,如前所述,该模型在推理过程中也比普通的转换器快得多,尤其是对于较长的上下文。例如,对于长度为 800 个字符的上下文,速度提高了 363 倍,对于长度为 3,800 个字符的上下文,速度提高了 1,874 倍。

实施细节

该模型是开源的,并且在 TensorFlow 和 PyTorch 中均实现(包括预训练的模型)。没有指定每个数据集的训练持续时间。

结论

Transformer-XL 展示了几种不同数据集(大/小、字符/单词等)上语言建模的最新结果。它结合了深度学习的两个突出概念——重现和注意力——允许该模型学习长期依赖关系,并可能对需要这种能力的深度学习的其他领域有效,如音频分析(例如每秒 16k 样本的语音数据)。

该模型尚未在情感分析或问题回答等 NLP 任务上进行测试,与其他基于 Transformer 的模型(如 BERT )相比,这种强语言模型的优势是什么仍然是一个开放的问题。

关注深度学习最新研究,订阅我的简讯 LyrnAI

变压器如何工作

原文:https://towardsdatascience.com/transformers-141e32e69591?source=collection_archive---------0-----------------------

Open AI 和 DeepMind 使用的神经网络

如果你喜欢这篇文章,并想了解机器学习算法是如何工作的,它们是如何产生的,它们将走向何方,我推荐以下内容:

[## 让事物思考:人工智能和深度学习如何为我们使用的产品提供动力

这是显而易见的,但大多数时候却很难看到。人们说‘这和你脸上的鼻子一样明显。’…

www.holloway.com](https://www.holloway.com/g/making-things-think)

变压器是一种越来越受欢迎的神经网络架构。变形金刚最近被 OpenAI 用于他们的语言模型,最近也被 DeepMind 用于阿尔法星——他们击败顶级职业星际玩家的程序。

变形金刚是为了解决 序列转导神经机器翻译的问题而开发的。这意味着将输入序列转换成输出序列的任何任务。这包括语音识别、文本到语音转换等..

Sequence transduction. The input is represented in green, the model is represented in blue, and the output is represented in purple. GIF from 3

对于执行序列转导的模型来说,有某种记忆是必要的。例如,假设我们将下面的句子翻译成另一种语言(法语):

“变形金刚”是一支日本[[硬核朋克]]乐队。该乐队成立于 1968 年,正值日本音乐史上的鼎盛时期

在本例中,第二句中的单词“the band”指的是第一句中介绍的乐队“The Transformers”。当你读到第二句中的乐队时,你知道它指的是“变形金刚”乐队。这对翻译可能很重要。有很多例子,有些句子中的词引用了前面句子中的词。

为了翻译这样的句子,模型需要找出这种依赖和联系。由于递归神经网络(RNNs)和卷积神经网络(CNN)的特性,它们已经被用来处理这个问题。让我们回顾一下这两种架构及其缺点。

递归神经网络

递归神经网络中有环路,允许信息持续存在。

The input is represented as x_t

在上图中,我们看到神经网络的一部分, A,处理一些输入 x_t 和输出 h_t,一个循环允许信息从一个步骤传递到下一个步骤。

这些循环可以用不同的方式来思考。一个递归神经网络可以被认为是同一个网络的多个副本,一个,每个网络传递一个信息给下一个。考虑一下如果我们展开循环会发生什么:

An unrolled recurrent neural network

这种链状性质表明,递归神经网络与序列和列表明显相关。这样,如果我们想要翻译一些文本,我们可以将每个输入设置为该文本中的单词。递归神经网络将前面单词的信息传递给下一个可以使用和处理该信息的网络。

下图显示了序列到序列模型通常如何使用递归神经网络工作。每个单词被单独处理,通过将隐藏状态传递给解码阶段来生成结果句子,然后解码阶段生成输出。

GIF from 3

长期依赖的问题

考虑一个语言模型,它试图根据前面的单词预测下一个单词。如果我们试图预测句子“天空中的云”的下一个单词,我们不需要进一步的上下文。很明显,下一个词将会是天空。****

在这种情况下,相关信息和需要的地方之间的差异很小,RNNs 可以学习使用过去的信息,并找出这个句子的下一个单词是什么。

Image from 6

但是有些情况下我们需要更多的上下文。比如说你在试着预测课文的最后一个单词:“我在法国长大…我说得很流利…”。最近的信息表明,下一个单词可能是一种语言,但如果我们想缩小哪种语言的范围,我们需要法国的上下文,那是在文本的更后面。

Image from 6

当相关信息和需要信息的点之间的差距变得非常大时,rnn 变得非常无效。这是因为信息是在每一步传递的,链越长,信息就越有可能沿着链丢失。

理论上,RNNs 可以学习这种长期依赖性。在实践中,他们似乎不学他们。LSTM,一种特殊类型的 RNN,试图解决这种问题。

长短期记忆(LSTM)

当安排一天的日程时,我们会优先安排我们的约会。如果有什么重要的事情,我们可以取消一些会议,把重要的事情放在一边。

RNNs 不会这么做的。每当它添加新信息时,它通过应用一个函数来完全转换现有信息。整个信息都被修改,没有考虑什么重要什么不重要。

LSTMs 通过乘法和加法对信息进行小的修改。在 LSTMs 中,信息通过一种称为单元状态的机制流动。通过这种方式,LSTMs 可以选择性地记住或忘记重要的和不那么重要的事情。

在内部,LSTM 看起来如下:

Image from 6

每个单元将输入 x_t (在句子到句子翻译的情况下是一个单词)、前一个单元状态和前一个单元的输出** 作为输入。它处理这些输入,并基于它们生成新的细胞状态和输出。我不会详细讨论每个细胞的结构。如果你想了解每个细胞是如何工作的,我推荐克里斯托弗的博文:**

**[## 了解 LSTM 网络——colah 的博客

这些循环使得循环神经网络看起来有点神秘。然而,如果你想得更多一点,事实证明…

colah.github.io](http://colah.github.io/posts/2015-08-Understanding-LSTMs/)**

利用单元状态,在翻译时,句子中对于翻译单词来说重要的信息可以从一个单词传递到另一个单词。

LSTMs 的问题是

通常发生在 rnn 上的同样的问题也会发生在 lstm 上,也就是说,当句子太长时,lstm 仍然做得不太好。其原因是,保持远离当前正在处理的单词的单词的上下文的概率随着离它的距离而指数下降。

这意味着当句子很长时,模型经常会忘记序列中远处位置的内容。RNNs 和 LSTMs 的另一个问题是很难并行处理句子,因为你必须一个字一个字地处理。不仅如此,也没有长期和短期依赖关系的模型。总之,LSTMs 和 RNNs 存在 3 个问题:

  • 顺序计算抑制了并行化
  • 没有长短期依赖关系的显式建模
  • 位置之间的“距离”是线性的

注意力

为了解决其中的一些问题,研究人员创造了一种关注特定单词的技术。

翻译句子时,我会特别注意我正在翻译的单词。当我转录一段录音时,我会仔细听我主动写下的片段。如果你让我描述我正坐的房间,我会一边描述一边扫视周围的物体。

神经网络可以使用 注意力 实现同样的行为,专注于它们被给予的信息子集的一部分。例如,一个 RNN 可以参与另一个 RNN 的输出。在每一个时间步,它聚焦于另一个 RNN 的不同位置。

为了解决这些问题,注意力是一种在神经网络中使用的技术。对于 RNNs 来说,每个单词都有一个相应的隐藏状态,并一直传递到解码阶段,而不是仅以隐藏状态对整个句子进行编码。然后,在 RNN 的每一步使用隐藏状态进行解码。下面的 gif 展示了这是如何发生的。

The green step is called the encoding stage and the purple step is the decoding stage. GIF from3

其背后的想法是,一个句子中的每个单词都可能有相关的信息。所以为了解码精确,它需要考虑输入的每个单词,使用注意力。****

为了在序列转导中引起对 RNNs 的注意,我们将编码和解码分成两个主要步骤。一步用绿色的表示,另一步用紫色的表示。绿色的步骤被称为编码阶段,紫色的步骤是解码阶段。********

GIF from 3

绿色部分负责从输入中创建隐藏状态。我们不是像使用 attention 之前那样只将一个隐藏状态传递给解码器,而是将句子的每个“单词”生成的所有隐藏状态传递给解码阶段。每个隐藏状态在解码阶段使用,以计算出网络应该注意的地方。

例如,当将句子“Je suisétudiant”翻译成英语时,要求解码步骤在翻译时查看不同的单词。

This gif shows how the weight that is given to each hidden state when translating the sentence “Je suis étudiant” to English. The darker the color is, the more weight is associated to each word. GIF from 3

例如,当你翻译句子“1992 年 8 月欧洲经济区协议”从法语到英语,以及对每个输入的重视程度。

Translating the sentence “L’accord sur la zone économique européenne a été signé en août 1992.” to English. Image from 3

但是我们讨论过的一些问题,仍然没有通过使用注意力的 RNNs 得到解决。例如,并行处理输入(单词)是不可能的。对于大型文本语料库,这增加了翻译文本所花费的时间。

卷积神经网络

卷积神经网络有助于解决这些问题。有了他们,我们可以

  • 并行化很简单(每层)
  • 利用本地依赖性
  • 位置之间的距离是对数的

一些最流行的用于序列转导的神经网络 Wavenet 和 Bytenet 是卷积神经网络。

Wavenet, model is a Convolutional Neural Network (CNN). Image from 10

卷积神经网络可以并行工作的原因是输入的每个单词可以同时处理,而不一定依赖于要翻译的前面的单词。不仅如此,对于一个 CNN 来说,输出单词与任何输入之间的“距离”依次为【log(N)——也就是从输出到输入生成的树的高度大小(你可以在上面的 GIF 上看到。这比一个 RNN 的输出和一个输入的距离要好得多,后者的数量级为T5【N

问题是,卷积神经网络不一定有助于解决翻译句子时的依赖问题。这就是为什么变形金刚被创造出来,它们是两个 CNN 与关注的结合。

变形金刚(电影名)

为了解决并行化问题,Transformers 试图通过使用卷积神经网络和注意力模型来解决问题。注意力提高了模型从一个序列转换到另一个序列的速度。

我们来看看变压器是怎么工作的。Transformer 是一个利用注意力来提升速度的模型。更具体地说,它使用了自我关注。

The Transformer. Image from 4

从内部来看,Transformer 的体系结构与前面的模型类似。但是转换器由六个编码器和六个解码器组成。

Image from 4

每个编码器都非常相似。所有编码器都具有相同的架构。解码器共享相同的属性,即它们彼此也非常相似。每个编码器包括两层:自关注和一个前馈神经网络。

Image from 4

编码器的输入首先流经自关注层。它帮助编码器在对特定单词进行编码时查看输入句子中的其他单词。解码器有这两层,但在它们之间有一个注意力层,帮助解码器关注输入句子的相关部分。

Image from 4

自我关注

注:此部分来自 Jay Allamar 博客文章

让我们开始看看各种向量/张量,以及它们如何在这些组件之间流动,以将训练模型的输入转化为输出。正如 NLP 应用程序中的一般情况一样,我们首先使用嵌入算法将每个输入单词转换成一个向量。

Image taken from 4

每个单词被嵌入到大小为 512 的向量中。我们将用这些简单的盒子来表示这些向量。

嵌入只发生在最底层的编码器中。所有编码器共有的抽象是它们接收每个大小为 512 的向量列表。

在底部的编码器中,这将是单词嵌入,但在其他编码器中,这将是直接在下面的编码器的输出。在我们的输入序列中嵌入单词后,它们中的每一个都流经编码器的两层中的每一层。

Image from 4

在这里,我们开始看到转换器的一个关键属性,即每个位置的字在编码器中通过自己的路径流动。在自我关注层,这些路径之间存在依赖关系。然而,前馈层没有这些依赖性,因此各种路径可以在流经前馈层时并行执行。

接下来,我们将把这个例子换成一个更短的句子,看看编码器的每个子层发生了什么。

自我关注

让我们首先看看如何使用向量来计算自我注意力,然后继续看看它实际上是如何实现的——使用矩阵。

Figuring out relation of words within a sentence and giving the right attention to it. Image from 8

计算自我注意力的第一步是从编码器的每个输入向量中创建三个向量(在这种情况下,是每个单词的嵌入)。因此,对于每个单词,我们创建一个查询向量、一个键向量和一个值向量。这些向量是通过将嵌入乘以我们在训练过程中训练的三个矩阵而创建的。

请注意,这些新向量的维数小于嵌入向量。它们的维数是 64,而嵌入和编码器输入/输出向量的维数是 512。它们不一定要更小,这是一种架构选择,以使多头注意力的计算(大部分)保持不变。

Image taken from 4

将 x1 乘以 WQ 权重矩阵产生 q1,即与该单词相关联的“查询”向量。我们最终创建了输入句子中每个单词的“查询”、“键”和“值”投影。

什么是“查询”、“键”和“值”向量?

它们是对计算和思考注意力有用的抽象概念。一旦你开始阅读下面的注意力是如何计算的,你就会知道你所需要知道的关于这些向量所扮演的角色。

计算自我关注度的第二步是计算一个分数。假设我们在计算这个例子中第一个词“思考”的自我关注度。我们需要将输入句子中的每个单词与这个单词进行比较。分数决定了当我们在某个位置对一个单词进行编码时,对输入句子的其他部分的关注程度。

分数是通过查询向量与我们正在评分的相应单词的关键向量的点积来计算的。因此,如果我们正在处理位置#1 的单词的自我注意,第一个分数将是 q1 和 k1 的点积。第二个分数是 q1 和 k2 的点积。

Image from 4

第三和第四步是将分数除以 8(文中使用的关键向量的维数的平方根— 64。这导致具有更稳定的梯度。这里可能有其他可能的值,但这是默认值),然后通过 softmax 操作传递结果。Softmax 将分数标准化,因此它们都是正数,加起来等于 1。

Image from 4

这个 softmax 分数决定了每个单词在这个位置将被表达多少。显然,在这个位置的单词将具有最高的 softmax 分数,但是有时关注与当前单词相关的另一个单词是有用的。

第五步是将每个值向量乘以 softmax 分数(准备将它们相加)。这里的直觉是保持我们想要关注的单词的值不变,并淹没不相关的单词(例如,通过将它们乘以像 0.001 这样的小数字)。

第六步是对加权值向量求和。这就在这个位置产生了自我关注层的输出(针对第一个单词)。

Image from 4

自我关注的计算到此结束。得到的向量是我们可以发送给前馈神经网络的向量。然而,在实际实现中,这种计算是以矩阵形式进行的,以便更快地处理。现在让我们来看看,我们已经看到了单词级别的计算的直觉。

多头注意力

变形金刚基本就是这样工作的。还有一些其他细节使它们工作得更好。例如,变形金刚不是只在一个维度上关注彼此,而是使用了多头关注的概念。

其背后的想法是,每当你翻译一个单词时,你可能会根据你所提问题的类型对每个单词给予不同的关注。下图显示了这意味着什么。例如,每当你在翻译“我踢了球”这句话中的“kicked”时,你可能会问“谁踢了”。根据不同的答案,这个词的另一种语言的翻译会有所不同。或者问其他问题,比如“做了什么?”等等…

Images from 8

位置编码

转换器的另一个重要步骤是在对每个单词进行编码时添加位置编码。编码每个单词的位置是相关的,因为每个单词的位置与翻译相关。

概观

我概述了变压器是如何工作的,以及为什么这是用于序列转导的技术。如果你想深入了解这个模型的工作原理及其所有的细微差别,我推荐下面的帖子、文章和视频,我把它们作为总结这个技术的基础

  1. 递归神经网络的不合理有效性
  2. 了解 LSTM 网络
  3. 可视化神经机器翻译模型
  4. 图示变压器
  5. 变压器——你只需要关注
  6. 带注释的变压器
  7. 注意力是你所需要的全部注意力神经网络模型
  8. 生成模型的自我关注
  9. OpenAI GPT-2:通过可视化理解语言生成
  10. WaveNet:原始音频的生成模型

递归转换 BigQuery JSON API 响应

原文:https://towardsdatascience.com/transforming-bigquery-json-api-responses-recursively-5c462f5b01?source=collection_archive---------31-----------------------

从字段/值行嵌套构建键值对

La Sagrada Familia, Barcelona, by Paolo Nicolello.

跟我一起说:“嵌套的 JSON 很难用!”。我说的对吗?当然可以!既然我们已经说清楚了,我只想说我完全相信 JSON。它是合乎逻辑的,是通用的,大多数语言都用它来创建快速访问的散列映射风格的数据结构。所有人的胜利!

直到你筑巢。

一群相信嵌套 JSON 的好处的人和那些相信扁平 JSON 是他们选择 API 有效负载幸福的圣杯的人。这场无声的战斗如此激烈,以至于许多扁平化技术充斥着黑客的宝库,如 递归方式非递归方式 等方法。

递归地飞越巢穴

看过电影盗梦空间?这是个好东西。时间线中的时间线。当一切恢复时,你会看到事情是如何组合在一起的。以类似的方式,递归在代码中占用的空间很小,但是可以处理巨大的计算(理解为“嵌套”)复杂性。

好了,够了,让我们开始吧!

BigQuery 的查询 API 返回 JSON

这是 Google BigQuery 在执行查询后的 API 响应示例:

BigQuery’s query API result looks like this

该模式向您展示了数据是如何构造的,并且各行用字段的“f”和值“v”来表示哪些值适合该模式。

现在,看起来像这样的 JSON 不是更容易阅读和操作吗?

Transformed BigQuery result into something more manageable

如果你同意,那么你会得到很好的照顾。

解决方案

下面是进行这种转换的 node.js 代码。请随意使用它,根据您的需求进行调整,通常会让您的生活更简单,让您的数据更快乐。该功能的界面是:

convertBQToMySQLResults(schema, rows)

您可以像这样传递 BigQuery 结果:

// apiResponse is the payload you receive from a BigQuery query API // responseconvertBQToMySQLResults(apiResponse.schema.fields, apiResponse.rows)

JsFiddle 演示

下面是一个 JsFiddle 代码演示:

概括起来

JSON 的很多转换都存在。递归解决方案不是最容易调试的,但是它们有最简单的代码足迹。用调试器单步调试代码是以“慢动作”方式查看此类算法的首选方式。本文提供了一种将源自 Google BigQuery 的复杂嵌套 JSON 简化为您可以自己操作和使用的东西的方法。试试吧!快乐转换!

为机器学习预测中的可用性转换分类数据

原文:https://towardsdatascience.com/transforming-categorical-data-for-usability-in-machine-learning-predictions-90459c3fc967?source=collection_archive---------17-----------------------

使用邮政编码、纬度和经度的快速示例

凯文·维拉斯科&亚历克斯·什罗普郡

给定华盛顿州金县 2014 年至 2015 年(【https://www.kaggle.com/harlfoxem/housesalesprediction】T2)的房屋销售数据集,我们的任务是创建一个模型来准确预测房屋销售价格。经过最初的数据探索和清理,我们发现了大量描述房屋质量的有用信息,但没有多少关于位置的有用信息。

Aerial photo of Seattle by Thatcher Kelley

为什么位置对我们的数据集很重要

我们都听说过被过度使用的短语“位置,位置,位置”作为房地产市场评估的中心主题。人们普遍认为这是决定一个人应该住在哪里的最重要的因素。价格和位置往往与买家密切相关。任何房屋的条件、价格和大小都可能改变。唯一不变的是房子的位置。

以我们数据集的邮政编码特征为例:

在其当前形式中,在“邮政编码”列中有 70 个唯一的分类值,机器学习模型无法提取每个邮政编码中包含的任何有用信息来评估与价格的关系。在每一个类别中都存在一个有意义的房地产因素的独特选择,如公园、学校、咖啡馆、商店、杂货店、公共交通和主要道路。所有这些都是主要因素,可以表明西雅图的沃灵福社区与亚基马山谷中部的住宅之间的内在差异。揭示邮政编码在价格方面的内在品质对于纳入我们的价格预测模型非常重要,因此我们必须适应以保持类别的力量。

快速浏览一下上面的信息,很明显我们需要设计新的功能来理解邮政编码,以及经度和纬度!

转换和理解分类数据

我们以独特的方式正确应用纬度和经度信息的方法包括创建一个功能来测量到贝尔维尤和西雅图这两个主要经济中心的距离,以便改进我们的价格预测。我们没有通过创建一个数学函数来重新发明轮子,而是决定通过下图所示的哈弗辛公式来计算距离:

Example of the Haversine function

哈弗辛模块(https://pypi.org/project/haversine/)为我们节省了大量时间。Haversine 接受两个纬度和经度元组,并计算特定单元中两个地理点之间的地理距离。我们假设房价与西雅图市中心和贝尔维尤市中心地区之间存在显著关系,选择这两个地区是因为它们是该地区最大的就业中心&和经济活动中心。我们认为缩短通勤时间和方便获取大城市的资源通常会增加需求,从而提高价格。

对于这个公式,我们需要转换每栋房子的坐标。给定单独列中的纬度和经度,我们应用 zip 函数创建一个新的坐标元组列:

利用数据集中每个家庭的单点,以及两个参考点,哈弗辛公式的所有变量都被创建。事实证明,将函数直接应用到现有数据框架的新列中是很棘手的。为了创建一个指示距离的新列,我们必须从列表数据类型创建一个 Pandas 系列,然后将其添加到现有的 Dataframe 中。

最后,我们创建了另一个列,它选择两点之间的最小距离作为“距离震中”列的输入。这一步对于获取这两个城市的邻近信息非常重要,以确保我们对到经济中心的最短距离的解释为我们的模型解释做好准备。

对于邮政编码,我们实现了 one hot encoding pd.get_dummies()方法,通过该方法,分类变量被转换成可以提供给 ML 算法的形式,以便更准确地预测价格。就我们的数据而言,我们希望获得邮政编码的一个类别,并将其转换为二进制 yes[1],这一行是该邮政编码的成员,或者 no[0],它不是。邮政编码的庞大数量起初似乎令人担忧,给我们的数据框架增加了许多列:

但是,通过将 zipcode 特性转换为包含二进制信息的多个列,我们就可以将它作为训练模型的一个特性。为了正确解释我们的模型将为所有列生成的系数,我们首先必须在 pd.get_dummies()方法之后选择一个不同的邮政编码来删除冗余信息。换句话说,我们删除了一个邮政编码列,因为每隔一个邮政编码列出现零表示该行是我们删除的邮政编码的一个成员。该信息是剩余的 n-1 列的二进制形式所固有的。我们选择放弃 98103 的邮政编码,它包括沃灵福德、格林莱克、菲尼岭、格林伍德和弗里蒙特地区。我们选择这个邮政编码是因为它代表了西雅图市中心的一个热门区域,我们希望它能被更广泛的西雅图观众理解为一个价格基准。我们想选择一个既不是比尔·盖茨的邮政编码,也不是更接近相反极端的邮政编码的邮政编码,这样很多其他邮政编码的房屋价格就会高于或低于 98103。最重要的是,整个过程确保了我们得到的系数可以用 98103 个邻域来解释。

我们模型改进工作的结果

经过仔细的数据清理和特征工程,我们的模型包含 10 个预测因子,包括一个初始的“距离西雅图”预测因子。在通过 statsmodels 的普通最小二乘线性回归模型运行数据集后,我们的汇总输出得出了相当不错的 R 平方(一种快速、简便的初始评估模型质量的方法):

Initial OLS Results

在 0.735,我们的情况还不错,但还有改进的空间。意识到 R 平方作为模型质量度量的局限性,为了说明基本模型迭代之前和之后的场景,它可以发挥作用。也就是说,在整合了我们的“距离震中的距离”功能(整合了距离经济中心西雅图市中心和贝尔维尤市中心的距离)后:

adding distance_from_epicenter

令人尊敬的进步!最后,通过使用 one-hot 编码将格式混乱的邮政编码类别转换为有用的数字格式:

adding zipcode

有了这样一个显著的推动,并且取决于业务案例的潜在上下文,我们可能准备好部署我们的预测器或者引入新数据、设计新特性,或者简单地继续在现有数据集内迭代。我们的模型现在得出调整后的 R 平方为 0.876。换句话说,我们的线性模型可以解释 86.7%的响应变量变化。

最后的想法

回顾原始数据集和所提供的信息,最初看起来非常少的关于位置的可操作信息实际上包含了强大的分类邮政编码数据和可转换的纬度和经度数据,一旦每个数据的潜力被释放出来,它们就会对我们的机器学习算法产生巨大的改进。“位置,位置,位置”这句古老的格言在理解一个住宅的市场价格时,似乎仍然具有真正的力量。从这里开始,可以考虑时间、更大的地理界限和来自其他需求影响模式的数据等变量,特别是当房地产/物业技术领域的高增长公司进入分析军备竞赛以成为最有知识的公司时。我知道你们是好人,但我们是为你们而来的。

如需了解项目详情、我们最准确的价格预测代码以及相关幻灯片,请查看我们的 GitHub repos:

亚历克斯·什罗普希尔:

[## as 6140/king county wa _ home _ price _ predictor

通过在 GitHub 上创建一个帐户,为 as 6140/kingcountyWA _ home _ price _ predictor 开发做出贡献。

github.com](https://github.com/as6140/kingcountyWA_home_price_predictor)

凯文·维拉斯科:

[## kevinthedou/DSC-1-final-project-Seattle-ds-career-040119

通过在 GitHub 上创建一个帐户,为 kevinthedou/DSC-1-final-project-Seattle-ds-career-040119 开发做贡献。

github.com](https://github.com/kevintheduu/dsc-1-final-project-seattle-ds-career-040119)

在 Linkedin 上保持联系!

凯文:https://www.linkedin.com/in/kevinrexisvelasco/

亚历克斯:https://www.linkedin.com/in/alexshropshire/

用深度学习翻译肯尼亚手语

原文:https://towardsdatascience.com/translating-the-kenyan-sign-language-with-deep-learning-e58792f1b27a?source=collection_archive---------18-----------------------

Chart showing the Kenyan Sign Language Alphabet

2016 年 7 月,我遇到了 Hudson——一位才华横溢的聋人开发者,他刚刚开发了一款应用,向他的聋人社区教授性健康。我们成了忠实的朋友。从那以后,我的聋人朋友和熟人圈子越来越大。

我甚至有了一个标志名。在聋人社区,从一个独特的特征中给某人分配一个符号比每次用手指拼写他们的名字更容易。但有一个问题,很长一段时间,我无法与这个日益壮大的聋人朋友和熟人圈子很好地沟通,因为我没有学过手语。

与哈德逊和他同样失聪的共同创始人阿尔弗雷德的对话,首先由他们为会议指定的手语翻译进行调解。Hudson 的应用程序和 Sophie bot 是由同一个项目资助的,所以我们有很多这样的项目。

我们的对话变成了在我们每个人的手机笔记或信息应用程序上输入文本。在几次会议和活动中,我让他无法专心听他的翻译,这是我的过错。很快,我们就制定了一个我们都能理解的粗略的手势清单。这些在聋人群体中被称为“乡村手语”。

从那以后,与聋人群体的互动才开始增加。去年 5 月,在微软的 Build 大会上,在一个特别的主题演讲队列边上,一群失聪的开发人员加入了我们,我要求介绍我自己并展示我的签名。幸运的是他们有一个翻译,他帮了忙。去年六月,在肯尼亚海岸的一次活动后,Hudson 让我跟着去参加他朋友的选美比赛。她是选美皇后,也是个聋子。后来我们都出去喝酒了,但我不能完全参与谈话。我只知道如何用手指拼写“GIF ”,我的手语名字,以及如何说“嗨”。

去年 10 月,在我帮助组织的一次会议上,肯尼亚 Droidcon,我们有两个聋人开发者参加,他们带来了两个手语翻译。很明显,宇宙希望我学习手语。

我很自豪地说,我现在可以流利地用手指拼写肯尼亚手语字母,并且我有意每天学一个单词。

我知道这种学习曲线并不是每个人都想与失聪的朋友、家人、同事和熟人更好地交流的解决方案。我们可以利用人工智能技术给我们带来的进步来建立一个工具,让这变得更容易。去年年底,才华横溢的开发人员 Hudson 发布了一个应用程序来教听力正常的人手语,这让我对合适的工具有了直觉。

如果我们能建立一个图像分类器手语翻译器会怎么样?如果我们可以建立一个端到端的手语翻译模型,仅仅使用人们手语的照片,会怎么样?本博客对此进行了调查。

肯尼亚手语翻译的图像分类器

让我们回顾一下我们的目标。我们正试图建立一个应用程序,它使用图像分类器来识别手语,不仅通过看手指的照片,还通过现实生活中的网络摄像头或手机摄像头。这样,我们的应用程序将像人眼一样工作。

这是一个循序渐进的指南,解释了我解决问题的过程。

数据收集和数据标注

Kaggle 数据集

我的第一反应是去 Kaggle 看看是否有数据集存在。

我找到了一个,但都是白色的手指,这是我手指的样子

Physics Gangster sign

哎呦。这可能是行不通的。这是许多数据科学数据集的常见问题。例如,《黑豹》中的角色和演员会得到像这样的面部识别记分卡:

Wakanda Foreeeva!!!!

许多研究人员和现在的政治家都指出了数据集的这些固有偏见,这可能导致在这些数据集上训练的模型和算法的偏见。

回到我们的 Kaggle 发现——更糟糕的是,数据集使用的是美国手语。

图像已经矢量化和扁平化,以消除 RGB 层。它不适合我的问题案例。我想要一个端到端的模型,像真实世界的数据一样拍摄半个身体的图像,而不是必须建立一个对象检测层来检测手。

众包深度学习数据集

第二个本能是在我的社交媒体账户上发帖,让我的朋友发送他们用不同字母签名的图片。要么是我的网络圈子里没有人像我一样不热衷于手语,要么是我没有发挥我自认为的那么大的影响力。

自己构建数据集

我不得不自己去工作,自己收集数据。给我拍照,用不同的衬衫和背景签署整个 KSL 字母表。当我每个字母有十张照片时,我不断地在每张照片上添加微小的变换,直到我有了 100 多张照片。快点。

给我的数据集加标签是最简单的部分。把每一个字母放在它自己的目录中,目录的名字会被选作标签

```~/data~/data/A/A (1).jpg~/data/A/A (2).jpg...~/data/Z/Z (1).jpg~/data/Z/Z (2).jpg```

我已经将数据作为 floydhub 数据集上传到这里

选择神经网络

和往常一样,数据集创建和数据标记过程比我预期的要长得多。但是现在我有了一个合适的数据集,是时候开始考虑我可能用于这个项目的神经网络架构和深度学习框架了。

这个社区在快速人工智能和 ResNet 上很大,但我学习了 tensorflow 和 Keras 学习曲线,并在其上加倍下注。

卷积网络是计算机视觉问题的首选网络,但从头训练一个需要大量的数据和时间。所以让我们停止在 keras code labs 上这样做。

我们可以重新训练已经预先训练好的 CNN 的最后一层来进行我们的图像分类。我选择两个预训练的卷积神经网络。Inception,更大、更慢但精度更高的卷积神经网络和 Mobilenets,一种更轻、更快、精度更低的神经网络,旨在运行在移动电话上。

我作为一名移动开发者的背景让我本能地尝试首先开发移动产品。对我来说,我有两个模型的经验,甚至有来自早期“热狗,不是热狗”代码实验室的预定义脚本

预定义的脚本不仅仅是训练模型。他们有代码自动下载预训练重量的计算图表。编写用于评估和调试模型的 tensorboard 摘要日志,将训练好的模型输出为冻结的计算图形。

最后,他们还对我的训练数据进行预处理,对图像进行矢量化,并将矢量值存储在一个文本文件中,该文件的目录结构与训练数据类似。这在用调整的超参数重新训练模型时节省了大量时间。

脚本是由 tensorflow 团队编写的,该团队随后激发了他们的“tensor flow for poets code lab

训练模特

tensorflow 团队精心编写的预定义脚本的额外好处是,我们只需使用适当的超参数运行脚本。对于这个代码实验室,我们将在 floydhub 上进行训练。

使用超参数运行样本

开始

我们对初始模型做同样的事情

首先,我们在本地环境中初始化一个 floydhub 项目:

```bashfloyd init iamukasa/ksl_translator```

然后我们训练这个模型:

```bashfloyd run — env tensorflow-1.9 \ — follow \ — data iamukasa/datasets/ksl/1: data \“python retrain.py — model_dir ./inception — image_dir=/data”```

移动网络

```bashfloyd init iamukasa/ksl_translator_mobilenets```

然后我们训练这个模型

```bashfloyd run — env tensorflow-1.9 \ — follow \ — data iamukasa/datasets/ksl/1:data \“python retrain.py — bottleneck_dir= [path to bottleneck directory] — how_many_training_steps= [number of trainnig steps you want] — output_graph= [path and name of file you want to save .pb file] — output_labels= [ path and name of file you want to save as a .txt file] — image_dir=data”```

为了解释不同的超参数,与 mobilenets 脚本相比,inception 脚本在脚本中定义了更多的默认值。一旦一切都设置好了,瓶颈代码已经如上所示运行,您应该会在终端上看到这样的输出。

*评估我们训练好的模型

预定义的脚本写得非常好,它们会自动在 tensorboard 上写 tensorboard 摘要。您只需在 floydhub 作业仪表板上点击一个按钮,即可直观显示训练迭代的准确性和损失。Floydhub 会生成一个指向您的 tensorboard 摘要的链接:

对于 AI 开发人员来说,没有什么比这两个绘制的图形更令人满意的了,每次训练迭代的准确度趋向于 1,而损失(熵)趋向于 0。这是你做事正确的第一个标志。

有两个不同颜色的图,橙色的是用我们用来训练模型的数据评估损失和准确性的图,蓝色的是用没有用来训练模型的数据评估模型的图。

你可以在 floydhub 这里重现同样的结果

调试我们的模型

1500 次迭代之后,Inception 模型交付了 99.6 %的最终准确性总结。一个非常高的精确度,我怀疑这个模型确实过拟合了。

这是当人工智能模型从你的训练数据中学习得太好时,它不能推广到现实世界的数据。今天,我将保持特定模型不变,并根据现场演示的不同数据进行改进。

企业家所说的 MVP,用更好的现实生活数据不断改进。

初始阶段最终总结:

然而,mobilenets 的实现提出了一个不同的挑战。与初始模型相同的超参数交付了 100%的最终准确性总结

该模型明显过拟合,并且在迭代 22 时过早过拟合

在这种情况下,大多数人工智能研究人员会提高数据质量,引入更多的变异。引入一个丢弃层,每当模型过拟合时,就删除一半的突触。

在那个时候,这两种选择对我来说都不可行,所以我做了一些我不鼓励你做的事情。我用更少的迭代重新训练了模型。

而不是让我的训练迭代达到 100%准确的总结。

黑客攻击后的最终总结

部署到现实世界

如果我不把模型放在现实生活的用例中,所有这些工作和准确性都将是浪费。我开始使用分类器来翻译来自我的网络摄像头的直播。

将图像标签 python 脚本重写为模块化方法,简单地从我的网络摄像头获取一个帧对象到一张照片,并返回预测和预测的置信度得分。下一步是以编程方式从我的前置摄像头流式传输一张实时照片,并将每一帧作为一个帧对象,这样我就可以在模型中运行它进行预测。然后在屏幕上显示预测和置信度得分。

如果你用的是我的 GitHub repo,下面是运行的代码:

import tensorflow as tfimport cv2import base64import  timecap = cv2.VideoCapture(-1)count =0if cap.isOpened():rval,frame=cap.read()else :rval=False# Loads label file, strips off carriage returnlabel_lines = [line.rstrip() for linein tf.gfile.GFile("inception/output_labels.txt")]# Unpersists graph from filef = tf.gfile.FastGFile("inception/output_graph.pb", 'rb')graph_def = tf.GraphDef()graph_def.ParseFromString(f.read())_ = tf.import_graph_def(graph_def, name='')with tf.Session() as sess:while True:cv2.imshow("Inception Classifier", frame)# true or false for ret if the capture is there or notret, frame = cap.read()  # read frame from the ]buffer= cv2.imencode('.jpg',frame)[1].tostring()image_data=buffer# Feed the image_data as input to the graph and get first predictionsoftmax_tensor = sess.graph.get_tensor_by_name('final_result:0')predictions = sess.run(softmax_tensor,{'DecodeJpeg/contents:0': image_data})# Sort to show labels of first prediction in order of confidencetop_k = predictions[0].argsort()[-1:][::-1]for node_id in top_k:human_string = label_lines[node_id]score = predictions[0][node_id]#Only add label to feed if confidence is more than 40 %if score > 0.4:text_color = (255, 0, 0)cv2.putText(frame, s, (33, 455),cv2.QT_FONT_NORMAL, 1.0, text_color, thickness=2)name_of_file="frames/"+str(human_string)+str(score)+".jpg"cv2.imwrite(name_of_file,frame)print(name_of_file)count= count+1key = cv2.waitKey(20)if key == 27:breakcv2.destroyWindow("Inception Classifier")

结果是这样的:

Signing letter D

Signing the letter O

我将帧保存在一个目录中,以实时改进我的数据集,并最终使模型变得更好。很快我就有了足够的数据,mobilenets 实现并没有溢出。

然而这还不是结束。接下来的步骤

这个项目只是触及了所能实现的表面。

  • 部署到 Android :部署到 Android 应用程序有两种途径,第一种选择是将 tflite 应用程序添加到应用程序的源代码中,就像这个 tensorflow 示例应用程序或使用本教程中的 Firebase ML 工具包。你可以在这里测试我的 Firebase ML 工具包实现。我们可以将获得的图形文件转换为 tensorflow lite 文件,并将其部署在 android 应用程序上。为此,运行以下命令
```bash
toco \ — input_file= [path to .pb file] \ — output*_file=output/output_*graph.tflite \ — input*_format=TENSORFLOW_*GRAPHDEF \ — output_format=TFLITE \ — input_shape=1,224,224,3 \ — input_array=input \ — output*_array=final_*result \ — inference_type=FLOAT \ — input*_data_*type=FLOAT\ — allow*_custom_*ops```
  • 扩展到视频:我看到这正在扩展到肯尼亚手语词的 gif,并利用视频字幕应用程序的收益。简单地说,视频是一系列照片,我们可以将一层冻结的卷积网络和一层 LSTM 层结合起来,从三帧视频中解读手语词。其灵感来自于 Fchollet 的 TensorFlow 开发峰会演示

直到下次:

政府 AI 的透明度

原文:https://towardsdatascience.com/transparency-in-government-ai-7c871a9cc219?source=collection_archive---------15-----------------------

给机器学习的黑盒子照一盏灯会保护我们吗?

Photo by Kyle Glenn on Unsplash

为什么我们希望政府 ML 透明?

媒体和公众有一种感觉,透明度是确保机器学习的潜在危害不会发生的理想方式。但这在现实中是什么样的呢?

思考机器学习和人工智能在政府手中的潜在危害或担忧,会让人想起奥威尔的《1984 年的 T1》或斯皮尔伯格的《T2 的少数派报告 T3》。

我相信这是因为人类对有人以任何准确度预测我们将做什么的想法感到不舒服。我认为,当一个对我们有权力根据这些预测做出决定的实体(比如政府)做出这种决定时,这种不安会明显加剧。

我在之前写过关于潜在影响和危害的文章,但在其他文章和在线社区中也可以找到大量的故事和担忧。

什么是政府透明度?

透明是自由民主的标志。这是因为政府数据、政府决策和政府规则的透明度为公民和非政府组织质疑政府提供了一些必要的工具。它还赋予这些组织权力,作为对政府的制衡,建立游说和接触当选立法机构所需的知识基础,以改变现有法律或颁布新法律。

在美国,政府决策和规则制定的透明度不仅体现在第五和第十四修正案中,还体现在其他几项立法中。第五条和第十四条修正案一般规定了政府决策的正当程序,尤其是那些影响个人公民自由的决策。

美国还通过了阳光政府法案、信息自由法案、行政程序法和文书工作减少法案。这些法案结合起来向公众提供有关政府推理、决策和内部程序的重要信息。

然而,透明度是有限的。法律学者已经表明,法院会篡改这些法律,在做出决定或实施项目时,不能完全理解政府机构的内部运作。例如,《信息自由法》有九项豁免,政府机构可以排除或拒绝所要求的信息。这些可以有相当宽泛的解释。

但是,尽管这些法律为政府提供了广泛的豁免和警告,从某些信息的发布,仍然有机制来在许多问题上进行三角测量。

对机器学习透明度的错误乐观

在欧盟通过并实施《通用数据保护条例》(GDPR)后,通过对机器学习透明度的讨论,也出现了一种新的代理感。然而,正如学者所指出的,“解释权”的承诺过于乐观,原因有几个。

首先,有人担心政府将无法提供必要的服务水平,以允许关于每个 ML 预测实例的个人信息。

此外,这些算法将完全由政府机构控制的想法在世界范围内仍是一个公开的问题,因为许多政府机构依赖私营公司提供这些技能和技术。

第二,正如我们在 GDPR 所看到的——也很可能在其他法规中得到考虑——公民的个人同意可以免除数据处理器参与透明度的责任。

在私营部门,这被证明是近乎荒谬的控制手段。在公共部门,这还有待研究,但当个人知道政府将使用这些信息并对有影响的决策负责时,这可能会沿着私人路线或有所不同。

然而,人们担心,在没有对条款进行深入审查的情况下,便利会促使大多数个人同意,这种担心是真实的,我们可以预计,这在政府决策中也是无效的。

第三,我们知道机器学习并不总是能被个体公民所理解。这要么是因为公民通常不具备理解所需的知识和技能水平,要么是因为模型本身的性质不符合设计者和实践者的解释能力。

严格透明的替代方案

有用的解释。在一些研究中,出现了如何让机器学习对个人“可解释”的想法。如 Edwards 和 Veale 所述,有两种方法,以主题为中心的解释(SCE)或以模型为中心的解释(MCE)。

在 MCE 中,需要向个人解释经过训练的机器学习模型。这需要对输入、训练数据、参数和模型类型有深刻的理解。它还要求能够解释模型如何对单个预测进行排序和决策。这在团体层面上可能是有用的,但在个人层面上很难描述。

此外,MCE 可能需要机器学习算法、训练和测试数据以及输出的完整发布和透明。这将危及公司的私权,但也可能将游戏引入系统…在这种情况下,基本上抵消了机器学习的潜在好处。

另一方面,常设专家委员会可以帮助个人了解他们的情况将如何影响对他们作出的决定或产出,而不必打开“黑箱”。这也可以为他们提供了解他们的行为如何对他们的未来产生积极和消极影响的方法,并证明他们更好地理解关于未来的决策和机构。

SCE 的一个例子是信用评级公司允许用户操纵个人情况(工作、拖欠账户数量、家庭规模等)。)并查看基于这些变化的假设输出。

合理的解释。 另一种选择涉及通过合理的解释而不是鱼缸透明度来实现政府洗钱计划的透明度。鱼缸透明度是一个概念,类似于目前的“解释权”的理想,即政府在洗钱过程中所做的一切都将供公众消费和审查。

在一个合理的解释中,政府机构只需要提供 ML 模型背后的输入、输出和理论来描述它是如何设计的以及它的目标是什么。例如,它可以简单到解释数据输入以及观察犯罪行为和预测未来犯罪的目的。

这与目前美国政府法规的一些实例没有什么不同。在这些情况下,政府机构需要解释他们将如何作出裁决,他们的因果关系理论,考虑的因素,决定的法律标准,以及在这些决定中使用的推理。标准不是他们总是正确的,而是他们为公众提供了关于他们推理的深入信息。

政府问责制。 Cintron 和 Pasquale 提出了一个审计政府 ML 算法的流程,以帮助确保它们不包含对其目的和决策不可接受的偏差。

这种独立审计将通过提供第三方审查来确认合理解释的完整性。

它也可以作为一种机制和最大似然算法的储存库,可以防止担心或指控政府机构在没有公开通知的情况下修改甚至替换最大似然程序。

在公民诉讼或立法监督的情况下,可以将审计的算法与当前在特定情况下部署或使用的算法进行比较,以确认没有重大变化。

总之,公众对政府使用 ML 的谨慎或恐惧并不是没有根据的。但目前正在讨论的呼吁完全透明的提议,不太可能缓解或对这些担忧提供有意义的制衡。

与典型意义上的透明度不同,我同意一些研究人员的观点,他们试图确定政府洗钱项目中有意义的透明度类型,这将允许在政府裁决中采用和实施,但也不会限制政府的正当程序和监督。

允许政府对 ML 项目进行公告和审查,既不会提出不可实现的要求,也不会在第一步就降低其使用 ML 的能力。

考虑 SCE 可以为公民提供一个实际的方法来理解 ML 模型是如何对他们做出决策的,以及他们可以采取什么行动来影响未来的决策。

提供一个独立审计的平台可以建立在这些步骤上,以提供对洗钱项目的额外信任,并确保宪法规定的正当程序和监督。

我们应该仔细思考传统透明度和“解释权”背后的理念,作为减轻政府洗钱担忧的可行机制。

陷阱 DS 项目:当心“容易”的细分项目

原文:https://towardsdatascience.com/trap-ds-projects-beware-of-easy-segmentation-projects-e52ffc12a395?source=collection_archive---------22-----------------------

99%的可能性你还没准备好

TL;dr:依赖于一大堆其他东西的无界的、范围很小的项目和你想象的一样有趣。

今天的某个地方,世界上有人在对一位数据科学家说这句话的某个版本:“我们有很多客户行为数据,让我们将它们聚集到一些有用的细分市场,看看我们可以从哪里了解我们的业务,这有多难?”

剧透:很难,非常难,看似很难。大多数系统还没准备好。

And you’re on the boat

在我十多年的创业生涯中,我自己或在不同人的指导下,已经开始了不少于 3 个这样的项目。他们都没有好的结局,基本上只有一个原因——我们没有准备好。

分段听起来很容易

https://dilbert.com/strip/2000-11-13

在所有的机器学习算法中,聚类算法是最容易理解和实现的。像 k-means 这样的东西听起来很容易应用,大体上你只需要…

  • 将活动数据放入算法中
  • 对照现实观察输出
  • 迭代?
  • 利润!!!

除了,不。不是真的。

“把数据扔进算法中”?真的吗?

当“把 X 扔进 Y”这个词被四处传播时,警钟应该总是响起。数据几乎从来没有处于可以被“扔”到任何地方的状态。一旦你开始弄清楚你在隐喻性地到处扔什么数据,这个阶段就可以扼杀你的项目。

首先是“你有数据吗”这个基本问题。仅仅因为你一直在收集东西到数据库中,并不能使它对机器学习有用。如果您在持续记录关键事件方面有所懈怠,或者拥有大量有偏见的样本,或者出于成本原因而丢弃数据,那么您将不得不重新考虑所有这些决策。

—但是我有数据,以前甚至有人提到过数据仓库的事情?

很可能您有事务性数据,并且数据存储已经针对 OLTP 工作负载进行了优化,这是许多生产系统的自然状态。但是分析通常会问一些从侧面看数据的问题。这就是为什么在大约 15-20 年前“数据挖掘”成为行业热点时,“数据仓库”成为一个大话题。

Remember when “data mining” was a thing?

现在,如果您碰巧在某个地方有一个漂亮、干净、维护的数据仓库,其中有精选的度量标准和精心布局的数据立方体,那么您实际上就处于一个集群项目的相当好的开始位置。

我真的没见过多少员工少于 100 人的创业公司有这些东西。它们是需要维护的复杂系统,尤其是在其他系统发展和新数据产生的时候。大多数创业公司没有足够的资金来进行这种程度的分析。

—我实际上有数据,所以我可以正确地使用它?

让我们假设您已经有了一些可以使用的、有组织的、相对来说没有错误的数据。我们准备好了,对吗?

没那么快!!

接下来,您需要进行某种形式的特征生成/选择。虽然算法本身并不关心你是否加入了随机数,但作为分析师和最终用户,你是关心的。除非你喜欢虚假相关性,否则你必须对什么特征重要,什么不重要有所了解(如果你愿意,可以称之为假设)。你有必要的领域知识来做出这种有根据的猜测吗?有人知道吗?

因此,你至少需要了解你的业务的一些基本驱动因素,或者知道什么与你所寻求的成功相关。这意味着你需要对谁是你的客户,他们通常做什么做基础研究,即使只是在高层次上。

让我们用一些具体的例子来巩固这一点

假设你认为用户浏览页面的顺序对于区分用户未来的行为很重要。一个序列有多长很重要?因为存储/处理无限长的序列是$$$。

那么多次会话的行为呢,你有会话吗?与其他用户的行为是否有足够的重叠,让你拥有有用的熵?你从哪里剪掉长尾?

他们是否使用优惠券,或通过平面广告链接注册,或在第一天购买了 5 个小工具呢?也许是他们的原籍国,或者他们是否有信用卡记录,或者他们的个人资料?所有这些东西都被正确地装备了吗,在时间和空间上与用户适当地联系起来了吗?

—等等,我正要用所有的东西!为什么我不能现在就走?

因为两个大问题,各种形式的信息泄露,现有数据泄露了你的输出。想象一下,你发现有个人销售电话的用户很可能使用免费试用…因为销售团队为了“节省空间”而错误地从 CRM 中删除了旧的不成功的线索。或者你的系统中有一个“当前付费客户”标志(非常常见),所以如果你盲目地包括它,相对于没有这个标志的人来说,这将是一个很好的收入预测。

另一个原因是你想要使用的所有数据很可能不是普遍兼容和一致的。所有数据都有一致的用户密钥吗?有些字段表示当前的当前状态,有些字段表示时间上的历史状态,还有一些隐含的状态(例如“’”用户在离开默认状态之前不会在此设置字段中获得一行,因为默认状态是假定的)。仅仅因为它的存在并不意味着它值得一起讲述一个关于世界的一致的故事。

好吧,所以我只是看看田地,打扫一下,这能有多难?

当然,所以你去写查询来收集数据,然后你马上开始发现错误,这些数字并不完全一致,所以你必须弄清楚那里发生了什么并修复它们,对吗?然后你会努力去修复各种系统,也许会实现新的系统来取代坏的系统。突然,这个为期两周的“有趣”项目进入了第三个月。

由于这些特性中有许多不是聚类算法可用的格式,所以您会希望将它们存放在某个地方。也许那里有一个临时表,这里有一个聚集表。然后,您会希望随着时间的推移跟踪这些信息,如果这些信息都在一个系统中就好了...等等,这听起来开始像一个数据仓库(另一个梦想破灭的项目,但是我离题了)…

这个过程中最简单的部分

如果你设法达到这一步,这一部分通常不会太糟糕。确定您的特定集群包所采用的数据的确切格式通常是一件痛苦的事情,因为有 1500 万种方法来创建和存储“距离矩阵”,每个人都认为他们的格式是不言自明的,并不真正需要文档…

但除此之外,只要按下按钮!

“眼球簇对抗现实”

因为这是一个定义明确的问题,对吗?

假设您对 5 个集群运行 k-means 尝试。我们不确定 5 是否是正确的集群数量,除了我们从空气中提取的数字,我们盲目地进入这个项目,但我们有人类,我们可以检查看看“感觉”有多正确,对吗?

https://xkcd.com/1838/

这在实践中如何运作?我们转储行的例子,并试图得出一些押韵或理由。我们的希望是,我们看着集群,它以一种不明确的方式有点“有意义”。本质上,你必须看看机器的分类,看看你过度创造的人类大脑是否能想出一个可信的解释来命名这个集群。

但是没有真正的保证你能找到对你有用的东西。不清楚这一大堆数据点是有用的一组还是我们选择的特征的哑工件。即使集群代表了一种“真实的现象”,我们也可能无法充分理解它并广泛使用它。在任何这种模棱两可的情况下,你会想知道你是应该继续你的发现,还是放弃它,再试一次。

哦,对了,我是不是忘了提到,根据您使用的聚类方法和您的数据属性,可能会有关于在多次运行和一段时间内聚类的稳定性的问题?

重复

——因为第一次做起来很有趣,我们想再做几次,直到我们觉得做对了为止

帕尔塔伊。(顺便说一句,到现在过了几个月才走到这一步?)

利润?

如果你幸运的话。

整个聚类练习的最终目标是 1)了解关于用户的新的有趣的事情,或者 2)将新发现的组应用到其他事情上,这在以后会很有用。现在(大概)您已经有了一组集群用户,您会想要尝试做这些事情。希望它们能起作用,并开启各种洞见和神奇的独角兽。

那么是不是没有希望了?!?

有一些!

先做一些定性的作业

请注意,当您验证这些任意的无监督聚类时,您实际上是在使用您自己的数据心理模型作为参考点?如果你不能对是什么组成了一个集群有一个一致的理解,那么这个集群就不会感觉“正确”。既然你无论如何都需要这个作为参考点,先做

然后你会对你要寻找的集群数量有一些先验的假设,以及对什么潜在特征对模型有影响有一个更好的认识。所有这些都会对你的模型有所帮助你甚至会发现这个作业已经足够好了,甚至可能没有必要去做数据挖掘。

尽可能的限制自己的范围!

关键是要认识到,你想要使用的数据越多,涉及的痛苦就越多,直到一切都变得不可能。

安全生存的方法是非常严格地控制范围。这意味着你应该有

  • 一个非常确定和简短的列表列出了用户应该聚集起来反对的因素,假设是被鼓励的!
  • 你的数据收集系统提前调试好了
  • 您的数据访问/移动/管道基础设施处于可管理状态(您能否获得所有数据并将其复制到需要处理的地方?)
  • 如果所有这些基本要素都不具备,他们会有强烈的抵制意愿

知道什么时候该停下来推回去

开放式问题会耗费你愿意投入的时间,所以如果你发现你做的数据工程工作比集群工作多,你应该重新评估整个项目。

数据工程部分可能实际上是你应该做的推动公司前进的必要工作,但是把所有这些工作放在一个单独的数据人员的权限下的“做集群项目”的保护伞下是错误的。这个工作量应该是使用不同资源并与管理层讨论的严肃工作。

重要的是,在你对事情投入太多之前,先往后推。

穿越欧洲旅行(以一种书呆子的方式)

原文:https://towardsdatascience.com/travel-budget-optimization-5c97501babe0?source=collection_archive---------25-----------------------

通过使用 python 库抓取谷歌航班来创建最佳旅行路线

作为一个旅行爱好者,我明年的目标是尽可能多地旅行。我对目的地不是很挑剔;然而,我确实有一些限制。首先,我只能在周末旅行,因为我从周一到周五都在办公室工作。第二,我想用最少的预算尽可能多地游览不同的城市。第三,我不想在飞机上花太多时间。那么让我们来看看如何自动找到一个最优的旅行路线。

考虑到我的灵活性和局限性,我尝试了许多航班搜索工具,最终我选择了 https://www.google.com/flights 的 T2。在这里,您可以选择一个出发城市,将目的地留空以探索各种选项。您还可以选择灵活的旅行日期,例如,在未来 6 个月内的所有周末旅行,只需点击几下鼠标:

Google flights is flexible but not what I’m looking for

然而,我发现他们对周末的定义毫无用处。例如,参见上面的截图。你可以看到 4 月 2 日周四飞往布拉格的航班谢谢你,谷歌,给了我这个便宜的选择,但我周五必须去办公室。同样,它为其他城市提供了一些其他选择,周六晚上出发,周日早上返回,如果你只是对了解机场感兴趣那就太好了。

所以,谷歌,伴随着巨大的灵活性而来的是巨大的责任,你对周末旅行的假设是错误的。

好吧,让我们给谷歌更少的灵活性。让我们告诉谷歌,我想在 2019 年 12 月 13 日至 15 日的周末去欧洲任何地方旅行,从阿姆斯特丹往返,周五在 hs 的 18.0024.00 之间出发,周日在 hs 的 16.0024.00 之间返回。这是该搜索的链接:

https://www.google.com/flights#flt=AMS..2019-12-13 * . AMS . 2019-12-15;c:欧元;e:1;dt:1800-2400 * 1600-2400;ls:1w;SD:1;t:e

在该 URL 中,AMS 指的是阿姆斯特丹,您也可以在那里看到我们选择的日期和时间限制。

URL 中的搜索逻辑非常简单:

*[https://www.google.com/flights?hl=en#flt={city_code}..{departure_date}*.{city_code}.{return_date};c:EUR;e:1;dt:{takeoff_after}-{takeoff_until}*{return_after}-{return_until};ls:1w;p:{max_budget}.0.EUR;px:1;sd:1;er:296254327.-269199219.671078146.490175781;t:e](https://www.google.com/flights?hl=en#flt=/m/0k3p..{departure_date}*./m/0k3p.{return_date};c:EUR;e:1;dt:{takeoff_after}-{takeoff_until}*{return_after}-{return_until};ls:1w;p:{max_budget}00.2.EUR;px:1;sd:1;er:296254327.-269199219.671078146.490175781;t:e)*

其中城市 _ 代码为 IATA 机场代码,出发 _ 日期返回 _ 日期格式为yyyy-mm-DD;起飞 _ 之后,起飞 _ 直到,返回 _ 之后,返回 _ 直到格式为HHMM;而 max_budget 格式是一个整数,以欧元为单位定义最高价格。 er 参数定义了寻找目的地的区域。您可以使用缩放功能,将这些数字更改为您感兴趣的任何区域。

按照这个简单的 URL 逻辑,我创建了一个 python 库,它可以扫描 Google 航班并将行程保存在一个 CSV 文件中。您可以在此回购中找到代码:

https://gitlab.com/cintibrus/scrap_flights

您可以下载它,导入库,然后通过用 CSV 文件名创建 GoogleFlights 对象来调用它。然后,您可以通过调用 createDataWorldwide 方法扫描任何地方的所有目的地,如下所示:

*gs = GoogleFlights(csv_filename)
gs.createDataWorldwide(travel_lenght_list,start_period,end_period,steps_days,takeoff_after,takeoff_until,return_after,return_until,nr_passengers)*

createDataWorldwide 方法的参数如下。travel _ length _ list是一个数组,包含您要扫描的住宿天数,例如,[2,3]将扫描包含 2 晚和 3 晚的旅行。 start_period 是开始扫描的第一个出发日期;因此,如果您想扫描周六出发、周日返回的所有往返航班,请确保 start_period 是周六,并且travel _ length _ list=[1]。 end_period 是扫描的最后一个出发日期;对我来说,是 2020 年 12 月的任何一天。参数 steps_days 是扫描出发日期之间的间隔天数;因此,如果 steps_days =7,它将扫描每周出发的航班,如果 steps_days =1,它将扫描每天出发的航班。我使用起飞 _ 之后起飞 _ 直到只扫描 18 小时后出发的行程。因为我想周五下班后去旅游。同样,我使用 return_afterreturn_until 扫描 17 小时后返回阿姆斯特丹的航班。因为我想在周日早上花些时间在城里逛逛。最后可以用 nr_passengers 指定乘客数量。

如果你没有任何限制,并且想去野外,你可以设置 travel _ length _ list =2,3,7,start _ period= ' 2020–01–01 ',end _ period= ' 2020–12–31 ', steps_days =1, takeoff_after ='000 ',take off _ out 这将扫描 2020 年任何日期从阿姆斯特丹出发、持续 2、3 或 7 晚的所有往返航班。**

F 还是我的用例,我用我的 python 库刮出了 2020 年每个周末从阿姆斯特丹到任何目的地的所有往返,价格低于 300 欧元的 2 位乘客。

我对周末的定义是 18 小时后的星期五。17 小时后周日返回,但可以很容易地更改。这是我如何使用库来实现我想要的:

*gs.createDataWorldwide([2],'2019-12-06','2020-12-01',7,takeoff_after='1800',return_after='1700',nr_passengers=2)*

它会创建一个 CSV 文件。该文件的一个小示例如下所示:

目前还没有 2020 年 11 月和 12 月的选项,所以我找到的最后一个周末的航班是 2020 年 10 月 16 日。

现在我可以称这个方法为 optimum_weekends,来寻找 2020 年最低预算的旅行路线。

*gs.optimum_weekends(duration_max,from_start,allow_max_city_duplicates)*

参数 duration_max 过滤掉超过*x*小时的航班。我选择了 duration_max =7,因为我不想飞行超过 7 个小时。参数 from_start 指定旅程的开始日期。参数allow _ max _ city _ duplicates过滤掉具有超过*x*个重复目的地的路线。该方法通过为 2020 年所有周末的每个日期选择目的地的排列,创建了数千条可能的路线。输出是对于扫描的行程具有最低可能预算的路线。输出如下所示:

Itinerary of weekend trips for 2020

我需要在 2020 年每个周末旅行(不包括 11 月和 12 月)的总预算是 7670 欧元,2 名乘客,从阿姆斯特丹来回。我将在 42 个周末了解 26 个不同的城市。我也不需要在工作中请假。

实际上,我对多次访问同一个城市不感兴趣,所以让我们删除重复的城市,让我们保留最便宜的选项。

Itinerary of weekend trips for 2020 to unique destinations

我需要为 2020 年 2 名乘客游览 26 个不同城市的优化预算旅行路线的总预算是 5061 欧元。

我期待人们使用该工具,根据不同的限制或改进建议,提出其他优化策略。在我的头顶上,人们可以使用该工具找到 2020 年前往特定目的地的最便宜的日期;或者调查航班价格是否在一天之内、一周之内或随着 IP 国家发生变化;或者发现票价错误。天空不是极限,是目标:)。

创建伦敦的现代旅游地图

原文:https://towardsdatascience.com/travel-map-8407796c9219?source=collection_archive---------11-----------------------

我设计了一张个性化的伦敦地图,显示了我在 10 分钟、20 分钟、30 分钟等时间内使用公共交通工具可以走多远..)分钟。它看起来是这样的:

Map of London showing how far you can travel using public transport from my house in Ealing. Interactive map here. Can you guess where the tube stops are?

更好的是,代码可以在世界任何地方使用,也可以行走。以下是我有幸居住过的另外三个大城市的个性化地图:

Travel time areas for 10, 20, 30, and 45 minutes travel around where I lived in Montreal, Manchester, and Edinburgh, using any public transport available.

该过程

在一个慵懒的周日早晨,我偶然发现了一系列美丽的历史地图。这些被称为等时线地图,代表了制图员对你在不同时期能走多远的估计。我最喜欢的是巴塞洛缪的从伦敦到世界各地的等时距离图。

John G. Bartholomew’s isochronic map [1]. Look how inaccessible South America, Africa, and Australia are.

虽然这些很有趣,但我们应该有所保留。我怀疑巴塞洛缪先生是否广泛研究过波兰的火车时刻表。但是这些天我们有高度准确的旅行时间预测。那么,对于世界上我最喜欢的城市来说,真正的等时地图会是什么样的呢?

我发现伦敦特别有趣的地方是,从我住在伦敦西部的地方,我可以很快到达主要的博物馆,并进入伦敦金融城(伦敦内一平方英里的区域)。但是去伦敦东南部旅行是一场噩梦(大约 1.5 小时),比从爱丁堡到格拉斯哥的旅程还要长。

到代码上…

代码

为了创建个性化地图,我们需要选择一组要分析的点,检索这些点的旅行时间,通过绘制外壳将这些点分组到边界中,并在地图上绘制这些点。

当创建一个点的点阵时,我始终专注于使用 NumPy 来利用它的矢量化,以及比 Python 列表更高效的计算。我创建了两个选项:

  1. 以原点为中心的局部网格,具有定义的点间距和点数
  2. 一个全球格网,取一个区域的最小和最大纬度和经度进行搜索,以及格网分割的次数

接下来,我必须生成旅行的实际时间。有许多选项可以做到这一点,但我决定使用谷歌距离矩阵 API 。这将返回往返目的地的距离和时间。我查看的其他选项包括 Google 方向 API (它也返回方向,这对于这个应用程序是不必要的),以及 MapQuest 方向 API 。

Screenshot of my Google Developer Console

你可以通过谷歌开发者控制台访问超过 24 个谷歌 API 的套件。我发现设置 API 非常直观,虽然这些 API 是付费的,但你可以在 12 个月的试用期内获得 300 美元的免费积分,我发现这对我的项目来说绰绰有余。确保您对结果进行了筛选,这样您就不需要多次调用同一个区域的 API 了!

# Storing my latitudes, longitudes, and travel times from the API
pickle.dump([lats, lngs, travel_times], open(pickle_path, 'wb'))

我在使用这个 API 时发现了一些有趣的怪癖,包括:

  1. 您发送给 API 的查询字符串可能太长,在这种情况下,您需要使用折线编码对其进行编码。
  2. 每个请求只能发送 100 个元素(1 个起点,100 个目的地),所以我使用chunked_latitudes = np.split(latitudes, len(latitudes)//chunk_size)分块我的 NumPy 数组。
  3. 它意外超时,所以我每 5000 个请求就暂停一次代码。

有了一组数据点,我就必须想出如何根据旅行时间将它们连接到不同的区域。这并不是一项简单的任务。我的第一个想法是把外面的点连接起来,这就是所谓的凸包。然而这不是我想要的。我想要的是进入角落和缝隙,在数据中找到“峡湾”。这种实现称为凹面外壳。

The unique convex hull for the set of points on the left, and a concave hull for these points on the right [3].

凹面外壳是不唯一的,你可以通过选择最近邻的数量来决定你希望你的凹面外壳在点周围有多少包裹。我使用了 J. P. Figueira 写的一个很棒的实现,我使用了这个实现。

凹面外壳实现没有处理的是点的孤岛。这些是地图上最有趣的部分。特别是,地铁和公共汽车周围的区域是可以到达的,而地理位置更近的区域则不可以。这是我真正好奇的:伦敦有哪些离我比较近,但又隐藏起来的地方?

Points I can access within 30 minutes from my home in London. Are there 7, 8, or 9 islands?

我对机器学习很感兴趣,所以我开始尝试实现两种无监督的机器学习方法:K-means 聚类和高斯混合方法(GMMs)。然而两者都有问题。

K-means 聚类在聚类中心周围绘制一个恒定的半径,这并没有考虑到点是如何在纵向上更加分散的。

A K-means clustering for the points with 7 clusters. It’s terrible. Code thanks to Python: Data Science Handbook by J. VanderPlas

GMM 通过绘制任意对齐的椭圆来分组集群岛,从而解决了这个问题。然而,我发现这些省略号仍然是病态的。这并不奇怪,因为 GMM 主要是一种密度估计方法。事实上,我寻找的是一种没有聚类中心的聚类方法,它只是根据成对的距离对点进行分组。

经过一番搜索(并试图自己编写算法),我意识到我需要的是 DBSCAN 。Sci-kit learn 有一个易于使用的实现,但是有讨论这个实现是否是一个有效的。

The code to implement Sci-kit learn’s DBSCAN

在这一切当中,我发现 J .范德普拉斯的书非常有助于理解这些方法以及为什么它们不适合我的问题。这是一个很好的教训,在尝试重新发明轮子之前,要先寻找存在的东西,并且思考简单而不是复杂的方法。

这个问题的最后一步是把数据放到地图上。有相当多的地图库可用,包括允许你将数据直接放到谷歌地图上的库。然而,我一直在寻找的是绘制多边形的能力,事实证明,叶子库可以为 OpenStreetMap 做到这一点。

Folium 是一个直观的库,因为它遵循与 Matplotlib 相似的编码风格,让您创建一个地图对象,并将子对象作为点或多边形的层添加到其中。此外,它们被创建为交互式 html 页面,您可以放大和缩小,或者选择和取消选择图层。

Adding island-clusters of points onto the map

我们还可以将它用于哪些有趣的应用?

伦敦在繁忙的地区有一组标志,显示你可以在 5 或 15 分钟内到达哪里,但它们是相当不准确的圆圈。精确的版本呢?

Photo I took of a sign in London at Charing Cross station left. Map with the sign’s five minute walking radius in red, with the true five minute walking distance in black right. No more trying to walk into the Thames.

我尚未探索的想法:

  • 查看伦敦哪些地区的交通状况较差,尤其是到“文化中心”的交通状况,并调查可达性和贫困指数之间的相关性。
  • 这种个性化地图是如何在 24 小时内演变的,尤其是自从引入夜视管以来。

完成后不久,我在网上找到了两家这样做的公司。不幸的是,其中一个只允许你在付费前进行两次搜索,另一个有国家限制。由于他们画出的形状和他们找到的岛屿是不同的,我将联系他们来找出他们的方法是如何比较的。

你还能在哪里使用这个代码?你可以用它来找到一个合适的住处,离你的工作地点、健身房或其他地方都很近。

请随意使用我的 GitHub 代码(适当地),或者有任何疑问或想法联系我。

参考

[1] J. G. Bartholomew,I 社会距离图 (1904 年),通过大卫·拉姆齐地图收集获得。

[2] 波兰在 1795 年至 1918 年间甚至还不存在。

[3] E .罗森、e .扬松和 m .布伦丁,实现一种快速有效的凹壳算法 (2014)。

[4]奥莱,https://www.oalley.net/

[5]旅行时间地图,https://app.traveltimeplatform.com/

使用 Python 在区块链生态系统中旅行

原文:https://towardsdatascience.com/travelling-in-the-blockchain-ecosystem-with-python-47ab5dd0500d?source=collection_archive---------19-----------------------

Aggregate Market Caps of all Coins

全球有超过 2500 个活跃的区块链项目,每个项目都有自己独特的统计特征,我们很少看到对整个加密市场的顶级分析,因为清理和收集时间序列太耗时了。

在零售方面,我们没有一套清晰的功能来收集、清理和探索定制区块链生态系统投资组合所需的关键数据。接下来的博文将为更深入的量化方法打下坚实的基础,这些方法与使用数据科学量化策略的基于投资组合的波动性、聚类、预测和日志回报等相关。我们现在可以通过 CrytpoCompare 用他们优秀的 API 来聚集和交换特定的交易数据——对散户投资者是免费的。

这篇文章将介绍长时间序列的并行下载,加速比是 8 倍(取决于您机器上的内核数量),我将探索每个可用符号的其他实用统计数据( ticker )。本帖将探讨利用以太坊等协议(即平台)的令牌的性质,以及基于 ERC20 等的令牌。我们将会看到,目前区块链市场的市值为 150,404,143,218 美元(1500 亿美元),仍然只是其他替代市场的一小部分。

首先,您需要在本地机器上下载 Anaconda,并在一个环境中用 Python 3.5+设置一个 conda,然后启动一个 Jupyter 笔记本来运行 chunks 下面的代码。更好的是,如果你还没有尝试过,在 Google Collab 中免费运行下面的代码。

接下来,我们将找出每个协议的令牌项目的数量。

Counts of Tokens per Protocol

  • 这里注意,以太坊协议下有 1700+ ERC20 个令牌。WAVES 和 NEO 分别以 53 个和 25 个令牌紧随其后。然后,我们将创建一个树形图来可视化不同协议分组之间的比例。

Token Ratios among Platforms with >1 Coin

我们可以清楚地看到,基于以太坊 ERC20 的项目与市场上所有其他区块链协议相比存在很大的不相称性。这些项目帮助推动了 2017 年底至今的 ICO 市场。

当第一次为这篇文章构建代码时,我试图下载所有列出的 3500+资产,我将在这里为那些在连接所有 crytpo 聚合价格方面有困难的人提供代码。然后,我们将继续在一个并行例程中下载所有历史资产。

Wall time: 5min 17s!! for 150 series!!

现在,我们将绘制显示前 150 个资产的图表,其中颜色编码的条块表示相应项目中的一个或多个令牌。

请注意,左边的高市值项目通常有一个以上来自其根协议的相关令牌。然后,我们将在一个并行化的例程中深入研究所有可用的令牌/协议——这将大大加快我们的处理时间。

创建一个二元图来显示项目从 2014 年到 2018 年的启动时间,按市值排序。

在这里,我用 CryptoCompare 上可用的价格数据绘制了所有 2600 种资产。其他 1000 多项资产要么是前 ico 资产,要么目前没有收集每个符号的汇总交易数据。值得注意的是,在 2017 年 5 月和 2017 年 10 月/2018 年有许多新项目上线的平台期。一些市值较高的项目根据其发布日期增长非常快,而其他类似发布日期的项目却没有增长。接下来,我们将看看大市值 ERC20 令牌在此分布中的位置。

这里的图显示了所有 29 个方案的颜色编码。因为 ERC20s 统治着当前的生态系统,我们看到它们在右边的黄色部分。它们的市值较低,主要是从 2017 年底加密市场的峰值释放到市场上的。这种选择的爆炸可能是密码市场如此迅速衰落的一个重要原因,因为如此多的资本开始分散到许多代币产品中。

在 TechCrunch 最近的一篇文章中,我们看到了“2018 年迄今已有 1000 个项目失败”。然而,截至 2019 年 1 月 30 日,仍有 2633 个活动项目。为了客观地看待问题,福布斯报道仅在 2017 年就提供了 800 个 ico。

以下是 2014 年以来 50 个项目及其各自价格的随机样本。这些资产都是高度正相关的。用上面的并行代码证明给自己看。

我们将使用 Python 中的 Bokeh 模块从 StackOverflow 改编的 gist 中提取一些代码。它非常适合使用 D3 探索多个时间序列——具有缩放功能和基于悬停的信息。

同样,我们将按市值查看顶级资产。

波动性呢??我们将在以后的文章中探讨这个问题。

现在我们想从 CryptoCompare 并行拉入循环补给,并将其与我们原来的 stats 合并,原来的 stats 只包括最大补给。前者是目前被广泛接受的衡量数字资产市值的方法。关于更适合区块链估值的未来和预期测量方法的更深入的讨论,请看经济学的这篇精彩文章。另一个受欢迎的网站 Coinmarketcap.com 用流通供应量来计算市值。

现在合并统计数据,以便按协议探索聚合市场资本

现在,让我们按每个硬币的市值来绘制市值图。我们看到比特币(BTC)、Ripple (XRP)和以太坊(ETH)仍在市场份额上占据主导地位。之后,我们将展示协议生态系统中所有令牌的市场价值。

Market Cap Shares of Aggregate per Coin

接下来,我们显示了基于 marketcap 分组的协议的 marketcap。现在,基于 ERC20 的令牌开始挤占空间。CryptoCompare 似乎有一些令牌在 marketcap 计算中存在异常值。我希望他们尽快修复这些错误,这些错误在下面的代码中被过滤掉了,例如:

“比特 CNY”、“BTF”、“NPC”、“MTN”、“圆点”、“I0C”、“阿米什”、“WBTC*”、“蜂巢”、“OCC”、“SHND”(它们似乎在市值计算中反映不准确)

按协议市场份额分组,瑞士联邦理工学院现在仅次于 BTC。

Source: https://giphy.com/explore/bravocado

感谢您花时间一起探索区块链的生态系统。期待回答您的任何问题。上述代码在一段时间内应该是完全可复制的。如果您对使用上述数据的帖子有任何建议,请分享您的想法。

穿越图形计算和数据库领域

原文:https://towardsdatascience.com/traversing-the-land-of-graph-computing-and-databases-5cbf8e8ad66b?source=collection_archive---------24-----------------------

您对图形技术世界的一站式介绍。

Photo courtesy: Neo4j

该博客最初发表于亚特兰蒂斯 数据刊物 人类。

图形是优雅而强大的数据结构,可以在不同规模的多个行业和组织中找到应用。本文旨在向数据人员介绍图形数据库和图形技术领域,并揭开它们的神秘面纱。

:我最近有幸在意大利的PyCon X演讲。这个演讲,就像它的名字一样,和这篇文章有着共同的目标。如果你喜欢这种视觉媒体,可以在这里随意观看

为什么要关心图形?

  • 图表是数据的优雅表示,适合各种用例。作为一个数据人,了解它们可以帮助你评估它们对你的问题陈述的效用。
  • 从十九世纪开始,图论就作为一个学术领域存在了,从柯尼斯堡桥问题开始。你可以利用大量相关的工作和理论。突出的用例包括最短路径问题、链接预测和 PageRank 。

The Königsberg bridge problem from the 1800s. Photo courtesy: Wikipedia

  • 过去几十年的发展导致了图表技术的兴起。图表为互联网巨头提供动力,如谷歌(知识图表)、脸书(社交图表)和 LinkedIn ( 经济图表)。

什么是图?

图是一组顶点(节点、实体)和边(关系)。

传统上,数据以表格格式表示。图表以一种更接近我们心智模型的方式来表示数据。

图形技术怎么样?

图形技术指的是允许用户利用图形数据结构的软件。

Graph tech 软件可以是数据库,如 Neo4j 或 AWS Neptune ,处理框架,如 Apache Giraph 或 Apache Spark 的 GraphX ,或可视化工具,如 Cytoscape 。

让我们比较一下图表数据格式和表格数据结构。

多年来,表格已经成为我们表示数据的事实上的格式。尽管表格模型很有用,但它有局限性,因为它处理的是行和列,而不是真实世界中的实体。逻辑和业务模型从技术模型中分离出来,这就产生了对中介的需求。

这里有一个例子。它涉及到印度 DTC(德里运输公司)的一些 GTFS (通用公交馈电规范)公交数据。

最初由谷歌推出,GTFS 定义了公共交通时刻表和相关地理信息的标准格式。我们用 GTFS 做旅行计划。这些数据由一系列文件组成,比如路线、站点和站点时间,它描绘了德里的公共汽车交通状况。

为了执行有意义的分析,您要么必须在查询/读取时连接各种表,要么以重复的非规范化格式存储它们,这很快就会变得混乱。

连接是一项开销很大的操作。如果您以前处理过关系数据库,您就会知道这样的操作会如何增加您的成本。

处理 GTFS 数据的一个更好的方法是将其存储为图表。通过这样做,我们可以利用健壮的图算法来寻找最短路径和连接组件。图表在视觉上也有很大的不同。

可以用 SQL 做图吗?

鉴于我们对基于 SQL 的解决方案的熟悉,我们可能倾向于在忠于它们的同时解决这个问题,而不是选择图形技术。但这可能会导致一个痛苦的世界。

请看以下摘自 Martin Kleppmann 和 O'Reilly Media 的 设计数据密集型应用 的节选,它为 graph tech 提供了一个强有力的案例。

An excerpt from Designing Data-Intensive Applications on comparing Cypher with SQL

在左上角,您可以看到我们的数据模型。它显示了一对夫妇 Lucy 和 Alain 的信息,以及他们的地理位置。你可以注意到不同国家之间的区域结构和粒度存在差异。

如果我们决定不使用图形数据库会怎么样?

就用基于 SQL 的解决方案比如 Postgres?

虽然我们可以创建一些表——顶点和边——但是 SQL 并不是为查询图形而设计的。

一个创建从美国移民到欧洲的人的列表的查询,显示在上图的右侧,可能需要 50 多行。

如果我们选择基于图形的本地解决方案,我们的数据模型将保持不变。

我们可以使用一种图形查询语言,比如 Cypher,只需几行代码就可以获得相同的信息。

可读性很重要。

- 禅宗之蟒

为什么这些年来图形技术变得越来越流行?

有几个因素导致了 graph tech 今天的地位。这是过去几十年图形技术发展的时间表。

语义网

我们的故事始于 2001 年的语义网。

WWW 发明者蒂姆·伯纳斯·李和他的合著者在《科学美国人》的一篇文章中创造了这个词,它被建模为网络的延伸。语义泛指对意义的研究。

语义网标准旨在用一个物联网取代网页。一个关键的概念是将实体表示为三元组,即主体-客体-谓词,即节点和关系。

尽管语义网还没有完全实现,但它对图形技术的发展做出了巨大的贡献。

A representation of semantic web. Photo courtesy: Wikipedia

开源生态系统

从 2000 年代末开始,一个庞大的图形技术开源生态系统——包括数据库、处理(OLAP/OLTP)和可视化软件——已经形成并继续增长。

还有几种查询语言(Cypher,Gremlin)和抽象层(GraphQL)。

最近,已经开始努力提出一个通用的图形查询标准, GQL 。目标是让 GQL 成为所有基于图形的系统的统一标准,类似于 SQL 对于表格数据系统的意义。

标准化对任何技术来说都是一个好兆头。因此,GQL 的努力是一大积极因素。

托管云服务

Graph tech 将受益于各种大小厂商提供的托管服务。这些产品包括 AWS Neptune 和 Tigergraph cloud 等。这与上一个关于开源生态系统的观点相联系,并从中受益。

AWS Neptune is an example of a managed cloud database.
Photo courtesy: ZDNet

野外的图表

这一部分可以合理地包含一整篇文章,甚至一系列文章。

现在,我将强调一些用例。这些概述了广泛的问题陈述,可以使用图表来解决。

这里一个共同的主题是关系的重要性。

  • 知识图谱(KGs) :许多组织如谷歌和美国宇航局利用知识图谱来改善服务和内部效率。KG 以图形格式存储关于域或组织的信息。在数据点之间的关系变得越来越重要的时代,这是一个高度相关的概念。
  • 数据民主化和发现:数据民主化意味着允许最终用户,包括非专业人员,能够在没有任何外部帮助的情况下访问和分析数据。阅读这篇关于 Airbnb 如何在图形数据库的帮助下在他们的组织内部实现同样功能的精彩报道。
  • 调查性新闻:巴拿马论文背后的 ICIJ (国际调查记者联盟)团队使用图形数据模型有效地探索数据。即使是非技术用户也能够处理视觉上丰富的图形数据。

其他值得注意的用例包括数据治理和合规性( Apache Atlas )、推荐( Pinterest 、亚马逊)和社交网络(脸书)。

与数据相关的技术挑战是什么?

这些挑战可以分为两个主要方面:

1.发展中的生态系统和缺乏共识/标准

无论是选择存储和处理图形数据的工具,还是选择合适的查询语言,决策都可能变得令人不知所措。但是进展很快。为发展 GQL 所做的努力就是一个很好的例子。

2.将数据转换成图形格式

将数据转换为图表格式的过程可能涉及大量的处理和清理工作。它还会导致重复数据删除或记录链接。杂乱的数据让这种转变更加痛苦。

我们在 Atlan 的数据团队在数据民主化和发现方面投入巨大——这是我们构建知识图表平台的主要动机。一个好的平台所提供的抽象将会消除上面提到的挑战。

你应该使用图形数据库吗?

我的建议是:知道你的目的。

你应该根据你的问题陈述仔细评估 graph tech 的效用。一些相关的包括欺诈检测、推荐引擎和法规遵从性。

有些情况下,graph tech 可能不是最合适的,例如简单的 CRUD 应用程序或定期执行数据批量扫描的系统。

最后的话

我希望能够让您相信,在数据关系是首要公民的世界里,图表会一直存在。

别等了。继续前进,穿越图表的土地!

Travis CI for R —高级指南

原文:https://towardsdatascience.com/travis-ci-for-r-advanced-guide-719cb2d9e0e5?source=collection_archive---------20-----------------------

在 Travis CI 中构建 R 项目的持续集成,包括代码覆盖、[pkgdown](https://github.com/r-lib/pkgdown) 文档、osx 和多个 R 版本

Photo by Guilherme Cunha on Unsplash

Travis CI 是构建 R 包的常用工具。在我看来,在持续集成中使用 R 是最好的平台。一些下载量最大的 R 包就是在这个平台上构建的。例如测试magickcovr 。我也在这个平台上构建了我的包 RTest 。在安装过程中,我遇到了一些麻烦。在这本指南中,我将与你分享我获得的知识。

目录

  • 来自“构建 R 项目”的基础知识
  • 修改 R CMD 版本
  • 多种操作系统
  • 使用用户界面运行脚本
  • 代码覆盖率
  • 构建并部署一个 pkgdown 页面到 github 页面
  • ImageMagick 和 Travis CI
  • 延伸阅读

“构建 R 项目”的基础知识

Travis CI 的文章“构建一个 R 项目”告诉您一些基本知识。它允许为 R 包或 R 项目建立一个构建。主要的收获来自这个. travis.yml 文件。

# Use R language
language: r#Define multiple R-versions, one from bioconductor
r:
  - oldrel
  - release
  - devel
  - bioc-devel# Set one of you dependencies from github
r_github_packages: r-lib/testthat# Set one of your dependencies from CRAN
r_packages: RTest# set a Linux system dependency
apt_packages:
  - libxml2-dev

教程向你解释你应该把你的类型语言设置成 R. 你可以使用不同的 R 版本。这些 R 版本是:

[旧版本,发布,开发,生物开发,生物发布]

此外,你可以通过r_github_packages从 github 加载任何包。或者你可以通过r_packages从起重机处拿到任何包裹。可以使用标准的 yml 格式创建多个包的列表:

r_packages:
  - RTest
  - testthat

如果你有 Linux 依赖,这需要被提及。RTest 包使用 XML 测试用例。需要的 XML Linux 库是libxml2。可以通过以下方式添加:

apt_packages:
  - libxml2-dev

您已经完成了基本操作。如果您的存储库中有这个. travis.yml 文件,它将使用R CMD buildR CMD check来检查您的项目。

修改 R CMD 命令

为了建立我的项目,我想把它建得像克兰一样。因此,我需要更改包检查的脚本。因此我补充道:

script:
  - R CMD build . --compact-vignettes=gs+qpdf
  - R CMD check *tar.gz --as-cran

在这个脚本中,你可以改变R CMD buildR CMD check参数。关于R CMD的参数列表,请参见 RStudio 的本教程。

要运行晕影压缩,请通过以下方式获得gs+qpdf:

addons:
  apt:
    update: true
    packages:
      - libgs-dev
      - qpdf
      - ghostscript

多重操作系统

Travis CI 目前提供两种不同的操作系统(2019 年 1 月)。那些是 macOS 和 Linux。测试的标准方式是 Linux。对于我的项目 RTest,我也需要在 macOS 中进行测试。要在两个操作系统中进行测试,请使用 Travis CI 的matrix参数。

matrix参数允许为某些构建调整某些参数。为了在 Linux 和 macOS 中拥有完全相同的版本,我使用了以下结构:

matrix:
  include:
  - r: release
    script:
      - R CMD build . --compact-vignettes=gs+qpdf
      - R CMD check *tar.gz --as-cran 
  - r: release
    os: osx
    osx_image: xcode7.3
    before_install:
      - sudo tlmgr install framed titling
    script:
      - R CMD build . --compact-vignettes=gs+qpdf
      - R CMD check *tar.gz --as-cran

matrix函数将构建分成不同的操作系统。对于 macOS,我使用了 xcode7.3 图像,因为它是由 rOpenSCI 提出的。这个版本额外的一点是,它接近目前的 CRAN macOS 版本。正如你所看到的,你应该安装乳胶包framedtitling来创建插图。

使用用户界面运行脚本

我的包 RTest 使用 Tcl/Tk 用户界面。为了测试这样的用户界面,您需要分别在 Linux 和 macOS 中启用用户界面。Travis CI 为 Linux 提供了xvfb包。对于 macOS,您需要用homebrew重新安装xquartztcl-tk

Linux 的用户界面

要在 Linux 中启用用户界面,请安装xvfb

addons:
  apt:
    update: true
    packages:
       -   x11proto-xf86vidmode-dev
       -   xvfb
       -   libxxf86vm-dev

您可以在用户界面中运行所有的 R 脚本,方法是在R命令前使用xvfb-run命令。

script:
      - R CMD build . --compact-vignettes=gs+qpdf
      - xvfb-run R CMD check *tar.gz --as-cran

macOS 的用户界面

对于 macOS 来说,用户界面的安装更加困难。您需要将xquarttcl-tk添加到xcode7.3中提供的图像中。

before_install:
      - brew update
      - brew cask reinstall xquartz
      - brew install tcl-tk --with-tk
      - brew link --overwrite --force tcl-tk; brew unlink tcl-tk

要使用 xquartz,macOS 下没有xvfb-run命令。在 github 的一期中,我发现了一个解决方案,仍然可以让用户界面与xquartz一起工作。

before_script:
      - "export DISPLAY=:99.0"
      - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ( sudo Xvfb :99 -ac -screen 0 1024x768x8; echo ok ) & fi

在运行 R 会话可以使用的任何 R 脚本之前,创建一个显示。导出DISPLAY变量很重要。该变量由 tcktk R 包读取。

在 macOS 中,你不需要修改脚本

script:
      - R CMD build . --compact-vignettes=gs+qpdf
      - R CMD check *tar.gz --as-cran

插件

有关用户界面的更多信息,您可以阅读以下两个 github 问题:

  • 带特拉维斯和闪亮的硒元素
  • 酱硒

代码覆盖率

对于代码覆盖率,我建议使用一个特定版本的构建。我决定用 Linux + r-release 来测试代码覆盖率。首先,我将 covr 包添加到我的构建脚本中:

r_github_packages:
  - r-lib/covr

其次,我想使用 covr 测试我的包。这可以在 Travis 中使用after_success步骤完成。为了在这个步骤中使用 covr ,你需要定义你的包 tarball 将如何命名。您可以将这一点直接写入您的脚本。更好的方法是将其写入 you .travis.yml 文件的env部分。您的 tarball 的名称将始终是*package name+" _ "+package version+" . tar . gz "。在您的描述文件中,您定义了 PackageNamePackageVersion。我使用 CODECOV 来存储我的覆盖测试的结果。*

env:
    - PKG_TARBALL=RTest_1.2.3.1000.tar.gzafter_success:
      - tar -C .. -xf $PKG_TARBALL
      - xvfb-run Rscript -e 'covr::codecov(type=c("tests", "vignettes", "examples"))'

我在我的包中使用的设置包括了我所有的例子、插图和测试的代码覆盖率。要部署代码覆盖率的结果,您必须定义全局变量CODECOV_TOKEN。令牌可以在https://codecov.io/gh/<owner>/<repo>/settings下找到。你可以把它秘密地插入你的崔维斯电脑里。在https://travis-ci.org/<owner>/<repo>/settings内添加代币。环境变量部分为您秘密存储变量。

要使用工作服而不是代码罩,使用covr::coveralls功能并在您的环境中定义一个COVERALLS_TOKEN

构建并部署一个 pkgdown 页面到 github 页面

构建一个 pkgdown 页面对于记录您的代码非常有用。在我的 github 存储库中,我还托管了我的包 RTest 的 pkgdown 页面。你可以在这里找到页面:https://zappingseb.github.io/RTest/index.html

为了允许部署到 github 页面,我在 https://github.com///设置中激活了这个特性。你必须使用 gh-pages 分公司。如果您没有这样的分支,您需要创建它。

在. travis.yml 中,首先安装 pkgdown。

r_github_packages:
  - r-lib/pkgdown

你将不得不从你的包 tarball 建立页面。必须定义包 tarball 的名称。请参见章节代码覆盖率了解如何做到这一点。拆开 tarball 的包装后,您应该在rm -rf <PackageName>.Rcheck之前删除检查包装时留下的任何内容。

after_success:
      - tar -C .. -xf $PKG_TARBALL
      - rm -rf RTest.Rcheck
      - Rscript -e 'pkgdown::build_site()'

Rscript将在docs文件夹中生成网站。该文件夹必须部署在 github 页面上。

登录 github 后,首先进入https://github.com/settings/tokens。在那里,您必须创建一个具有public_reporepo范围的令牌。现在将这个令牌存储在您的 Travis CI 构建中。因此转到https://travis-ci.org/<owner>/<repo>/settings并将其存储为名为GITHUB_TOKEN的全局变量。现在,将使用以下脚本在每个成功的构建上部署网站:

deploy:
  - provider: pages
        skip-cleanup: true
        github-token: $GITHUB_TOKEN
        keep-history: false
        local-dir: docs
        on:
          branch: master

有关部署页面的更多信息,您可以查看第页的 Travis CI 指南。

ImageMagick 和 Travis CI

在 travis-ci 社区中,有一个关于如何在 travis-ci 上安装magick包的问题。答案很简单。您需要拥有 ImageMagick 的所有系统依赖项。通过以下方式为 Linux 安装这些软件:

addons:
   apt:
     update: true
     sources:
       - sourceline: 'ppa:opencpu/imagemagick'
       - sourceline: 'ppa:ubuntugis/ppa'
     packages:
       - libmagick++-dev
       - librsvg2-dev
       - libwebp-dev
       - libpoppler-cpp-dev
       - libtesseract-dev
       - libleptonica-dev
       - tesseract-ocr-eng
       - r-cran-rgdal
       - libfftw3-dev
       - cargo

这也适用于我的 macOS。

亲爱的读者:写我在持续集成方面的工作总是令人愉快的。感谢你一直读到这篇文章的结尾。如果你喜欢这篇文章,你可以在 或者在github上为它鼓掌。如有评论,请在此处或在我的LinkedIn个人资料http://linkedin.com/in/zappingseb.上留言

进一步阅读

  • 在 Travis CI(基础)上构建 R 项目
  • Travis CI 社区为 R (论坛)
  • RTest 包. travis.yml 文件
  • RTest 包—Travis-CI 的 99%代码覆盖率

在推特上搜索钓鱼信息

原文:https://towardsdatascience.com/trawling-twitter-for-trollish-tweets-6a6307f96453?source=collection_archive---------35-----------------------

Source: JNL — Troll of Nordic folklore turning to stone in the daylight

虚假信息是民主的最大威胁之一。假新闻、钓鱼和其他政治和社会颠覆性内容困扰着社会。社交媒体巨头在促成和培养这种行为方面发挥了作用。一些人甚至出现在美国国会和欧盟议会面前,承诺采取更多措施应对社交媒体上的虚假信息和仇恨言论的挑战。这些承诺中的一些已经花了将近一年时间,而 T2 仍然受到限制。

因此,当有机会在谷歌云平台(GCP)上创建一个生产机器学习(ML)系统的演示时,我欣然接受了创建一个 trolling tweet 检测器的机会。该演示要求在 GCP 上建立一个完整的项目结构,该结构将生成并部署一个定制的 ML 估计器到云 ML 引擎。

我本可以选择更“商业”的东西。然而,虚假信息识别的用例激励着我。虚假信息和仇恨言论的危害是真实的,我想在这个话题上发表自己的看法,尽管只是一小步。

在这篇文章中,我将重点关注特定于这个 trollish tweet 检测器的数据集和模型开发,在后续文章中,我将讨论使用 MLFlow 跟踪模型性能,以及使用 GCP 部署模型。之前,我写过关于 ProductionML 框架的文章,它在更广泛的架构层次上涵盖了这个主题,并呼吁在数据科学家和数据工程师之间架起一座桥梁。

在钓鱼数据集上进行训练和测试

收集数据

我使用的数据集是由 FiveThirtyEight 在他们的故事 中分享的推文集合,为什么我们要分享 300 万条俄罗斯巨魔推文

这就是 FiveThirtyEight 要说的:

FiveThirtyEight 于 2018 年 7 月 25 日从克莱姆森大学研究人员 传播学副教授达伦·林维尔 和经济学副教授 帕特里克·沃伦 处获得数据。他们在一个名为 Social Studio 的工具上使用定制搜索收集数据,该工具归 Salesforce 所有,并由克莱姆森的 社交媒体收听中心 签约使用...

...他的 目录 包含了近 300 万条推文的数据,这些推文是从连接到互联网研究机构、俄罗斯“巨魔工厂”和司法部于 2018 年 2 月提交的一份起诉书 中的一名被告 中发送的,作为特别顾问罗伯特·穆勒俄罗斯调查的一部分。这个数据库中的推文是在 2012 年 2 月至 2018 年 5 月之间发送的,其中绝大多数是在 2015 年至 2017 年发布的。

数据集是存储在 GitHub 存储库中的一系列 CSV 文件。我将它们下载到我的本地机器上,并使用 Python 的 Pandas 库将每个数据帧结合在一起。此时,我已经在一个统一的结构中拥有了完整的数据集,然后我将它存储在 BigQuery 中,再次使用 Pandas。

import os
import pandas as pd# Union
paths = [os.path.join("../data", x) for x in os.listdir("../data")]
cols = pd.read_csv(paths[0]).columns
df = pd.DataFrame(columns=cols) # roughly 3+ million recordsfor path in paths:
 df_tmp = pd.read_csv(path)
 df = pd.concat([df, df_tmp])# Store in BigQuery
df.to_gbq(
 destination_table="dataset.table_name"
 , project_id=project_id
 , chunksize=None
 , verbose=None
 , reauth=False
 , if_exists='fail'
 , private_key=None
 , auth_local_webserver=False
 , table_schema=table_schema
)

我在下游使用的关键特性是account_categorycontent字段。然而,获得完整的数据集,然后通过 BigQuery 视图,根据需要进行转换,以确保您可以在将来需要时利用更多功能,这始终是一种好的做法。视图,如果您不知道,就不要创建新表——不会存储任何新内容,也不会产生新的存储成本。简单地说,视图是保存到需要时的查询。

阶级不平衡

在阅读了关于数据集的文档并做了初步的探索性数据分析(EDA)后,我得出结论,需要解决一些与类不平衡相关的挑战。

首先,在account_category下有八个等级或类别。所有这些都来自被怀疑或确认与互联网研究机构(IRA)有关的句柄,因此没有一个是非巨魔,而是与 IRA 有关的各种类型的巨魔。

以下是这些类以及与每个类相关的一些内容示例:

RightTroll

  • “我们有一位在任的民主党参议员因腐败接受审判,而你几乎没有听到主流媒体的一点声音。”~ @nedryun
  • Marshawn Lynch 穿着反特朗普的衬衫参加比赛。从他下垂的裤子来看,衬衫上应该写着林奇对贝尔特
  • 倒下的海军水手的女儿提供了强大的颂歌抗议独白,燃烧她的 NFL 包装工齿轮。#抵制 NFL
  • 刚刚消息:特朗普总统将总统杯高尔夫锦标赛奖杯献给佛罗里达州、德克萨斯州和波多黎各的人民。
  • 一万九千尊重我们的国歌!#StandForOurAnthem🇺🇸

非英语

  • Причина #67 Мутко: «Зенит-Арене» для адаптации к ЧМ потребуется 1,5–2 млрд рублей
  • Причина #70 Житель Самары умер в очереди в поликлинике
  • Причина #74 Президентский советник предложил ограничить Интернет, как в Китае
  • Причина #75 Казаков благословили на защиту интернет-пространства
  • Причина #77 В Кстово полицейские сломали женщине лицевую кость, когда та отказалась показать грудь

恐惧使者

  • 食物中毒不是玩笑!#沃尔玛#科奇农场

  • 感谢上帝,我几天前吃的#火鸡很好吃。#科赫农场
  • 我很容易受伤,我只是不表现出来。你可以伤害别人却不自知。
  • 金和坎耶的婚礼
  • 谁的妆最差,别告诉我,魔镜

LeftTroll

  • blacklivesmatter # BLM # equality # equal rights

  • @big_gun_in_utah 所以?如果你交更多的税,你就有更多的权利?“这就是它的工作原理,”
  • @犹他州的 big_gun_in_utah 有人吗?
  • 黑人学生迫使大学放弃私人监狱 2500 万美元#blacktwitter
  • 种族主义的缅因州州长在“毒品问题”上#种族主义渣滓#白痴

未知

  • 我的牙医让他的助手吸(我嘴里的水),但我以为他在跟我说话,所以我吸了他的手指。我很羞愧
  • 48.“我不吃水牛”
  • 新闻史上最伟大的台词
  • 从没在这么短的时间内见过这么多的面部表情
  • 我不敢相信奶牛是整个宇宙中最可爱、最完美的动物:-)不

HashtagGamer

  • 本周由@googlygirl98 主持的@GooglyTags 是# ItWasJustThatOneTime
  • 总统自己政党的参议员花在询问总统可能行为不端的情况上的时间似乎异常多。
  • 今天将变得伟大因为我选择不在乎任何人说什么或做什么!!这是我的生活,我为自己而活。

  • 说真的,如果塞申斯追求色情,特朗普将永远失去动画纳粹
  • 今天会很棒,因为我有酒

新闻提要

  • 阿尔伯克基男子因试图出售偷来的枪支零件被捕
  • 阿尔伯克基口袋妖怪 Go 玩家在这里停留和回馈
  • 英国女王伊丽莎白二世因“重感冒”错过了教堂
  • 新任联合国秘书长敦促新年决议:“把和平放在第一位”
  • 中国表示将在 2017 年底停止象牙贸易

商业

  • APA 风格研究论文写作指南
  • 为什么教室过敏最严重
  • 下周别来上课了,我要生病了。史上最伟大的大学教授
  • 脸书的 15 个白痴被叫了出来

幸运的是,我的一个同事一直在挖掘推文——其中许多来自经过验证的 Twitter 账户。所以,我从那些经过验证的账户中提取了推文,并用它们作为非钓鱼者的代理。“已验证”成为 account_category 中的第九个类别。

我们遇到的与类相关的第二个挑战是数据集作为一个整体是不平衡的。每节课的内容量差异很大;有几门课的音量低得令人痛苦。

为了快速有效地处理这个问题,我们做了两件事:

  1. 删除了非常低的账户类别-非英语、散布谣言者和未知
  2. 开发了 train_test_split.py 来拆分和平衡我们的数据集

数据集的平衡通过以下 BigQuery 视图解决:

SELECT * FROM (SELECT * FROM (SELECT account_category, content FROM `project_id.ira_russian_troll_tweets.trans_source_unioned_with_verified_view` WHERE account_category = 'Verified' ORDER BY rand() LIMIT 90000)UNION ALLSELECT * FROM (SELECT account_category, content FROM `project_id.ira_russian_troll_tweets.trans_source_unioned_with_verified_view` WHERE account_category = 'Commercial' ORDER BY rand() LIMIT 90000)UNION ALLSELECT * FROM (SELECT account_category, content FROM `project_id.ira_russian_troll_tweets.trans_source_unioned_with_verified_view` WHERE account_category = 'LeftTroll' ORDER BY rand() LIMIT 90000)UNION ALLSELECT * FROM (SELECT account_category, content FROM `project_id.ira_russian_troll_tweets.trans_source_unioned_with_verified_view` WHERE account_category = 'RightTroll' ORDER BY rand() LIMIT 90000)UNION ALLSELECT * FROM (SELECT account_category, content FROM `project_id.ira_russian_troll_tweets.trans_source_unioned_with_verified_view` WHERE account_category = 'HashtagGamer' ORDER BY rand() LIMIT 90000)UNION ALLSELECT * FROM (SELECT account_category, content FROM `project_id.ira_russian_troll_tweets.trans_source_unioned_with_verified_view` WHERE account_category = 'NewsFeed' ORDER BY rand() LIMIT 90000))ORDER BY rand()

train_test_split.py 脚本用于创建该视图。此外,该脚本使用 trans_balanced_view(即 transform 中的 trans)来开发一个数据帧,随后将其拆分为 train 和 test 表。

训练-测试划分为 80/20——80%的数据用于训练,20%用于测试。在训练和测试子数据集中,跨“帐户类别”的数据分布应该保持相等。

ML 管道

sci kit-学习管道

对于机器学习模型,我选择使用 Scikit-learn。我做出这个选择很大程度上是出于重用我已经开发的东西的愿望——如果你只想证明汽车是向前行驶的,那么再造轮子又有什么意义呢?

对于那些不知道的人,Scikit-learn 中的管道允许特征提取器(例如计数或 TF-IDF 矢量器)和 ML 估计器的耦合。换句话说,我能够将矢量器(一种将文本转换为有意义的数字数组的方法)与决策树分类器(一种非常简单的预测目标特征类别的学习方法)连接起来。这帮助我自动化了每次运行所需的数据建模。此外,这允许我使用整个文本(例如一条 tweet)作为输入,而不是整个文本的矢量形式。

虽然将特征提取器与监督学习模型链接在一起相对简单,但它有效地展示了如何以简洁的方式从原始数据输入到预测。

pipeline = Pipeline(
 [
 ("vectorizer", vectorizers[vectorizer])
 ,(model, models[model][0])
 ]
)grid_search_cv = GridSearchCV(
 estimator=pipline
 , param_grid=models[model][1]
 , scoring=None
 , fit_params=None
 , n_jobs=1
 , iid=True
 , refit=True
 , cv=2
 , verbose=0
 , pre_dispatch='2*n_jobs'
 , error_score='raise'
)

网格搜索

任何好的 ML 系统的一个关键方面是超参数调整。通过这种方法,不仅可以选择最佳的统计模型,还可以选择最佳的特征提取器(至少在 Scikit-Learn 中)。

在这个项目中,我选择了使用 Gridsearch,这是公认的非常暴力的方法。也就是说,Gridsearch 很容易理解并被广泛使用。它基于所有允许的参数评估模型的所有排列的性能。

请参见下面的示例,了解如何限制或扩展我为 Gridsearch 提供的参数选项(如矢量器 __ngram_range 或‘DTC _ model _ _ criteria’)。

vectorizer_params = {
 "vectorizer__ngram_range": [(1,1), (2,2)]
 , "vectorizer__stop_words": [None] 
}count_vectorizer = CountVectorizer()
tfidf_vectorizer = TfidfVectorizer()vectorizers = {
 "count_vectorizer": count_vectorizer
 , "tfidf_vectorizer": tfidf_vectorizer
}# Statistical Model
splitter = ['best', 'random']
min_impurity_decrease = [0.0, 0.8]
max_leaf_nodes = [None, 5]
min_samples_leaf = [1, 5]
min_samples_split = [2, 5]
min_weight_fraction_leaf = [0.0, 0.50]
criterion = ['entropy', 'gini']
random_state = [None, 42]
max_features = [None, 'auto']
max_depth = [None, 5]
class_weight = [None]dtc_param = {
 'dtc_model__splitter': splitter
 , 'dtc_model__min_impurity_decrease': min_impurity_decrease
 , 'dtc_model__max_leaf_nodes': max_leaf_nodes
 , 'dtc_model__min_samples_leaf': min_samples_leaf
 , 'dtc_model__min_samples_split': min_samples_split
 , 'dtc_model__min_weight_fraction_leaf': min_weight_fraction_leaf
 , 'dtc_model__criterion': criterion #
 , 'dtc_model__random_state': random_state
 , 'dtc_model__max_features': max_features
 , 'dtc_model__max_depth': max_depth
 , 'dtc_model__class_weight': class_weight
}for key in vectorizer_params.keys():
 dtc_param[key] = vectorizer_params[key]

从上面的代码中,我向参数字典中添加了矢量器和 ML 模型参数。这允许我们使用作为特征提取的一部分的参数来调整我们的估计器,这可能对估计器的最佳性能有重大影响。

现状核实

重要的是退一步。正如你所看到的,这是一个模型的基础,可以检测一个给定的推文可能属于哪个类别;训练数据集中过去推文的相似词汇和词频有助于建立一个模型,将新推文与该类别或类别相关联。

使用词汇的频率作为特征意味着这个模型仅限于照亮与过去的推文相似的推文。因此,产生的 ML 模型肯定需要与其他模型一起使用来识别单个的巨魔。结合预测其他方面的模型,如病毒范围、辱骂性语言或仇恨图像,可以帮助识别个体巨魔。

研究人员和社交媒体公司正在研究的策略中可以看到这种混合方法。在一项名为自动处理虚假信息的研究中,欧洲议会研究服务(EPRS)详细说明了导致虚假信息传播的因素,并探索了处理虚假信息的可能技术方法。我做的这个小项目很可能符合第 3.2 节中描述的工作。检测计算放大和假账 (p33)。

如果你对跟踪和解决虚假信息的话题以及更广泛的内容监控话题感兴趣,以下内容可能值得一读:

  • 乔希·拉塞尔
  • 社交机器人传播低可信度内容
  • 全球反误导行动指南
  • 不可能的工作:脸书努力调和 20 亿人口的内幕

下一步是什么?

好,我有一个模型。那又怎样!

一个 ML 模型不是生活在一个静态的环境中。这个项目就是一个完美的例子。政治和文化的变化。人们在推特上谈论的变化。必须对模型进行再培训,使其准确、相关、可持续和负责任。

那么,如果我把这个模型投入生产,会是什么样子呢?我们如何快速再培训?我们如何跟踪模型性能以确保寿命?我们如何部署到最终用户可以通过 API 访问的源?

我将在下一篇文章中解决这些问题。敬请关注。

喜欢你读的吗?在 Medium 或 LinkedIn 上关注我。

本文原载于 Servian:云和数据专业人士

根据你的自然语言处理任务不同对待否定停用词

原文:https://towardsdatascience.com/treat-negation-stopwords-differently-according-to-your-nlp-task-e5a59ab7c91f?source=collection_archive---------6-----------------------

否定词(not,nor,never)在 NLTK,spacy 和 sklearn 中都被认为是停用词,但我们应该根据 NLP 任务的不同给予不同的注意

Photo by Jose Aragones on Unsplash

最近我在做一个关系抽取(RE)项目。但是我注意到一些流行的 NLP 工具,NLTK,spacy 和 sklearn,都把否定词当做停用词。如果我将这些否定词作为停用词删除,这将对检测两个实体之间的真实关系产生不良影响。所以我写这篇文章是为了那些遇到同样问题的人。

什么是停用词?

在计算中, 停用词 是在处理自然语言数据(文本)之前或之后过滤掉的词。停用词通常是语言中最常见的词。

我们可以看到这个定义是从统计学的角度来看的。但是在某些自然语言处理任务中,对于否定词的识别是有限的。

为什么要区别对待否定词?

在 RE 任务中,两个实体之间的【SDP】最短依赖路径,被证明可以有效地提取出识别两个实体之间关系的最重要信息。

下面是我从论文中选取的一个例子:修剪后的依赖树上的图卷积改进了关系提取。

在这个例子中,SDP 是['he', 'relative', 'Cane', 'Mike']。预测关系为per:other_family。但真正的标签是no_relation。因为not不在 SDP 中,not表示heCane Mike之间没有关系。

我们可以看到not是一个重要的上下文词,它直接影响对两个实体之间关系的判断。我们不能只删除not作为正常的停用词。

如何看待不同 NLP 任务中的否定词?

这取决于我们想要解决什么样的 NLP 任务。如果你的项目很小,你只需要统计功能,像词袋,tf-idf,你可以删除否定词作为停用词。

如果你的 NLP 任务是与上下文相关的,例如,情感分析,我们应该保留否定词。我建议根据 NLP 任务定制一个停用词列表。Twitter 否定语料库就是一个例子。本文中给出了对该方法的解释

如果你的 NLP 任务是高度上下文相关的,我推荐使用 ELMo、ULMFiT、BERT、XLNet 等上下文相关模型。在这种模型中,所有停用词都被保留以提供足够的上下文信息。

查看我的其他帖子 中等 一分类查看
GitHub:
bramble Xu LinkedIn:徐亮 博客:bramble Xu

参考

  • 如何用 spaCy 和 StanfordNLP 找到最短依赖路径
  • 修剪后的依赖树上的图形卷积改进了关系提取
  • Twitter 情感分析的否定范围检测
  • https://data science . stack exchange . com/questions/15765/NLP-why-is-not-a-stop-word

数据科学中的树

原文:https://towardsdatascience.com/trees-in-data-science-dcd9830cbfcf?source=collection_archive---------28-----------------------

在简单的决策树中导航,引导/打包,最终形成随机森林模型

机器学习中最容易解释的模型之一是 CART(分类和回归树),俗称决策树。在这篇文章中,我希望给出一个决策树的概述,一些围绕决策树的基本概念,最后是随机森林。内容如下

  • 理解决策树
  • 纯洁
  • 自举和打包
  • 随机森林

我们走吧!

决策树

Basic structure of a Decision Tree (Source: cway-quan)

在机器学习宇宙中,树实际上是真实树的颠倒版本。假设我们有一个由特征‘X’和目标‘Y’组成的数据集。决策树所做的是在 X 中寻找模式,并基于这些模式将数据集分割成更小的子集。

在上面略加简化的图像中想象这些分裂。这是一份工作是否被接受的问题。“X”包含“通勤时间”、“薪水”、“免费咖啡”等特征。

基于“X”中的模式,该树被分成分支,直到它到达到达“Y”的纯答案的点。在我们的场景中,被接受的工作机会必须提供超过 50k 的薪水,通勤时间< 1hr and free coffee. In this manner the tree reaches the last leaf which is a pure decision about ‘Y’.

决策树中的纯度

决策树根据节点的纯度进行分裂。这种纯度是基于“Y”的分布来测量的。如果我们的“Y”是连续的,我们的问题是一个回归问题,节点是基于 MSE(均方误差)分裂的。如果“Y”是离散的,我们的模型正在处理一个分类问题,需要不同的纯度测量。

在分类案例中,广泛使用的衡量标准是基尼系数。基尼系数的公式如下:

Source: General Assembly DSI curriculum (Authors:David Yerrington, Matt Brems)

当决定在给定的节点上进行哪个分裂时,它挑选从父节点到子节点的基尼不纯度下降最大的分裂。

自举和打包

要理解 bootstrapping 和 bagging,第一步是理解为什么首先需要它们。它基本上是试图模仿“群体的智慧”原则,即多个模型的综合结果优于单个模型的结果。下面这张由 Lorna Yen 拍摄的图片给出了一个关于系鞋带的好主意。

(Author: Lorna yen, Source)

如上所示的自举只是对数据进行随机采样,并进行替换。Bagging 只是在这些样本中的每一个上构建决策树并获得总体预测的过程。概括来说,装袋包括以下步骤:

  1. 从大小为 n 的原始数据,用替换引导 k 个大小为 n 的样本
  2. 在每个引导样本上构建一个决策树。
  3. 通过所有采油树传递测试数据,并开发一个综合预测

Bagging 因此也被称为自举聚合

随机森林模型

仔细观察下面的图片,你会对随机森林有一个基本的直觉。

Source: globalsoftwaresupport.com, (link)

bagging 的一个基本障碍是各个决策树高度相关,因为所有的树都使用相同的特征。所以我们模型的预测受到方差问题的困扰。要了解更多关于方差或偏差的信息,您可以阅读此链接。去相关我们的模型是一个解决方案,这正是随机森林所做的。

随机森林在 bagging 中遵循类似的步骤,除了它们在学习过程中的每个分裂处使用特征的随机子集。这减轻了装袋中的差异问题,并且通常产生更好的结果。这种有效而简单的方法使随机森林成为广泛实施的机器学习模型。

奖金

用于在 sklearn 中导入解释的三个分类模型的代码。

#Import for decision trees
**from** **sklearn.tree** **import** DecisionTreeClassifier#Import for bagging
**from** **sklearn.ensemble** **import** BaggingClassifier#Import for random Forests
**from** **sklearn.ensemble** **import** RandomForestClassifier 

本周热门人工智能项目 44-19

原文:https://towardsdatascience.com/trending-ai-projects-of-the-week-44-19-1fb4085edf59?source=collection_archive---------36-----------------------

关注我,这样你就不会错过伟大的人工智能项目。

这里有几个你可能会感兴趣的链接:

- [Labeling and Data Engineering for Conversational AI and Analytics](https://www.humanfirst.ai/)- [Data Science for Business Leaders](https://imp.i115008.net/c/2402645/880006/11298) [Course]- [Intro to Machine Learning with PyTorch](https://imp.i115008.net/c/2402645/788201/11298) [Course]- [Become a Growth Product Manager](https://imp.i115008.net/c/2402645/803127/11298) [Course]- [Deep Learning (Adaptive Computation and ML series)](https://amzn.to/3ncTG7D) [Ebook]- [Free skill tests for Data Scientists & Machine Learning Engineers](https://aigents.co/skills)

上面的一些链接是附属链接,如果你通过它们进行购买,我会赚取佣金。请记住,我链接课程是因为它们的质量,而不是因为我从你的购买中获得的佣金。

你只看系数

yolact 是一个简单的、完全卷积的实时实例分割模型,其任务是检测和描绘图像中出现的每个不同的感兴趣对象。这是用于显著更快(比任何以前的竞争方法)实例分割的开源代码。

细流

Streamlit 让你用看似简单的 Python 脚本为你的机器学习项目创建应用。它支持热重新加载,因此当您编辑和保存文件时,您的应用程序会实时更新。不需要弄乱 HTTP 请求、HTML、JavaScript 等。你所需要的只是你最喜欢的编辑器和浏览器。

Streamlit 演示项目让你浏览整个 Udacity 自动驾驶汽车数据集并实时运行推理。

PyTorch 示例

展示深度学习库 PyTorch 使用示例的优秀知识库:

  • 使用 Convnets 的图像分类(MNIST)
  • 使用 LSTM RNNs 的单词级语言建模
  • 用残差网络训练 Imagenet 分类器
  • 生成对抗网络(DCGAN)
  • 变型自动编码器

数据-科学-ipython-笔记本

数据科学 Python 笔记本深度学习(TensorFlow,Theano,Caffe,Keras),scikit-learn,Kaggle,大数据(Spark,Hadoop MapReduce,HDFS),matplotlib,pandas,NumPy,SciPy,Python essentials,AWS,各种命令行。

pwnagotchi

不同于像大多数基于强化学习的人工智能那样仅仅玩超级马里奥或雅达利游戏, Pwnagotchi 随着时间的推移调整其参数,以便在你暴露的环境中更好地控制 WiFi。更具体地说,Pwnagotchi 正在使用一个带有 MLP 特征提取器的 LSTM 作为其针对 A2C 代理的策略网络。如果你对 A2C 不熟悉,这里有一个非常好的介绍性解释(以漫画的形式!)Pwnagotchi 如何学习背后的基本原则。

在你走之前

在 Twitter 上关注我,在那里我定期发布关于数据科学和机器学习的消息。

Photo by Courtney Hedger on Unsplash

O'Reilly Media 首席数据科学家的数据科学趋势

原文:https://towardsdatascience.com/trends-in-data-science-with-oreilly-media-s-chief-data-scientist-do-n-f89353d6ca17?source=collection_archive---------27-----------------------

苹果 | 谷歌 | SPOTIFY | 其他 | 剪辑

本·洛里卡在 TDS 播客

编者按:这是迈向数据科学播客“攀登数据科学阶梯”系列的第九集,由 Jeremie Harris、Edouard Harris 和 Russell Pollari 主持。他们一起经营一家名为sharpes minds的数据科学导师创业公司。可以听下面的播客:

当我开始读研时,数据科学才刚刚成为一件事。当时,你只需要与熊猫和 sklearn 合作几个 jupyter 笔记本项目,就能获得一些最赚钱的技术工作。到 2016 年我退学的时候,这还不够——雇主已经在代码质量方面提出了更高的要求。如今,公司不仅在寻找擅长编码、统计和机器学习的人,也在寻找优秀的软件工程师。

向模型部署、工程和构建“有用的东西”发展的趋势只是目前成熟的数据科学世界发展的最新一步。不过,这几乎肯定不会是最后一个,保持数据科学曲线的领先意味着密切关注即将到来的趋势。这就是为什么我们邀请奥莱利媒体的首席数据科学家本·洛里卡加入我们的播客。

Ben 不仅对数据科学世界有着一英里高的视野(他为十几家初创公司提供建议,并组织了多次世界级会议),而且他的视角跨越了数据科学发展的二十年。他已经看到了趋势是如何来来去去的,并且一直站在这个领域的顶端。以下是我们从聊天中获得的最大收获:

  • 数据科学领域的最新转变是强调将模型投入生产。了解如何使用 Docker、Git、AWS/GCP 或其他云计算平台等工具,甚至 Flask 等 web 框架变得越来越重要,甚至令人期待。
  • 数据科学家是专业的自动化人员:他们的全部工作是自动化决策过程,而以前这些决策过程是由人类来完成的。因此,随着该领域每一轮创新浪潮的到来,数据科学任务往往是最先实现自动化的任务,因为数据科学家一直在关注这些任务。这就是为什么数据科学的角色变化如此之快:它们不断地被自动化,让数据科学家有更多的时间在越来越高的抽象层次上思考。
  • 这听起来很老套,但最后一点的一个结果是,软技能(沟通和同理心)在今天是成败的关键,并且在未来变得更加重要。随着数据科学家在超参数调整或模型选择等繁琐任务上花费的时间减少,他们有越来越多的时间从全局角度思考。然后,确定业务和产品开发的优先顺序变得越来越重要,如果没有与用户和客户交谈所需的沟通技巧,以及在自己的公司内倡导具体的行动方针,你就无法做到这两点。
  • 全面发展可能是一个巨大的优势,并有望在未来成为一个越来越具有决定性的优势。在上一集乔治·海沃德的节目中,我们看到了即使是法律学位也可以在数据科学角色中发挥重要作用,本的观点是,这种知识广度不仅对个人层面很重要,对团队层面也很重要。随着经理和副总裁越来越多地从不同背景中寻找人才,推销你独特的故事和观点的能力将变得越来越重要。

你可以通过本·洛里卡的账号@bigdata 在 Twitter 和 Medium 上关注他,并查看他帮助运行和组织的 O'Reilly 数据科学会议。

TDS 播客—剪辑

如果你在推特上,随时欢迎和我联系 @jeremiecharris !

人工智能的分类:医院入院分类的机器学习方法

原文:https://towardsdatascience.com/triage-to-ai-a-machine-learning-approach-to-hospital-admissions-classification-7d3a8d5df631?source=collection_archive---------17-----------------------

Photo by Arseny Togulev on Unsplash

简史

你曾经不得不在急诊室等很长时间吗?想知道为什么那个断了脚趾的家伙比你先被征召?这是伤检分类。分诊是医疗提供者根据资源可用性和患者需求对入院患者进行分类的过程。现在让我们后退一点。这个分类是什么东西?triage 这个词来自法语单词“trier”,意思是“分类”。大约在 1792 年,这个英俊的家伙(下图)是拿破仑帝国卫队的外科医生。

在受伤士兵对一些装备不良的医生的持续轰炸后,多米尼克·让·拉雷男爵(多好的名字)想“嘿伙计们。我认为有更好的方法。”因此,最初的伤检分类形式诞生了,法国人“称赞[拉雷]设计了一辆飞行救护车。”

Larrey 实施的灾难救援形式的分流包括在新来的病人身上贴上标签,标签上有颜色和文字,标明类别,如“死亡”、“立即”、“轻微”等。这使得当时的医疗提供者能够快速地优先考虑和分配资源给那些在给定时间内受益最大的患者。今天的急诊室仍然使用一种基于此的分类形式,但是,使用 1-5 的等级来代替彩色标签。

问题是

好吧…为什么我要让你经历这个分类历史?我相信了解一个系统的背景是开始迭代和改进的最好方法。还有什么比计算机更好的方法来迭代排序问题呢?**咳二分搜索法冒泡排序合并排序如果我们可以使用一种算法来为我们的患者进行优先排序,而不是花费时间来生成一个甚至可能在提供商之间不一致的评级,会怎么样?嗯……好在我们是数据科学家!

为了简化这个问题,我将把重点放在住院患者(那些需要过夜并需要许多资源的患者)和临时患者(那些将在一天内离开并需要较少资源的患者)之间的区别上。与 Larrey 提出的粒度化方法相反,我对此的理由有两点:

  1. 这些组是不同的,因此该算法将更加可靠和准确
  2. 包括平均住院时间和总医院运营成本,每个住院病人的费用可能高达 6000 美元。这表明医院资源的负担比那些住院几个小时的病人要大得多。

因为有两个目标条件要预测,所以这是一个二元结局的分类问题(1:录取;0:未录取)。

数据

我用来训练这个分类器的数据来自于韩国两家医院的分类研究。在其原始状态下,大约有 1200 行和 24 个特征。原始特征的子集如下:

清洁和特征工程

这些数据相当混乱,有一些常见的疑点:空值、奇怪的标注、不相关的特征、不均匀的分布等等。我采取了一些步骤来清理数据并为建模做准备:

  1. 删除了对该分析没有帮助的特征。
  2. 空值的估算中值
  3. 将离散的、不一致的特征归入更广泛的类别。
  4. 为分类特征创建虚拟变量
  5. 根据数据集中名为“处置”的原始要素构建预测要素(y)。这表明患者在评估后去了哪里。我把像“入院”这样的事情归类为入院,而像“出院”这样的事情则不属于入院。

干净的数据框(带有虚拟对象)如下所示:

该模型的最终特征分组如下。它们被从急诊室进入时的问卷中获取的数据和由护士测量的生命体征分开。

目标(承认与不承认)是不平衡的(我们将在后面处理这个问题):

建模

在深入建模之前,我们先来谈谈指标。我将使用两个重要分类指标的加权分数(称为 Fbeta):精确度和召回率。精度表示我的实际结果中的真阳性。这就是,在我预测的所有入院中,我预测的入院患者中实际上没有入院(假阳性)的比例是多少?回忆从我的预测结果中描述了我真正的积极因素。这是,在我预测的所有事情中,我错过录取(假阴性)的比例是多少?如果我的精度较低,我可能会过度分配资源,因为我预测的入院病人比实际的多。然而,低回忆率可能意味着我错过了应该住院的病人。回忆对我来说更重要,因为我宁愿过度分配资源,也不愿分配不足。为了优先考虑召回,同时也确保我不会过度分配资源,我更倾向于召回来衡量我的 beta 值,以严厉惩罚召回率低的模型。下面是我生成的一个混淆矩阵的例子:

Confused?

看到左下角有生命、宇宙和一切的答案了吗?那些是我的假阴性。这个数字越大,越多我认为不会被录取的人被录取了,这让我很吃惊。突然间,我毫无准备,没有床位和资源来安置他们。我想尽可能多的把它们移到右边。

好的。现在我们知道测量什么了。继续下一个问题。还记得我们那个讨厌的阶级不平衡问题吗?事实证明,大部分通过急诊室的人都将在一天结束时被治愈出院。被接纳的类别代表一个较小的子集。我决定使用一些不同的方法对少数类进行上采样,包括随机过采样、ADASYN 和 SMOTE。通过分析各种模型的 ROC 曲线,我最终选定了随机过采样。下面是我用随机过采样、kfold 交叉验证和均值 FBeta 作为度量考虑的模型。

在这种情况下,逻辑回归似乎是赢家(FBeta 为 0.65)。除了高 FBeta 之外,逻辑回归也是一个不错的选择,因为我将能够解释这些特征。下面是系数大小的曲线图。

Just don’t get old I guess?

虽然我真的不需要知道特征对预测能力的重要性,但展示一点洞察力是很好的。上面的模型没有提供任何关于分类分数的提示。为什么?这是故意的。如果我们给了我们的模型答案,我们如何自动分类?然而,我确实想看看在给定这些信息的情况下,性能会如何变化。不出所料,这个模型变得更好了。0.68 的 FBeta 可以通过指示患者严重性的某个等级 1-5 来实现。

所以。机器学习很棒。模型很棒。非常好。分诊机器人在哪里?我们可以称他为 BOTriage(工作进展中)。总之… 这里的是我创建的模拟自动分诊的示例应用程序:

For dramatic effect, you can look at how much time could be wasted manually assessing triage

The prediction page (BOTriage) offering “Admitted” or “Not Admitted” and the percent strength of prediction.

那都是乡亲们!感谢收听,至少如果将来有人问你关于分流的问题,你可以向他们推荐“那个发明了飞行救护车的法国人”。如果你有兴趣了解这个项目的更多信息,可以在我的 GitHub 上找到代码,或者你可以在这里联系我。

资源

  1. 分流历史:https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2564046/
  2. 住院费用:https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3303656/

在 10 分钟或更短时间内搞定你的终端

原文:https://towardsdatascience.com/trick-out-your-terminal-in-10-minutes-or-less-ba1e0177b7df?source=collection_archive---------3-----------------------

如何在短短几分钟内打造一个更好、更快、更强、更性感的终端

Image by khamkhor from Pixabay

你盯着终端的时间不一定是痛苦的。

几乎不需要时间或努力,你就可以把你的终端从一个令人沮丧的白色痛苦的地方变成一个漂亮、快速、有趣、易于使用的电源座。

GIF via GIPHY

终端是一个不可思议的工具。这是一个神奇的盒子,从这里你可以运行你的世界。为什么要浪费更多的时间去使用那些让你不那么兴奋的东西呢?

当你第一次开始你的编码之旅时,你会很快意识到你会花很多时间在终端上。你可能想从事程序员或开发人员的工作,或者你可能对人工智能、机器学习、数据科学或任何其他职业感兴趣。无论你走哪条路,花几分钟时间,放松一下,让你的终端成为一个快乐的地方都是一个好主意。

如果你使用的是苹果电脑,刚接触编程,并且完全不喜欢那种空白的感觉,那么这款适合你。

Photo by Nicola Gypsicola on Unsplash

预装的 Mac 终端

如果你有一台 Mac,你有一个终端窗口。万岁!但是,即使进行了一些基本的定制,这可能也不是您一天中的大部分时间所希望看到的:

它在那里,它工作,这是伟大的。但是几乎不费吹灰之力,你就可以把你的终端变成你会兴奋地玩的东西。会让你的生活变得更轻松的东西。

终端与 iTerm

不一定要用终端!有一个名为 iTerm 的终端得到了极大的改进,它更加可定制,并且有许多很酷的功能。你可以搜索一下。您可以拆分窗格。你有各种各样的选择,这些选择可能是你从未考虑过的。

此外,你可以让它变得非常性感,而且几乎不费吹灰之力就能轻松完成!

只需前往官方网站,然后点击“下载”这个大按钮。下载后,打开它并安装它,就像你做任何事情一样。(如果你感兴趣,你可以在这里找到 iTerm3 的下载链接。)

您将从如下所示的终端窗口开始:

我们才刚刚开始。

关闭登录

你可能不太喜欢打开终端时弹出的“上次登录”消息。通过在您的终端中运行这个简单的命令来摆脱它:

touch ~/.hushlogin

抓取一些甜蜜的下载

重要的是要意识到在你的改变生效之前,你可能需要关闭并重新打开你的终端。

如果您没有看到您的修改,请关闭您的终端窗口并打开一个新窗口。

自制

家酿啤酒是你武器库中的一个好东西。他们称自己为“macOS 缺失的软件包管理器”,他们不是在开玩笑。他们安装你需要的东西,而苹果没有为你安装。

你可以通过运行

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

它会暂停并告诉你它正在安装什么。这东西非常有用,我怎么推荐都不为过。家酿啤酒是救星。

Zsh

默认的 shell 是 bash,如果您想保留它,这很好。但是 Zsh 更加可定制,并且以速度更快而闻名。Zsh 做的最酷的事情之一就是自动完成。任何时候你都可以输入类似“git c”的东西,然后按 tab 键,你就会得到一个可爱的小帮助窗口,里面有自动完成的建议。

此外,Zsh 有一些非常好的插件,你真的不想错过。它预装在 Mac 上,但版本似乎总是过时,所以您会想运行:

brew install zsh

Oh-My-Zsh

你喜欢 Zsh 吗?你需要得到 Oh-My-Zsh !这是一个用于管理你的 Zsh 配置的开源框架,它有数以千计令人敬畏的助手和函数、插件和主题。您可以通过运行以下命令下载它

sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

插件

你可以在这里找到官方插件的完整列表。他们随时准备出发。您只需将它们添加到您的~/中即可启用它们。zshrc 文件。(留在这里陪我。比听起来容易!)

要想知道你能立即得到什么,请访问插件网站。向下滚动,看看所有你几乎不费吹灰之力就能安装的插件。你可能想添加 Git、GitHub、Python、Sublime、VSCode 或其他任何看起来会让你的生活更轻松的东西。

你肯定要 z。

添加插件非常容易,但是如果你是终端新手,这些说明可能没有意义。当您想要进行这样的更改时,您需要编辑您的~/。zshrc 文件。这听起来很复杂,但实际上并不复杂!要打开该文件,请运行

open ~/.zshrc

这将打开您需要进行更改的文本文件。请务必尊重这份文件。改变这里的某些东西能够而且将会对事情的运作方式(以及是否)产生重大影响。

当你浏览这个文件时,你会看到一些东西,如果你想改变它们,你可以取消注释。您还会看到可以添加您自己的修改的空间。

想要添加或删除插件?向下滚动到这一部分:

# Which plugins would you like to load?
# Standard plugins can be found in ~/.oh-my-zsh/plugins/*
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(git)

好像他们想让这一切变得简单!

现在添加任何你想使用的插件。例如,您可能希望将最后一行改为

plugins=(git z github history osx pip pyenv pylint python sublime vscode)

保存它,你就可以走了!

语法突出显示

您希望突出显示 Zsh 语法。它会告诉你,如果你的命令有效,甚至在你运行它之前。很方便。

要启用语法突出显示,请运行

cd ~/.oh-my-zsh && git clone git://github.com/zsh-users/zsh-syntax-highlighting.gitecho "source ${(q-)PWD}/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" >> ${ZDOTDIR:-$HOME}/.zshrc

然后通过运行以下命令启用它

source ~/.oh-my-zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

重新启动您的终端以使您的更改生效。

Z

爱 Z 爱爱爱 Z!z 更上一层楼。它让终端生活变得如此之快!要安装它,请运行

brew install z

(希望你的插件中包含了 Z。)

z 很牛逼。z 很聪明。如果您经常键入类似以下的内容:

cd this/is/the/path/to/the_file/ThisOne

现在,您将能够键入:

z thisone

你在那里!你需要做一段时间你正常的事情,而 Z 找出你喜欢做什么,然后你就可以去比赛了。

假设你总是去你的“回购”文件夹。从任何地方输入cd repos都不会起作用。

但是现在你只需输入z repos就可以从任何地方直接跳转到它!

崇高的文字

如果你使用 Sublime Text 作为你的主要文本编辑器,你可以通过设置 Sublime 快捷方式让你的生活变得无比简单。这样,任何时候你想用 Sublime 打开一个文件(或者创建一个新文件并用 Sublime 打开它),你都可以使用命令subl

如果您想在 Sublime 中创建和打开一个名为“test.txt”的新文件,您可以输入

subl test.txt

这将打开 Sublime 并创建一个名为“test.txt”的全新文本文件

我在这里找到了在装有 Zsh 的 Mac 上运行这个功能的最简单方法。首先确保你已经安装了 Sublime Text,并且在你的应用文件夹中。要启动并运行它,运行以下命令在~/bin 下创建一个目录

mkdir ~/bin

然后运行以下命令:

ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" ~/bin/subl

现在运行这个命令在你的~/中添加一行。zshrc 文件

echo 'export PATH=$PATH:$HOME/bin' >> ~/.zshrc

然后用下面这行代码将 Sublime 设置为默认编辑器:

echo "export EDITOR='subl' -w" >> ~/.zshrc

重新启动终端后,您可以使用以下命令进行测试:

subl .

这应该为你打开崇高的权利!

让我们把它变漂亮

虽然有很多主题可以用来修改终端窗口的外观,但您可能希望从简单的开始。

打开 iTerm,将 iTerm 菜单下拉至“首选项”会弹出一个有很多选择的窗口。您可以选择您喜欢的颜色,或者使用“颜色”标签中“颜色预设”下拉菜单中的一个选项。你可能想选择一个黑色的主题或者做一些其他简单的颜色选择。在“文本”标签下,很容易改变字体和字体大小

您也可以随时导入不同的主题。我在配色方案中使用了 Atom,但是你有很多选择。看看这个 GitHub 库的例子。

如果你想安装一个定制的 iTerm 主题,那很简单。只需进入这个 GitHub repo ,然后点击顶部的图标下载主题。(我用的是 zip 文件。下载文件后,单击它将其解压缩。)

接下来,转到“首选项”,点击“颜色”标签,并在“颜色预设”下拉菜单中点击“导入”。让你选择你想要的配色方案。这将打开一个查找窗口。进入你下载的文件夹中的“schemes”文件夹,如果你想使用 Atom 主题,选择“Atom.itermcolors”并点击“打开”

现在你可以从下拉菜单中选择“Atom ”!

如果您想要更改字体或字体大小,请转到“文本”标签然后单击“更改字体”按钮进行更改。

摩纳哥看起来很开心。

您还可以轻松调整窗口的透明度。你可能想要留意你窗户后面的东西。你可能是编程新手,需要确保你仔细地按照教程学习。这很有帮助!

只需转到“窗口”选项卡,调整“透明度:”下的滑块,直到你满意为止。

做你想做的事。

永远不要忘记:你的操场,你的规则。让你的空间牛逼起来!这只是你能做的事情的表面。有几乎无限的方式,你可以定制你的终端。

找点乐子!

如果你想出了一个让你心动的终端配置,就在下面的回复里让大家都知道吧!一如既往,在 LinkedIn 上随时联系 @annebonnerdata 。

感谢阅读!

想要更多很酷的文章和想法?查看内容简单!

操纵概率的技巧

原文:https://towardsdatascience.com/tricks-for-manipulating-probability-470b7eb7dfd?source=collection_archive---------16-----------------------

概述

  • 身份诡计
  • 跳跃戏法
  • 密度比例技巧
  • 对数导数技巧
  • 重新参数化技巧

解决机器学习和人工智能的基本问题需要在概率方面的灵活性。这个博客旨在总结不同概率问题中应用的各种技术,使计算更容易,有时甚至是可能的!本博客假设对概率和期望有基本的理解。因此,对基础知识的预先修订可能有助于进一步理解博客。

让我们快速概述一下机器学习中常见的推理问题及其概率方程。我们将不讨论这些问题的细节。这个列表应该是作为一个复习,而不是指南。

证据估计:

力矩计算:

参数估计:

预测:

假设检验:

如果你不知道其中的一些应用,不要担心。这不是即将到来的讨论的焦点,而是强调 ML 中概率建模的不同领域。因此,没有任何延迟,让我们深入到上述概率问题的操纵技术。

  1. 恒等式技巧: 这将一个对 f(x) w.r.t. a 分布p(x)的期望转换成一个对g(x;f) w.r.t .分配 q(x)。这是一个非常简单却非常有效的技巧。在很多场景下,计算期望 w.r.t. p(x) 是比较困难的。因此,我们引入一个分布 q(x),,它在数学上对我们来说很方便,并将期望值转换如下:

应用:

让我们用这个技巧来看看 ML 域的一个真实问题。

贝叶斯公式中的证据计算是多维变量中的一个棘手问题。在生成模型中,计算 p(x) 是主要目标。这里, x 是样本, z 是潜在变量, p(x|z) 是观察到 x 的可能性给定z下面给出的等式是联合概率 p(x,z) w.r.t. z. 的边缘化

p(z) 是实际的潜在变量分布,因此很难处理。我们引入一个不同的分布 q(z) ,它将逼近 p(z) ,并且具有良好的数学性质。从这种分布q(z)中采样很容易,而且在许多情况下,是一种高斯分布。我们简单地乘以和除以 q(z ),并将期望值的分布改为 q(z)。

条件:

  • q(z) > 0,当p(x | z)p(z)0
  • q(z) 已知或者容易处理。

我们可以进一步使用蒙特卡罗
抽样方法计算期望值,因为 q(z) 很容易从中抽样。这表现为:

在哪里,

注:我们将在《边界戏法》中讨论解决这个问题的另一种方法。

其他地方的身份诡计:

  • 操纵随机梯度。
  • 推导概率界限。
  • RL 用于政策修正。

2.边界技巧:
这个技巧来自于‘凸分析’,我们在其中对要计算的积分进行边界处理。其中之一是詹森不等式,

在大多数 ML 问题中,我们使用对数作为函数 f,,因为它们的可加性和严格的凹性。

其他跳跃技巧:

  • 芬切尔对偶。
  • 霍尔德不等式。
  • 蒙日-坎特罗维奇不等式。

一个应用出现在变分推理中的证据下界(ELBO)* 估计中。我们将使用詹森不等式找到一个下限进行优化,而不是使用第一招中证据计算*的蒙特卡洛估计。

对数并使用詹森不等式,

RHS 是变分下限,其中

  • 第一项是重建损失。
  • 第二项是在潜在变量上引入的近似分布族 q(z) 和原始的 p(z)之间的 KL 散度。

第一项采用 l2 损失或交叉熵损失的形式,取决于 p(x|z) 的分布,并且可以使用期望最大化(em)算法来优化该问题。

3。密度比技巧:
通常,当我们需要一个概率密度的比值时,一个简单的计算方法是计算两者,然后取比值。这个技巧说 两个概率密度的比率可以用一个分类器来计算,这个分类器使用从两个分布中抽取的样本。 由下式给出其中 p*(x)和 q(x)是两个概率分布,p(y=1|x) & p(y=-1|x)是分类器。

注:p*和 p 不相关。(抱歉符号滥用)。

让我们看看它的起源,找出它工作的基本原理。

通过组合来自两种分布的样本来创建数据集{显示为“组合数据”},并将+/- 1 指定为标签来表示分布{显示为“指定标签”}。现在,在等价设置中,我们可以将原始分布 p*(x)和 q(x)定义为组合数据集上的条件概率 p(x | y){显示为‘等价’}。

回想一下贝叶斯规则,该规则应用于条件分布 p(x|y=1)和 p(x|y=-1 ),如下所示:

注意:创建一个平衡数据集,使得 p(y=+1)等于 p(y=-1)。因此,它进一步简化为:

其他地方的密度比技巧:

  • 生成对抗网络。
  • 噪声对比估计。
  • 双样本测试。

接下来,我们来看看操纵函数 f. 的期望梯度的技巧

下面是统计科学中最常见的梯度问题。如果分布 q(z) 是简单的,并且积分是一维的,则可以计算出期望值,因此也可以计算出它的梯度。但是,在一般的框架中,我们不能以封闭的形式计算期望。因此,计算其梯度成为一个不平凡的问题。

这里φθ 分别是 q(z)f(z) 的参数。

将期望值表示为积分形式,我们可以看到有两种方法来进行梯度估计:

  1. 求密度的微分 q(z):(得分函数估计器)
  2. 求函数 f(z)的微分:(路径估计器)

我们将详细了解这两种方法是如何工作的,并以 RL 为例给出一个算法来获得直觉。在示例中,我们将公式化上述梯度估计问题,并使用我们的技巧来解决它。

在此之前,这些是出现上述问题的典型领域:

  • 生成模型和推理。
  • 强化学习和控制。
  • 运筹学
  • 蒙特卡洛模拟。
  • 金融和资产定价。
  • 灵敏度估计。

4.对数导数技巧:

第一种方法是微分密度q(z)也称为得分函数估计量。

统计学中的‘分数’是什么?
得分(或线人)是对数似然函数 log 的梯度(【θ】)w . r . t .参数向量 θ (见 wiki )。

因此,在我们的例子中,诀窍是:

(这里, ϕ参数,t47】q 为似然函数,梯度为 w.r.t. ϕ )

得分函数的性质:
1。得分函数的期望值是 0。(容易证明。提示:詹森不等式)

2.得分函数的方差由 Fisher 矩阵给出。(只是一个有用的属性)

让我们来看看上面的技巧是如何用来解决随机优化问题的。

在下图中,
1。梯度为 w.r.t. ϕ ,积分和梯度的顺序可以互换。
2。取 q(z) 的梯度,并通过乘以和除以 q(z) 来应用恒等技巧。
3。对数导数技巧开始发挥作用。
4。所示期望的梯度被转换成所示函数的期望。

注意,我们引入了一个常数 c ,它不会改变使用属性“得分函数的期望值为 0”的等式。但是从 f(z) 中减去计算的常数 c 减小了梯度的方差。

现在,我们准备在强化学习中导出香草 策略梯度

让我们看看推导中使用的一些定义:

  • 一条轨迹是世界上一系列的状态和行为。

这里,s 和 a 分别表示任意时刻 t 的状态和动作。

  • 代理人的目标是最大化某个轨迹上的累积回报,称为 回报。
  • 一种回报是无限期贴现回报,这是代理人曾经获得的所有回报*的总和,但按照他们在未来多远获得的时间贴现。这个奖励公式包括一个折扣因子 γ(0,1)*

  • 另一种是有限期限未贴现回报,也就是在一个固定的台阶窗口内获得的回报之和。我们将在推导中使用这一点。

  • 一个策略 π 是代理用来决定采取什么行动的规则。它可能是随机的。下面等式中的 π 表示给定状态下动作的概率分布。我们通常用 θ 来表示这种政策的参数,

  • 让我们假设环境转变 P 和策略 π 都是随机的。在这种情况下,T-步进轨迹给定策略 π 的概率为:

  • 对数导数技巧:

  • 轨迹的对数概率是:

  • 因此,轨迹对数概率的梯度为:

  • 注意环境对 θ 没有依赖性,所以初始状态概率ρ跃迁概率 P 的梯度为零。
  • 预期回报由下式表示:

RL 的目标是选择一个策略,当代理人按照这个策略行动时,这个策略使期望收益 J(π) 最大化。RL 中的中心优化问题可以表示为:

其中,π*是最优策略。

我们希望通过梯度上升来优化策略,例如

政策绩效的梯度,【∇j(π】,称为政策梯度。以这种方式优化策略的算法被称为策略梯度算法。任何政策梯度背后的关键思想是提高导致更高回报的行动概率,并降低导致更低回报的行动概率,直到你达到最优政策

下面给出了推导过程(取自旋转 RL 的图像片段)。我强烈推荐所有 RL 从业者阅读这个资源。链接此处

这是一个期望值,这意味着我们可以用一个样本均值来估计它。如果我们收集一组轨迹 D = {τ},政策梯度可以用以下公式估算

这是我们的最后一个魔术,

5.重新参数化技巧: 你可能在处理变分自动编码器时遇到过这个技巧。这是它在一般框架中的执行方式:

任何分布都可以表示为其他分布的变换。这方面的一个例子是逆采样方法,它说所有的均匀分布都可以转化为我们感兴趣的分布的逆 CDF(见 wiki )。一般来说,一个分布 p(z) 可以转换成另一个分布 p( ε ) 如下:

回到随机优化的第二种方法,我们有路径估计或重新参数化技巧。这次我们将操纵 f(z)。

注意 z 是从 q(z)采样的。我们引入了 p( ε ) 和上式定义的一个函数 g 。现在,代替我们问题中的 z (由下式给出),我们有

上述两种方法都有助于将期望梯度转换成某种梯度的期望,这种期望可以进一步用变分法或蒙特卡罗法来近似或有效地计算。

这都是为了操纵概率。希望下次遇到你的概率问题时,你会备上这些招数。

这是我的第一个博客。任何反馈都将受到高度赞赏。我真诚地建议仔细阅读参考资料,以便更好、更全面地理解。如果你能坚持到这里,非常感谢!

参考资料:

[1]Deep mind 的高级深度学习和强化学习。
[2]通过打开 AI 旋转 RL。

让你的生活变得更轻松的 Postgres 和 Docker 技巧

原文:https://towardsdatascience.com/tricks-for-postgres-and-docker-that-will-make-your-life-easier-fc7bfcba5082?source=collection_archive---------15-----------------------

如今,每个人都试图在容器中运行一切,我不责怪他们,我也做同样的事情,因为在 Docker 容器中运行应用程序、数据库或其他工具是非常好的,我们都知道为什么(隔离、容易设置、安全……)。然而,有时调试、访问或通常与容器的交互会非常烦人。这包括访问、修改或查询数据库。因此,由于我广泛使用 PostgreSQL,并且已经在容器中运行了一段时间,随着时间的推移,我列出了一些命令,这些命令在对数据库服务器进行简单和不太简单的操作时会有很大帮助。

登录 PSQL

如果您想与数据库服务器交互,您需要做的最基本的事情就是连接到数据库本身(使用 PSQL ):

因此,对于名为db的 Docker 容器、默认用户postgres和数据库名blog,应该是

对数据库运行命令

您可以登录然后执行您需要的任何命令,这很好,但是一次完成通常更方便,尤其是如果您只想运行一个命令或查询:

因此,如果我们想使用与上例相同的参数列出数据库中的所有表:

这里,\l列出了当前数据库中的所有表格,如果您不熟悉 psql “反斜杠”命令,那么我强烈推荐这张备忘单。

除了psql命令之外,您可以运行任何 SQL 查询,如下所示:

备份您的数据

有时,我需要备份数据或数据库的整个模式,有时只是作为一种“保险政策”,有时我可以不顾一切地进行更改,然后恢复一切,所以下面是如何做的:

在这个例子中,我们使用了pg_dump实用程序,它允许我们提取 PostgreSQL 数据库。我使用--column-inserts--data-only标志只获取表行,但通常只需要模式,为此您可以使用-s标志。

执行整个 SQL 文件

有时,您需要用足够的数据填充现有数据库进行测试(请不要对生产数据库这样做),或者使用文件中的数据,然后将它们复制并粘贴到上面的命令中会更容易。

这里我们首先需要将文件本身复制到运行容器中,然后使用-f标志执行它。

开始时预填充数据库

如果您需要不时地执行它,前面的例子已经足够好了,但是如果您每次启动数据库时都必须这样做,那就变得很烦人了。因此,如果您决定最好在一开始就填充数据库,那么这里有一个解决方案。它只需要多做一点工作:

我们需要以下文件:

  • Dockerfile - Dockerfile 为你的 Postgres 镜像
  • create_db.sh -创建数据库、模式并填充它的脚本。
  • schema.sql -包含数据库模式的 SQL 文件
  • data.sql -包含用于填充数据库的数据的 SQL 文件
  • .env -带环境变量的文件,让你的生活更轻松

第一,Dockerfile:

这非常简单 Dockerfile ,我们在这里需要做的就是将我们的脚本和模式/数据复制到映像中,以便它们可以在运行启动时使用。你可能会问,没有 *ENTRYPOINT* 或者 *COMMAND* ,我们如何在启动时运行它? -答案是,基本的postgres映像在docker-entrypoint-initdb.d目录中的任何脚本上运行,所以我们需要做的就是将我们的脚本复制到这个目录,PostgreSQL 会处理它。

但是剧本里有什么(create_db.sh)?

启动脚本首先使用指定的用户名(POSTGRES_USER)登录psql,然后创建您的数据库(DB_NAME)。接下来,它使用我们复制到映像中的文件创建数据库模式,最后用数据填充数据库。这里的所有变量都来自前面提到的.env文件,这使得随时更改数据库名称或用户名变得非常容易,而无需修改脚本本身。

更多完整的例子请见我的知识库这里

docker-compose呢?

根据我的经验,大部分时间我都是将数据库与使用它的应用程序一起运行,最简单的方法是 docker-compose 。通常我更喜欢通过服务名来引用 docker-compose 服务,而不是容器名,容器名可能是也可能不是同一个东西。如果不一样,您可以执行以下命令:

这里与前面的例子唯一不同的是docker-compose部分,它查找指定服务的信息。-q标志使得只显示容器 id,这正是我们所需要的。

结论

我希望这些小技巧中至少有一些能让您在处理 Docker 和 PostgreSQL 时更轻松,或者如果您只是因为在处理数据库时 Docker 可能有点烦人而避免使用它,那么我希望您在阅读完本文后会尝试一下。🙂

注:此文最初发布于martinheinz . dev

提高生产率的 R 技巧(第 1 部分)

原文:https://towardsdatascience.com/tricks-in-r-to-boost-your-productivity-8c977242c69c?source=collection_archive---------7-----------------------

Photo by Anete Lūsiņa on Unsplash

我想和你们分享我在 R 和 RStudio 中用来提高工作效率的一些技巧。它们是公共资源(比如 StackOverflow)和我个人的最佳实践的结合。生命短暂,不要再用这些伎俩浪费时间了。我希望你能从中受益,并与我分享你的技巧。当我得到更多的时候,我会继续在帖子中添加新的技巧!

1.计算向量权重

在许多情况下,我们需要根据参考向量的权重将一个数分配给一个向量,其中每个条目的权重计算为其占所有条目之和的比例。例如,您的总销售预测为 1,000,跨 3 个渠道(比如 A、B、C)的历史销售分布为(300,100,100)。然后,对于 A、B、C,渠道级别的销售预测可以分别计算为(3/5 * 1000、1/5 * 1000、1/5 * 1000)。一种极端情况是,可能没有任何历史渠道销售观察。在这种情况下,甚至跨所有渠道分发可能是一种常见的选择。如果总和等于 0,那么所有条目的所有权重都应该相等,因为它们都应该等于 0。如果你经常需要调用这样的函数,你可以创建一个助手函数来实现,如下所示

一个示例调用是

> lw(c(1,2,3))[1] 0.1666667 0.3333333 0.5000000

2.对于大向量,将字符转换为日期

当我们通过 DBI 从 CSV 文件或数据库中读取数据时,日期列可能仍然是字符类型。人们通常使用一个命令,如 base R 中的as.Date()lubridate 包中的ymd()将目标列转换为日期类型。它非常适合小数据。但是,如果列中有超过 1000 万个条目,这种转换方法可能需要相当长的时间。有一种更快的方法来实现它,如下所示

查看代码,关键的技巧是首先对字符向量进行重复数据删除,将经过重复数据删除的字符向量转换为日期向量,然后将每个条目映射回原始向量中的位置。速度的提高是基于这样的假设,即大向量中的大多数日期都是重复的,这是很常见的。

3.检查数据框中的缺失值

每个 R 用户都应该非常熟悉summary()函数,以便对数据框中的所有列进行快速统计。然而,在很多情况下,我们只关心一些特定的统计数据。就我个人而言,我经常检查每一列中缺失值的数量。因此,创建了两个辅助函数:

  • cc()代表为我“检查清洁”。它会告诉您每一列中有多少个丢失的值。
  • cd()代表我的“清洁密度”。它只是告诉您每一列中缺失值的百分比。

我喜欢这些功能是因为在键盘上输入“c”和“d”比输入“summary”要快得多。

4.到处使用管道运算符

在我看来,R 中的管道运算符%>%是迄今为止最伟大的发明。它简化了我们编码时的思维流程,极大地简化了代码结构。我建议你尽可能多地使用它。显示其灵活性的几个例子如下:

  • a %>% f(b)相当于f(a, b)
  • a %>% f(b) %>% f(c)相当于f(f(a, b), c)
  • a %>% {f(., b)}相当于f(a, b)

另外,记住在 macOS 中插入管道符号的快捷方式是CMD + SHIFT + M

5.与 H2O 合作

H2O 是我最喜欢的 R 包之一,并且正在成为 R 中的高性能机器学习框架

  • 首先,我建议你总是使用命名空间约定调用 H2O 函数h2o::而不是使用library(h2o)加载整个 H2O 库,因为加载整个库很可能会导致与其他常用包的函数冲突。与 H2O 的函数冲突有时会导致意想不到的后果,因为 H2O 软件包修改了其他流行软件包中许多函数的实现。
  • 其次,启动 H2O 实例的命令涉及到相当多的参数设置,需要输入一些内容。我喜欢用我的个人设置而不是默认设置来启动 H2o 实例。因此,我编写了下面的助手函数,根据我的喜好来包装最初的 H2O 初始化和关闭。

6.在 RStudio 中优化窗格布局

大多数人使用 RStudio 中的默认窗格布局。经过几年的实践,我优化的窗格布局如下:

  • 如今,由于大多数电脑屏幕都很宽,因此垂直空间非常宝贵。水平拆分源码和控制台,充分利用了屏幕空间。
  • 我总是隐藏左下方的窗格以最大化源代码窗格,所以只有命令历史是左下方的窗格,这是不常使用的。
  • 因为没有办法消除左下方的窗格,所以我将所有其他功能都移到了右下方的窗格中。

7.自动格式化您的代码

在 python 中,由于缩进的重要作用,很好地格式化代码总是令人痛苦的。在 r 中肯定不是这样,所以在 RStudio 中,你可以选择你所有的代码,在 macOS 中按下CMD + I的快捷键,进行自动缩进。不管你的代码有多丑,经过这个操作后,你会惊奇地发现它变得多么美丽。

更新:你现在可以在这里找到本主题的第 2 部分。

提高生产率的 R 技巧(第 2 部分)

原文:https://towardsdatascience.com/tricks-in-r-to-boost-your-productivity-part-2-7222461c6671?source=collection_archive---------10-----------------------

Photo by Brad Neathery on Unsplash

我总是热衷于能帮助我更快完成工作的工具和技巧。虽然提高生产率并不一定意味着它能给你带来好的或正确的结果,但它肯定能减少你的工作时间,这意味着犯错误的时间更少。花些时间学习技巧和工具会在你以后的工作中得到回报,这是完全值得的。继我上一篇关于 R 和 RStudio 技巧的文章之后,我将在这篇文章中继续与您分享一些我认为有用的其他技巧。

设置 R 配置文件

当一个 R 会话启动时,它首先尝试在您的项目目录或您的主目录中搜索一个.Rprofile文件,如果它存在,就执行函数.First。你可以使用.Rprofile在每节课开始时执行一些事情来节省你的时间

  • 加载经常工作的包(如 tidyverse、data.table、ggplot2 等。).
  • 设置环境变量(例如开发环境标识符(“沙箱”、“暂存”、“生产”等)。)、AWS 凭证、您的数据库连接凭证等)。
  • 设置 Java 参数(如果您需要通过 DBI/rJava 包从数据库中提取大量数据,您肯定需要设置这个参数)。
  • 设置 ggplot2 主题和调色板(如果您需要使用特定品牌的调色板,这很有用)。

下面是我的.Rprofile的一个例子:

让您的数据库查询包装函数

如果您经常使用 R 来查询数据库,那么您应该考虑更好地组织您的文件结构,并编写包装器函数来使您的生活更加轻松。首先,你应该把所有的 R 文件放在一个文件夹里,把所有的 SQL 文件放在另一个文件夹里。有些人喜欢将 SQL 命令直接写入 R 函数或脚本中,我认为这不是最佳做法,它会使您的 R 代码变得难看,并且您的 SQL 代码不能被另一个 R 代码重用。组织好后,你可以编写下面的包装函数:

Wrapper Functions for database query

  • connect_db是一个包装函数,在您调用驱动程序并使用 url 和凭证建立数据库连接后,它会返回一个数据库连接处理程序。
  • get_sql是 SQL 文件解析器。
  • 是您调用来执行查询的函数,在这里您可以发送一个 sql 文件路径或一个纯 SQL 字符串。您可以通过DBI::sqlInterpolate函数向函数传递额外的参数来替换 SQL 查询中的参数。最重要的是,我们需要在执行查询后关闭连接。

使用上面的包装器函数,所以您可以通过简单地调用下面的命令来执行 SQL 查询。

# String based query
accounts <- db_query('select count(*) from accounts where created_at < ?time', time = '2019-01-01')# File based query
accounts <- db_query('sql/accounts.sql', time = '2019-01-01')

您可以轻松地用更多的功能来扩展上述包装函数,比如删除、加载等。来满足你的需求。

退出时不要保存Workspace数据

如果您在终端中使用 R 命令行工具来完成所有工作,那么当您想要退出 R 会话时,系统会询问您是否保存您的工作区数据。如果选择保存工作区数据,一个隐藏的"。RData”文件将创建在您的工作目录中。如果您的工作空间仅包含少量数据,则可以保存数据。但是,如果您的工作空间包含大量数据(512MB 或更多),保存过程可能需要很长时间才能执行,因为工作空间数据需要压缩到文件中,这对于大数据来说很慢。所以,我个人的建议是,千万不要保存工作区数据存储。如果您使用 RStudio,您可以设置如下选项。如果你真的想在某些场合保存数据,你可以在退出前简单地调用save命令。

包装开发

包重装

如果您正在编写一个 R 包,并且想要重新加载整个开发包而不重新启动 R 会话并因此丢失数据,您可以使用devtools包中的函数devtools::reload()来实现。在 RStudio 中,重新加载的快捷方式是CMD + SHIFT + L

包装文件

在你的包的函数内部,你可以按CMD + Option + Shift + R调用Roxygen2为你的函数生成一个文档骨架,如下图所示。

Package Documentation Skeleton generated by Roxygen2

RStudio 代码设置

我是 RStudio 的忠实用户,使用 RStudio 已经超过 4 年了。下面是我对 RStudio 的代码设置建议。目的是让编码体验更加愉悦高效。

Display Setting

Saving Setting

发展环境

我相信 99%的 R 用户使用 RStudio 作为他们主要的 R 编程 IDE。RStudio IDE 有两个主要产品。一个是 RStudio 桌面,一个是 RStudio 服务器。大多数 R 用户从桌面版本开始,主要用于特定的分析和模型开发。如果他们的需求扩展到模型部署、任务自动化、闪亮的网站、仪表板、报告等。,那么服务器版本就成了更好的选择。如果您使用服务器版本,为了更好的软件管理,您最好在您的服务器上创建您的开发、试运行和生产环境。对我来说,我只有一台 EC2 服务器,没有三台分别用于开发、试运行和生产环境的专用服务器。作为一种变通方法,您可以在 git 和 Github 控制的三个不同的文件夹版本中创建三个 R 项目,以模拟开发、登台和生产环境,如下所示:

Environment Management

  • dev :它是我建模和分析的沙盒。
  • stg :这是一个新特性的测试环境。
  • prod :它包含用于生成报告、仪表板和自动化任务的代码和 cron 作业。在生产环境中,您应该只通过 git pull 更改代码,而不要手动更改。

如果您使用 RStudio server 的免费版本,在项目之间切换将会重新启动 R 会话,因此会丢失数据。如果使用 RStudio Pro 版本,可以在浏览器中并排运行 3 R 会话,更加方便。

三叉戟网络评论

原文:https://towardsdatascience.com/tridentnet-review-7f9936d2498a?source=collection_archive---------33-----------------------

TridentNet 是为解决目标检测中的尺度变化问题而提出的网络。

单级和两级检测器在处理标度变化时都有问题。存在解决尺度变化问题的方法,但是推理时间的增加使得这些方法不太适合实际应用。

Types of architectures to solve scale variance problems

解决大尺度变化的一种方法是利用多尺度图像金字塔。如图(a)所示,可以通过在多种规模下训练/测试网络来利用检测性能。

另一种方法是使用网络内特征金字塔来近似图像金字塔,具有更少的计算成本。这是通过从附近的比例级别内插一些特征通道来实现的。上图(b)是以 FPN 网络为例。

在本文中,作者提出了一种使用三叉块的网络结构,而不是像图像金字塔那样输入多尺度信息,如图所示。

standard convolution

dilated convolution

三叉戟块共享相同的参数,但它们有不同的感受野。借助于扩张的脑回,这是可能的。与标准卷积不同,扩张卷积利用扩张因子来获得更大的感受野。

感受野的研究

本文作者还研究了感受野对不同尺度物体探测的影响。他们通过将主干网络中的标准回旋转换为扩展回旋来测试这一点。在测试了各种扩张率后,他们发现随着感受野的增加(更大的扩张率),检测器对小物体的性能在 ResNet-50 和 ResNet-101 上都持续下降。

Detection results with different dilation factors

如上表所示,随着膨胀率的增加,大对象的精度增加,而小对象的精度降低。

三叉戟网络

Illustration of the TridentNet

为了继承不同感受野大小的优点并避免它们在检测网络中的缺点,trident 架构使用了上图所示的 Trident 模块。每个 trident 块都放置在主干网络中。该块由多个分支组成,其中所有分支共享卷积权重。唯一的区别是每个分支使用不同的膨胀因子。

Inside the trident block

规模意识培训计划

本文还提出了一种新的训练方案来解决由尺度不匹配(例如,分支上的小对象膨胀过大)引起的退化问题。

与 SNIP 类似,为每个分支定义了一个有效的范围。在训练时,对于每个分支,仅考虑训练有效范围内的框。所有超出有效范围的框都将被过滤掉。

结果

Comparison of TridentNet with other state-of-the-art networks

一个应用在更快的 R-CNN 上的 TridentNet 达到了 42.7 AP。为了更好地与 SNIPER 和 SNIPER 进行比较,还使用了可变形的回旋来代替膨胀的回旋。结果表明,可变形卷积的使用也优于基于图像金字塔的 SNIP 和 SNIPER 网络。

参考

[## 用于目标检测的尺度感知三叉戟网络

尺度变化是目标检测中的关键挑战之一。在这项工作中,我们首先提出了一个控制…

arxiv.org](https://arxiv.org/abs/1901.01892) [## 综述:扩展网络—扩展卷积(语义分割)

又名“atrous 卷积”、“algorithme à trous”和“hole algorithm”

towardsdatascience.com](/review-dilated-convolution-semantic-segmentation-9d5a5bd768f5) [## COCO 测试开发中用于对象检测的最先进的工作台

82 种方法的性能比较。

paperswithcode.com](https://paperswithcode.com/sota/object-detection-on-coco)

用 Pytorch-Lightning 进行琐碎的多节点训练

原文:https://towardsdatascience.com/trivial-multi-node-training-with-pytorch-lightning-ff75dfb809bd?source=collection_archive---------3-----------------------

How you feel running on 200 GPUs

因此,您拥有这款出色的 HPC 集群,但仍然只在 1 个 GPU 上训练您的模型?

我知道。斗争是真实的。😭

Pytorch-lightning ,为人工智能研究人员设计的 Pytorch Keras,让这变得微不足道。在本指南中,我将介绍:

  1. 在同一台机器的多个 GPU 上运行单个模型。
  2. 在具有多个 GPU 的多台机器上运行单个模型。

免责声明:本教程假设您的集群由 SLURM 管理。

模型

AI model

我们先来定义一个 PyTorch-Lightning (PTL)模型。这将是来自 PTL 文档的简单 MNIST 示例。

请注意,这个模型没有关于 GPU 的任何特定内容。cuda 或类似的东西。PTL 的工作流程是定义一个任意复杂的模型,PTL 将在你指定的任何 GPU 上运行它。

多 GPU,单机

让我们单独在 CPU 上训练我们的 CoolModel,看看是怎么做的。

要在单个 GPU 上训练,只需传入 GPU id

而对于多 GPU,只需添加更多的 id!

因此,在您的高级集群 GPU 机器上运行的完整脚本是:

GPU id

让我们快速迂回到 NVIDIA GPU 旗帜之地。当你在训练器中设置 GPU[0,1]时,你是在说“在这台机器上使用 GPU 0 和 GPU 1。”该顺序对应于 NVIDIA-SMI 命令的输出

Courtesy of servethehome.com

在引擎盖下,PTL 做了以下事情来让你的模型在 GPU 上工作

  1. 将 CUDA_VISIBLE_DEVICES 设置为这些 ID 和 CUDA_DEVICE_ORDER = "PCI_BUS_ID ",这保证了 ID 将对应于机器上的物理 GPU 布局(即:NVIDIA-SMI 的输出)。
  2. 在您的模型上添加适当的 DistributedDataParallel 或 DataParallel 包装器。

单节点圆滑线

假设您提交了一个使用 2 个 GPU 的 SLURM 作业。您仍然应该将 GPU ids,1 传递给 Trainer,即使您可能实际上正在使用一个 8 GPU 节点 上的物理最后 2 个 GPU。这是因为 SLURM 会为您的工作筛选出正确的 GPU,从 0 开始索引。

现在,例如,如果您在一个交互式作业中,并且该节点有 8 个 GPU,那么您将需要相应地更改索引。

例如,通过使用不同的 GPU ids 启动脚本 4 次,或者运行如下所示的 4 个进程,您可以在单个 8 GPU 节点上运行相同的模型 4 次:

当然,您可能只是出于调试的目的才这样做,或者因为您只是直接 ssh 到一台机器上。

试管使在单个节点上运行网格搜索变得简单。这里有一个网格搜索的例子,当你不通过 SLURM 提交的时候。

多机训练

Synced Training

要跨多个节点训练 PTL 模型,只需在训练器中设置节点数:

如果您创建适当的 SLURM 提交脚本并运行这个文件,您的模型将在 80 个 GPU 上训练。

请记住,您编码的原始模型仍然是相同的。底层模型不知道分布式复杂性。

这是使用 PTL 的最大优势之一,将工程任务交给框架,这样您就可以专注于研究。

一个 SLURM 脚本示例如下:

# SLURM SUBMIT SCRIPT #SBATCH --gres=gpu:8
#SBATCH --nodes=10
#SBATCH --ntasks-per-node=8
#SBATCH --mem=0
#SBATCH --time=02:00:00# activate conda env
conda activate my_env # run script from above
python my_test_script_above.py

还有其他可能特定于您的集群的标志,例如:

  1. 划分
  2. 限制

此外,PTL 目前只支持 NCCL 后端。这是 PyTorch 团队推荐的后端,也是拥有最快库的后端。如果一个新的,更快的出来,PTL 将尽快添加这一选项。

自动圆滑线脚本提交

SLURM… ugh

写 SLURM 脚本可以是一个皮塔饼。如果您想进行网格搜索,这一点尤为重要。

为此,您可以对 PTL 使用 SlurmCluster 对象,它将:

  1. 为您自动提交脚本。
  2. 将网格搜索分割成单独的脚本,然后全部提交。
  3. 在下班前几分钟重新排队。
  4. PTL 还将保存并加载您的模型,使重新排队无缝(您不需要做任何事情来保存或加载模型,PTL 会自动完成)。

让我们修改上面的脚本来使用 SlurmCluster 示例。

首先,让我们使用 SlurmManager 配置 SLURM 作业

optimizer _ parallel _ cluster _ GPU被调用时,SlurmManager 将为通过 HyperOptArgumentParser 传入的每组超参数提交一个脚本。

因此,更新后的完整脚本现在看起来像这样:

要在集群上运行网格搜索,只需:

  1. ssh 进入您的登录节点
  2. 安装 lightning 后激活您的 conda env
  3. 运行上面的 python 脚本
ssh some_nodeconda activate my_env_with_ptl# run the above script
python above_script.py

这可能不是您习惯的工作流,但是当您运行这个脚本时,它只会提交每个带有一组超参数的 slurm 作业。然后当脚本再次运行时,它会实际运行你传入optimize _ parallel _ cluster _ GPU的函数。

SLURM 会将所有 out、err 和 submit 脚本文件保存到您传递给 SlurmCluster 对象的目录中。

实际的训练日志将由实验对象来写。确保将实验版本设置为 cluster.hpc_exp_number,它在集群作业的总体方案中具有正确的实验版本。

不幸的是,由于底层的 SLURM 系统,在多个节点上的分布式训练需要更多的工作。PTL 将尽可能多的内容抽象出来,并给出了一种使用 SlurmCluster 对象来降低集群复杂度的可选方法。

电车问题不再是理论上的了

原文:https://towardsdatascience.com/trolley-problem-isnt-theoretical-2fa92be4b050?source=collection_archive---------4-----------------------

Photo by Justin Bautista on Unsplash

你是一辆高速电车的售票员,这辆电车正以每小时 85 英里的速度在轨道上疾驰,直奔一群在轨道上玩耍的小男孩,他们幸福地意识到自己即将面临的厄运。你意识到你可以拉一个杠杆将电车切换到另一条轨道,拯救这些男孩的生命。但是在你拉下控制杆之前,你会看到一个年轻的女孩正在备用路线的铁轨上玩耍。拉这个杠杆就意味着结束她的生命。你有十秒钟的时间来决定,否则就太晚了…

你是干什么的?

手推车问题是菲利帕·福特在 1967 年首先提出的一个思维实验。1984 年,JJ·汤姆森博士在一篇学术论文中再次提出了这个问题。它被引用了 1300 多次。

好消息是,关于伦理的讨论在大学的计算机科学课堂上越来越普遍。当涉及到数字系统和算法时,工程师们终于开始讨论关于价值观和公平的问题。然而,没有被高度讨论的是歧视性系统和偏见算法的后果——有意或无意——这些系统和算法已经生效,并且每天都被人类使用。

无轨电车的问题已经被像特斯拉、谷歌、优步、 Lyft 、 Argo 、 Embark 和通用汽车这样的公司解决了。问题是这样的:

如果一辆自动驾驶汽车发现自己不得不转向以拯救司机,但左转意味着撞上一名过马路的儿童,右转意味着撞上两名过马路的老年妇女——它应该转向哪个方向?

此前,谷歌选择了义务论的价值观:无论什么东西都永远击中最小的物体(垃圾桶和婴儿车中的婴儿没有区别)*。特斯拉选择不承担责任;人群来源的人类驾驶数据和模拟人类驾驶行为。这包括超速、急转弯和(有时)违法。

为什么 CS 教室都在理论上讨论算法和 AI?技术就在这里。它不再是理论上的了。是时候评估已经存在于不断增长的数字世界中的算法了。他们做出的决定会对社会产生积极或消极的影响。

但首先,我们必须讨论这些系统所基于的道德框架。

什么是伦理道德哲学?

在我们能够从伦理上评估算法和机器学习模型之前,我们必须首先讨论编码到它们中的价值。尽管有许多伦理学和道德哲学的框架,我只打算回顾最常见的几个:

1。功利主义

这个伦理理论是一个数字游戏。它关注的是一个行为的后果。根据功利主义,如果一个行为引起最大的好处/快乐和最小的痛苦/痛苦,那么这个行为就是道德的。

功利主义者可以接受摘取一个不知情的人的器官,如果这意味着拯救五个需要移植的人的生命。当谈到手推车问题时,功利主义者总是选择撞到路上最少的人——不管他们是谁。

scenario from moralmachine.mit.edu

这种道德框架是数字系统最容易采用的,因为很容易将数字游戏转化为代码。没有任何粒度的余地。

2.义务论

义务论诞生于著名哲学家康德。这种理论较少关注后果,而更多关注行动本身。在义务论中,一个规则被选择成为普遍法则。

结果永远不能证明手段的正当性。

在电车问题的例子中,这意味着售票员必须选择一个他们永远不会打破的公平标准。这可能意味着他们选择总是拯救最多的生命,最年轻的生命,最年长的生命,等等..无论如何,都必须遵循他们的标准。

在下图中,自动驾驶汽车的道义规则可能是“总是拯救最多的生命,这将有助于实现最大的整体利益。”

scenario from moralmachine.mit.edu

这类似于法律是如何产生的。一个规则涵盖了特定操作的所有情况。但是,就像政策的情况一样,义务论有一个重大缺陷:生活中的所有事情都是有背景的。有时候,遵循同样的规则会导致对一些人公平的决定和对另一些人不公平的决定。我们的义务论规则如何解释下面的情况?

scenario from moralmachine.mit.edu

3.美德伦理

最后,美德伦理。这种道德哲学不太关注行为或结果,而是把所有的压力都放在做行为的人的道德品质上。换句话说,行动的动机是焦点。

如果电车售票员救了 5 个男孩的命,但只是为了让电车转向他的前女友(她最近和他分手了),他的行为是不道德的。尽管他救了五条命,但他的动机并不单纯。

这给了人类更大的权力去打破规则,做一些对某些人来说可能有争议的事情,只要这些行为是出于良好的动机。这确实导致了一个大问题:

什么是良性动机?

事实证明,这个问题的答案因人、文化和地理位置的不同而大相径庭。

我们所使用的系统的伦理是什么?

giphy.com

既然我们都理解了伦理和道德哲学的基础,我们就可以将这些概念应用到对当今社会产生重大影响的数字系统中。

海伦·尼森鲍姆创建的隐私作为背景完整性框架是一个可以帮助我们评估数字系统潜在伦理含义的工具。虽然这个框架最初是为了帮助评估数字隐私,但它可以很容易地应用于所有的数字创新。

利用尼森鲍姆框架中的一些技术,我提出了一个框架来识别和修改不道德的技术。为了让这个框架对每个人都平易近人,我将把它作为决策树来介绍。

让我们称之为伦理技术框架:

为了确保我们完全理解这个框架,让我们用一个用例来测试它:

评估被告重新犯罪的风险。

又名:分配一个累犯风险分值。

让我们回到 18 世纪、19 世纪和 19 世纪:

在这种情况下,法庭上评估某人再犯风险的非数字替代方案通常只是法官的意见。可能会有证据表明过去的行为可能会影响被告重新犯罪的可能性,但某人的“风险评估”充其量只是一个有根据的猜测。

在过去,在统计学和技术被更广泛地应用于法庭之前,犯罪学家、法官或陪审团成员可以简单地将某人标记为“惯犯的高风险”,因为他们不喜欢他们的行为。或者更糟,因为他们不喜欢自己的种族

现在快进到 1990 年,一种新的数字替代品进入了场景: COMPAS 一种预测被告再犯风险分数的软件。它在美国的一些州被广泛使用。

“像这样的分数——被称为风险评估——在全国各地的法庭上越来越常见。它们被用来在刑事司法系统的每个阶段决定谁可以被释放,从指定保证金金额,到关于被告自由的更基本的决定。" ~ 机器偏差,ProPublica

不幸的是,对 COMPAS(以及那些遭受其软件后果的人)来说,他们的算法给黑人被告的风险分数比给白人被告的高得多。他们的算法是 义务论 ,但是他们评估风险的规则对任何非白人都是不公平的。这个软件是不道德的。[1][2][3]

现在,让我们想象一次重来。让我们假设现在是 1989 年,我们是 COMPAS 算法的开发者。为了不重复过去,我们决定在开始选择要在我们的训练数据集中使用哪些特征之前,我们将专注于我们算法的伦理。

我们使用方便的伦理技术框架。

玩家:

系统: COMPAS 软件

非数字替代:法官/陪审团意见

如果在 2013 年由我来决定,我们的 COMPAS 软件会达到以下标准:

或者,对于乐观的人来说,至少我们的 COMPAS 软件会映射到这里:

我的观点是:在过去,我怀疑 COMPAS 算法的设计者们有过关于道义论的对话。我怀疑如果他们选择了功利主义或基于价值观的方法,他们会研究他们的算法会做什么。老实说,这个软件的开发者似乎根本没有就道德问题进行过对话。或者如果他们有,那一定是在他们的系统被广泛使用之后很久。

COMPAS 并不孤单。通过利用类似伦理技术框架的东西,今天还有哪些系统可以造成更少的社会危害?

透明度&可解释性——成功的关键

现在我们终于理解了我们的系统所维护的道德和价值观。应该采取两个重要步骤:**

*1\. Make sure the *intended* values of the system match its reported values (ask users if they think the system is fair or not).2\. Explain these values to all stakeholders involved. This includes the users that are negatively/positively impacted by the system, the engineers who built the system, and anyone else who may interact with it.*

在 COMPAS 算法的案例中,被告有权知道他们的哪些信息导致了高或低的风险分数。他们没有得到这个信息。更糟糕的是,法官也没有得到这些信息。

每个人都盲目地相信一种算法,这种算法就像输入其中的数百年的犯罪数据一样种族主义。

透明度可能有助于解决这个问题。

还剩下什么?

如果你参与任何一种技术的创造,或者如果你与任何一种技术互动,你应该积极关注这些问题。理想情况下,你应该在你的工作场所或学校里谈论算法伦理。如果你的课程感觉非常理论化,问问你的老师你是否可以开始使用当前的案例研究来推动对话。

我知道这些问题不容易解决,但是改变必须从某个地方开始。很可能需要一种非常跨学科的方法来评估算法和机器学习模型的价值。

还有一个主要的障碍:

公司不愿意评估他们自己算法的道德性。

就在我写这篇文章的时候,我意识到大型科技公司的法律部门可能会嘲笑我的话。过去几年臭名昭著的算法丑闻[1][2][3][4][5]已经证明,只有当道德成为法律问题时,科技行业才会关注道德。

这就是为什么我提出了另一种道德评估的方法:将道德作为商业指标。如果用户意识到他们正在使用的系统所宣扬的价值,他们就会更好地理解这个系统。当用户没有被他们没有意识到的价值观蒙蔽时,他们会更加信任一个系统。

信任直接关系到用户留存。

公司害怕评估或审计他们的算法,害怕发现有问题。如果他们发现他们是不道德的,他们必须花费金钱和时间来解决这个问题。这就是为什么大多数公司的法律团队建议工程师尽可能避免算法审计,除非有诉讼或法律政策要求合规。

如果我们可以利用公平和道德作为商业标准,也许公司会更愿意检查自己。也许法律团队会放松。

这不是一个保证,但这是一个很好的开始。

遗言

Photo by Amogh Manjunath on Unsplash

我们已经就伦理和道德哲学争论了几千年。哲学是一个理论领域,因为没有让所有人都满意的“好”和“坏”的通用标准。当持相反信仰的人辩论道德和美德时,留给他们的问题往往多于答案。

随着技术的出现,现在有机会创造具有内置价值的系统和工件。

如果我们不明确定义我们为一个系统选择的道德框架或价值观,我们就有可能面临意想不到的后果,这对许多人来说可能是“不公平的”。

通过创建更容易理解的关于系统创建所选择的价值的指南,工程师将更容易理解他们工作的社会意义。这将更容易向用户解释这些系统影响的信息。

可解释性建立透明度。透明建立信任。

我的目标不是惩罚科技公司。相反,我的目标是通过利用课堂上开始的精彩的道德对话,激励* 他们希望合乎道德,并希望对自己负责。让我们把这些讨论应用到已经存在的问题上。*

一起,我们可以用更大的意图帮助编码。

有意的系统降低了无意的社会伤害的风险。

在电车问题中,我们不会就该救谁或杀谁达成一致。我们有不同的价值观和不同的观点。当谈到自动驾驶汽车时,谁同意或不同意并不重要,拯救谁的选择已经为我们做出。

是时候理解这些选择的后果了。是时候让算法设计透明化了。这不再是理论了。这就是现实。当我们提高声音时,我们有一个选择。

giphy.com

脚注: 我关于谷歌自动驾驶汽车的信息是基于一篇过时的文章。如果有人为谷歌或 Waymo 工作,并希望分享您的自动驾驶汽车在不可避免的碰撞情况下的当前目标函数,我们将非常感谢您的帮助和透明度!*

巨魔和机器人正在扰乱社交媒体——下面是人工智能如何阻止它们(第 1 部分)

原文:https://towardsdatascience.com/trolls-and-bots-are-disrupting-social-media-heres-how-ai-can-stop-them-d9b969336a06?source=collection_archive---------13-----------------------

巨魔和机器人对社交媒体有着巨大的、通常不为人知的影响。出于商业或政治原因,它们被用来影响对话。他们允许小规模的隐藏团体来推广支持他们的议程和大规模的信息。他们可以将自己的内容推到人们的新闻源、搜索结果和购物车的顶端。有人说他们甚至可以影响总统选举。

为了保持社交网站上讨论的质量,有必要对社区内容进行筛选和调节。我们可以使用机器学习来识别可疑的帖子和评论吗?答案是肯定的,我们会告诉你怎么做。

Source: pixabay.com

巨魔和机器人是社交媒体的巨大痛苦

巨魔在网上是危险的,因为当你受到他们的影响或与他们接触时并不总是显而易见的。俄罗斯特工发布的帖子在脸书被多达1 . 26 亿美国人看到,导致了最近的选举。Twitter 发布了来自俄罗斯巨魔的超过 900 万条推文的海量数据转储。而且不仅仅是俄罗斯!也有报道称,在与华为发生冲突后,巨魔试图影响加拿大。这个问题甚至延伸到网上购物,亚马逊上的评论已经慢慢地被商家严重操纵。

机器人是伪装成人的计算机程序。他们可以通过集体参与或喜欢他们的内容,或者通过自动发布他们自己的内容来放大巨魔的影响。未来它们会变得更加复杂,更难被发现。机器人现在可以创建完整的文本段落来回应文本帖子或评论。 OpenAI 的 GPT-2 模型可以写出感觉和外观都非常接近人类素质的文字。出于安全考虑,OpenAI 决定不发布它,但垃圾邮件发送者跟上只是时间问题。作为免责声明,并不是所有的机器人都是有害的。事实上,Reddit 上的大多数机器人都试图通过调节内容、查找重复链接、提供文章摘要等方式来帮助社区。区分有益的和有害的机器人是很重要的。

我们如何保护自己免受恶意巨魔和机器人发布的宣传和垃圾邮件的攻击?我们可以仔细调查每张海报的背景,但我们没有时间对我们读到的每条评论都这样做。答案是使用大数据和机器学习来自动化检测。让我们以毒攻毒吧!

在 Reddit 上识别机器人和巨魔

我们将把重点放在 Reddit 上,因为用户经常抱怨政治话题中的“巨魔”。由于匿名发帖,巨魔更容易操作。操作人员可以创建数十个或数百个账户来模拟用户参与、喜欢和评论。来自斯坦福的研究表明,仅仅 1%的 T4 账户就造成了 74%的冲突。在过去的几个月里,我们在世界新闻子网站上看到了许多类似这样的评论:

“还有人注意到这个帖子里的虚假用户吗?我认识他们的语言。它有非常具体的特征,比如看起来有真正的好奇心,但背后却有荒谬的陈述。要求“明确的证据”和质疑陈述的真实性(这通常是好事,但不是伪装)。我想知道你是否可以通过机器学习来识别这些类型的用户/评论。”—koalefant in r/world news

我们可以利用几个现有的资源。例如,机器人观察 subreddit 在 reddit 上跟踪机器人,名副其实! Reddit 的 2017 年透明度报告还列出了 944 个涉嫌为俄罗斯互联网研究机构工作的巨魔账户。

还有,有分析 Reddit 用户的软件工具。例如,设计非常好的 reddit 用户分析器可以进行情感分析,绘制用户评论的争议性,等等。让我们更进一步,建立一个工具,把权力放在版主和用户手中。

本文是由两部分组成的系列文章的第一部分,我们将介绍如何从 Reddit 的 API 中捕获数据进行分析,以及如何构建实际的仪表板。在第二部分中,我们将更深入地探讨如何构建机器学习模型。

创建可疑机器人和巨魔的仪表板

在本教程中,你将学习如何在机器学习的帮助下,创建一个仪表板来实时识别 Reddit 评论上的僵尸和巨魔。这可能是一个有用的工具,有助于政治子网站的版主识别和删除来自机器人和巨魔的内容。当用户向 r/politics 子编辑提交评论时,我们将捕捉这些评论,并通过我们的机器学习模型运行它们,然后在仪表板上报告可疑的评论,供版主审查。

这是我们仪表板上的一个截屏。在reddit-dashboard.herokuapp.com亲自尝试一下。

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

系统结构

由于社交媒体网站上的大量帖子和评论,有必要使用可扩展的基础设施来处理它们。我们将使用 Heroku 团队在使用 Apache Kafka 管理实时事件流中编写的示例来设计我们的系统架构。这是一个事件驱动的架构,它将让我们从 Reddit API 生成数据,并将其发送给 Kafka。 Kafka 使处理流数据和分离我们系统的不同部分变得容易。从 Kafka 读取这些数据,我们的仪表板可以调用机器学习 API 并显示结果。我们还将数据存储在 Redshift 中,用于历史分析和用作训练数据。

从 Reddit 收集数据

我们的第一步是从 politics 子编辑中下载评论进行分析。Reddit 使得以 JSON 格式的结构化数据访问评论变得很容易。要获得任何子编辑的最近提交,只需请求以下 URL:

https://www.reddit.com/r/${subreddit}/comments.json

同样,我们可以访问每个用户的公共数据,包括他们的因果报应和评论历史。我们需要做的就是从包含用户名的 URL 请求这些数据,如下所示。

https://www.reddit.com/user/${username}/about.json
https://www.reddit.com/user/${username}/comments.json

为了收集数据,我们遍历了 r/politics 子编辑中的每个评论,然后加载了每个评论者的用户数据。您可以使用任何您喜欢的 HTTP 请求库,但是我们在我们的示例中将使用 axios for Node.js。此外,我们将把来自两个调用的数据合并到一个方便的数据结构中,该数据结构包括用户信息和他们的评论。这将使以后存储和检索每个示例变得更加容易。这个功能可以在 profile-scraper.js 文件中看到,你可以在自述文件中了解更多关于如何运行它的信息。

卡夫卡中的实时事件流

既然已经从 Reddit 收集了数据,我们就可以将评论输入 Kafka 了。在连接到 Kafka 服务器之前,您需要在 Heroku 仪表板中创建一个主题。单击添加主题,并用单个分区设置主题名称。

要在 Node.js 中作为生产者连接到 Kafka 服务器,您可以使用 no-kafka 库,其中的连接信息已经在 Heroku 创建的集群中设置:

const Kafka = require(‘no-kafka’)const url = process.env.KAFKA_URL
const cert = process.env.KAFKA_CLIENT_CERT
const key = process.env.KAFKA_CLIENT_CERT_KEYfs.writeFileSync(‘./client.crt’, cert)
fs.writeFileSync(‘./client.key’, key)const producer = new Kafka.Producer({
 clientId: ‘reddit-comment-producer’,
 connectionString: url.replace(/\+ssl/g, ‘’),
 ssl: {
   certFile: ‘./client.crt’,
   keyFile: ‘./client.key’
 }
})

连接到 Kafka 后,您可以向之前创建的主题发送消息。为了方便起见,我们决定将 JSON 消息字符串化,然后在我们的直播应用程序中发送给 Kafka:

producer.send({
  topic: ‘northcanadian-72923.reddit-comments’,
  partition: 0,
  message: {
    value: JSON.stringify(message)
  }
})

在我们的 repo 中,样本实时流工作代码位于 kafka-stream.js 文件中。

构建主持人仪表板

我们的示例仪表板是一个 JavaScript 应用程序,它基于 Heroku 的先前版本的 twitter 显示 Kafka 演示应用程序。我们通过删除一些依赖项和模块来简化应用程序,但总体架构仍然存在:一个快速应用程序(服务器端)来消费和处理 Kafka 主题,通过 web socket 与一个 D3 前端(客户端)连接,以实时显示消息(Reddit 评论)及其分类。你可以在https://github.com/devspotlight/Reddit-Kafka-Consumers找到我们的开源代码。

在服务器端节点应用程序中,我们作为一个简单的消费者连接到 Kafka,订阅主题,并将每组消息广播到我们加载预测的函数:

new Consumer({
 broadcast: (msgs) => {
   predictBotOrTrolls(msgs)
 },
 interval: constants.INTERVAL,
 topic: constants.KAFKA_TOPIC,
 consumer: {
   connectionString: process.env.KAFKA_URL,
   ssl: {
     cert: ‘./client.crt’,
     key: ‘./client.key’
   }
 }
})

然后,我们使用 unirest (HTTP/REST 请求库)将来自这些消息的统一数据方案发送到我们的机器学习 API,以实时预测作者是人还是机器人或巨魔(在本文的下一节中有更多相关内容)。

最后,在我们的 app.js 中使用了一个 WebSocket 服务器,这样前端就可以实时获取所有的显示数据。由于 subreddit 注释流是实时的,所以应该考虑和监控每个应用程序的伸缩和负载平衡。

我们使用流行的 D3 JavaScript 库在 Kafka 消息流入时动态更新仪表板。从视觉上看,有一个特殊的表绑定到数据流,当最新的评论出现时,该表会更新(最新的优先),以及检测到的每个用户类型的计数:

import * as d3 from ‘d3’class DataTable {

 constructor(selector, maxSize) {
   this.tbody = d3.select(selector)
   this._maxSize = maxSize
   this._rowData = []
 } update(data) {
   data.forEach((msg) => {
   this._rowData.push(msg)
 } if (this._rowData.length >= this._maxSize)
   this._rowData.splice(0, this._rowData.length — this._maxSize) // Bind data rows to target table
 let rows = this.tbody.selectAll(‘tr’).data(this._rowData, (d) => d)
…

详见数据表. js 。上面显示的代码只是摘录。

调用我们的 ML API

我们的机器学习 API 旨在检查关于评论发帖人账户和最近评论历史的特征。我们训练我们的模型来检查他们的 Reddit“karma”、发布的评论数量、他们是否验证了他们的帐户等特征。我们还为它提供了一系列功能,我们假设这些功能将有助于对用户进行分类。我们将集合作为 JSON 对象传递给模型。然后,该模型为该用户返回一个预测,我们可以在我们的仪表板中显示该预测。你可以在本系列的第二部分中读到更多关于我们如何构建 ML 模型的信息。

下面是作为请求发送给 HTTP API 的示例 JSON 数据对象(使用我们的统一数据模式)。

一个机器人用户的例子:

{
“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 按钮轻松运行它

正如你所看到的,我们的架构有许多部分——包括生产者、Kafka 和一个可视化应用——这可能会让你认为它很难运行或管理。然而,我们有一个 Heroku 按钮,允许我们只需点击一下就可以运行整个堆栈。很整洁,是吧?这为使用更复杂的架构打开了大门,而无需额外的麻烦。

如果你有技术上的倾向,试试看。你可以让 Kafka 集群运行得非常快,而且你只需为它运行的时间付费。查看我们代码的 README 文档中本地开发和生产部署流程的文档。

后续步骤

我们希望鼓励社区使用这些类型的技术来控制巨魔和有害机器人的传播。这是一个激动人心的时刻,当这些社区开发出更好的机器学习和调节工具来阻止他们时,活着并看着巨魔试图影响社交媒体。希望我们能够让我们的社区论坛成为有意义讨论的地方。

查看我们的第二部分文章“使用机器学习在 Reddit 上检测机器人和巨魔”,这将深入探讨我们如何建立机器学习模型及其准确性。

GC 笔记本故障排除

原文:https://towardsdatascience.com/troubleshooting-gc-notebooks-f3531a4478e1?source=collection_archive---------26-----------------------

我最近花了相当多的时间搞清楚谷歌云提供的 Jupyter 笔记本服务。这是一个解决我在设置服务时不得不处理的一些烦人问题的指南。

I have no infra guys, I have none.

如果一切顺利,创建笔记本应该是一项简单的任务。然而,我无法只使用谷歌云控制台来启动和运行它。笔记本实例一直在初始化,显然在setting up of proxy.失败了

如果这个简单的过程(New Instance——Open Jupyter)适合您,那么就没有必要阅读指南。然而,如果你在这里,你可能会寻找更多。

解决设置代理错误

一本正经的指南:

  • 创建一个具有所需配置的新笔记本。
  • 在完成之前,点击Customise并向下滚动到Networking并禁用Allow proxy access when it's available
  • 许可下,默认Compute Engine default service account有效。如果您稍后遇到权限错误,也可以考虑其他两个选项(Other service accountSingle user only)。
  • 创建笔记本实例。
  • 单击实例的名称将打开配置编辑器页面。在进行以下任何配置更改之前,您需要停止该实例。
  • 故障排除文档提到正确设置Custom metadataproduct_owners下的proxy-mode。文档可以在这里找到。然而,对我来说,工作配置是 **proxy_mode** 设置为 **none**。当您执行步骤 2 时,这是默认模式。
  • Network Interfaces下,确保External IP不是None
  • IAM and Admin中,确保当前用户拥有计算访问所需的相关权限。(E.x. compute.instances.get)
  • 接下来,打开jupyter-lab的选项将被替换为 SSH 到实例。点击connect获取需要在本地机器上执行的预编写的 shell 命令。
  • 当尝试使用 SSH 连接时,您的实例需要正在运行。
  • 如果您在尝试 SSH 时得到一个Permission denied (publickey),或者类似这样的消息:
ssh: connect to host IP port 22: Connection refusedERROR: (gcloud.compute.ssh) [/usr/bin/ssh] exited with return code [255].

启动文本编辑器,用超级用户权限编辑这个文件。(以下位置适用于 MacOS)

sudo nano /private/etc/ssh/sshd_config

将现有的两行更新为:

Port 22
PermitRootLogin yes

请再次尝试关闭该实例。您现在应该能够成功地做到这一点。您可以使用下面的命令来验证jupyter-lab是否真的作为服务在实例ps -ef | grep jupyter上运行

如果您仍然得到相同的错误,运行gcloud auth login并基于网络完成认证过程。您也可以设置默认的项目详细信息。

前往[http://localhost:8080](http://localhost:8080)访问笔记本!

附加注释

如果您使用 GPU,请确保在配置笔记本实例时选中自动安装必要的驱动程序。

一个新启动的实例需要一些时间来安装驱动程序,所以请耐心等待。使用下面的代码片段来验证是否一切顺利,以及是否列出了 GPU。(来源)

from __future__ import absolute_import, division, print_function, unicode_literalsimport tensorflow as tf
print("Num GPUs Available: ", len(tf.config.experimental.list_physical_devices('GPU')))

如果您已经打开了日志记录(tf.debugging.set_log_device_placement(True)),那么您可以在 SSHed 实例中使用下面的命令来查看日志:journalctl -f -u jupyter。这些日志将有助于在出现 GPU 相关问题时进行额外的故障排除。这些日志也可在控制台上的监控-串行端口#1(控制台)中找到。

再见。

自然语言处理中的 Truecasing

原文:https://towardsdatascience.com/truecasing-in-natural-language-processing-12c4df086c21?source=collection_archive---------6-----------------------

全面回顾使用 NLTK、spaCy、StandfordNLP 纠正单词大写的 NLP 方法

自然语言处理(NLP)是分析以自然语言之一表示记录的文本数据的学科。Ethnologue.com(第 21 版)有数据表明,在目前列出的 7,111 种现存语言中,有 3,995 种有发达的书写系统(如英语、法语、 Yemba 、汉语、……)。自然语言处理的应用包括文本分类、拼写 T20 语法纠正、信息提取、语音识别、机器翻译、文本到语音合成、同义词生成,以及更高级的领域,如摘要、问答、对话系统和语音模仿。

在本文中,我们将通过一个实际的例子来回顾现有的解决 Truecasing 的方法。true case是一个自然语言处理问题,即在无法获得相关信息的文本中找到单词的正确大写。Truecasing 有助于完成 NLP 任务,如命名实体识别、自动内容提取、以及机器翻译。专有名词大写可以更容易地发现专有名词,并有助于提高翻译的准确性。

有几种实用的方法可以解决真实情况问题:

  • 句子分割:将输入的文本拆分成句子,并将每个句子的第一个单词大写。
  • 词性标注:查找句子中每个词的定义和上下文,并分配最合适的标注。最后,用特定的标签包装单词。
  • 名称-实体-识别(NER) :将句子中的单词分类到特定的类别,并决定大写例如人名等。
  • 统计建模:通过对常用大写形式的词和词组进行统计模型训练。

我们将探索每一种方法,寻找现有的开源库和代码片段。我们将实施和测试有希望的方法,并解释它们如何工作或不工作。最后,我们将提出一个建议,以及开放的关注点和未来的工作。

让我们考虑下面的句子,大部分单词都是小写的。

text = "I think that john stone is a nice guy. there is a stone on the grass. i'm fat. are you welcome and smart in london? is this martin's dog?"

分词

自然语言工具包(NLTK)为计算机语言学家和 NLP 专家所熟知。它最初创建于 2001 年,是宾夕法尼亚大学计算语言学课程的一部分。它提供了一个直观的框架以及大量的构建模块,给用户一个实用的 NLP 知识,而不会陷入通常与处理带注释语言
数据相关的繁琐的内务处理中。通过在 Python Anaconda 提示符下运行以下命令来安装 NLTK。

pip install –-upgrade nltk

NLTK 附带了记号赋予器。它们的工作方式类似于正则表达式,用于将字符串分成子字符串列表。特别是,下面使用句子标记器来查找我们文本中的句子列表。

from nltk.tokenize import sent_tokenize
import redef truecasing_by_sentence_segmentation(input_text):
    # split the text into sentences
    sentences = sent_tokenize(input_text, language='english')
    # capitalize the sentences
    sentences_capitalized = [s.capitalize() for s in sentences]
    # join the capitalized sentences
    text_truecase = re.sub(" (?=[\.,'!?:;])", "", ' '.join(sentences_capitalized))
    return text_truecasetruecasing_by_sentence_segmentation(text)
"I think that john stone is a nice guy. There is a stone on the grass. I'm fat. Are you welcome and smart in london? Is this martin's dog?"

正如我们看到的第一个单词,如果每个句子的大写字母正确。然而,像johnlondon这样的词仍然需要正确处理。

用 NLTK 进行词性标注

为了能够将单词 johnlondon 识别为人名和城市,我们使用了所谓的词性技术,这是根据单词的定义和上下文将文本中的单词标记为与特定词性相对应的过程。这是一个基于上下文的监督学习解决方案,在流行的 Penn Treebank 标签集上训练。NLTK 库中的 POS 标记器为某些单词输出特定的标记。比如 NN 代表名词,用单数,比如斯通约翰盖伊。NNS 代表复数名词。下面我们将文本中的所有名词都大写。

from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
def truecasing_by_pos(input_text):
    # tokenize the text into words
    words = nltk.word_tokenize(text)
    # apply POS-tagging on words
    tagged_words = nltk.pos_tag([word.lower() for word in words])
    # apply capitalization based on POS tags
    capitalized_words = [w.capitalize() if t in ["NN","NNS"] else w for (w,t) in tagged_words]
    # capitalize first word in sentence
    capitalized_words[0] = capitalized_words[0].capitalize()
    # join capitalized words
    text_truecase = re.sub(" (?=[\.,'!?:;])", "", ' '.join(capitalized_words))
    return text_truecasetruecasing_by_pos(text)"I think that John Stone is a nice Guy. there is a Stone on the Grass. i'm fat. are you welcome and smart in London? is this Martin's Dog?"

正如我们所看到的,词性标注方法比句子分割方法取得了更好的效果。然而,我们将像grassdog这样在标准英语中不应该大写的单词大写。

带空间的命名实体识别

spaCy 是工业级 NLP 的快速库。它支持词向量、语义分布和许多统计模型,我们不仅可以使用这些模型进行更好的词性标注(POS),还可以用于命名实体识别(NER)。

而词性标注(POS)的目的是识别一个词属于哪个语法组,所以它是名词、形容词、代词等。;另一方面,命名实体识别(NER)试图找出一个词是否是一个命名实体,如人、地点、组织等。

spaCy 带有预先训练的语言模型,通常是用于各种语言处理任务的卷积神经网络,如 POS 和 NER。我们将使用 en_core_web_lg 模型,这是一个英语多任务 CNN (700 MB)。也可以使用较小的型号 en_core_web_sm (10 MB),结果稍差。

spaCy 通过运行命令pip install -U spacy来安装,然后在 Anaconda 提示符下运行python -m spacy download en_core_web_lg来下载模型。下面我们显示文本中的单词及其相应的位置标签和 NER。

import spacy
spacy_nlp = spacy.load('en_core_web_lg')
words = spacy_nlp(text)
[(w.text, w.tag_) for w in words]
[('I', 'PRP'),
 ('think', 'VBP'),
 ('that', 'IN'),
 ('john', 'NNP'),
 ('stone', 'NN'),
 ('is', 'VBZ'),
 ('a', 'DT'),
 ('nice', 'JJ'),
 ('guy', 'NN'),
 ('.', '.'),
 ('there', 'EX'),
 ('is', 'VBZ'),
 ('a', 'DT'),
 ('stone', 'NN'),
 ('on', 'IN'),
 ('the', 'DT'),
 ('grass', 'NN'),
 ('.', '.'),
 ('i', 'PRP'),
 ("'m", 'VBP'),
 ('fat', 'JJ'),
 ('.', '.'),
 ('are', 'VBP'),
 ('you', 'PRP'),
 ('welcome', 'JJ'),
 ('and', 'CC'),
 ('smart', 'JJ'),
 ('in', 'IN'),
 ('london', 'NN'),
 ('?', '.'),
 ('is', 'VBZ'),
 ('this', 'DT'),
 ('martin', 'NNP'),
 ("'s", 'POS'),
 ('dog', 'NN'),
 ('?', '.')]
print([(w.text, w.label_) for w in words.ents])
[('john', 'PERSON'), ('martin', 'PERSON')]
print([(w, w.ent_iob_, w.ent_type_) for w in words])
[(I, 'O', ''), (think, 'O', ''), (that, 'O', ''), (john, 'B', 'PERSON'), (stone, 'O', ''), (is, 'O', ''), (a, 'O', ''), (nice, 'O', ''), (guy, 'O', ''), (., 'O', ''), (there, 'O', ''), (is, 'O', ''), (a, 'O', ''), (stone, 'O', ''), (on, 'O', ''), (the, 'O', ''), (grass, 'O', ''), (., 'O', ''), (i, 'O', ''), ('m, 'O', ''), (fat, 'O', ''), (., 'O', ''), (are, 'O', ''), (you, 'O', ''), (welcome, 'O', ''), (and, 'O', ''), (smart, 'O', ''), (in, 'O', ''), (london, 'O', ''), (?, 'O', ''), (is, 'O', ''), (this, 'O', ''), (martin, 'B', 'PERSON'), ('s, 'O', ''), (dog, 'O', ''), (?, 'O', '')]

我们获得了比 NLTK 更详细的标记,但是我们仍然不能区分物体(石头和城市(伦敦)的 NN 标记。尽管约翰被 NER 处理器识别为一个人,但是斯帕西并不将单词斯通的第一个实例识别为一个人。

基于统计的真实大小写

推断正确大小写的任务经常会出现歧义:考虑句子中的单词 stone 他有一块石头他与 stone 交谈。前者指一个物体,后者指一个人。在这篇论文中提出了一种统计方法来处理这种模糊性。下面我们改编了它的实现。

该模型需要从训练语料库中获得的关于单字、双字和三字的频率的信息。作者提供了这样一组预训练的频率,下面称为distributions _ English . obj

import string
import math
import pickle"""
This file contains the functions to truecase a sentence.
"""

def getScore(prevToken, possibleToken, nextToken, wordCasingLookup, uniDist, backwardBiDist, forwardBiDist, trigramDist):
    pseudoCount = 5.0

    #Get Unigram Score
    nominator = uniDist[possibleToken]+pseudoCount    
    denominator = 0    
    for alternativeToken in wordCasingLookup[possibleToken.lower()]:
        denominator += uniDist[alternativeToken]+pseudoCount

    unigramScore = nominator / denominator

    #Get Backward Score  
    bigramBackwardScore = 1
    if prevToken != None:  
        nominator = backwardBiDist[prevToken+'_'+possibleToken]+pseudoCount
        denominator = 0    
        for alternativeToken in wordCasingLookup[possibleToken.lower()]:
            denominator += backwardBiDist[prevToken+'_'+alternativeToken]+pseudoCount

        bigramBackwardScore = nominator / denominator

    #Get Forward Score  
    bigramForwardScore = 1
    if nextToken != None:  
        nextToken = nextToken.lower() #Ensure it is lower case
        nominator = forwardBiDist[possibleToken+"_"+nextToken]+pseudoCount
        denominator = 0    
        for alternativeToken in wordCasingLookup[possibleToken.lower()]:
            denominator += forwardBiDist[alternativeToken+"_"+nextToken]+pseudoCount

        bigramForwardScore = nominator / denominator

    #Get Trigram Score  
    trigramScore = 1
    if prevToken != None and nextToken != None:  
        nextToken = nextToken.lower() #Ensure it is lower case
        nominator = trigramDist[prevToken+"_"+possibleToken+"_"+nextToken]+pseudoCount
        denominator = 0    
        for alternativeToken in wordCasingLookup[possibleToken.lower()]:
            denominator += trigramDist[prevToken+"_"+alternativeToken+"_"+nextToken]+pseudoCount

        trigramScore = nominator / denominator

    result = math.log(unigramScore) + math.log(bigramBackwardScore) + math.log(bigramForwardScore) + math.log(trigramScore)

    return result

def getTrueCase(tokens, outOfVocabularyTokenOption, wordCasingLookup, uniDist, backwardBiDist, forwardBiDist, trigramDist):
    """
    Returns the true case for the passed tokens.
    @param tokens: Tokens in a single sentence
    @param outOfVocabulariyTokenOption:
        title: Returns out of vocabulary (OOV) tokens in 'title' format
        lower: Returns OOV tokens in lower case
        as-is: Returns OOV tokens as is
    """
    tokensTrueCase = []
    for tokenIdx in range(len(tokens)):
        token = tokens[tokenIdx]
        if token in string.punctuation or token.isdigit():
            tokensTrueCase.append(token)
        else:
            if token in wordCasingLookup:
                if len(wordCasingLookup[token]) == 1:
                    tokensTrueCase.append(list(wordCasingLookup[token])[0])
                else:
                    prevToken = tokensTrueCase[tokenIdx-1] if tokenIdx > 0  else None
                    nextToken = tokens[tokenIdx+1] if tokenIdx < len(tokens)-1 else None

                    bestToken = None
                    highestScore = float("-inf")

                    for possibleToken in wordCasingLookup[token]:
                        score = getScore(prevToken, possibleToken, nextToken, wordCasingLookup, uniDist, backwardBiDist, forwardBiDist, trigramDist)

                        if score > highestScore:
                            bestToken = possibleToken
                            highestScore = score

                    tokensTrueCase.append(bestToken)

                if tokenIdx == 0:
                    tokensTrueCase[0] = tokensTrueCase[0].title();

            else: #Token out of vocabulary
                if outOfVocabularyTokenOption == 'title':
                    tokensTrueCase.append(token.title())
                elif outOfVocabularyTokenOption == 'lower':
                    tokensTrueCase.append(token.lower())
                else:
                    tokensTrueCase.append(token) 

    return tokensTrueCasef = open('english_distributions.obj', 'rb')
uniDist = pickle.load(f)
backwardBiDist = pickle.load(f)
forwardBiDist = pickle.load(f)
trigramDist = pickle.load(f)
wordCasingLookup = pickle.load(f)
f.close()def truecasing_by_stats(input_text):
    truecase_text = ''
    sentences = sent_tokenize(input_text, language='english')
    for s in sentences:
        tokens = [token.lower() for token in nltk.word_tokenize(s)]
        tokensTrueCase = getTrueCase(tokens, 'lower', wordCasingLookup, uniDist, backwardBiDist, forwardBiDist, trigramDist)
        sTrueCase = re.sub(" (?=[\.,'!?:;])", "", ' '.join(tokensTrueCase))
        truecase_text = truecase_text + sTrueCase + ' '
    return truecase_text.strip()truecasing_by_stats(text)"I think that John stone is a nice guy. There is a stone on the grass. I'm fat. Are you welcome and smart in London? Is this Martin's dog?"

这似乎是迄今为止取得的最好成绩。问题仍然是将石一词的一审认定为人名,即应当大写。虽然像这样的著名名字被算法正确识别并大写,但是并没有被推断为人名。单词 stone 可能没有作为人名出现在该方法的作者所使用的训练语料库中。

带标准套管的真实套管

StanfordNLP 是一个 Python 自然语言分析包,构建在 PyTorch 之上。由社区推荐,特别用于识别与人名相关的实体。它是通向 Stanford CoreNLP 的桥梁,最初是用 Java 编写的,但是即使在 NLTK 中也有使用它的方法。

如果尚未安装,则需要以下软件包:

pip install stanfordnlp

此外,我们需要运行以下命令来下载神经管道的英文模型。这将带来 ca。1.96 克数据到我们的机器。

stanfordnlp.download('en')

以下代码使用 POS 处理器创建了一个管道,并在我们的文本上评估 StandfordNLP 模型。

>>> stf_nlp = stanfordnlp.Pipeline(processors='tokenize,mwt,pos')
>>> doc = stf_nlp(text)
>>> print(*[f'word: {word.text+" "}\tupos: {word.upos}\txpos: {word.xpos}' for sent in doc.sentences for word in sent.words], sep='\n')word: I         upos: PRON      xpos: PRP
word: think     upos: VERB      xpos: VBP
word: that      upos: SCONJ     xpos: IN
word: john      upos: PROPN     xpos: NNP
word: stone     upos: PROPN     xpos: NNP
word: is        upos: AUX       xpos: VBZ
word: a         upos: DET       xpos: DT
word: nice      upos: ADJ       xpos: JJ
word: guy       upos: NOUN      xpos: NN
word: .         upos: PUNCT     xpos: .
word: there     upos: PRON      xpos: EX
word: is        upos: VERB      xpos: VBZ
word: a         upos: DET       xpos: DT
word: stone     upos: NOUN      xpos: NN
word: on        upos: ADP       xpos: IN
word: the       upos: DET       xpos: DT
word: grass     upos: NOUN      xpos: NN
word: .         upos: PUNCT     xpos: .
word: i         upos: PRON      xpos: PRP
word: 'm        upos: AUX       xpos: VBP
word: fat       upos: ADJ       xpos: JJ
word: .         upos: PUNCT     xpos: .
word: are       upos: AUX       xpos: VBP
word: you       upos: PRON      xpos: PRP
word: welcome   upos: ADJ       xpos: JJ
word: and       upos: CCONJ     xpos: CC
word: smart     upos: ADJ       xpos: JJ
word: in        upos: ADP       xpos: IN
word: london    upos: PROPN     xpos: NNP
word: ?         upos: PUNCT     xpos: .
word: is        upos: AUX       xpos: VBZ
word: this      upos: DET       xpos: DT
word: martin    upos: PROPN     xpos: NNP
word: 's        upos: PART      xpos: POS
word: dog       upos: NOUN      xpos: NN
word: ?         upos: PUNCT     xpos: .

用 StandfordNLP 得到的 POS 标签看起来棒极了!单词 stone 的第一个实例现在被正确识别为人名,允许正确的大写,如下所示。

[w.text.capitalize() if w.upos in ["PROPN","NNS"] else w.text for sent in doc.sentences for w in sent.words]
['I', 'think', 'that', 'John', 'Stone', 'is', 'a', 'nice', 'guy', '.', 'there', 'is', 'a', 'stone', 'on', 'the', 'grass', '.', 'i', "'m", 'fat', '.', 'are', 'you', 'welcome', 'and', 'smart', 'in', 'London', '?', 'is', 'this', 'Martin', "'s", 'dog', '?']

斯坦福 CoreNLP 也提供了一套强大的工具。它可以检测单词的基本形式(词条)、词性、公司名称、人名等。它还可以标准化日期、时间和数字量。它还被用来标记短语和句法依存关系,表示情感,以及获取人们所说的引语。StanfordNLP 只需几行代码就可以开始利用 CoreNLP 复杂的 API。想深入了解的,查看链接的帖子这里。

结论

在这篇文章中,我们研究了没有案例信息的文本的案例恢复。使用的所有技术都是在单词级别使用 NLTK、spaCy 和 StandfordNLP 工具包进行操作。在链接这里的文章中提出了一种使用字符级递归神经网络(RNN)的方法,供我们当中的一些英雄参考。

真正有创造力的机器人

原文:https://towardsdatascience.com/truly-creative-robots-b6c9935626d1?source=collection_archive---------26-----------------------

为什么艺术中的创造性是人类活动(目前)

machine generated art

机器能有创造力吗?

和其他事情一样,这取决于你对创造力的定义。机器能创造艺术吗?音乐?诗歌?绝对的。这让他们变得有创造力了吗?呃,算是吧。

艺术中的大多数美——绘画、雕塑、音乐——都是通过某种创造性的媒介来表达思想和情感。例如,语言是一种媒介,艺术通过诗歌和文学来表现。那么,是什么阻止了机器人的创造力呢?毕竟,我们有绘画、创作音乐和写诗的机器。为什么不一样?

人类的优势

人类的艺术灵感来自内部外部来源,而任何机器娱乐(绘画、诗歌、音乐)仅来自外部来源——对人类艺术的模仿。今天的机器没有任何真实、复杂的内部现实模型,它们从中汲取情感和欲望,正是人类的情感孕育了艺术。换句话说,他们没有感情。

这就是机器生成的艺术和人类创造力之间的主要区别:人们通过内在的——感觉和情感,以及外在的——他人的创作来创造艺术。机器只是简单地复制人类。

《模仿游戏》

那么,今天的机器是如何创造艺术的呢?

一般来说,人类艺术被大量收集——这被称为训练数据。然后,这些数据被输入机器,直到它们能够很好地学习这些模式,以近似类似的创造。通过几乎任何类型的艺术编码成数字(特别是——向量和矩阵,机器可以开始“理解”(读取:数学建模)训练数据中的这些模式。

一旦机器知道它看到的是什么类型的数字,它就能创造出新的和类似的数字。

然后我们获取这些数字并解码它们(完全与相反的我们最初是如何编码它们的),并在最初创造的媒介中恰当地呈现机器产生的创造。

借助当今最先进的技术,这种训练可以产生令人难以置信的效果。生成的艺术可以是明显的、超现实的,甚至是超现实的。有时候,完全不可能区分人类和机器的创造。

Surreal, mathematical, and photo-realistic examples

然而,我们仍然停留在模仿机器,而不是以新颖和有目的的方式表达自己的思考和感受的存在。同样,机器人没有激发创造力的内在自我意识,只是一个尽最大努力复制所见的数学模型。

有关系吗?

有些人可能会说这没什么区别——艺术就是艺术。没有正确的答案来划分界限。但是,这没有抓住重点。我们在讨论机器创造力的问题,肯定会有好论点的人落在线的两边。

我认为机器艺术背后的基本过程缺少一个至关重要的元素——内在灵感。仅仅通过随机过程进行模仿是不够的。

结论

最后,需要注意的是,这种情况不可避免地会发生变化。模型会变得更复杂,机器智能会继续发展。体验情感、表达自我和有意识意味着什么,这些基本问题对于划定机器何时真正从内心渴望的地方汲取灵感,而不是简单的数学模仿,将是至关重要的。

如果你对机器意识的未来感兴趣,请查看这篇文章了解更多。

感谢阅读!😃

用基础知识理解内核技巧

原文:https://towardsdatascience.com/truly-understanding-the-kernel-trick-1aeb11560769?source=collection_archive---------4-----------------------

在这里,我们学习内核技巧背后的基本原理。它是如何工作的?内核绝招如何在不增加计算量的情况下,无限维内点积(或相似度)?

<了解深度学习,了解更多> >

什么是内核技巧?尽管它对机器学习世界产生了深远的影响,但几乎没有发现可以解释内核技巧背后的基本原理。在这里,我们将看看它。在这篇文章的结尾,我们会意识到基本的概念是多么简单。或许,这种简单性使得内核技巧变得深刻。

如果你正在读这篇文章,你可能已经知道事实上如果函数中有点积,我们可以使用内核技巧。当我们了解 SVM 时,通常会遇到这种情况。SVM 的目标函数是,

在这个目标函数中,我们有点积 𝐱 𝑖ᵀ⋅ 𝐱 𝑗.由于这个点积,SVM 变得非常强大,因为现在我们可以使用内核技巧。

这个内核是什么,它是如何让 SVM 变得强大的?

在下面,我们将看看这个概念,并得到最小的细节,以帮助我们理解。这篇文章应该澄清了大部分关于为什么内核技巧有效的问题,包括在无限维中工作意味着什么?我们将从最常见的例子开始,然后扩展到一般情况。

Figure 1: Example of a labeled data inseparable in 2-Dimension is separable in 3-Dimension. Source: [2]

在上面的例子中,原始数据是二维的。假设我们把它表示为, 𝐱 ={𝑥₁,𝑥₂}.我们可以在图 1(左图)中看到 𝐱 在其空间中是不可分的。但是它们在由下式给出的变换空间(见图 1,右侧)中是可分离的,

其中,φ是应用于 𝐱 的从二维到三维的变换函数。这些点也可以用φ(𝐱)→x₁、 x ₂变换分开,但是 Eq 中的那个。上面的 2 将有助于解释高维空间的使用。√2 不是必要的,但会使我们的进一步解释在数学上更方便

等式中的φ。2,现在我们可以在三维空间中有一个决策边界,

如果我们做一个逻辑回归,我们的模型会像方程。3.在 SVM,一个类似的决策边界(一个分类器)可以使用内核技巧找到。为此,我们需要找到⟨φ(𝐱𝑖),φ(𝐱𝑗)⟩的点积(见等式)。13 英寸〔4〕)我们就这么办吧。我会这样做,

我的方式:

相反,我的朋友萨姆更聪明,他做了下面的事情,

有什么不同?

计算操作:

  • 我的方式:达到情商。在图 4a 中,我执行 3×2 的计算,以将𝐱I 和 𝐱 𝑗中的每一个变换到φ的三维空间中。之后,我们在φ(𝐱𝑖)和φ(𝐱𝑗)之间执行点积,它有 3 个额外的运算(在等式中)。4b)。总计:9 次操作。
  • 山姆之道:直到 Eq。5b,Sam 做了 2 次运算。最后,在 Eq。5c,他又做了一次计算。总计:3 次操作。请注意,在等式中。5b 我们对一个标量求平方,因此只有一个操作。

计算空间:

  • 我的方式:我对我的数据 𝐱 应用了映射转换函数φ。然后在φ空间(一个三维空间)执行我的操作。
  • 山姆之道:山姆没有应用变换功能。他停留在最初的二维空间,得出了和我在三维空间计算时一样的结果。

萨姆绝对比我聪明。他所做的被证明是核心的把戏。但我不会就这样离开。让我们用更多的例子来讨论它。

假设我需要一个比等式 1 更大的表达式来表示我的决策边界。3(因为我们期望它工作得更好),它同时具有一阶和二阶项,

让我们再看看我和山姆的方式,

我的方式:

山姆的方式:

再次比较我的方式山姆的方式:

  • 我必须明确定义φ。虽然有人可能会说,山姆也必须明确地知道将 1 加到 𝐱 𝑖、 𝐱 𝑗的点积上,但是我们很快就会看到,山姆的方法很容易推广。
  • 我的方式采取了 16 的操作,山姆的方式仍然只采取了 3 的操作。(再次注意,在等式中。8a,我们正在平方一个标量,因此只有一个操作。)
  • Sam 再次没有离开原来的 2-D 空间去寻找我在 5-D 空间中找到的相同的相似性度量(点积也是相似性度量)。

同样的,我们可以不断往更高维度发展。如果是 Sam,他可以很容易地找到在 9 维空间中具有三阶项的相似性度量,

山姆的方式:

在这一点上,我甚至懒得走自己的路。我希望你明白为什么萨姆的方式明显比我的好。他只是在原始空间中计算点积,并将结果(标量)提升到幂。这和高维空间中的点积完全一样。

这正是内核的诀窍。让我们从 Sam 的方法中总结一下内核的窍门。

  • 内核:在上面的例子中,Sam 使用的内核函数是,

  • 映射函数:Sam 不需要知道 3 维、5 维或 9 维的映射函数φ来获得这些高维空间中的相似性度量(点积)。

神奇回顾:山姆需要做的就是意识到有更高维度的空间可以分离数据。选择一个相应的内核,瞧!他现在在高维空间工作,同时在原来的低维空间做计算。他还在分离早期不可分割的数据。Sam 到目前为止使用的内核示例是线性内核的特例,

在无限维中内核技巧是如何工作的?

我们知道,核可以找到无限维空间中的相似性,,而不需要在无限维空间中进行计算。如果到目前为止你还和我在一起,现在准备好迎接这个疯狂的时刻吧。

这是魔术背后的诀窍。我将用一个高斯核(也称为径向基函数,RBF)来展示这个技巧,同样的逻辑可以扩展到其他无限维核,如,指数,拉普拉斯等。

高斯核被定义为,

为简单起见,假设𝜎=1.方程中的高斯核。10 然后可以扩展为,

根据萨姆的计算,现在我们知道⟨、𝐱、𝑖、𝐱和𝑗⟩ⁿ将放弃𝑛-order 条款。由于高斯函数有一个无穷级数展开,我们得到了直到无穷的所有阶的项。因此,高斯核使我们能够在无限维中找到相似性。在这个例子中,我们要做的所有计算也是找到𝐱𝑖和𝐱𝑗之间的平方欧几里德距离,并找到它的指数(计算发生在原始空间)。

所以 Sam 在使用内核时没有什么可担心的了?

他有。最后,他确实需要

  • 来选择使用哪个内核函数。[ 1 ]有一个详尽的内核列表可供选择。而且,
  • 调整内核的超参数。例如,在高斯核中,我们需要调整𝜎.T21 有一份关于这方面的论文列表。

我们需要先知道合适的核函数吗?

是的,我们确实需要确定哪个内核函数是合适的。然而,我们不需要先了解它。首先,我们必须认识到线性决策边界是行不通的。当我们看到模型精度很差时,就会意识到这一点,如果可能的话,可以使用一些数据可视化(例如图 1)。当意识到线性边界是行不通的时候,我们开始使用内核技巧。

大多数内核将导致非线性的、可能更好的决策边界。[ 1 ]给出了一个详尽的选择列表。但是没有直接的方法知道哪个核函数将是最佳选择。传统的机器学习模型优化方法,如交叉验证,可用于寻找性能最佳的核函数。

然而,由于使用核技巧没有额外的计算来分离一些高维或无限维中的数据点,人们通过使用高斯(RBF)核来处理无限维。RBF 是最常用的核。

简而言之,作为一个经验法则,一旦你意识到线性边界是行不通的,尝试一个非线性的 RBF 核边界。

结论

在这篇文章中,我们介绍了内核技巧的基本细节。我们的目标是理解内核技巧。我们还找到了内核技巧如何在不增加计算量的情况下在无限维中找到点积(相似性)的答案。

如果你有不明白的地方,请留下你的评论。

免责声明:这是我之前在 Quora 上针对这个问题发表的帖子的编辑版本, 什么是内核诀窍 也是 Quora 博客 这里

参考

[1] 机器学习应用的内核函数

[2] [伯克利 CS281B 讲座:内核诡计](https://people.eecs.berkeley.edu/jordan/courses/281B-spring04/lectures/lec3.pdf%20(https://people.eecs.berkeley.edu/jordan/courses/281B-spring04/lectures/lec3.pdf)

[3] 支持向量机:参数

[4] [支持向量机:讲座(斯坦福 CS 229)](http://cs229.stanford.edu/notes/cs229-notes3.pdf (http://cs229.stanford.edu/notes/cs229-notes3.pdf)

特朗普、推特和贸易

原文:https://towardsdatascience.com/trump-tweets-and-trade-96ac157ef082?source=collection_archive---------26-----------------------

用 Python 中的主题建模和情感分析交易标题驱动的标准普尔 500

Photo by 🇨🇭 Claudio Schwarz | @purzlbaum on Unsplash

特朗普总统最近用现代的天字第一号讲坛(他的推特)重创了金融市场。随着美国和中国继续各自的姿态,与中国正在进行的贸易摩擦已经升温。上周日,新一轮针对中国商品的关税生效,这一次,美国的消费者很可能将承担 15%关税增长的负担。围绕贸易谈判方向的不确定性仍然存在,除非取得重大突破,否则股市将继续受到特朗普总统言论的推动。

对交易员来说幸运的是,总统并不羞于在推特上发表他对贸易的短期观点。标准普尔 500 指数的交易策略能利用特朗普总统的贸易相关推文预测市场的短期走势吗?我转向主题建模和情感分析来寻找答案。总体项目设计和工作流程如下:

  1. 数据收集和预处理:收集原始推文并进行预处理,以将标记化和词条化的单词传递给主题模型。
  2. 使用 LDA 的主题建模:主题建模用于为每条推文分配一个主题。只有与贸易话题相关的推文被传递用于情绪分析。
  3. VADER 的情感分析:识别出与交易相关的推文后,每条推文都被赋予一个情感分数。情绪得分被作为交易策略的核心输入。
  4. 回测标准普尔 500 指数数据的交易策略:一旦情绪得分被分配,定制的交易策略被设计成根据重要的情绪得分进行交易。

让我们进入项目的一些细节,并以结果的讨论来结束!

数据采集和预处理

特朗普总统的 7,779 条推文是从他上任的第一天(2017 年 1 月 21 日)到 2019 年 8 月 14 日收集的。预处理是必不可少的,以确保主题模型能够准确识别与贸易相关的推文。

使用 Gensim 和 nltk python 库执行了以下预处理步骤:

  • 包含不到 20 个字符的推文(总共 375 条推文)被视为噪音,随后被删除。
  • 推文被符号化;句子被拆分成单个的单词,单词全部小写,标点符号被删除。
  • 使用了 nltk 中的默认停用词,以及自定义停用词。识别自定义停用词的过程是迭代的,并且包括诸如“假货、新闻、詹姆斯·科米、波多黎各等”的词,这些词主导了与贸易无关的推特话题。
  • 单词被词条化以减少每个单词的基本形式。
  • 二元模型后来被用于主题建模。选择二元模型来捕捉围绕单个短语的上下文。
  • 最后,为了让 gensim 的数据更友好,一个详细记录一个单词在所有推文中出现次数的单词字典被创建出来。Gensim 还需要一个语料库——为每条推文创建一个字典,其中包含推文中出现的单词数量以及每个单词在推文中出现的次数。

词汇化和二元模型阶段后的预处理 tweet 示例:

['china', 'intent', 'continue', 'receive', 'hundred', 'billion', 'dollar', 'take', 'unfair', 'trade', 'practice', 'currency', 'manipulation', 'one_side', 'stop', 'many', 'years_ago']

用 LDA 进行主题建模

经过预处理后,语料库和词袋词典被传递给潜在的狄利克雷分配(LDA)主题模型。参见这里的 python 中 LDA 模型的演示。简而言之,LDA 可以用来为给定推文的主题概率分布建模。

例如,考虑这样的情况,LDA 给一条推文分配 50%与贸易相关的机会,25%与移民相关的机会,以及 25%与医疗保健相关的机会。鉴于该推文的主题概率分布的细分以及贸易主题具有最高概率的事实,该推文可以被归类为与贸易相关的。

为 LDA 模型指定的主要超参数是主题的数量。经过多次迭代和一些关于主题适当分离的主观判断,30 个主题产生了最好的结果。

lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus,id2word=id2word,
num_topics=30, passes = 10)

我使用 pyLDAvis 来可视化模型分离主题的能力。下面的主题间距离图显示了一些主题之间的轻微重叠,但总的来说,该模型表现出了令人满意的分离水平。

通过分析 LDA 模型中的 30 个主题,主题 9 因其捕捉与中国贸易相关的术语的能力而脱颖而出。下面的 pyLDAvis 输出中还列出了主题 9 的相关术语的完整列表。

LDA model exhibited adequate separation of topics. Topic 9 in particular was able to capture terms related to trade with China.

一旦我对主题 9 识别与贸易相关的推文感到满意,与其他主题相关的推文就会被删除。结果只剩下 590 条推文。我对推文子集进行了最后一次扫描,以确保模型正确标记推文。原始推文及其主题百分比贡献的示例如下所示:

“So far you’ve had Tariffs imposed on 300 Billion Dollars worth of Chinese products but you can’t tell me that it has hurt our economy…; it really hasn’t led to any kind of serious rise in prices at the consumer level. And we are taking in $Billions!”Dominant Topic: Trade
Topic Percent Contribution: 0.653

上面的例子和剩余的推文子集表明,LDA 模型在识别与贸易相关的推文中通常是准确的。由于对主题建模结果感到满意,我将注意力转向了情感分析。

VADER 的情感分析

在找到相关的推文子集后,我使用效价感知词典和情绪推理器(VADER)分析来生成情绪交易信号。VADER 是一个预先训练好的情感模型,特别适合社交媒体文本。建立 VADER 模型和下载现有词典轻而易举。点击这里深入了解 VADER 的应用。

from nltk.sentiment.vader import SentimentIntensityAnalyzer
analyser = SentimentIntensityAnalyzer()
nltk.download('vader_lexicon')
sia = SentimentIntensityAnalyzer()

VADER 接受一串文本作为输入,并返回一个正面的、中性的、负面的和复合的情感分数。重点放在检查复合分数上,它很好地概括了文档的整体情感。复合得分范围从-1(极负)到 1(极正)。在下面的例子中,川普总统表达了对***的赞扬,随后 VADER 给这条推文的综合评分为 0.8439。

I know President Xi of China very well. He is a great leader who very much has the respect of his people. He is also a good man in a tough business. I have ZERO doubt that if President Xi wants to quickly and humanely solve the Hong Kong problem he can do it. Personal meeting? {'neg': 0.082, 'neu': 0.693, 'pos': 0.225, 'compound': 0.8439}

所有与交易相关的推文的综合得分都被收集起来。为了确定最有能力在短期内推动市场的推文,带有大量积极或消极情绪的推文被分离出来。

  • 积极情绪:综合得分> 0.7
  • 负面情绪:复合得分< -0.7

Tweets that did not meet the sentiment cutoff were dropped and as a result the final subset of data included 194 trade-related tweets with significant sentiment scores.

Backtesting Trading Strategy on S&P 500 Data

After finding the final set of 194 tweets, I developed a straightforward custom trading sentiment strategy to backtest on the S&P 500. Before diving into the details of the trading logic, it’s important to cover some key details and assumptions I made prior to developing the trading strategy:

  1. The SPDR S&P 500 ETF (Ticker: SPY) was used as a tradable proxy for the S&P 500 Index.
  2. The benchmark to compare the trading strategy against was a simple buy-and-hold SPY strategy.
  3. The granularity of available and free historical pricing data was restricted to open and closing daily SPY prices. As an individual, obtaining tick-by-tick pricing data for the last two and a half years was not feasible. 结果,回溯测试交易被限制在开市或闭市。理想情况下,一旦从特朗普总统的推特(twitter)消息中识别出一个值得未来调查的信号,就应该立即进行交易。
  4. 没有借贷成本就可以利用杠杆。
  5. 交易成本是不存在的。
  6. 如果一天内产生了多个信号,信号的平均值决定了交易的方向。

虽然上面的第四点和第五点是理想化的,是为了使计算更容易,但它们有助于抵消第三点所述限制(信号和交易执行之间的时间间隔)导致的假设的负面后果。尽管如此,重要的是要指出,更现实的假设,如借款和交易成本,将对任何交易利润产生负面影响。

现在所有的关键假设都已经涵盖,我们可以把注意力转向交易策略的发展。任何情绪交易策略的核心都是这样一个理论,即当情绪高涨时,动物精神会推动市场上涨,当情绪受挫时,动物精神会推动市场下跌。鉴于总统拥有制定关税政策的行政权力,他的情绪应该会对美国股票价格产生相当大的影响。积极关注股价和特朗普总统推特消息的市场参与者可能会同意这种相关性在现实中成立,但让我们看看利用总统短期情绪的策略是否真的有利可图。下面详细列出了基本情况、积极情绪信号和消极情绪信号的每日交易策略逻辑:

基本情况:无交易信号

  • 投资组合只包含 100%的间谍

积极的情绪信号:将投资组合的间谍敞口提高到 200%,持续 1 个交易日

  • 开市前出现信号s:开市时买入,收盘时卖出
  • 信号发生在市场时段:收盘时买入,明天收盘时卖出
  • 信号在小时后出现:在明天开盘时买入,在明天收盘时卖出

负面情绪信号:卖出投资组合头寸,并在 1 个交易日内保持 0%的间谍敞口

  • 开市前出现信号:开市时卖出,收盘时回到 100%的间谍敞口**
  • 信号出现在市场时段:收盘时卖出,明天收盘时恢复 100%的间谍敞口
  • 信号在盘后出现:在明天开盘时卖出,在明天收盘时回到 100%间谍暴露**

简而言之,该策略旨在增加对美国股价上涨的敞口,减少对美国股价下跌的敞口。让我们看看交易策略在 2017 年 1 月 21 日至 2019 年 8 月 14 日的回测中表现如何。在下图中,策略投资组合用蓝线表示,而基准间谍买入并持有投资组合用灰线表示。此外,绿色箭头表示触发买入信号的日期,红色箭头表示触发卖出信号的日期。

交易策略在回溯测试期间的回报率为 85.3%,而简单的买入并持有策略同期的利润为 56.7%。虽然回溯测试的结果令人鼓舞,但让我们花点时间思考一下为什么该策略的表现优于其基准,并讨论一下回溯测试的局限性。

快速眼球测试表明,大部分买入信号是在市场上涨趋势中产生的,卖出信号是在小幅抛售时产生的,这对策略来说是个好消息。然而,这种策略也有可能只是运气好——在趋势性牛市中,发出更多买入信号而不是卖出信号,听起来肯定是跑赢市场的好方法。记住这两点,是时候提醒大家相关性并不意味着因果关系。特朗普总统的情绪真的导致了市场波动吗?还是这些推文恰好与其他市场变动事件如经济数据发布或美联储演讲相吻合?理解特朗普推文的实际效果是一个完全不同的问题;不同于这个项目的动机是看看利用特朗普总统的情绪是否有利可图。目前,我们只能说川普总统的情绪很有可能与市场回报正相关。****

回溯测试的一个更明显的限制是,它只是…对过去的测试。找到一个有利可图的回溯测试是一项有价值的研究,但是任何交易策略的真正成功是它在未来实时数据中的表现。

最后,让我们回忆一下,回溯测试没有考虑借贷或交易成本。将这些包括在计算中会降低策略的表现和未来的任何预期利润。

结论

总的来说,使用 LDA 和 VADER 情绪分析的主题建模是解析总统推特上的噪音并隔离他对中国贸易的情绪的可能解决方案。根据回溯测试期间产生的情绪信号进行交易是有利可图的,优于简单的买入并持有策略的表现令人鼓舞,足以考虑根据实时数据跟踪该策略的表现。未来的工作,如格兰杰因果分析和事件研究,以分离特朗普贸易推文的实际市场效应,也值得追求。

投资者关心总统对贸易的政策和言论,在贸易战解决之前,请关注唐纳德·特朗普的推特。

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

附录

领英

机器学习中的信任和可解释性

原文:https://towardsdatascience.com/trust-and-interpretability-in-machine-learning-b7be41f01704?source=collection_archive---------12-----------------------

机器学习模型总是需要可解释的吗?如果要在不准确的可解释模型和准确的不可解释模型之间做出选择,你会选择不可解释但准确的模型吗?换句话说,在可解释性的祭坛上牺牲准确性有任何理由吗?

在进一步探讨之前,我们应该试着澄清是什么使得一个模型是可解释的。通常,可解释性等同于简单性。这个定义明显模糊不清;对一个人来说简单的事情对另一个人来说可能不简单。更重要的是,高级机器学习对复杂系统建模最有用。这些系统被称为复杂是有原因的——它们并不简单!无论如何,要求这种系统的有用模型应该简单是没有意义的。

也许,如果我们考虑如何在传统的建模环境中思考可解释性,我们可以走得更远。考虑汽车内燃机的数学模型。我怀疑是否有人会认为这很简单。但是,另一方面,我也怀疑是否有人会认为内燃机的模型是不可解释的。这主要是因为我们可以从热力学和流体动力学等成熟的物理理论中推导出这个模型。

为什么不用这个作为我们对可解释性的定义呢?如果一个模型可以从一个值得信赖的理论中推导出来(或者至少有动机),那么它应该被认为是可解释的。这个可解释性的定义服务于理解和信任的双重目的。它帮助我们理解模型,因为我们倾向于以演绎的方式理解事物——从已知到未知。同样,有了这样的定义,模型中的信任来源于我们对基础理论的信任。

事实上,有些情况下理解和信任都是必要的——在这些情况下,我们有兴趣确定系统行为背后的因果因素。在这样的场景中,我们必须坚持相应的模型必须根据上述定义是可解释的。物理科学领域的大多数模型都属于这一类。有人可能会说,纯粹的感应黑盒模型不适合这种情况。

然而,在许多其他情况下,理解可能是很好的,但绝不是必须的。在这些情况下,真正重要的是做出可信预测的能力。在这些情况下,如果我们能够提供一个替代的信任源,那么我们的模型就不需要被上面给出的可解释性定义所束缚。这是一个常见的论点,也有可取之处。请记住,机器学习是一种使用归纳推理从(最好是)大量数据中系统地建立模型的方法。限制这些模型以演绎的方式解释会严重限制它们的准确性。

因此,接下来的问题是,我们如何在一个我们对其内部运作知之甚少甚至一无所知的黑盒模型中产生信任。可信的信任基础可能是测试。毕竟,测试是我们信任常规软件的基础。但是为了测试一个模型,我们需要能够形式化我们对它的期望。如果我们能够完全形式化我们的期望,那么这将对应于模型本身的完整规范。在这种情况下,我们真的不需要机器学习或任何其他建模方法。我们真正需要做的是将我们对模型中我们认为重要的方面的期望正式化。这也不容易,因为我们关心的许多概念,如公平,并不适合于方便的数学处理。

值得指出的是,在开发测试机器学习模型的测试方法方面已经取得了重大进展。我个人认为使用变形关系来形式化期望的想法特别有前途。但是,我们距离拥有允许我们对黑盒模型进行全面测试的具体方法还有很长的路要走,我们的这种无能导致了黑盒模型中的信任赤字。

人们可能会质疑这种基于预期的全面测试的有效性。毕竟,机器学习的目标是在数据中发现未被发现的模式。坚持认为模型符合我们的期望相当于预先定义了模型,这违背了整个目的。按照这种推理方式,人们会认为,只要数据具有代表性,并且我们的算法足够强大,能够捕捉到模式,就没有理由不相信模型——我们应该期望模型结果能够推广到总体,并且我们应该期望它们推广的程度包含在模型的性能(准确性)得分中。

因此,本质上,我们被要求将我们的信任委托给数据、算法和性能分数这三者。我们首先需要说服自己不要认为一个单一的性能(准确性)分数就可以构成信任模型的充分基础。性能分数通常是在给定当前数据的情况下,模型在总体上的平均推广程度的点估计值。另一方面,信任是一个微妙的多维度概念,无法用这么一个粗粒度的分数来概括。人们可以想象定义更精细的绩效分数,例如通过人口细分。但是,这需要对人口有一定程度的了解,并确定我们认为什么是重要的——这与形成预期没有太大区别。

让我们检查这个论点的数据方面。事实上,很容易说服自己,如果数据代表我们感兴趣的人群,那么它应该包含所有相关的模式,而不是虚假的。不幸的是,情况很少如此。数据的无代表性程度取决于具体情况。尽管如此,我们可以确定某些高级场景。

在第一个场景中,我们将对人口有很好的了解,并完全控制数据收集机制。在这种情况下,我们可以选择具有代表性的数据,并且有很高的可信度,我们可以预期我们的结果模型的预测适用于总体人口。但是,请注意,对总体有足够好的了解,能够为手头的任务绘制代表性样本,这意味着我们已经对哪些特征对预测很重要有了一些了解。因此,在这种情况下,黑盒模型是否非常有用是有争议的。预测选举结果的民意调查就是这种情况的一个很好的例子。

在第二种情况下,我们不能完全控制数据收集,但是我们的预测不会影响收集的数据。在这种情况下,如果我们假设数据收集机制是无偏的,那么如果我们等待足够长的时间,我们将得到一个具有代表性的总体样本。当然,这个假设有很多如果和但是。首先,人们不知道多长时间才算够长。因此,人们需要假设收集数据的时间尺度足够长,足以产生代表性样本。此外,在此期间,人口本身也可能发生变化。因此,另一个假设是,人口变化的时间尺度比产生代表性样本的时间尺度长得多。只要我们能够证明这些假设,那么估计的性能将是可靠的。预测股票价格的模型就是这种情况的一个例子——只要我们没有进行大到足以影响整个市场的投资,我们根据预测结果做出的决策就不会影响股票价格。

第三种情况是,数据收集受到预测的影响,但我们对错误预测的风险偏好从中度到高度不等。这方面的一个例子是产品推荐系统。推荐系统的模型将在由不同用户已经购买/点击的产品的有序列表组成的数据上被训练。基于这些数据,模型将预测用户最有可能购买/点击什么,并且基于模型的预测,系统将决定用户可以看到什么,这限制了他可以购买/点击什么。因此,预测会使数据收集产生偏差。在产品推荐系统中,人们可以通过保留一个探索预算来在某种程度上规避这个问题——对于一小部分情况,系统向用户显示一组随机的产品,而不管模型的预测。从这些随机预测中得到的观察结果可以用来估计模型的性能。为了获得这些估计的可靠性,人们仍然必须解决上述第二种情况的问题。

在第四个也是最后一个场景中,数据收集受到预测的影响,但是我们对错误的预测几乎没有风险偏好。例如,假设我们必须建立一个模型来预测某人是否会拖欠抵押贷款。抵押贷款将根据预测批准或不批准。如果预测是这个人会违约,那么贷款将不会被批准,在这种情况下,没有办法知道这个人是否真的会违约。很难想象一家机构会为了数据探索而随机批准(或以其他方式)一笔贷款。在这些情况下,在没有额外信息的情况下,很难衡量所得模型的估计性能的可靠性。

因此,盲目地期望数据能够代表总体并不是一个好主意。在大多数情况下,考虑到手头问题的限制,可能根本不可能获得无偏见的代表性样本。了解一个人的数据收集机制的局限性,能够推断出这些局限性的含义,并诚实地将这些作为模型结果的一部分进行报告,这对建立信任大有帮助。

现在让我们考虑一下论证的算法方面。人们普遍认为算法越灵活越好,因为灵活性使算法能够捕捉更复杂的模式。但是,如果机器学习的实际成功应用的历史可以借鉴的话,那么这种信念似乎是完全错误的。在计算机视觉中,当我们能够以卷积神经网络的形式将图片中的对称性编码到模型中时,成功就来了。在自然语言处理中,我们现在能够构建极其精确的跨用途语言模型,因为我们可以将我们关于语言的知识,包括结构和单词上下文,编码到这些模型中。在推荐系统中——包括矩阵分解方法在内的大多数协同过滤算法,对用户对某个项目的亲和力做出了强有力的假设。

不管我们愿不愿意给这些模型贴上可解释性的标签,当我们理解了模型需要运作的领域和环境时,我们会构建更好的模型,这是一个客观事实。最好的模型不是来自最灵活的算法,而是来自受到领域知识很好约束的算法,这些算法具有恰到好处的灵活性来捕捉数据中的相关模式。

在上面的讨论中,我们已经多次看到理解这个词。我们现在应该已经意识到,没有理解就很难建立信任。最终,它归结为一个人如何看待机器学习。是的,机器学习是一种非常强大的归纳建模技术。当与大数据和大计算相结合时,它允许我们对系统进行建模,并解决以前我们力所不及的问题。但是机器学习的进入不应该意味着其他一切的退出,包括常识。机器学习是更广泛的建模家族中的一个元素,包括演绎建模以及领域知识。我们越好地理解和利用这些元素之间的相互联系,我们就能更好地进行健壮的复杂系统建模。

信任是有背景的,信任可以有多种来源,但最终它来自知识和诚信;特别是我们对构建模型的个人的知识和诚信的信任。在我看来,只有当更广泛的受众相信建模者有知识理解他们的模型的局限性(机器学习或其他),并诚实地报告它们时,信任以及模型的采用才会到来。

信赖域和最近策略优化

原文:https://towardsdatascience.com/trust-region-and-proximal-policy-optimization-b10b33a9becc?source=collection_archive---------17-----------------------

Photo from Deepmind

欢迎来到揭开强化学习背后秘密的另一个旅程。这一次,我们将后退一步,回到策略优化,以介绍两种新的方法:信赖域策略优化(TRPO)和邻近策略优化(PPO)。请记住,在策略梯度技术中,我们试图使用梯度下降来优化策略目标函数(预期的累积回报)。政策梯度对于连续的大空间是很好的,但是也有一些问题。

  • 高方差(我们用演员-评论家模型来解决)
  • 延迟奖励问题
  • 样品低效
  • 学习速度对训练有很大影响

特别是最后一个问题困扰了研究者很长时间,因为很难找到一个适合整个优化过程的学习速率。小的学习率可能导致梯度消失,而大的学习率可能导致梯度爆炸。总的来说,我们需要一种方法来改变政策,不要改变太多,也不要改变太少,甚至更好的方法来不断改进我们的政策。这方面的一篇基础论文是:

信任区域策略优化(TRPO)

为了确保策略不会移动得太远,我们在优化问题中添加了一个约束,以确保更新后的策略位于信任区域内。信赖域被定义为函数的局部近似精确的区域。好吧,但那是什么意思?在信任区域中,我们确定最大步长,然后我们在区域内找到策略的局部最大值。通过重复同样的过程,我们找到了全局最大值。我们还可以根据新近似的好坏来扩大或缩小区域。这样,我们就可以确信,新政策是可信的,不会导致严重的政策退化。我们可以用 KL 散度(你可以把它想象成两个概率分布之间的距离)从数学上表达上述约束:

新旧政策的 KL 背离必须低于 delta (δ),其中 delta 是地区的大小。我可以进入一些数学领域,但我认为这只会使事情变得复杂,而不是澄清它们。所以本质上,我们只有一个约束优化问题。

现在的问题是我们如何解决一个约束优化问题?使用共轭梯度法。当然,我们可以解析地解决这个问题(自然梯度下降),但这在计算上是无效的。如果你对数值数学有所了解,你可能会记得共轭梯度法提供了一个方程组的数值解。从计算的角度来看,这要好得多。所以我们要做的就是线性逼近目标函数,二次逼近约束,让共轭梯度完成它的工作。

总而言之,该算法有以下步骤:

  • 我们运行一组轨迹并收集策略
  • 使用优势估计算法来估计优势
  • 用共轭梯度法求解约束优化问题
  • 重复

一般来说,信赖域被认为是解决最优化问题的非常标准的方法。棘手的部分是将它们应用于强化学习环境中,以提供优于简单策略梯度的优势。

虽然 TRPO 是一个非常强大的算法,但它有一个严重的问题:血腥的约束,这给我们的优化问题增加了额外的开销。我的意思是,它迫使我们使用共轭梯度法,并用线性和二次近似法来迷惑我们。如果能够以某种方式将约束直接包含到我们的优化目标中,这不是很好吗?正如您可能已经猜到的那样,这正是最近策略优化所做的。

近似策略优化(PPO)

这个简单的想法给了我们一个比 TRPO 更简单、更直观的算法。事实证明,它在大多数情况下都优于许多现有的技术。因此,我们不是单独添加一个约束,而是将它合并到目标函数中作为惩罚(我们从函数中减去 KL 散度乘以常数 C)。

一旦我们这样做,就不需要解决约束问题,我们可以在上述函数中使用简单的随机梯度下降。并且该算法被转换如下:

  • 我们运行一组轨迹并收集策略
  • 使用优势估计算法来估计优势
  • 对目标函数执行随机梯度下降一定数量的时期
  • 重复

一个小警告是,很难选择系数 C ,使其在整个优化过程中工作良好。为了解决这个问题,我们根据 KL 散度的大小来更新系数。如果 KL 太高,我们增加它,或者如果它太低,我们减少它。

就这样吗?这就是著名的近端策略优化?实际上没有。很抱歉。原来上面说的功能和原纸不一样。作者找到了一种方法来改进这个惩罚版本,使其成为一个新的、更健壮的目标函数。

嘿嘿等等。这里发生了什么?其实不多。让我解释一下。到目前为止,我故意忽略了一件事,那就是概率的分数,它似乎也出现在 TRPO 中。这就是所谓的重要抽样。我们基本上有一个新的政策,我们想评估和一个旧的政策,我们用来收集样本。通过重要性采样,我们可以用旧策略中的样本评估新策略,并提高采样效率。这个比值可以推断出这两种策略有多大的不同,我们用 r(θ)表示。

使用这个比率,我们可以构建一个新的目标函数,如果新政策远离旧政策,则将削减估计的优势。这正是上面的等式所做的。如果一个动作在新策略下比旧策略下更有可能发生,我们不想过多地更新动作,所以我们裁剪了目标函数。如果在新策略下比旧策略下可能性小得多,则目标动作被展平以防止再次过度更新。

可能只有我一个人,但我想我已经有一段时间没碰到更简单更干净的强化学习算法了。

如果你想进入兔子洞,查看来自 OpenAI 的基线代码,它会给你一个整个算法的水晶般清晰的图像,并解决你所有的问题。当然,如果你尝试自己一个人从零开始实现,那会好得多。这不是最容易的任务,但为什么不呢。

我想现在就这样吧。继续学习…

如果您有任何想法、评论、问题或者您只想了解我的最新内容,请随时在LinkedinTwitterinsta gramGithub或在我的

要阅读完整的深度强化学习课程,学习所有你需要了解的人工智能知识,去 这里

原载于 2019 年 1 月 11 日sergioskar . github . io

尝试将脸书预言家用于时间序列模型

原文:https://towardsdatascience.com/trying-facebook-prophet-for-time-series-model-3170cfd416fa?source=collection_archive---------13-----------------------

当我在研究生院学习时间序列时,我的教授告诉我 Python 中没有他认为有用的好的时间序列包。最近,我了解到脸书发布了一个关于 Python 和 R 的时间序列模型的 API,名为脸书先知。由于我也有一个小项目,对 R 中的 SFO 客流量进行预测,我很高兴有一个在 Python 中构建时间序列的选项,所以我尝试了一下。

对 2018-2019 年 SFO 客运量进行预测
我做的项目是用我在研究生院学过的时间序列模型,建立一个模型来预测 2018-2019 年 R 月客运量。我从 Open SF 获得了客流量数据,并用 Holt-Winters 和 Box-Jerkins 方法(特别是 ARIMA 和萨米亚)训练了模型。您可以在本文末尾的链接中找到我的 Github 资源库。

下面的图片是我为霍尔特温特斯,ARIMA 和萨米亚模型建立的情节。

Plot of Holt-Winters model

霍尔特-温特斯方法通过使用指数平滑技术进行预测,换句话说,该模型是通过采用指数加权移动平均来学习的,不需要任何假设。

Plot of ARIMA model

Plot of SARMIA model

Box-Jenkins 方法是一种自回归综合移动平均模型,通过将数据集转换为平稳的来学习。我用了 ARIMA 和萨里玛模型。两者的区别在于 ARIMA 是非季节性的,而萨里玛是季节性的。

在 R 中,您可以通过使用预测包中的以下代码来避免学习超参数的麻烦。

library(forecast)
auto.arima()

但是使用 auto.arima()的缺点 R 学习的超参数不一定是最优的。例如,为 ARIMA 模型学习的超参数 R 是 ARIMA(0,1,0 ),预测完全基于上一时段。这就是为什么这个项目中 ARIMA 模型的情节看起来很好玩。

为了评估 3 个模型中的模型,我使用 RMSE 作为度量。霍尔特-温特斯、ARIMA 和萨里玛模型的 RMSE 分别为 0.1342、0.6746 和 0.1812。因此,我认为霍尔特-温特斯模型是这些模型中预测效果最好的模型。

脸书预言家
我对脸书预言家的第一印象还不错,因为这是我第一次看到 Python 和 Sklearn 模型的时序包。为了评估软件包是否有用,我使用相同的数据集并计算模型的 RMSE。

要使用脸书先知,您需要在 pandas dataframe 的两列中准备好您的数据集——日期和值。请注意,日期列必须是“YYYY-MM-DD”格式的日期时间数据类型(时间戳也是可以接受的)。但是,文档不建议使用其他日期时间格式。此外,日期和值的列名必须是“ds”和“y”。

一旦数据集准备好了,下一步就是为模型设置一个对象。如果你一直在用 Sklearn,这个对你来说很容易。遵循以下代码:

model = Prophet()
model.fit(dataset)

之后,您可以通过传递一个您想要预测的日期的单列数据帧作为输入来进行预测。

不幸的是,你只能使用线性模型和逻辑增长在脸书先知。Holt-Winters 和 Box-Jerkins 方法在软件包中不可用。默认情况下,线性模型是脸书先知中的默认模型。

进行预测时,文档建议使用此语法制作一个单列数据帧,并让模型进行预测。

future = model.make_future_dataframe(periods=365)
forecast = model.predict(future)

这个语法在我的项目中不起作用,因为“make _ future _ data frame(periods = 365)”返回一个 365 天的数据帧。然而,我希望的日期是 2018 年至 2019 年期间每个月的最后一天。或者,我必须手工制作数据帧。

from datetime import datetime
from dateutil.relativedelta import relativedeltafuture = [datetime(2016, 1, 1) + relativedelta(months=i, day=31) for i in range(24)]
future = pd.DataFrame(data=future, columns=[‘ds’])
prediction = model.predict(future)

“dateutil”中的“relativedelta”是 Python 中一个有用的日期包。如果您将 relativedelta(months=2,day=31)添加到 2016 年 1 月 1 日,即使您在输入中过了 31 天,它也可能会返回到 2016 年 2 月的最后一天。

一旦 dataframe 被传递给模型,它将返回我想要的结果。该模型的 RMSE 为 1.0493。事实证明,用脸书预言家学会的模型不如 r

脸书先知的另一个很好的功能是,您可以轻松地将模型和预测传递给 Plotly 进行可视化。事情就像这样简单:

from fbprophet.plot import plot_plotly
import plotly.offline as pyfig = plot_plotly(model, prediction)
py.plot(fig, filename=’fbprophet_plot.html’)

根据我得到的结果,情节看起来是这样的:

Plots for linear model in Facebook Prophet

我的想法
我其实很喜欢用脸书 Prophet 进行时间序列分析,主要是因为它的语法与 SKlearn 非常相似,而且 Python 中也有。在大数据世界中,Python 变得越来越重要,因此需要在 Python 中提供良好的时间序列。不幸的是,没有 Holt-Winters 和 Box-Jerkins 模型可用,模型学习的准确性是我关心的问题。最终,由脸书 Prophet 学习的模型的 RMSE 高于由 R 预测包学习的 Holt-Winters 模型。脸书先知是新的,我期待着开发人员添加更多的时间序列方法到这个包。

此外,我确实有一些困难的时间安装脸书先知。如果您使用的是 iOs,请确保安装了编译器和 Python 开发工具。最好的方法是用 Anaconda 安装。当你安装脸书先知时,一定要检查文档。

结论
脸书 Prophet 为用 Python 制作时间序列模型提供了很好的资源,但是缺乏成熟的统计时间序列方法来建模。如果你对应用的统计方法不是很挑剔,脸书先知是一个很好的软件包,因为它的语法与 SKlearn 非常相似,并且易于在 Plotly 中进行趋势分析。在您的 Python 代码中,您只需要有加载数据的代码,声明模型对象,用数据拟合模型,进行预测,并在 Plotly 中绘制模型。然而,如果准确性和性能是一个问题,脸书先知可能不是一个很好的选择,根据我的 SFO 客流量预测项目的结果。我建议将 Holts-Winters 或 SARIMA 在 R 中学习的模型与预测包进行比较。

总结脸书先知
优点
1。遵循 SKlearn 代码
2。进行预测的简单语法
3。Python 和 R
4 中都有。Plotly 中易于可视化的语法

缺点
1。只有线性模型和逻辑增长模型可用
2。难以安装
3。列名必须是“ds”和“y”

参考
脸书先知文档
https://Facebook . github . io/Prophet/docs/quick _ start . html # python-API

https://github.com/jacquessham/sfotraffic github 链接
T22

Polynote 的第一手体验——数据工程师的最佳笔记本

原文:https://towardsdatascience.com/trying-polynote-from-netflix-a-better-notebook-for-data-engineers-5107277ff2e5?source=collection_archive---------21-----------------------

网飞最近宣布了 Polynote ,这对致力于 Spark 和 Scala 的数据工程师来说很有希望。有许多很棒的特性,包括

  • Scala 的交互式自动完成和参数提示
  • 将 Maven 存储库中的依赖项配置为笔记本级别的设置
  • Scala 和 Python 代码在同一个笔记本中,变量在它们之间共享(也称为多语言)

让我们用 Spark 中一个经典的字数统计例子来试试 Polynote。在这个例子中,我们读取了来自网飞的 Polynote medium post 的文本,并用它用 python matlablib 绘制了一个字数统计条形图。代码可以在这里找到

装置

按照它的指南,安装过程非常简单。另外,我还安装了 matplotlib

pip3 install matplotlib

如果你打算尝试它的多语言特性(例如 Scala 和 Python 之间的共享变量),你需要再包含一个环境变量:

export PYSPARK_ALLOW_INSECURE_GATEWAY=1

如果没有,您将会看到:

编辑经验

使用笔记本级别的“配置和依赖项”设置,可以很容易地配置从 maven 存储库中提取依赖项。让我们包含请求——Scala使用 HTTP get 从网飞的博客获取我们的文本。

数据工程师终于有了一种简单的方法,通过一个集中的 maven 资源库,向笔记本用户共享他们用 Scala 或 Java 编写的代码!

自动完成功能适用于从 maven 资源库中提取的库:

然而,lambda 函数的自动完成似乎还不能工作:

火花集成

在这个字数统计示例中,我们从 HTTP 获取文本,将其标记化,并保留所有长度超过 4 个字符的标记。

Spark 也可以通过“配置和依赖”设置轻松配置:

一个小问题是,spark 配置设置中至少需要一个项目,Spark 才能工作,这一点并不明显。

切换到 Python

现在,我们切换到 python,使用 panda 和 matplotlib 绘制条形图,只取前十个单词。

它神奇地起作用。但是,在使用 python 代码运行 cell 时,有时会弹出此异常:

当这种情况发生时,接口停止工作,唯一的解决方法是终止 Polynote 进程并重新运行它。

好了

Polynote 是我迄今为止试过的最好的 Spark 和 Scala 笔记本。有一些小故障,但我相信他们会在任何时间拉平。

我很高兴看到它如何在现实生活中发挥作用。例如,与 Kerberozied 化的 spark 集群集成,并以集群模式而不是独立模式运行 spark。也许在下一篇博客中会有更多的内容。

感谢阅读,编码快乐!

seq2seq 教程的调整版本

原文:https://towardsdatascience.com/tuned-version-of-seq2seq-tutorial-ddb64db46e2a?source=collection_archive---------7-----------------------

这是我对 seq2seq 教程的更新。这个帖子的代码可以在这里找到。本次更新的目的是教育:获得关于 seq2seq 模型的更深入的见解,并实现深度学习(和 pytorch)的一些最佳实践。非常感谢 fastai 的灵感。特别有用的是 nn 教程和 fastai github repo。代码用 python 3.7.1 编写(也在 python 3.6 上测试过),使用 pytorch 版本 1.0.1.post2。

我应用的更改:

  • 代码重构:分离数据管理和模型训练的类
  • 单独的验证数据集。这提供了比训练数据更真实的模型性能图。训练损失/准确度将总是小于/高于验证集。如果没有验证集,您如何知道自己没有过度拟合?
  • 标记化是多重编码
  • 使用预训练单词向量的可能性
  • 增加了老师强行
  • pytorch 版本 1 的小代码更新。

现在让我们快速介绍一下 seq2seq,然后查看更新。

seq2seq 快速介绍

seq2eq 模型的介绍可以在原版教程中看到。在这里,我将给出非常简要的概述。Seq2seq 模型是由两个递归神经网络 (RNNs)组成的模型。其中一个将输入序列编码成上下文向量,另一个将其解码成输出序列(例如一种语言的句子到另一种语言的句子)。

Seq2seq scheme. Source

使用 seq2seq 的积极方面是任意长度的输入序列可以被“翻译”成任意长度的输出序列。从一种语言翻译成另一种语言通常比翻译单个单词更困难。输出序列可能比输入序列长或短。即使大小匹配,单词的顺序也可能不匹配。

seq2seq 学习的两个比较重要的概念是注意老师强制。注意力帮助解码器“注意”输入序列的不同部分。这通常会提高模型性能,因为更细微的学习是可能的(仅使用编码的上下文向量会给学习所有细微差别带来沉重的负担)。我鼓励你去查阅原始的教程和谷歌来了解更多的细节。我将在下面的帖子中分享其中的一些。

数据管理

Pytorch 是一个很好的处理神经网络的库。但是它没有一种简便的方法来处理 sequence2sequence 数据集。这也是为什么我写了几个助手类用于数据管理的原因。逻辑很简单:Vocab处理词汇(记号和它们相应的数字 id),SeqData处理单边序列(例如英语句子),Seq2SeqDataset处理具有相应序列的序列(例如英语句子和它们的法语翻译),并使我的数据集符合 pytorch Dataset类。Seq2SeqDataManager是一个处理整体训练和验证序列创建和管理的类。这可以从下面的方案中看出。

这些课程完全是定制的。一个例外是继承自 torch Dataset类的Seq2SeqDataset。它必须实现方法__len__(提供数据集的大小)和__getitem__(支持整数索引)。与 pytroch Dataset类兼容有助于我们稍后实现数据加载器。原始教程没有使用 pytorch 类进行数据管理。

有时输入/输出序列可能很长,这可能会使他们难以学习。这就是为什么Seq2SeqDatasetSeq2SeqDataManager可以选择过滤出符合长度标准的序列。Seq2SeqDataManager发动机罩下的所有处理:

MIN_LENGTH = 3 #min nr of tokens in sequence so that 
#sequence is kept (otherwise removed) 
MAX_LENGTH = 15 #max nr of tokens in sequence so that 
#sequence is kept (otherwise removed)
MIN_COUNT = 3 #min count of token occurences so that it is not 
#transformed to <unk> tokendata_manager = Seq2SeqDataManager.create_from_txt('data/eng-fra_sub.txt','en', 'en', min_freq=MIN_COUNT, min_ntoks=MIN_LENGTH,                                           max_ntoks=MAX_LENGTH, switch_pair=True)

批处理,数据加载器

数据加载器有助于训练,它们从训练/验证数据中抽取样本,并将其转换成一批。批处理是一组用于训练/验证的序列。更清晰的解释见下图。

Process of turning batch of input sequence to training/validation tensor

从输入序列(句子)中,我们得到记号,并从中得到记号数字 id。然后,我们从最长到最短的序列对令牌进行排序,并用填充 id 填充较短的序列(在示例 0 中)。这是在数字化序列被转换成 pytorch 张量之后完成的。当前示例中的批量大小为 3(我们有 3 个序列/句子)。为了训练,我们转置张量(改变轴 0 和 1 的顺序)。在我们每行有一个序列之前,在转置之后,我们在一行中有每个序列的第一令牌 id。

标记化和数值化在初始数据准备期间完成。使用数据加载器将一批数据转换成张量并进行转置。DataLoader是一个 torch 类,帮助迭代序列。创建一个很简单,这是我的示例中的示例:

train_dataloader = DataLoader(self.train_seq2seq,
    batch_size=self.train_batch_size, 
    collate_fn=self._collate_fn)

这就是遵从 torch Dataset有用的地方:我们可以将它作为输入提供给DataLoader。第二个参数显示了我们每次运行需要多少个序列,而collate_fn是我们的自定义函数,用于将序列转换为转置填充张量。在我们的示例中,函数执行以下操作:

#this is a bit simplified from the one in github example
#[https://github.com/RRisto/seq2seq/blob/master/seq2seq/data/data_manager.py](https://github.com/RRisto/seq2seq/blob/master/seq2seq/data/data_manager.py)
def _collate_fn(self, data:list):
        #data is list of sequences (each list element is a list of 
        #input and corresponding output token ids, example:
        #[[[1, 2, 3, 4],[1, 3, 5]],
        #[[1, 2, 3, 4],[1, 3, 5]]] #sort sequences from longest to smallest using input 
        #sequence lengths
        data.sort(key=lambda x: len(x[0]), reverse=True) 

        #zip into separate input, output sequences
        input_seq, target_seq = zip(*data)

        #turn into tensors, pad and transpose and calc seq lengths
        input_tens, input_lens = self._to_padded_tensor(input_seq)
        target_tens, target_lens = self._to_padded_tensor(target_seq) return input_tens, input_lens, target_tens, target_lens

要获得数据加载器,我们可以使用Seq2SeqDataManager并查看第一批训练:

train_dataloader, valid_dataloader = data_manager.get_dataloaders() #lets see one batch from training data
next(iter(train_dataloader))

最后一行代码应产生类似于以下内容的输出:

(tensor([[ 25, 135,  25,  95,  41,   0,   0,   0,  96, 117],
         [  0, 163,   0,  29,   5,   5,   4,   5,   5,   5],
         [  5,   5,   5,   5,   3,   3,   3,   3,   3,   3],
         [  3,   3,   3,   3,   1,   1,   1,   1,   1,   1]]),
 tensor([4, 4, 4, 4, 3, 3, 3, 3, 3, 3]),
 tensor([[  0, 162,  74,  74,  14,  65,   0,  74,  48,  48],
         [  7,   7,   7,   7,   4,   7,   4,   7,   7,   7],
         [  3,   3,   3,   3,   3,   3,   3,   3,   3,   3]]),
 tensor([3, 3, 3, 3, 3, 3, 3, 3, 3, 3]))

第一个张量是输入张量(转置,由我们的collate_fn产生),第二个是输入序列长度的张量,第三个输出张量和第四个输出序列长度的张量。

如您所见,我定制了数据处理部分,但是对于模型的数据输入,我使用了 pytorch 类。定制 pytorch 类非常方便(pytorch 文档非常有用)。这避免了从头开始编写所有内容(和一些调试),并且只定制 pytorch 中没有的内容。

学习者

为了管理编码器和解码器的初始化和训练,我创建了[Seq2SeqLearner](https://github.com/RRisto/seq2seq/blob/master/seq2seq/model/seq2seq_learner.py)类。基本上这个类初始化我们的 seq2seq 模型。创建很简单,您需要 data_manager 并指示隐藏层大小:

hidden_size=300
learner=Seq2seqLearner(data_manager,hidden_size)

在最初的教程中,事情有点松散(不是在函数/类中),这使得处理它们更容易出错。[Seq2SeqLearner](https://github.com/RRisto/seq2seq/blob/master/seq2seq/model/seq2seq_learner.py)是火炬nn.Module的子类。这继承了它的一些方法。我们可以看到我们模型的架构:

learner

产出:

Seq2seqLearner(
  (encoder): EncoderRNN(
    (embedding): Embedding(285, 300, padding_idx=1)
    (gru): GRU(300, 300, num_layers=2, dropout=0.1, bidirectional=True)
  )
  (decoder): LuongAttnDecoderRNN(
    (embedding): Embedding(269, 300, padding_idx=1)
    (embedding_dropout): Dropout(p=0.1)
    (gru): GRU(300, 300, num_layers=2, dropout=0.1)
    (concat): Linear(in_features=600, out_features=300, bias=True)
    (out): Linear(in_features=300, out_features=269, bias=True)
    (attn): Attn()
  )
)

拥有学习者类有助于将所有培训、验证和预测相关代码集中在一起。[Seq2SeqLearner](https://github.com/RRisto/seq2seq/blob/master/seq2seq/model/seq2seq_learner.py)中最重要的方法是 fit(训练/验证编码器,解码器用户给定的历元数),forward(训练/评估编码器/解码器在一个历元中的单个批次),predict(使用编码器,解码器对新序列预测输出)。

验证集

当我们训练模型时,验证集的有用性变得很明显。

#initialize learner
hidden_size=300
learner=Seq2seqLearner(data_manager,hidden_size)batch_size=100
learning_rate=0.001
learner.fit(2,learning_rate, show_attention_every=5, show_attention_idxs=[0])

我们可以看到训练产生了这样的东西:

0:0:25.0 (1 50.0%) loss train: 3.712 loss valid: 3.179
0:0:25.3 (2 100.0%) loss train: 2.491 loss valid: 3.152

这是一个具有 2 个纪元的玩具示例,但是我们已经可以看到训练损失显著减少,而验证损失几乎没有变化。原始示例使用数据中的随机文本来显示模型输出。这还不错,在我的例子中也是这样做的,但这并不能概括我们在更广泛/量化的范围内做得如何。培训损失下降得非常快,但是验证损失趋于缓慢下降,并在某个点饱和。这个点显示了我们开始过度拟合的地方。始终使用验证集!

令牌化是多核的

我还更新了令牌化,以利用多核的优势(如果您的计算机有多个内核的话)。这样做的函数在标记化模块中:

def proc_all_mp(self, strings:list, ncpus:int=None):
        #get number of cpus, make sure it is not 0
        ncpus = ncpus or num_cpus() // 2
        if ncpus == 0:
            ncpus = 1
        #apply function proc_all (basically turns string 
        #into tokens of words) to a list of strings so that strings
        # list is partitioned by number of cores 
        #each gets roughly equal size
        with ThreadPoolExecutor(ncpus) as e:
            return sum(e.map(self.proc_all, \ 
                   partition_by_cores(strings, ncpus)), [])

功能partition_by_corespartition也很简单:

def partition_by_cores(a, ncpus):    
    sz=(len(a) // ncpus) or 1 #if ncpus is more than len(a) 
    return partition(a, sz)def partition(a, sz):    
     """splits iterables a in equal parts of size sz"""
     return [a[i:i + sz] for i in range(0, len(a), sz)]

这利用了多核计算机的优势。在序列列表较长的情况下,多核处理有助于节省时间。这部分纯属抄袭 fastai 库。

预先训练的单词向量

改进模型的一种方法是初始化嵌入,不是用零或随机浮点,而是用预训练的字向量。这应该已经编码了一些关于不同单词之间关系的信息。例如,facebook 收集了这些在这里找到的。使用data_manager加载它们:

#first one is for input sequence, second output
data_manager.load_ft_vectors('data/wiki.en.vec', 'data/wiki.fr.vec')

保留当前词汇所需的向量。之后,初始化模型和训练。一个重要的注意事项:hidden_size和单词向量的长度必须匹配(例如,我希望每个单词向量的长度为 300)!

hidden_size=300 
learner=Seq2seqLearner(data_manager,hidden_size)

也可以使用自定义单词向量,从技术上讲,它们必须是字典:

hidden_size = 2 
#silly vectors with length of two and only with two tokens
x_silly_wordvector = {'this':[-0.3,0.2],'is':[0.1,0.5]}
y_silly_wordvector = {'le':[-0.4,0.2],'cat':[0.6,0.5]}learner = Seq2seqLearner(data_manager,hidden_size,
    emb_vecs_x = x_silly_wordvector, 
    emb_vecs_y = y_silly_wordvector)

尝试它们,它们使训练更快(使用更少的时期,你应该得到类似或更好的结果,因为没有预先训练的单词向量)。

在教师的强迫和关注下进行培训

原例说了几个关于老师强制的话,但没有实现(除了变量teacher_forcing_ratio被初始化但没用过)。我通过添加几行代码解决了这个问题:

if random.random() < self.teacher_forcing_ratio: 
                    #next input istaken from target
                    decoder_input = target_batches[t]                else: 
                    #next input is taken from decoder prediction
                    decoder_input = decoder_output.data.max(1)[1]

这随机选择将什么作为下一次预测的输入提供给解码器:

  • 先前解码器输出或
  • 以前的实际目标(如果高于阈值)

下图描述了为什么这很重要。

Example of teacher forcing

在模型训练期间,解码器一次给出一个输出(在图中为一个令牌)。这意味着前一个输出会影响下一个输出。解码器可能会给出错误的猜测(在图形中,真实的令牌应该是“猫”,但解码器预测的是“狗”)。这反过来可能会导致其他不可预测的输出完全错误(标记为“?”)例如)令牌。教师强制确保我们偶尔不使用解码器先前的输出作为下一个预测的输入,而是使用真实的目标值。这可能有助于模型更快地收敛。现在我们准备训练模型。

训练本身很简单:

batch_size=100
learning_rate=0.001
learner.fit(2,learning_rate, show_attention_every=5, show_attention_idxs=[0])

通常你希望有尽可能大的批量来满足你的记忆。要使用 cuda(或特定设备),只需将其设置为 fit:

learner.fit(2,learning_rate, show_attention_every=5, show_attention_idxs=[0], **device='cuda'**)

在培训过程中,您将会看到所指示的验证批次序列的注意事项show_attention_idxs=[0]指示索引为 0 的验证批次序列(第一个序列)注意事项会在每 5 个时期(show_attention_every=5)后显示。

Example decoder attention

解码器注意力只是一个应用于输入以获得输出的权重矩阵(张量)。从左图中,我们可以看到在每次输出预测中,解码器关注的是输入序列的哪一部分。例如,在输出标记“I”的情况下,注意力集中在输入标记“je”上。

训练后,学习者可以用来进行预测:

learner.predict('Je suis sûr.', device='cpu')

这可能会给出类似的输出:

i <unk> . <eos>

请注意,在训练过程中,我们为每个序列添加了一个字符串结束标记“”(以便解码器知道它何时到达了末尾)。我们可以使用我们想要的任何设备(默认为 cpu)进行预测,学习者被转换为在运行中使用该设备。

失败,棘手的部分

棘手的部分是储蓄。这是我想通过使用torch.save来使用nn.Module全部力量的地方,但是发现我的使用 spacy 的记号赋予器有酸洗的问题。相反,保存分两步完成:

  • 保存数据 _ 管理器
  • 保存学习者状态字典(点击阅读更多关于保存状态字典的信息)
data_manager.save('example_data_manager.pth')
torch.save(learner.state_dict(), 'example_state_dict.pth')

加载以相同的顺序完成,但多了一个步骤:

  • 加载数据 _ 管理器
  • 初始化学员对象
  • 向学员添加保存的状态字典
data_manager_new=Seq2SeqDataManager.load('example_data_manager.pth')
model=Seq2seqLearner(data_manager_new,hidden_size) 
model.load_state_dict(torch.load('example_state_dict.pth'))

在场景后面,data_manager 在保存期间将 tokenizer 设置为None,并在加载期间重新初始化它们。我知道,这不是最有说服力的解决方案,但我不想浪费时间,因为它毕竟只是一个教程。

摘要

这是对原始教程的温和更新。我希望你能从这篇文章中学到一些东西。为了更好地理解 seq2seq 模型,请深入研究教程代码。更好的是尝试做出改变。我希望我在以下几点上说服了你:

  • 官方的例子可能有缺陷,要持怀疑态度。努力改善他们!
  • 在 pytorch 的情况下,尽可能多地使用原始的类和方法,您不必从头开始编写所有的东西(尽管出于学习的目的,这并不是一个坏主意)
  • Seq2seq 型号很酷:)

祝你更新我的例子愉快。

在命运大令上调整多任务 Pytorch 网络

原文:https://towardsdatascience.com/tuning-a-multi-task-fate-grand-order-trained-pytorch-network-152cfda2e086?source=collection_archive---------16-----------------------

在之前的帖子中,我在 Keras ( here )中做了一些多任务学习,在完成那篇帖子后,我想在 Pytorch 中做一个多任务学习的后续帖子。这主要是因为我认为在另一个框架中构建它对我来说是一个很好的练习,然而在这篇文章中,我将讲述我如何在构建模型后做了一些额外的调整,这是我在构建基于 Keras 的模型时没有经历的。

我还将这个模型作为我在另一系列帖子中建立的面部相似度管道的一部分(第一部分和第二部分)。

简单回顾一下,多任务模型是指单个模型通过优化来解决一系列通常相关的问题。从机械上来说,这是通过将来自模型管道的某个核心部分的输出馈送到一系列输出“头”来完成的,这些输出“头”的损耗可以被评分和组合,通常通过相加,然后网络可以根据总损耗来调整其权重。

我注意到,在培训这些人的时候,集中精力提高单个任务的难度有点大,因为用于优化的损失函数是通过将各个损失函数相加而创建的。然而,通过对 Pytorch 网络的一些早期实验,我发现传统的调优策略相当有效。

我使用的基本调整策略是吴恩达在他的在线讲座中概述的策略,其中大多数机器学习算法都在方差和偏差之间进行权衡,但对于神经网络来说,情况并非如此。有了神经网络,这种权衡就不那么令人担心了,因为我们可以使用不同的机制来解决这两个问题。在网络欠拟合的情况下,您可以增加额外的计算能力,在网络过拟合的情况下,您可以应用正则化,如丢弃或批量归一化。通过平衡这两种机制的应用,您可以调整您的网络。

在这篇文章中,所有的艺术图片都用最后一批标准化 pytorch 模型的输出进行了说明。

Gender: Female, Region: Europe, Fighting Style: melee, Alignment: LG, Main Colors: [‘Silver’, ‘Gold’, ‘Blue’]. Two characters, both are from Europe, use melee weapons, are LG in alignment and the colors seem pretty good.

数据集和管道

Gender: Female, Region: Asia, Fighting Style: melee, Alignment: CG, Main Colors: [‘Red’, ‘Black’, ‘White’]. This character is European and has a Chaotic Neutral alignment but figured I should include to show that the model puts out alignments besides LG and NE

这个项目的数据集与我之前的基于 Keras 的多任务学习帖子相同,它由手机游戏《命运大令》(FGO)中大约 400 个角色的图像组成。数据集由大约 40 个不同的字符和 26 个不同的标签组成,以创建多标签样式的数据集。

这些类别包括角色的性别,他们来自的地区,战斗风格,图像的主要颜色,以及角色排列(合法的好,真正的中立,混乱的邪恶,等等)。要了解更多细节,请查看之前的帖子。

我必须做的另一个真正的修改是定制 Pytorch 数据集类,它接受一系列列表并输出图像和模型的 5 个目标向量。Pytorch 使得获取数据集类并根据需要修改它变得很容易。通常只需编写自己的 init、getitem 和 len 函数。我的大部分修改来自 getitem 部分,在那里我指定了如何读入图像并从目标列表列表中获取相应的目标,我戏称其为“列表之王”。

I like the colored code vs the grey code snippets you can add into the blog post

Gender: Female, Region: Europe, Fighting Style: melee, Alignment: NE, Main Colors: [‘Silver’, ‘Gold’, ‘Purple’]. Similar to the Keras model it looks like it has learned about the relationship between color and character alignment in the sense characters with evil alignments tend to be drawn with darker colors in FGO.

构建基本 Pytorch 模型

对于这一个,我的第一步是从一个非常基本的模型开始。我首先用 Resnet50 作为主干构建了一个模型,将它的输出送入 5 个输出头。

在 Pytorch 中构建定制网络非常简单,只需初始化需要在 init 部分优化的层和内容。然后,在 forward 部分定义数据如何流经模型。对于这个用例,我真正要做的是初始化核心模型(resnet50 ),然后将输出输入到我创建的 5 个 heads,y2o,y3o,y4o,y5o)中的每一个。这些是模型的输出,而不是你通常看到的标准的单一输出。

first model with just a Resnet50 and 5 output heads

要查看训练循环,请随意查看笔记本(此处)。很大程度上只是我在修改标准 Pytorch 网络。然而有趣的是损失函数是如何计算的。我原以为这样做起来会更复杂……但实际上非常简单……基本上我只是计算每个头部的损失(损失 0、损失 1、损失 2、损失 3、损失 4 ),将它们加在一起,然后用于反向传播。

loss0 = criterion[0](outputs[0], torch.max(gen.float(), 1)[1])
loss1 = criterion[1](outputs[1], torch.max(reg.float(), 1)[1])
loss2 = criterion[2](outputs[2], torch.max(fight.float(), 1)[1])
loss3 = criterion[3](outputs[3], torch.max(ali.float(), 1)[1])
loss4 = criterion[4](outputs[4], color.float())loss = loss0 + loss1 + loss2 + loss3 + loss4
loss.backward()

我用 Adam 优化器对这个基本模型进行了 50 个时期的训练,学习率为 0.0001,随着时间的推移而衰减,并保存了具有最佳验证损失的模型。请参见下面所有 5 项任务的得分。

val gender_Acc: 0.9390
region_acc: 0.6707
fighting_acc: 0.8537
alignment_acc: 0.7439
color_acc: 0.8384

总体不可怕,但也不伟大。然而,总的来说,它确实比我之前的文章《VGG 的 Keras》要好。

基本 Pytorch 模型通常优于 Keras 模型。这是有意义的,因为 Keras 模型使用 VGG19 模型作为冻结权重的主干,而这一轮的 Resnet 正在数据集上进行微调。

Gender: Male, Region: Middle East, Fighting Style: magic, Alignment: LG, Main Colors: [‘White’, ‘Blue’, ‘Purple’]. This one was good to see in the Pytorch model… because the Keras one would always label this character as “Female”. so this is another are where the new Pytorch models are well performing.

这是一个不错的开始,但我认为我可以提高所有车型的性能。基本上我认为 Pytorch 模型仍然不适合。作为回应,我添加了两个更密集的大小为 256 的图层,并将其输入到模型中。以下代码片段进行了修改。基本上只是增加了两层尺寸为 256 的 x1 和 x2。

Added two layers x1 and x2 for extra firepower

在训练这个新模型之后,与我构建的基本 Keras 和 Pytorch 模型相比,训练和验证准确性有所提高,总体性能更好。

一方面,我们可以称之为一天,但我在这里注意到的另一件事是,虽然模型整体表现更好,但它现在过度适应训练集。请参见下面第二款产品的得分。

 Training
gender_Acc: 0.9877
region_acc: 0.9417
fighting_acc: 0.9509
alignment_acc: 0.7577
color_acc: 0.8723Validation
gender_Acc: 0.9390
region_acc: 0.9146
fighting_acc: 0.8537
alignment_acc: 0.7439
color_acc: 0.8506

现在它是过度拟合,我想我可以添加一些正则化来尝试和抵消它。这需要一些修补,但我发现在这种情况下,相对高水平的批处理规范化是有用的。在这次运行中,我最终使用 2e-1。

added bn1 and bn2 to act as regularization

在这第三轮之后,增加了批量标准化的模型显示,在排列上比以前的最佳准确度增加了大约 10 个百分点,我认为这是最难的类别,在战斗风格上增加了 5 个百分点。而在性别和肤色上有所下降。它与给定字符的起源区域相关联。所以总的来说,我会说这部分有混合的成功,但确实有助于一个困难的类别。

Training
gender_Acc: 0.9816
region_acc: 0.9540
fighting_acc:  0.9632
alignment_acc: 0.8926
color_acc: 0.8129Validation
gender_Acc: 0.9146
region_acc: 0.9146
fighting_acc: 0.9024
alignment_acc: 0.8537
color_acc: 0.7912

需要注意的是,虽然我添加了批处理规范来尝试和减少过度拟合,但训练和验证之间的差距与以前类似…然而,模型的预测似乎比以前概括得更好,这也是添加正则化的目标结果之一。

Gender: Female, Region: Middle East, Fighting Style: ranged, Alignment: NE, Main Colors: [‘Blue’, ‘Gold’, ‘Black’]. Character has a LG alignment and don’t quite see the blue here, but the rest of the details are pretty good.

结论和总结

我认为这个简单的调优过程是一个很好的指标,表明您在普通网络上使用的策略仍然可以应用于多任务模型。这其中的一个困难是,很难针对多任务模型中的特定缺陷,现在我只是针对更大的总体问题(所有节点的过度拟合和欠拟合)。在这些头上添加额外的层和节点是一个选项,但随后会成为您需要调整的额外的超参数。

因此,最终的两个模型表现得相当相似,基础更深的网络在颜色和性别方面表现得更好,在区域方面打成平手,而批量标准化模型在战斗风格和对齐方面表现得更好。

这就提出了选择什么模式的问题。你可以计算 Fbeta 之类的东西来处理它,尝试在所有不同的任务中做出一个组合的度量。如果你的目标是拥有一个单一的最佳模型,那么拥有这个单一的度量标准是有意义的。

如果你对使用多个模型持开放态度,另一个选择是采用表现良好的模型,并集合它们进行预测。这将允许您利用每个不同模型的性能更好的区域。我认为这在这种情况下是可行的,即一个模型在比对类别上表现更好,而第二个模型在多个不同类别上表现更好,差距较小。

在另一种情况下,你有一个较低的执行任务,在这种情况下,颜色不太好,你可能会成功地将专门的模型添加到整体中,以尝试和提高这些领域的性能。

Gender: Female, Region: Europe, Fighting Style: magic, Alignment: LG, Main Colors: [‘Blue’, ‘White’, ‘Silver’]. 15th anniversary photo for the character, only thing wrong with the predicted outputs I would say is the fighting style… there is a sword stuck in the ground but the model says she uses magic

收听纽约的音乐街区

原文:https://towardsdatascience.com/tuning-in-to-nycs-music-neighborhoods-efb7ae77a4cd?source=collection_archive---------17-----------------------

K-Means 通过音乐档案聚类邻居

摘要

机器学习允许创建能够识别多维数据集中的模式的计算模型。这个项目旨在利用 Foursquare 的“Places API”和一种叫做“k-means clustering”的机器学习算法来识别具有类似“音乐档案”的“纽约市”社区。

介绍

背景

音乐是一种艺术形式,已经并将永远深深地嵌入城市、社区和更广泛的人群的文化活动中。音乐是一种交流和表达的方式,有时甚至是抗议的方式,它有能力和平地将大量志同道合的人聚集在一起,影响流行文化,用一首令人难忘的歌词催眠你,让你在淋浴时潜意识地连续几周唱歌,即使在有意识地对自己这样做感到失望之后…..我跑题了……

问题

城市在某种程度上是由音乐实体组成的,如唱片店、乐器供应商、音乐厅、圆形剧场等等,它们不仅满足当地居民的音乐需求,也满足来自世界各地的游客的需求。对于较大的城市,音乐实体可以分散开来,从而形成一个随着时间的推移而发展和变化的时尚利基社区生态系统。这种生态系统通常由寻找酷音乐场景的人通过自然生活体验(流浪/浪荡)或以互联网评论、评论和与现实生活中的人交谈的形式推荐来了解。

这个项目旨在量化一个大都市纽约市的社区的“音乐档案”,以识别相似音乐场景的集群。

利益相关者

不同的团体可能对能够基于可用音乐商店的类型来量化邻域相似性的模型感兴趣。这种模型将能够通知那些喜欢住在音乐发生的地方的租房者和购房者,他们的下一个家就在合适的位置。未来的音乐场所初创企业可以利用该模型来识别缺乏现场音乐场所的社区,并确保他们投资于一个未饱和的地区。未来的音乐零售商,如唱片和乐器销售商,同样可以利用这种模式来确保他们开展的业务中竞争对他们有利。

方法学

数据源

NYU 空间数据仓库:我使用 NYU 空间数据仓库托管的“2014 年纽约市街区名称”数据集作为街区名称和相关位置质心的基础[0]。下图显示了此信息的一个示例:

DataFrame created from NYU’s ‘2014 New York City Neighborhood Names’

Foursquare—‘Places API’:我将使用 four square 的‘Places API’来获取与‘场馆’(four square 定义的)相关的数据,这些数据被归类为与音乐有某种关联[1]。值得注意的是,Foursquare 将“地点”定义为一个人们可以去或签到的地方,并且“地点”不一定是音乐地点,而是可以是任何机构,如餐馆或零售商店。每个 Foursquare“地点”被分配一个“类别”,每个“类别”与一个特定的“类别 ID”相关联。右图显示了 Foursquare 提供的“categoryID”值,该值将用于获取纽约市内与音乐相关的场所:

Foursquare Music-Related Venue CategoryIDs

资料检索

街区名称&位置质心数据:由 NYU 空间数据仓库托管的“2014 年纽约市街区名称”数据集可轻松下载为 JSON 文件并导入 Jupyter 笔记本:

Importing the newyork_data.json fie

然后,将与每个邻域相关的“区”、“邻域”、“纬度”和“经度”值从 JSON 转换为 Pandas 数据框架,作为分析的基础。

Creating a DataFrame out of the JSON data

Foursquare 音乐相关场地数据 : 如本报告数据来源部分所述,Foursquare 拥有众多的“场地类别,用于标识各类场地。对“API . four square . com/v2/ventures/search?”的“get”请求提供类别 ID 的端点将返回该类别的地点。下面的示例代码向 Foursquare 发送一个“get”请求,请求一个属于“音乐商店”类别的场所(categoryID = ' 4 BF 58 DD 8d 48988 D1 Fe 941735 '):

Example Foursquare Places API Request

通过递归地发送“get”请求到前面提到的端点,确保结果特定于具有音乐相关“类别 id”的场所,创建了与每个纽约市街区相关的音乐相关场所的初步数据集。对于每个邻域,我们可以在一个“get”请求中包含所有选定的类别 id,方法是将它们作为逗号分隔值传递。下面显示了一个创建所需 url 的函数和一个示例:

Dynamically creating API request URLs

下面的函数递归地向 Foursquare 发送一个“get”请求,请求所有与音乐相关的地点。在遍历 NYU 数据集中的每个邻域时,该函数将每个与音乐相关的地点条目附加到一个列表中,并且在遍历每个邻域后,创建所有结果的数据帧。对于数据集中的每个条目,包括邻居名称和位置,以及地点名称、位置和类别。

Recursively retrieving music-related venues for each New York City neighborhood

最终的初步场馆数据框架包括从 Foursquare 中抽取的 9,442 个场馆:

9,442 venues were pulled from Foursquare

由于我对超出 Foursquare 的 API 速率限制有一些问题,在获得初步数据集后,将一个副本保存到 csv,以便将来的开发不需要从 Foursquare 重新请求信息。

Write data to csv

Sample of csv file

探索性数据分析

下面的一系列图片旨在捕捉我探索从 Foursquare 检索的数据的过程,以更好地了解在我的请求期间实际上是什么样的场地。在一个完美的世界中,每个条目都与音乐相关,并且位于纽约市,但是这需要被验证。以下问题说明了如何对初步场馆数据进行预处理,如本报告的数据预处理部分所示。

问题:场馆位于哪些州?

回答:从 API 请求中提取的大多数条目都包含一个等于“纽约”或“NY”的“州”参数某些条目包含等于“CA”、“MA”和“NJ”的“state”参数,需要删除。

Showing the Venue State counts

:参赛作品属于哪个场馆类别?

:这个数据集中有 149 个独特的场馆类别。有些类别与音乐无关,这是因为使用了 Foursquare 定义的更高级别的“场地类别”。与音乐无关的类别将被删除。

Showing the Venue Category counts

问题:有多少场馆没有填写“城市”参数?

:下图显示有不少场馆没有填写“城市”参数。起初,我认为这不会是一个问题,因为我仍然有一个与每个条目相关联的纬度和经度。经过进一步分析,确定没有“城市”参数的条目不再是活跃的机构,因此将被删除。

Showing venues that do not have a Venue City parameter

问题:数据集中有空值吗?

回答:没有。

Checking for null values in the data

问题:检索到多少个独特场馆?

:初步数据集中,唯一场馆名称比条目总数少。这意味着存在与多个邻近区域相关联的场所,这是由于 API 请求中半径被设置为 1000 米而导致查询重叠的结果。这是可以接受的,因为场地在邻近区域质心的步行距离内,可以影响邻近区域的场景。

Checking for duplicate Venue Names

数据预处理

数据清理

根据上面探索性数据分析部分中列出的答案清理初步数据集。首先,位于“纽约”或“NY”以外的州的场馆被移除。“地点州”等于“纽约”的条目被更改为“纽约”

Removing venues not in New York state

Foursquare 返回的没有“场馆城市”并给予“不适用”待遇的条目也被删除:

Removing venues with no Venue City parameter

基于包括在初步数据集中的独特场所类别,创建了音乐相关场所类别的列表。这个列表用于过滤掉混入我们请求中的与音乐无关的条目。

Removing venues that are not music-related

下图显示了 ny _ music _ venues 数据帧中的条目总数和唯一条目数。如前所述,一些场馆被分配给多个街区,因为场馆位于街区质心位置的 1000 米以内。

Checking for duplicate venues

一键编码场馆类别

为了使用 Foursquare 的类别值来找到基于音乐场所的相似邻居,使用 Pandas 的“get_dummies”功能创建了每个条目的一个热编码表示。结果是纽约市音乐相关场所的数据框架,其中条目场所类别由匹配场所类别列中的值 1 表示,如下所示:

One-Hot-Encoding categorical variables

数据可视化

使用 one hot encoded DataFrame 确定了纽约市每个场馆类别和街区的场馆数量:

Total amount of venues of each category in each neighborhood

使用上面显示的场馆数量的数据框架,为选定的场馆类别创建了水平条形图,以帮助可视化每个特定场馆最多的前 25 个社区。使用以下循环和 matplotlib:

Code for recursively plotting top neighborhoods with venues of particular category

拥有最多“音乐厅”的社区

拥有最多“音乐场所”的社区

拥有最多“夜总会”的社区

“爵士俱乐部”最多的街区

“钢琴酒吧”最多的街区

特征生成

纽约市音乐相关场所的编码数据集随后被用于量化每个街区的音乐概况。对于每个场馆类别,计算了场馆在每个社区的分布百分比。然后,该信息将用于使 K-Means 聚类算法适合数据,以努力确定相似音乐场所简档的邻域。

首先,确定每个类别的场馆总数:

Creating a dictionary of venue category and total count

最后,根据场馆类别,计算每个街区的场馆相对于数据集中场馆总数的百分比。很明显,Astoria 的“Lounge”列中显示的值表示位于 Astoria 的休息室在数据集中所占的百分比。

Percentage of entities of particular venue in a particular neighborhood

根据上述内容,创建了一个数据框架,显示每个街区的前五大音乐场所类别:

Showing the top five venue categories per neighborhood

结果

集群建模

Scikit-learn 的 K-Means 聚类用于根据音乐场所百分比确定相似的邻域。下图显示了正在缩放的数据和正在创建的 K 均值模型:

Clustering neighborhood venue data

一个新的数据框架是通过合并邻居位置数据和聚类标签和顶级场馆类别创建的。

Merging neighborhood location and cluster data

集群可视化

以下代码通过基于分类标签对每个邻域点进行着色,使用 follow 来可视化相似音乐配置文件的邻域:

Code to generate a folium leaflet map with neighborhoods colored by cluster

Map of New York City showing clusters

聚类评估

下面的代码遍历并打印每个分类的结果:

Code to iterate through and print each cluster

由此产生的集群可以在本文档附录的集群部分看到。每个聚类显示一个邻域列表及其各自的顶级场馆类别。我们可以将得到的聚类与数据可视化部分中的条形图进行比较,并根据与音乐相关的场地计数来判断聚类是否正确地对邻近区域进行了分组。

有趣的是,一些集群非常小,有时只包含一个邻居,并且似乎已经确定了一个利基音乐简档。这方面的例子有:

集群 1 —康尼岛—音乐节(康尼岛音乐节)

第二组团——林肯广场——歌剧院(大都会歌剧院)

诸如集群 4 和集群 7 的其他集群非常大,并且看起来是具有诸如音乐场所、夜总会、摇滚俱乐部、休息室等各种现场音乐类型场所的分组邻居。

集群 9、11、12、13 和 14 的集群间第一大场馆类别都是相同的;爵士俱乐部、录音室、摇滚俱乐部、爵士俱乐部和钢琴俱乐部。有趣的是,集群 9 和集群 12 都主要对爵士乐感兴趣,但由于它们的其他顶级场所类别不同,这意味着不同的音乐概况,所以它们被不同地分组。

结论

机器学习和聚类算法可以应用于多维数据集,以发现数据中的相似性和模式。使用高质量场地位置数据,可以生成具有相似音乐简档或任何简档的邻居的聚类。关于高质量有一个前言,因为分析模型的好坏取决于对它们的输入(垃圾输入,垃圾输出)。幸运的是,Foursquare 提供了一个强大的“位置 API”服务,虽然(正如我们所看到的)并不完美(没有什么是完美的),但可以在类似的研究和模型制作中加以利用。

这个项目并没有完成,可以用不同的方式进行扩展。Foursquare 的 API 可以被进一步询问,以检索和考虑纽约市更多与音乐相关的场所。可以获得音乐相关场所的新数据集,并可能与从 Foursquare 检索到的数据集合并。DBSCAN 聚类算法在保持密集聚类和忽略异常值方面更好,可以实现该算法并与 KMeans 进行比较。该聚类模型可以成为推荐系统的基础,该推荐系统旨在向用户提供相似音乐档案的邻居。

我期待着在未来继续探索和利用音乐相关的数据集。

GitHub 项目:https://github.com/cascio/IBM_Data_Science_Capstone

个人领英:https://linkedIN.com/in/mscascio

个人网站:https://cascio.co

推特:【https://twitter.com/MCasiyo

参考

[0] — 2014 纽约市街区名称— NYU 空间数据仓库

[1]—‘Places API’文档— Foursquare

附录

群集 0:

群组 1:

第二组:

第三组:

第 4 组:

第 5 组:

第 6 组:

第 7 组:

第 8 组:

第 9 组:

第 10 组:

第 11 组:

第 12 组:

第 13 组:

第 14 组:

带 JAX 的涡轮增压 SVD

原文:https://towardsdatascience.com/turbocharging-svd-with-jax-749ae12f93af?source=collection_archive---------22-----------------------

在之前的文章中,我写了两种常用的降维方法的基本原理,奇异值分解(SVD)和主成分分析(PCA)。我还用 numpy 解释了他们的关系。快速回顾一下,一个以 0 为中心的矩阵 X (n 个样本× m 个特征)的奇异值()),等于其特征值的平方根(λ),使得使用 SVD 计算 PCA 成为可能,这通常更高效。

在这篇文章中,我将探索一些 SVD 算法,并用 Python 对平方稠密矩阵( Xn×n )进行基准测试。我还有一个非常令人兴奋的发现:最近开发的由 XLA 编译器支持的 JAX 库能够显著加速 SVD 计算。我们开始吧!

SVD 怎么算?

*奇异值分解是探索性数据分析和机器学习中一种常见的基本技术,但我们实际上如何计算出左右酉矩阵( UV )和奇异值呢?通过我远非详尽的文献综述,至少有四种算法可以求解稠密矩阵的完全奇异值分解。甚至更多的算法可用于稀疏矩阵的截断/缩减 SVD,为了效率,其仅计算最大的 k 奇异值。在本帖中,我将重点介绍密集矩阵和完整的 SVD 算法:

  1. 分治法(GESDD) :两阶段算法。它首先通过 Householder 反射将输入矩阵简化为双对角形式,然后将双对角矩阵分成更小的矩阵,以计算奇异值和酉矩阵 U 和 v。最后,整个输入矩阵的奇异值就是更小的子矩阵的奇异值。在这里可以看到这个算法更深入的讲解。这种算法在概念上类似于 MapReduce ,其中大块数据被分成多个块进行并行处理,每个块的结果可以使用简单的函数进行聚合,例如求和和连接。
  2. 通用矩形方法(GESVD) :也是一种两阶段算法,其中第一步与 GESDD 相同。第二步可以使用迭代 QR 分解得到奇异值。更多数学细节可在这里获得。

这两种算法都在用 Fortran 编写的经典线性代数库 LAPACK 中实现。分治法被证明比一般的矩形法快得多,但是占用更多的内存。

Python 中的 SVD 实现

Scipy 和 Numpy 都包含在各自的线性代数子模块下计算 SVD 的方法:

  • numpy.linalg.svd :“使用 LAPACK 例程` _gesdd '执行分解”。但通过查看这个函数的源代码,似乎 numpy 是通过一些用 c 编写的调用宏来调用 LAPACK 的,这样设计的目的很可能是为了规避构建 numpy 时对一个 Fortran 编译器的要求。
  • scipy.linalg.svd :提供更多参数,如overwrite_acheck_finite,为 svd 计算提供潜在的加速。它还有一个参数lapack_driver,用于在 LAPACK 中的 GESDD 和 GESVD 算法之间进行选择。
  • scipy . sparse . Lina LG . svds:执行截断 SVD,计算稀疏矩阵的最大 k 奇异向量。虽然这个函数也能够计算完整的 SVD,但是它的效率比 scipy.linalg.svd 低得多。

您可能想知道为什么在 numpy 和 scipy 中都有linalg.svd的实现。np.linalg.svdscipy.linalg.svd有什么区别?我在 scipy 的 FAQ 中找到了这个问题的答案:scipy.linalg是使用 f2py 对 Fortran LAPACK 更完整的包装,而 numpy 则试图独立于 LAPACK。

Timings for numpy/scipy SVD methods as a function of matrix size n

为了比较不同 SVD 实现的速度,我建立了一个非常简单的基准,通过改变大小为 n 的方阵的大小来测量 numpy 和 scipy 中 SVD 实现的执行时间。如上图所示,scipy ( scipy_svd)和 numpy ( np_svd)中的分治法(GESDD)比 QR 分解法(GESVD)快一个数量级以上(scipy_gesvd)。scipy.linalg.svd 也比它的 numpy 版本快得多,这可能是因为它与 LAPACK 的通信效率更高。

JAX 和 XLA

让我们绕一小段路到 JAX,这是谷歌最近开发的开源库,旨在加速线性代数计算。 JAX 是一个“非官方”的谷歌项目,配备了亲笔签名的和 XLA 编译器,汇集在一起进行高性能机器学习研究。XLA(加速线性代数)是 Tensorflow 背后的编译器,用于在不改变源代码的情况下加速模型计算。它的工作原理是将多个简单操作“融合”到一个内核中。JAX 在 jit (实时)函数中实现了 XLA 编译器,以允许显式编译 Python 函数。下面是 JAX 简单用法的快速浏览,展示了如何用 jit 编译器加速原始 Python 函数。

JAX 的另一个显著特点是,XLA 编译的代码会被自动缓存,如果重复运行可以重用,以进一步加快进程。这在教程中有演示。

此外,JAX 还在子模块jax.numpyjax.scipy下提供了 XLA 加速器支持的 numpy 和 scipy 函数,尽管目前并不支持所有的 numpy/scipy 函数。幸运的是,linalg.svd对于 numpy 和 scipy 都已经在 JAX 实现了。

密集矩阵的奇异值分解函数基准测试

随着 JAX 加速 numpy 和 scipy,我可以比较他们的表现与他们的香草同行。我使用了与之前相同的计时函数来获得以下结果。

First attempt in timing JAX powered SVD implementations

乍一看,这看起来很惊人:JAX 驱动的 numpy 和 scipy 都大大超过了 SVD 的简单的 numpy 和 scipy 实现。但是,这看起来好得令人难以置信:JAX 驱动的奇异值分解怎么可能快四个数量级,并且几乎有一个O【1】的复杂度呢?在检查了我的计时功能后,我发现 JAX 可能已经找到了一种方法,通过缓存以前运行的结果来作弊。为了防止 JAX 这样做,我编写了另一个计时函数,在每次试验中生成一个全新的随机密集矩阵,从而得到下面这个更真实的结果。

Timings of SVD methods with and without JAX acceleration as a function of matrix size n

上图显示,numpy ( jnp_svd)中 JAX 支持的 SVD 函数在速度上明显优于所有其他计数器,而 JAX 支持的 scipy 实现(jsp_svd)与其普通的 scipy 对应物没有任何差异。值得更多地研究实现,找出原因。这可能与 scipy 和 numpy 与 LAPACK 交互的不同方法有关,这可能会影响它们被 XLA 编译器进一步优化的能力。

还有必要提一下,所有的基准测试结果都是从 CPU 运行时生成的。我还试图通过 Google Colab 在单个 GPU 和单个 TPU 运行时上运行它们。而且看起来 GPU 并没有促进jax.numpy的加速,而 TPU 从 CPU 产生几乎相同的结果。这些观察结果也需要进一步研究。

但是从所有这些基准测试结果中得到的好消息是,您可以通过切换到jax.numpy 来轻松加速您的机器学习工作流,而无需进行重大的代码更改!

以上所有基准测试的 Jupyter 笔记本都可以在这里找到:https://gist . github . com/Wang 10/d6f 43 db 76 ca 260516d 149d 92 b 8834 bf9

参考

  • SciPy 中的奇异值分解
  • Python 中的稀疏 SVDs】
  • 为什么既有 numpy.linalg 又有 scipy.linalg?有什么区别
  • 数学 2071:实验室#9:奇异值分解
  • 分治特征值算法
  • SVD 的 LAPACK 文档

将亚马逊 S3 变成时空数据库!

原文:https://towardsdatascience.com/turn-amazon-s3-into-a-spatio-temporal-database-40f1a210e943?source=collection_archive---------14-----------------------

好吧,充满希望这个标题,S3 到底有什么可能?事实证明,相当多。事实上,这篇文章描述了如何使用 S3 搜索 n 维。

用于存储的 S3

S3 是亚马逊几乎无限的存储产品。您可以在 S3 存储桶中存储任何大小的文件,这些文件将被冗余地存储在一个区域内多个设施的多个设备上。对于您希望频繁交互的文件,标准存储成本约为每月每 GB 3c(US)。如果您将数据标记为存储在 S3 冰川,则费用为每月每 GB 0.4c,如果需要,您可以在几个小时内将其恢复到标准状态。

我把世界表面的一大块区域的船只运动数据存储在 S3,并配置旧数据自动转移到冰川。一天可能有多达 2700 万条记录,逗号分隔值(CSV)格式占用 2.4GB。事实上,我将原始数据(AIS NMEA)存储在 S3,Java Lambda 触发器创建了一个 CSV 版本。

随机访问 S3

我喜欢云服务的一点是发现成本和功能方面的最佳点,我想知道我是否可以快速廉价地查询 S3 的数据集。

原来 S3 的文件是可以随意获取的。我可以使用 Range HTTP 请求头指定一个字节范围,这就是将返回的全部内容(没有延迟损失)。

随机访问支持索引查找。如果我通过使用索引知道了我的记录在文件中的大致位置,那么我就可以只抓取文件的那一部分并提取我想要的信息。

GIS 系统如何执行空间查询?

2 维、3 维或更多维的窗口查询是在相同维数的框内搜索数据。例如,如果我有整个美国的时空数据,那么窗口查询可能是在特定的一天午餐时间查找芝加哥特定郊区的记录。

Fig 1. A spatio-temporal window query (researchgate.net)

GIS 系统如何对 2D 空间和时空数据进行窗口查询?

空间查询通常用 R 树来完成,R 树是一种相当复杂的数据结构。搜索平面文件中表示的树结构可能意味着在遍历树时进行多次随机访问读取。更重要的是,读取在本质上是串行的,因为在完成前一次读取之前,我不知道下一次读取的位置。更多的离散串行读取意味着更多的延迟,尤其是当我在 S3 读取平面文件时,每次读取都会遇到延迟。

将 3 维或更多维映射到希尔伯特曲线

在 3 维或更多维时,一种流行的索引技术是使用空间填充曲线将多维区域映射到一维。空间填充曲线的一个很好的选择是希尔伯特曲线。将您的 3D 域分割成 1024x1024x1024 个单元的规则网格,然后由一条摆动线组成的希尔伯特曲线将访问所有 1m 个点。

作为一个插曲,这里有几个 2D 的例子,这条曲线被称为希尔伯特曲线。

Fig 2. 2D Hilbert Curve, 4 bits

Fig 3. 2D Hilbert Curve, 8 bits

这是希尔伯特曲线的三维动画:

希尔伯特曲线有一些很好的局部性属性,因为它没有大的跳跃,曲线上的下一个值只有一个单位之遥。这意味着,如果两个点具有彼此接近的索引,那么它们在几何上也将彼此接近。不保证相反的情况。

稀疏索引

现在,所有数据点都映射到一个维度,我可以在该维度中对它们进行排序,然后使用简单的一维数据库索引查找技术。当您索引数据库表中的列时,您最终能够在每个表中找到与该列中的值相对应的精确行。但是,索引中的条目可以与表中的行一样多。如果你使用所谓的稀疏索引,那么你有一些行的位置,但是你可能需要在它们之后做一些额外的阅读来找到其他的。一个稀疏索引可以比一个完整索引小得多,比如说是一个完整索引大小的 0.1%。

我在这里拐弯抹角,所以让我们进入正题。如果我将我的 2,700 万条记录(2.4GB 的 CSV 文件)按照 Hilbert 索引的升序值(10 位,100 万个点)进行排序,然后创建一个小的稀疏索引文件(440K),我就能够通过对数据的随机访问进行快速窗口查询。我甚至可以并行地进行搜索,因为我预先知道我的记录(大约)在哪里。理想情况下,我想到的查询在空间和时间上都很小,尽管我发现不受时间限制的查询也可以很好地工作。

一个图书馆来帮忙

在将搜索框转换成希尔伯特曲线上的范围(如果范围太多,可能会将其变粗)以及从那里访问索引所指向的字节范围方面,这里有一些棘手的问题需要处理。幸运的是,这些问题由一个名为sparse-Hilbert-index的 java 库来处理,这个库是我在 GitHub 上完成并发布的。

让我们试一个例子。我的 CSV 输入数据如下所示:

mmsi,messageId,time,lat,lon,speedKnots,heading,course,navigationStatus,rateOfTurn,source,specialManoevreIndicator,timeSecondsOnly,isUsingRAIM,class
4124607775,18,1543283257000,-66.97455333333333,33.95234833333333,8.7,67.3,67,,,NORAIS2,,35,N,N,
4124607775,18,1543283257000,-66.97455333333333,33.95234833333333,8.7,67.3,67,,,NORAIS2,,35,N,N,
538006789,1,1543283259000,-39.57300333333333,33.18371833333333,12.7,85.1,84,UNDER_WAY_USING_ENGINE,-13,NORAIS2,0,39,Y,N,A
...

我通过运行这段代码创建一个排序的数据文件和一个 Hilbert 索引(感谢 commons-csv ):

Viewing search statistics

13 分钟后,在 i5 笔记本电脑上完成了 2700 万条 CSV 记录的排序,并创建了索引文件。

然后,我将input-sorted.csv (2.4GB)和input-sorted.csv.idx部署到一个 S3 桶,并尝试查询如下所示的数据。首先我会数一个小时悉尼地区的记录数。我将使事情变得更简单,并假设数据在一个公共可访问的桶中,因此我不需要进行身份验证(但只有当您的数据不敏感时才这样做)。

加载索引文件(如果需要,可以在本地缓存):

执行搜索:

加载索引文件(440K)花费了 500 毫秒。

上面的搜索在169 毫秒中通过不太灵活的企业互联网连接找到了 2389 条记录。读取了 3347 条记录(命中率为 0.71)。稀疏索引导致了一定程度的浪费,但是我们当然不需要在服务器上安装 GIS 系统!

有趣的是,如果我们查询整个时间维度(24 小时)的悉尼(澳大利亚)地区的数据集,那么性能仍然是合理的:6720 毫秒返回 36940 条记录,命中率为 0.55。(部分)读取了 37 个块(由索引条目指向的 S3 对象的部分),第一个字节的平均时间 (TTFB)为 114 毫秒(因此我们的互联网连接的延迟导致了 4200 毫秒的运行时间)。靠近 S3(比如 EC2 或 Lambda)可以节省大量时间,但我们的另一个锦囊妙计是从 S3 同时读取。

使用并发!

在上面的搜索命令中,您会看到concurrency参数被设置为 1。我发现,对于 S3 的这个数据集,通过普通互联网连接的最佳数字是 8;也就是说,同时检索、解析、过滤和合并 8 个组块。耗时 6720ms 的查询(主要是因为无约束的时间维度)现在耗时 839ms

从 AWS 搜索

我也从 EC2 (t2.large)进行了测试,正如预期的那样,第一个字节的时间减少到了大约 50 毫秒。有了并发性,全天查询减少到了 380 毫秒。随着延迟的下降,我认为寻道时间开始发挥更大的作用,并发级别的最佳点似乎是大约 4。

流式 API

用于从搜索中检索记录的 api 通过 RxJava 库提供流功能。

其他格式

请记住,CSV 不是存储和检索数据的最有效方法。更有针对性的二进制格式可能会使您的查询速度快很多倍。

调谐

稀疏索引中的条目数量对命中率有很大的影响(命中率是一种衡量您为了找到所请求的内容而读取了多少记录的指标)。如果您可以在本地缓存索引文件,或者将它们放在速度更快的存储器上,那么您可以在每个索引文件中使用更多的条目。实验是必由之路。为不同大小的同一个文件创建多个索引,看看哪一个最适合您的查询模式。

一般来说,如果您的查询是定制的,这样它们就不会返回很多记录,那么您的响应时间应该是上面提到的顺序。使用不受约束的维度进行搜索(就像前面查询中的时间)可能会有效,但是我建议只使用一个不受约束的维度。

查看搜索统计数据

当您执行搜索时,您可以指定withStats选项来查看有关搜索的各种指标:

index
.search(bounds)
.withStats()
.concurrency(1)
.url(url)
.last()
.forEach(System.out::println);

生产:

WithStats [elapsedMs=169, recordsFound=2389, recordsRead=3347, hitRatio=0.7138, bytesRead=392261, timeToFirstByteMsTotal=94, timeToFirstByteMsAverage=94.0000, chunksRead=1]

二维呢?

我已经运行了一个 3 维的例子,但是稀疏的希尔伯特指数对于 2 维也同样适用。因此,S3 也可以成为您的 2D 空间数据库。

不仅仅是 S3

注意,Azure Blob 存储和 Google 云存储也通过 HTTP Range 头提供随机访问。你可以使用这些存储选项以及稀疏希尔伯特索引 T2 库。

雅典娜呢?

这个问题问得好!特别是当 AWS 在 S3 桶中提供 CSV 文件(和其他格式)的 Athena 时,它可以在 1.5 秒内完成 2GB CSV 文件的完整扫描!

当你考虑到与全扫描相比,在大量数据上运行许多索引搜索的成本时,稀疏希尔伯特索引方法可能会更有吸引力。Athena 的成本很低(为查询而扫描的数据为 5 美元/TB),但在一定规模下可能会变得非常重要。在某些情况下,进行大量全扫描搜索所产生的功耗也可能在伦理上具有挑战性(也很难计算)。我认为在大文件搜索方面很难与 Athena 竞争,但可能有一些边缘情况有利于稀疏希尔伯特索引

火上浇油的是,Athena 支持 Parquet 格式,这种格式可以被索引,这样每个页面都有 min-max 统计数据。如果您对您想要查询的字段进行排序(在我们的例子中,我们将添加一个计算的 Hilbert 索引列),那么 Athena 可以在理论上自己进行索引查找(未经测试)。Athena 仍然需要查看每个页面的统计数据(默认情况下为 1Mb ),所以理论上它不如精确知道要搜索哪些页面的稀疏希尔伯特索引有效。请注意截至 2019 年 6 月,Athena支持索引拼花格式以实现更快的访问( 1 )。当支持到来时,它将是值得尝试的!

带回家

  • 从平面文件或存储服务(如 S3)中进行高效的空间、时空甚至 n 维查询是可能的!
  • 转到 稀疏希尔伯特指数 获取该用例的易用库支持
  • 评估雅典娜也为您的查询需求

使用 Tkinter,将您以前的 Python 项目变成令人敬畏的工具

原文:https://towardsdatascience.com/turn-your-previous-python-projects-into-awesome-tools-with-tkinter-2e61f2241e29?source=collection_archive---------2-----------------------

Because building your own tools is… sexy?! (photo credit: Todd Quackenbush)

笔记本很无聊!

所以你在 Jupyter 笔记本上写了你的第一个脚本,每次你想使用这个脚本的时候,你疯狂地运行每个单元格。不太实用吧?当然,你可以安装一些扩展和一些小部件,我甚至看到一篇文章,有人创建了一个在笔记本中实时更新的仪表板。但是,如果你能创建自己的程序,只需点击一下鼠标就能启动,这不是更酷吗?作为一个附带项目,我决定制作一些关于我文章中代码的视频,所以我很乐意听到你关于格式、持续时间和任何其他反馈的意见!谢谢!

您将能够建立简单的模板,可以把您的旧的和未来的脚本变成个性化的工具!

一个图形用户界面也称为 GUI,是一种用户界面形式,允许用户通过图形图标与电子设备进行交互。这是一个普通人称为“应用程序”的花哨术语。除非您是从命令行阅读这篇文章(这实际上有点奇怪……),否则您现在很可能正在使用 GUI。

我喜欢 Jupyter 笔记本,因为它们易于使用,并让您在单独的单元格中构建代码。对于任何初学 Python 和编程的人来说,这无疑是最好的切入点,但是如果你真的想从事数据科学,你还需要更多的东西。笔记本完成后,说“完成”并转移到另一个项目是很容易的,但是如果你给他们自己的界面呢?如果代码不太复杂并且结构良好,你甚至可以为每个脚本使用一个简单的模板,就像我在本文中分享的那个。

有一段时间,当我想从事任何 Python 项目时,我都坚持使用 Jupyter 笔记本。我努力去理解工作背后的框架。py 文件,但最终,它点击了!这件事发生在我搜索 Tkinter 资源的时候,所以你大概能感觉到我的意思…今天不会使用 Jupyter 笔记本了!我们将使用。py 文件和一个 IDE。

我的文章是为非 IT 人士而写的,所以如果你是这种情况,不必惊慌!在整个代码过程中,我会一直陪着你,并尽力回答评论中的每一个问题

您可以利用这个 Tkinter 项目做些什么:

  • 创建用户界面来运行您的脚本
  • 要求用户在文本字段中输入一些内容,并将其用作变量
  • 单击运行代码特定部分的按钮
  • 要求用户选择一个文件以使用文件对话框提示
  • 奖励:不再与 Jupyter 独家合作!

对于这个项目,我将使用我以前的文章作为我们的应用程序使用的脚本的来源。这是一个从 Kayak 检查航班价格并编译结果的基本脚本。它有一些硬编码的输入,但正如我提到的,我们希望我们的体验更像一个正常的程序,所以我不得不稍微调整一下。我在我制作的作为文章补充的视频中解释了它。我强烈建议你看一看,因为为了简洁起见,一些细节必须从文章中删除!

在继续之前,您需要几样东西:

  • 代码编辑器:我将使用 Spyder,它并不完美,但已经足够好了。如果你不确定这是什么意思,试试看你是否安装了 IDLE 。它预装了 Python,所以您在这里应该没问题。趣闻:IDLE 是用 Tkinter 造的!
  • 包:显然你需要安装Tkinter包。有很多在线资源可以帮助你做到这一点。但是如果你想掌握它,我会在最后留下几本推荐的书。
  • 模块:您需要将之前的 FlightScraper 脚本更新为。我分享的 py 文件 这里 。把它放在你将要处理的文件夹中。

每个程序都从一个窗口开始

Tkinter 一开始可能看起来很奇怪,很难理解,这就是为什么我会一个块一个块地构建代码,试图解释我们正在创建什么,以及它如何在应用程序中显示。假设您已经安装了所有东西,只需为项目创建一个文件夹,并创建一个扩展名为. py 的文件。

每个 Tkinter 应用程序都需要这样构建。我们称这个为 tk。Tk() 来创建应用程序窗口,然后我们构建我们的应用程序,在用 window.mainloop() 来“编译”所有东西之前,在我们想要的地方放置小部件(框架、按钮、标签等)。我不会详细介绍 Tkinter 是如何工作的,但如果你想了解什么是循环和构建一个应用程序的基本结构,请查看他们的资源。

在这一点上,我们讨论我们将需要的小部件可能更好。顺便说一下,小部件是 Tkinter 的元素(如按钮、标签、框架、条目等)。我只使用几个,如果你掌握了这些基本知识,你就可以很容易地自己去测试其他人了。

  • 框架:我们的应用程序将被分成三个框架堆叠在一起。顶部框架将用于放置我们的标题,而底部将显示我们的应用程序按钮。中间的框架将由另外两个框架组成(是的,您可以将一个小部件放在另一个小部件中!)
  • 网格:我将使用网格作为定义应用程序布局的一种方式。如果你喜欢冒险,可以试试 Place,它可以让你用屏幕上特定的 x,y 坐标来设置位置。在我看来,网格是最容易理解和使用的,所以我们将使用它并打包。
  • Pack :它也是一个布局管理器,真的很好理解……每次使用。pack()它会将小部件堆叠在之前打包的小部件下面。
  • 标签:简单地说,它们是文本框。我们将在页眉和输入框旁边使用它。
  • 条目:它是一个小部件,让用户编写某种输入,比如城市和日期。
  • 按钮:我真的需要解释什么是按钮吗?!玩笑归玩笑,在按钮部件中有一个名为命令的参数,它告诉按钮当它被按下时运行什么功能。

现在你知道了配料,让我们来看看食谱

所以让我们直接进入主题。下面是前三帧和标题的代码。我用网格法把它们放在 app 里。您可能已经注意到了,标题在顶部(第 0 行第 0 列),中心在中心(1,0),底部框架在中心框架的下面(2,0)。我添加了一些参数,比如边框宽度和pady(y 轴填充),让它看起来更漂亮。当我们创建框架时,我们需要告诉 Tkinter 它们属于哪个窗口,我们通过将 window 变量(我们的主窗口)作为框架的主窗口来定义它。这里的关键点是,参数 master 用于每个小部件中,它定义了小部件的放置位置。

我们还在标题中放置了一个标签,因此在标签小部件中传递了 frame_header 。每个小部件的流程都是一样的。你用你想要的小部件创建一个变量,告诉 Tkinter 它属于哪里,然后把它放在应用里。由于 frame_header 将只包含标题标签,我们将其放在位置 0,0。摆弄标签参数来理解你的格式选项!这个是关于 Tkinter 以及如何使用这些小部件的非常好的资源,并附有例子。

记住上面的代码必须放在 window.mainloop()之前,否则程序不会运行

这是一个好主意,节省一些时间和挫折以后总是测试你在做什么。你可能认为你把所有的东西都放在了最合适的位置,但是当你运行这个文件的时候,这简直是疯了。它发生了!所以我们需要不时地运行这个文件,看看小部件是如何显示的。这是没有办法的。如果你来自 Jupyter 笔记本,先不要惊慌。您正在使用的编辑器可能有运行文件的方法(希望是 Python 文件!).在 Spyder 中,您可以在编辑器中直接使用 F5,控制台将运行代码。事实上,大多数 IDE 都有相同的快捷方式(F5)来运行文件。就是这么简单…如果你有我给你看的代码,和最后的main loop(),在你运行它之后,应该会弹出一个窗口。恭喜你,这是你第一个 GUI 的开始!

它看起来还不太像,但我们会到达那里。如果你注意代码,我说我放了三个框架,但是只有标题出现了…是的,那是我和 Tkinter 的第一次斗争。我没有意识到框架只有在有某种元素的情况下才会出现。咄…!所以接下来我们将处理其余的帧。您可以关闭应用程序窗口,并根据需要多次运行该文件。

检查之前先打包

让我们在中心框架内再添加两个框架, frame_main_1frame_main_2 。同时,让我们也为这些帧添加标签。我想有一个输入框的每一个标签。我们接下来会处理这个问题。

标签的逻辑和框架一样。我们告诉 Tkinter 标签属于帧 1 和帧 2,以及它们将显示什么文本。拥有 GUI 的目的是让用户更流畅地与程序交互,所以我们需要决定我们希望用户给我们什么输入。如果您还记得另一篇文章中的代码,我们需要一些字符串来构建我们的 url,所以本质上,我们期待来自用户的字符串。标签下面的线就是这样。

我们将四个变量定义为 StringVar() 。很难用简单的术语来解释,但是可以把这种变量想象成,当程序运行时,Tkinter 能够跟踪的对象。然后,您可以创建当这些变量发生特定事件时要执行的操作。他们还是一串,但属于不同的品种!

我不得不在最后一行加上。pack() 因为否则,如果我们再次运行程序,什么也不会显示。请随意删除最后几行,然后再次运行程序。它将显示与之前完全相同的框,只有标题。我在这一点上告诉你,因为这些线不会停留在这个位置,因为我们需要在打包所有东西之前添加更多的部件(和一些功能)。文章最后一段应该有完整代码的链接!

if you run it now, it’s clear we’re getting there

等等,还有功能?!

我故意把函数留到后面,但是它们必须放在 import 语句下面的某个地方和 widgets 部分之前。这里有四个函数,其中两个是我们的条目表单所需要的(使城市条目中的字母大写,并将长度限制为 3 个字符)。我们还将有两个按钮,一个运行机器人,另一个退出应用程序。 run_app 函数将在后面介绍。

我们希望用户输入什么?简单…我们希望他们键入城市(出发和到达),以及旅行日期(出发和返回)。有了这个,机器人就可以做自己的事了。第三个视频涵盖这部分!

我将需要函数 caps_fromcaps_to ,因为我们需要在输入框中使用它们的 bind 方法。什么。bind() 的作用是等待小部件中的事件发生,并运行一个序列/函数。在这种情况下,小部件是输入框,事件是按键释放,函数将限制字符长度并将字母转换为大写。非常简单,我觉得这是你的保留曲目的一个很好的技巧!

如果您要一段一段地进行,只需将 tkinter_app3.py 中之前的 pack() 语句替换为这个代码片段中的整个代码 tkinter_app5.py.

you can only type 3 letters, and it converts them to upper case as you type

按钮在哪里?!

是的,是时候让按钮显示在应用程序中了。我们已经处理了退出应用程序的功能。这个命令叫做“destroy ”,听起来超级毛骨悚然和恐怖,但它就是这么做的:它破坏了窗户!所以,我们的 close_app 函数就是一行, window.destroy() 。我们之前创建的 run_app 函数将简单地在控制台中打印“run ”,所以如果我们收到一个文本说“run ”,我们将知道它正在工作。

这一部分可以直接放在最后一个代码片段的下面, mainloop() 将负责正确的执行。所以你可以打包小部件,然后再创建几个,打包在下面。重要的是跟踪你正在使用的订单。否则,更复杂的脚本会变得混乱

按钮小部件很容易与参数“command=”中的函数进行映射。注意我是如何将一个指向 run_app 函数,另一个指向 close_app 。哦,这些按钮的主人是底部框架。

瞧啊!界面完整。它看起来很粗糙,校准可能会更好(至少可以这么说),但嘿…这是你的应用程序,所以继续改进它吧!

finally, something that looks like an actual tool!

这应该给了你为你的脚本构建简单应用的基础,但我们仍然需要将这个项目链接到我们的 Flight Scraper 脚本,并重做 run_app 函数,用“开始”按钮激活它。下面是 run_app 函数最终的样子。该功能使用方法。get() 在条目上,它将使用 Flight_bot()启动我们的 Bot。然后,它将用户输入传递给作为机器人一部分的函数 start_kayak 。你应该能从上一篇文章中认出它的名字。

请注意:为了启动机器人,您需要在初始导入中导入它!!查看第四个视频

我是这样做的:将上一篇文章中的脚本(在 jupyter 笔记本中)改编成一个名为 flight_scraper_bot.py 的 py 文件,并将其放在与我们正在处理的文件夹相同的文件夹中。从那里,我们可以导入它并在我们的程序中使用它。这个 py 文件可以在这里找到。我们需要添加到 tkinter 文件中的行是:from Flight _ scraper _ Bot import Flight _ Bot

这已经包含在我们脚本的最终版本和编译版本中,我把它放在这里供您抓取。这比在整篇文章中复制和粘贴多个片段要容易得多。不客气!

我在视频中对它进行了更详细的介绍,所以如果你需要帮助,一定要看看它们。就像我在开始提到的,你的评论对帮助我提高文章和视频的质量非常重要,所以请随时发送你的反馈和问题!

这本 的书 有我需要知道的一切,无论何时我正在与一个特定的小部件作斗争。如果你想掌握 Tkinter,我相信它可以帮助你。如果你对网页抓取部分感兴趣,这是我用来学习 Selenium 和其他人的 (如果您使用此链接,我会收取少量费用,无需您支付额外费用。我确实需要很多咖啡来写这些文章!)**

it’s funny because it’s true…

感谢您的阅读!如果你喜欢这篇文章,我邀请你看看我的其他故事。我主要感兴趣的是数据科学、 区块链 和数字货币、技术,以及其他一些类似 摄影

如果你想取得联系,可以在这里联系我或者直接回复以下文章。****

将数据愿景转化为数据行动计划

原文:https://towardsdatascience.com/turning-a-data-vision-into-a-data-action-plan-820976c22a4f?source=collection_archive---------28-----------------------

好吧,假设你最近被聘用或调任一个职位,负责将你的公司转变为一个更加数据驱动的公司。本文将介绍如何将您的数据愿景转化为数据行动计划。这样,你就有了一个指导框架,将你的愿景和战略以及最后的战术步骤联系起来。顺便说一句,这些想法大部分来自我个人的经验,我发现这些想法很管用。

从为什么到如何和什么

为什么是数据愿景。愿景为战略目标奠定基础。这里有几个数据愿景的例子。“5 年内,80%的销售额将来自数字销售。”另一个例子,“我们一半以上的管理工作将有自动化流程,这将消除手动耗时的任务。”

请记住,在开发数据目标的过程中,将它们分散到多个业务部门是很有帮助的。数据转换影响到公司的多个部门,并且不是单独完成的。换句话说,不要让所有的 KPI(关键绩效指标)都是财务的。除了财务指标之外,还要检查与转型相关的其他因素,如客户满意度、节省的时间、减少的错误等。

寻找开始数据转换的地方

根据你的企业规模,这可能比其他人更容易。我们将从大公司的角度来讨论,因为小公司只需要较少的步骤。任何做过任何形式的组织管理的人都知道,这需要很多时间。我记得我与一位前财富 500 强高管的对话曾告诉我,“我们的公司就像浴缸里的战舰。转向需要时间。”开始的一个方法是选择公司中你认为会产生显著影响的部分。在大多数情况下,这恰好与销售、营销或避免巨额成本有关。

请记住,技术支持业务

人是感性的。在丹尼尔·卡内曼的书中,思维,快和慢陈述了思维有两个系统[1]。系统一更快更感性。系统二缓慢、复杂,而且耗费脑力。大多数人在系统一中思考。当人们被激情激怒时(系统一),他们往往会变得过分热情,有时会失控。在数据转换的情况下,与其他选择相比,数据领导者有时会沉迷于多种技术的潜力,而没有为业务实现任何实质性的价值。

技术意味着提高业务效率,从而为市场或客户带来更高的价值。一个可以使用的实用方法是敏捷方法。敏捷宣言是一个可以应用于任何项目的软件开发框架,它关注于创造价值而不是庞大的计划[2]。在商业中,价值可以定义为更多的销售、自动化程度的提高、风险的降低等等。一个功能性的原型比仍在开发中的完美系统好一百倍。

建立有回报的预算

在制定数据转换计划时,幸运的是,大部分成本都很容易估算,而且可信度很高。你知道你需要购买多少技术,员工工资,培训费用等等。

另一方面,收益的不确定性更大。例如,我参与的一个项目是用人工智能模型开发一个改进的信用风险管理。一个主要问题是数据质量差。一旦数据质量提高,它不仅有助于信用模型,也有助于其他风险经理评估他们的手动决策,该模型的援助。类似地,对于看不见的事件,组织也有改变的成本或接受的成本。人们的改变需要时间,这一点必须在预算项目的预期持续时间中考虑进去。

结论

在实现数据转换的过程中,数据远景充当了一个目标,从中可以推导出策略和具体的操作步骤。与所有其他目标一样,数据愿景必须支持一个期望的目标,包括具体的、可衡量的任务以及最终期限。为了获得更高的初步成功机会,从公司中对收入或利润有重大影响的部分开始。

一旦最初的项目成功了,你就可以更容易地将愿景应用到业务的其他部分。在转型的过程中,请记住所应用的技术是为了支持业务。不要为了追求新技术而追求新技术。你的项目在改善业务方面有一个关键的价值。就预算规划和估算回报而言,成本很容易估算,而收益是多方面的,有时是不可预见的。这是一件好事,这是数据科学为什么会存在的一个例子。

最后一个实用的注意事项是,当与决策者和关键利益相关者谈论过程改进时,一定要记住解释改进如何帮助他们的角色。大多数人倾向于认为 AI 会抢走他们的工作。事实上,我们正在让他们的角色变得更轻松,这样他们就可以专注于更重要的任务,从而改善他们的生活并使业务受益。

免责声明:本文陈述的所有内容均为我个人观点,不代表任何雇主。此外,这篇文章包含附属链接。

来源

[1] D .卡尼曼,思考,快与慢 (2013),法勒,斯特劳斯和吉鲁

[2] W. Cunningham,敏捷软件开发宣言(2001),https://agilemanifesto.org/

借助英特尔 Movidius NCS2,将 Raspberry Pi 3B+变成强大的对象识别边缘服务器

原文:https://towardsdatascience.com/turning-a-raspberry-pi-3b-into-an-object-recognition-server-with-intel-movidius-ncs2-8dcfebebb2d6?source=collection_archive---------9-----------------------

我们通过部署 MobileNet-SSD 架构,使用英特尔 OpenVINO 平台,将 raspberry PI 3B+变成一个对象识别服务器。

The Intel NCS2 attached to a Raspberry Pi Model 3B+, the hardware used in this tutorial

在这一部分中,我们将在英特尔神经计算棒中使用一个易于编译的神经网络,以便它能够接收 Base64 编码的图像,并将它们转换为边界框预测。此外,还将提供一个向 PI 发送摄像机输入的前端示例。请不要忘记查看由 Mattio Varile 撰写的关于如何部署和测试模型的精彩 w 评论。

  • 预训练和编译的模型将在附件中提供。
  • 为自定义数据集训练和编译模型以及前端的更多细节将是另一个故事的一部分,敬请关注!

System diagram visualizing the flow of information via numbers. Click here for the draw.io diagram: https://drive.google.com/file/d/17yTw1YnhjOJh_EjIYLqGVYuYjnB8pKyl/view?usp=sharing

0。要求

  • 1。准备树莓酱
  • 1.1。安装 NOOBS 镜像
  • 1.2。安装最新的英特尔 OpenVINO 软件
  • 1.3。在神经计算棒上部署对象检测
  • 3。运行服务器并设置开机自动启动
  • 4。使用示例 GUI 部署我们的服务器
  • 5。结论和展望

更新 1,2019 年 5 月 29 日:现在包括系统图,
更新 2,2019 年 8 月 5 日:pybase64 因未使用而从要求中删除

0.要求

  • 树莓派,最好是 3B+型,但其他型号也可以https://www.raspberrypi.org/products
  • 英特尔 NCS 2https://software.intel.com/en-us/neural-compute-stick

可选择的

  • 一些 USB 摄像头
  • 一些其他的计算机来运行前端

1.准备树莓酱

1.1.安装 NOOBS 映像

在 FAT32 格式的微型 SD 卡上刷新 NOOBS 图像。https://www.raspberrypi.org/downloads/

正常启动 USB 镜像,设置账户密码,连接互联网等…

确保同时安装 python3、pip3 和 wget

sudo apt-get update
sudo apt-get install python3-picamera python3-pip wget

1.2.安装最新的英特尔 OpenVINO 软件

下载 OpenVINO 工具包

cd ~/Downloads && wget [https://download.01.org/opencv/2019/openvinotoolkit/l_openvino_toolkit_raspbi_p_2019.1.094.tgz](https://download.01.org/opencv/2019/openvinotoolkit/l_openvino_toolkit_raspbi_p_2019.1.094.tgz)

我建议遵循以下指南,直到(不包括)“构建和运行对象检测示例”一节。

[## 为 Raspbian*操作系统安装 OpenVINO 工具包——open vino 工具包

open vino toolkit 以前被称为英特尔计算机视觉软件开发套件。这些步骤适用于 32 位 Raspbian* 9 操作系统…

docs.openvinotoolkit.org](https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_raspbian.html)

成功完成所有操作后,当您打开一个新的终端时,您应该会看到以下输出:

1.3.在神经计算棒上部署对象检测

我们将使用 flask 服务器来接收用于预测的编码图像。你可以在下面的 github 库【https://github.com/AlexeyGy/NCS2-server 找到所有的代码

a)首先在您的主文件夹中创建一个名为 detection_server 的新文件夹。

mkdir ~/detection_server && cd detection_server

b)用以下内容创建一个 requirements.txt 文件。该文件包含所需的包。

  • flask 是网络服务器,flask-cors 是传递 cors 头的包装器(跨站点脚本需要),更多关于它的在这里
  • 注意 OpenCV (cv2)不在这个包列表中,因为这个包是在步骤 1.2 中与 OpenVINO 一起安装的。这是因为 OpenVINO 提供了自己的 cv2 风格,包括对 CNN 架构的支持。
flask-cors
flask

现在快跑

pip3 install -r requirements.txt

自动安装软件包。

c)设置服务器启动脚本,创建一个名为 RUN 的文件。嘘

d)下载预训练的 MobileNet-SSD 架构中间表示文件,该文件可以区分螺钉和 rawl 钉。请继续关注本教程的第二部分,我们将讨论培训。

mkdir models && cd models && wget [https://github.com/AlexeyGy/NCS2-server/raw/master/models/no_bn.bin](https://github.com/AlexeyGy/NCS2-server/raw/master/models/no_bn.bin) && wget [https://github.com/AlexeyGy/NCS2-server/raw/master/models/labelmap.prototxt](https://github.com/AlexeyGy/NCS2-server/raw/master/models/labelmap.prototxt) && wget [https://raw.githubusercontent.com/AlexeyGy/NCS2-server/master/models/no_bn.xml](https://raw.githubusercontent.com/AlexeyGy/NCS2-server/master/models/no_bn.xml)

您可以看到该架构包含三个文件,一个包含可能标签的 labelmap,一个包含冻结网络权重的. bin 文件和一个包含网络拓扑的. xml 文件。更多信息可以在这里找到。

Intel IR model. Image courtesy of Intel https://software.intel.com/sites/default/files/managed/ed/e9/inference-engine-700w-300h.png

e)现在让我们创建实际的服务器,使用以下内容创建文件 server.py。下面将提供关于各个功能的更多细节。

  • 在第 12 行,我们使用英特尔 OpenVino cv2.dnn.readNet 函数读取提供的模型文件
  • 第 14 行为我们的计算设置了一个更好的运行目标
  • 第 17- 19 行包含了我们的 flask 服务器的一些标准配置,
  • 第 23 行使用 flask-cors 包装器来设置 cors 头,更多信息在这里
  • 第 25–29 行是可选的,它们为所有不包含正确格式的 jpg 或 png 图像的输入数据设置了一个过滤器
  • 第 31 行为我们的 flask 服务器设置了默认路由,我们接受包含图像的 POST 请求
  • 除了传递给服务器 s.t .的图像之外,第 37 行还允许我们接受一个阈值。所有低于阈值的预测都不会返回
  • 第 43 行返回预测结果的 JSON
  • 第 46–50 行中的函数执行实际的图像处理,我们稍后将进入相应的 util_mobilnet.py 文件。以下是对其功能的高级概述
    —首先执行特定于 Mobilenet-SSD 架构的预处理和缩放步骤
    —然后网络进行推理(第 48-49 行)
    —最后执行后处理步骤,包括阈值过滤

f)最后,让我们创建并查看 util_mobilnet.py 文件

  • 第 5 行配置了 mobilnet 需要的尺寸,因为它是在 300x300 的正方形图像上训练的,我们将它设置为我们的尺寸
  • read_labels 函数逐行读取 labelmap 文件来定义支持的类
  • 第 21 行中的预处理函数处理传入图像的颜色和尺寸,mobilnet 需要任意的转换来正确处理图像
  • 第 32 行中的后处理函数检查所有预测,并过滤掉低于阈值的预测,此外,不返回背景预测

3.运行服务器并设置启动时自动启动

为了最小化 raspberry PI 上的资源使用,我们想要建立一个客户端服务器应用程序,其中 flask 服务器接收图片并返回边界框预测。

我发现自动启动烧瓶的最佳方法是 a)将烧瓶启动添加到。b)使用自动登录将系统设置为自动启动到 cli。

a)至于将这些行添加到。bashrc 文件,确保将“Downloads”文件夹设置为您下载 OpenVINO 工具包的文件夹

b)在终端中运行以下行

sudo raspi-config

您将看到以下屏幕,您应该在其中选择选项 3 引导选项/ 1 桌面 CLI / 2 控制台自动登录

select the options as per screenshots

现在,启动后,你会看到树莓会在端口 5000 上自动启动 flask 服务器,恭喜!

4.使用示例 GUI 部署我们的服务器

以下步骤应该在另一台机器上执行,但是如果您选择在 Raspberry 上运行 GUI,它们也可以在 Raspberry 上执行(这会导致性能降低)。

克隆库https://github.com/AlexeyGy/NCS2-frontend

git clone [https://github.com/AlexeyGy/NCS2-frontend](https://github.com/AlexeyGy/NCS2-frontend)

只需运行运行。SH 文件来运行一个简单的 python 服务器。你可以通过 localhost:8000 访问它,但是在你看到任何图像之前,你可能需要让它访问你的相机。

permission request

服务器会将网络摄像头图片发布到地址 http://192.168.0.2:5000/ ,如果您使用的不是您的 raspberry,请确保将其定制到您的 raspberry 的地址。

我会写另一篇文章,介绍 JavaScript 前端如何确保边界框绘图只有在收到来自我们的 raspberry 服务器的新响应时才会刷新。

给定的示例 GUI 来自 FIR 的一个试点演示器,我们用它来演示智能合同平台的可能用例。在以后的文章中会有更多的介绍。

您可以通过浏览器的 JavaScript 控制台调试设置。

5.结论和展望

这是前端和后端一起运行的整个系统的 gif 图:

螺丝和罗尔塞的检测示例

如果在两台机器上运行,运行的系统能够传送 60fps 的视频,检测时大约 8 fps。用户体验不会受到影响,因为预测是由 JavaScript 前端以异步方式显示的。我发现太多的检测帧会导致糟糕的用户体验,因为检测更新得太快了!

随着边缘计算的到来,像谷歌这样的其他竞争对手也加入了这场竞赛,我们将迎来神经计算棒的一些令人兴奋的未来用例。

请继续关注培训和前端设计部分。

资源

  • Mattio Varile 撰写的关于如何部署和测试模型的文章
  • 英特尔神经计算棒官方教程
  • 更多关于 Movidius on Raspberry inc .的信息性能测量作者Adrian rose Brock

将数据转化为可操作的见解

原文:https://towardsdatascience.com/turning-data-into-actionable-insights-c246969fa4c?source=collection_archive---------14-----------------------

Credit: Alaa Khamis

数据和见解

洞察力是新的黄金,而不是数据,因为数据没有价值,除非这些数据转化为重要的可操作的洞察力。这些见解可用于支持决策,并有助于改进设计和制造流程。机器学习算法可以用来完成不同的应用数据挖掘任务。这些任务可以是描述性分析、预测性分析、诊断性分析和规定性分析。描述性数据分析提供对过去和现在的洞察,而预测性分析预测未来。诊断分析提供根本原因分析,说明性分析就可能的结果及其预期影响提出建议。

数据分析

描述性数据分析提供了对数据及其性质的更好理解,并识别数据中的模式或关系。这些描述性模型回答了以下问题:

  • 发生了什么事?
  • 现在发生了什么?
  • 某个变量的趋势是什么?
  • 变量之间有什么关系?
  • 一个项目相对于其他项目或基准项目的表现如何?

预测模型对数据的未来值进行预测,并预测新的特性,而不是像描述性分析那样只是探索数据属性。这些模型回答了以下问题:

  • 会发生什么?
  • 什么时候会发生?
  • 会在哪里发生?

诊断分析提供根本原因分析来回答以下问题:

  • 为什么会这样?
  • 为什么会这样?

最后但并非最不重要的一点是,规范模型侧重于决策支持。这个决策支持或推荐引擎回答以下问题。

  • 从预测模型中获得的预测会如何影响其他一切?
  • 需要做出什么样的主动决策/行动?
  • 我们如何从预测/建议中受益?
  • 最好的行动是什么?
  • 采取这一行动的最佳时机是什么?
  • 这一行动会产生什么影响?

以预测性维护为例

预测性维护是一种预防性维护方法,它依赖于对实际机器状况、运行效率和运行状况的其他指标的定期监控和分析,以检测早期问题,最大限度地减少计划外停机的次数和成本,并防止关键设备发生灾难性故障。根据麦肯锡的数据,到 2025 年,预测性维护将帮助公司节省 6300 亿美元。幸运的是,机电设备不会毫无征兆地损坏。故障发生前几个月,可以发现最小的振动。故障前几周,明显的噪声开始出现。在机器升温前几天和故障前几分钟,它开始冒烟。

Data Analytics | Credit Alaa Khamis

在这种情况下,描述性分析可以洞察机器的当前状况。而预测模型可以执行健康评估并预测任何初期问题或可能的故障或异常。诊断分析提供根本原因分析,最后,说明性分析模型可以处理由描述性分析模块生成的关于机器当前状态的信息、来自预测性分析模块的健康评估以及任何其他可用的先验知识。然后,它会针对主动行动或维护计划提出及时的建议/决策,以降低任何可能的风险。使用这些推荐的决策和由说明性分析模型生成的预期影响信息,用户可以考虑最高优先级的维护需求来主动规划维护,或者可以创建工作订单并向指定的技术人员发送关于所需维护的消息,以便保持生产力并减少停机时间和维护支出。

数据汇总、可视化、聚类、数据关联和序列发现是描述性分析中的常见任务。而预测分析使用分类、回归和时间序列分析来提供信息,如异常预测、故障风险评分、故障前时间或剩余使用寿命估计和/或退化趋势。诊断分析使用事件和因果因素分析、变化分析、障碍分析、故障树分析和自然语言处理等技术来解释可能的故障原因。规定性分析采用来自机器学习、算法推理、优化和自然语言处理的不同人工智能技术来提供建议,以减轻机器中任何可能的风险。

在当前弱/窄的 AI 浪潮中,分类和回归是最常见的成熟和使用的 ML 技术。强/一般人工智能浪潮将使更复杂的 ML 技术成熟,以处理更多依赖于认知数据收集和准备、聚类、数据关联和时间序列分析的数据,包括序列发现、趋势/周期性/季节性、相似性分析和存档、流式和实时数据中的异常检测。

将数据转化为声音

原文:https://towardsdatascience.com/turning-data-into-sound-4854a35b3504?source=collection_archive---------8-----------------------

听起来是个好主意!

Photo by Spencer Imbrock on Unsplash

我在西蒙·罗杰斯的帖子的启发下,介绍了 TwoTone ,一个将数据表示为声音的工具,我创建了我的第一个数据“发音”(也就是数据的音乐表示)。这让我特别感兴趣,因为我只梦想创造令人瞠目结舌的可视化效果,但从未想过我可以将数据转换成另一种格式,尤其是声音。这篇文章涵盖了双音以及如何使用它的基础知识。

什么是发音?

发音是指使用声音来表示数据,通常是为了补充或取代传统的可视化。尽管它已经存在了相当长的时间(1908 年首次使用),但它还没有像可视化一样被探索——这使得它成为想要尝试新事物(和酷)的人的绝佳选择。

什么是 TwoTone?

TwoTone 由数据化技术在谷歌新闻倡议的支持下构建,是一个进行发音的工具。它既是一个网络应用程序(在你的浏览器上运行),也是一个命令行应用程序(在你的电脑上运行),允许没有任何音乐或技术背景的用户从他们的数据集创建声音,以便更好地理解它们!

有了上面的特性,对于想打入数据科学领域而没有太多背景知识的人来说,它是一个非常棒的工具!这很容易上手。

数据如何转化为音频?

为了将数值转换成音频,TwoTone 使用音阶,由此较高的值对应于较高的音高。你可以在这里阅读更多关于它的信息。事不宜迟,让我们开始使用双色调吧!

如何使用 TwoTone?

在这篇文章中,我将使用 TwoTone 的更加用户友好和易用的网络应用。

前往 app.twotone.io 开始吧!您不需要帐户,但您肯定需要数据集—您可以选择自己的帐户,也可以使用任何可用的默认帐户。点击“开始”按钮后,系统会提示您选择“数据源”

TwoTone accepts any form of tabular data with the above specifications

我将使用数据集“美国历史收入、公共债务和 GDP”,这是 TwoTone 作为样本提供的数据集之一。也可以选择添加自己的数据(确保符合要求)。

在您按下“选择”后,您将获得一个门户网站的迷你导览(请不要跳过)。随着巡演的突出显示,一个音频轨道是自动为您生成的!你说完了吗?号码

重要的一点是,TwoTone 仅支持每个音轨一个数据源,这对于音阶来说有直观的意义。但是,您可以添加多个“轨道”来添加更多的数据!

很明显,你可以用数据做更多的事情,为什么要降低要求呢?让我们探索一些有趣的特性:

1:不同的乐器

Photo by John Matychuk on Unsplash

是的,你没听错。您可以选择用不同的工具来表示您的数据!弹出打开音轨的乐器下拉菜单,您可以查看以下菜单:

Different instruments supported by TwoTone

没错!您可以在 12 种不同的乐器中“声音化”您的数据!选择您最喜爱的乐器,然后按下播放按钮,聆听您的数据。

2:多首曲目——成为 DJ

Photo by Skullector R on Unsplash

是的,你也可以通过混音成为 DJ。点击右下方的“+”图标添加另一个音轨,并选择“音阶”(我们稍后会谈到另一个选项)。Tada!还会自动为您创建另一个音频轨道。现在,你可以改变数据源或乐器来改变这个轨道的声音,并尝试混合!

PS:不一定要停在两条轨道上。

3:带旁白的讲故事

Photo by Jason Leung on Unsplash

添加另一个轨道时还记得另一个选项吗?那是旁白!您可以通过在曲目之间或期间进行叙述,将自己的声音添加到数据中,并制作成一个美丽的故事。通过这种方式,您可以用数据讲述一个“故事”,并从多个受众的数据中获得见解和意义。

完成后,您可以导出音频(右下角)并将其下载到您的计算机上!这是我第一次发音!

如果你制作了一个发音,请通过回复这个故事或发送给我来与我分享!我总是对用数据(和发音)讲故事感兴趣。

将 Lending Club 的最差贷款变成投资黄金

原文:https://towardsdatascience.com/turning-lending-clubs-worst-loans-into-investment-gold-475ec97f58ee?source=collection_archive---------15-----------------------

So shiny…

我们使用机器学习从 Lending Club 最垃圾的贷款中挖掘利润

这是我完成的一个机器学习项目的文字记录。在这篇文章中,我希望:

  • 描述一下我预测贷款违约的算法。
  • 使用该算法构建一个获得高于平均回报率的清洁贷款投资组合。
  • 介绍并解释 ROC 曲线、精确度和召回率。

你可以在我的 GitHub 上找到我用来运行分析的 代码。

L ending Club 是最初的 P2P 贷款公司之一,也是金融科技的宠儿(尽管不再是了),是一项有趣的业务。他们通过把想借钱的人和愿意借钱的人联系起来来赚钱。Lending Club 通过筛选出风险最高的借款人,并使用其专有算法为所有通过筛选的贷款申请人分配一个等级(和利率),从而为这一过程增加价值。

我们今天对它们感兴趣,因为它们提供了目前很少有其他投资资产提供的东西——丰厚的利率。对于那些关注金融趋势的人来说,你们知道自 2008 年金融危机以来,美联储(美国中央银行)已经将收益率推至并维持在历史低位。请查看下面的图表:

The One Year Treasury Bill Rate is Pretty Low These Days

这种低利率货币政策的最终结果是整个风险范围内的收益率下降(收益率是利率的另一种说法)。从抵押贷款利率到高收益债券(向负债水平相对于收入较高的公司发放的贷款)的利率,所有收益率都被压缩至历史低点,因为投资经理会购买任何能够为他们带来可观回报的东西。

如果你有兴趣投资一些能给你固定利率的东西,这是你的选择菜单(见下图)。在通胀和美国国债勉强跑赢通胀后,你的银行账户为你赢得了负回报。将风险曲线进一步延伸到各种类型的公司债也没有多大帮助。但是那边是什么?

Inflation Adjusted Yields for Various Investment Assets

粉色条真的跳出来对吧?“Lending Club High Yield”是 Lending Club 的 D、E、F 和 G 评级贷款收益率的加权平均值(其中 A 最高,G 最低)。这些垃圾贷款(金融业对风险贷款的说法)比它们的高评级(A、B 和 C)同行提供了更高的收益率。A、B 和 C 级贷款的平均收益率比垃圾贷款的收益率低大约 12%

问题是

那么有什么问题呢?问题是这些垃圾贷款的违约率极高。

我看到大约 28%的垃圾贷款违约了!(我的数据集是 2015 年由 Lending Club 发起的每 36 个月的贷款)

下图显示了这一巨大的违约率是如何影响我们本以为会获得的 15%的收益率的。违约让我们的通胀调整收益率从 15%下降到仅仅 2%!2%的回报包括收回的部分——在借款人违约后从借款人那里提取的欠款。

After Defaults, Lending Club Junk Loans Yield Very Little (All Yields are Inflation Adjusted)

但是还是有希望的!

并非一切都没了。如果我们能够建立一个分类模型,可靠地预测哪些贷款将成为坏账,那么我们就可以将投资集中在我们的模型认为最不可能违约的垃圾贷款上。首先让我们后退一步,回答这个问题,“什么是分类模型?”

分类是机器学习算法的一个流行目标——我们想知道一个观察值属于哪一类(也称为组)。对观察结果进行精确分组的能力对于各种业务应用程序非常有用,比如预测某个特定用户是否会购买某个产品,或者预测某笔贷款是否会违约。

如果上面的段落听起来很熟悉,那是因为我几乎一字不差地引用了之前的博客文章。在那篇文章中,我写了大量关于随机森林分类器的内容——我们现在将使用该算法将每笔贷款分类为可能违约或不可能违约。

如果你想更深入地了解随机森林是如何工作的,请阅读那个帖子。但是这里是 TLDR — 随机森林分类器是许多不相关的决策树的集合。树木之间的低相关性产生了多样化效应,使得森林的预测平均优于任何单个树木的预测,并对样本外数据具有鲁棒性。

随机森林算法采用以下两种技巧来减少树之间的相关性—【bagging】(引导聚合)和特征随机性(查看我在随机森林上的帖子了解更多)

特征选择

我用来构建模型的贷款数据和特征来自 Lending Club 的网站。我下载了。包含 2015 年承保的所有 36 个月贷款数据的 csv 文件。如果你在没有使用我的代码的情况下玩他们的数据,一定要仔细清理以免数据泄露。例如,其中一列代表贷款的收款状态——这是我们在发放贷款时肯定无法获得的数据。

正如贷款数据所预期的那样,大多数特征都与借款人的个人和财务特征有关:

  • 房屋所有权状况
  • 婚姻状况
  • 收入
  • 债务收入比
  • 信用卡贷款
  • 贷款特征(利率和本金金额)

因为我有大约 20,000 个观察值,所以我使用了 158 个特性(包括一些自定义特性——ping me 或查看我的代码,如果你想知道细节的话),并且依赖于适当地调整我的随机森林来保护我免于过度适应。

使用 ROC 曲线的模型选择

尽管我让它看起来像随机森林和我注定要在一起,我也考虑过其他模式。下面的 ROC 曲线显示了这些其他模型如何与我们心爱的随机森林(以及随机猜测,45 度虚线)相比较。

ROC Curves for the Various Classification Models I Tried (Validation Data)

等等,你说什么是 ROC 曲线?我很高兴你这么问,因为我写了一整篇关于它们的博文!

万一你不想读那篇文章(真让人难过!),这是一个略短的版本 ROC 曲线告诉我们,我们的模型在收益(真阳性率)和成本(假阳性率)之间的权衡有多好。让我们根据我们当前的业务问题来定义这些意味着什么。

The Confusion Matrix

  • 真阳性率,也称为召回率,是真阳性与实际违约的比率。在我们的混淆矩阵(左侧)中,它是绿色方框除以绿色和黄色方框之和。它告诉我们用我们的模型正确分类的实际违约的百分比。**
  • 误报率是误报与实际无违约的比率。在我们的矩阵中,它是红色方框除以红色和蓝色方框之和。它告诉我们被我们错误归类为违约的干净贷款的百分比。**

关键是要认识到虽然我们想要一个漂亮的大数字在绿盒子里——增加真阳性也是以牺牲红盒子里更大的数字为代价的(更多的假阳性)。

让我们看看为什么会出现这种情况。对于每一笔贷款,我们的随机森林模型都给出了违约概率。但是什么构成了默认预测呢?25%的预测概率?50%呢?或者我们想额外确定 75%?答案是视情况而定。

决定一个观察值是否属于正类的概率截止值是一个我们可以选择的超参数。

这意味着我们的模型的性能实际上是动态的,并根据我们选择的概率截止值而变化。如果我们选择一个非常高的截止概率,如 95%,那么我们的模型将只把一小部分贷款归类为可能违约(红色和绿色框中的值都很低)。但另一方面,我们的模型只捕获了实际违约的一小部分——或者换句话说,我们的真实正利率很低(黄色框中的值比绿色框中的值大得多)。

如果我们选择一个非常低的截止概率,例如 5%,就会出现相反的情况。在这种情况下,我们的模型会将许多贷款归类为可能违约(红色和绿色框中的大额贷款)。由于我们最终预测大多数贷款将会违约,因此我们能够捕捉到绝大多数的实际违约(高真实正利率)。但结果是,红框中的值也非常大,因此我们背负着很高的假阳性率。

How a ROC Curve is Generated

回到 ROC 曲线

哇,这是一个比预期更长的题外话。我们终于准备好复习如何阅读 ROC 曲线了。

左边的图表显示了 ROC 曲线上的每条线是如何绘制的。对于一个给定的模型和截断概率(比如截断概率为 99%的随机森林),我们通过其真阳性率和假阳性率将其绘制在 ROC 曲线上。在我们对所有截止概率做了这些之后,我们在 ROC 曲线上画出一条线。

但这实际上意味着什么呢?

右边的每一步都代表着截断概率的降低——伴随着假阳性的增加。因此,我们需要一个模型,对于每一个额外的假阳性(产生的成本),该模型能够获得尽可能多的真阳性。

这就是为什么模型越呈现驼峰形状,其性能就越好。曲线下面积最大的模型是驼峰最大的模型,因此也是最好的模型。

咻终于解释完了!回到上面的 ROC 曲线,我们发现 AUC 为 0.61 的随机森林是我们的最佳模型。其他一些有趣的事情需要注意:

  • 名为“Lending Club Grade”的模型是一个以 Lending Club 自己的贷款等级(也包括子等级)为特征的逻辑回归。虽然他们的成绩显示出一些预测能力,我的模型优于他们的这个事实暗示着他们,不管是有意还是无意,没有从他们的数据中提取出所有可用的信号。

Average Interest Rate and Investor Return for Lending Club Loans (2007 to Q1/2019)

  • 雪上加霜的是, Lending Club 的高风险贷款表现不如它们的安全贷款,这是现代投资组合理论的信徒所厌恶的(左图)。这里的含义是,Lending Club 可能不会向风险较高的借款人收取足够高的利率。我的预感是,达到收入目标的压力正迫使他们收取更低的利率,以吸引更多的借款人。
  • 朴素贝叶斯分类器产生的结果与随机猜测的结果相同。在某个时候,我会写这个模型,但我对它的糟糕表现感到惊讶。

为什么是随机森林?

最后,我想详细解释一下为什么我最终选择了随机森林。仅仅说其 ROC 曲线的 AUC 最高是不够的,即曲线下面积(逻辑回归的 AUC 几乎一样高)。作为数据科学家(即使在我们刚刚起步的时候),我们应该寻求理解每个模型的利弊。以及这些利弊如何根据我们正在分析的数据类型和我们试图实现的目标而变化。

我选择了随机森林,因为我的所有特征与目标变量的相关性都很低。因此,我觉得从数据中提取一些信号的最佳机会是使用一种算法,这种算法可以捕捉我的特征和目标之间更微妙的非线性关系。我还担心过度拟合,因为我有很多特征——来自金融,我最糟糕的噩梦总是打开一个模型,看到它以惊人的方式爆炸,第二次我把它暴露给真正的样本数据。随机森林提供了决策树捕获非线性关系的能力,以及它自己对样本外数据的独特鲁棒性。

特征重要性

scikit-learn 中的随机森林实现有一个方便的“feature_importances_”属性。如果我们检查一下我们的模型,我们会发现三个最重要的特征是:

  1. 贷款利率(很明显,利率越高,月供越高,借款人违约的可能性越大)
  2. 贷款金额(与以前相似)
  3. 债务收入比(负债越多,违约的可能性越大)

精确度和召回率

好了,我们现在有了模型,所以终于到了构建投资组合的时候了。也是时候回答我们之前提出的问题了,“在决定是否将贷款归类为可能违约时,我们应该使用什么样的概率截止值?”

让我们定义两个关键术语:

Precision: 当我们的模型将一笔贷款归类为可能违约时,它实际违约的概率是多少?

强调精确度的模型具有高概率截止值,并且会导致更多的假阴性。

回想一下:在所有实际违约的贷款中,我们的模型标记了多少可能违约的贷款?

一个强调回忆的模型有一个低的概率截止值,会导致更多的假阳性。

分类中一个关键但又被忽视的部分是决定是优先考虑精确度还是召回率。这与其说是一个数据科学问题,不如说是一个商业问题,它要求我们对我们的目标有一个清晰的认识,以及假阳性的成本与假阴性的成本相比如何。

我强烈主张召回。请记住,我们的目标是找到一套我们可以放心投资的干净贷款。假阴性(我们预测没有违约,但贷款违约)会让我们付出真金白银的代价,而假阳性(预测违约,但贷款没有违约)只是一种机会成本——因此,即使贷款看起来有点不可靠,我们也应该扔掉它。总会有更多的贷款可供选择,所以在决定是否投资我们辛苦赚来的钱时,我们应该非常谨慎。

让我们用一个概率截止值 20%。

最后,投资结果

我有一个秘密要坦白——在我们分析的开始,我隐藏了大约 6500 笔贷款,这样我们现在可以用它们来执行真正的样本外测试。让我们看看我们做得怎么样。

在我们测试的 6500 笔贷款中,有 28%违约。但是在我们的模型归类为安全(不太可能违约)的大约 450 笔贷款中,只有 15%违约。我们能够将违约频率降低近 50%!

这很酷,但当我们将其转化为回报时,情况会是怎样呢?Lending Club 建议投资者购买并持有至少 100 笔贷款的投资组合(以实现多样化)。因此,让我们使用蒙特卡罗模拟,从整个测试集中随机选择 100 笔贷款,并从我们的干净集(由我们的模型挑选的贷款)中反复选择 100 笔贷款(我们将运行 5000 次模拟),看看我们做得如何。

Return Comparison — Model Picked Loans vs. All Loans

当我们只投资于我们的模型所选择的贷款时,我们成功地将获得的回报从整个测试集的 6%提高到了 12%!胜利!

结论

看起来我们能够成功预测哪些贷款更有可能违约,避免它们,并最终获得显著更高的回报。

我们还了解了更多关于随机森林的知识,如何解释 ROC 曲线,以及精度和召回因素如何影响我们模型的概率截止值。

如果你喜欢这个,请看看我的其他帖子(下面的链接)。干杯!

链接

更多来自数据科学上的真知:

了解随机森林如何工作

了解逻辑回归如何工作

我的数据科学训练营经历

更多来自贵府的真才实学:

股票比现金有超额回报吗?

下一次股市低迷可能会是什么样子

把你的手机摄像头变成一个物体探测器(靠你自己!)

原文:https://towardsdatascience.com/turning-your-mobile-phone-camera-into-an-object-detector-on-your-own-1428055b8e01?source=collection_archive---------20-----------------------

是时候释放你相机的潜能了!

如果更多人只需几行代码就能把手机摄像头变成物体探测器,会怎么样?写这个故事是为了给大家的生活注入乐趣!这可能是开始学习 JavaScript 和反应的一个很好的方法!

这个故事假设了 JavaScript、npm 和 React 的简单基础知识。嗯,可能真的很容易实现,只要按照步骤!如果你需要任何帮助,请在下面给我留言。

安装和初始准备

为了安装 npm,安装 Node.js ,npm 就会随之而来。然后,启动“命令提示符(cmd)”,指向要安装 React 应用程序的目录,并输入以下命令:

npx create-react-app obj-detector
cd obj-detector
npm install @tensorflow/tfjs @tensorflow-models/coco-ssd

该命令将创建一个新的 React 应用程序和一个名为“obj-detector”的新目录。然后它将安装 tensorflow.js 和 COCO-SSD(也称为上下文中的公共对象和单次多框检测)。

代码

进入 obj-detector/src/ 目录,打开这个文件 App.js 。用以下代码替换所有内容:

接下来,用以下代码替换 App.css 中的所有内容:

.app-position {
  position: fixed;
  margin: auto;
}

仅此而已,真的!是时候部署应用程序了。

部署

回到控制台,当您在目录 obj-detector 中时,输入以下命令来部署应用程序:

npm start

过一会儿,你应该能在你的浏览器上看到一个指向 http://localhost :3000 的页面。允许使用您的网络摄像头,并花时间玩您的物体检测器!请注意,用于检测的文件相对较大,因此需要一段时间才能开始工作。

等等,你不是说我们可以用手机吗?

是的,当然。然而,还有几个步骤要做。

首先,下载这个软件 Ngrok 并按照页面上的前 3 步来设置软件。接下来,在保持运行 npm start 的现有命令提示符的同时,启动另一个命令提示符并输入以下内容:

# Run the code on cmd while in the directory that has ngrok.exe
ngrok http 3000

You should see this after running the code

接下来,使用你的手机,在你的浏览器中访问 https URL(在我的情况下,是https://5ca 86203 . ngrok . io),像往常一样,给浏览器访问你的相机的权限,等待探测器加载。是时候在你的手机上玩你自制的物体探测器了!

或者,你可以通过这里的访问它,我在 Heroku 上部署它。如果您担心图像的存储,您可以放心,相机不会存储任何图像。(因为是在免费账号上而且我也没有那么大的存储磁盘空间来存储那么多数据!)

Screenshot taken from my iPad. That’s what it can detect!

这就是目前实现的全部内容。如果实施有任何问题,请给我留言。干杯!

一个接一个的项目,我着迷于事物如何使用收集的数据和建立在其上的模型工作,并通过部署模型来解决现实生活中的问题。目前,我在计算机视觉和深入思考我们如何感知世界方面投入了大量时间,希望将其转化为计算机视觉的发展。你可以通过我的 LinkedIn 联系我。

自动性能图创建教程

原文:https://towardsdatascience.com/tutorial-automatically-creating-a-performance-map-of-a-heat-pump-water-heater-7035c7f208b0?source=collection_archive---------24-----------------------

您可以学习在真实世界场景中自动分析实验室数据

许多寻求学习如何用 Python 编程的人要求实际的例子,在那里他们可以通过解决现实世界的问题来学习 Python。它为这个过程提供了更多的背景和意义。

别再看了。这是教程中第一篇这样做的文章。本教程将教你 Python 编程,给出确切的代码,多元回归等数据科学概念,如何自动化整个过程,并通过解决一个常见的工程问题来实现。

我们将解决的工程问题是创建一个性能图,预测热泵热水器的性能,作为周围条件的函数。如果那句话里的专业术语对你没有任何意义,也不用担心。接下来的几节将回答你的问题。

本教程将教你几个重要的概念,例如:

  • "性能图"和"热泵热水器"的定义、
  • 如何编写自动化科学数据分析的 Python 代码,
  • 如何分割数据文件、自动分析测试、检查那些结果是否有错误、验证、记录一个简单的仿真模型,以及
  • 多元回归。

但是首先要做的是。让我们确保你理解上面的术语,因为它们是遵循教程的关键。

什么是热泵?

热泵本质上是一种在两个位置之间传递热量的装置。维基百科上的定义是“热泵是一种将热能从热源转移到所谓的散热器的装置。”热泵的一个例子是美国家庭中常见的家用空调。这些设备将热量从热源(在这种情况下是建筑物的内部)传递到散热器(建筑物的外部)。

"热泵是一种将热能从热源转移到所谓的散热器的装置。"—维基百科

但是热泵是怎么做到的呢?它是如何将热量从冷空间转移到热空间的?通过热力学的“魔力”。图 1 提供了热泵一般功能的示意图。

Figure 1: Schematic of a Heat Pump

制冷剂沿箭头方向流过图 1 中列出的所有设备。制冷剂是设计用于在特定条件下升高/降低温度的传热流体,在热泵中非常有用。

图 1 所示的四个设备都使制冷剂通过不同的过程,驱动热泵。当制冷剂通过系统时,会经历以下过程:

  • 压缩机:压缩机基本上就是一个泵。制冷剂以气体形式进入压缩机,在压缩机中被泵压至更高的压力。当它被泵到更高的压力时,制冷剂变热,导致温度非常高的气体通过冷凝器。
  • 冷凝器:冷凝器是连接制冷剂和散热器的热交换器。由于此时制冷剂的温度非常高,它会将热量散失给散热装置进行冷却。在我们的空调例子中,散热器是外部空气(是的,制冷剂比热空气更热!).制冷剂通过冷凝器时冷凝,形成高压中温液体。
  • 膨胀阀:膨胀阀是将制冷剂导入另一侧的低压环境和条件,使制冷剂膨胀的阀门。随着它的膨胀,它会进一步冷却。这产生了一个低温流体,因为它通过蒸发器。
  • 蒸发器:蒸发器是另一个热交换器,这次连接热源。以空调为例,这是室内的低温条件。由于液体非常冷,它会从室内带走热量,从而提高制冷剂的温度。当它变热时,制冷剂膨胀,导致压缩机产生冷气体。

因此循环重新开始。

设备传递的热量取决于冷凝器和蒸发器的传热速率。正如那些研究过热传递的人所知道的,这些点的热传递速率是由冷凝器和蒸发器周围的空气温度决定的。

在那个描述中有三种不同类型的能量转移。泵消耗电力以确保制冷剂通过循环。热量从制冷剂传递到冷凝器中的散热器。热量从热源传递到蒸发器中的制冷剂。设备传递的热量取决于冷凝器和蒸发器的传热速率。正如那些研究过热传递的人所知道的,这些点的热传递速率是由冷凝器和蒸发器周围的空气温度决定的。

这就产生了术语“性能系数”。性能系数表示相对于泵消耗的能量,从热源传递到散热器的热量。通常超过一个。不过,它对热源和散热器的温度非常敏感。随着这些温度越来越接近制冷剂温度,传递的热量越来越少,因此在不改变所需泵送能量的情况下降低了热泵的性能。

现在我们了解了热泵,下一个要探索的概念是热泵热水器(HPWH)。

什么是热泵热水器?

热泵热水器是一种用于加热水的热泵。他们使用一个大的储水箱,通常有 55 到 80 加仑,储存热水以备不时之需。热泵将周围空气(热源)中的热量传递给储存在水箱中的水(散热器)。图 2 显示了热泵热水器的示意图。

Figure 2: Schematic of a Heat Pump Water Heater

请注意,热泵的四个部分与图 1 中列出的部分相同。唯一真正的区别是冷凝器位于热水储水箱内。这样,热制冷剂将热量传递给水箱中的水。同时,蒸发器将周围空间的热量转移给制冷剂。这样,它将热量从空间中的空气传递到水中。

什么是性能图?

在介绍热泵一节中,我们提到性能系数取决于冷凝器和蒸发器周围的温度。这意味着性能系数将随着周围温度的变化而变化。这些温度会改变。室外温度不是全天恒定的。空调运行时,室内温度会发生变化。

人们可以想象一个曲线图或函数来描述两个温度变化时的性能系数。

这是一张性能图。性能图是在影响设备的条件发生变化时识别设备性能的一种方式。这是一个多变量方程,表示器件性能与这些条件的函数关系。

在科学和工程领域,创建性能图是一项常见的工作。这方面的一个例子是建筑能源模拟。预测新建筑的能源消耗,并设计新的方法来减少建筑能源消耗在美国是一个很大的领域。这些人使用模拟模型来预测建筑的性能。这些模拟模型需要预测安装在建筑物中的设备所消耗的能量。由于热泵用于建筑,这些模型需要预测热泵的性能。这些热泵的性能是由这些模型预测的,使用的是,你猜对了,性能图。

接下来是什么?

这篇文章介绍了理解和遵循教程所需的背景概念。接下来的教程将教你获取一组描述 HPWH 在不同条件下的性能的实验室测试数据并生成性能图所需的步骤。它将教你编写自动完成这项工作所需的 Python 代码。它将让您有机会在现实世界的例子中学习这些有用的技能。

如果你只是通读文章,本教程将会很有用。您将能够理解这些概念,您将看到所有工作都完成了,并且您将看到自己完成这些工作所需的 Python 脚本。然而,它真正有用的地方是,如果你能够编写代码,生成结果,并自己检查答案。为此,我创建了一个配套数据集。如果你下载了数据集,你就能跟上,确保你做的每件事都是正确的,并尽可能多的学习。

可以在这里找到配套数据集。

该数据集包含伪造的结果,模拟您可能从实验室获得的结果。它包含来自三个实验的准数据,展示了热泵热水器随着空间和水温变化的性能。

第一项任务,也是本教程的第一步,是将数据集分割成独立的文件,每个文件提供一次测试的结果。那篇文章很快就会发表。

教程目录

这是一系列文章的一部分,教你自动分析实验室数据和绘制热泵热水器性能图所需的所有技巧。本系列的其他文章可以通过以下链接找到:

分割数据集

自动分析实验室测试数据

检查分析的实验室数据是否有错误

如何编写检查数据质量的脚本

如何在 Python 中自动生成回归

使用置信区间和引导的教程

原文:https://towardsdatascience.com/tutorial-for-using-confidence-intervals-bootstrapping-860ba716aef3?source=collection_archive---------16-----------------------

验证假设检验的另一种方式

Photo by Lisa Fotios

在本教程中,我将尝试展示如何使用 bootstrapping 和置信区间来帮助突出样本分布之间的统计显著差异。

First 5 Rows of albums_data

首先,假设我们有一个名为 albums_data 的数据集,其中包含专辑评论者的姓名、他们给每张专辑的评分以及每张专辑所属的流派。由于一些专辑有多个流派,这些流派是使用虚拟录制的(换句话说,每个流派都有自己的栏)。如果我们想问这个问题“评论者 X 和评论者 Y 在他们如何评论特定流派的专辑方面有统计学差异吗?”我们可以用自举和置信区间来回答这个问题。

马克和斯蒂芬

首先 ,我们需要定义我们要问的问题。让我们假设我们想知道两个评论家,马克和斯蒂芬,在他们如何给电子专辑评分方面是否有统计学上的显著差异。为了回答这个问题,我们创建了两个假设,称为零假设和备择假设。我们的零将永远是没有差别的场景。这是我们的两个假设:

零假设:“Mark 的电子分数和 Stephen 的电子分数之间没有统计上的显著差异。”

替代假设:“Mark 的电子分数和 Stephen 的电子分数之间存在统计上的显著差异。”

Filtering the albums_data to only electronic albums.

其次 ,我们需要过滤我们的 albums_data 只包含属于电子流派的专辑。

Creating two separate datasets for both reviewers.

第三个 ,我们需要为我们想要比较的两个评论者创建两个单独的数据集。我们这样做是为了在引导公式中具体引用每个样本。我们需要的两个数据集是 Mark 和 Stephen 的。

我们差不多准备好出发了!但是,在我们开始之前,让我们先来看看 Mark 和 Stephen 的电子分数的当前分布情况:

Current electronic score distribution, pre-bootstrapping.

正如我们在上面看到的,马克和斯蒂芬的分数有很多重叠。我们还可以看到,斯蒂芬的分布比马克的分布略偏左。然而,我们从图表中看不到的是这两个样本之间是否存在统计上的显著差异。换句话说,我们不能仅仅通过看上面的图表来拒绝或接受我们的零假设。

什么是引导

好了,快休息。我知道我已经读了一半教程,还没有对什么是自举给出一个合适的解释。设置很重要,但是让我快速解释一下引导背后的想法。我们知道我们想要回答的问题是,我们的零假设或替代假设是否正确。任何假设检验的目的都是为了回答整个群体的问题,而不仅仅是为了我们现有的数据。

大多数时候,我们只能处理人口数据的样本。因此,我们需要最大限度地利用我们的样本。为此,我们从样本数据中抽取重复的小样本,计算每个样本的平均值,并创建这些平均值的新分布。如果我们做 10,000 个迷你样本,我们在这个新的分布中将有 10,000 个均值。我们对两个样本都这样做(在上面的例子中,我们对 Mark 和 Stephen 都这样做)。

这是明确的解释。如果这对于你来说是一个新的概念,我保证随着教程的进行,它会变得更有意义。

回到马克和斯蒂芬

因此,正如我们刚刚在上一节中了解到的,我们在自举中的第一步是从我们的数据集中提取一些小样本,并计算每个样本的平均值。我们分别为马克和斯蒂芬做这件事。

下面是创建这些方法列表的代码。为了快速浏览正在发生的事情,我们创建了 10**4(也就是 10,000)个方法列表。每个列表在数据集中选择 100 个随机评论分数来计算平均值。我们这样做是为了马克和斯蒂芬。最终输出是两个列表( sample_mark_elec_meanssample _ Stephen _ elec _ means),每个列表包含 10,000 个均值。

信不信由你,就自举复杂性而言,差不多就是这样了。然而,在当前的列表格式中,它不是特别有用。让我们在图表上查看这些分布:

**

哇!这比我们之前制作的图表更能说明问题。请记住,这里唯一的不同是,这个图表使用了我们从引导工作中获得的 10,000 个随机生成的表示。上图是所有实际分数的分布。

虽然看起来这些分布非常不同,但我们实际上不能说是否有统计上的显著差异。你看到分布中有重叠的地方了吗?我们需要知道每个样本的置信区间是否重叠。如果它们确实与重叠,我们接受我们的零假设,并得出结论:在马克和斯蒂芬的电子分数之间没有统计上的显著差异。

置信区间

好了,关键时刻到了。马克和斯蒂芬的电子成绩在统计上有显著差异吗?首先,我们需要确定我们的假设是单尾的还是双尾的。

单尾:单尾检验要求样本之间的差异在特定方向*。例如,如果我们的替代假设是“马克的电子分数在统计上显著地 比斯蒂芬的电子分数 高”,那么我们将使用单尾测试。*

双尾:双尾检验是假设中不需要方向差异的情况。我们的另一个假设是“Mark 的电子分数和 Stephen 的电子分数之间存在统计学上的显著差异”,这并没有指定任何一个样本需要高于(或低于)另一个样本。它只要求在的任一方向*有差异。*

Two-Tailed Test. Distribution sans 2.5% on each end for 95% Confidence Interval.

所以我们知道我们有一个双尾检验。但是当谈到置信区间时,这意味着什么呢?嗯,澄清什么是置信区间可能很重要。置信区间是我们在接受或拒绝我们的零假设时希望有多自信。如果我们希望 95%确信马克和斯蒂芬的电子分数之间存在差异,我们将有 5%的置信区间。然而,正如我们刚刚在上面学到的,我们有一个双尾检验。这意味着这 5%将被分成样本分布的两个尾部(2.5%在左尾部,2.5%在右尾部,马克和斯蒂芬都是如此)。这个范围也可以写成:2.5%-97.5%之间 (97.5%就是 100%减去 2.5%) 。本质上,这只是切断了马克和斯蒂芬分布的末端,如上图所示。

Calculating the 2.5% and 97.5% confidence interval cutoffs for both samples.

Results from the above code.

现在我们想知道,马克和斯蒂芬的分布(两端各有 2.5%截断* )在我们的 bootstrap 图中重叠吗?这是一个快速而容易回答的问题。我们需要做的就是找出马克和斯蒂芬的 2.5%和 97.5%的值。幸运的是,Python 库 numpy 为我们找到了这些百分比的值。正如我们在输出中看到的,马克的 2.5%和 97.5%临界值在 7.13 和 7.61 之间,而斯蒂芬的临界值在 6.65 和 7.11 之间。*

我们问自己的问题是:“这些分布在两端没有 2.5%的情况下重叠吗?”。我们可以看到 7.11 小于 7.13,这意味着两个分布之间没有重叠。换句话说,我们可以拒绝我们的零假设并以 95%的置信度得出结论,马克和斯蒂芬的电子分数之间存在统计学上的显著差异。

太多了。我希望这篇教程对你有用。记住,这是一个双尾测试。如果它是单尾的(假设一个样本高于另一个样本),我们将把的全部 5%放入一个尾。我们把它放在哪个尾部,取决于我们假设哪个样本比另一个大。

摘要

我想最后一次快速浏览一下这个过程。首先,我们确定想要回答什么问题,并创建适当的无效假设和替代假设。其次,我们为想要比较的两个样本创建两个数据集。第三,我们为每个样本创建我们的自举均值列表。第四,我们可视化的自举平均分布。第五,我们计算置信区间(双尾模型每端 2.5%,单尾模型特定端 5%)。最后,我们比较置信区间并寻找任何重叠。如果没有重叠,我们可以拒绝零假设,接受另一个假设。如果不是,我们接受我们的零假设。

教程:从假设到网络搜集分析

原文:https://towardsdatascience.com/tutorial-from-the-hypothesis-to-the-analysis-with-web-scraping-98ac3c774bd?source=collection_archive---------14-----------------------

一个真正的数据科学项目的教程,收集所需的数据,清理,转换并最终分析它

通常人们有一些有趣的想法来分析,然后发现没有免费的数据来回答这个问题。获取所需数据的一种有趣方式是网络搜集。互联网上有大量的数据,但这些数据无法以结构化的方式进行分析。通常,教程以读取数据开始,以保存数据结束。在本教程中,我想走一条不同的道路。我想带你踏上一个真实世界的数据科学项目之旅。我们从我们的想法开始:我们收集、清理和转换数据,并用收集到的数据集回答我们的问题。更详细的分析不刮部分可以在这里找到

这个想法和我们的假设

近日,2018/2019 赛季全国及国际比赛以足球落幕。传统上,在夏季休赛期,转会窗口打开,俱乐部在市场上争夺最好的球员。令人吃惊的是,同样的俱乐部一次又一次地为他们的球星花费创纪录的金额。仅皇马就在埃登·阿扎尔投资了 1.35 亿英镑。因此,我想探究的问题是,球队的价值和运动上的成功有多大的关联。未来几年除了巴萨和皇马还会有其他冠军吗?其他联赛呢?我的假设是,更高的团队价值也会带来更高的成功。所以我有了一个有趣分析的想法,但是没有数据。然而,我知道网上有球队价值的数据库。所以先来点数据吧!

我们需要一些数据——通过网络搜集收集的数据

网页抓取有不同的软件包。两个最著名的图书馆当然是 Scrapy 和 BeautifulSoup。Scrapy 是一个建立在异步网络库上的强大框架,这使得它非常有性能。它还具有许多功能来避免典型的刮擦问题。这些包括例如重定向、重试请求、避免服务器过载等。然而,由于复杂性,Scrapy 的学习曲线也明显高于 BeautifulSoup。这个库主要用于解析和提取 HTML 中的数据。在抓取时出现的所有异常和问题都必须由程序员来识别,并在编码中加以考虑。然而,这样做的好处是,用户实际上必须在这里处理问题,并从头开始学习网络抓取。因此,我们将在这里使用 BeautifulSoup。

数据库

所需数据可在 transfermarkt.com[1]上找到。例如,在图 1 中,您可以看到 2018/2019 赛季德国德甲联赛的阵容值。在同一页上,你会发现一个当前赛季的结果表:排名,净胜球和积分。如果我们不厌其烦地搜集数据,我们应该提取出所有我们需要的信息用于进一步的分析。

Figure 1: The red-marked area contains the required information

说到 web 抓取,我们通常对页面的某个部分感兴趣,我们希望有选择地从中提取信息。在我们的例子中,我们首先要提取两个表的内容(图 1)。为了做到这一点,我们需要识别包含元素的 HTML 标签。每个浏览器都提供了识别 HTML 标签的可能性。在这个例子中,我使用的是谷歌浏览器(图 2)。首先,右键单击包含必要数据的区域。然后你点击Inspect,它会在右边打开一个菜单。如果您将鼠标移动到菜单中的每一行,站点就会突出显示与 HTML 代码相关的区域(图 3)。

**

Figure 2: Inspecting the region of interest with your browser / Figure 3: The HTML-Code of the are of interest

所以第一个表在 HTML 元素table中,类名为items。其中,有元素theadtfoodtbody,它们又包含进一步的元素。基本内容在tbody中找到,它包含表中每行的tr元素。第一步我们不需要更多的信息。因此,我们首先导入所需的模块:

*import pandas as pd
import numpy as np
import requests
from bs4 import BeautifulSoupimport warnings
warnings.filterwarnings('ignore')*

然后,我们将 URL 赋给一个变量,并设置一个用来模拟真实用户的头。否则,一些页面会直接阻止请求。我们将使用模块requests调用 URL 并加载内容。然后我们将使用BeautifulSoup解析requests对象的内容,以提取我们需要的内容:

*url = 'https://www.transfermarkt.com/bundesliga/startseite/wettbewerb/L1/plus/?saison_id=2018'
headers = {"User-Agent":"Mozilla/5.0"}
response = requests.get(url, headers=headers, verify=False)
soup = BeautifulSoup(response.text, 'html.parser')*

soup元素现在包含了解析后的页面。从soup元素中,我们能够提取所需的表格:

*table = soup.find('table', {'class' : 'items'})*

现在,我们可以将表中的每一行保存在一个列表中:

*row = table.findAll('tr')*

通过键入len(row),我们发现总共有 20 个元素。德甲 18 支球队,页眉页脚。我们应该找到拜仁慕尼黑:

Figure 4: Bayern Munich

现在我们有了第一个俱乐部的数据。在图 4 中红色标记的区域,我们有名字,球队的规模,平均年龄,外国人的数量,总市值和平均市值。但是我们如何将数据转换成合理的形式来分析它呢?为此,我们首先必须删除所有带有后缀.text的 HTML 代码。Row[2].text让我们的信息更具可读性:

*'\nBayern Munich Bayern Munich 3224,715835,55 Mill. €26,11 Mill. €835,55 Mill. €26,11 Mill. €'*

这看起来好多了,但是现在我们在一个变量中有了所有的信息。因此,我们将带有findAll['td']的行按列划分,这样我们可以寻址每个单元格并保存它。现在,类似于这些行,我们也可以寻址单个列或组合两者:

*In:
row[2].findAll('td')[1].text
row[2].findAll('td')[3].text
row[2].findAll('td')[4].text
row[2].findAll('td')[5].text
row[2].findAll('td')[6].text
row[2].findAll('td')[7].textOut:
'Bayern Munich '
'32'
'24,7'
'15'
'835,55 Mill. €'
'26,11 Mill. €'*

现在我们有了用循环读取整个表的所有东西:

我们能够从列表中创建一个数据框架。我们总是跳过第一行,因为我们已经刮去了我们不需要的标题。

更动态地抓取数据

当然,我们不会大费周章只读取一个表。我们将在七年的时间里读出排名前十的联赛。这样我们就有了一个可靠的数据库来进行计算。首先,我们为每个联盟创建一个字典,其中存储了每个赛季的数据:

然后我们用每个联盟的 URL 创建一个列表。你还记得 2018/2019 赛季的拜仁网址吗?

*[https://www.transfermarkt.com/bundesliga/startseite/wettbewerb/L1/plus/?saison_id=2018'](https://www.transfermarkt.com/bundesliga/startseite/wettbewerb/L1/plus/?saison_id=2018')*

在列表中,我们只存放:

*[https://www.transfermarkt.com/bundesliga/startseite/wettbewerb/L1/plus/?saison_id=](https://www.transfermarkt.com/bundesliga/startseite/wettbewerb/L1/plus/?saison_id=)*

我们用一个循环来添加年份。这样,我们可以为我们的项目编写一个灵活的脚本。十大联赛的完整列表如下:

现在我们需要一个嵌套循环。最外层的循环遍历带有联盟 URL 的列表,内层循环遍历 2012 年到 2018 年:

数据转换

这样一来,我们每个联赛从 2012 年到 2018 年每个赛季都有十本字典。首先,我们将合并每个联盟的所有赛季,然后将所有联盟合并到一个数据集。问题是,如果我们最终将所有数据组合在一起,为什么我们不直接将所有数据收集到一个数据集中。如果没有一年或一个联赛的数据,我已经将tryexcept块包含在刮削部分以避免错误。因此,我们仍然获得最大可能的数据量和数据质量。首先,我们连接每个联赛的每个赛季,将各自的国家存放在单独的数据集中,然后合并所有联赛:

让我们来看看三个精选的俱乐部:

*df_final.loc[df_final['Team'] == 'Bayern Munich']
df_final.loc[df_final['Team'] == 'KV Oostende']
df_final.loc[df_final['Team'] == 'Real Madrid']*

Figure 5: String values ​​that still need to be converted

到目前为止,数据看起来不错,但是我们没有数字,尽管在Total valueAverage value有字符串。在图 5 中,我们看到了添加工厂。€。€和比尔。每个牢房里都有€。在将列转换为 float 之前,我们必须移除这些。在 Age 列中,分隔符仍然是逗号,而不是点。我们还必须清理这个列:

然后我们可以将所有列转换为 float:

为了安全起见,我们将数据集保存一次:

*df_final.to_pickle(“…path\\df_final.pkl”)
df_final.to_excel(“…path\\df_final.xlsx”)*

我们终于可以回答我们的问题了

在搜集和清理数据之后,我们有了一个干净的数据集来检验我们的假设。首先,让我们用下面的代码来看看平均团队值的演变:

我们看到球队的平均价值不断增加。球队在所有联赛中投资,所以总的来说,在他们的球队中投资更多。现在,让我们来看看这两个变量相互关联的程度:

df_final.corr()['Total Value']['Points']

相关系数是0.664,这意味着我们有很强的正相关性。这种相关性并没有说明任何因果关系。我们假设更高的团队价值也导致更大的运动成功。我们将做一个回归,看看球队价值观对得分的影响有多大:

调整后的 R 为 0.569。这意味着队值解释了点的方差的 56.9%。结果具有统计学意义,每增加 100 万欧元,得分平均增加 0.2029 分。

结论

在这篇文章中,我们首先提出了一个假设,然后在网上确定了一个数据库。我们研究了网络抓取的基础知识,并基于一个特定的问题开发了一个脚本,通过它我们可以有目的地读取网站的数据。然后,我们准备和清理数据,为我们的分析奠定基础。使用基本的统计方法,我们检查了我们的假设。
团队价值和运动成功之间的相关性非常显著。此外,球队价值对得分的影响非常大。
更详细的分析可以在这里找到。

Github:

archiv:
https://github.com/bd317/tutorial_scraping
教程第一步:
https://github . com/BD 317/Tutorial _ scraping/blob/master/Soccer _ Scrape _ Tutorial _ Part _ 1% 20(1)。ipynb
完整脚本:
https://github . com/BD 317/Tutorial _ scraping/blob/master/Soccer _ Scrape _ Tutorial _ Part _ 2 . ipynb

来源:

[1]https://www.transfermarkt.com
【2】https://www . uefa . com/memberassociations/uefarankings/country/#/yr/2019

如果您喜欢中级数据科学,并且还没有注册,请随时使用我的推荐链接加入社区。

教程:使用 Python 和 Heroku 的 Google Vision API

原文:https://towardsdatascience.com/tutorial-google-vision-api-with-python-and-heroku-3b8d3ff5f6ef?source=collection_archive---------5-----------------------

了解如何使用 Google Vision API

Image by author

正如我们之前了解到的,谷歌视觉人工智能可以分为两个部分, AutoML 视觉和视觉 API 。对于 Vision API 参考,这里是以前的帖子,讨论 Vision API 可以做什么,如何创建 API 键,然后用 curl 查询它。

[## ML Study Jam — Vision API

使用云视觉 API 检测图像中的标签、人脸和地标

towardsdatascience.com](/ml-study-jam-detect-labels-faces-and-landmarks-in-images-with-the-cloud-vision-api-a80e89feb66f)

今天,我们将学习如何在 Python 中使用它。然后我们可以在将来的项目中使用它。

在我们开始之前,我想和你分享一下官方教程。

[## 通过 Python 使用 Vision API

谷歌云视觉 API 允许开发人员轻松地将视觉检测功能集成到应用程序中…

codelabs.developers.google.com](https://codelabs.developers.google.com/codelabs/cloud-vision-api-python/index.html?index=..%2F..index#0)

在接下来的段落中有一个快速教程,但是如果你想在阅读之后了解更多的细节,你仍然可以从 Google Codelabs 中学习。太好了,现在我们开始吧。

步骤概述

  1. 建立一个 Vision API 项目。
  2. 启用 Vision API。
  3. 验证 API 请求并下载keyFile.json
  4. keyFile.json设置GOOGLE_APPLICATION_CREDENTIALS
  5. 安装谷歌客户端视觉 API 客户端库。
  6. 编写 Python 代码来查询 Vision API。
  7. 将代码推至 Heroku 。

第一步。建立一个 Vision API 项目。

  1. 登录到谷歌云平台控制台并创建一个新项目。

2.命名项目并点击创建按钮。

3.点击主动云壳

4.然后底部会出现一个控制台外壳。
运行$ gcloud auth list以确认您已通过身份验证。并运行$ gcloud config list project确认项目 id。

第二步。启用 Vision API。

运行命令行$ gcloud services enable vision.googleapis.com

第三步。验证 API 请求并下载keyFile.json.

根据 Google Codelabs 教程,我们需要创建一个服务帐户和一个访问 Vision API 的密钥。

为了向 Vision API 发出请求,您需要使用一个服务帐户。一个服务帐户是一个属于你的项目的帐户,它被 Google 客户端 Python 库用来发出 Vision API 请求。

单击下面的链接,并按照Setting up authentication GCP 控制台的步骤操作。

[## Vision API 客户端库|云 Vision API 文档| Google 云

本页显示了如何开始使用 Cloud Vision API 的云客户端库。阅读有关客户端的更多信息…

cloud.google.com](https://cloud.google.com/vision/docs/libraries#client-libraries-usage-python)

  1. 转到创建服务帐户密钥页面
  2. 服务账户列表中,选择新服务账户
  3. 服务帐户名称字段中,输入一个名称。
  4. 不要从角色列表中选择值。访问此服务不需要任何角色。

如果所有设置都设置正确,用户界面将如下所示:

5.点击创建。将出现一条注释,警告此服务帐户没有角色。

6.点击创建无角色。一个 JSON 文件,包含你下载到你电脑上的密钥。

第四步。用keyFile.json设置GOOGLE_APPLICATION_CREDENTIALS

将 JSON 文件重命名为keyFile.json。然后用文件设置GOOGLE_APPLICATION_CREDENTIALS

export GOOGLE_APPLICATION_CREDENTIALS=~/Desktop/keyFile.json

第五步。安装谷歌客户端视觉 API 客户端库。

  1. 运行pip freeze | grep google-cloud-vision来检查库是否已经安装。

2.如果您没有设置环境,请运行pip install --upgrade google-cloud-vision

第六步。编写 Python 代码来查询 Vision API。

将以下代码复制并保存为 Python 文件。

运行 Python 文件来测试是否正确设置了所有环境设置。

/usr/local/opt/python/bin/python3.7 [path/to/your/filename.py]

我们上传了两位巨星的照片,并使用 Vision API 中的人脸检测来获取他们的人脸边界和情感。

输入数据:

images from WikiMedia and Pinterest

以下是输出:

=========================================================File: {pic}Face surprised: VERY_UNLIKELYFace bounds: (207,54),(632,54),(632,547),(207,547)=========================================================File: {pic}Face surprised: LIKELYFace bounds: (16,38),(323,38),(323,394),(16,394)

恭喜你!这意味着我们已经成功查询了 Vision API。尝试官方教程中的其他 Vision APIs。

[## 教程|云视觉 API 文档|谷歌云

无论您的企业是刚刚踏上数字化转型之旅,还是已经走上数字化转型之路,谷歌云的解决方案…

cloud.google.com](https://cloud.google.com/vision/docs/tutorials)

第七步。将代码推至 Heroku 。

注:根据Mandar Vaze的建议,我们不应该将个人 ***keyFile.json*** 上传到公共空间。如果您对安全问题有所顾虑,请参考 本帖 寻求解决方案。

如果你还是不太了解 Heroku,请先看看之前的帖子。

[## 教程:使用 Python 和 Heroku 的 LINE Bot

从头开始,建立你的线机器人

medium.com](https://medium.com/better-programming/line-bot-with-python-and-heroku-tutorial-e8c296f3816f)

在第 6 步中,该项目在本地运行良好,但我们需要将其构建为应用程序或 web 使用的在线服务。

  1. 下面是代码示例,请下载并在下面的步骤中学习如何在线推送。

https://github . com/mutant 0113/Google _ Vision _ API _ sample/blob/master/medium-Google-Vision-API . zip

2.将你自己的谷歌服务账号keyFile.json添加到文件夹medium-google-vision-api/config/

3.创建一个新的 Heroku 项目。

heroku login
heroku create [your/project/name] --buildpack heroku/python

4.链接项目并将代码推送到主分支。

cd [path/to/your/local/project/download/from/step1]
heroku git:remote -a [your/project/name]
git push heroku master

5.将GOOGLE_APPLICATION_CREDENTIALSkeyFile.json设定在 Heroku 上。

heroku config:set GOOGLE_APPLICATION_CREDENTIALS='config/keyFile.json'

6.确保至少有一个应用程序实例正在运行。

heroku ps:scale web=1

7.打开 Heroku 网站

heroku open

如果一切都设置正确,您应该会看到网站的内容像图片一样。

8.您可以在 hello/views.py 和 hello/vision_api.py 中编辑代码

今天到此为止。我们现在可以开始使用 Google Vision API 编写代码了。希望这篇文章能帮助你更多地了解 Google Vision API。

如有任何问题或建议,欢迎在本文下方留言评论。再见。

参考

云愿景 API 定价

[## 定价|云愿景 API 文档|谷歌云

云视觉 API 提供了一组用于分析图像的功能。在这些情况下,我们让您只需支付…

cloud.google.com](https://cloud.google.com/vision/pricing)

我们的 Heroku 代码基于官方样本代码。

[## 使用 Python 开始使用 Heroku

本教程将让你在几分钟内部署一个 Python 应用程序(一个简单的 Django 应用程序)。再坚持几分钟…

devcenter.heroku.com](https://devcenter.heroku.com/articles/getting-started-with-python)

Node.js 版本的另一个教程。

[## 如何在 Heroku for Node.js App 上认证谷歌云服务

在这篇文章中,我将讨论如何授权各种谷歌云服务,如数据存储、云存储…

medium.com](https://medium.com/@naz_islam/how-to-authenticate-google-cloud-services-on-heroku-for-node-js-app-dda9f4eda798)

定义在图上的各向异性、动态、谱和多尺度滤波器

原文:https://towardsdatascience.com/tutorial-on-graph-neural-networks-for-computer-vision-and-beyond-part-2-be6d71d70f49?source=collection_archive---------12-----------------------

作为“计算机视觉图形神经网络教程”的一部分

我将通过使用 Python 和 PyTorch 提取关键思想并解释里程碑方法背后的简单直觉,来概述重要的图形神经网络工作。本帖继续 我的教程第一部分

Graph of Graph Neural Network (GNN) and related works. Some other important works and edges are not shown to avoid further clutter. For example, there is a large body of works on dynamic graphs that deserve a separate overview. Best viewed on a very wide screen in color.

20 多年的图形神经网络

在上面的“图神经网络(GNN)的图及相关著作”中,我补充了我最近一年接触到的关于图的论文。在该图中,两个作品之间的有向边表示一篇论文基于另一篇论文(尽管没有必要引用它),作品的颜色表示:

  • 红色— 光谱方法(需要拉普拉斯图的特征分解,这将在下面解释)
  • 绿色—在空间域中工作的方法(不需要拉普拉斯图的特征分解)
  • 蓝色—相当于光谱方法,但不需要特征分解(因此,实际上是空间方法)
  • 黑色——是 GNNs 的补充方法,与 GNN 本身的选择无关(例如,集中注意力)。

请注意,为了避免混乱,其他一些重要的作品和边缘没有显示出来,只有一小部分作品,用粗体框突出显示的将在本文中介绍。声明:我仍然在那里找到了挤压我们自己最近作品的空间😊。

大多数重要的方法都包含在这个非详尽的作品列表中:

  • Nicket 等人,2015 年,知识图的关系机器学习综述
  • 布朗斯坦等,2016,几何深度学习:超越欧几里德数据
  • 汉密尔顿等,2017,图上的表征学习:方法与应用
  • Kipf 等人,2018,结构化深度模型:图形上的深度学习及超越,演示幻灯片。
  • 巴塔格利亚等人,2018 年,关系归纳偏差、深度学习和图网络
  • 张等,2018 关于图的深度学习:一个调查
  • 周等,2018,图神经网络:方法与应用综述
  • 吴等,2019,【图神经
    网络综合研究】
  • Petar Velič ković,2019,深度神经网络中结构的复兴,博士论文。
  • 尼普斯和 CVPR 视频教程

使用神经网络对图进行分类的第一项工作似乎是由亚历桑德罗·斯佩尔杜蒂和安东尼娜·斯塔丽塔在发表的一篇 1997 关于“用于结构分类的监督神经网络”的论文。

A figure from (Sperduti & Starita, 1997), which is strikingly similar to what we are doing now, after more than 20 years.

斯珀杜蒂&斯塔里塔,1997 :“到目前为止,神经网络已经被用于对非结构化模式和序列进行分类。然而,标准的神经网络和统计方法通常被认为在处理复杂结构时是不够的,因为它们是基于特征的方法。”

自 1997 年以来,关于从图中学习的大量工作已经在如此多的不同方向上增长,如果没有一些智能的自动化系统,很难保持跟踪。我相信我们正在使用基于神经网络的方法(基于我的教程第一部分中的 中解释的公式(2)】,或者神经网络和其他方法的某种组合。

Graph neural layer’s formula (2) from the first part of my tutorial that we will also need in this part. Keep in mind, that if we need to compute a specific loss for the output features or if we need to stack these layers, we apply some activation like ReLU or Softmax.

回顾一下我们在第一部分中使用的符号,我们有一些无向图 GN 节点。该图中的每个节点都有一个 C 维特征向量,所有节点的特征都表示为一个 N × C 维矩阵 X⁽ˡ⁾.在一个典型的图网络中,比如 GCN ( Kipf & Welling,ICLR,2017 ),我们将这些特征 X⁽ˡ⁾ 馈送到一个具有 C × F 维可训练权重 W⁽ˡ⁾ 的图神经层,这样该层的输出就是一个 N × F 矩阵𝓐是一个 N × N 矩阵,其中条目𝓐 ᵢⱼ 指示节点 i 是否连接到节点 j 的相邻节点。这个矩阵被称为邻接矩阵。我使用𝓐而不是普通的 A 来强调这个矩阵可以被规范化以促进深层网络中的特征传播。出于本教程的目的,我们可以假设𝓐= A ,即矩阵乘积𝓐 X⁽ˡ⁾ 的第 i 至第t51】行将包含节点 i 邻居的特征的总和。**

在本部分教程的剩余部分,我将简要解释概览图中用粗体框显示的我选择的作品。我推荐布朗斯坦等人的评论进行更全面和正式的分析。

请注意,尽管我在下面深入研究了光谱图卷积的一些技术细节,但最近的许多作品(如徐等人的 GIN,2019 )都是在没有光谱卷积的情况下建立的,并在一些任务中显示出很好的结果。然而,了解谱卷积的工作原理仍然有助于理解和避免其他方法的潜在问题。

1。光谱图卷积

布鲁纳等人,2014,ICLR 2014

我在我的另一篇文章中详细解释了谱图卷积。

为了这部分教程的目的,我在这里简单总结一下。谱图卷积的正式定义与信号/图像处理中的卷积定理非常相似,可以写成:

Spectral graph convolution, where ⊙ means element-wise multiplication.

其中 V 为特征向量,λ图拉普拉斯 L 的特征值,通过特征分解可以找到:l=vλvᵀ;w_ 光谱滤光片。在本教程中,我将假设“对称归一化拉普拉斯算子”。它是基于图的邻接矩阵 A 上的唯一来计算的,这可以用几行 Python 代码来完成,如下所示:

**# Computing the graph Laplacian
# A is an adjacency matrix** import numpy as npN = A.shape[0] **# number of nodes in a graph**
D = np.sum(A, 0) **# node degrees**
D_hat = np.diag((D + 1e-5)**(-0.5)) **# normalized node degrees**
L = np.identity(N) — np.dot(D_hat, A).dot(D_hat) **# Laplacian**

这里,我们假设 A 是对称的,即 A = A ᵀ,并且我们的图是无向图,否则节点度不是明确定义的,并且必须做出一些假设来计算拉普拉斯算子。在计算机视觉和机器学习的背景下,图形拉普拉斯定义了如果我们以公式(2)的形式堆叠几个图形神经层,节点特征将如何更新。

所以,给定图的拉普拉斯 L ,节点特征 X 和过滤器 W _spectral,在 Python 图上的谱卷积看起来非常简单:

**# Spectral convolution on graphs
# X is an *N×1 matrix of 1-dimensional node features*** **# L** **is an** ***N******×N* graph Laplacian computed above
# W_spectral are** ***N******×******F weights (filters) that we want to train*** from scipy.sparse.linalg import eigsh **# assumes *L* to be symmetric***Λ**,V* = eigsh(L,k=20,which=’SM’) **#** **eigen-decomposition (i.e. find *Λ******,V)***
X_hat = V.T.dot(X) **# *20*****×*****1* node features in the "spectral" domain**
W_hat = V.T.dot(W_spectral)  **# 20×*F* filters in the** **"spectral" domain**
Y = V.dot(X_hat * W_hat)  **# *N******×******F* result of convolution**

其中我们假设我们的节点特征 X⁽ˡ⁾ 是一维的,例如 m 像素,但是它可以扩展到 C 维的情况:我们将只需要对每个通道重复这个卷积,然后像在信号/图像卷积中一样对 C 求和。

公式(3)本质上与使用傅立叶变换的规则网格上的信号的频谱卷积相同,因此为机器学习产生了一些问题:

  1. 可训练权重(滤波器)的维数取决于图中节点的数量;
  2. W_ 光谱也取决于图结构中编码的特征向量 V.

这些问题阻碍了扩展到具有可变结构的大型图形的数据集。

为了解决第一个问题,布鲁纳等人提出在谱域对滤波器进行平滑,根据谱理论使滤波器在空间域更加局部化。其思想是,您可以将公式(3)中的滤波器 W_ 频谱表示为𝐾预定义函数(如样条函数)的和,并且我们学习这个和的 WN 值,而不是学习这个和的 K 系数 α :

We can approximate our N dimensional filterW_spectral as a finite sum of K functions f, such as splines shown below. So, instead of learning N values of W_spectral, we can learn K coefficients (alpha) of those functions; it becomes efficient when K << N.

虽然 fk 的维数确实取决于节点 N 的数量,但是这些函数是固定的,所以我们不学习它们。我们唯一知道的是系数 α ,因此 W_ 光谱不再依赖于 N 。为了使我们在公式(4)中的近似合理,我们希望 K < < N 将可训练参数的数量从 N 减少到 K ,更重要的是,使其独立于 N ,以便我们的 GNN 可以消化任何大小的图。

虽然解决了第一个问题,但是这种平滑方法没有解决第二个问题。

2。切比雪夫卷积

Defferrard 等人,NeurIPS,2016 年

上面的频谱卷积及其平滑版本的主要缺点是,它仍然需要对一个 N × N 维拉普拉斯图 L 进行本征分解,这产生了两个主要问题:

  1. 🙁特征分解的复杂度是巨大的,O( N )。此外,在大图的情况下,在 RAM 中以密集格式保持图拉普拉斯是不可行的。一种解决方案是使用稀疏矩阵,并用 Python 中的scipy.sparse.linalg.eigs找到特征向量。此外,您可以在具有大量 RAM 和 CPU 内核的专用服务器上预处理所有训练图。在很多应用中,你的测试图也可以提前预处理,但是如果你不断有新的大图涌入,特征分解会让你难过。
  2. 🙁另一个问题是,你训练的模型最终与图的特征向量 V 密切相关。如果您的训练图和测试图具有非常不同的结构(节点和边的数量),这可能是一个大问题。否则,如果所有的图形都非常相似,问题就不大了。此外,如果您在频域中使用一些平滑滤波器,如上面讨论的样条,那么您的滤波器将变得更加局部化,适应新图形的问题似乎更加不明显。然而,这些模型仍然非常有限。

那么,切比雪夫图卷积和这些有什么关系呢?

原来它同时解决了两个问题!😃

也就是说,它避免了计算昂贵的特征分解,并且滤波器不再“附着”于特征向量(然而它们仍然是特征值λ)的函数)。此外,它有一个非常有用的参数,通常表示为 K ,具有与我们上面的公式(4)中的 K 相似的直觉,确定滤波器的局部性。非正式地:对于 K =1,我们只将节点特性 X⁽ˡ⁾ 提供给我们的 gnn 对于 K =2,我们馈 X⁽ˡ⁾ 和𝓐x⁽ˡ⁾;对于 K=3,我们馈x⁽ˡ⁾𝓐x⁽ˡ⁾和𝓐x⁽ˡ⁾;对于更大的 K 以此类推(我希望你已经注意到这个模式)。更准确正式的定义见 Defferrard et al. 和下面我的代码,加上额外的分析在( Knyazev et al .,NeurIPS-W,2018 )中给出。****

由于邻接矩阵的幂属性,当我们执行𝓐 X⁽ˡ⁾ 时,我们实际上对 2 跳邻居进行平均(或求和,取决于𝓐如何归一化),并且类似地,对𝓐 ⁿX⁽ˡ⁾ 中的任何 n 进行平均,如下图所示,其中我们对 n 跳邻居进行平均。

Chebyshev convolution for K=3 for node 1 (dark blue). Circled nodes denote the nodes affecting feature representation of node 1. The [,] operator denotes concatenation over the feature dimension. W⁽ˡ⁾ are 3C×F dimensional weights.**

注意,为了满足切比雪夫基的正交性,𝓐 假设图中没有回路,因此在矩阵乘积𝓐 X⁽ˡ⁾ 的每 i 行中,我们将具有节点 i 的邻居的特征,但是没有节点 i 本身的特征。节点 i 的特征将作为矩阵 X⁽ˡ⁾.单独输入

如果 K 等于节点数 N ,则切比雪夫卷积非常接近于频谱卷积,因此滤波器的感受域将是整个图形。但是,正如卷积网络的情况一样,由于我已经讨论过的一些原因,我们不希望滤波器与输入图像一样大,因此在实践中, K 取合理的小值。

根据我的经验,这是最强大的 gnn 之一,在非常广泛的图形任务中取得了很好的结果。主要的缺点是在向前/向后传递中必须循环遍历 K (因为切比雪夫多项式是递归的,所以不可能并行化它们),这会降低模型的速度。

与上面讨论的样条一样,我们不是训练滤波器,而是训练切比雪夫多项式的系数。

Chebyshev basis used to approximate convolution in the spectral domain.

要生成切比雪夫基,可以使用以下 Python 代码:

****# Set K to some integer > 0, like 4 or 5 in our plots above
# Set n_points to a number of points on a curve (we set to 100)** import numpy as npx = np.linspace(-1, 1, n_points)
T = np.zeros((K, len(x)))
T[0,:] = 1
T[1,:] = x
for n in range(1, K-1):
    T[n+1, :] = 2*x*T[n, :] - T[n-1, :] **# recursive computation**   
return T**

生成样条和切比雪夫基的完整代码在我的 github repo 中。

为了说明切比雪夫滤波器在不规则网格上的表现,我再次遵循布鲁纳等人的实验,从 MNIST 网格中随机抽取 400 个点,其方式与我展示拉普拉斯图的特征向量的方式相同。我在从这 400 个位置采样的 MNIST 图像上训练了一个切比雪夫图卷积模型(相同的不规则网格用于所有图像),下面显示了一个用于 K =1 和 K =20 的过滤器。

A single Chebyshev filter (K=3 on the left and K=20 on the right) trained on MNIST and applied at different locations (shown as a red pixel) on a irregular grid with 400 points. Compared to filters of standard ConvNets, GNN filters have different shapes depending on the node at which they are applied, because each node has a different neighborhood structure.

3。GCN

Kipf &韦林,ICLR,2017

您可能已经注意到,如果增加切比雪夫卷积的 K ,可训练参数的总数就会增加。例如,对于 K =2,我们的权重 W⁽ˡ⁾ 将是 2 C × F 而不是仅仅 C × F 。这是因为我们将特征x⁽ˡ⁾t16】t17】和𝓐 X⁽ˡ⁾ 连接成一个单一的 N ×2 C 矩阵。更多的训练参数意味着模型比更难训练,需要标注更多的数据进行训练。图表数据集通常非常小。在计算机视觉中,MNIST 被认为是一个很小的数据集,因为图像只有 28×28 维,只有 60k 个训练图像,而在图网络中,MNIST 是相当大的,因为每个图将有 N =784 个节点,60k 是大量的训练图。与计算机视觉任务相比,许多图形数据集只有大约 20-100 个节点和 200-1000 个训练样本。这些图可以表示某些小分子,标记化学/生物数据通常比标记图像更昂贵。因此,训练切比雪夫卷积模型可能导致训练集的严重过拟合(即,模型将具有接近 0 的训练损失,但将具有较大的验证或测试误差)。所以, Kipf & Welling 的 GCN 本质上是将节点特征x⁽ˡ⁾t36】t37】和𝓐 X⁽ˡ⁾ 的矩阵“合并”成一个单独的 N × C 矩阵。结果,与具有 K =2 的切比雪夫卷积相比,该模型需要训练的参数少了两倍,但具有 1 跳的相同感受野。主要的技巧是通过将一个单位矩阵 I 添加到𝓐 中,并以特定的方式对其进行规范化,从而将“自循环”添加到您的图中,因此现在在矩阵乘积的每一行I**x⁽ˡ⁾中,我们将拥有节点 i、 的邻居的特征,以及节点 i.特征****

这个模型似乎是一个标准的基线选择,非常适合许多应用程序,因为它的轻量级、良好的性能和对较大图形的可伸缩性。

3.1.GCN vs 切比雪夫层

GCN 卷积和切比雪夫卷积的区别如下图所示。

上面的代码遵循与我的教程 的第一部分 中相同的结构,在那里我比较了经典的 NN 和 GNN。GCN 和切比雪夫卷积中的一个主要步骤是重新标度图拉普拉斯 L 的计算。进行这种重新调整是为了使特征值在[-1,1]的范围内,以便于训练(这在实践中可能不是非常重要的步骤,因为权重可以在训练期间适应)。在 GCN,如上所述,在计算拉普拉斯算子之前,通过添加单位矩阵将自循环添加到图中。这两种方法的主要区别在于,在切比雪夫卷积中,我们递归地遍历 K 来捕获 K 跳邻域中的特征。我们可以将这样的 GCN 或切比雪夫层与非线性交错堆叠起来,构建一个图形神经网络。

现在,让我礼貌地打断一下😃我们的频谱讨论并给出了另外两种令人兴奋的方法背后的大致想法:边缘条件滤波器,由 Simonovsky & Komodakis,CVPR,2017 和莫奈,由 Monti 等人,CVPR,2017 ,它们共享一些类似的概念。

4。边缘调节的滤波器

西蒙诺夫斯基&CVPR 科莫达基斯,2017

如你所知,在 ConvNets 中,我们通过优化一些损失来学习权重(过滤器),如交叉熵。同样,我们在 GNNs 中学习 W⁽ˡ⁾。想象一下,你有另一个网络来预测这些权重,而不是学习这些权重。因此,在训练过程中,我们学习辅助网络的权重,它以一幅图像或一个图形作为输入,并返回权重 W⁽ˡ⁾ (他们工作中的θ)作为输出。该想法基于动态滤波器网络 ( Brabandere 等人,NIPS,2016 ),其中“动态”意味着滤波器 W⁽ˡ⁾ 将根据输入而不同,这与标准模型相反,在标准模型中,滤波器在训练后是固定的(或静态的)。

Using an auxiliary “filter generating network” Fˡ to predict edge-specific weights Θ for the main network. Xˡ⁻¹ are input node features and Xˡ are output features. The figure shows a single iteration of “dynamic convolution” for node 1 (in yellow). Standard GNNs typically would simply average (or sum) features of node 1 neighbors (nodes 2, 3, 4, 5) , which would correspond to having an isotropic filter (Θ would be a constant vector). In contrast, this model has anisotropic filters, because it predicts different edge values between node 1 and all it’s neighbors based on edge labels L, so that features Xˡ(1) are computed as a weighted average of neighbors’ features. Figure from (Simonovsky & Komodakis, CVPR, 2017).

这是一种非常普遍的卷积形式,除了图像之外,还可以很容易地应用于图形或点云,正如他们在 CVPR 的论文中所做的那样,并获得了出色的结果。然而,没有“免费的午餐”,训练这样的模型相当具有挑战性,因为常规的网格约束现在已经放松,解决方案的范围急剧增加。这对于具有许多边的较大图形或较深层中的卷积来说尤其如此,这些图形通常具有数百个通道(特征数量, C) ,因此您可能最终会为每个输入总共生成数千个数字!在这方面,标准 ConvNets 非常好,因为我们没有浪费模型的能力来训练预测这些权重,而是直接强制要求滤波器对所有输入都应该相同。但是,这种先验使 ConvNets 受到限制,我们不能直接将它们应用于图形或点云。因此,一如既往,在特定任务中,灵活性和性能之间会有一些权衡。

当应用于图像时,如 MNIST,边缘条件模型可以学习预测各向异性滤波器——对方向敏感的滤波器,如边缘检测器。与我的教程 的第一部分 中讨论的高斯滤波器相比,这些滤波器能够更好地捕捉图像中的某些模式,例如数字中的笔画。**

Convolutional filters learned on MNIST sampled in low (left) and high (right) resolutions. Figure from (Simonovsky & Komodakis, CVPR, 2017).

我想再强调一次,每当我们有一个带有辅助网络的复杂模型时,在某种意义上它就变成了一个先有鸡还是先有蛋的问题。为了解决这个问题,其中一个网络(辅助网络或主网络)应该接收到非常强的信号,这样它就可以隐式地监控另一个网络。在我们的 BMVC 论文中,类似于Simonovsky&Komodakis的工作,我们在生成边的网络上应用了额外的约束来促进训练。我将在后面的帖子中详细描述我们的工作。

5。莫奈

蒙蒂等人,CVPR,2017 年

MoNet 不同于本文中讨论的其他作品,因为它假定具有节点坐标的概念,因此更适合于几何任务,如 3D 网格分析或图像/视频推理。它有点类似于 Simonovsky & Komodakis 的边缘条件滤波器,因为它们也引入了预测权重的辅助可学习函数𝐷(𝑤、𝜃 ,ρ 。不同的是,这些权重取决于节点极坐标(角度𝜃和半径ρ);并且该函数的可训练参数𝑤被约束为高斯分布的均值和方差,从而我们不是学习 N × N 矩阵,而是仅学习与图大小 N 无关的固定大小的向量(均值和方差)。就标准 ConvNets 而言,对于每个滤波器来说,只学习 2 个值(高斯分布的平均值和方差)是相同的,而不是分别学习 3×3、5×5 或 11×11 维滤波器的 9、25 或 121 个值。这种参数化将极大地减少 ConvNet 中的参数数量,但滤波器捕捉图像特征的能力非常有限。****

Monti 等人训练高斯的𝐽均值和方差,转换节点坐标的过程类似于将它们拟合到高斯混合模型。如果我们希望我们的过滤器足够全局,那么这个模型的训练计算量相当大,但它可能是视觉任务的一个很好的选择(参见我们的 BMVC 论文进行比较),但在非视觉任务上,它往往比简单的 GCN 差( Knyazev 等人,NeurIPS-W,2018 )。由于函数 D 依赖于坐标,生成的滤波器也是各向异性的,并且具有如下图所示的定向和拉长的高斯形状。

Filters trained with MoNet in polar coordinates 𝜃 and ρ. Each ellipse corresponds to a slice of a Gaussian at some fixed level. The idea is that if the coordinates of the i-th node are close to the middle of the j-th Gaussian, then the generated weight at index (i,j) will have a value close to 1.

*****Pseudo-code of the MoNet layer using PyTorch*****# assume X to be input *N***×***C* node features**
**# coord are *N*×*N*×*2* node coordinate differences between all pairs of nodes (node degrees for non-geometric tasks)
# coord can be viewed as angular and radial edges between nodes**1\. Generate *J* Gaussian-shaped filters based on coordinates of nodes    using some trainable function D
   weights = D(coord)  # weights: *J*×*N*×*N*
2\. Multiply node features X by these weights
   X = torch.bmm(weights, X.expand(J, N, C))  # X: *J*×*N*×*C*
3\. Project features by a learnable linear transformation
   X = fc(X.permute(1, 2, 0).view(N, J*C))  # X: *N*×*F* 4\. Feed X to the next layer**

结论

尽管讨论了很长时间,我们只是触及了皮毛。图形神经网络的应用正在扩展,远远超出了典型的图形推理任务,如分子分类。不同图形神经层的数量增长非常快,类似于几年前卷积网络的情况,因此很难跟踪它们。在这一点上,py torch Geometric(PyG)——一个从图表中学习的好工具箱——经常用新颖的图层和技巧填充它的集合。

鸣谢:本教程的很大一部分是我在 SRI International 实习期间在 穆罕默德·阿梅尔 ( 主页 )和我的博士导师格拉汉姆·泰勒( 主页 )的指导下编写的。我也感谢Carolyn Augusta*的有用反馈。*

在 Github 、 LinkedIn 和 Twitter 上找我。我的主页。

如果你想在你的论文中引用这篇博文,请使用:
@ misc
{ Knyazev 2019 Tutorial,
title = {用于计算机视觉及超越的图形神经网络教程},
author={Knyazev,Boris and Taylor,Graham W and Amer,Mohamed R},
year={2019}
}
**

变分图自动编码器教程

原文:https://towardsdatascience.com/tutorial-on-variational-graph-auto-encoders-da9333281129?source=collection_archive---------4-----------------------

图适用于许多现实世界的数据集,如社会网络、引用网络、化学图等。对图结构数据日益增长的兴趣增加了对图神经网络的研究。

变分自动编码器体现了变分贝叶斯方法在深度学习中的成功,并激发了广泛的研究。变分图自动编码器(VGAE)将 VAE 的思想应用于图结构数据,显著提高了在大量引用网络数据集(如 Cora 和 Citesser)上的预测性能。

我在网上搜了一下,还没有看到关于 VGAE 的详细教程。在这篇文章中,我将简单地谈谈传统的自动编码器和变化的自动编码器。此外,我将讨论将 VAE 应用于图结构数据(VGAE)的想法。

传统自动编码器

Figure 1: The architecture of the traditional autoencoder

传统的自动编码器是包含编码器和解码器的神经网络。编码器将数据点 X 作为输入,并将其转换为低维表示(嵌入) Z 。解码器采用低维表示 Z 并返回原始输入 X-hat 的重构,看起来像输入 X 。嵌入的质量决定输出的质量 X-hat 。然而,编码器不可能编码所有的信息,因为嵌入的维数比输入的维数低。因此,如果嵌入从输入中捕获更多的信息,输出将具有更好的性能。

编码器和解码器的架构

Figure 2: Traditional autoencoder for MNIST dataset

让我们看一个例子。图 2 显示了一个自动编码器的例子,它将 MNIST 图像作为输入。MNIST 数据集包含灰度图像,每个图像的形状为 28 x 28 像素。编码器获取该图像并将其转换为低维嵌入 Z 。解码器采用嵌入 Z 并返回重构的输入图像,该图像是自动编码器的输出。

损失函数

自动编码器的损失函数测量重建期间的信息损失。我们希望最小化重建损失,以使 X-hat 更接近 X 。我们经常使用均方误差作为损失函数,

其测量 X-hatX 的接近程度。

为什么我们要将输入转换为低维嵌入?

让我们以图像为例。有几种方法可以使用图像的低维嵌入。与存储图像的像素强度相比,存储图像的低维嵌入可以节省存储空间。存储图像的低维嵌入也可以节省计算能力,因为输入维度更低。

靠近图像嵌入的点也是嵌入空间中的图像嵌入,这是使自动编码器嵌入有用的另一个原因。例如,如果您修改 MNIST 影像的像素强度,您将得到一个看起来不像 MNIST 数据集中的影像的噪声影像。但是,如果您对 MNIST 图像的嵌入进行少量修改,然后对修改后的嵌入进行解码,您仍然可以得到看起来像 MNIST 图像的东西。

Figure 3: Modify the pixel intensities of an MNIST image

图 3 显示了修改 MNIST 图像的像素强度的例子。在每个像素的强度中添加一些随机噪声后,输出的是一幅噪声图像,看起来不像 MNIST 数据集中的图像。

Figure 4: Modify the embedding of MNIST image by a small amount

图 4 显示了一个修改 MNIST 图像的嵌入的例子。少量修改嵌入与嵌入空间的小位移是一样的。从图 4 中我们可以看到,在嵌入 Z 中每个元素加 4 后,输出图像 X2 帽仍然与原始输出 X1 帽非常相似。

Figure 5: An example of plotting MNIST data on embedding space

我们也可以把这些低维嵌入标绘到 n-d 坐标上。图 5 显示了在嵌入空间上绘制 MNIST 数据的例子。嵌入空间上的每个点代表一个输入数据。这种可视化很方便,因为它可以系统地组织坐标中的所有输入数据。

低维嵌入也可以用于下游的机器学习任务。我们可以使用预先计算的嵌入来解决另一个机器学习问题,即分类问题。我们可以对这些嵌入而不是原始输入进行分类。我们还可以在迁移学习或半监督学习中使用嵌入,这可能会给我们带来比原始输入更好的结果。

可变自动编码器

为什么我们需要可变的自动编码器?

变分自动编码器的最大优势之一是 VAE 可以从原始源数据集生成新数据。相比之下,传统的自动编码器只能生成与原始输入相似的图像。假设你想建一个长满灌木的花园。每一株灌木都需要与众不同,这样你的花园才会看起来真实。你肯定不能自己画每一棵灌木,一个更聪明的方法是使用自动编码器自动生成新的灌木。

主要思想

变分自动编码器的主要思想是将输入 X 嵌入到一个分布中,而不是一个点中。然后随机样本 Z 取自分布,而不是直接从编码器产生。

编码器和解码器的架构

VAE 的编码器通常写成 qφ(z|x) ,它取一个数据点 X 并产生一个分布。该分布通常被参数化为多元高斯分布。因此,编码器预测高斯分布的平均值和标准偏差。低维嵌入 Z 从此分布中采样。解码器是一个变分近似, pθ(x|z) ,它采用一个嵌入 Z 并产生输出 X-hat

Figure 6: An example of a variational autoencoder

损失函数

VAE 的损失函数有两部分。损失函数的第一部分称为变分下界,它衡量网络重构数据的好坏。如果重建数据 X 与原始数据差别很大,那么重建损失将会很高。损失函数的第二部分作为正则项工作。它是近似值与真实后验值( p(z) )的 KL 散度,它衡量输出分布( qφ(z|x) )与 p(z) 的匹配程度。

摘要

VAE 的想法可以用下图来概括:

Figure 7: The architecture of the variational autoencoder

编码器将数据点 X 作为输入,并生成μ和 logσ作为输出。我们使用 logσ而不是σ的原因是σ是非负的,因此我们将需要一个额外的激活函数。但是 logσ可能是正的,也可能是负的。在我们得到μ和 logσ之后,我们试图让μ和 logσ都接近 0,也就是说μ接近 0,σ接近 1。因此,最终分布将接近于 N(0,1) 。最后,我们想通过 z = μ + σ * ε 由μ和σ生成嵌入 Z ,其中ε ~ N(0,1) 。这被称为重新参数化技巧。现在有了潜在变量 Z ,我们可以通过解码器生成我们的输出 X-hat

变分图自动编码器

介绍

我们希望构建一个变分图自动编码器,将 VAE 的思想应用于图结构数据。我们希望我们的变分图自动编码器能够生成新的图形或关于图形的推理。然而,我们不能直接应用 VAE 的思想,因为图结构的数据是不规则的。每个图都有不同大小的无序节点,图中的每个节点都有不同数量的邻居,所以我们不能再直接使用卷积了。让我们弄清楚如何以神经网络可以理解的方式来表示图形。

邻接矩阵

我们使用一个邻接矩阵 A 来表示输入图。通常我们假设邻接矩阵是二进制的。第 i 行和第 j 列的值 1 表示顶点 i 和顶点 j 之间有一条边。行 m 和列 n 的值 0 表示顶点 m 和顶点 n 之间没有边。

Figure 8: An example of the adjacency matrix

图 8 显示了当输入图是有向和无向时邻接矩阵的例子。在图的左侧,当图是无向图时,邻接矩阵是对称的。顶点 0 和顶点 1 是相连的,所以 A[0,1] = 1A[1,0] = 1 。当图是有向图时,右边的邻接矩阵是不对称的。顶点 0 指向顶点 1,意味着顶点 1 聚合了来自顶点 0 的信息,所以 A[1,0] = 1

特征矩阵

我们使用特征矩阵 X 来表示输入图中每个节点的特征。特征矩阵 X 的行 i 代表顶点 i 的特征嵌入。

Figure 9: An example of the feature matrix

图 9 显示了特征矩阵的一个例子。每个节点 i 都有自己的特征矩阵 X_i ,我们可以将它们组合在一起得到整个图的特征矩阵 X ,其中每一行 i 代表节点 i 的特征矩阵。

编码器和解码器的架构

Figure 10: The architecture of the variational graph autoencoder

VGAE 的编码器(推理模型)由图卷积网络 ( GCNs )组成。它以邻接矩阵 A 和特征矩阵 X 作为输入,生成潜变量 Z 作为输出。第一 GCN 层生成低维特征矩阵。它被定义为

A-tilde 是对称归一化邻接矩阵。

第二 GCN 层产生μ和 logσ,其中

现在如果我们把两层 GCN 的数学结合在一起,我们得到

从而产生μ和 logσ。

然后我们可以使用参数化技巧计算出 Z

其中ε ~ N(0,1)。

解码器(生成模型)由潜在变量 Z 之间的内积定义。我们解码器的输出是一个重构的邻接矩阵 A-hat ,其定义为

其中σ()是逻辑 sigmoid 函数。

总之,编码器表示为

并且解码器被表示为

损失函数

变分图自动编码器的损失函数和以前几乎一样。第一部分是输入邻接矩阵和重构邻接矩阵之间的重构损失。更具体地说,它是目标(A)和输出(A’)逻辑之间的二元交叉熵。第二部分是 q (Z | X,A)p(Z) 之间的 KL-散度,其中 p(Z) = N(0,1) 。它测量我们的 q (Z | X,A)p(Z) 的匹配程度。

使用内积解码器的优势

在我们得到潜变量 Z 之后,我们要想办法学习潜变量中每一行的相似度(因为一行代表一个顶点)来生成输出邻接矩阵。内积可以计算两个向量的余弦相似性,这在我们需要一个对向量大小不变的距离度量时很有用。因此,通过对潜在变量 ZZ^T 应用内积,我们可以学习 Z 内部每个节点的相似度来预测我们的邻接矩阵。

链路预测实验

在变分图自动编码器论文中,作者还创建了一个传统的图自动编码器模型(GAE)作为 VGAE 模型的对比。GAE 模型有一个单 GCN 层作为编码器,直接生成潜变量 Z ,还有一个内积解码器,和 VGAE 模型一样。作者在三个数据集(Cora、citeser 和 Pubmed)上测试了这两个模型,VGAE 模型在 Cora 和 citeser 数据集上都获得了更高的预测性能。

结论

在这篇文章中,你已经学习了传统自动编码器、变分自动编码器的基本思想,以及如何将 VAE 的思想应用于图结构数据。

图结构数据在当今各个领域发挥着越来越重要的作用。我相信在不久的将来,图结构数据分析将成为机器学习中最受欢迎的主题之一。

参考

[1] 自动编码变分贝叶斯

[2] 变分图自动编码器

[3] 图形自动编码器 TensorFlow 实现

[4] 变分自动编码器教程

[5] 库尔贝克-莱布勒散度

教程:使用深度学习和 CNN 制作手势识别模型

原文:https://towardsdatascience.com/tutorial-using-deep-learning-and-cnns-to-make-a-hand-gesture-recognition-model-371770b63a51?source=collection_archive---------1-----------------------

首先,这是包含代码的 Github 库。该项目采用 Jupyter 笔记本的形式,可以上传到谷歌合作实验室,在没有环境问题的情况下工作。

机器学习对于各种现实生活中的问题非常有用。它通常用于分类、识别、检测和预测等任务。此外,自动化使用数据的流程非常有效。基本思想是使用数据生成一个能够返回输出的模型。这个输出可以用新的输入给出正确的答案,或者产生对已知数据的预测。

这个项目的目标是训练一个机器学习算法,能够对不同手势的图像进行分类,例如拳头、手掌、拇指和其他手势。例如,这个特殊的分类问题对手势导航很有用。我将使用的方法是借助基于 Tensorflow 和 Keras 的卷积神经网络进行深度学习。

深度学习是更广泛的机器学习方法家族的一部分。它基于处理输入数据的图层的使用,从这些图层中提取要素并生成数学模型。这个“模型”的创建将在下一次会议中更加清晰。在这个特定的项目中,我们的目标是对手势的不同图像进行分类,这意味着计算机必须“学习”每个手势的特征,并对它们进行正确分类。例如,如果给定一个做竖起大拇指手势的手的图像,模型的输出需要是“手在做竖起大拇指的手势”。我们开始吧。

加载数据

这个项目使用了 Kaggle 上的手势识别数据库(引用如下)。它包含了 20000 张不同手和手势的图片。在数据集中呈现了 10 个不同的人的总共 10 个手势。女被试 5 人,男被试 5 人。
这些图像是使用 Leap Motion 手部跟踪设备拍摄的。

Table 1 — Classification used for every hand gesture.

有了这些,我们必须准备图像来训练算法。我们必须将所有图像加载到一个名为 X 的数组中,并将所有标签加载到另一个名为 y 的数组中。

X = [] # Image data
y = [] # Labels# Loops through imagepaths to load images and labels into arrays
for path in imagepaths:
  img = cv2.imread(path) # Reads image and returns np.array
  img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Converts into the corret colorspace (GRAY)
  img = cv2.resize(img, (320, 120)) # Reduce image size so training can be faster
  X.append(img)

  # Processing label in image path
  category = path.split("/")[3]
  label = int(category.split("_")[0][1]) # We need to convert 10_down to 00_down, or else it crashes
  y.append(label)# Turn X and y into np.array to speed up train_test_split
X = np.array(X, dtype="uint8")
X = X.reshape(len(imagepaths), 120, 320, 1) # Needed to reshape so CNN knows it's different images
y = np.array(y)print("Images loaded: ", len(X))
print("Labels loaded: ", len(y))

Scipy 的 train_test_split 允许我们将数据分成一个训练集和一个测试集。训练集将用于构建我们的模型。然后,测试数据将被用来检验我们的预测是否正确。使用了一个 random_state 种子,因此我们的结果的随机性可以被重现。该函数将随机播放它正在使用的图像,以最大限度地减少训练损失。

# Percentage of images that we want to use for testing. 
# The rest is used for training.
ts = 0.3X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=ts, random_state=42)

创建模型

为了简化这里构建的模型,我们将使用线性回归的概念。通过使用线性回归,我们可以创建一个简单的模型,并使用等式 y = ax + b 来表示它。
ab (分别是斜率和截距)是我们试图寻找的参数。通过寻找最佳参数,对于任何给定的 x 值,我们可以预测 y 。这是相同的想法,但更复杂,使用卷积神经网络。

卷积神经网络(ConvNet/CNN)是一种深度学习算法,可以接受输入图像,为图像中的各个方面/对象分配重要性(可学习的权重和偏差),并能够区分彼此。与其他分类算法相比,ConvNet 中所需的预处理要低得多。虽然在原始方法中,过滤器是手工设计的,但是经过足够的训练,CNN 有能力学习这些过滤器/特征。

Figure 1 — Example of Convolutional Neural Network.

从图 1 和想象我们讲过的线性回归模型方程,我们可以想象输入层是 x ,输出层是 y 。隐藏层因模型而异,但它们用于“学习”模型的参数。每一个都有不同的功能,但他们致力于获得最佳的“斜率和截距”。

# Construction of model
model = Sequential()
model.add(Conv2D(32, (5, 5), activation='relu', input_shape=(120, 320, 1))) 
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu')) 
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(10, activation='softmax'))# Configures the model for training
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])# Trains the model for a given number of epochs (iterations on a dataset) and validates it.
model.fit(X_train, y_train, epochs=5, batch_size=64, verbose=2, validation_data=(X_test, y_test))

CNN 将一系列过滤器应用于图像的原始像素数据,以提取和学习更高级别的特征,然后模型可以使用这些特征进行分类。CNN 包含三个组件:

  • 卷积层,将指定数量的卷积滤镜应用于图像。对于每个子区域,图层执行一组数学运算,以在输出要素地图中生成单个值。然后,卷积层通常对输出应用 ReLU 激活函数,以将非线性引入模型。
  • 池层,对卷积层提取的图像数据进行下采样,以降低特征图的维度,从而减少处理时间。最大池算法是一种常用的池算法,它提取特征地图的子区域(例如,2x2 像素的分块),保留其最大值,并丢弃所有其他值。
  • 密集(完全连接)图层,对卷积图层提取的要素执行分类,并由汇集图层进行缩减采样。在密集层中,该层中的每个节点都连接到前一层中的每个节点。

测试模型

既然我们已经编译和训练了模型,我们需要检查它是否是好的。首先,我们运行“model.evaluate”来测试准确性。然后,我们进行预测,并绘制出带有预测标签和真实标签的图像,以检查一切。这样,我们就可以看到我们的算法是如何工作的。稍后,我们制作一个混淆矩阵,这是一个特定的表格布局,允许可视化算法的性能。

test_loss, test_acc = model.evaluate(X_test, y_test)print('Test accuracy: {:2.2f}%'.format(test_acc*100))

6000/6000[= = = = = = = = = = = = = = = = = = = =]—39s 6 ms/步

测试准确率:99.98%

predictions = model.predict(X_test) # Make predictions towards the test sety_pred = np.argmax(predictions, axis=1) # Transform predictions into 1-D array with label number# H = Horizontal
# V = Verticalpd.DataFrame(confusion_matrix(y_test, y_pred), 
             columns=["Predicted Thumb Down", "Predicted Palm (H)", "Predicted L", "Predicted Fist (H)", "Predicted Fist (V)", "Predicted Thumbs up", "Predicted Index", "Predicted OK", "Predicted Palm (V)", "Predicted C"],
             index=["Actual Thumb Down", "Actual Palm (H)", "Actual L", "Actual Fist (H)", "Actual Fist (V)", "Actual Thumbs up", "Actual Index", "Actual OK", "Actual Palm (V)", "Actual C"])

Figure 3 — Confusion matrix showing the predicted outcomes and the actual image label.

结论

基于上一节中给出的结果,我们可以得出结论,我们的算法基于深度学习模型以足够的置信度(> 95%)成功地对不同的手势图像进行了分类。

我们模型的准确性直接受到我们问题的几个方面的影响。呈现的手势相当清晰,图像清晰,没有背景。此外,存在合理数量的图像,这使得我们的模型更加健壮。缺点是,对于不同的问题,我们可能需要更多的数据来将我们的模型参数推向更好的方向。此外,鉴于其抽象性,深度学习模型很难解释。然而,通过使用这种方法,开始解决实际问题变得更加容易,因为我们不必考虑特征工程。这意味着我们不需要用边缘或斑点检测器预处理图像来提取重要特征;CNN 为我们做的。此外,它可以相对容易地适应新问题,通常表现良好。

如上所述,解决该问题的另一种方法是使用特征工程,例如二值化阈值(检查手的区域)、圆检测和其他方法来检测图像上的独特特征。然而,有了 CNN 的方法,我们就不用担心这些了。

有疑问吗?欢迎在Github 资源库上发送问题/议题!

信用

T.Mantecón,C.R. del Blanco,F. Jaureguizar,N. García,“使用 Leap Motion Controller 提供的红外图像进行手势识别”,Int。糖膏剂智能视觉系统的先进概念,ACIVS 2016,意大利莱切,第 47–57 页,2016 年 10 月 24–27 日。(doi:10.1007/978–3–319–48680–2 _ 5)

适合初学者的 Tweepy

原文:https://towardsdatascience.com/tweepy-for-beginners-24baf21f2c25?source=collection_archive---------8-----------------------

使用 Twitter 的 API 建立你自己的数据集

建立你的投资组合的一个好方法是自然语言处理项目,但是像每个项目一样,第一步是获取数据。Twitter 可以成为文本数据的巨大资源;它有一个 API,凭证很容易获得,并且有许多 python 库可以帮助调用 Twitter 的 API。

总的来说,这些资源很棒,但它们有一些容易引起头痛的怪癖,本文将帮助您导航该过程并避免这些头痛,请将它视为您的赛前扑热息痛!

第一步:获得你的证书

给自己注册一个账户:Twitter 用户账户是拥有“开发者”账户的必要条件,所以要么注册一个新账户,要么登录一个现有账户。

申请开发者账号:前往https://developer.twitter.com申请开发者账号。如果出现提示,请选择个人或个人帐户,而不是企业帐户。当提交一个预期用途时,确保你的答案是足够描述性的,而不是一些垃圾或现成的复制粘贴语句。

创建 app: 在https://developer.twitter.com/en/apps注册 app。对于必填的网站字段,您可以放置一个占位符。设置完成后,转到“令牌和密钥”以生成访问令牌和密码。连同消费者 API 密钥(已经生成),这些是我们用来与 Twitter API 通信的凭证。

步骤 2:安装 Tweepy

有几个库可用于与 Twitter 的 API 交互,我更喜欢 Tweepy ,它进行可靠的调用,非常适合处理超过 140 个字符的推文。

只需将pip install tweepy写入您的终端。

您可能需要的其他几个库(取决于您想做什么)是 json、pandas、time 和 datetime。稍后我们会看到更多关于这些的内容。

第三步:快速测试运行

API 凭证,检查。Tweepy 安装完毕,检查完毕。时间来看看它是否工作,粘贴下面的代码在一个笔记本上,在你自己的键 sub(注意错别字!)然后跑。

嘣!您刚刚进行了第一次 Twitter API 调用。你现在应该会看到你的账户主页时间线上的一系列推文(你的账户关注的每个人的推文)。它看起来会像这样:

Tweepy text output

够简单了吧?不对。我们可能会看到一些数据,但在目前的格式下,这些数据不是很有用,一些推文已经被截断,我们只有来自我们已经关注的账户的数据。如果我们想要构建一个结构化的数据集来进行分析,我们必须更深入地研究 API 调用输出…戴上安全帽!

步骤 4:检查 tweets json

在一个新的单元格中键入并执行public_tweets[0]来查看与第一条 tweet 相关的 json,享受输出。

A messy output, hard to make sense off

这不是我们处理数据的方法,试几分钟,你就会重读几行,然后马上让自己头疼。

如果你以前尝试过抓取,你可能使用过 pprint (漂亮的打印)以一种更可读的方式格式化数据。不幸的是,pretty print 在这里不能帮助我们,因为 public_tweets[0]不是一个基本的 python 数据类型,它的类型是 tweepy.models.Status,并且 pprint 模块不兼容。

我们需要使 tweepy 的输出更具可读性,这样我们就可以知道需要编写什么代码来提取我们想要的数据。我们可以这样做:

现在,您将看到一些更有条理的东西:

A clean output, a lot easier to parse

有了这个视图,我们可以慢慢地浏览字典和列表,以确定哪些信息是可用的,以及访问这些信息需要哪些键。

步骤 5:解析出数据

如果您只是想要 tweet 上的原始数据(文本、id、用户 id),访问这些信息相对容易和可靠,正如我们已经看到的,当使用 home timeline API 调用时,我们可以使用status.text访问 tweet 的文本。

根据你项目的性质和你需要的数据,你需要选择合适的 API 调用来收集它。本文的其余部分将重点介绍如何使用 user_timeline 调用,该调用(对于一个标准帐户)可以检索一个用户的多达 3200 条最新推文(只要配置文件没有被锁定)。

这就是 Tweepy 变得有点麻烦的地方。API 调用返回的 json 结构根据 tweet 的特征而变化(想想常规 tweet、retweet 或 quote tweet)。不是提供一致的格式(如果没有信息可用,则键指向空列表),有些键只在有数据指向时才出现。

克服这一点的简单方法是满足于主要的推文信息,但是如果你关心转发和引用,那么你的数据将是不完整的。如果我们想要构建一个丰富的数据集,我们需要使用 try 和 except 语句来处理这种不一致性。

收集数据的一个好方法是构建一个可以进行 API 调用并一次性解析数据的类。它可能看起来像这样:

关于这段代码的几点说明:

  • 无论 tweet 类型如何,挖掘的字典中没有 try 语句的所有内容都是可访问的。
  • tweet_mode = 'extended'将文本索引替换为 full_text,并防止长度超过 140 个字符的主要推文被截断。不幸的是,转发仍然被截断,我们可以使用.retweeted_status.full_text访问完整的转发文本,这里我们放入一个 try 语句,因为它只在推文是真正的转发时出现。
  • 位置数据包含坐标、城市和国家,这取决于您想要什么,您需要进一步解析它,但这很容易。
  • result_limit 和 max_pages 相乘得到调用的 tweets 数。
  • 转发和引用推文包括在你的 3200 条推文中,无论你是否收集它们(关闭此设置不会获得更多主推文)。
  • 如果你在使用这个类打电话时没有提供用户名,你将会从独一无二的 wint 中抓取推文,欢迎你!

请务必花时间对照我们之前制作的结构化 json 输出版本和两个附加输出(每种 tweet 类型一个,常规、转发和引用)来查看这段代码。通过这样做,你将更好地理解数据是如何被访问的,并准备好为不同的调用创建你自己的类,或者修改这个类来收集额外的数据。

第六步:选择一个项目,确定你想要的数据

这可能是你的第一步,甚至可能是你读到这篇文章的原因。在这里你可能不需要太多帮助,但是一些建议不会有坏处。

在开始一个项目之前,找出是否有任何可用的现有资源。像每一个原始数据科学家一样,我带着分析政客的推文的意图选择了 Tweepy,通过快速的谷歌搜索,我找到了每一个拥有推特账户的英国国会议员的推特账号列表,这让我省去了很多繁重的工作。

明确你的目标,如果是学习,确保你关注其他项目,这有利于激励,获得想法,如果你陷入困境,可以帮助你指出正确的方向。如果原创是你的目标,再次,看看其他项目,你最好的想法可能是对现有项目的补充,拥抱开源哲学。

一旦你确定了你想收集谁的 tweets,就把所有的句柄收集到一个字符串列表中(不要在每个 Twitter 用户名前加上@符号)。

步骤 7:收集数据!

通过导入所需的库来启动会话:

复制该类的代码,代入您自己的 API 凭据。

实例化您的 miner,记住默认的 tweets collected 设置为 20,您可以在实例化时更改它(调用时指定的页面数量,即调用收集的 result_limit 的倍数):

现在,您已经准备好打电话,并以您可以使用的格式收集数据。要拨打电话:

现在你知道了。有了 3200 条 wint tweets 的数据框架,你离理解生命的意义就差一点点了!

最后要记住的是 API 调用是有限制的,对于一个标准用户来说,这是每 15 分钟 900 个请求。不要担心,一条 tweet 不是一个请求,但是可能很难知道你什么时候要过去。要同时拨打多个电话,请尝试以下方法:

开始在没有睡眠计时器的情况下打电话,然后如果你得到一个与你的通话限制有关的错误,就试试睡眠计时器和计数器 if 语句(每 25 次通话启动一次计时器),直到你得到对你有用的东西。

最后,注意 all_tweets 数据帧的索引对于每个句柄都是重复的。为了使它对所有的推文都是唯一的,需要重新设置索引。

就这些了!你现在已经准备好以一种可用的格式收集大量的推文了。狩猎愉快!

通过圆圈和用户交互实现 Tweets 数据可视化

原文:https://towardsdatascience.com/tweets-data-visualization-with-circles-and-user-interaction-485cad7ff248?source=collection_archive---------19-----------------------

如何利用 circles 和 Matplotlib 从一组 tweets 中创建有趣、漂亮且“可探索”的可视化

Photo by: https://m.yourshot.nationalgeographic.com/photos/8981395/

在这里,我们将讨论如何利用圆圈从一组推文中创建一个有趣的、美丽的、可探索的可视化。这个想法是,每个圆圈将对应一条推文,我们将组织所有的圆圈,以便它将成为数据可视化的一个有趣的静态图像。此外,可视化可以设计为我们可以通过点击静态图像上的相应圆圈来浏览推文。我们将会看到,我们实际上可以做到这一点,甚至不改变静态图像的一部分。这里讨论的实现将使用 Matplotlib 来完成。

模型

一个圆圈将被用来代表一条推文。圆圈的颜色透明度将反映该推文的转发数量(也可能是喜欢的数量,取决于你的兴趣)。颜色较深的圆圈代表转发量较高的推文。透明度高的圆圈是转发次数少的推文。在数据集中的所有推文中,肯定有一条推文的转发次数最高,这条推文将由一个没有透明度的圆圈表示。因此,只有转发量最高的推文才会是彩色的,没有透明度。数据集中的所有其他推文将会更加透明。

到目前为止,我们只为可视化添加了一个度量:转发的数量(或喜欢的数量)。但是我们可以利用圆的另一个属性,那就是大小(半径)。那么尺寸代表什么呢?有很多选择..但是让我们选一个。默认情况下,所有圆圈的半径都是 1,但如果一条推文的赞数多于转发数,那么我们会将圆圈的半径设置为 2。通过这种方式,我们的眼睛可以很容易地区分哪些推文的点赞数多于转发数。

现在我们应该如何组织圈子?我们可以只是分散图中的圆圈,但这看起来很乱,圆圈可能会相互重叠。我们可以将圆放在散点图中(x 轴和 y 轴代表两个额外的测量值),但是圆也可以相互重叠。所以,我们想要的是没有两个圆互相重叠。这需要我们自己写算法。对于我们的例子,我们将使用一种类似于圆形装箱算法的算法(一般 &具体 )。圆的位置将是随机的,但是居中,并且将尽可能地紧凑。

以下是一个样本非常少的示例(为简单起见):

Visualization with small samples (5 tweets for each account)

上图是使用小样本(5 条推文)的可视化示例,这些样本来自 Sadiq Khan(伦敦市长)、Donald Trump(美国总统)、Prabowo Subianto(印度尼西亚总统候选人)和佐科·维多多(印度尼西亚总统)的推特账户。汗和特朗普的推文收集于 2018 年 11 月 25 日,普拉博沃和佐科维的推文收集于 2018 年 11 月 22 日。我们可以很容易地看到,唐纳德·特朗普的推特比其他人有更多的反应。只有一条推文的转发量超过了点赞量,它来自萨迪克·汗。以下是两条推文的快照(一条来自特朗普,另一条来自萨迪克·汗):

The number of retweets and likes on the image are already updated. (this image is captured on 1 Feb 2019)

At the time of collection, the number of likes is 0 and the number of retweets is 38. The tweet was retweeted by Sadiq Khan. (this image is captured on 1 Feb 2019)

Sadiq Khan 和 Prabowo Subianto 的 5 条推文并不出名,因为圆圈的颜色非常接近白色(非常透明)。

用于可视化的数据集由 tweet 对象组成,每个 tweet 对象由类tweepy.models.Status表示(在 Tweepy 包中有更多关于这个的信息)。该类存储了许多信息,如 tweet 文本、发布时间、作者信息、转发次数、喜欢次数等。

算法和数学

在本节中,我们将讨论算法及其背后的数学原理。为了在绘图中显示一个圆,我们可以使用[matplotlib.patches.Circle](https://matplotlib.org/api/_as_gen/matplotlib.patches.Circle.html)类。我们可以创建该类的一个实例,然后我们可以通过将该圆补片(实例)添加到轴上来绘制圆。例如,下面的代码将绘制一个蓝色的圆圈:

from matplotlib.patches import Circlea_circle = Circle(xy = (0, 0), radius = 1, color = "blue") #a blue circle with center at (0,0) and radius 1fig, ax = plt.subplots()
ax.axis('square')
ax.add_patch(a_circle)fig.show()

我们也可以用另一种方式设置蓝色,使用带有透明编号的 RGB 颜色序列:

blue_color = (0, 0, 1, 1) #edit the 4th number to change the transparency 
a_circle = Circle(xy = (0, 0), radius = 1, color = blue_color)

现在,我们的数据可视化将不仅仅是绘制圆圈,还将尽可能整齐地组织它们。我们不希望两个圆互相碰撞,但是如何使用 Matplotlib 实现呢?要回答这个问题,让我们分析一下圈子的一些行为。这是两个“几乎”相互重叠的相邻圆的图像:

Two circles tangent to each other

上图是两个圆相互接触的情况。注意,我们还从图像中得到了一个小小的数学洞见: 当两个圆相互接触时,它们的半径之和等于两个圆心之间的距离 这是回答撞圆问题的关键。你可以继续自己解决问题。这并不难,让我给个提示:想象另外两种情况(两个圆互相重叠,两个圆不互相接触)

到目前为止,我们应该已经知道如何绘制圆,以及如何设计图形以使两个圆不会发生碰撞。我们需要考虑的下一个概念是“圆圈的位置分布”。我们需要分配(或打包)所有的圆圈,这样就不会有两个圆圈碰撞,但是圆圈之间不应该有很大的间隙。这部分比较棘手,这里有一个显而易见的算法(但是比较耗时):

  1. 创建一个圆心随机的圆
  2. 然后检查该圆与所有其他绘制圆的“碰撞”状态
  3. 如果发现一个碰撞,那么用另一个随机中心改变圆心,然后从上面的步骤 2 重新开始。如果没有发现碰撞,画圆。

我们讨论的可视化不采用上述算法。它从这条 中取长补短。我们的算法看起来与我们排序的方式相似。例如,假设地板上有 10 个重叠的圆(由一张纸制成),它们都位于非常靠近点 P 的位置。为了像圆圈打包一样组织它们,我们可以滑动与另一个圆圈重叠的每个圆圈(滑动是这样的,两个圆圈互相排斥,位移很小)。经过多次重复后,所有的圆圈都将装满 P 大约在包装的中心。这个算法看起来更生动,它使上面明显的“3 步”算法看起来非常僵硬。

此外,为了使我们的数据可视化更有趣,我们可以添加交互式元素。可视化可以设计成这样,我们有两个图形,一个用于圆圈(主要数据 viz),另一个显示关于一条 tweet 的更详细的信息(文本)。更具体地说:如果我们点击一个圆圈,那么关于相应推文的一些信息(文本、转发次数、喜欢次数和发布日期)将出现在第二张图中。这可以通过使用 Matplotlib 的特性[fig.canvas.mpl_connect](https://matplotlib.org/users/event_handling.html)函数来完成。

增加互动性:点击发布信息

在绘制和打包所有的圆后,我们可以让每个圆像一个按钮一样工作。为了实现这一点,我们可以包含来自函数fig.canvas.mpl_connect.的帮助。该函数可以接受两个参数,第一个参数是对应于交互类型的字符串(在我们的例子中,它必须是"button_press_event"),第二个参数是当该类型的事件被触发时将被调用的函数。示例:

fig.canvas.mpl_connect('button_press_event', on_click)

上面的代码行将为图形fig添加交互性,但仅限于按钮按下事件(如果您想要另一种类型的交互:对于图形上的鼠标移动,使用"motion_notify_event")。第二个参数中的函数必须设计成有一个名为event.的输入。在我们的例子中,我们将把函数命名为on_click.

现在,我们必须设计函数on_click,使我们每次在主图中选择并点击一个圆,另一个图就会显示该圆对应的 tweet 的一些细节。信息的呈现必须设计得简洁。以下是当前用于可视化的一个示例:

### fig2 is the figure for the tweet informationfig2, ax2 = plt.subplots()ax2.set_xlim([0, 50])
ax2.set_ylim([0, 50])
ax2.tick_params(colors = (0,0,0,0))def on_click(event):
    ax2.cla()
    x = event.xdata
    y = event.ydata
    print(x,y)
    for i in scattered:
       if abs(x-i.center[0]) <= i.radius:
           if lower_circle(x, i.radius, i.center) <= y <= upper_circle(x, i.radius, i.center):
               try:
                   text = i.tweet.full_text
               except:
                   text = i.tweet.text

               ax2.text(25, 35, i.tweet.created_at, fontproperties = helv, \
                        ha = 'center', va = 'center', color = 'black')
               ax2.text(25, 33, squeeze_text(text), fontproperties = helv, \
                        color = "white", ha = 'center', va = 'top', \
                        bbox = {'boxstyle': 'round', 'ec': "black", 'fc': "gray"}) ax2.text(25, 17, i.tweet.author.name + " (@{})".format(i.tweet.author.screen_name), \
                        fontproperties = helv, ha = 'center', va = 'center', color = "black") ax2.text(25, 15, "Retweet: {}, Likes: {}".format(i.tweet.retweet_count, i.tweet.favorite_count), \
                        fontproperties = helv, ha = 'center', va = 'center', color = "black") fig2.show()
               break
    print("done")fig.canvas.mpl_connect('button_press_event', on_click)

scattered是包含许多CircleObj 对象的列表。CircleObj是用户定义的类,继承自 Matplotlib 的Circle类。这是设计的一瞥:

class CircleObj(Circle):

    def __init__(self, tweet, value, label, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.value = value
        self.label = label
        self.tweet = tweet def collide(self, circles):
        colliding = []
        [colliding.append(i) for i in circles if (dist(self.center, i.center) < self.radius + i.radius)]
        return colliding

    #other methods

代码有circles,它是一个全局变量,是所有CircleObj对象的列表,它们的顺序在scattered列表中被随机化。self.tweet属性由tweepy.models.Status.用于 tweet 对象,collide方法旨在返回所有与self冲突的CircleObj对象。这里没有给出用上一节描述的算法分发和打包圆的完整代码。但是很明显..它包含一个代码块,该代码块反复更新圆的位置,直到它们都没有重叠。

当条件:abs(x-i.center[0]) <= i.radiuslower_circle(x, i.radius, i.center) <= y <= upper_circle(x, i.radius, i.center)都为真时,tweet 信息将以文本形式绘制。lower_circleupper_circle是圆方程的函数(给定x,它们将返回圆曲线上的点的 y 值(【T5,y】)。

当我们在图上的任何地方按下鼠标按钮时,总是会触发on_click功能,但是当我们在绘制的圆圈内单击时,它只会绘制 tweet 信息。以下是绘制信息的示例:

注意,该字体不是 Matplotlib 中的默认字体。您可以通过实现matplotlib.font_manager.来了解如何在 Matplotlib 中使用新字体。另外,请注意,还有另一个用户定义的函数来修饰圆形边界框内的 tweet 文本,即squeeze_text。它使文本每行最多 7 个单词,最多 8 行/行。

大型数据集的结果

使用 400 条 tweets 的实现通常需要大约 400-500 次检查所有圆圈的迭代,一次迭代通常需要半秒钟。如果 tweets 的数量更大,那么完成一次迭代所需的时间会更长。在第一次迭代时:所有的圆都非常接近原点,点(0,0),与它的最大偏差为 0.01 半径。然后,对于之后的每一次迭代,我们通过应用排斥运动,对每两个重叠的圆中的每一个进行非常小的扫动,两个圆相互推开,而不必在一个步骤中使它们成为非重叠的圆。在本节中,我们将查看数据可视化的两个示例结果:

  • 第一个例子是使用 1000 条推文的数据集。500 条推文来自印尼 CNN,另外 500 条来自 Metro TV。两者均于 2018 年 11 月 21 日采集。结果如下:

500 tweets from CNN Indonesia and 500 tweets from Metro TV. There are two green circles with quite strong color.

从这个结果我们可以得出一些结论:

—与所有其他推文相比,印度尼西亚 CNN 的 2 条推文(2 个绿色圆圈)的转发量非常高。似乎没有任何来自地铁电视台的推文像这些推文一样受欢迎。

——我们不能说有更多转发>喜欢的推文,或者其他

虽然从静态图像中没有太多的见解,但我们可以通过简单地点击圆圈来清楚地进行探索。而且可视化也挺好看的。

好吧,我们的第一次数据分析并不令人满意。接下来,如果我们使用包含 4 个不同账户的数据集,事情会变得更有趣。

  • 第二个例子是使用来自四位政治家的 400 条推文的数据集:萨迪克汗先生、川普先生、普拉博沃先生和佐科·维多多先生(各 100 条推文)。萨迪克先生和特朗普先生的推文是在 2018 年 11 月 25 日收集的,而普拉博沃先生和佐科维先生的推文是在 2018 年 11 月 22 日收集的。对于第二个示例,我们还将看到一个展示用户交互的视频:

除了视频,这里是静态图像(*与视频中的略有不同:两者提供相同的信息,但由于不同的计算,它们在定位上有所不同)

400 tweets from 4 politicians. Trump’s tweets appear to be more popular than all the others, with quite a large gap.

我不会写一些关于上述可视化的结论,但有一点很清楚,与其他 3 位政治家相比,特朗普的推文非常受欢迎。此外,突出的推文通常是有争议的,这里有一些例子:

结束语

我们已经看到,像圆形这样简单的形状可以用来在数据可视化中表示推文。我们还可以使可视化具有交互性(尽管仍然非常简单)。使用 Matplotlib 实现并不困难。

这种可视化方法可以扩展:

  • 可视化也可以用图形来建模:圆或 tweets 可以用顶点来表示,圆的邻接可以用边来表示。邻接也可以被设计成具有意义(当前的邻接不使用邻接来给出信息)。此外,圆的位置可以表示一个或多个测量值。没有意义的留下一个圈位置是一种浪费。
  • 一个简单的扩展:我们可以将喜欢的数量附加到圆的半径上,从而将喜欢的数量包含到可视化中。请注意,我们不需要确切的数字来显示在主视图中,因为我们只需单击一个圆圈,然后 tweet 信息就会出现在另一个图中。以下是一个示例结果(使用每个账户的 50 条推文):

Visualization that includes the number of likes (represented by the size of the circle)

这个文笔离专家级还很远。有更多类型的复杂数据和数学可视化可以提供更多的见解和更多的应用。我欣赏建设性的意见。

(完整代码预计将在 Github 上提供)*

扭转图——来自推特行为的数据可视化(Art)

原文:https://towardsdatascience.com/twiring-diagrams-data-visualization-art-from-tweeting-behaviour-38601aa2b2c6?source=collection_archive---------20-----------------------

https://twiring.appspot.com/

twining来自 Twitter+Wiring——因为这些图看起来像“接线”图。而且,扭动是为了 害羞或狡猾地瞥一眼 这正是这种可视化形式的功能。

灵感

我的灵感来自于吉姆·瓦兰丁汉姆的句子图画(最初灵感来自于斯蒂芬妮·波萨维克的句子图画艺术),我想为用户的推特行为做一个类似的可视化。我的一些旧项目着眼于生成 Twitter 自我网络,然后通过算法从推文中提取和描述主题,所以这有点像混搭。

Posavec’s original Sentence Drawings

波萨维克的画句子的概念相当简单:你画一条相对相当于句子长度(字数)的线,右转,画一条对应下一句话的线,以此类推。这导致视觉在遇到连续的短句时变得拥挤,在出现长句时变得开阔。

Posavec’s original Legend and Basic Structure

扭曲

Twiring 采用上述句子绘图的基本结构,将句子替换为来自用户的 tweet 并执行概念上的扭曲:一行的长度代表自上次 tweet 以来的时间差,而不是 tweet 的字数。句子绘制的空间性成为一种可视化用户推特行为时间维度的方式。除了这个主开关之外,我还添加了一些其他可视化代码,以便在绘图上添加更多信息。

我还在绘图的背景中添加了一些圆圈,以表明一条推文的受欢迎程度。

此外,我还加入了搜索功能(基本的字符串匹配)来过滤图片上的线条/推文——我认为这很酷,因为你可以看到哪些术语何时出现,并缩小特定术语周围的推文行为。

可视化摘要

  • 每条线都是一条推文
  • 基本结构:在每条线的末端,你做一个右转然后开始画下一条线
  • 在内有+的黑框是最早的推文,空的黑框是最近的推文
  • 一行的长度是相对于从用户最后一次发推起有多长时间了
  • 每行的颜色是推文被分组的主题
  • 每一行的粗细与其主题有多密切的关系
  • 点击任何一个图例项将会切换它们在图上的可见性
  • 搜索栏(键入并按回车键)也可以用于过滤,基于你的输入与 tweet 中的文本的非常基本的比较
  • 回复和不回复按钮可以分别切换推文。(注意:回复自己不被视为“回复”)
  • 在每条线的开头画出了圆圈,表示基于 RTs 和喜欢的 tweet 的受欢迎程度(相对而言)
  • 将鼠标悬停在一行上会显示该推文的更多细节
  • 可以使用右边的工具栏平移、缩放和保存该图

笔记

我将它作为一个 web 应用程序托管,供您使用和播放——请注意,主题建模和收集推文可能需要一些时间(0-3 分钟)。

主题建模有一些随机性,因此刷新将重新计算它们,您将丢失当前配置。

我最多只分析了 1000 条最近的推文。

我还会过滤掉少于 50 个字符的 RTs/赞或推文。

出于可伸缩性/速度的原因,主题建模本身是简单的、轻量级的和未经过滤的(不使用词性标注或 NLP 来预处理文本)。

我不存储任何人的推文,我只要求 twitter 认证的只读权限。

链接:https://twiring.appspot.com/

示例用法

  • 直观感受你在发推之间休息了多长时间
  • 搜索一个特定的术语,看看它是如何/何时出现在你的历史中的
  • 以同样的方式分析其他用户的推文
  • 立即看到热门推文脱颖而出,并找出任何模式
  • 等等等等

Twitter——或者我的机器人和你的机器人说话的地方

原文:https://towardsdatascience.com/twitter-3478a68d5875?source=collection_archive---------16-----------------------

PYTHON DIY 终极指南——构建 TWITTER 机器人

阅读我如何用 Python 构建了一个 Twitter 机器人来运行一个有问题的实验。包括所有代码和详细的解释。

Image by Jonny Lindner from Pixabay

摘要

在这个故事中,我将详细解释我如何构建一个 Twitter 机器人,它利用人类的一些基本情感来产生追随者。这种事每天都发生在我们所有人身上。我认为说明它是多么容易是至关重要的。我将分享一些有趣的经历,并在 Twitter 上展示 bot 感染的证据。

文章的后半部分深入描述了机器人的代码和功能。当前的生产代码可在 Github 上获得。我在 AWS 上运行 bot,并通过无服务器框架部署它。它甚至没有使用每月 AWS 免费层的 5%。所以试试吧。

如果这篇文章会让我的推特账户被封禁,我不会感到惊讶。但是嘿,尤洛!

动机

Photo by Patrick Fore on Unsplash

大约六周前,我开始在媒体上写作。我想写一些文章,帮助人们接触 Python,并且,总的来说,拓宽他们的技能。原因是我的一些团队成员想学习 Python,我想这可能会有协同作用。当我开始时,我对自己说,我会这样做两个月,看看会有什么结果。如果出现最坏的情况,我会有一些结构良好的文章,可以用来教 Python。我确信,几乎每个人都可以从了解 Python 中受益。

我写了第一篇关于群体的文章。我没有研究人们是否关心这个话题。坦白说,我不在乎。我不知道如何恰当地编排媒体文章的格式,甚至不知道你最初可以包含图片。我只是想开始,这是我最近做了一些工作的一个主题。

观众人数少得可笑,大约每天只有 30 次浏览。然后这篇文章出现在专栏数据科学编程中,不久之后,出版物更好的编程发布了它。观众人数直线上升。至少按照我当时的标准。

当你从未见过建筑时,即使是一层楼的房子看起来也像一座大房子

我每天被浏览 150 次。感觉很好。那一刻,我设定了一个雄心勃勃的目标。我想写一篇在 30 天内有 100,000 浏览量的文章。实际上是一个任意的数字,但是明确和雄心勃勃的目标有助于不失去焦点。我对自己说,我每周至少要发表一篇文章。我在晚上写作,晚上 9 点到 11 点,周末也写作。有时候很有挑战性,但是我一直坚持。

第二篇文章在观看人数方面要好得多。 走向数据科学 发现了这个故事,因为我热爱这个出版物,所以我毫不犹豫地在那里发表。也许这个话题更贴切一点。谁知道呢。没关系。我正朝着正确的方向前进。

推特

Photo by Nicholas Green on Unsplash

介绍 Twitter!我的第三篇文章是第二篇文章的后续。它包括了某种程度上先进的可视化。我在一个星期五的晚上发表了它,我知道它并不完美,但我没有时间早点完成它。毕竟,我必须达到我的目标。然后奇怪的事情发生了。我的观众人数爆炸了。仅在周日,这篇文章就获得了 4000 次浏览。我大吃一惊。我必须了解这一点,所以我开始寻找潜在的原因。经过一番挖掘,我发现了这个:

Kirk Borne had tweeted a link to my third article

我没有想到 Twitter 是一个合适的媒体作品分销渠道,但不可否认它的影响。我想,如果柯克能做到这一点,我当然也能做到。因此,我重新启用了自己创建的账户,关注唐纳德·特朗普(Donald Trump),偶尔开怀大笑。只有一个问题,这个账号有精确的零关注者。

我开始在推特上发帖,喜欢推文,转发,关注人。天啊,这太累了。我很快意识到,Twitter 就像一个疯狂的集市,每个人都通过扩音器以疯狂的频率不断脱口而出他们的想法和观点。我从事营销工作,对 Twitter 上的推荐活跃度做了一些研究,这简直太疯狂了。一些消息来源暗示每天多达 20 个帖子,其他人甚至更多。我没数过,但我想柯克大概是每天 200 个左右。

这样手动做了一天左右,我烦得要命。我决定我需要一种不同的方法。事实上,我的追随者增加了一个,这无助于我的动力。

十二岁

Photo by Safar Safarov on Unsplash

我在 Twitter 上的活动是令人麻木的重复。从柯克的所作所为来看,他也不像是在阅读他发布的所有内容。每当一件事被反复做的时候,它通常是自动化的首选。我找到了用于访问 Twitter API 的 Python 库 tweepy 。文档看起来很干净,代码维护得很好。我想试试这个。

资格证书

设置身份验证和获取凭证非常简单:

  1. 前往 Twitter 开发者页面
  2. 使用您的 Twitter 帐户登录
  3. 创建一个应用程序并获取凭证(在密钥和令牌下,见红色圆圈)

Steps to create a Twitter app

机器人的结构

我在 Jupyter 笔记本上用一个简单的 API 调用测试了凭证,一切看起来都很好。现在是时候让它更上一层楼了。我的机器人应该做两件事:

  • 产生追随者
  • 广告媒体文章

产生追随者

从几年前的一次 Instagram 机器人实验中,我知道了实现我第一个目标的确切方法。这相对来说是不道德的,因为它迎合了人们渴望被喜欢和被认可的心理。这是最假的了。不过话说回来,这是 Twitter。另外,我认为有必要谈谈这些做法。展示它们是如何工作的至关重要。关键是要表明它们每天都在以更大的规模被使用。

工作方式—给予员工认可和关注:

  1. 与用户互动(点赞、转发、评论他们的推文并关注他们)
  2. 等待和观察
  3. 看着他们跟着你回来
  4. 再等一段时间,然后放开他们

所以抛开所有的道德因素,让我们把这个编码起来。

①与用户互动

在我的项目中,我倾向于使用配置模块作为配置设置的抽象层。

bots.config

配置如下所示:

production.yml

然后,我们可以设置一个模块来提供 Twitter API,如下所示:

bots.twitter_api

下面这段代码包含交互逻辑。

bot.fetchfollow

我们从两个全大写的变量开始,COMMENTSHASHTAG_SETS这两个变量稍后会被引用,给定内容和名称,用法是相当明显的。COMMENTS列表保存了一些通用的正面评论,HASHTAG_SETS保存了一个用于搜索的不同标签组合的列表。

主要功能是fetchfollow,它执行以下操作:

  • 使用从HASHTAG_SETS设置的随机标签来搜索推文。
  • 获得这些推文背后的独特用户。根据关注者的数量(越少越好)、关注者与关注者的比率(越低越好)和帐户的年龄(越新越好)对用户进行评分,并根据分数对他们进行排序,最高(即最有可能再次关注)在前,最低在后。
  • 从 s3 中获取following_history,该文件包含用户被关注的日期(以及后来被取消关注的日期)。
  • 从最高分到最低分与不在following_history中的用户互动(每次最多 10 分,我们毕竟不想触发机器人警报)。互动意味着给包含我们标签的用户推文打分,然后随机点赞、评论和转发
  • 将用户添加到following_history并更新到 s3。毕竟,我们不想再跟着他们了。

②等待观察

这个阶段比较搞笑。这个阶段是你把你的机器人放到野外并观察结果的时候。有时带着娱乐,有时带着困惑。当我试验 Instagram 机器人的时候,我很快发现 Instagram 上有相当多的色情内容。但那是以后的事了。

在部署了第一个版本的 Twitter 机器人之后,我学到了三件事:

我不得不调整我搜索推文的方式,因为我最初只搜索 Python。

Snakes are scary

我不得不调整机器人运行的频率,使其行为不那么确定。这个机器人的第一个版本很快就被屏蔽了,因为我像喝了一杯能量饮料后冰河时代的松鼠一样被机枪评论和传播。

The first app got restricted to read access only after having commented a little too much

然而,这一次创建一个新的应用程序并采取更加谨慎的方法是相当容易的。

ⓒ:推特上有很多机器人。我得到了回应,“嘿,谢谢你关注我。检查我正在使用的这个伟大的服务: https://xxxbots。 xx”相当经常。向他们致敬。他们运用了一种聪明的病毒式营销方法。

Bots responding to my bot and the list goes on

③看着他们跟着你回来

在过去的四周里,我的 Twitter 账户已经积累了大约 600 名粉丝,除了偶尔在中型帖子列表中添加一个新条目之外,我什么也没做。

④等待一段时间,然后放开他们

因为你不想让你关注的人数过多,所以你必须时不时地取消关注以保持平衡。

bots.unfollow

unfollow 函数在执行时,获取之前上传的following_history,并按照日期升序对所有未被取消关注的进行排序。对于第一个一到三个用户,它将调用destroy_friendship(调用 unfollow)。如果你问我,我觉得这个名字很合适。它将更新following_history,然后准备好被再次调用。

广告媒体文章

这一部分是直截了当的,它的道德性肯定没有那么多问题。

bots.post

这个脚本从参考列表中随机发布了一篇文章。参考列表如下所示:

Sample posts

部署

Photo by elCarito on Unsplash

我使用无服务器框架,利用 Lambda 函数和预定义的时间表(在 serverless.yml 中指定)将机器人部署到 AWS

serverless.yml

安装非常简单,但是解释无服务器将是另一篇文章。更新机器人需要我对脚本做一些修改,然后运行serverless deploy

结束语

我会让这个机器人多运行一段时间,这样阅读这篇文章的人就可以有一个实时参考。不过,我最终会关闭它。

如果你想聊天,请在 LinkedIn 上连接!我很乐意和你谈谈,或者回答你可能有的任何问题。

看看我在 Medium 上写的其他文章,如果你喜欢这篇文章,请留下一两个掌声。

面向数据科学家的 Twitter 机器人

原文:https://towardsdatascience.com/twitter-bot-for-data-scientists-8f4242c4d876?source=collection_archive---------12-----------------------

有没有想过如何创建你的@Getvideobot @threadreaderapp 之类的东西

Photo by AbsolutVision on Unsplash

Twitter 是使用最广泛的社交平台之一。它被个人和组织使用。对于那些其信息(数据)驱动其生活和工作的人来说,它是一个巨大的信息库。

twitter API 的存在为平台上共享和提供的信息提供了无限的创造性访问,因此,不同的 twitter bot 被创建用于不同的目的,它帮助 twitter 成为一个更好的平台。

这些机器人的使用不仅仅使 twitter 平台变得有趣,它还可以作为数据科学家众包数据的一种手段。

在本文中,我们将学习如何为您的数据科学项目创建不同的 twitter bot 来众包数据,例如如何:

  1. 通过监控特定关键字下载图像和视频。
  2. 通过在推文中引用来下载媒体数据。
  3. 收集被监控用户的推文。
  4. 将 twitter 线程展开到文本文件中。
  5. 在 aws s3 中存储数据集合。

这些不同的过程可以帮助众包数据,不仅用于 NLP,还用于计算机视觉(因为大多数人认为 twitter 最适合收集自然语言处理的数据)。

在本文中,我将假设您拥有 Twitter API 认证证书,并且知道如何使用 Tweepy。如果没有,请查看下面的参考资料,了解如何获得 twitter API 证书以及如何安装 tweepy,并获得一些关于它的介绍。但是我建议您先阅读这篇文章,只是为了获得应用程序视图,然后再回到参考资料。

如果您有 twitter API 凭证,那么要做的第一件事就是创建一个配置文件,用 twitter API 设置您的身份验证。

调用该函数有助于检查身份验证是否有效。您可以直接用 api 密钥替换os.getenv(),或者将 api 密钥存储在您的environment中。wait_on_rate_limitwait_on_rate_limit_notify帮助 tweepy 等待,并在超过速率限制时打印出一条消息。

通过监控特定关键字下载媒体数据

数据收集是每个数据驱动项目的基础。收集的数据类型取决于正在进行的项目类型。例如,对于一个计算机视觉项目,它需要图像或视频。Twitter 可以作为一个平台,以不同的方式收集这些数据。其中一种方法是监控与项目所需数据类型相关的一组特定关键字。

比方说,你想策划或收集涉及特朗普的数据,可以创建一个 twitter 机器人来始终收听提到特朗普的每条推文。

监控机器人是使用 tweepy 接口的 Twitter Stream service api 创建的。这有助于机器人在 Twitter 平台上持续收听不同的推文。Monitor 类继承自tweepy.StreamListener,它包含两个方法;on_status这有助于传入推文,并对传入的推文做我们想做的任何事情,并且on_error提供了可操作点,以防在on_status过程中遇到错误。

on_status传入的 tweet 包含了每条 tweet 的 JSON 属性。因为在这个例子中我们需要媒体数据。tweet 的 json 元素包含将被称为entities的内容,实体包含媒体文件和 tweet 中嵌入的 url。例如

{u'hashtags': [{u'indices': [0, 12], u'text': u'NeurIPS2019'}],
 u'media': [{u'display_url': u'pic.twitter.com/GjpvEte86u',
   u'expanded_url': u'https://twitter.com/doomie/status/1206025007261876226/photo/1',
   u'features': {u'large': {u'faces': []},
    u'medium': {u'faces': []},
    u'orig': {u'faces': []},
    u'small': {u'faces': []}},
   u'id': 1206024997262618626,
   u'id_str': u'1206024997262618626',
   u'indices': [278, 301],
   u'media_url': u'http://pbs.twimg.com/media/ELypWGAUcAIpNTu.jpg',
   u'media_url_https': u'https://pbs.twimg.com/media/ELypWGAUcAIpNTu.jpg',
   u'sizes': {u'large': {u'h': 1536, u'resize': u'fit', u'w': 2048},
    u'medium': {u'h': 900, u'resize': u'fit', u'w': 1200},
    u'small': {u'h': 510, u'resize': u'fit', u'w': 680},
    u'thumb': {u'h': 150, u'resize': u'crop', u'w': 150}},
   u'type': u'photo',
   u'url': u'https://t.co/GjpvEte86u'}],
 u'symbols': [],
 u'urls': [],
 u'user_mentions': []}

tweet.entities包含该键和值项。因为我们需要媒体文件。对于图像文件,media_url将用于下载 tweet 中的图像。对于推文中上传的视频,将使用expanded_url下载;对于通过 url 嵌入的视频,如 youtube 视频。将从urls中提取,但是在这个 tweet 中,它不包含 URL,这就是为什么数组是空的。但是对于包含 url 的 tweet

{ ....
  u'urls': [{...,u'expanded_url':'youtube.com?...}]

因此,在urls[0]['expanded_url']中通过解析下载视频。

已经创建了各种 python 库或模块来简化图像和视频的下载。为了下载图像,使用了一个名为 wget 的 python 包。对于 youtube 视频下载,使用 pytube ,对于 twitter 视频,使用 twitter_dl 。所有这些库都是很棒的库,它们使得构建这个项目更加容易。但是对于 twitter-dl 和 pytube,由于我遇到的错误,我对它们做了一些修改,但是我认为新的更新应该可以解决这个问题。所以如果你遇到任何错误,你可以检查我的 github 下载它们。

为了下载这些媒体文件,我们将这些库合并成一个文件

现在我们可以将它与 Monitor.py 结合起来,开始下载媒体文件

当被推文引用时下载媒体文件

有时,我们可以让其他人在 twitter 上帮助我们众包数据,而不是试图监控一个特定的关键词。这种方法包括让人们在包含你想要的数据的推特下引用你的推特名字。这一过程与监控过程类似,只是我们不会使用流式 api,并且它不会监听所有推文,除了您在中提到的那条推文。

refrenced to a tweet.

提及功能利用api.mention,获取你被提及的所有 tweet。为了防止api.Cursor获取你被提到的所有推文,从你加入 twitter 开始,我们使用since_id。以确保它不断获取你被提到的新推文。首先,我们得到你最后一次提到的 tweet 的 id。

tweety = []
for tweet in tweepy.Cursor(api.mentions_timeline).items():
    if len(tweety) > 1:
        break
    else:
        tweety.append(tweet)

因为推文是基于新创建的推文获取的。我们只需要这个,然后我们索引tweety来获得 tweet 的 id。

tweety[0].idoutput[]:
1208298926627074049

在上述代码面板的mention()中,我们使用了max(tweet.id,new_since_id) ,因为对于每个新的 tweet,id 总是大于它之前的 tweet id。也就是说,新的推文 id 高于旧的推文 id。

不要忘记,收集的tweet不仅仅是文本,还有 json 元素,包含 tweet 属性。对于这个机器人,你会通过评论区被引用到一条推文。你想要的主要内容在用户通过评论引用你的推文中。所以用户在回复一条推文。

在 tweet json 元素中,可以提取用户回复的 tweet 的 id。我们把这个 id 叫做in_reply_to_status_id。当用户没有回复推文时,id 通常是None。为了创建 bot,我们首先检查回复状态 id 是否不是 None,然后我们处理 tweet。然后我们从状态 id 中获取 tweet,使用

status_id = tweet.in_reply_to_status_id                                   tweet_u = api.get_status(status_id,tweet_mode='extended')

然后,您现在可以打印出推文中包含的文本。

在这个基本过程之后,如果需要媒体文件,剩下的过程类似于 Monitor bot 的过程。对于上面的代码,我们可以将文本存储在数据库中。创建另一个名为 popular know hasUnrollthread的机器人仍然需要这样一个过程,这将在本文结束之前讨论。

下载媒体数据

收集被监控用户的推文

可以创建一个 Twitter bot 来始终跟踪来自特定用户集的 twitter feeds,这可以帮助管理数据以创建基于特定数据的语言模型,并用于各种 NLP 数据分析。回顾一下最初创建的特定于 Monitor 的关键字 bot,但是在这个过程中,我们使用用户 id 来订阅用户,而不是订阅关键字。

在代码中,我指定了用户 id,这个用户 id 可以通过;例如

api.get_user("[@_mytwtbot](http://twitter.com/_mytwtbot)").id #specify the user screen name you want//1138739106031308800

因此,你将总是第一个获得这个用户创建的推文。

将 Twitter 线程展开成文本文件

你在 twitter 上听说过展开的线程机器人,它总是创建一个 pdf 格式的线程。我们将创造这样的机会。这也有助于为您的数据科学项目收集数据。这个过程仍然与提及机器人相同。它利用回复状态 id,并使用一个recursive函数来获取一个线程中的所有 tweets。

存储 AWS s3 中收集的数据

既然我们已经有了不同的方法来收集数据,我们需要能够存储它们。如果您没有在线存储服务,Aws s3 提供了一种快速简便的在线存储媒体文件的方法。

首先,安装 aws sdk,它是通过 python 库 boto3 提供的

pip install boto3

然后,为了让 boto3 工作并连接到您的 aws 资源,您需要通过创建一个iam用户权限来获得 aws 凭证,然后可以将凭证存储在您的计算机主目录中

touch ~/.aws/credentials

然后在凭证中,我们存储必要的信息

[default]
aws_access_key_id = YOUR_ACCESS_KEY_ID
aws_secret_access_key = YOUR_SECRET_ACCESS_KEY

现在获取访问密钥;

首先,访问 aws 控制台并进入 iam 资源

Step by step process of creating iam on aws.

按照图片从左到右的排列顺序在 aws 上设置 iam。完成后,你可以下载如上图所示的 csv 文件,复制其中的凭证并粘贴到~/.aws/credentials

完成后,我们继续在 aws S3 创建一个存储桶。

点击create bucket创建一个存储桶来存储您的文件。

然后指定名称,你想要的地区,然后点击create,这样你的桶就创建好了。

既然创建了 bucket,我们就可以使用 boto3 调用它:

import boto3s3 = boto3.client("s3")
s3.upload_file(path,"bucket_name","name_to_store_file")

这是我们将用来在 s3 上存储文件的基本函数。upload_file 方法接受要上传的文件的路径,例如/home/documents/bot/video . MP4,而bucket_name是您创建的 bucket 的名称,那么第三个参数是您想要在 s3 上存储文件的名称。

因此,只要对我们的download_t.py稍加修改,我们就可以将文件保存在 aws s3 上

文件上传后,可以通过点击存储桶进行查看

aws s3 scrrenshot.

现在一切都设置好了,我们现在可以创建 docker 映像,然后部署到 aws。查看下面的参考资料,了解如何部署到 aws。

但是,在您从 reference 链接中学习了如何部署到 aws 之后,只需添加一点东西,即 aws 凭证和环境变量

from realpython.com

此外,为了能够将媒体文件保存到 aws s3

-e aws_access_key_id="sjbkjgkjhfyfyjfyjyfj" \
-e aws_secret_access_key="1124knlkhk45nklhl" \
fav-retweet-bot

现在,作为一名数据科学家,我们已经学会了从 twitter 上收集数据并创建一个机器人的方法。看看这个,了解如何使用深度学习创建 twitter 机器人。

从 github 下载包含代码的回购协议

参考

这篇文章很大程度上依赖于来自 realpython.com的某个团队的工作查看这里学习如何生成 twitter api 以及如何部署到 aws。

使用 Python 的 Twitter 数据收集教程

原文:https://towardsdatascience.com/twitter-data-collection-tutorial-using-python-3267d7cfa93e?source=collection_archive---------0-----------------------

“没有数据,你只是另一个有观点的人”——w·爱德华兹·戴明

Photo by Carlos Muza on Unsplash

在过去的一年里,我在 Twitter 上变得更加活跃,随着互动次数的增加,我需要回答一些基本问题,比如:

  • 我的追随者来自哪里?
  • 我的推文平均有多少赞?
  • 我关注的客户分布情况如何?

所以我认为这可能是一个有趣的编程练习。但是在我进行任何分析之前,我们需要收集所需的数据。

在本教程中,我们将学习如何使用 Twitter 的 API 和一些 Python 库来收集 Twitter 数据。我们将介绍如何设置开发环境、连接 Twitter 的 API 以及收集数据。

对于“只给我看代码”的人来说,这是笔记本:

[## 谷歌联合实验室

编辑描述

colab.research.google.com](https://colab.research.google.com/drive/1cwefy0vNKHjW_XUZeyvKvc0U-no3gKGt#scrollTo=EaGv0ePkydNz)

工具和 Python 库

这是我们将使用的工具清单

  • 用于开发环境的 Google Colab
  • Google Drive 存储数据

它们是免费的,只需一个基本的谷歌账户,将有助于让事情变得简单。

至于 Python 库,下面是我们需要的

  • tweepy 用于使用 Python 访问 Twitter API。
  • google.colab 将 Google Drive 链接到 colab 笔记本
  • json 用于加载和保存json文件
  • csv 用于加载和保存csv文件
  • 日期时间用于处理日期数据
  • 时间为定时代码执行

我们将导入我们需要的所有库,如下所示

**# Import all needed libraries**import tweepy                   **# Python wrapper around Twitter API**
from google.colab import drive  **# to mount Drive to Colab notebook**
import json
import csv
from datetime import date
from datetime import datetime
import time

将 Google Drive 连接到 Colab

要将 Google Drive (存储数据的地方)连接到 Colab 笔记本(处理数据的地方)运行以下命令。

**# Connect Google Drive to Colab** drive.mount('/content/gdrive')**# Create a variable to store the data path on your drive** path = './gdrive/My Drive/path/to/data'

执行上面的代码块将提示您跟随一个 URL 来验证您的帐户,并允许 Google Drive 和 Colab 之间的数据流。只需点击提示,当硬盘安装成功时,您将在笔记本中收到一条消息。

向 Twitter 的 API 认证

首先,申请一个开发者账号访问 API。对于本教程来说,标准 API 已经足够了。它们是免费的,但是有一些限制,我们将在本教程中学习如何解决。

设置好您的开发者账户后,点击右上角的用户名打开下拉菜单,然后点击“应用”,创建一个将使用 API 的应用,如下所示。然后选择“创建应用”,并填写表格。出于本教程的目的,使用 Google Colab 笔记本的 URL 作为应用程序的 URL。

Select “Apps” from the top right corner once you log into your developer account

现在您已经创建了一个开发人员帐户和一个应用程序,您应该有一组连接到 Twitter API 的密钥。具体来说,你会有一个

  • API 密钥
  • API 密钥
  • 访问令牌
  • 访问令牌秘密

这些可以直接插入到您的代码中,或者从外部文件加载以连接到 Twitter API,如下所示。

**# Load Twitter API secrets from an external JSON file** secrets = json.loads(open(path + 'secrets.json').read())
api_key = secrets['api_key']
api_secret_key = secrets['api_secret_key']
access_token = secrets['access_token']
access_token_secret = secrets['access_token_secret']**# Connect to Twitter API using the secrets** auth = tweepy.OAuthHandler(api_key, api_secret_key)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

Twitter 数据收集

概观

我们将创建函数来收集

  • Tweets: 这也包括转发,以及作为 Tweet 对象收集的回复。
  • 关注者:作为用户对象收集的所有关注者信息。
  • 关注:我关注的所有账户的信息(又名好友)收集为用户对象。
  • 今日统计:当日跟随者及跟随者统计。

此外,我们将创建两个助手函数来简化我们的工作

  • 保存 JSON: 将收集到的数据保存在 Google Drive 上的json文件中
  • 速率限制处理:管理免费版本附带的 Twitter API 限制,主要是 15 分钟内允许的 API 调用数量。

助手功能

保存 JSON

**# Helper function to save data into a JSON file
# file_name: the file name of the data on Google Drive
# file_content: the data you want to save**def save_json(file_name, file_content):
  with open(path + file_name, 'w', encoding='utf-8') as f:
    json.dump(file_content, f, ensure_ascii=False, indent=4)

费率限额处理

**# Helper function to handle twitter API rate limit**def limit_handled(cursor, list_name):
  while True:
    try:
      yield cursor.next() **# Catch Twitter API rate limit exception and wait for 15 minutes**
    except tweepy.RateLimitError:
      print("\nData points in list = {}".format(len(list_name))))
      print('Hit Twitter API rate limit.')
      for i in range(3, 0, -1):
        print("Wait for {} mins.".format(i * 5))
        time.sleep(5 * 60) **# Catch any other Twitter API exceptions**
    except tweepy.error.TweepError:
      print('\nCaught TweepError exception' )

为了解开这段代码,让我们从定义什么是光标开始。下面是来自 Tweepy 文档的介绍:

我们在 Twitter API 开发中大量使用分页。遍历时间表、用户列表、直接消息等。为了执行分页,我们必须为每个请求提供一个 page/cursor 参数。这里的问题是这需要大量的 boiler plate 代码来管理分页循环。为了使分页更容易,需要更少的代码,Tweepy 有了光标对象。

我的解释是,Cursor 对象是 Tweepy 管理和传递跨多页数据的方式,就像您最喜欢的书的内容分布在多页上一样。

记住这一点,上面的函数首先请求下一个数据指针(或页面)。如果在过去 15 分钟内收集的数据量超过了 API 限制,就会引发一个tweepy.RateLimitError异常,在这种情况下,代码将等待 15 分钟。最后一个异常是为了捕捉执行过程中可能出现的任何其他tweepy.error.TweepError,比如 Twitter API 的连接错误。

数据收集功能

推文

我们将重用 Github 上稍加修改的实现

**# Helper function to get all tweets of a specified user
# NOTE:This method only allows access to the most recent 3200 tweets
# Source:** [**https://gist.github.com/yanofsky/5436496**](https://gist.github.com/yanofsky/5436496)def get_all_tweets(screen_name): **# initialize a list to hold all the Tweets**
  alltweets = [] **# make initial request for most recent tweets 
  # (200 is the maximum allowed count)** new_tweets = api.user_timeline(screen_name = screen_name,count=200) **# save most recent tweets**
  alltweets.extend(new_tweets) **# save the id of the oldest tweet less one to avoid duplication**
  oldest = alltweets[-1].id - 1 **# keep grabbing tweets until there are no tweets left**
  while len(new_tweets) > 0:
    print("getting tweets before %s" % (oldest)) **# all subsequent requests use the max_id param to prevent
    # duplicates**
    new_tweets = api.user_timeline(screen_name = screen_name,count=200,max_id=oldest) **# save most recent tweets**
    alltweets.extend(new_tweets) **# update the id of the oldest tweet less one**
    oldest = alltweets[-1].id - 1
    print("...%s tweets downloaded so far" % (len(alltweets)))
 **### END OF WHILE LOOP ###** **# transform the tweepy tweets into a 2D array that will 
  # populate the csv** outtweets = [[tweet.id_str, tweet.created_at, tweet.text, tweet.favorite_count,tweet.in_reply_to_screen_name, tweet.retweeted] for tweet in alltweets] **#** **write the csv**
  with open(path + '%s_tweets.csv' % screen_name, 'w') as f:
    writer = csv.writer(f)
    writer.writerow(["id","created_at","text","likes","in reply to","retweeted"])
    writer.writerows(outtweets)
  pass

上面的代码块基本上由两部分组成:一个 while 循环用于收集列表中的所有 tweet,以及一些命令用于将 tweet 保存到一个csv文件中。

在我们解释 while 循环中发生了什么之前,让我们先了解一下使用的两个关键方法

  • api.user_timeline([,count][,max_id])返回指定用户最近的推文。count参数指定了我们希望一次检索的推文数量,最多 200 条。max_id参数告诉该方法只返回 ID 小于(即早于)或等于指定 ID 的 tweets。
  • list.extend(*iterable*)*iterable* 中的所有项目添加到列表中,不像append只将单个元素添加到列表的末尾。

现在,让我们分析一下 while 循环中发生了什么

  1. 这里有三个变量:alltweets是一个存储所有收集的 tweet 的列表,new_tweets是一个存储最新一批收集的 tweet 的列表,因为我们一次只能检索 200 条 tweet,而oldest存储我们迄今检索的最早的 tweet 的 ID,所以下一批检索的 tweet 在它之前。
  2. 变量在循环开始前被初始化。注意,如果指定的用户没有任何 tweets,new_tweets将为空,循环将不会执行。
  3. 在每次迭代中,检索在oldest之前发布的 200 条推文的新列表,并将其添加到alltweets
  4. while 循环将继续迭代,直到在oldest之前没有找到 tweet,或者达到 3200 条 tweet 的限制。

现在,为了将 tweet 数据写入一个csv文件,我们首先从每条 tweet 中提取我们关心的信息。这是通过使用一个列表理解来完成的,在这个列表中,我们将 tweet ID、文本和赞数等信息捕获到一个名为outtweets的新列表中。最后,我们打开一个CSV文件,首先用我们的表的标题名写一行,然后在下面的行中写outtweets中的所有数据。

追随者

**# Function to save follower objects in a JSON file.**def get_followers():
 **# Create a list to store follower data** followers_list = [] **# For-loop to iterate over tweepy cursors** cursor = tweepy.Cursor(api.followers, count=200).pages()for i, page in enumerate(limit_handled(cursor, followers_list)):  
    print("\r"+"Loading"+ i % 5 *".", end='')

    **# Add latest batch of follower data to the list**
    followers_list += page

 **# Extract the follower information**
  followers_list = [x._json for x in followers_list] **# Save the data in a JSON file**
  save_json('followers_data.json', followers_list)

如您所见,我们使用了上面创建的助手函数。此外,tweepy.Cursor(api.followers, count=200).pages()创建一个 Cursor 对象,一次返回 200 个关注者的数据。我们现在可以将这个光标和followers_list一起传递给我们的limited_handled函数。注意,检索到的用户对象包含两个键_api_json,因此我们只需使用 List comprehension [x._json for x in followers_list]提取我们关心的数据。

跟随

**# Function to save friend objects in a JSON file.**def get_friends():
 **# Create a list to store friends data** friends_list = [] **# For-loop to iterate over tweepy cursors** cursor = tweepy.Cursor(api.friends, count=200).pages()for i, page in enumerate(limit_handled(cursor, friends_list)):  
    print("\r"+"Loading"+ i % 5 *".", end='')

    **# Add latest batch of friend data to the list**
    friends_list += page

 **# Extract the friends information**
  friends_list = [x._json for x in friends_list] **# Save the data in a JSON file**
  save_json('friends_data.json', friends_list)

您可以看到,这与我们的get_followers()函数完全一样,只是我们使用api.friends来定义我们的光标对象,因此我们可以检索我们所关注的用户的数据。

今天的统计数据

**# Function to save daily follower and following counts in a JSON file**def todays_stats(dict_name): **# Get my account information**
  info = api.me() **# Get follower and following counts**
  followers_cnt = info.followers_count  
  following_cnt = info.friends_count **# Get today's date**
  today = date.today()
  d = today.strftime("%b %d, %Y") **# Save today's stats only if they haven't been collected before**
  if d not in dict_name:
    dict_name[d] = {"followers":followers_cnt, "following":following_cnt}
    save_json("follower_history.json", dict_name)
  else:
    print('Today\'s stats already exist')

api.me()返回认证用户的信息,在本例中是我。从那里,收集追随者和以下计数是简单的。我指定的日期格式%b %d, %Y将以类似于2019 年 11 月 11 日、的格式返回日期。有许多格式可供选择。

结束语

我希望你喜欢这篇介绍 Twitter 数据收集的教程。写这篇文章对澄清我对自己代码的理解很有帮助。例如,我更好地理解了 tweepy 光标对象。这让我想起了那句名言

如果你想学什么,就去教它

我一直在寻找提高写作的方法,所以如果你有任何反馈或想法,请随时分享。感谢阅读!

Twitter Pulse Checker:Twitter 上用于数据科学的交互式 Colab 笔记本

原文:https://towardsdatascience.com/twitter-pulse-checker-an-interactive-colab-notebook-for-data-sciencing-on-twitter-76a27ec8526f?source=collection_archive---------14-----------------------

What’s popping in Seattle? Original background image: http://clipart-library.com/clipart/2099977.htm

想用 Twitter 数据进行奇特的数据科学研究吗?

我创建了一个交互式的 Google Colab,它可以带你浏览一个选定主题的端到端趋势分析。

Colab 是一个很棒的(也很少被使用的)工具,它的表单功能可以让你创建一个很棒的类似于应用程序的 UX 体验,同时提供了深入挖掘底层代码的选项。

我在笔记本中使用西雅图作为我的例子,但是它被设置用于任何主题。你可以搜集 twitter 数据,解析标签(NER),进行情感分析,用情节和文字云将所有好东西可视化。

要直接进入实验室,请点击这里:https://lnkd.in/ghKzQV4

概观

这是一种快速而肮脏的方式来了解 Twitter 上与特定主题相关的趋势。对于我的用例,我关注的是西雅图市,但是您可以很容易地将它应用于任何主题。

笔记本中的代码执行以下操作:

*抓取与你感兴趣的话题相关的推文。
*从文本中提取相关标签(NER:命名实体识别)。
*对这些推文进行情感分析。
*以互动的形式提供了一些可视化效果,以获得正在发生的事情的“脉搏”。

我们使用 Tweepy 收集 Twitter 数据,使用 Flair 进行 NER /情绪分析。我们使用 Seaborn 进行可视化,所有这一切都是可能的,因为有了精彩、免费和快速(使用 GPU)的 Google Colab。

关于 NER 的一点信息

这是从文本中提取标签的过程。

所以,举个例句:‘乔治·华盛顿去了华盛顿’。NER 将允许我们提取标签,如“乔治华盛顿的人”和“华盛顿(州)”的位置。它是 NLP 中最常见和最有用的应用之一,使用它,我们可以从推文中提取标签并对它们进行分析。

关于情感分析的一点看法

最常见的是,这是一个判断某个文本是正面还是负面的过程。更普遍的是,你可以把它应用到你选择的任何标签上(垃圾邮件/非垃圾邮件等等。).

因此,“我讨厌这部电影”将被归类为负面陈述,而“我喜欢这部电影”将被归类为正面陈述。同样,这是一个非常有用的应用程序,因为它让我们能够了解人们对某些事情的看法(Twitter 话题、电影评论等)。

要了解这些应用程序的更多信息,请查看 Flair Github 主页和教程:https://github.com/zalandoresearch/flair

使用

你显然需要一个谷歌账户才能使用 Colab。您可以通过点击顶部的“在操场上打开”选项来编辑笔记本。我建议在继续之前,将它作为你自己的副本保存在你的 Google Drive 中。

Open in Playground mode and then Save in your drive

快速提示:运行单元格的快捷方式是按键盘上的 SHIFT+ENTER。这是很方便的,因为你要穿过很多单元格。

你也应该去笔记本电脑设置,并确保选择了 GPU,因为只有一个 CPU 的刮/分析会变得非常慢。

GPU should be selected

你需要 Twitter API 密匙(当然还有一个 Twitter 账户)来实现这个功能。在这里报名就能拿到:【https://developer.twitter.com/en/apps

一旦有了 API 密钥和 API 秘密密钥,就可以将这些凭证输入到身份验证单元中,并运行整个笔记本。

Enter your Twitter API Keys here

获取数据

一旦通过认证,您就可以开始刮!输入您感兴趣的搜索词和要推送的推文。我们每 15 分钟最多可以使用 API 抓取 45,000 条推文,因此滑块允许您选择这个限制。

您可以选择是否要过滤掉转发。我选择过滤掉它们,专注于原始推文。

一旦我们收集了推文,我们就把它们加载到熊猫的数据框架中。在这里,我们做一些切片和切块,为一些视觉效果做好准备。

NER 和情感分析

我们使用 NER 提取相关标签:人、组织、位置等。

因为 Flair 不具备处理标签的能力,所以我们为它们创建了一个自定义标签。

最后,我们创建了一个数据框架,其中我们将所有标签按照它们的流行度、喜欢、回复、转发指标进行分组。

我们还计算这些标签的平均极性(情感得分)。

视觉化!

我们为最受欢迎的、喜欢的、回复的、转发的标签创建一些基本的情节。我们也用感情来切割这个。

What’s hot in Seattle today?

该单元格设置为允许您按标签过滤。

我们可以选中 Filter_TAG 框,然后选择我们想要度量的标记。然后,我们简单地重新运行单元以获得刷新的图。

词云

我承认我花了太多的时间来设置背景蒙版,但是它看起来很酷!

你可以选择你所选择的面具(如果你喜欢马或者出于某种原因做马的分析,就选一匹马…)。

我选择了西雅图,并用这个掩码生成了一个单词云(如顶部的第一幅图所示)。

希望这能给你的数据项目一个好的开始。Colab 设置为以最少的输入运行,但是如果您想深入研究并根据您的需要定制它,代码就在那里。这就是笔记本的魅力。

你可以从这里开始玩笔记本:【https://lnkd.in/ghKzQV4】T4

使用 NLTK、Python 的 Twitter 情感分析

原文:https://towardsdatascience.com/twitter-sentiment-analysis-classification-using-nltk-python-fa912578614c?source=collection_archive---------2-----------------------

自然语言处理(NLP)是机器学习的一个独特子集,它关注现实生活中的非结构化数据。尽管计算机不能识别和处理字符串输入,但是 NLTK、TextBlob 和许多其他库找到了一种用数学方法处理字符串的方法。Twitter 是一个平台,大多数人在这里表达他们对当前环境的感受。作为人类,我们可以猜测一个句子的情绪是积极的还是消极的。同样,在本文中,我将向您展示如何使用 python 和 NLP 库来训练和开发一个简单的 Twitter 情感分析监督学习模型。

让我们从导入这个项目所需的库开始。

由于这是一个监督学习任务,我们得到了一个由标有“1”或“0”的推文组成的训练数据集和一个没有标签的测试数据集。训练和测试数据集可以在这里找到。

  • 标签“0”:积极情绪
  • 标签“1”:消极情绪

现在我们用熊猫来读数据。

train_tweets = pd.read_csv('train_tweets.csv')
test_tweets = pd.read_csv('test_tweets.csv')

探索性数据分析

无论在哪个领域,对机器学习问题进行数据分析都是必要的。让我们做一些分析,以获得一些见解。

sns.barplot('label','length',data = train_tweets,palette='PRGn')

sns.countplot(x= 'label',data = train_tweets)

上面两张图告诉我们,给定的数据是不平衡的,只有很少数量的“1”标签,推文的长度在分类中没有起主要作用。处理不平衡数据是一个单独的部分,我们将尝试为现有的数据集生成一个最佳模型。

数据预处理和特征工程

给定的数据集由非常多的非结构化 tweets 组成,应该对其进行预处理以建立 NLP 模型。在这个项目中,我们尝试了以下预处理原始数据的技术。但是预处理技术不受限制。

  • 删除标点符号。
  • 删除常用词(停用词)。
  • 文字规范化。

标点符号在 NLP 中总是一个干扰,特别是标签和“@”在 tweets 中扮演主要角色。TextBlob 从句子中提取单词的功能可以在最佳水平上删除标点符号。遗漏的标点符号和其他不常见的符号将在即将到来的预处理技术中删除。

在 NLP 任务中,停用词(最常见的词,例如:is,are,have)在学习中没有意义,因为它们与情感没有联系。因此,去除它们既节省了计算能力,又提高了模型的准确性。

所有不常见的符号和数值都被删除,并返回一个包含单词的纯列表,如上所示。但是我们仍然会遇到同一个词的多种表达。(例如:play,plays,played,playing)尽管单词不同,但它们给我们带来的意思和正常单词“play”一样。所以我们需要做词汇规范化的方法来解决这个问题。NLTK 内置的 WordNetLemmatizer 就做到了这一点。

现在我们已经完成了我们的文本预处理部分,我们将进入矢量化和模型选择。

矢量化和模型选择

在让我们的数据训练之前,我们必须用数字表示预处理过的数据。自然语言处理中比较著名的单词矢量化技术有:CountVectorization 和 Tf-IDF 变换。让我们深入了解一下这些矢量化技术的理论背景。

计数矢量化生成一个代表文档中所有单词的稀疏矩阵。计数矢量化的演示如下所示:

Demonstration of Count Vectorization

  • Tf(d,t) (术语频率)定义为术语 t 在文档 d 中的出现次数。
  • Idf(t) (频率的逆文档)定义为 log(D/t),其中 D:文档总数,t:带项的文档数。

Tf-Idf transformer 做的是返回 TfIdf 的乘积,也就是该项的 Tf-Idf 权重。

因此,我们现在已经将我们的 sting 数据矢量化为数值,以便将其输入到机器学习算法中。我们选择朴素贝叶斯分类器进行二进制分类,因为它是 NLP 中最常用的算法。此外,我们使用 scikit-learn 内置的机器学习流水线技术来预定义算法的工作流程。这节省了大量时间和计算能力。

模型验证

因为我们决定选择自然语言处理技术,所以在应用于测试数据集之前,我们必须用现有的训练数据集来验证它。我们将使用传统的 train_test_split 技术来分割测试大小为 0.2 的训练数据集,并让我们的管道模型在分割的数据集上得到验证。一旦我们对验证的准确性感到满意,我们就可以将获得的模型应用于测试数据集。使用 scikit-learn、混淆矩阵和分类报告的内置功能来测量准确度。

Output of the above code

对于我们的简单管道模型,获得了 0.93837 的精度。请注意,通过使用 GridSearchCV 和其他预处理技术调整参数,有机会提高这种准确性。

希望这篇文章给你一个用 NLTK 和 Python 进行情感分析的基本概念。此处提供了该项目的完整笔记本。

下面是一些有用的链接,可以帮助我们开始使用我们在这个项目中使用的自然语言处理库:

  • NLTK 书籍:分析文本的完整指南
  • 文本斑点处理
  • 在 scikit 中处理文本数据-学习
  • monkey learn 的情感分析指南

使用 fastText 的 Twitter 情感分析

原文:https://towardsdatascience.com/twitter-sentiment-analysis-using-fasttext-9ccd04465597?source=collection_archive---------6-----------------------

在这篇博客中,我们将使用一个快速文本库来分析各种推文的情绪,该库易于使用和快速训练。

Twitter sentiment analysis

什么是 fastText?

FastText 是由脸书人工智能开发的自然语言处理库。这是一个开源、免费、轻量级的库,允许用户学习文本表示和文本分类器。它在标准的通用硬件上工作。模型可以缩小尺寸,甚至适合移动设备。

为什么选择 fastText?

深度神经网络模型的主要缺点是它们需要大量的时间来训练和测试。在这里,fastText 有一个优势,因为它只需要很少的时间来训练,并且可以在我们的家用电脑上高速训练。

根据 fastText 上的脸书人工智能博客的说法,这个库的准确性与深度神经网络相当,并且只需要很少的时间来训练。

comparison between fastText and other deep learning based models

现在,我们知道了 fastText 以及我们为什么使用它,我们将看到如何使用这个库进行情感分析。

获取数据集

我们将使用 betsentiment.com 的上可用的数据集。推文有四个标签,分别是正值、负值、中性和混合型。我们会忽略所有带有混合标签的推文。

我们将使用团队 tweet 数据集作为训练集,而球员数据集作为验证集。

清洗数据集

正如我们所知,在训练任何模型之前,我们需要清理数据,在这里也是如此。

我们将根据这些规则清理推文:

  1. 移除所有标签,因为标签不会影响情绪。
  2. 删除提及,因为它们在情感分析中也不重要。
  3. 将任何表情符号替换为它们所代表的文本,作为表情符号或表情符号在代表一种情绪方面发挥着重要作用。
  4. 用完整的形式代替收缩。
  5. 删除推文中出现的任何 URL,因为它们在情感分析中并不重要。
  6. 删除标点符号。
  7. 修复拼写错误的单词(非常基础,因为这是一个非常耗时的步骤)。
  8. 将所有内容转换为小写。
  9. 删除 HTML 标签(如果有)。

清理推文的规则:

我们将清理这条推文

tweet = '<html> bayer leverkusen goalkeeeeper bernd leno will not be #going to napoli. his agent uli ferber to bild: "I can confirm that there were negotiations with napoli, which we have broken off. napoli is not an option." Atletico madrid and Arsenal are the other strong rumours. #b04 #afc </html>'

删除 HTML 标签

有时 twitter 响应包含 HTML 标签,我们需要删除它。

为此,我们将使用[Beautifulsoup](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) 包。

如果没有 HTML 标签,那么它将返回相同的文本。

tweet = BeautifulSoup(tweet).get_text()#output
'bayer leverkusen goalkeeeeper bernd leno will not be #going to napoli. his agent uli ferber to bild: "I can confirm that there were negotiations with napoli, which we have broken off. napoli is not an option." Atletico madrid and Arsenal are the other strong rumours. #b04 #afc'

我们将使用正则表达式来匹配要删除或要替换的表达式。为此,将使用[re](https://docs.python.org/3/library/re.html) 包。

移除标签

Regex @[A-Za-z0-9]+代表提及次数,#[A-Za-z0-9]+代表标签。我们将用空格替换匹配这个正则表达式的每个单词。

tweet = ' '.join(re.sub("(@[A-Za-z0-9]+)|(#[A-Za-z0-9]+)", " ", tweet).split())#output
'bayer leverkusen goalkeeeeper bernd leno will not be to napoli. his agent uli ferber to bild: "I can confirm that there were negotiations with napoli, which we have broken off. napoli is not an option." Atletico madrid and Arsenal are the other strong rumours.'

删除 URL

Regex \w+:\/\/\S+匹配所有以 http://或 https://开头并用空格替换的 URL。

tweet = ' '.join(re.sub("(\w+:\/\/\S+)", " ", tweet).split())#output
'bayer leverkusen goalkeeeeper bernd leno will not be to napoli. his agent uli ferber to bild: "I can confirm that there were negotiations with napoli, which we have broken off. napoli is not an option." Atletico madrid and Arsenal are the other strong rumours.'

删除标点符号

用空格替换所有标点符号,如.,!?:;-=

tweet = ' '.join(re.sub("[\.\,\!\?\:\;\-\=]", " ", tweet).split())#output 
'bayer leverkusen goalkeeeeper bernd leno will not be napoli his agent uli ferber to bild "I can confirm that there were negotiations with napoli which we have broken off napoli is not an option " Atletico madrid and Arsenal are the other strong rumours'

小写字母盘

为了避免大小写敏感问题

tweet = tweet.lower()#output
'bayer leverkusen goalkeeeeper bernd leno will not be napoli his agent uli ferber to bild "i can confirm that there were negotiations with napoli which we have broken off napoli is not an option " atletico madrid and arsenal are the other strong rumours'

替换收缩

去掉缩写,翻译成合适的俚语。没有通用的列表来代替缩写,所以我们为了自己的目的制作了这个列表。

CONTRACTIONS = {"mayn't":"may not", "may've":"may have",......}tweet = tweet.replace("’","'")
words = tweet.split()
reformed = [CONTRACTIONS[word] if word in CONTRACTIONS else word for word in words]
tweet = " ".join(reformed)#input
'I mayn’t like you.'#output
'I may not like you.'

修复拼写错误的单词

在这里,我们实际上并没有构建任何复杂的函数来纠正拼写错误的单词,而只是检查每个字符在每个单词中出现的次数是否不超过 2 次。这是一个非常基本的拼写错误检查。

tweet = ''.join(''.join(s)[:2] for _, s in itertools.groupby(tweet))#output
'bayer leverkusen goalkeeper bernd leno will not be napoli his agent uli ferber to bild "i can confirm that there were negotiations with napoli which we have broken off napoli is not an option " atletico madrid and arsenal are the other strong rumours'

替换表情符号或表情符号

由于表情符号和表情符号在表达情感方面发挥着重要作用,我们需要用它们在简单英语中所代表的表达方式来取代它们。

对于表情符号,我们将使用emoji包,对于表情符号,我们将建立自己的字典。

SMILEYS = {":‑(":"sad", ":‑)":"smiley", ....}words = tweet.split()
reformed = [SMILEY[word] if word in SMILEY else word for word in words]
tweet = " ".join(reformed)#input 
'I am :-('#output
'I am sad' 

表情符号

表情包返回给定表情的值为:flushed_face:,所以我们需要从给定的输出中删除:

tweet = emoji.demojize(tweet)
tweet = tweet.replace(":"," ")
tweet = ' '.join(tweet.split())#input
'He is 😳'#output
'He is flushed_face'

所以,我们已经清理了我们的数据。

为什么不用 NLTK 停用词?

清除数据时,删除停用词是一种有效的方法。它去掉了所有无关紧要的词,通常是每个句子中最常用的词。获取 NLTK 库中存在的所有停用词

from nltk.corpus import stopwords
stop_words = stopwords.words('english')
print(stop_words)

NLTK stop words

我们可以看到,如果使用 NLTK 停用词,那么所有的负面缩写都将被移除,这在情感分析中起着重要的作用。

格式化数据集

需要格式化 fastText 监督学习所需的数据。

FastText 假设标签是以字符串__label__为前缀的单词。

fastText 模型的输入应该如下所示

__label__NEUTRAL _d i 'm just fine i have your fanbase angry over
__label__POSITIVE what a weekend of football results & hearts

我们可以使用以下方式格式化数据

def transform_instance(row):
    cur_row = []
    #Prefix the index-ed label with __label__
    label = "__label__" + row[4]  
    cur_row.append(label)
    cur_row.extend(nltk.word_tokenize(tweet_cleaning_for_sentiment_analysis(row[2].lower())))
    return cur_rowdef preprocess(input_file, output_file):
    i=0
    with open(output_file, 'w') as csvoutfile:
        csv_writer = csv.writer(csvoutfile, delimiter=' ', lineterminator='\n')
        with open(input_file, 'r', newline='', encoding='latin1') as csvinfile: # encoding='latin1'
            csv_reader = csv.reader(csvinfile, delimiter=',', quotechar='"')
            for row in csv_reader:
                if row[4]!="MIXED" and row[4].upper() in ['POSITIVE','NEGATIVE','NEUTRAL'] and row[2]!='':
                    row_output = transform_instance(row)
                    csv_writer.writerow(row_output )
                    # print(row_output)
                i=i+1
                if i%10000 ==0:
                    print(i)

这里,我们忽略标签不是Positive, Negative and neutral的推文。

nltk.[word_tokenize](https://www.nltk.org/api/nltk.tokenize.html#nltk.tokenize.punkt.PunktLanguageVars.word_tokenize)()将字符串转换成独立的单词。

nltk.word_tokenize('hello world!')#output
['hello', 'world', '!']

对数据集进行上采样

在我们的数据集中,数据并没有被平均划分到不同的标签中。它包含中性标签中大约 72%的数据。因此,我们可以看到,我们的模型往往会被大班淹没,而忽略小班。

import pandas as pd
import seaborn as snsdf = pd.read_csv('betsentiment-EN-tweets-sentiment-teams.csv',encoding='latin1')df['sentiment'].value_counts(normalize=True)*100

percentage of tweets for each labels

sns.countplot(x="sentiment", data=df)

countplot for sentiment labels

由于中性类由数据集的大部分组成,该模型将始终尝试预测中性标签,因为它将保证 72%的准确性。为了防止这种情况,我们需要每个标签有相同数量的推文。我们可以通过向 minor 类添加新的 tweets 来实现这一点。向少数族裔标签添加新推文的过程被称为上采样。

我们将通过一次又一次地重复给定标签中的 tweet 来实现上采样,直到每个标签中 tweet 的数量相等。

def upsampling(input_file, output_file, ratio_upsampling=1):
    # Create a file with equal number of tweets for each label
    #    input_file: path to file
    #    output_file: path to the output file
    #    ratio_upsampling: ratio of each minority classes vs majority one. 1 mean there will be as much of each class than there is for the majority class 

    i=0
    counts = {}
    dict_data_by_label = {}# GET LABEL LIST AND GET DATA PER LABEL
    with open(input_file, 'r', newline='') as csvinfile: 
        csv_reader = csv.reader(csvinfile, delimiter=',', quotechar='"')
        for row in csv_reader:
            counts[row[0].split()[0]] = counts.get(row[0].split()[0], 0) + 1
            if not row[0].split()[0] in dict_data_by_label:
                dict_data_by_label[row[0].split()[0]]=[row[0]]
            else:
                dict_data_by_label[row[0].split()[0]].append(row[0])
            i=i+1
            if i%10000 ==0:
                print("read" + str(i))# FIND MAJORITY CLASS
    majority_class=""
    count_majority_class=0
    for item in dict_data_by_label:
        if len(dict_data_by_label[item])>count_majority_class:
            majority_class= item
            count_majority_class=len(dict_data_by_label[item])  

    # UPSAMPLE MINORITY CLASS
    data_upsampled=[]
    for item in dict_data_by_label:
        data_upsampled.extend(dict_data_by_label[item])
        if item != majority_class:
            items_added=0
            items_to_add = count_majority_class - len(dict_data_by_label[item])
            while items_added<items_to_add:
                data_upsampled.extend(dict_data_by_label[item][:max(0,min(items_to_add-items_added,len(dict_data_by_label[item])))])
                items_added = items_added + max(0,min(items_to_add-items_added,len(dict_data_by_label[item])))# WRITE ALL
    i=0with open(output_file, 'w') as txtoutfile:
        for row in data_upsampled:
            txtoutfile.write(row+ '\n' )
            i=i+1
            if i%10000 ==0:
                print("writer" + str(i))

至于重复推文,一次又一次,可能会导致我们的模型过度适应我们的数据集,但由于我们的数据集很大,这不是一个问题。

培养

尝试用 git 克隆安装 fastText,而不是使用 pip。

我们将使用监督训练法。

hyper_params = {"lr": 0.01,
                "epoch": 20,
                "wordNgrams": 2,
                "dim": 20}     

        print(str(datetime.datetime.now()) + ' START=>' + str(hyper_params) )# Train the model.
        model = fastText.train_supervised(input=training_data_path, **hyper_params)
        print("Model trained with the hyperparameter \n {}".format(hyper_params))

lr代表learning rateepoch代表number of epochwordNgrams代表max length of word Ngramdim代表size of word vectors

train_supervised是用于使用监督学习来训练模型的函数。

评价

我们需要评估这个模型以确定它的准确性。

model_acc_training_set = model.test(training_data_path)
model_acc_validation_set = model.test(validation_data_path)

# DISPLAY ACCURACY OF TRAINED MODEL
text_line = str(hyper_params) + ",accuracy:" + str(model_acc_training_set[1])  + ",validation:" + str(model_acc_validation_set[1]) + '\n' print(text_line)

我们将在训练和验证数据集上评估我们的模型。

test返回模型的精度和召回率,而不是精度。但是在我们的例子中,两个值几乎相同,所以我们只使用精度。

总的来说,该模型对训练数据给出了 97.5%的准确度,对验证数据给出了 79.7%的准确度。

预测

我们将预测传递给我们训练好的模型的文本的情感。

model.predict(['why not'],k=3)
model.predict(['this player is so bad'],k=1)

predict让我们预测传递的字符串的情感,而k代表返回的带有置信度得分的标签的数量。

量化模型

量化有助于我们降低模型的规模。

model.quantize(input=training_data_path, qnorm=True, retrain=True, cutoff=100000)

保存模型

我们可以保存训练好的模型,然后随时使用,而不是每次都训练它。

model.save_model(os.path.join(model_path,model_name + ".ftz"))

结论

我们学习如何清理数据,并将其传递给训练模型来预测推文的情绪。我们还学习使用 fastText 实现情感分析模型。

利用 Python 的 matplotlib 可视化空间数据

原文:https://towardsdatascience.com/two-dimensional-histograms-and-three-variable-scatterplots-making-map-like-visualisations-in-7f413955747?source=collection_archive---------14-----------------------

在 matplotlib 中制作类似地图的可视化效果

为什么要对空间数据使用 matplotlib?

作为预测房价项目的一部分,我收到了一个来自美国华盛顿州金县的大型房屋数据集。该数据集包含大量与房屋相关的数据,包括一年内售出的每栋房屋的经度和纬度。因为纬度和经度都是连续的数字数据,所以在多元线性回归模型中,这些是潜在有用的特征。然而,甚至在项目进行到那个阶段之前,在数据集中看到纬度和经度就表明您也可以看到令人兴奋的空间数据制图世界。

确实存在一些免费或低价的基于 GUI 的电子表格程序,具有半功能地图功能——从笨重的 Excel Power Map,到有限的 Google My Maps,再到可悲的即将停产的 Google Fusion Tables。然而,只需几行代码,您就可以使用 Python 更快地创建信息丰富的类似地图的可视化效果,并且有更多的定制选项。你甚至不需要专门的地理空间分析库的知识就可以做到这一点——只要你的数据集中有纬度和经度,你就可以使用每个人都喜欢的绘图伙伴 matplotlib 来可视化它。

二维直方图

直方图是可视化数据集中变量分布的一种很好的方式,它显示数据集中位于特定值范围或区间的条目数量。下面的代码为 King County ('kc ')数据集中的纬度和经度生成简单的(一维)直方图:

import matplotlib.pyplot as pltfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))fig.suptitle(‘Distributions of latitude and longitude in the King County housing dataset’, fontsize=16)ax1.hist(kc.lat)ax1.set_xlabel(‘Latitude’, fontsize=13)ax1.set_ylabel(‘Frequency’, fontsize=13)ax2.hist(kc.long)ax2.set_xlabel(‘Longitude’, fontsize=13)ax2.set_ylabel(‘Frequency’, fontsize=13);

这些很好地显示了每个变量的分布,但是它们并没有给你一种地理上的感觉。我们想要的是一张地图。幸运的是,我们可以用二维直方图来实现这一点。这实质上是将沿 x 轴(经度)的直方图与沿 y 轴(纬度)的直方图相结合。不再是条的宽度(即一维),它们现在基本上是一个网格(即二维的正方形)。我们可以添加一个带有plt.colorbar()的颜色条,帮助我们将它可视化为一种热图:

plt.figure(figsize = (10,8))plt.hist2d(kc.long, kc.lat, bins=150, cmap=’hot’)plt.colorbar().set_label(‘Number of properties’)plt.xlabel(‘Longitude’, fontsize=14)plt.ylabel(‘Latitude’, fontsize=14)plt.title(‘Number of properties in each area of King County, Washington’, fontsize=17)plt.show()

如果你仔细观察,稍微眯着眼睛,你可以分辨出国王郡的形状,西雅图在左上方,还有普吉特湾的形状。

Map of King County, Washington, USA. Source: Google Maps

三变量散点图

使用 matplotlib 绘制空间数据的另一种方法是使用散点图。散点图将两个变量之间的关系可视化,一个在 x 轴上,一个在 y 轴上,通过在 x 和 y 变量的值上绘制每个数据点的点。Matplotlib 允许我们更进一步,使用第三个变量根据第三个变量的数据点值来改变每个点的颜色(或形状,或大小)。

King County 数据库包含每栋房屋的销售价格和每栋房屋的居住面积等信息。从上面的 2D 直方图中可以清楚地看到,在西雅图及其周边地区发现了许多房产,但是数据集也包括了远离城市的房产。地段大小可能以非随机方式变化,城市中的地段较小,乡村中的地段较大。因此,比较同类产品的更好方法是比较每平方英尺的价格。

在该散点图中,绘制了经度和纬度,并根据每平方英尺的价格对各点进行了着色,从而生成了一张地图,显示了每个地区的价格:

plt.figure(figsize = (10,8))plt.scatter(kc.long, kc.lat ,c=kc.price_per_sqft, cmap = ‘hot’, s=1)plt.colorbar().set_label(‘Price per square foot ($)’, fontsize=14)plt.xlabel(‘Longitude’, fontsize=14)plt.ylabel(‘Latitude’, fontsize=14)plt.title(‘House prices in King County, Washington’, fontsize=17)plt.show()

毫不奇怪,最昂贵的房产(以每平方英尺的价格计算)位于贝尔维尤和麦地那——科技亿万富翁比尔·盖茨和杰夫·贝索斯的家,以及美国一些最昂贵的邮政编码。

这就是我们使用 matplotlib 创建类似地图的可视化的两种方法。下次当您发现自己拥有包含纬度和经度的数据集时,为什么不尝试一下呢!

两个基本的熊猫附加产品

原文:https://towardsdatascience.com/two-essential-pandas-add-ons-499c1c9b65de?source=collection_archive---------3-----------------------

这两个必备的用户界面将帮助你提高你的熊猫技能

Python 数据分析库(Pandas)是 Python 事实上的分析工具。如此强大的分析库居然可以开源免费使用,这还是让我很惊讶。

但它并不完美…

Yes Pandas does have some shortcomings

我对这个库有一些不满,尤其是在执行简单的过滤和旋转时。在某些情况下,用户界面确实可以加速分析。对于探索和过滤数据的直观方式来说,没有什么比“拖放”更好的了,而这不是 Pandas 允许你做的事情。令人欣慰的是,有两个图书馆解决了这些问题,并与熊猫完美地合作。

Pivottable.js ,交互式数据透视表和图表

Pandas 中的数据透视表非常强大,但它并不适合快速简单的数据浏览。事实上,事情会很快变得非常复杂:

Pandas pivot tables can leave you scratching your head. Credit https://pbpython.com

谢天谢地,有一个奇妙的交互式数据透视表和绘图插件,****。它可以用 4 行代码安装和运行:

!pip install pivottablejs
from pivottablejs import pivot_uipivot_ui(df,outfile_path=’pivottablejs.html’)
HTML(‘pivottablejs.html’)

这给了你一个交互式的 HTML 数据透视图。这可以在笔记本中显示,也可以在浏览器中以 HTML 文件的形式打开(这样可以方便地与他人共享):

pivottable.js allows for interactive pivoting and charting of a Pandas dataframe

QGrid :快速的交互式表格

厌倦了看熊猫数据框的第一行和最后 5 行?您是否经常希望能够快速过滤并查看您的数据发生了什么?Pandas 使用 lociloc 提供了有用的过滤功能,然而,数据透视表同样会变得非常复杂,使用这些索引功能的语句也是如此。

QGrid 允许你这样做,甚至更多。一些关键特征是:

  • 过滤和排序数据帧
  • 在不降低性能的情况下滚动大型数据帧(超过 100 万行)
  • 直接通过用户界面编辑数据框中的单元格
  • 返回应用了过滤器/排序/编辑的新数据帧
  • 兼容 Jupyter 笔记本和 JupyterLab

通过 pip 或 Conda 安装非常简单:

pip install qgrid
jupyter nbextension enable --py --sys-prefix qgridimport qgrid# only required if you have not enabled the ipywidgets nbextension yet
jupyter nbextension enable --py --sys-prefix widgetsnbextension#to show a df simply use the below:
qgrid.show_grid(df)

要了解什么是可能的,请参见 QGrid Github 页面上的以下演示:

Visit https://github.com/quantopian/qgrid for more information on QGrid

仅此而已。希望这两个工具将有助于加快您在 Python 中的数据分析。

如果你知道任何其他的熊猫用户界面库,请在下面的评论中告诉人们。

有抱负的数据科学家的两项重要技能

原文:https://towardsdatascience.com/two-important-skills-for-an-aspiring-data-scientist-acdcb44a5c3a?source=collection_archive---------31-----------------------

Photo by Austin Distel on Unsplash

这就像生命中的另一天。

我当时正在为一家基于互联网的公司解决一个回归问题。

我加倍努力查找该领域的文献,试图找出还可以做些什么来提高性能。

尽我所能。

这就是我很多天来试图解决的问题。

他联系我问:哎,你工作怎么样?有进展吗?

我回答说:是的,我提高了性能。平均绝对误差已经降低到 10。

他:嗯..?梅。那是什么,伙计?解释一下。

Me:预测值和实际值之间的绝对差值的平均值。

他:用人类的语言和我说话,伙计。我不明白这一切。

然后,在尝试了很多之后,我写了一份对 MAE 的直观解释并发给了他。

他明白了,但还是有问题。

他:好的,听起来很酷!我明白了,但我们不会像这样向客户解释。并不是每个人都会这样理解。我想让你报道一些其他的,任何人都能一口气看懂的东西。

我:好的,我会尽快回复你。

敲响了警钟。

有些事情需要弄清楚,需要从这次事件中吸取教训。

你明白了吗?

是的,它传达了你从数据中得出的见解,这样每个人都能理解。

看,不是每个人都来自技术和数学背景。他们一点也不在乎。他们不关心你的 15 层深层神经网络。重要的是:你有没有给这张桌子增加价值,如果有,用简单的英语向我们解释。

几乎所有的生意都是为了拥有更多的顾客,赚更多的钱。这就是你的工作。所以,你需要坐下来,找出你试图解决的业务核心问题是什么。它将如何帮助企业。然后你只需要用这些术语来解释。

我给你一个建议。

训练你的移情肌肉,站在另一个人的立场上,想象那个人,然后试着解释你的见解。

看,你知道所有的数学概念并运用它们来解决问题是很好的。但是,如果你不能帮助企业做出决策或赚更多的钱,那就没有任何意义。

Source

这也是数据可视化有很大帮助的地方。数据可视化不是画那些花哨的图,数据可视化的唯一目的是用视觉传达你的见解。

项目开始前

作为初学者,我们大多习惯于从 kaggle 或一些随机课程中挑选一个问题,然后解决它。我们事先知道所有的细节,这是回归问题,这是你最后得到的数据集,现在你必须解决它。

但大多数时候事情并不是这样。当你工作时,你会遇到一个商业问题,然后你必须找出并映射到一个机器学习问题。

Business Problem -> ML Problem

快速 举例:假设你在 Quora 工作,有人告诉你一个问题存在大量重复条目,使得平台难以使用。你能想办法解决这个问题吗?

这就是商业问题。现在你已经彻底明白了,机器学习是否能有所帮助,如果是的话,那么,把它映射到一个机器学习问题上。

你可以使用 NLP 技术或基于深度学习的解决方案来找出给定的两段文本是否重复。如果是,删除其中一个,如果不是,保留两个。

不仅止于此。你还需要计算出你要用来评估你的模型的误差度量。误差度量的选择将指导您的模型开发之旅。

外卖:

  • 学会使用数据可视化和简单的英语有效地交流你的结果。
  • 甚至在开始一个项目之前,学会将商业问题映射成机器学习问题。

如果你发现它对你有任何帮助,一定要帮我传播这个消息,并关注我以获得更多这样的文章。和平与力量。

一枚硬币的两面:杰瑞米·霍华德的 fast.ai vs 吴恩达的 deeplearning.ai

原文:https://towardsdatascience.com/two-sides-of-the-same-coin-fast-ai-vs-deeplearning-ai-b67e9ec32133?source=collection_archive---------10-----------------------

如何不通过同时参加 fast.ai 和 deeplearning.ai 课程来“过度适应”你的人工智能学习

Which One to Take? WHY NOT BOTH!

数据科学和人工智能可能是目前科技领域最热门的话题,这是理所当然的。在应用层面和研究领域都有巨大的突破。这是一种祝福,也是一种诅咒,至少对于想要进入这一领域的学生和爱好者来说是这样。有太多的算法要学习,太多的编码/工程技能要磨练,太多的新论文要跟上,即使你觉得你已经掌握了这门艺术

旅程漫长,学习曲线陡峭,冲突真实存在,但潜力如此之大,人们仍然蜂拥而至。好的一面是,我们也有很棒的教育者和指导者致力于减轻痛苦,让这个过程少一点苛刻,多一点乐趣。我们将探索其中最伟大的两个,并分享一种潜在的有效方法,以帮助您更快乐地在数据科学的海洋中畅游。

人工智能学习“耗尽”

Photo by Toa Heftiba on Unsplash

如果你列出一个人要成为一名“好的”数据科学家或机器学习工程师需要学习的东西,那可能会长得吓人:

数学:线性代数,微积分,统计学,算法,…

编码: Python,R,SQL/NoSQL,Hadoop,Spark,Tensorflow/PyTorch,Keras,Numpy,Pandas,OpenCV,数据可视化…

算法:线性回归、逻辑回归、支持向量机、PCA、异常检测、协同过滤、神经网络、CNN、RNN、K-Means、NLP、深度学习、强化学习、AutoML、…

工程:命令行,云平台(AWS,GCP,Asure),DevOps,部署,NGINX/Apache,Docker…

对于一个刚刚进入这个领域的人来说,这份名单很容易让人晕头转向。然而,它仍然只是触及表面。有些人制定了一个雄心勃勃的计划,并投入其中。一些人失去了动力,感觉完全淹没在水下,出口看不见了。哪里出了问题?

你“过度适应”了自己

From Andrew Ng’s Machine Learning course

对于了解一点机器学习的人来说,verfitting 是一个非常熟悉的想法。这基本上意味着你的算法学习了“太多”的数据,把自己埋进了数据集的小细节中,错过了大画面。想一想,有时当我们学习一件事情时,我们太投入了,以至于忘记了我们为什么要学习它,以及它将如何融入大局。我称之为“过度适应”你自己的学习。这种情况经常发生在有学术背景的人身上。数学博士倾向于确保在继续下一个之前所有的定理都被完全理解。这对学习数学很有帮助。对理论有深刻的理解会给你很大的直觉和信心。它将使您能够看到未经培训的人不容易看到的模式和问题,但数据科学要求更多。

抛开理论不谈,这其中也有实用的部分。一个恰当应用的算法,加上高效的代码、精心调整的超参数和精心设计的流水线,通常会取得不错的结果,但光有算法是不够的。过于深入地钻研理论,你可能会错过学习的实践部分。同样重要的是,积累如何实施所学知识和处理现实生活中的复杂问题的经验。如何解决这个问题?进入 deeplearning.ai 和 fast.ai 课程。

Deeplearning.ai 和 Fast.ai

已经开发了很多课程来帮助人们完成学习过程。其中,Deeplearning.ai 和 fast.ai 是两个独特的,它们有自己的方法,可以给我们一些关于学习数据科学的潜在有效方法的见解。

deeplearning.ai

deeplearning.ai 是由吴恩达开发的付费课程。和他的其他课程一样,它以精心设计的学习曲线、平静流畅的教学风格、充满挑战而又有趣的作业而闻名。它被公认为是一门不会出错的深度学习课程。它从基础理论开始,并逐步发展到如何将所有部分结合起来解决现实生活中的问题。这也被称为“自下而上”的方法。

fast.ai

fast.ai 由杰瑞米·霍华德和雷切尔·托马斯推出,作为一门免费课程,教授有基本编码经验的人最先进的深度学习技术。在没有太多基础理论解释的情况下,使用很少几行代码,fast.ai 的学生能够在自己的领域内快速取得惊人的成果。(在完成 fast.ai 课程的第一课后,我构建了一个达到 96%准确率的中国书法风格分类器和部署在云上。)它首先教你如何解决现实世界的问题,然后越来越深入地探究事物是如何工作的以及为什么工作。这也被称为“自上而下”的方法。

哪一个是最好的方法?都是!

那么‘自下而上’和‘自上而下’,哪个更好?我们应该走哪一条?答案是双双

Photo by Maarten Deckers on Unsplash

看,这两门课程相辅相成。假设你从吴恩达的 deeplearning.ai 课程开始,你将自己埋进了无尽的公式和理论中,你获得了很多直觉,但是经过几周的学习,你仍然没有什么可以展示给你的朋友,也不太确定你什么时候可以应用你新获得的知识。你对机器学习基础的研究回报越来越少。你的大脑变慢了,你开始觉得无聊。现在是开始上一两课 fast.ai 课程的最佳时机。在强大的 fast.ai 库和几行代码的帮助下,你将能够构建令人印象深刻的模型来解决现实生活中的问题,甚至击败一些最先进的论文和竞赛。这将给你的大脑一种完全不同的刺激,给你的心更多的信心和激情去更深入地探究为什么一切都在运转。一旦你建立了几个项目,让你的朋友们惊叹不已,你就会更有动力去学习更多的基础知识,然后你就可以回到 deeplearning.ai 课程,并在那里继续学习。这两个过程互相推动,你可以只是冲洗和重复,直到你完成这两个。

这就形成了一个完美的学习圈。

Photo by Dan Freeman on Unsplash

以这种方式选修两门课程的最大好处是,一旦你完成了两门课程,你就会做好充分的准备。从 fast.ai 课程到向潜在雇主展示,你有大量的项目,你也对一切如何运作有深刻的了解,甚至发表过一两篇论文来展示你的发现。你现在是一名全面发展的数据科学家。多酷啊。

欢迎任何反馈或建设性的批评。你可以在 Twitter 上找到我,也可以在我的博客网站 wayofnumbers.com T2 找到我。

关于手工标注数据的两个故事——它仍然有效

原文:https://towardsdatascience.com/two-stories-about-labeling-data-by-hand-it-still-works-fec167d74ac7?source=collection_archive---------21-----------------------

当然,这是一个屁股痛,有自己的问题,但人类的大脑仍然是惊人的

我知道。手动标注数据可能会非常乏味,让人麻木。这是你能得到的最迷人、最性感的机器学习工作。作为超级聪明的数据科学家,我们难道不应该超越这种经常强加给实习生、研究生或机械土耳其人的苦差事吗?

事实上,不是。在很多情况下,我认为它比许多涉及无监督学习方法的替代方法更少痛苦(也更快)。它还会产生非常重要的特定领域见解,我认为一名优秀的数据科学家绝对需要在他们选择的行业中保持高效。

https://xkcd.com/2173/

也许是因为十年前我作为数据分析师在这个行业崭露头角,艰难地拼凑出自己的见解。或者可能是因为我的社会科学背景,手动编码回答是我们定量工具箱中非常重要的工具。尽管如此,我不是唯一相信这一点的人。

总的来说,我发现手动分类数据是最有用的,当你陷入这样一种情况时,你需要:1)作为研究人员学习理解数据集/问题空间,2)提出一个分类系统。

在这种情况下,很难制造一个开箱即用的自动化系统。当然,有一些无人监管的方法,你可以尝试各种形式的聚类,然后进行分类,但是当你自己不熟悉问题空间时,你得到的聚类是否有效和可用并不完全明显。既然事实上没有地面真理可言,你也可以在你的头脑和你的分类器中,潜进你自己去建立一些地面真理的表象。

人类的分类器会错吗?绝对的。有无意识(或有意识)的偏见?你打赌。错过重要功能?当然了。但对于我平时操作的应用来说,这些都不重要。我们需要足够好的东西来开始,来建立一个测试用例。一旦事情被引导,我们可以看到事情如何执行并检查问题。

这里有两个 2010 年代早期的说明性故事,当时技术是不同的(但并不完全不同)。

技术提示:我通篇交替使用动词“编码”和“标签”。只是习惯。

故事#1,在黑客马拉松上给一些企业分类

2012 年,我参加了某种形式的数据黑客马拉松,我相信是由 Data Kind 的人与各种政府机构和非营利组织合作举办的。我们分成几个小组,每个小组都有一些需要数据帮助的问题,我们都尽力在几个小时内提供帮助。输出可以是一个模型,或者一个方法,或者任何有用的东西。

对于我的团队,我们与纽约的一家代理机构合作,我忘了是哪家了。我们的任务基本上可以归结为企业的大型 csv 文件和他们拥有的专业许可证(香烟零售商、台球室、讨债、路边咖啡馆、一般供应商等)。这些企业也有他们的注册地址和建筑类型,是否有与该网站相关的餐馆执照或酒类执照,以及其他一些细节。我们的目标是了解企业和执照是如何结合在一起的,这样如果一家企业碰巧丢失了执照(比如说,一家没有执照的酒吧),就可以标记出来。

我的四五人团队(我觉得?我忘记了一些细节,但有旧数据文件的副本要查看)有许多超级聪明的人,数据科学界的一些名人。首先,他们拿出 R(一种我还不知道的语言),并开始研究如何摄取我们拥有的各种 CSV 文件,以便他们可以运行各种分析(相似性计算等)。

潜入水中

看到他们在工作中有编码的一面,我继续做我通常做的事情,努力通过原始数据获得对事物的感觉,试图让自己在这方面有用。因为我们最终想要的是一种不使用现有的业务分类代码,根据业务实体拥有的许可证对其进行独立分类的方法,所以我有一种预感,我们必须找到一种方法,用我们不应该使用的标签之外的非常非常少的数据对这些业务实体进行分类(因为我们试图预测它以找到差异)。

另一种方法是做一个两步分类系统,我们将 1)把许可证分组在一起,希望企业的属性能够自然地聚类,然后 2)利用聚类并使用它们来形成一个分类器,可以捕获没有正确许可证的企业。这两者都不能保证商业/许可证集群会以任何合理的方式真正形成。只有大约 10k 个许可证(一个给定的企业可能有多个许可证和行),可能会有太多的干扰。

当我浏览这些企业并试图猜测它们是什么时,奇怪的是,我发现这出奇的容易。我会查看该实体的名称,并会不断地看到类似“弗雷德自助洗衣店”或“阳光咖啡馆”的东西。我意识到虽然没有严格的要求,但人们经常以他们从事的业务来命名他们的商业实体。几乎没有人会开一家名为“玛丽咖啡有限责任公司”的汽车商店。如果没有人坐下来通读大量数据,我们永远不会发现这一点。

我最终做的是编辑一个关键词列表,我觉得这些关键词是某类业务的高度指示,例如:“汽车”、“熟食店”、“Duane”(Duane Reade 连锁药店)、“超市”等..然后,我们分析了哪些许可证与这些词相关联。例如,卷烟零售许可证常常与名称中带有“熟食店”的企业联系在一起,也与“食品”和“市场”联系在一起,偶尔还会与“汽车”联系在一起。下表显示了我们发现的一些关联。

The number of business entities w/ a word in its name (top row) vs business licenses associated (down the left)

到这一步时,我们的时间有点紧,但我们本质上构建的是一个系统,它可以接受一个企业名称,并生成它可能拥有的许可证列表。它不会对所有东西进行分类,但它是一种比其他可用功能(如地址、建筑类型(两个家庭与电梯合作公寓等)、零售面积)更强大的将企业聚集在一起的方式。

有了这个初始分类,我们就可以试验其他特征,看看是否有任何有意义的聚类,因为我们已经半手工标记了数以千计的企业。这是我们(相当)坚定的基础事实,允许我们利用数据集的其余部分。

可悲的是,数据黑客马拉松很快就结束了,我不知道这个模型发生了什么,不管它是否被使用过。但希望它能帮助某人更接近目标。

故事#2,为 Meetup 创建一些组类别

我不记得这个项目是什么时候出现的了,但是大概是在 Meetup 第一次尝试在直接关键词搜索之外进行群体发现的时候,大概是 2012 年左右吧?自从我帮助建立这个系统以来,他们的分类已经发生了很大的变化,所以我确信这与现有的系统没有任何关系,在这里谈论应该是安全的。

作为背景,在 2011 年之前,Meetup 群组最初有多达 15 个“主题与之相关联。这些影响了当你的组被宣布时什么用户会得到通知,你可以用它来浏览组。疯狂的是,主题是完全自由形式的用户字符串,由组组织者创建。有一些轻微的监管,以防止人们使用顽皮的词语,但除此之外,你可以自由地写下像“摄影”这样的单个单词或像“晚上拍奶酪汉堡的照片”这样的完整句子。

问题是,虽然大多数类型的小组通常都有一个主导主题,就像大多数摄影小组使用“摄影”一样,但并不是所有的小组都这样做。这在“全职妈妈”组和“全职爸爸”组中最为突出,这两个组本质上都是育儿组,但一个组可能只选择一个。

好吧,如果我们要有一个更好的方法来找到群体,就需要有一种方法通过某种类别来组织群体。我们需要将 1-15 个主题标签提取到 1 个(也许 2 个)类别中。这些类别应该是什么?虽然新创建的组无论如何都要经过人工审核,并且可以在那里进行人工分类,但是我们如何处理大约 10 万个现有的组呢?

盲目地来看这个问题,你可能会试图分析和 k-means 聚类所有的主题字符串,基于什么组使用它们。因为我们知道我们希望 K 是一个“可管理的数字”(低于 30 岁),所以它可能会起作用。这可能需要一些调整和反复试验,但听起来可行。

这个计划

我没有采用 k-means 方法,而是走了一个不同的方向。凭直觉工作(深入研究 Meetup 的内部数据 2-3 年),我有一种感觉,“最常用的主题可能已经足够有信息了”,这意味着我可以忽略主题的超长尾巴。

因此,我转而抛弃了所有与超过一定数量的群组相关联的主题(超过 50 个群组或者类似的,我忘了)。这产生了一个大约 1800 个主题的列表,相比之下,一个巨大的列表包含超过 15k 个主题字符串。

在那之后,我和我的犯罪定性研究伙伴谈了谈,我们分开了数据集,然后坐下来用手对主题进行分类。就像编码自由形式的调查回答一样,我们创建了我们认为合适的类别,并努力通过。

创建映射后,我创建了一个非常简单的算法来给一个组分配一个类别,1 个分类主题=一个类别的 1 票,投票最多的类别就是该组的类别。仅用这种简单的算法,我们就覆盖了大约 85-90%的现有群体。对一组随机样本进行的抽样检查显示,这些类别总体上相当准确(我忘记了细节,但与人类的一致性达到了 90%左右)。

我们如何处理无法以这种方式分类的~ 10–15k 组?我们为它制作了一个简单的网络工具,并要求客户支持团队中的每个人在他们轮班的安静时间里对它进行整理。对所有东西进行分类并不需要很长时间,可能需要 1-2 周的时间。

接下来,我们使用相同的算法来建议类别应该是什么,但是支持团队无论如何都会在审查新组的 TOS/质量时检查并更改它。

我确信他们现在使用的系统和我很久以前帮助建立的系统是不同的。当前类别似乎修复了我们在 v1 中发现的一些问题。例如,我们最初的遗憾之一是某些类别“太大”,太多的商业/创业/企业家/投资团体都被归为“商业”一类。我们应该回去平衡事情,但是我们选择不这样做,因为我们不确定类别在那个时候会如何被使用。

Meetup’s current categories (2019), about half of which weren’t ones I put together almost a decade ago

所以卷起你的袖子

想试试吗?这里有一些快速提示。

建立一个良好的编码环境。贴标签的行为应该让你进入一个流程,在那里你可以快速制作出准确的标签。当你最大限度地减少点击链接或眼睛在屏幕上跳来跳去的摩擦时,你就帮助最大限度地减少了引入非受迫性错误的精神疲劳。然后,当你感到疲劳时,确保经常休息(我喜欢吃零食)。

如果你有多个编码员,确保每个人都同意用相似的方式编码(更正式的说法是你有一本编码书),经常交流,检查你的工作。对于更严格的东西,确保你做了健全的交叉检查,并检查了评分者之间的可靠性。

最后,想办法把工作分散开来。在团队环境中,编程更有趣。我们可以就奇怪的例子交换笑话,或者在飞行中讨论奇怪的边缘案例。另外,有另一个人和你一起工作有助于集中注意力。

但是,这不会扩展!

当然,如果你有 5000 万件事情要编码,你不会手工去做所有的事情。但是从 500 个到 5000 个,甚至到 15000 个标记条目将使你制作的任何分类器表现得更好。然后,您应该能够比以前更有信心地扩大规模。

希望我的小故事能让你相信,手动标注数据这种完全不性感、时常令人头脑麻木和痛苦的工作是你工具箱中的一个超级有用的工具。

两个任务,两个数据集,一个网络:DnD 的多任务学习

原文:https://towardsdatascience.com/two-tasks-two-datasets-one-network-multi-task-learning-with-dnd-eaef00b5e741?source=collection_archive---------12-----------------------

elf/human (.95), rogue (.65). HERE is a link to view for free if you like

这篇文章的动机是我在 Shoprunner 的实际工作中一直试图解决的问题。对于上下文,我负责对不断增长的类别进行建模,我们可能永远不会有一个我们想要建模的事物的完整列表。因此,建立一个数据集来统治所有这些被我们需要的所有类别完全标记的数据并不特别可行。虽然这可以在物理上实现,但存在许多风险,例如新的类别在统一数据集中表现不足,然后我们必须用所有以前的类别标记一个全新的数据集。此外,它可能只是花费一堆额外的钱。

有很多解决方案,我会考虑部分解决方案,如建立一堆特定类别的模型并部署这些模型,或者继续寻找用一个数据集来统治所有模型的方法。

构建和部署单个模型似乎很容易,直到从现在起一年内您必须维护几十个模型,这时您可以使用单个模型来完成相同的任务。因此,如果能用一个单一的多任务网络解决所有这些问题,那就更好了。

为了继续追求“一个数据集来统治所有路径”,我一直在建立针对特定类别训练的较小模型,并使用这些模型来标记更大的图像池,以创建大型完全标记的数据集。然而,这个过程需要手动检查类别来测量清洁度,并且存在许多与保持完全标记的数据集的清洁度相关的问题。对我来说,这是一个权宜之计,可能很难维持。

对我来说,我真正需要的是一种训练多任务模型的方法,可以灵活地为单个任务使用多个数据集。

Dragonborn (.96) Paladin/Warrior (.91). When I looked at this image in my jupyter notebook I was confused as to what it was… then I saw the race and class was written on it. Gogo model I guess? The only label this image would have in the dataset was “dragonborn” so the model gets paladin right which is cool.

背景:滚动历史检查

能够使用多个数据集来训练我的多任务网络,而不是依赖于一个统一的完全标记的数据集,这将给我带来相对容易地添加和删除类别的灵活性。在过去的几个月里,我对网络架构和管道做了很多实验,但是直到最近我才接近成功。

大约一周前,我很无聊,当天早些时候又听了一遍吴恩达的多任务学习讲座,但直到我在咏春练习中与一些人对练,我才真正理解了视频的细节。在对练过程中,我意识到吴恩达简要地提到了使用非统一数据集进行多任务学习(视频中大约 5:30)。这分散了我的注意力,我被打了几次,但这非常值得。

multi-task learning lecture from Andrew Ng’s deep learning course

虽然非常模糊,但吴恩达的基本思想是,通过只计算相关损失并将其用于反向传播,可以在部分标记的数据集上进行多任务学习。

这个高层次的想法看起来很直观,因为吴恩达在一次演讲中提到了它,所以我认为这是可能的。所以我经历了几次不同的管道迭代,试图做到这一点。所有失败。太好了,又回到起点了…我还是错过了一些东西。

对我有帮助的第二点信息来自于对 Google 的 Bert NLP 模型应用的最新研究。虽然我不喜欢芝麻街的命名趋势(ELMO,伯特,大鸟),但如果你没有检查过的话,这些模型非常有趣。我在斯坦福黎明看到了一个帖子。对我来说,关键在于以下几点。

我们的训练时间表也很简单:将所有参与的任务分成几批,随机排列,通过网络一次传送一个,这样每个任务中的每个训练例子在每个时期就可以看到一次。

我有一种相当强迫性的需要去做数据科学的事情,我自称是一个“数据科学迷”。所以当我读完这篇文章后,我基本上是下班回家,直到凌晨 2 点才开始修改我在这篇文章中使用的细节。

数据集:主动滚动

humanoid (.57) warrior/paladin (.57). swords and plate armor for warrior/paladin. Dataset label is just warrior/paladin.

与所有项目一样,首先需要找到/构建一个数据集。然而,在这篇文章中,我使用了两个小数据集,它们是我收集的与两个 DnD 种族和阶层相关的图片/艺术品。

种族包括人形种族(精灵/人类),侏儒,龙族,职业包括圣骑士/战士,盗贼,巫师/巫师。

这些都包括在内,并能概括 DnD 的一切吗?绝对不是,但是它们符合我的目的,对于每个数据集,随机猜测大约是 35–40%

另一个细节是,我使用 fastai 讲座中提到的方法快速建立了这些数据集,该方法参考了来自 pyimagesearch 的另一篇博客文章。

总的要点是,你可以使用谷歌图片搜索来挖掘数据集相对一致的类别,然后手动删除不相关的图片,以彻底清理它。作为一个曾经手工构建图像数据集并对其进行标记的人,这是生活质量的巨大提高,我强烈推荐你尽你所能使用它。目前,我仍在试图用这种方法解决多标签问题,但这可能是另一个话题。

版本 1 管道:滚动修补检查?

我建立这条管道的第一步主要是修改我现有的培训管道。下面是一些实现细节。

  • 制作了两个数据集加载器,而不是一个。我将两者分开,这样我就可以对它们进行迭代,分别生成批次,并只计算网络中那个任务头的损失。
  • 现在,我使用两个数据集中较小的一个来确定一个时期内要生成的批次数量。这可能是不必要的,可能只有在两个数据集具有相似数量的样本的用例中才是有意义的。
  • 我只做一次反向传播。我运行一个数据集的批处理,并计算该任务的相关损失(完全忽略吴恩达建议的另一个任务的损失计算)。然后运行第二个数据集的批处理,并计算第二个任务的损失。一旦这两个做了,我总结他们的损失,并执行反向传播

请随意检查我做修补的笔记本。我制定培训计划的初始笔记本是这里

我在让这个模型收敛时遇到了问题,但是我发现稍微低于正常的学习速度就能很好地工作。这可能有助于网络不过度适应某个特定的任务,避免它在两者之间来回跳跃。高度推测性的,它在我这边经得起进一步的测试。

这条管道的最终结果是,我能够以大约 70%的准确率预测输入图像的种族和类别。

一方面,这是一个胜利,因为我得到了以上的随机猜测…然而,它仍然有点畏缩值得,因为我觉得它应该能够做得更好…所以,现在管道工程,我应该如何改善它?

由于我使用的学习率低于正常水平,我认为主干网 Resnet 模型很可能无法很好地适应这个 DnD 特有的领域。为了测试这个假设,我需要做的就是得到一个 DnD 微调模型。

具有微调主干的版本 2:滚动洞察检查

因为我已经有了数据集,所以我训练了一个 Resnet50 模型来预测种族类别。我对我的标准培训管道做了一些小的修改(大部分只是将它们转换回只做一项任务,因为我身边的大多数管道都是多任务学习者)。目标是将更多的领域专门化到主干模型中,主干模型承担了大部分繁重的工作。

虽然我可能已经从这个模型中挤出了更高的性能,但它在任务中达到了 80%的准确率。因此,这超过了比赛任务 40%的随机猜测阈值和版本 1 多任务模型 70%的准确性。

微调主干网 Resnet50 模型发生在这里

我用这种新的微调过的 Resnet50 替换了 vanilla Resnet50 模型,并运行了几次培训管道。我发现,循环学习率并实际上让它使用稍高的学习率(低于正常水平,但高于我之前使用的水平)可以让模型在种族方面达到 83%的准确率,在类别方面达到 75%。

具有微调主干的版本 2 管道在这里是。当我基本上只是循环学习率时,我还记下了不同的跑步。

这和我想要的一样高吗?仍然没有,但我认为它演示了一个相当有效的方法来训练这些模型,并表明一个微调的主干提高了这个设置的性能。

humanoid (.998) and wizard/sorcerer (.834). Staff and robes seem to equal wizard to the model.

结果:进行感知检查

因此,与使用非微调模型的管道版本 1 相比,微调模型显示了显著的改进。版本 1 模型在最低损失 1.681 上具有 70%和 71.25%(种族和阶级)的最高准确度。相比之下,第二版模型提高了良好位得分 83.75%和 75%,最佳损失为 1.5751。

唯一的区别是用一个微调的模型替换了网络的主干,这很有帮助,因为它提供了一个很好的方法来解决我在 Shoprunner 面临的问题。基本上,您可以应用当前调整良好的模型,并使用这种多数据集训练方法添加其他类别。

我感兴趣的另一件事是,这个网络的多任务版本能够在同一问题上胜过单一任务网络。

对于 DnD 竞赛类别,优化的 Resnet50 得分为 80%,但使用该网络作为主干的多任务网络在同一任务中得分为 85%。使用多任务学习的原因之一是因为在多任务上训练网络充当了一种正则化的形式。Sebastian Ruder 经历了多任务学习,并在这里谈到了一些。

在不同的任务上训练一个网络比单独训练每个任务可以看到泛化能力的提高,因为网络因过度适应一个任务而受到惩罚。

这种性能提升也很有趣,因为当我向我的工作模型中添加更多类别时,随着更多任务的学习和网络获得比以前更多的主题专业知识,它可能会在以前的迭代中提供性能改进。

gnome (.778) rogue (.9112). Because of the way I constructed these classes paladin/warrior is mostly people wearing plate armor, rogue is for characters dressed fairly normally, and wizard/sorcerer is people with long robes who are using magic/have staffs. My fault, not really the model’s

结论:进行一次智慧检查

humanoid (.995) wizard/sorcerer (.93). likely says wizard due to the robe-y feel?

因为这主要是我在做实验,这方面还有很多需要改进的地方,我希望我会回顾这项工作,并从我攻击这个问题的方式中获得笑声。然而,就目前而言,这种方法似乎相对有前途,实施起来也不可怕。

我认为,随机选择批次,而不是像我现在这样按顺序循环不同任务的批次,可能会提高性能,并给模型的训练周期增加更多变化。

对于计算损耗并将其反向传播回网络的最佳方式,也需要进行实验。我试着做了两个优化步骤,并得到了一些错误,这就是为什么我默认回到像其他多任务模型一样将损失加在一起。

也像其他多任务网络一样,我需要找出好的方法,在任务执行不良的情况下,改进特定的任务。

即使有我认为可以改进的地方,这个管道对我目前的工作来说是一个很大的进步,也是我几个月来一直在纠结的一个问题。

构建大型统一数据集既费时又费钱。也许之前的一些工作已经完成,所以在一个地方有特定类别的标签,另一个是全新的,所以你必须众包该类别的标签,第三个是来自一些已购买的数据集。在一个需要统一数据集的环境中,你需要做一些像我所做的工作一样的事情,我在每个问题上训练更小的模型,并用它来标记统一的数据集或支付众包标签。对于这两种情况,您需要花费大量精力来确保初始数据集和生成的标签都是干净和可用的,否则会有交叉污染的风险,并且最终模型的性能会下降。

您可以单独使用这三个数据集,并同时使用每个数据集对每个任务训练一个多任务网络,而不是找到某种方法来统一这三个数据集的标签以训练一个模型。这减少了需要训练的模型数量和需要进行的人工检查的数量。

能够使用为特定任务标记的数据集来训练多任务网络意味着您可以使用在任何给定点最有意义的任何方法来生成这些标签。

这里是回购的一般链接。它还包括一个笔记本,我只是在这个博客中使用的一堆不同的图像上运行这个模型。

humanoid (.995) wizard/sorcerer(.964)

在数据科学面试中脱颖而出的两个技巧带回家的挑战或工作

原文:https://towardsdatascience.com/two-tips-to-stand-out-in-your-data-science-interview-take-home-challenge-or-job-a4682b3e9afb?source=collection_archive---------10-----------------------

TL;速度三角形定位法(dead reckoning)

技巧 1:使用 h2o.ai 而不是 scikit-learn 构建随机森林模型。

技巧 2:使用 LIME 提供本地模型解释。

下面我会告诉你怎么做、为什么做以及一个简单的方法。

谁应该读这篇文章?

本文面向两类读者:

  1. 您正在寻找您的第一份/下一份数据科学工作,并且有兴趣在带回家的挑战中领先一步,以便从人群中脱颖而出。
  2. 您是一名数据科学家,希望提高随机森林模型的性能,或者厌倦了向业务伙伴解释机器学习模型的准确性与可解释性之间的权衡。

技巧 1:使用 h2o.ai 而不是 scikit-learn 构建随机森林模型

你已经花了几个小时来润色这些杂乱的数据,进行特色工程,并最终准备好用你的机器学习模型来攻击你的训练数据集。随机森林通常是我的首选武器,因为它们易于实现,并且往往提供良好的开箱即用性能,而不需要密集的超参数调优。如果您的数据集中有分类要素,您需要对它们进行一次性编码,使其便于 scikit 学习。您是否知道,在大多数情况下,这一步骤实际上会阻止您的模型发挥其全部性能潜力?

假设你有两个特征——年龄(连续)和教育程度(分为四个等级——高中、学士、硕士和博士)。一键编码将这两个特征转换成五个特征。当决策树为节点处的分裂选择最佳特征时,除非其中一个分类级别单独比年龄具有更强的预测能力,否则连续特征往往会首先被选中。因此,如果你曾经看过 scikit-learn 的特性重要性图,你会注意到连续变量通常在最上面。

然而,h20.ai 或 R 的随机森林实现通过整体考虑分类特征来规避这个问题。使用一个热点编码,在一个节点上只检查四个教育条件以进行分割。如果训练数据点具有高中的一键编码值,那么将数据点移动到节点的左侧,否则将它们移动到右侧,并且对于学士、硕士和博士进行同样的检查

另一方面,h2o.ai 检查上述条件,但也检查复合条件。复合条件是指不同的分类级别被归入一个类别。例如,如果数据点具有高中值或学士值,则将数据点移动到节点的左侧,否则向右移动。还会检查所有其他级别组合的拆分。例如,高中或硕士、学士或博士、高中或学士或硕士(这类似于博士的一键编码值)等。这些额外的复合条件导致分类变量被选择用于拆分的概率更大。请记住,由于这些实现检查附加的复合条件,它们的训练时间通常比 scikit-learn 实现长。

看完上面一段就挠头?这篇文章用例子详细解释了这一现象。

如果你从未使用 h2o.ai 建立过模型,不用担心,我会支持你的。本文末尾有一个 Jupyter 笔记本的链接,里面有一个简单的例子。这很简单!

技巧 2:使用 LIME 提供本地模型解释

LIME 代表局部可解释的模型不可知解释。虽然随机森林的特征重要性提供了对预测的全局解释,但是 LIME 让您可以对测试集中的每个预测进行解释。如果你以前从未听说过 LIME,这里有一个很好的资源来理解它是如何工作的,并把你指向原始论文和 Python 包。

下面是对著名的泰坦尼克号数据集中的一个预测的解释。

LIME Example

上面的图表告诉我们,模型使用橙色突出显示的特征来分配此人生存的高概率。

不幸的是,将 LIME 与 h2o.ai 一起使用可能会令人困惑,但为了帮助你,我编写了一个名为 limewrapper 的包来简化功能工程过程,以便能够轻松地将 LIME 与 h2o.ai 一起使用。如果你想深入研究,这里有一个示例笔记本,我将向你展示如何使用 h2o.ai 构建一个简单的随机森林模型(分类器和回归器),以及如何使用 limewrapper 包获得本地解释。

有了这两条锦囊妙计,你应该可以毫不费力地给面试官留下深刻印象,或者减轻一些(但不是全部)对 ML 持怀疑态度的商界人士的担忧。

我希望这对您的数据科学之旅有所帮助。你可以在这里了解更多关于我的旅程。如果你有任何问题,可以通过 LinkedIn 联系我——www.linkedin.com/in/joelprince。聊的开心!

如果你喜欢这篇文章,请查看:

  1. 我的第一份数据科学简历
  2. 从研究生到数据科学家:我对成功转型的两点看法

调整神经网络的两种奇怪方法 Tensorflow 中的手动反向传播]

原文:https://towardsdatascience.com/two-weird-ways-to-regularize-your-neural-network-manual-back-propagation-in-tensorflow-f4e63c41bd95?source=collection_archive---------27-----------------------

两个奇怪的想法,实际上调整了一个神经网络。

Image from this website

这个帖子纯粹是为了满足我的好奇心。看了多篇论文,了解到在深度神经网络的训练过程中注入噪声,会产生更好的泛化能力。(与这个概念相关的一些论文是摇动-摇动正则化和添加梯度噪声)

但是有一天,我想,与其注入噪音,不如我们采样会发生什么?此外,可以使用激活函数作为正则化,旨在创建稀疏的内部数据表示?

我感谢我的导师Bruce博士的有益讨论。此外,我还要感谢我在瑞尔森视觉实验室、 Jason 的一名实验室成员的有益讨论。更多文章请访问我的网站, jaedukseo.me 。

简介

正则化深度神经网络是一项棘手的任务,一方面,我们不希望网络简单地记住所有的输入和输出映射。而另一方面,我们希望网络达到最高的性能。

今天,我想尝试两种非常规方法,看看这些方法是否可以执行正则化。

方法 1:随机抽样反向传播

Image from this website

这个想法很简单,我们不是直接采用梯度,而是对高斯分布进行采样,将计算出的梯度视为该分布的平均值。

但是我们可以在三个不同的地方进行这种采样。

蓝色球体 →每层渐变
绿色球体 →权重动量
黄色球体 →权重速度
红色球体 →计算出的亚当更新

上述过程显示了 Adam optimizer 如何使用梯度信息来计算权重的更新值。从上面的图像中,我们可以看到,我们可以从红色球体或蓝色球体中取样,或者从两者中取样!我对所有情况都进行了实验,所以我们将看到每种情况的表现。最后,我们可以执行采样的最后一个地方是前馈过程。

蓝色球体 →每层输入
绿色球体 →每层权重
红色球体 →每层卷积运算
黄色球体 →每层激活运算

我执行采样的下一个区域是权重本身,在训练期间,模型使用权重值,然而,在测试期间,模型执行采样以获得权重值。

所有这种抽样方法的一个缺点是,我们需要选择一些标准偏差。对于所有的实验,我将标准偏差设为 0.00005。这种方法的一个优点是这种方法可以克服消失梯度,因为即使梯度为零,它也会重新采样并得到一个小的值。(布鲁斯博士已经向我提到了这个优点。).最后,合并了每种情况的卷积层可以在下面看到。

方法 2:作为正则化激活

蓝色球体 →卷积层
红色球体 →非线性激活

该方法背后的思想是划分稀疏约束和特征提取部分。因此,我们不打算在权重上添加稀疏性约束,而是添加激活权重。

如何实现这一点很简单,简单地说 ReLU layer 只让正值通过。这可以被认为是一个掩码,其中这个掩码被乘以数据的内部表示。

现在,我们可以通过拥有与内部数据维度完全相同的权重来放松 ReLU 激活的零和一约束,并执行元素级乘法。我们可以在这些权重上添加稀疏约束。

如上所示,我们有一个称为 ReLU 的正则化层,这个层简单地执行元素乘法。然而,在执行反向传播时,我们添加了稀疏项,最后为了实现 ReLU 的软化版本,我们应该将该值从 0 剪切到 1。

实验设置

蓝色球体 →输入图像数据 STL10
黄色矩形 →卷积层
红色方块 →交叉熵损失项用于分类

网络架构相当简单,六个卷积神经网络。此外,我在多集上训练了 200 个时期的网络,以研究该方法是否能重复产生稳定的结果。

结果 1)随机抽样反向传播

Training Accuracy Plot (left) Testing Accuracy Plot (right) over 10 episodes

情况 A →基础情况无随机抽样
情况 B →退出
情况 C →在 Adam 更新中随机抽样
情况 D →在 Adam 更新/梯度中随机抽样
情况 E →在前馈期间在 Adam 更新/梯度/权重中随机抽样

粗线代表 10 集的平均准确度,最小-最大范围以透明色显示。我们可以直接观察到情况 E 在训练和测试图像上都达到了最高的准确度。它也胜过辍学。

然而,我们应该注意案例 C 能够跑赢其他案例的情况。当我们绘制一段时间内精度的标准偏差时,我们会得到如下图。

STD of Training Accuracy Plot (left) STD of Testing Accuracy Plot (right) over 10 episodes

令人惊讶的是,当我们增加随机抽样的区域时,每集之间的方差减少了,这意味着我们得到了一致的结果。

结果 2)作为正则化/随机采样反向传播的激活

对于以下所有实验,随机采样仅在 Adam 更新和梯度上执行。(案例 D)。

Training Accuracy Plot (left) Testing Accuracy Plot (right) over 5 episodes

左边显示了所有不同的正则项及其情况。

我们可以注意到,每种方法都给出相似的结果。

STD of Training Accuracy Plot (left) STD of Testing Accuracy Plot (right) over 5 episodes

绘制每集的标准差变得极其混乱,对于这个实验,我不认为它增加了任何有价值的信息。

结果 3)测试集的最高准确度

如上所述,实现最高测试精度的方法是来自随机采样反向传播的情况 E。这是我们随机采样的情况,不仅是梯度,还有 Adam 更新的值和用于测试图像的过滤器的权重。

讨论

多名研究人员发现,注入某种随机噪声最有可能提高泛化能力,因此这多少有些出乎意料的结果。我确实想联系的一件事是,从论文“识别和攻击高维非凸优化中的鞍点问题”可以看出,鞍点是深度神经网络训练时的问题。因为随机采样反向传播总是确保到处都有一点梯度,所以它在避开那些区域方面可能非常有效。

从上面的下降来看,由于随机性,网络可能会逃离其中一个区域。(不是 100%确定)。

对于将激活视为规则,在计划这项研究时,我认为这是一个好主意,并将提高泛化能力,但将特征选择和稀疏性约束分开似乎真的不是一个好主意。

结论/代码

总之,添加随机噪声,无论是以添加还是采样的形式,似乎都有正则化的效果。此外,复合噪声因子似乎是一个好主意,这意味着在几个不同的地方添加噪声。最后,划分特征学习和稀疏性似乎不是一个好主意。(针对泛化和网络性能)。

要访问随机抽样反向传播代码,请点击此处。
要访问代码激活为正规化,请点击这里。
要访问创建图的代码,请点击此处。

所有这一切都有些令人惊讶,但在我的目标范围内,没有什么接近的泛化能力。

最后,我想提一个事实,这些技术都没有数学证明。只有实证结果。所以请对这一切有所保留。

参考

  1. Pixabay 上的自由图像——银河系,宇宙,人,星星。(2019).Pixabay.com。检索于 2019 年 2 月 3 日,来自https://pix abay . com/en/milky-way-universe-person-stars-1023340/
  2. Gastaldi,X. (2017)。抖抖正则化。arXiv.org。检索于 2019 年 2 月 3 日,来自https://arxiv.org/abs/1705.07485
  3. Neelakantan,a .,Vilnis,l .,Le,q .,Sutskever,I .,Kaiser,l .,Kurach,k .,和 Martens,J. (2015 年)。添加梯度噪声改善了对非常深的网络的学习。arXiv.org。检索于 2019 年 2 月 3 日,来自https://arxiv.org/abs/1511.06807
  4. Zucconi,a .,Zucconi,a .,和 Zucconi,A. (2015 年)。如何生成高斯分布数?艾伦·祖科尼。检索于 2019 年 2 月 3 日,来自https://www . alanzucconi . com/2015/09/16/how-to-sample-from-a-Gaussian-distribution/
  5. RELU 市(2019)。要点。检索于 2019 年 2 月 4 日,来自https://gist . github . com/JaeDukSeo/239890 e 40 AC 72705 ed 0 c 82 Fe 25 b 39680
  6. JaeDukSeo/每日神经网络实践 2。(2019).GitHub。2019 年 2 月 4 日检索,来自https://github . com/JaeDukSeo/Daily-Neural-Network-Practice-2/blob/master/Class % 20 stuff/Three % 20 werid % 20 ways/a % 20 things % 20 to % 20 compare % 20(% 20 batch % 20 size % 20100)-copy 1 . ipynb
  7. 权重观点中的正则化[张量流中的手动反向传播]。(2019).走向数据科学。检索于 2019 年 2 月 4 日,来自https://towards data science . com/regulation-in-weights-point-of-view-manual-back-propagation-in-tensor flow-4 FDC 7b 389257
  8. 道芬、y、帕斯卡努、r、古尔切雷、c、乔、k、甘古利、s 和本吉奥(2014 年)。高维非凸优化中鞍点问题的识别与攻击。arXiv.org。检索于 2019 年 2 月 4 日,来自https://arxiv.org/abs/1406.2572

假设检验的第一类和第二类错误:用图表理解

原文:https://towardsdatascience.com/type-i-and-type-ii-errors-of-hypothesis-tests-understand-with-graphs-43079fdd936a?source=collection_archive---------8-----------------------

当我在我的第一堂统计学课上第一次学习假设检验时,我学习了第一类错误(α)和第二类错误(β)的定义。

  • 第一类误差(α,也称为显著性水平):当 H₀(零假设)为真时拒绝它的概率。(假阳性)
  • 置信水平(1 - α):如果要生成许多样本,产生包括真实参数值的准确区间的能力
  • 第二类误差(β):当 H₀为假时拒绝失败的概率。(假阴性)
  • 统计检验的功效(1- β):当 H₀为假时拒绝它的概率

当我们进行假设检验以获得临界值或置信区间时,我们使用α。如果 p 值落在置信区间内,我们不能拒绝零假设,如果它在区间外,我们就拒绝它。

这是一种模式,但我对统计能力或β并没有很好的了解。事实上,假设检验是一种“巡航控制”,只要我知道要进行哪种检验。

但最近我意识到,在实验设计中,假设检验的力量对于理解选择合适的样本量是至关重要的。然后,我被介绍给克里斯托佛·马格努松的关于统计能力和显著性测试的交互式可视化,我终于在脑海中有了一个解释α、β、样本大小和效应大小如何一起工作的画面。

在本文中,我将展示统计功效与α的关系。

树立榜样:

首先让我们先设定解决方案。进行单样本 z 检验的目的是检验总体均值𝜇(未知)是否是一个特定值 m

我们将确定一个正态分布作为总体的分布,使总体均值开始。

人群:从平均和标准偏差分别为 163 磅和 7.2 磅的人的体重中收集的数据。

假设我们正在进行假设单样本 z 检验,以检查给定样本组的总体参数是否为 163 lb。

H₀: 𝜇=163

Hₐ: 𝜇≠163

1.1α和β的关系

Fig.1: β level changes depending on α level: The sum of two red parts represent Type I error and the blue part represent Type 2 error.

根据定义,红色部分的总和代表 I 型误差:当 p 值落入读取部分时,当零假设为真时,我们拒绝 H₀(当群体 PDF 为绿线时)。同样,蓝色部分是第二类误差,当它不成立时,我们接受 H₀(当人口 PDF 是橙色线时)。

看到当 alpha 级别从 0.05 增加到 0.1 时,蓝色部分变小了!你也可以这样想,当你拒绝的多了,不拒绝(拒绝失败)带来的误差就减少了!

1.2 绘图生成

以下是用于绘制图 1 的 python 代码。

备选假设图是从正态分布生成的,平均值为 190 磅,标准偏差为 7.2 磅。

Importing libraries

Setting up the distributions and function to create points to plot PDFs

卷积的类型:可变形和可变换的卷积

原文:https://towardsdatascience.com/type-of-convolutions-deformable-and-transformable-convolution-1f660571eb91?source=collection_archive---------17-----------------------

让 ML 变得有趣

理解可变形和可变换卷积的直观方法

如果你听说过可变形或可变换卷积,并对它们的实际含义感到困惑,那么这篇文章就是为你准备的。我将尝试用直观的方式向你们解释两个不太为人所知但非常有趣的卷积。

假设你已经熟悉标准卷积,我将从以直观(但不常见)的方式介绍标准卷积开始,引出可变形和可变换卷积。

这篇文章的内容包括:

  1. 背景
  2. 可变形卷积
  3. 可变换卷积

1.背景

Figure 1: 2D convolution using a kernel size of 3, stride of 1 and no padding

首先,我们需要理解一个标准的 2D 卷积运算。标准的 2D 卷积在 固定感知场空间位置 对输入应用 2D 滤波器/核,以生成输出特征图。卷积运算中涉及某些参数,如内核大小、步幅和填充。

内核大小:定义卷积的视场。

Stride: 定义内核遍历图像时的步长。

填充:定义如何处理样本的边框。例如,对于步长为 1 的核 3,没有填充将导致下采样。

取样矩阵

标准卷积本质上是在图像上应用采样矩阵来提取输入样本,然后在其上应用核。下图说明了采样矩阵的概念:

Figure 2: 2D convolution using a kernel size of 3, stride of 1 and no padding represented with sampling matrix. Note that sampling matrix is just an overlay over the kernel, defining how the input should be sampled

对于输入中的任何 pₒ位置,采样矩阵(表示为绿色矩形网格)定义了如何从输入中采样点,以应用内核(表示为输入网格上的深蓝色贴图),如图 2 所示。

核的形状可以由中心位置 pₒ和采样位置 pᵢ(与 pₒ.的相对距离)来描述这些取样地点的收集 pₒ,….,pᵢ被称为采样矩阵

输出特征图由核 w 和输入 x 之间的卷积运算生成,可以表示为 y = w * x ,特征图 y 中的每个元素可以计算为:

其中 pₒ是输入样本的中心位置,pᵢ列举了采样点集合中的点(即采样矩阵)。

Figure 3: 2D convolution using a kernel size of 3 and an offset of 2 (dilation = 2). Notice how the offsets are changed in the sampling matrix

给定一个采样矩阵,我们可以改变偏移(pᵢ),以在应用内核的输入中获得任何任意接收域。

在标准卷积运算中,所有方向上的偏移量始终为 1,如图 2 所示。

在另一种类型的卷积中,称为扩张卷积(也称为 atrous 卷积),使用大于 1 的偏移量,允许更大的感受野来应用内核(图 3)。

如果到目前为止你能够理解取样矩阵的概念,理解可变形和可转换卷积在这个阶段应该是非常容易的。但首先让我们谈谈标准卷积运算的一个固有限制。

由于采样矩阵的固定几何结构,CNN 固有地局限于模拟大的未知变换。例如,同一 CNN 层中所有激活单位的感受野大小是相同的。

— 微软亚洲研究院

因为输入特征图中的不同位置可能对应于具有不同尺度或变形的对象,所以对于某些任务来说,尺度或感受野大小的自适应确定是合乎需要的。

例如,在自然语言处理中,使用传统的 CNN 从可变换的和不连续的语言短语中捕获不同的适应性特征提出了巨大的挑战,例如,直接捕获“非……”。短语“差远了”的“好”模式。此外,从不同的转换形式(如“不太好”和“甚至不好”)中捕捉上述模式是困难的。

如果我们可以使采样矩阵适应输入中的要素变换,会怎么样?

可变形和可变换卷积都试图通过引入参数来学习 自适应采样矩阵 (也称为偏移或偏差矩阵,通常表示为 R 或 C)以识别同一模式的各种变换,从而解决上述问题。

1.可变形卷积

变形卷积引入了变形模块的机制,它具有可学习的形状以适应特征的变化。传统上,由采样矩阵定义的卷积中的核和样本的形状从一开始就是固定的。

可变形卷积使得采样矩阵是可学习的,允许核的形状适应输入中未知的复杂变换。让我们看看下图来理解这个概念。[1]

[1] Figure 4: Illustration of the sampling matrix in 3 × 3 standard and deformable convolutions. (a) regular sampling matrix (green points) of standard convolution. (b) deformed sampling locations (dark blue points) with augmented offsets (light blue arrows) in deformable convolution. c & d are special cases of (b), showing that the deformable convolution generalizes various transformations for scale, (anisotropic) aspect ratio and rotation

Figure 5: Deformable convolution using a kernel size of 3 and learned sampling matrix

不像在图 2 的标准卷积中那样使用具有固定偏移的固定采样矩阵,可变形卷积学习具有位置偏移 的 采样矩阵。通过附加的卷积层,从前面的特征图中学习偏移。

因此,变形以局部、密集和自适应的方式取决于输入要素。

为了将此放入等式中,在可变形卷积中,常规采样矩阵 c 增加了偏移{∆pᵢ|n = 1,…,N},其中 N = |C|。

情商。(1)变成

其中,pₒ是输入中样本的中心位置,pᵢ列举了采样/偏移点集合 c 中的点。现在,采样是在不规则和偏移位置 pᵢ + ∆pᵢ上进行的,即内核的采样位置被重新分布,而不再是规则的矩形。

2.可变换卷积

Figure 6: Transformable convolution using a kernel size of 3 and two learned sampling matrices

像可变形卷积一样,可变形卷积也将位置偏移添加到核上,使它们的形状通过采样矩阵变得灵活和可适应。

但是可变换卷积通过将采样矩阵分裂成两个称为 动态和静态偏差 的矩阵来进行下一步。

因此,使用两个已学习的采样矩阵从输入中获取两个样本,并将其相加以获得输出特征图。

动态偏差

在推理阶段,动态偏差与当前输入相关,其值从当前特征中主动学习以捕捉当前变换信息(就像变形卷积中的偏移矩阵)。

静态偏差

静态偏差的值通过反向传播来更新,并在推理状态下保持静态,这描述了形状信息的全局分布。

因此,采样矩阵 C 被分成两部分,一部分与当前特征相关,另一部分与全局相关。让 D𝒸 ⊂ C 和 S𝒸 ⊂ C 分别表示它们。然后,它们被加上不同的偏差/偏移 D𝒸的∆pᵢ和 S𝒸的∆pᵢ,以调整采样位置。

情商。(2)成为

这里,采样也是在不规则和偏移的位置 pᵢ + ∆pᵢ和 pᵢ + ∆pᵢ上进行的,即内核的采样位置是重新分布的,并且不是矩形的。但不是一个,而是两个样本,一个基于静态偏差矩阵,另一个基于动态偏差矩阵。然后对两个样本进行核卷积,并将结果相加,以获得输出特征图中的元素。

我希望这篇文章能让你更容易对这两个卷积有一个直观的理解,并作为你学习/研究的有用参考。

感谢您阅读这篇文章..如果您有任何困惑,请随时在下面留下问题和评论。

参考

[1]【戴,齐,熊,李,张,胡,魏,可变形卷积网络(2017),微软亚洲研究院

[2] 戴,齐,熊,李,张,胡,魏,可转换卷积神经网络用于文本分类(2018),国际人工智能联合会议(IJCAI)

卷积核的类型:简化

原文:https://towardsdatascience.com/types-of-convolution-kernels-simplified-f040cb307c37?source=collection_archive---------1-----------------------

对迷人的 CNN 层的不同变化的直观介绍

简单介绍一下

卷积使用“内核”从输入图像中提取某些“特征”。让我解释一下。核是一个矩阵,它在图像上滑动并与输入相乘,从而以某种期望的方式增强输出。请看下面的实际操作。

例如,上面使用的内核对于锐化图像很有用。但是这个内核有什么特别之处呢??考虑两种输入图像排列,如下例所示。对于第一幅图像,中心值为 35 + 2-1 + 2-1 + 2-1 + 2-1 = 7。值 3 增加到 7。对于第二幅图像,输出为 15+ 2-1 + 2-1 + 2-1 + 2-1 = -3。值 1 减小到-3。很明显,3 和 1 之间的对比度增加到 7 和-3,这又会使图像变得清晰。

通过深度细胞神经网络,我们可以学习这些能够提取潜在特征的核值,而不是使用手工制作的核进行特征提取。为了进一步了解传统 CNN 的工作,我推荐这个博客。

[## 直观理解用于深度学习的卷积

探索让它们工作的强大的视觉层次

towardsdatascience.com](/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1)

内核与过滤器

在我们深入讨论之前,我只想弄清楚“内核”和“过滤器”这两个术语之间的区别,因为我见过很多人互换使用它们。如前所述,核是权重矩阵,与输入相乘以提取相关特征。核矩阵的维数是卷积如何得到它的名字。例如,在 2D 卷积中,核矩阵是 2D 矩阵。

然而,滤波器是多个内核的级联,每个内核被分配给输入的特定通道。过滤器总是比内核多一个维度。例如,在 2D 卷积中,滤波器是 3D 矩阵(本质上是 2D 矩阵即核的串联)。因此,对于具有核维数 hw 和输入通道 k 的 CNN 层,滤波器维数为 kh*w。

一个公共卷积层实际上由多个这样的滤波器组成。为了下面讨论的简单起见,除非特别说明,否则假设只存在一个过滤器,因为相同的行为在所有过滤器上重复。

1D、2D 和三维卷积

1D 卷积通常用于时间序列数据分析(因为在这种情况下的输入是 1D)。如前所述,1D 数据输入可以有多个通道。滤光器只能在一个方向上移动,因此输出是 1D。见下面一个单通道 1D 卷积的例子。

我们已经在本文开头看到了一个单通道 2D 卷积的例子,所以让我们来想象一个多通道 2D 卷积,并试着理解它。在下图中,内核尺寸为 3*3,过滤器中有多个这样的内核(标记为黄色)。这是因为输入中有多个通道(标记为蓝色),并且我们有一个对应于输入中每个通道的内核。显然,这里的滤波器可以在两个方向上移动,因此最终输出是 2D。2D 卷积是最常见的卷积,在计算机视觉中被大量使用。

很难将 3D 滤波器可视化(因为它是 4D 维矩阵),所以我们将在这里讨论单通道 3D 卷积。正如你从下图中看到的,在 3D 卷积中,一个内核可以在 3 个方向上移动,因此得到的输出也是 3D 的。

在修改和定制 CNN 层中所做的大部分工作都只集中在 2D 卷积上,所以从现在开始,我将只讨论 2D 卷积环境中的这些变化。

转置卷积(去卷积)

下面的 GIF 很好地捕捉了 2D 卷积如何降低输入的维数。但有时我们需要做输入处理,例如增加它的尺寸(也称为“上采样”)。

为了使用卷积实现这一点,我们使用了一种称为转置卷积或反卷积的修改(尽管它并不是卷积运算的真正“反转”,所以很多人不喜欢使用这个术语)。下面 GIF 中的虚线块代表填充。

我认为这些动画给出了一个很好的直觉,如何基于填充模式从相同的输入创建不同的上采样输出。这种卷积在现代 CNN 网络中非常常用,主要是因为它们能够增加图像尺寸。

可分卷积

可分离卷积指的是将卷积核分解成低维核。可分卷积有两种主要类型。首先是空间上可分离的卷积,例如见下文。

A standard 2D convolution kernel

Spatially separable 2D convolution

然而,空间可分离的卷积在深度学习中并不常见。另一方面,深度方向可分离卷积被广泛应用于轻量级 CNN 模型,并提供了非常好的性能。例如,见下文。

A standard 2D convolution with 3 input channels and 128 filters

Depthwise separable 2D convolution which first processes each channel separately and then applies inter-channel convolutions

但是为什么可分卷积? 效率!!使用可分离卷积可以显著减少所需的参数数量。随着我们今天拥有的深度学习网络的日益复杂和巨大规模,能够以更少的参数提供类似的性能无疑是一个要求。

扩张(阿特鲁)卷积

正如你在上面的所有卷积层中看到的(无一例外),它们一起处理所有相邻的值。然而,有时跳过某些输入值可能对流水线最有利,这就是膨胀卷积(也称为 atrous 卷积)的引入方式。这样的修改允许内核在不增加参数数量的情况下增加它的视图范围

很明显,从上面的动画中我们可以注意到,内核能够使用与之前相同的 9 个参数处理更宽的邻域。这也意味着信息的丢失,因为不能处理细粒度的信息(因为它跳过了某些值)。然而,在某些应用中,总体效果似乎是积极的。

可变形卷积

就特征提取的形状而言,卷积是非常严格的。也就是说,内核形状只是正方形/长方形(或者其他需要人工决定的形状),因此它们只能在这种模式上工作。如果卷积的形状本身是可以学习的呢?这是引入可变形卷积的核心理念。

可变形卷积的实现实际上非常简单。每个内核实际上都用两个不同的矩阵来表示。第一个分支学习预测从原点的“偏移”。该偏移量表示原点周围的哪些输入将被处理。由于每个偏移都是独立预测的,它们之间不需要形成任何刚性形状,因此允许可变形的性质。第二个分支只是卷积分支,其输入现在是这些偏移处的值。

下一步是什么?

已经有了 CNN 层的多种变体,这些变体已经被独立使用或者相互结合使用来创建成功且复杂的架构。每一种变化都源于对特征提取应该如何工作的直觉。因此,我相信,虽然这些深度 CNN 网络学习我们无法解释的权重,但形成它们的直觉对它们的性能非常重要,在那个方向上的进一步工作对高度复杂的 CNN 的成功非常重要。

这个博客是努力创建机器学习领域简化介绍的一部分。点击此处查看完整系列

[## 机器学习:简化

在你一头扎进去之前就知道了

towardsdatascience.com](/machine-learning-simplified-1fe22fec0fac)

或者只是阅读系列的下一篇博客

[## 分布式矢量表示:简化

可以说是机器学习中最基本的特征表示方法

towardsdatascience.com](/distributed-vector-representation-simplified-55bd2965333e)

参考

克里热夫斯基、亚历克斯、伊利亚·苏茨基弗和杰弗里·e·辛顿。"使用深度卷积神经网络的图像网络分类."神经信息处理系统进展。2012.
[2]杜默林、文森特、弗朗切斯科·维辛。"深度学习卷积算法指南."arXiv 预印本 arXiv:1603.07285 (2016)。
[3]陈,梁杰,等.“Deeplab:基于深度卷积网、atrous 卷积和全连通条件随机场的语义图像分割”IEEE 模式分析与机器智能汇刊 40.4(2017):834–848。
[4]戴,季峰,等.“可变形卷积网络”IEEE 计算机视觉国际会议论文集。2017.
[5] Howard,Andrew G .等,“移动网络:用于移动视觉应用的高效卷积神经网络”arXiv 预印本 arXiv:1704.04861 (2017)。
【6】

数据科学、数据挖掘和机器学习中的数据集类型

原文:https://towardsdatascience.com/types-of-data-sets-in-data-science-data-mining-machine-learning-eb47c80af7a?source=collection_archive---------2-----------------------

以及它们的一般特征…

Video version of the story, if you are into that sort of thing

我之前的一篇 中,我讲过什么是数据以及数据属性是什么意思。这个就继续那个,如果还没看的话,这里看一下以便对我在文章中要讲的话题和概念有一个恰当的把握。

请原谅我的概念性部分,我知道这可能有点无聊,但如果你有强大的基础,那么没有什么可以阻止你成为一名伟大的 数据科学家 机器学习工程师

T 这里有数据集的三个一般特征,即:维数、稀疏度、分辨率。我们将一次一个地讨论它们到底是什么意思。****

什么是维度?****

→数据集的维度是数据集中的对象所具有的属性的数量。

在一个特定的数据集中,如果有大量的属性(也称为高维数),那么分析这样一个数据集会变得困难。当面对这个问题时,它被称为维数灾难。****

为了理解这个维数灾难到底是什么,我们首先需要理解数据的另外两个特征。

什么是稀疏性?****

→对于某些数据集,如具有非对称特征的数据集,一个对象的大多数属性的值为 0;在许多情况下,不到 1%的条目是非零的。这样的数据称为稀疏数据或者可以说数据集具有稀疏性。****

什么是分辨率

→数据中的模式取决于分辨率水平。如果分辨率太精细,图案可能不可见或者可能被淹没在噪声中;如果分辨率太粗糙,图案可能会消失。例如,以小时为单位的大气压力变化反映了风暴和其他天气系统的运动。在几个月的时间里,这种现象是无法察觉的。

现在,回到维数灾难,这意味着随着数据集的维数(数据集中属性的数量)增加,许多类型的数据分析变得困难。具体来说,随着维度的增加,数据在其占据的空间中变得越来越稀疏。对于分类,这可能意味着没有足够的数据对象来允许创建一个模型,该模型可靠地将类别分配给所有可能的对象。对于聚类来说,对聚类至关重要的密度和点之间距离的定义变得不那么有意义了。

F 最后,根据数据集的类型,我们将其定义为三个类别,即记录数据、有序数据。让我们一次看一个。****

记录数据

Introduction to Data Mining — Pang-Ning Tan, Michael Steinbach, Vipin Kumar

→大多数数据挖掘工作假设数据是记录(数据对象)的集合。

→记录数据最基本的形式,记录或数据字段之间没有明确的关系,每条记录(对象)都有相同的属性集。记录数据通常存储在平面文件或关系数据库中。

****记录数据有一些变化,有一些特征属性。

  1. ****交易或购物篮数据:是一种特殊类型的记录数据,其中每条记录包含一组项目。例如,在超市或杂货店购物。对于任何特定的客户,记录将包含客户在相应的超市或杂货店访问中购买的一组商品。这种类型的数据称为市场篮子数据。交易数据是一组项目的集合,但可以看作是一组字段为非对称属性的记录。大多数情况下,这些属性是二进制的,表示一个商品是否被购买。
  2. ****数据矩阵:如果数据集合中的数据对象都具有相同的固定数值属性集,那么数据对象可以被认为是多维空间中的点(向量),其中每个维度表示描述对象的不同属性。一组这样的数据对象可以被解释为一个 m×n 矩阵,其中有 n 行(每个对象一行)和 n 列(每个属性一列)。可以应用标准的矩阵运算来转换和处理数据。因此,数据矩阵是大多数统计数据的标准数据格式。
  3. ****稀疏数据矩阵:稀疏数据矩阵(有时也称为文档-数据矩阵)是数据矩阵的一种特殊情况,其中属性是相同类型的并且是非对称的;即,只有非零值是重要的。

基于图表的数据

Introduction to Data Mining — Pang-Ning Tan, Michael Steinbach, Vipin Kumar

这可以进一步分为以下类型:

  1. ****具有对象间关系的数据:数据对象被映射到图的节点,而对象间的关系由对象间的链接和链接属性捕获,例如方向和权重。考虑万维网上的网页,它包含文本和到其他网页的链接。为了处理搜索查询,网络搜索引擎收集和处理网页以提取它们的内容。
  2. ****对象为图的数据:如果对象有结构,即对象包含有关系的子对象,那么这样的对象经常被表示为图。例如,化学化合物的结构可以用图来表示,图中的节点是原子,节点之间的链接是化学键。

有序数据

Introduction to Data Mining — Pang-Ning Tan, Michael Steinbach, Vipin Kumar

对于某些类型的数据,属性具有涉及时间或空间顺序的关系。如上图所示,它可以分为四种类型:

  1. ****顺序数据:也称为时态数据,可以认为是记录数据的扩展,其中每个记录都有一个与之相关联的时间。考虑一个零售交易数据集,它也存储交易发生的时间
  2. ****序列数据:序列数据由一个数据集组成,该数据集是一个单个实体的序列,例如一个单词或字母的序列。它与顺序数据非常相似,只是没有时间戳;相反,在有序的序列中有位置。例如,植物和动物的遗传信息可以以被称为基因的核苷酸序列的形式来表示。
  3. ****时间序列数据:时间序列数据是一种特殊类型的序列数据,其中每条记录都是一个时间序列,即一段时间内的一系列测量值。例如,金融数据集可能包含各种股票每日价格的时间序列对象。
  4. ****空间数据:有些对象有空间属性,比如位置或者面积,还有其他类型的属性。空间数据的一个例子是为各种地理位置收集的天气数据(降水、温度、气压)。

这篇关于数据集类型的文章到此结束。

这个帖子的后续是这里。

** [## 评估数据质量

对于数据挖掘和机器学习算法…

towardsdatascience.com](/assessing-the-quality-of-data-e5e996a1681b)**

我将免费赠送一本关于一致性的电子书。在这里获得你的免费电子书。

如果你喜欢阅读这样的故事,那么你应该 在你的收件箱 中收到我的帖子,如果你想支持我成为一名作家,考虑注册成为一名媒体成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你注册使用我的链接,我会赚一小笔佣金,不需要你额外付费。

** [## 加入我的推荐链接-塔伦古普塔

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

tarun-gupta.medium.com](https://tarun-gupta.medium.com/membership)

感谢阅读。如果你喜欢这篇文章,请访问我在这里的其他文章:

[## 标记故事列表的快速链接—感谢您的访问

我也有一份以快节奏出版为目标的出版物。读书成为作家。

tarun-gupta.medium.com](https://tarun-gupta.medium.com/thank-you-for-visiting-my-profile-9f708062c75e)**

神经网络的类型(以及每种类型的作用!)解释道

原文:https://towardsdatascience.com/types-of-neural-network-and-what-each-one-does-explained-d9b4c0ed63a1?source=collection_archive---------2-----------------------

有大量的神经网络具有吸引人的特性。以下是最著名的几个。

机器学习是人工智能的一个子集,它结合神经网络来创建一些我们日常使用的令人惊叹的软件。

如果你用谷歌找到这篇中型文章,你用的是谷歌的神经网络,它会根据你给的关键词对最相关的页面进行排序。如果你最近去了 Amazon.com,该网站向你推荐的所有产品都是由神经网络策划的。即使在今天,如果你使用手机,你可能会遇到一个神经网络,让你的生活变得更容易。它就在我们身边,它们都做着不同的事情,以不同的方式工作。

那么……什么是“神经网络”

“神经”这个词只是大脑的另一种说法。“那么这是一个 大脑 网络?”本质上,完全!神经网络是我们最强大的工具——大脑的简化。它使用的神经元都是通过权重相互连接的(下图中的线)。给神经元一些数字输入,并乘以权重。权重是神经网络的核心,通过将它们更改为特定的数值,我们可以处理任何输入并获得所需的输出。神经网络只是处理数据的一种方式。数据是🔑在这里,通过各种神经网络操纵数据…我们可以建立非常强大的工具,做一些疯狂的事情!

感知器——最古老的&最简单的神经网络

感知器是最古老的神经网络,创建于 1958 年。也是最简单的神经网络。由 Frank Rosenblatt 开发的感知机为神经网络的基础奠定了基础。

这个神经网络只有一个神经元,因此非常简单。它取 n 个数量的输入并乘以相应的权重。它只计算一个输出。它的缺点是缺乏复杂性,因为它只能处理一种复杂程度的数据。

使用案例:

  • 了解人类大脑
  • 针对更高级的神经网络进行扩展

多层感知器——什么是层?

多层感知器(MLP)仍然是一个感知器,但是通过的出现增加了复杂性。MLP 中有三种类型的图层:

输入图层:

输入层就是它听起来的样子,你输入到神经网络的数据。输入数据必须是数字。这意味着你可能需要一些非数字的东西,并找到一种方法把它变成数字。在将数据输入到神经网络之前处理数据的过程被称为数据 处理,通常情况下,这将是制作机器学习模型最耗时的部分。

隐藏图层:

隐藏层由神经网络中的大多数神经元组成,是操纵数据以获得所需输出的核心。数据将通过隐藏层,并受到许多权重和偏见的操纵。它被称为“隐藏”层,因为与输入和输出层相反,神经网络的开发人员不会直接使用这些层。

输出层:

输出层是处理神经网络中的数据的最终产品,可以表示不同的事物。通常,输出层由神经元组成,每个神经元代表一个对象,附加的数值是它是该特定对象的概率。其他时候,它可能是一个神经元输出,当给定某些输入时,它就是某个东西的值。主要思想是输出层是数据通过神经网络时的结果,也是我们试图达到的目标。

前馈本金:

这个想法是,我们将数字数据传递到网络中,它继续向前进行许多操作。我们向前输送数据。为了获得正确的操作,使得任何给定的输入总是产生期望的输出,需要训练。训练本质上是找到产生最佳结果的东西,并将它们应用到网络中。

使用案例:

  • 计算机视觉
  • 自然语言处理
  • 其他神经网络的基础

卷积神经网络—卷积层?

卷积神经网络仍然使用 MLP 使用的相同原理,但是该神经网络实现卷积层。值得注意的是,卷积神经网络通常用于图像和视频。

重要的是要认识到,图像只是一个数字网格,每个数字都告诉你某个像素有多强烈。知道了这是一个数字网格,我们就可以操纵这些数字来寻找图像的模式和特征。卷积层通过使用滤波器来实现这一点。

过滤器

滤镜是一个定义的 N x M (N & M 代表网格的大小)的数字网格,它与原始图像相乘多次。要了解实际发生的情况,请参考动画。

过滤器在网格中移动并产生新值。这些新值可以表示图像中的边缘或线条。例如,以下面的过滤器为例:

水平过滤器试图消除垂直中心以外的值。它通过使用负值来去除边缘,使用 0 表示中心来使像素保持中性。如果过滤成功,您将能够从新值中看到一条水平线。对于刚刚反转的垂直滤波器也是如此。

在整个图像中应用过滤器后,我们可以使用合并层轻松提取过滤器发现的主要特征。在训练模型时,确定哪些数字应该出现在过滤器中。弄清楚什么是最好的数字将为整个任务带来最好的结果。

汇集层

池层做他们听起来像的事情。它们将过滤器发现的最重要的特征“汇集”在一起。这是通过使用多种方法完成的。一种流行的方法是 Max Pooling,对于图像的每个过滤部分,取最大的数字并存储到新的网格中。这基本上是把最重要的特征压缩成一幅图像,以便处理成 MLP。这个过程也可以称为数据采样,使用这个过程会产生非常有希望的结果。

用例

  • 图像分类
  • 计算机视觉
  • 在图像中寻找特征/模式

递归神经网络——时态数据?

我们可以用神经网络分析的数据并不完全局限于静态数据。像图像、数字、帧这些东西,都是可以自己分析的数据。然而,依赖于自身的过去实例来预测未来的数据是时态数据的例子。像股票市场数据、时间序列数据、脑波数据等总是通过使用因变量的过去实例来分析。到目前为止,提到的神经网络没有处理数据的其他状态,但是 RNNs 是解决方案。

状态矩阵

rnn 通过将最后一次输出存储在自己的存储器中来记住以前的数据状态。这些被称为状态矩阵。它的工作方式类似于 MLP 中的普通图层,但它使用状态矩阵来计算新的输出。使用以前的输出和数据状态实质上是考虑最终输出中的数据。这对于股票市场预测和时间序列预测等应用至关重要。

LSTMs

长短期记忆网络进一步扩展了将状态矩阵保存为两种状态的思想。有长期状态和短期状态。如果一个状态持续存在于模型输出中,它将成为一个长期的状态矩阵,并且在考虑新数据时会更有分量。

LSTM 系统在发现连续数据的模式时非常有效,是股市预测的先锋。

用例

  • 自然语言处理
  • 股票市场预测
  • 基于时间的数据预测

自动编码器——以压缩方式表示数据

大多数神经网络接收数据并做出某些类型的决策。自动编码器有一个不同的任务,那就是找出一种方法来压缩数据,但保持相同的质量。

传统上,在机器学习中,附加到我们数据上的标签是不同的,并且是神经网络要产生的目标。在自动编码器中,标签与输入相同。

因此,在这种架构中,您有一个相同的输入和输出层。隐藏层比输入和输出层小(就节点而言),被称为【瓶颈】。由于瓶颈变小了,被迫想办法压缩原始数据,放回输出层。这种压缩通常比传统方法更好,因为它仍然可以保持高质量。

用例:

  • 主要用于以较小的压缩方式表示大量数据。

关键要点

多层感知器

  • 基本神经网络
  • 用于简单的任务

卷积神经网络

  • 使用过滤器和池来查找数据中的特征
  • 主要用于图像任务

递归神经网络

  • 使用以前的数据结果来计算新的输出
  • 用于时态数据

自动编码器

  • 一种无损质量的压缩数据的新方法

2014 年台风“红宝石”:情绪分析

原文:https://towardsdatascience.com/typhoon-ruby-2014-a-sentiment-analysis-a1a630a95ebb?source=collection_archive---------20-----------------------

基于潜在狄利克雷分析的脸书评论情感分类

高中时,我和格里·巴格塔萨博士一起做过短期实习,他是菲律宾迪利曼大学环境科学和气象研究所的教授。他的项目包括发现在脸书的菲律宾人在跟踪台风“红宝石”(2014 年)时对气象局(PAGASA)发布的更新的反应。

我们从菲律宾大气、地球物理学和天文学服务管理局发布的 23 条脸书天气更新中收集了 2300 条评论,这些更新追踪了台风“鲁比”袭击菲律宾的路径。由于对 Python 一无所知,我和一个实验室伙伴(Derrick)花了两周时间费力地将这些评论逐一分类。

Derrick hard at work on our tiny laptops

菲律宾的台风

菲律宾的季风季节很疯狂。每年六月到八月都会带来一连串的大雨、疯狂的洪水,以及被倒下的树木和电线阻塞的道路等等。台风“红宝石”是 2014 年菲律宾最严重的台风之一,夺去了 18 条生命,916 人受伤,造成 50.9 亿菲律宾比索(1.14 亿美元)的损失。尽管该国在备灾方面取得了长足进步,但仍有许多工作要做——其中一个方面是信息传播和反馈。脸书在菲律宾是一个极其强大的工具,近 98.6%的互联网用户都在这个社交媒体平台上。因此,这是一个很好的途径,可以找到市民需要的关于台风的更新/信息,并随着台风的展开收集用户提供的任何信息。

https://www.thesummitexpress.com/2014/12/typhoon-ruby-speeds-up-to-make-landfall-tonight-in-dolores-eastern-samar.html

方法

我们最近在课堂上讨论了主题模型,从此我的生活发生了变化(开玩笑)。但在此之前,一些数据清洗。

与菲律宾人打交道时,困难的是人们想出一堆同一个单词的缩写,以及许多其他创造性的拼写方法。例如,“thanks”的拼写是“thx”、“tnx”和“thanxs”(我妈妈也这么做)。因为模式多种多样,我把单词分类,集中在更常用的上,然后编辑它们。

我删除了 25 个最常用的词,目的是删除文章,但是像“上帝”、“主”、“阿门”和“祈祷”这样的词最终出现在列表中——我手动删除了这些词。这表明宗教和祈祷是评论中的一个主题。

然后,我使用类中的代码生成了单词集,它将每个评论总结为一个关键字及其对应计数的列表。举个例子,

**Comment**: '**Rosnel Amuan** lord pls help our country to be safe amen'
**Corpus**: [(58, 1), (107, 1), (61, 1), (37, 1), (86, 1), (87, 1)]
**Vocab List**: 58: 'lord', 107: 'pls', 61: 'help', 37: 'our', 86: 'country', 87: 'safe'

潜在的狄利克雷分配(以及我对它的解释)

然后我使用 Python 中的 gensim 包运行了潜在的狄利克雷分配(LDA)。LDA 是一种算法,旨在揭示一些文档共有的潜在主题或主题,在我们的情况下是 FB 评论。LDA 要求我们指定我们期望它生成的主题数量。我最初选择了 6,因为我们在进行手动分类时提出了六个一般主题供评论,但后来经过微调和重新运行模型,结果证明 7 产生了更明智的单词列表。

该算法首先通过随机给每个单词分配一个主题(用一个数字表示)来猜测哪些单词属于哪些主题。

然后,该算法通过计算每个可能主题的分数来更新对每个单词的猜测。分数是两个概率的乘积:

  • #1: 主题出现在该文档中的概率(即,基于我的文档是关于什么的,这个单词很有可能与主题 x 相关联吗?)
  • #2: 该单词属于某个主题的概率(即,基于该单词在其他文档中被分类的主题,该单词被分类为主题 x 的可能性大吗?)

具有最高分数的主题被分配给该单词,并且对所有单词重复这一过程,直到主题的分配不再改变(即,它们的概率已经收敛到某个后验概率)。这是因为单词对主题的分配不断翻转,直到单词最终开始为特定主题累积越来越高的分数。这个分数影响相同单词在其他文档中的分配,这又进一步增加了单词 w 属于其主题的概率。

评估

LDA 根据主题对脸书的评论进行了总结。例如,“上帝请帮助拯救我的同胞”可能被归类为 75%关于 宗教25%关于菲律宾同胞。我选择了构成大部分评论的主题——所以在这种情况下,评论将被归类为关于宗教

然后我把它和我和德里克最初做的分类进行了比较。因为这六个分类在手动分类下被分成更具体的类别,所以我将它们汇总起来,并查看它们与模型预测的对比情况。

结果

该算法得出了这六组单词,每组代表一个主题:

Look at all this Taglish!

根据单词和以前的分类,我将主题分类如下:

  1. 宗教/安全/菲律宾人:因加特(保持安全),卡巴延(国人),迪奥斯&潘吉诺恩(神),玛丽(圣母玛利亚)
  2. 宗教:上帝,主,保护,祈祷,帮助
  3. 请求更新:更新,信息,天气,信号,时速,风,?(问号说了很多!)
  4. 害怕/求饶:有,仁慈,耶稣
  5. 有希望的 : sana(有希望),pagasa(希望)
  6. 更新:胡米娜(减弱,如“台风减弱”),登陆,上午,
  7. 祈祷/家庭:祈祷、祈祷、拯救、家庭

然后生成了下表

Someone asked to send more typhoons?

综上所述,这些是我们获得的主题

估价

不可否认,这个模型没有我希望的那么好。这是我们之前进行的手动分类的总结

分布差异很大,分类为其他的评论有多个。发生这种情况是因为我们能够手动确定不属于这些一般类别的许多其他主题,但是,这些主题出现的频率不够高,模型无法充分提取它们。

在排除其他下的评论后,我发现该模型给出的准确率为 48.78% 。按主题分类,我们看到宗教评论分类更准确——因为它们有与主题相关的非常独特的关键词(“祈祷”、“主”、“潘吉诺恩”等)。),而像更新害怕/求饶这样的主题是由其他句子或评论使用的相同单词构成的,可能更难分类。

Religious:                  70.6
Prayers/Family:             67.1
Religious/Safety/Filipinos: 64.9
Hopeful:                    54.4
Asking for Updates:         45.5
Scared/Asking for Mercy:    13.6
Giving Updates:             12.7

下一步是什么

虽然这个模型没有我希望的那么好,但我希望使用其他模型(可能是嵌入)重新进行分析。主题模型在 NLP 中的应用相当惊人,我期待着将它们应用到其他数据集。

附录

点击查看代码

UNet

原文:https://towardsdatascience.com/u-net-b229b32b4a71?source=collection_archive---------2-----------------------

在分段中引入对称性

介绍

视觉是人类拥有的最重要的感官之一。但是你有没有想过这个任务的复杂性?捕捉反射光线并从中获取意义的能力是一项非常复杂的任务,但我们却轻而易举地做到了。由于数百万年的进化,我们开发了它。那么如何才能在极短的时间内赋予机器同样的能力呢?对于计算机来说,这些图像只不过是矩阵,理解这些矩阵背后的细微差别多年来一直是许多数学家的困扰。但是在人工智能,特别是 CNN 架构出现之后,研究取得了前所未有的进展。许多以前被认为是不可触及的问题现在显示出惊人的结果。

一个这样的问题是图像分割。在图像分割中,机器必须将图像分割成不同的片段,每个片段代表一个不同的实体。

Image Segmentation Example

正如你在上面看到的,图像是如何变成两段的,一段代表猫,另一段代表背景。从自动驾驶汽车到卫星,图像分割在许多领域都很有用。也许其中最重要的是医学成像。医学图像中的微妙之处非常复杂,有时甚至对训练有素的医生来说也是一个挑战。能够理解这些细微差别并识别必要区域的机器可以在医疗保健领域产生深远的影响。

卷积神经网络在简单的图像分割问题上给出了不错的结果,但在复杂的问题上没有取得任何进展。这就是 UNet 出现的原因。UNet 最初是专门为医学图像分割而设计的。它显示出如此好的效果,以至于后来它被用于许多其他领域。在本文中,我们将讨论 UNet 为什么以及如何工作。如果你不知道 CNN 背后的直觉,请先阅读这个。你可以在这里查看 UNet 在行动。

UNet 背后的直觉

CNN 背后的主要思想是学习图像的特征映射,并利用它来进行更细致的特征映射。这在分类问题中很有效,因为图像被转换成进一步用于分类的向量。但是在图像分割中,我们不仅需要将特征映射转换成一个向量,还需要从这个向量中重建图像。这是一项艰巨的任务,因为将矢量转换成图像比反过来要困难得多。UNet 的整个理念就是围绕这个问题展开的。

在将图像转换为矢量时,我们已经学习了图像的特征映射,那么为什么不使用相同的映射将其再次转换为图像呢?这是 UNet 背后的配方。使用用于收缩的相同特征映射将向量扩展为分割图像。这将保持图像的结构完整性,从而极大地减少失真。让我们更简单地了解一下架构。

UNet 架构

UNet 如何工作

UNet Architecture

该建筑看起来像一个“U”形,名副其实。这个架构由三个部分组成:收缩部分、瓶颈部分和扩展部分。收缩段由许多收缩块组成。每个块接受一个输入,应用两个 3×3 卷积层,然后是一个 2×2 最大池。每个块之后的核或特征图的数量加倍,以便架构可以有效地学习复杂的结构。最底层介于收缩层和膨胀层之间。它使用两个 3X3 CNN 层,然后是 2X2 up 卷积层。

但是这个架构的核心在于扩展部分。类似于收缩层,也是由几个膨胀块组成。每个模块将输入传递到两个 3X3 CNN 层,然后是一个 2×2 上采样层。此外,在每个块之后,卷积层使用的特征图的数量减半以保持对称性。然而,每次输入也得到相应收缩层的附加特征图。这个动作将确保在收缩图像时学习的特征将被用于重建图像。扩展块的数量与收缩块的数量相同。之后,所得到的映射通过另一个 3X3 CNN 层,其特征映射的数量等于期望的分段数量。

UNet 中的损失计算

在这种固有图像分割中,人们会使用哪种损失?好吧,它在论文中被简单地定义了。

结合交叉熵损失函数,通过在最终特征图上的逐像素软最大值来计算能量函数

UNet 为每个像素使用了一种相当新颖的损失加权方案,使得在分割对象的边界处具有较高的权重。这种损失加权方案有助于 U-Net 模型以不连续的方式分割生物医学图像中的细胞,从而可以在二进制分割图中轻松识别单个细胞。

首先对合成图像应用逐像素的 softmax,然后应用交叉熵损失函数。所以我们将每个像素分为一类。这个想法是,即使在分割中,每个像素都必须位于某个类别中,我们只需要确保它们确实如此。因此,我们只是将一个分割问题转化为一个多类分类问题,与传统的损失函数相比,它表现得非常好。

联合国网络的实施

我使用 Pytorch 框架实现了 UNet 模型。你可以在这里 查看 UNet 模块 。使用用于具有糖尿病性黄斑水肿的光学相干断层扫描图像的分割的图像。你可以在这里查看正在运行的 UNet。

上面代码中的 UNet 模块代表了 UNet 的整个架构。contraction_blockexpansive_block分别用于创建收缩段和扩张段。函数crop_and_concat将收缩层的输出与新的扩展层输入相加。训练部分可以写成

unet = Unet(in_channel=1,out_channel=2)
#out_channel represents number of segments desired
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(unet.parameters(), lr = 0.01, momentum=0.99)
optimizer.zero_grad()       
outputs = unet(inputs)
# permute such that number of desired segments would be on 4th dimension
outputs = outputs.permute(0, 2, 3, 1)
m = outputs.shape[0]
# Resizing the outputs and label to caculate pixel wise softmax loss
outputs = outputs.resize(m*width_out*height_out, 2)
labels = labels.resize(m*width_out*height_out)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()

结论

图像分割是一个重要的问题,每天都有新的研究论文发表。联合国教育网在此类研究中做出了重大贡献。许多新的建筑都受到了 UNet 的启发。但是仍然有太多的东西需要探索。行业中有如此多的这种架构的变体,因此有必要理解第一种变体,以便更好地理解它们。因此,如果您有任何疑问,请在下面评论或参考资源页面。

资源

  • UNet 原稿
  • UNet Pytorch 实施
  • UNet Tensorflow 实施
  • 关于语义分割的更多信息
  • 实用图像分割

作者说明

这篇教程是我的系列文章中的第二篇。如果你喜欢这个教程,请在评论中告诉我,如果你不喜欢,请在评论中简单告诉我。如果你有任何疑问或批评,请在评论中大量发表。我会尽快回复你。如果你喜欢这个教程,请与你的同伴分享。

灰度图像的 U-Net 深度学习着色

原文:https://towardsdatascience.com/u-net-deep-learning-colourisation-of-greyscale-images-ee6c1c61aabe?source=collection_archive---------11-----------------------

本文描述了使用深度学习训练神经网络从单通道灰度图像生成 3 通道彩色图像的实验。在我看来,尽管结果因主题不同而不同,但却令人震惊,因为模特会对原始主题应该是什么颜色产生幻觉。

Enhancement of a Greyscale 1 channel image to a 3 channel colour image.

Div2k(https://data.vision.ee.ethz.ch/cvl/DIV2K/)训练数据集用于训练,本文中的这些图像基于 Div2k 验证集。

这是基于 Fastai 深度学习课程中建议和教授的技术。

尝试给灰度图像上色的灵感来自于一位来自 Fastai 学生/校友的 GAN critic 训练的模型,Jason Antic 和他的去灰度化模型:【https://github.com/jantic/DeOldify】T2

该方法使用以下内容:

  • 一种交叉连接的 U-Net 架构,类似于 DenseNet
  • 一个基于 ResNet 的编码器和一个基于 ResNet 的解码器
  • 用 ICNR 初始化进行像素混洗放大
  • 基于来自 VGG-16 模型的激活、像素损失和克矩阵损失的损失函数
  • 从预训练的 ImageNet 模型进行迁移学习

这个模型或数学函数有超过 4000 万个参数或系数。

损失函数真正使最终模型的预测如此之好,允许模型中的可训练参数接近最佳值。这几乎与我的超分辨率实验中使用的损失函数相同。

通过使用在训练期间是静态的损失函数,而不是作为生成对抗网络(GAN)的变化,critic 允许更快地收敛到给定架构的接近最优的训练模型。

Examples of this model’s enhancement of Greyscale 1 channel images to 3 channel colour images.

Examples of this model’s enhancement of Greyscale 1 channel images to 3 channel colour images.

架构细节

基于 U-Net 的学习器和特征损失函数的体系结构相当复杂,因为它是其背后的推理。由于这些是我在不同实验中使用的架构和损失函数,我将它们分成两篇文章:

基于 U-Net 的模型架构:
https://towardsdatascience . com/u-nets-with-resnet-encoders-and-cross-connections-d8ba 94125 a2c

用于训练网络的特征损失函数:https://towardsdatascience . com/loss-functions-based-on-feature-activation-and-style-loss-2f 0 b 72 FD 32 a 9

ResNet-34 编码器

ResNet-34 是一个 34 层 ResNet 架构,它被用作 U-Net(U 的左半部分)的下采样部分中的编码器。

解码器

在将 ResNet-34 编码器转换为具有交叉连接的 U-Net 的情况下,Fastai 动态 U-Net 学习器在配备有编码器架构时将自动构建 U-Net 架构的解码器端。

预训练编码器

对于知道如何执行图像改进的模型来说,使用预先训练的模型极大地加快了训练时间,使得模型具有需要检测和改进的特征种类的初始知识。使用在 ImageNet 上预先训练好的模型和重量几乎是最理想的。用于 pyTorch 的预训练 ResNet-34 可从卡格尔:https://www.kaggle.com/pytorch/resnet34获得

培训详情

资料组

Div2k 数据集提供了 800 幅训练图像和 100 幅验证图像。在训练过程中,我使用了一定百分比的训练图像进行验证,使 Div2K 验证集与训练过程完全隔离,以避免模型在训练过程中观察到这些图像时出现任何错误。

每个图像被缩减到一个通道以用作灰度输入,原始的 RGB 图像被用作目标/背景真相。

通过以下方式进一步扩充了训练数据:

  • 随机选择农作物
  • 水平翻转图像
  • 调整图像的照明
  • 添加透视扭曲

训练过程从如上所述的模型开始:使用基于在 ImageNet 上预训练的 VGG-16 架构的损失函数结合像素损失和 gram 矩阵,在 ImageNet 上预训练的基于 ResNet-34 架构的 U-Net。

特征损失函数

损失函数使用来自 VGG-16 模型的激活、像素损失和克矩阵损失。

像素损失是预测中每个像素颜色与目标/地面真实颜色接近程度的简单像素比较。

来自 VGG-16 模型的激活允许损失函数确定特征看起来是否正确,在这种情况下,它们看起来颜色是否正确。

克损失着眼于所生成图像的艺术风格、其特征以及在颜色方面预测与原始图像的接近程度。

这些要素的组合允许损失函数检查上下文中要素的细节和样式,以改进模型的预测。

这允许模型学习令人信服的颜色,以应用于构成生成的预测图像的特征。

关于这个损失函数的更多细节在我的关于特征和风格损失函数的文章中有描述:https://towardsdatascience . com/loss-functions-based-on-feature-activation-and-style-loss-2f 0 b 72 FD 32 a 9

训练模特的头部和骨干

这里使用的三种方法特别有助于训练过程。这些是渐进调整大小、冻结然后解冻主干中权重的梯度下降更新和区别学习率。

该模型的架构分为两部分,主干和头部。

主干是 U-Net 的左侧部分,是基于 ResNet-34 的网络的编码器/下采样部分。头部是 U-Net 的右侧部分,即网络的解码器/上采样部分。

主干已经基于在 ImageNet 上训练的 ResNet34 预先训练了权重,这就是迁移学习。

头部需要训练其权重,因为这些层的权重被随机初始化以产生期望的最终输出。在最开始,网络的输出基本上是像素的随机变化,而不是使用 ICNR 初始化的像素混洗子卷积,其被用作网络的解码器/上采样路径中每个升级的第一步。

网络主干中的权重被冻结,因此最初只训练头部中的权重。

渐进调整大小

首先在大量较小的映像上进行训练,然后扩展网络和训练映像,这样会更快。与对 512 px x 512px 的图像进行着色相比,对 64px x 64px 的图像进行着色要容易得多,而且对更大的数据集进行着色要快得多。这被称为渐进式调整大小,它也有助于模型更好地概括,因为它看到更多不同的图像,不太可能过度拟合。

对于每个图像训练大小,模型被训练,直到训练损失和验证损失的改善趋于平稳,然后图像数据维度加倍。动态 U-Net 学习器处理较大的输入和输出图像。

64 x 64 像素图像的训练着色

较大的批量加速了小图像的训练。

训练了 50 个周期后,损失才停止显著改善。随着模型需要更多的像素/数据来预测特征的颜色和着色风格,损失停止显著改善。

Training colourising 64 x 64 pixel images

128 x 128 像素图像的训练着色

在 25 个训练周期后,损失停止显著改善。同样,随着模型需要更多的像素/数据,损失停止显著改善。训练图像尺寸加倍。

Training colourising 128 x 128 pixel images

256 x 256 像素图像的训练着色

在 10 个训练周期之后,损失停止显著改善,训练大小增加到 512×512 像素。同样,随着模型需要更多的像素/数据,损失停止显著改善。

Training colourising 256 x 256 pixel images

512 x 512 像素图像的训练着色

在 10 个训练周期之后,由于 GPU 内存限制,损失停止显著改善,增加训练图像大小完成,并且训练转移到解冻整个网络的权重。

Training colourising 512 x 512 pixel images

在 512x512 像素图像上训练,其中主干权重未冻结

现在,经过训练,骨架顶部的头部允许模型学习用骨架中预先训练的知识做一些不同的事情。

然后,整个模型的权重被解冻,并且该模型以判别学习率进行训练。这些学习率在第一层组中要小得多,然后在第二层组中增加,最后一层组在头部再次增加。

在 10 次训练后,损失停止显著改善。

预测中的颜色看起来更接近目标/实际情况。

Training on 512 x 512 pixel images with the backbone weights unfrozen

结果

此结果来自在 Div2K 验证集上对训练模型进行的预测。

如果颜色与目标和地面真实不匹配的结果令人信服,则不一定是坏的预测,如果目标/地面真实图像不可比较,则可能被认为是正确的。

这种算法没有办法知道图像中的原始颜色。该模型本质上可以将其训练的知识与基于图像中的内容、图像中的特征和图像中的风格的上下文的信息进行比较。然后模型会想象或产生幻觉,想象那里应该是什么颜色。

良好的结果

在这里,模型已经对目标图像/地面真实中的颜色产生了几乎完美的预测。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

该模型已经对目标图像/地面真实中的颜色产生了非常好且令人信服的预测。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

这个预测真的让我印象深刻,看起来很真实。该模型不能预测一些颜色,伪装色是错误的,但它们在孤立的地面真实/目标下看起来令人信服。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

另一个非常有说服力的颜色预测。在我看来,预测看起来与实际情况/目标一样真实,即使颜色不太匹配:

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

这里的头发颜色和肤色很接近。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

该模型预测了猫的皮毛会有很深的颜色,眼睛的颜色也很准确。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

除了金属屋顶的金色色调,几乎完美的颜色预测。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

有趣的结果

即使颜色明显是错误的,如果你看不到地面的真相,这个预测也会看起来令人信服。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

同样,一些颜色显然是错误的,但是模型怎么知道一朵花是什么颜色呢?如果你看不到事实真相,预测看起来会很有说服力。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

糟糕的结果

太多时候,论文和文章显示的是最佳结果,而不是模型表现不佳的地方。强调模型的局限性和/或不能很好概括的地方是很重要的。

总的来说,模型对绿色的预测缺乏鲜明的色调,这一点在这里非常明显。绿色非常柔和,通常缺乏对比。如果黄色/绿色更饱和,预测会更接近。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

在这里,模型没有真正创造任何颜色,预测类似于一个褐色的图像。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

结论

这种方法在高比例的验证图像上非常有效,几乎总是产生令人信服的彩色图像。

对一个人来说,做出这些着色是如此的辛苦和缓慢,在我看来,我要说这比人类的尝试要好,可能被认为是超人。

更多的结果

这里有一些来自模型和基本事实的预测,以便与介绍性的例子进行比较。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

预测与目标几乎无法区分:

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

同样,预测与目标几乎无法区分:

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

虽然预测与目标的颜色不同,但它非常有说服力:

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

该模型已经计算出图像中有水,但不知道水可能是绿色而不是蓝色。天空近乎完美。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

狐狸非常接近目标/地面的真实情况,天空和草地没有正确的颜色,尽管它们的颜色看起来很有说服力。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

狮子皮毛颜色的变化并不完美,草/植物的绿色缺乏对比,悬停生成的预测图像相当有说服力。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

这是一张复杂的图像,许多物体都被正确着色,其他的则令人信服:

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

对原始主题/目标中的颜色的另一个令人信服的预测。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

除了一些小细节,如浮标和船舱的木材颜色,大部分颜色都预测正确。

Examples of this model’s enhancement of a Greyscale 1 channel image to a 3 channel colour image.

技术细节

这个模型是由 Fastai 动态 U-Net 学习者https://docs.fast.ai/vision.models.unet.html创建的

这使用了 Fastai 软件库、PyTorch 深度学习平台和 CUDA 并行计算 API。

所有训练都是在 Nvidia Tesla K80 GPU 上进行的,内存为 12GB,从开始到结束不到 12 个小时,逐步调整大小。

法斯泰

感谢 Fastai 团队,没有你们的课程和软件库,我怀疑我是否能够进行这些实验并了解这些技术。

带 ResNet 编码器和交叉连接的 u 型网络

原文:https://towardsdatascience.com/u-nets-with-resnet-encoders-and-cross-connections-d8ba94125a2c?source=collection_archive---------1-----------------------

我已经将这一点从我关于超级分辨率的文章中分离出来(https://towards data science . com/deep-learning-based-Super-Resolution-without-use-a-gan-11 C9 bb 5b 6 CD 5),以更加通用,因为我在其他基于 U-Net 的模型上使用了相同的架构来预测自动协作的数据。

这是基于 Fastai 深度学习课程中演示和教授的技术。

Fastai 软件库打破了很多复杂深度学习入门的障碍。由于它是开源的,很容易定制和替换你的架构元素,以适应你的预测任务。

Fastai U-Net 学习者提供了实现这些技术的基础:【https://docs.fast.ai/vision.models.unet.html

该体系结构使用以下各项,下面将进一步解释每项内容:

  • 一种交叉连接的 U-Net 架构,类似于 DenseNet
  • 一个基于 ResNet 的编码器和一个基于 ResNet 的解码器
  • 用 ICNR 初始化进行像素混洗放大

剩余网络

ResNet 是一种卷积神经网络(CNN)架构,由一系列残差块(ResBlocks)组成,如下所述,通过跳跃连接将 ResNet 与其他 CNN 区分开来。

当最初设计 ResNet 时,它以显著的优势赢得了当年的 ImageNet 竞争,因为它解决了渐变消失的问题,即随着层数的增加,训练速度变慢,准确性没有提高,甚至变得更差。正是网络跳过连接完成了这一壮举。

这些在下面的图表中显示,并在描述 ResNet 中的每个 ResBlock 时进行更详细的解释。

Left 34 Layer CNN, right 34 Layer ResNet CNN. Source Deep Residual Learning for Image Recognition: https://arxiv.org/abs/1512.03385

残余块(ResBlocks)和密集块

如果卷积网络在靠近输入的层和靠近输出的层之间包含较短的连接,则卷积网络可以训练得更深入、更准确、更有效。

如果您将损失面(模型预测的变化损失的搜索空间)可视化,这看起来就像下图中左侧图像所示的一系列山丘和山谷。最低的损失就是最低点。研究表明,一个较小的最优网络可以被忽略,即使它是一个较大网络的一部分。这是因为损失面太难导航。这意味着在一个模型中增加许多深层,会使预测变得更糟。

Loss surface with and without skip connections. Source: Visualising loss space in Neural networks: https://arxiv.org/abs/1712.09913

一个非常有效的解决方案是在网络各层之间增加交叉连接,允许在需要时跳过大部分。这创建了一个损失表面,看起来像右边的图像。这对于用最佳权重训练模型以减少损失要容易得多。

A ResBlock within a ResNet. Source: Deep Residual Learning for Image Recognition: https://arxiv.org/abs/1512.03385

每个 ResBlock 从其输入有两个连接,一个经过一系列卷积、批量规格化和线性函数,另一个连接跳过这一系列卷积和函数。这些被称为身份连接、交叉连接或跳过连接。两个连接的张量输出相加在一起。

稠密连接的卷积网络和稠密块

在 ResBlock 提供张量相加的输出的情况下,这可以被改变为张量连接。随着每个交叉/跳跃连接,网络变得更加密集。然后,ResBlock 变成 DenseBlock,网络变成 DenseNet。

这允许计算跳过架构中越来越大的部分。

DenseBlocks within a DenseNet. Source: Densely Connected Convolutional Networks: https://arxiv.org/pdf/1608.06993.pdf

由于串联,DenseBlocks 与其他架构相比会消耗大量内存,非常适合较小的数据集。

u 型网

U-Net 是为生物医学图像分割开发的卷积神经网络架构。已经发现 u-网对于输出与输入大小相似并且输出需要该量的空间分辨率的任务非常有效。这使得它们非常适用于创建分割蒙版和图像处理/生成,如超分辨率或着色。

当卷积神经网络通常与用于分类的图像一起使用时,使用一系列每次减小网格大小的两个步长的卷积,图像被获取并向下采样到一个或多个分类中。

为了能够输出与输入大小相同或更大的生成图像,需要有一个上采样路径来增加网格大小。这使得网络布局类似于 U 形,U 形网络下采样/编码器路径形成 U 形的左侧,上采样/解码器路径形成 U 形的右侧

对于上采样/解码器路径,几个转置卷积实现这一点,每个卷积在现有像素之间和周围添加像素。基本上执行下采样路径的相反过程。上采样算法的选项将在后面进一步讨论。

请注意,该模型的基于 U-Net 的架构也有交叉连接,这将在后面详细说明,这些不是原始 U-Net 架构的一部分。

A U-Net network architecture. Source: http://deeplearning.net/tutorial/_images/unet.jpg

原来的研究可在这里:https://arxiv.org/abs/1505.04597

上采样/转置卷积

网络的解码器/上采样部分(U 的右手部分)中的每个上采样需要在现有像素周围以及现有像素之间添加像素,以最终达到期望的分辨率。

这个过程可以从论文“深度学习卷积算法指南”中可视化如下,其中在像素之间添加零。蓝色像素是原始的 2x2 像素扩展到 5x5 像素。在外部添加 2 个像素的填充,并在每个像素之间添加一个像素。在这个例子中,所有新像素都是零(白色)。

Adding pixels around and between the pixels. Source: A guide to convolution arithmetic for deep learning: https://arxiv.org/abs/1603.07285

这可以通过使用像素的加权平均(使用双线性插值)对新像素进行一些简单的初始化来改善,否则会不必要地使模型更难学习。

在这个模型中,它使用了一种改进的方法,称为像素混洗或带有 ICNR 初始化的亚像素卷积,这导致像素之间的间隙被更有效地填充。这在论文“使用高效亚像素卷积神经网络的实时单幅图像和视频超分辨率”中有所描述。

Pixel shuffle. Source: Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network, source: https://arxiv.org/abs/1609.05158

像素混洗以因子 2 放大,使图像的每个通道中的维度加倍(在网络的该部分的当前表示中)。然后执行复制填充以在图像周围提供额外的像素。然后,执行平均池以平滑地提取特征并避免由许多超分辨率技术产生的棋盘图案。

在添加了这些新像素的表示之后,随着路径继续通过网络的解码器路径,随后的卷积改善了这些像素内的细节,然后再进行另一个步骤并使维度加倍。

u 网和精细图像细节

当使用唯一的 U-Net 架构时,预测往往缺乏细节,为了帮助解决这个问题,可以在网络的块之间添加交叉或跳过连接。

不是像在 ResBlock 中那样每两个卷积添加一个跳过连接,而是跳过连接从下采样路径中相同大小的部分跨越到上采样路径。这些是上图中显示的灰色线条。

原始像素通过跳过连接与最终的 ResBlock 连接,以允许在知道输入到模型中的原始像素的情况下进行最终计算。这导致输入图像的所有细节都在 U-Net 的顶部,输入几乎直接映射到输出。

U-Net 块的输出被连接起来,使它们更类似于 DenseBlocks 而不是 ResBlocks。但是,有两个跨距卷积可以减小网格大小,这也有助于防止内存使用量增长过大。

ResNet 编码器

ResNet 可用于 U-Net 的编码器/下采样部分(U 的左半部分)。

在我的模型中,我使用了一个 ResNet-34,一个 34 层的 ResNet 架构,因为 Fastai 的研究人员发现这非常有效,比 ResNet-50 训练起来更快,使用的内存更少。

解码器

在将 ResNet-34 编码器转换为具有交叉连接的 U-Net 的情况下,Fastai U-Net 学习器在配备有编码器架构时将自动构建 U-Net 架构的解码器端。

预训练编码器

为了使图像生成/预测模型知道如何有效地执行其预测,如果使用预训练的模型,将大大加快训练时间。然后,该模型具有需要检测和改进的特征种类的初始知识。当照片被用作输入时,使用在 ImageNet 上预先训练的模型和权重是一个很好的开始。

损失函数

当使用这种 U-Net 架构进行图像生成/预测时,使用基于来自预训练模型(例如 VGG)的激活和格拉姆矩阵损失的损失函数非常有效。关于特征和风格损失函数的更多细节可以在我的文章中找到:https://towardsdatascience . com/loss-functions-based-on-feature-activation-and-style-loss-2f 0 b 72 FD 32 a 9

法斯泰

感谢 Fastai 团队,没有你们的课程和软件库,我怀疑我是否能够学习这些技术。

美国参议员的社交网络——基于 Twitter 的分析

原文:https://towardsdatascience.com/u-s-senators-social-network-analysis-based-on-twitter-147a5df968c7?source=collection_archive---------9-----------------------

随着“触网”的不断扩大,社交媒体已经融入现代生活的方方面面,成为我们学习、工作、交友、获取信息不可或缺的方式。除了作为日常交流工具,社交媒体在这个时代被赋予了更大的意义——政治家们将社交媒体作为自我宣传的重要阵地。

本文用 图论网络分析 来描绘美国参议员在推特上的社交地图,分析他们之间的相互关系以及他们在这个社交网络中的地位。

The U.S. Senators’ Social Network on Twitter

根据社交网络计算,美国参议员中的边数为 852,这意味着这 45 名参议员中有 852 个联系,其中包括 26 名共和党人和 19 名民主党人。

[## 美国参议院(@USSenate) |推特

美国参议院最新推文(@USSenate)。我们国家联盟的活象征。华盛顿哥伦比亚特区

twitter.com](https://twitter.com/USSenate)

度数最高的节点是@sendavidperdue,它属于美国参议员大卫·珀杜。也就是说,45 名参议员中有 39 名追随过大卫·珀杜,他在社交网络中最有声望,受欢迎程度也最高。

[## 大卫·珀杜(@sendavidperdue) |推特

来自大卫·珀杜的最新推文(@sendavidperdue)。美国参议员大卫·珀杜的官方推特账户

twitter.com](https://twitter.com/sendavidperdue)

小大卫·阿尔弗雷德·濮培德(David Alfred Schmidt Jr .),美国商人和政治家,自 2015 年以来一直担任佐治亚州的初级美国参议员。濮培德赢得了共和党初选,击败了民主党人米歇尔·纳恩。

出度最高的节点是@ChuckGrassley,属于美国参议员查克·格拉斯利。结果显示,查克关注了 45 名参议员中的 30 名,他在社交网络中处于最中心的位置,并获得了最高的合群度。

[## ChuckGrassley(@ ChuckGrassley)| Twitter

ChuckGrassley 的最新推文(@ChuckGrassley)。美国参议员。家庭农场主。新哈特福德的永久居民…

twitter.com](https://twitter.com/ChuckGrassley)

查克·格拉斯利是美国政治家,爱荷华州资深参议员,也是共和党成员。他第一次当选于 1980 年,现在是他在参议院的第七个任期。

介数最高的节点是@RoyBlunt,属于美国参议员 RoyBlunt。显示@RoyBlunt 在另外两个参议员节点之间沿最短路径充当桥梁的次数为 79.33342,这意味着 RoyBlunt 对其他参议员之间通信的控制力是最高的。

[## 罗伊·布朗特参议员(@RoyBlunt) |推特

罗伊·布朗特参议员的最新推文(@RoyBlunt)。美国参议员罗伊·布朗特的官方账户。很荣幸代表…

twitter.com](https://twitter.com/RoyBlunt)

罗伊·迪恩·布朗特是美国政治家,也是来自密苏里州的美国资深参议员,自 2011 年以来一直担任参议员。他也是共和党成员,曾在美国众议院任职,并担任密苏里州国务卿。

网络的互惠性为 0.4964706,也就是说,这些参议员之间的双向互动比例为 49.647%,这意味着近一半的参议员在推特上相互关注。

Community Detection of U.S. Senators on Twitter

社区检测结果显示,美国参议员中存在三个社区。共和党议员罗布·波特曼(Rob Portman)的 Twitter 账号是@SenRobPortman,他自己也组建了一个社区(黄色部分)。最有可能的原因是,罗布·波特曼在推特上没有关注任何其他参议员,只有两名参议员关注他。

[## 罗布·波特曼(@senrobportman) |推特

罗布·波特曼的最新推文(@senrobportman)。来自七叶树州的美国参议员。俄亥俄州

twitter.com](https://twitter.com/senrobportman?lang=en)

第二个群体,以蓝色显示,由 12 名参议员组成,他们都是民主党人。合理的解释可能是,所有 12 名参议员都持有相同的政治立场,并且彼此密切互动。

另一个有趣的事情是,第二个社区包含 5 名男性和 7 名女性,这意味着根据 35 名男性和 10 名女性的总数,整个女性参议员的 70%在这个社区。也就是说,第二社区可能是一个女性领导力比较明显的地方。

Female Senators (Image Credit to Marie Claire)

第三个社区,用绿色显示,由 32 名参议员组成,包括 25 名共和党人和 7 名民主党人,这也可以用同样的理由来解释——政治立场。第三选区的七位民主党参议员是— 马丁·海因里希 (@ 马丁·海因里希)、迈克尔·贝内特 (@ 森本内科)、乔·唐纳利 (@ 森多内利)、蒂姆·凯恩 (@ 森凯恩办公室)、谢尔登·怀特豪斯 (@

在这个社区的 32 名参议员中,只有 3 名是女性,这意味着第三社区是男性话语权占主导地位的地方。

Republican Senators 2019 (Image Credit to The Washington Post)

基于社区发现的结果,我们可以做出这样的假设:政党的选择和性别之间可能存在某种联系。

BigQuery 中的优步数据集:旧金山周围的行驶时间(以及您所在的城市)

原文:https://towardsdatascience.com/uber-datasets-in-bigquery-driving-times-around-sf-and-your-city-too-9ad95baa6bfe?source=collection_archive---------15-----------------------

Interactive travel times dashboard around the SF Bay Area. Powered by BigQuery, Data Studio, and Uber’s worldwide movement data.

优步一直在向他们的公共数据程序添加新的城市——让我们把它们载入 BigQuery。我们将利用最新的新功能:原生 GIS 功能、分区、集群和带有 BI 引擎的快速仪表板。

首先让我们来玩一下交互式仪表板,我们将在下面研究加载步骤和故障排除。注意,您可以使用这些步骤将任何其他城市加载到 BigQuery 中!互动数据工作室仪表盘:

Play with the interactive Data Studio dashboard.

第一步:从优步获取数据

我们可以在优步运动的公共数据网站找到几个城市的数据。在这里,我将下载一些旧金山旅行时间数据集:

Downloading Uber’s public data for San Francisco travel times

步骤 2:加载到 BigQuery 中

一旦我们有了文件,加载数据 CSV 就很简单了:

bq load --autodetect \
  fh-bigquery:deleting.uber_sf_censustracts_201803_all_hourly \
  san_francisco-censustracts-2018-3-All-HourlyAggregate.csvbq load --autodetect \
  fh-bigquery:deleting.uber_sf_censustracts_201803_weekdays_hourly \
  san_francisco-censustracts-2018-3-OnlyWeekdays-HourlyAggregate.csvbq load --autodetect \
  fh-bigquery:deleting.uber_sf_censustracts_201803_weekends_hourly \
  san_francisco-censustracts-2018-3-OnlyWeekends-HourlyAggregate.csv

然而,地理边界文件将带来一些挑战。它们是标准的 GeoJSON 文件,但是我们必须在加载到 BigQuery 之前对它们进行处理:

  1. 使用jq将 GeoJSON 文件转换为新的行分隔的 JSON 文件。
  2. 加载新的。json 文件作为 CSV 文件导入 BigQuery。
  3. 解析 BigQuery 中的 JSON 行以生成原生 GIS 几何。
jq -c .features[] \
  san_francisco_censustracts.json > sf_censustracts_201905.jsonbq load --source_format=CSV \
  --quote='' --field_delimiter='|' \
  fh-bigquery:deleting.sf_censustracts_201905 \
  sf_censustracts_201905.json row

对于步骤 3,我们可以解析 BigQuery 中加载的行:

CREATE OR REPLACE TABLE `fh-bigquery.uber_201905.sf_censustracts`
ASSELECT FORMAT('%f,%f', ST_Y(centroid), ST_X(centroid)) lat_lon, *
FROM (
  SELECT *, ST_CENTROID(geometry) centroid
  FROM (
    SELECT 
      CAST(JSON_EXTRACT_SCALAR(row, '$.properties.MOVEMENT_ID') AS INT64) movement_id
      , JSON_EXTRACT_SCALAR(row, '$.properties.DISPLAY_NAME') display_name
      , ST_GeogFromGeoJson(JSON_EXTRACT(row, '$.geometry')) geometry
    FROM `fh-bigquery.deleting.sf_censustracts_201905` 
  )
)

从 Lak Lakshmanan 和 Michael Entin 中找一些替代品(JavaScript,ogr2ogr)加载这个栈溢出回复中的 GeoJSON 数据。

步骤 3:为性能和效率按摩数据

现在我们在 BigQuery 中有了两个表,让我们处理数据以划分主表,创建本地 BQ GIS 几何列,并将所有内容连接在一起:

让我们创建我们的主表。该表将包含工作日、周末和总体统计数据,并且我们将添加一些人口普查区域数据以使其更易于可视化和理解。为了提高效率,我们将按季度对其进行分区,并按 stat 和旅行起始地的类型进行聚类。

我还会计算一些额外的数据:区域间的平均距离和给定距离的速度。请注意,拥有这些统计信息会使查询运行速度比我们跳过它们时慢得多:

CREATE OR REPLACE TABLE `fh-bigquery.uber_201905.sf_hourly`
PARTITION BY quarter 
CLUSTER BY table_source, source, destination
-- don't partition/cluster if using BQ w/o credit cardASSELECT *, distance * 0.000621371192 / geometric_mean_travel_time * 3600 speed_mph
FROM (
  SELECT * EXCEPT(geo_b, geo_c),  (ST_DISTANCE(geo_b, geo_c)+ST_MAXDISTANCE(geo_b, geo_c))/2 distance
  FROM (
    SELECT a.*,  SPLIT(_TABLE_SUFFIX, '_')[OFFSET(0)] table_source
      , b.display_name source  
      , c.display_name destination
      , b.lat_lon sourceid_lat_lon  
      , CAST(SPLIT(b.lat_lon, ',')[OFFSET(0)] AS FLOAT64) sourceid_lat  
      , CAST(SPLIT(b.lat_lon, ',')[OFFSET(1)] AS FLOAT64) sourceid_lon  
      , c.lat_lon dstid_lat_lon
      , CAST(SPLIT(c.lat_lon, ',')[OFFSET(0)] AS FLOAT64) dstid_lat
      , CAST(SPLIT(c.lat_lon, ',')[OFFSET(1)] AS FLOAT64) dstid_lon  
      , DATE('2018-07-01') quarter
      , COUNT(*) OVER(PARTITION BY sourceid, dstid) source_dst_popularity
      , COUNT(*) OVER(PARTITION BY dstid) dst_popularity
      , b.geometry geo_b, c.geometry geo_c
    FROM `fh-bigquery.deleting.uber_sf_censustracts_201803_*` a
    JOIN `fh-bigquery.uber_201905.sf_censustracts` b
    ON a.sourceid=b.movement_id
    JOIN `fh-bigquery.uber_201905.sf_censustracts` c
    ON a.dstid=c.movement_id
  )
)

步骤 4:查询和可视化

我用 Data Studio 创建了一个交互式仪表板。请注意,由于我们新的 BigQuery BI 引擎,它的运行速度非常快。但是你也可以运行你自己的查询!

例如,旧金山最糟糕的目的地和到达旧金山机场的时间:

SELECT ROUND(geometric_mean_travel_time/60) minutes
  , hod hour, ROUND(distance*0.000621371192,2) miles
  , destination 
FROM `fh-bigquery.uber_201905.sf_hourly`
WHERE table_source='weekdays'
AND quarter='2018-07-01'
AND source LIKE '100 Domestic Terminals Departures Level%' 
AND destination LIKE '%San Francisco%'
AND (distance*0.000621371192)>10
ORDER BY 1 DESC
LIMIT 20

The worst destinations in San Francisco by time to travel starting at the SFO airport. Avoid going to the Marina at 5pm — it will take you 45 minutes on a weekday.

从旧金山到旧金山的最佳旅行地点和时间:

SELECT ROUND(geometric_mean_travel_time/60) minutes
  , hod hour, ROUND(distance*0.000621371192,2) miles
  , destination 
FROM `fh-bigquery.uber_201905.sf_hourly`
WHERE table_source='weekdays'
AND quarter='2018-07-01'
AND source LIKE '100 Domestic Terminals Departures Level%' 
AND destination LIKE '%San Francisco%'
AND (distance*0.000621371192)>10
ORDER BY 1 
LIMIT 20

You can get from SFO to Potrero Hills in 10 minutes… at 5am.

从旧金山到奥克兰时,平均时间的最大变化(截至stddev)为:

SELECT destination 
  , STDDEV(geometric_mean_travel_time) stddev
  , COUNT(*) c
FROM `fh-bigquery.uber_201905.sf_hourly`
WHERE table_source='weekdays'
AND quarter='2018-07-01'
AND source LIKE '100 Domestic Terminals Departures Level%' 
AND destination LIKE '%Oakland%'
AND (distance*0.000621371192)>10
GROUP BY destination
HAVING c=24
ORDER BY stddev DESC
LIMIT 20

Going from SFO to Gwin Road in Oakland might take you 30 minutes, or double that at peak time.

轮到你玩了

在 BigQuery 中找到共享数据集。

加载更多城市——优步不断向他们的共享集合添加更多数据!

Some of the cities Uber is sharing data for.

后续步骤

想要更多的故事?查看我的媒体,关注我的推特,订阅reddit.com/r/bigquery。试试 big query——每个月你都可以免费获得一个完整的 TB 级分析。

优步的数据许可:数据是在知识共享,署名非商业许可下提供的。数据属性

背景图:http://extras . SF gate . com/img/pages/travel/maps/SF bay _ STD . gif

[## 堆栈溢出何时回复:如何用 BigQuery 预测

当你最后发布一个关于栈溢出的问题时,一个漫长的等待就开始了。有人会回答你的问题吗?会不会…

towardsdatascience.com](/when-will-stack-overflow-reply-how-to-predict-with-bigquery-553c24b546a3)

优步评论文本分析

原文:https://towardsdatascience.com/uber-reviews-text-analysis-11613675046d?source=collection_archive---------12-----------------------

探索性分析,词汇袋,逻辑回归

Source

介绍

他的项目概述了一个使用词袋和逻辑回归的文本挖掘分类模型。我们将尝试理解优步文本评论和游乐设备评级之间的关系。如果您对非结构化数据分析相对陌生,但有一些统计和/或其他分类经验,这是一个很好的起点。

数据源:用户 Purvank 的 Kaggle

目录

  1. 初步分析
  2. 格式化/转换文本
  3. 逻辑回归
  4. 测试/结论

初步分析

输入数据

首先,让我们引入数据并可视化数据框架:

#importing modules
import pandas as pd
import numpy as np
import seaborn as sns
%matplotlib inline
import matplotlib.pyplot as plt
import random#pulling in data
df = pd.read_csv(r'C:\Users\Andrew\Desktop\Python Text Analysis\Uber_Ride_Reviews.csv')
df

这是一个简单的数据集。我们有“骑行回顾”文本栏和“骑行评级”栏(范围从 1 到 5,最低评级和最高评级)。用户写下这些文字评论来描述他们的体验,分类 5 星评级总结了这一点。

基本统计

让我们检查一下。describe()方法来查看我们正在处理的实例数量和其他基本统计数据:

df.describe()

看来优步车手在这个样本中表现不佳。均值是 1.62 的评分,75%的标记是 1 星评论!这告诉我们有不成比例的 1 星评论。希望我们可以通过建立一个模型来深入了解这一点。

模型的目的

提到这一点,让我们重申我们将建立的词汇袋/逻辑回归模型的效用:

  • 我们将能够衡量未来文本评论的情绪,并将它们分为“好”或“坏”的类别。
  • 我们将能够找出对评级情绪有重大影响的特定词语。这些信息对优步来说可能是一笔财富(如果用于他们的整个内部数据集,而不是我们拥有的这个小样本)。例如,单词“rude”可能有一个负系数,促使我们的分类器将该评论标记为不好。单词“great”可能有一个正系数,促使我们的分类器将该评论标记为好。 目标是发现。我们不知道哪些有趣的话可能会对情绪产生影响,这就是有趣的地方。“伟大”这个词比“可怕”更重要吗?这是积极的还是消极的?很多类似这样的问题,都会用我们的模型来回答。

零检查

接下来,让我们检查数据集中的空值:

#checking for nulls
null_count = df.isnull().sum()
null_count

这次没有。如果我们有一些空值,我们需要探索如何处理它们。关于这个主题有很多好的资源,你可以研究。

分布

接下来,让我们将数据的评级分布可视化:

#seperating by groups
groups = df.groupby('ride_rating').count()
Values = groups.ride_review
colors = ['r', 'g', 'b', 'c', 'm']#making bar plot
plt.bar(([1,2,3,4,5]), Values, color= colors)
plt.title('Rating Distribution')
plt.xlabel('Rating')
plt.ylabel('Review Quantity')
plt.show()

正如我们之前发现的,这个样本中有很多 1 星评论。

为了稍后执行逻辑回归,我们需要找出一种方法来将这 5 个评级类别转换为二元类(1 和 0)。记住,逻辑回归只处理“非此即彼”的目标变量。将星级划分为二进制等级的最佳方式(在我看来)是:

  • 将低于 3 颗星的评分设为 0 级(负面情绪)
  • 将高于 3 的评分设为 1 级(积极情绪)
  • 删除 3 星评分。三颗星是中性的,不提供任何情绪洞察。

因此,让我们创建一个新列,删除 3 颗星评级,并创建一个新列,将其他评级分为两类:

#deleting all instances with ride_rating = 3
df = df[df.ride_rating != 3]#separating by groups
groups = df.groupby('ride_rating').count()
Values = groups.ride_review
colors = ['r', 'g', 'b', 'c']#making bar plot
plt.bar(([1,2,4,5]), Values, color= colors)
plt.title('Rating Distribution')
plt.xlabel('Rating')
plt.ylabel('Review Quantity')
plt.show()

#creating new binary_class column
df['binary_class'] = np.where(df['ride_rating'] > 3, 1, 0)
df

我们准备好了!让我们准备好课文。

格式化/转换文本

训练/测试分割

这个过程的第一步是将我们的数据分成训练集和测试集。我们将从训练数据中创建我们的模型,并保存一些实例,以便稍后进行测试。我们用 sklearn 来洗牌和分牌。在不干扰参数的情况下,它应该将我们的数据分成 75%的训练和 25%的测试。

通过调用 X_train.shape,我们可以检查这一点。此外,让我们打印一份随机回顾来验证它是否有效,并提醒我们自己我们在做什么。

#splitting into train and test
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df['ride_review'], df['binary_class'], random_state = 0)#setting random number between 1 and 1000
number = random.randint(1,1000)#printing random training text and X_train shape
print ('Random Review:')
print(' ')
print(X_train[number])
print(' ')
print('X_train shape: ' + str(X_train.shape))

不出所料,970/1294 =我们样本的 75%。

把单词变成数字

现在到了激动人心的部分,将我们的文本数据转换成数字特征。为了稍后对这些数据进行回归,我们需要为样本中的每个单词建立一个特征。本质上,我们将把每个单词翻译成一个数字,然后计算这些单词/数字在矩阵中的使用频率。这样做的过程叫做“****”。值得注意的是,单词的顺序并不重要,单词袋只计算每个单词实例的使用频率。首先,我们将使用 Sklearn 计数矢量器

#importing countvectorizer
from sklearn.feature_extraction.text import CountVectorizer#creating variable which assigns X_train to numbers
vect = CountVectorizer().fit(X_train)#translates numbers back to text
vect.get_feature_names()[1:10]

Words 1–10

我们可以看到使用 len(vect.get_feature_names())方法,所有评论中共有 6607 个单词:

#length of total words
len(vect.get_feature_names())

Total Words

现在,让我们将 X_train 数据转换成一个矩阵,该矩阵以行的形式包含文档(实例),以列的形式包含新功能的数量(6,607)。比如我们上面看到的第一个字(0)就是“弃”。这将是矩阵中的第一列。任何包含“废弃”的优步评论都会计算出它被使用的次数,并添加到那一栏。作为一个旁注,有人使用“放弃”,将有可能对评级产生负面影响。我们可以稍后再做实验。

#creating matrix array for logistic regression
X_train_vectorized = vect.transform(X_train)
print (X_train_vectorized.toarray())

1294 instance X 6607 feature array matrix

因为单词太多,而大多数评论只有其中的一小部分,所以这个数组中的大部分数字都会是 0。

逻辑回归

建筑模型

我们终于成功回归了。在我们继续之前,如果您需要逻辑回归复习,请在此处查看。

同样,我们将使用 sklearn 来执行此模型:

#creating log regression
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train_vectorized, y_train)

现在,我们将计算 AUC,看看它对测试数据的分类有多好。更多关于 ROC 曲线和 AUC 的信息可以在这里找到:

#calculating AUC
from sklearn.metrics import roc_auc_score
predictions = model.predict(vect.transform(X_test))
print('AUC: ', roc_auc_score(y_test, predictions))

这很好。理解这个指标的粗略方法是说我们有 75%正确分类的实例。

测试/结论

积极和消极的话

我们来深究一下哪些词对阶级分离的影响最大。在这里,我们将数字转换回文字,获得回归输出的系数,将它们添加到数据帧中,并根据系数对它们进行排序。

#creating array variable of all the words
feature_names = np.array(vect.get_feature_names())#creating array of all the regression coefficients per word
coef_index = model.coef_[0]#creating df with both arrays in it
df = pd.DataFrame({'Word':feature_names, 'Coef': coef_index})#sorting by coefficient
df.sort_values('Coef')

Most negative Coefficients (Most correlated with negative review)

Most positive Coefficients (Most correlated with positive review)

负面情绪:

这让我着迷。

  • “带电”是最负相关的词。
  • “Lyft”我认为也很有趣。如果客户有负面体验,我相信他们会倾向于评论“你的竞争对手比你好!”。
  • “免费”这个词让我很困惑。我本以为“免费”会是一个积极向上的词。

积极情绪:

当你向下移动数据框,单词变得更加正相关。

  • “伟大”是最高的,分数如此积极,甚至超过了“充电”。
  • “安全”、“方便”、“干净”……这些词很多都是直觉预期的。
  • 一个意想不到的正相关词是“她”。女司机是否对客户情绪有更积极的作用?

这些结果可以为优步的利益相关者和领导层提供潜在的无价的商业洞察力。

测试自定义评论

最后,我们可以试验和测试我们自己的定制评论。下面以粗体显示的是输入,下面是各自的输出(1 =正;0 =负)。最后一个应该是肯定的,但是我们的分类器把它标为否定的。其余的似乎是准确的。

print(model.predict(vect.transform(['**abandoned great**'])))print(model.predict(vect.transform(['**great she the best**'])))print(model.predict(vect.transform(['**charged slow horrible**'])))print(model.predict(vect.transform(['**it was as average as a trip could be**'])))print(model.predict(vect.transform(['**my family felt safe we got to our destination with ease**'])))print(model.predict(vect.transform(['**i got to my destination quickly and affordably i had a smile on my face from start to finish**'])))

感谢阅读。

我在 Kaggle 上有一个内核,里面有这个分析这里

还有,如果你想联系,我的 LinkedIn 是这里

如果你觉得这有帮助,请订阅。如果你喜欢我的内容,请查看其他几个项目:

随机森林是否优于 Logistic 回归?(一比较)

基尼指数 vs 信息熵

简单线性 vs 多项式回归

用 Python 中的逻辑回归预测癌症

二元逻辑回归示例(python)

从头开始计算 R 平方(使用 python)

为 Arvato Financial Services 创建客户细分报告

原文:https://towardsdatascience.com/udacity-data-scientice-nano-degree-capstone-project-create-customer-segmentation-report-for-852d3e6d3180?source=collection_archive---------16-----------------------

来自数据科学纳米级的 Udacity 顶点项目

Photo by Christiann Koepke on Unsplash

项目概述

通过创建客户细分并与一般人群进行比较,可以知道一般人群中的哪一部分更有可能成为客户,哪一部分不是。我分析了德国一家邮购销售公司客户的人口统计数据,并将其与普通人群的人口统计信息进行了比较。

首先,我使用不同的方法对数据进行预处理,然后我使用无监督学习技术,PCA(主成分分析)和 k-NN(k-最近邻算法),来进行客户细分并识别公司的核心客户特征。

其次,根据公司营销活动目标的人口统计信息,我使用不同的模型来预测哪些人最有可能转化为客户。

最后,我还通过 kaggle 测试了比赛中的模型,其中比赛是这里,所有讨论的内容都是基于上传到 Github 资源库这里的 jupyter 笔记本。

问题陈述

该目标包括以下四个部分:

  1. 数据预处理:清理和重新编码数据。
  2. 细分:使用无监督学习技术来创建客户和普通人群的聚类,然后识别差异。
  3. 预测:使用人口统计特征来预测一个人在邮寄活动后是否会成为客户。
  4. 用同样的算法预测,提交给 Kaggle 竞赛,得到评价。

韵律学

在分割部分,解释方差比被用于主成分分析过程。解释方差说明了描述整个特征方差的能力,解释方差越大,组件的重要性越大。

在监督模型预测部分,精度主要用作主要度量。

分析和方法——数据探索、可视化和预处理

有四个数据集,它们都具有相同的人口统计特征(只有一部分不同)

  • uda city _ AZDIAS _ 052018 . CSV:德国一般人口的人口统计数据;891 211 人(行)x 366 个特征(列)
  • uda city _ CUSTOMERS _ 052018 . CSV:邮购公司客户的人口统计数据;191 652 人(行)x 369 个特征(列)
  • uda city _ MAILOUT _ 052018 _ train . CSV:作为营销活动目标的个人的人口统计数据;42 982 人(行)x 367 人(列)。
  • 【uda city _ MAILOUT _ 052018 _ test . CSV:作为营销活动目标的个人的人口统计数据;42 833 人(行)x 366 人(列)。

除了上述数据,还有两个额外的元数据:

  • DIAS 信息级别—属性 2017.xlsx :属性和描述的顶级列表,按信息类别组织
  • DIAS Attributes-Values 2017 . xlsx:按字母顺序详细映射每个特征的数据值

还有,我基于DIAS Attributes-Values 2017 . xlsx文件创建了一个名为DIAS _ Attributes _ Values _ 2017 _ details . CSV的文件,这样我就可以将每个属性映射到它的类型或者缺失值编码。

处理缺失/未知值

在数据预处理过程中,我将缺失或未知的值重新编码为 Nan,以确保所有值的编码都是一致的。例如,在 AGER_TYP 属性中'-1 '值表示未知,我用 np.nan. 替换它

评估每个属性中缺失的数据

在每个属性中,计算缺失值的比例。从缺失率的分布来看,大多数属性都在 20%以下。因此,我根据这个标准删除了异常值。(图 1)

Fig. 1 Distribution of missing ratio for each attribute

评估每行中缺失的数据

每行中缺失的数据也会被评估。可以看到,大多数行没有丢失值,所以我将删除至少有一个丢失值的所有行。(图 2)然而,为了确保我删除的数据对整个数据没有大的影响,我将检查一些特征的分布。

Fig. 2 Distribution of missing ratio in each row

通过比较两个子集(不包括已删除行的数据和只包括已删除行的数据)之间至少五个属性的值的分布,两者之间没有大的差异。(图 3)所以我将在处理行中丢失的值时保留这个标准。

Fig. 3 Comparison of distribution of two data set on specific attributes (see Github for all graphs)

重新编码并提取特征

数据中有四种类型的数据:序数、数值、分类和混合。对于顺序变量,虽然值可能不是线性相关的,但我在这里假设顺序变量是区间变量。剩余的分类和混合变量将被重新编码和选择。

例如,关于分类变量,OST_WEST_KZ 特征包括二进制的值“W”和“O”。我把它重新编码成 0 和 1 的数值二进制变量。另一方面,CAMEO_DEUG_2015 功能包括详细信息文档中未描述的“X”值,因此我将其重新编码为 Nan。对于其余的分类变量,我绘制了相关图,以了解这些特征是否具有共同的特征。(图 4)

Fig. 4 Correlation heat-map between categorical features

根据上图,LP_FAMILIE_FEIN 和 LP_FAMILIE_GROB 高度相关,LP_STATUS_FEIN 和 LP_STATUS_GROB 也高度相关。由于 LP_FAMILIE_FEIN 和 LP_STATUS_FEIN 太详细了,我在这里把这两个去掉了。此外,虽然上图中没有绘制 CAMEO _ DEUG _ 2015and 和 CAMEO_DEU_2015,但根据描述文件,它们非常相似。所以我去掉了 CAMEO_DEU_2015 来简化。最后,还有一个特性 EINGEFUEGT_AM 没有在文档中描述,我也放弃了这个特性。在重新编码和选择分类变量之后,我使用 Pandas 中的 get_dummies 方法转换为虚拟值。

除了分类变量之外,还有如下六个混合特征:

  1. CAMEO_INTL_2015
  2. FEIN 的生活
  3. GROB 的生活
  4. PLZ8_BAUMAX
  5. PRAEGENDE _ JUGENDJAHRE
  6. 沃纳拉赫

通过查看 CAMEO_INTL_2015 属性,似乎该属性可以分为两个区间变量:一个与财富有关,另一个与人生阶段有关,因此我使用 map 方法对该特征进行重新编码。关于 LP_LEBENSPHASE_FEIN 和 LP_LEBENSPHASE_GROB,因为它们都描述了与 CAMEO_INTL_2015 具有相似特征的人的生命阶段,所以我在这里放弃了这两个属性。另一方面,PLZ8_BAUMAX 和 WOHNLAGE 属性在某种程度上可以视为区间变量,我在这里保留了它们。最后,在 PRAEGENDE _ JUGENDJAHRE 功能中,它看起来也可以分为两个部分:十年和运动。因此,我创建了两个函数来处理这个变量。

经过所有的预处理和重编码过程后,uda city _ AZDIAS _ 052018 . CSV被清洗并转换为熊猫 daframe 对象AZDIAS _ informational _ dummy。我还创建了一个函数 clean_data ,它包含了上面提到的所有过程,因此对于每个人口统计数据,清理过程都是确定的并且保持不变。

最后,在重新编码的过程中,一些特征变得不规则,所以我用输入器来代替带有手段的。然后我用 StandardScaler 来缩放所有的特征。为了检查最终的输出,我计算了每个属性中的 Nans(缺失率)的数量。(图 5)

Fig 5. The missing ratio in each attribute (parial)

实施和完善

客户细分报告部分

从近 425 个特征中,我进行了主成分分析来提取一般人群的重要特征。知道了每个属性的主要解释方差,我决定使用前 6 个分量,因为在第 6 个分量之后,累积方差缓慢增加。(图 6 和图 7)

Fig. 6 (Top): Explained variance across different PCA components. (Bottom): Accumulated

Fig. 7 Accumulated explained variance for top 100 PCA components

在选择了主成分分析后,我使用 KMeans 方法进行聚类。为了决定我应该使用多少个聚类,我调查了 KMeans 分数的聚类数。结果表明,当聚类数增加到大约 30 时,误差(分数)变得足够低,并且不会快速变化。因此,我选择 30 作为聚类数。(图 8)

Fig. 8 The change of score (error) to k (number of clusterings)

上面使用的所有过程和方法也适用于客户数据。因此,我可以获得普通人口数据和客户数据的聚类标签。(图 9)通过绘制聚类的分布,我得到了两个数据集之间的差异结果。(图 10)

Fig. 9 The distribution of the clusterings across two populations

在此表中,gp_portion 表示一般人群中聚类的比例,cs_portion 表示客户人群中聚类的比例,表明客户和一般人群之间的差异在聚类 21 和 28 中最大,在聚类 6 和 20 中最小。

Fig. 10 The difference of clustering distribution in the two datasets

监督学习模型部分

在监督学习模型部分中,由于数据与普通人群共享相同的人口统计特征,因此所有预处理都与客户细分部分中的相同。然而,为了确保被清理的列是相同的并且所有的行都被保留,clean_data 函数被修改为 clean_data_preserve_row 。在预处理过程之后,我在分割报告部分使用了相同的算法来获得 PCA 值和聚类。

独立变量是原始清理特征、6 个 PCA 分量和聚类标签。因变量是数据集中的响应列。为了预测响应值,即 0 或 1 二进制值,我使用了三种模型:逻辑回归,随机森林和 k-NN 来预测。还进行了网格搜索以获得最佳参数。

结果

解释、模型评估和验证

客户细分报告部分

首先,我将讨论 6 个 PCA 成分,然后我将使用上面的聚类结果来了解一般人群和客户之间的差异。

对于每个 PCA 组件,我显示了主要特性的详细信息,以便了解其特性。(图 11 和图 12)第一列显示了每个特征的重要性。

Fig. 11 The details of PCA components 1 to 3

Fig. 12 The details of PCA components 4 to 6

以下是基于每个组件的详细信息的摘要。为了方便起见,我将命名每个组件并在后面解释。

PCA 成分 1 : 富人指数。可能是一些关心财经新闻或产品的人,住在繁忙的城市地区,倾向于独居或只和伴侣住在一起。

PCA 成分 2:年轻和流浪指数。 此人出生于 90 年代,主要接触数字媒体,不是存钱的人,有很高的网络亲和力,不是金融投资者,思想不传统。

PCA 成分 3:汽车品牌狂热指数。 由于宝马&奔驰、高级轿车或跑车的高份额,以及顶级德国制造商(奔驰、宝马)的高份额。

PCA 成分 4:网购者指数。 由于交易活跃,邮购交易活跃,每平方公里居民密度高,6-10 户家庭住宅数量多。

PCA 成分 5:汽车寿命指数。

PCA 成分 6:反社会指数。 因梦幻亲和力低,熟悉度低,文化社交度低,不信教。

除了 PCA 成分,我还比较了一般人群和顾客的区别。正如前面提到的,我从图 9 和图 10 中得到了下面的结果。

  • 一般认为 的人群更有可能成为邮购公司的主要客户:集群 21 和 28
  • 不太可能成为邮购公司主要客户的普通人群:集群 6 和 20

查看每个集群,以下是每个集群的特征(为方便起见,采用绝对值为 3 的标准):

  • 聚类 21: PCA 成分 2 ( 年轻与流浪指数)负相关。
  • 群集 28: PCA 组件 4 ( 在线购物者指数)正相关。
  • 聚类 6: PCA 成分 1 ( 富人指数)和 3 ( 汽车品牌狂热指数)负相关,而 PCA 成分 5 ( 汽车生活指数)正相关
  • 聚类 20: PCA 成分 1 ( 富人指数)负相关,成分 6 ( 反社会指数)正相关

综合以上所有信息,这里是总结。

  • 倾向于成为顾客的人群:可能是成年人并且通常在网上购物的人群。
  • 可能不是消费者的人群:不富裕,也不关注汽车品牌的人。然而,他们倾向于经常使用汽车。他们中的一些人可能有一些反社会的特征。

综上所述,活动的目标应该集中在不年轻且经常在网上购物的用户身上。另一方面,对于那些非常富有或对汽车非常感兴趣或具有反社会特征的人来说,可能没有必要向他们发起这场运动。

监督学习模型部分

数据被分成训练数据和测试数据。然而,结果并不好。对于三种模型(逻辑回归、随机森林和 k-NN),它们都没有很好的精度。我将在下一个理由部分讨论它。

正当理由;辩解

监督学习模型部分

由于原始数据不平衡(大多数响应为 0,值 1 低于 1 %),我尝试了以下部分来解决问题:

  1. 使用 GridSearch 方法。
  2. 设置“class_weight”参数。
  3. 在 train_test_split 流程中设置分层参数。
  4. 尝试 6 个以上 PCA 成分到 20 个 PCA 成分。

然而,它们都没有提高精度。这部分我最后会留在改进部分。

此外,我已经将测试数据的预测上传到 kaggle。如前所述,模特的表现不好,所以分数也不好。(图 13)

Fig. 13 The submission to kaggle

结论

反射

在分割部分,对数据进行了预处理,并采用主成分分析和 k-NN 相结合的方法对不同人群进行聚类。我们讨论了这种差异,我知道哪些人可能是潜在客户,哪些人可能不是。了解了这种差异,公司就可以更专注于他们的目标,然后提高转化率或降低营销成本。影响大。

然而,在监督学习部分,模型的性能并不好。这可能是由于因变量的大部分值为 0 的有偏数据分布造成的。需要进一步调查。

改进

为了提高监督学习模型的性能,可以进行以下部分。

  1. 处理不平衡数据的方法:欠采样或过采样。
  2. 增加 PCA 成分。
  3. 仅使用 PCA 成分作为独立变量。

乌胡鲁·肯雅塔 2019 年国情咨文,最积极

原文:https://towardsdatascience.com/uhuru-kenyattas-2019-state-of-the-nation-address-most-positive-557d9cfb3f13?source=collection_archive---------20-----------------------

作为肯尼亚总统,https://en.wikipedia.org/wiki/Uhuru_Kenyatta·乌胡鲁·肯雅塔负责通过每年的国情咨文向肯尼亚人民通报政府取得的进步。他在 2013 年掌权,因此他的第一个儿子是在 2014 年。我看了一下演讲稿,发现了一件事。对于像我这样的人来说,它们太长太无聊了。听他们的话本来是有意义的,但我错过了这一切。因此,我部署了一些自然语言处理(NLP)技术来提取演讲中的一些知识。这就是机器比人类做得更好的地方。

数据

我们利用了 2014 年(乌呼鲁掌权一年后)至 2019 年间公开发表的国情咨文演讲。我在我的分析中使用了 R ,其中涵盖了一些数据分析和建模方面。

数据清理和一点点分析

我使用了下面的一些库来处理数据。小心!有些可能根本没用。希望你能在这个分析中找出对你有用的东西。

该文档被转换成一个术语文档矩阵,以便于对其中的单词进行统计计算。以下过程如下:-

矩阵中每个单词的频率计算如下。

两者的输出;首字(最常用)和尾字(最不常用)如下

总的来说,总统重复的单词比其他的多。另一方面,根据下表,580 个单词在他的所有演讲中至少被提到两次。

总统强调了下面的单词,因为它们在数据集中出现的频率最高。

“国家”、“政府”、“肯尼亚”、“肯尼亚人”、“成员”、“民族”、“国家”、“人民”、“年份”

看一下与上面最常用的单词相关的单词,可以让我们了解这些单词的使用环境。单词 "country" 的示例在下面的代码和输出中进行了说明:-

主要术语汇总

最主要的术语总结在下面的单词云中。

Summary of all words in Uhurus’ speeches minus stop-words. Bigger words were emphasized by the president more than the ones in smaller fonts.

单词云和条形图通过以下代码生成:-

主题建模

在自然语言处理中,主题模型被定义为帮助发现文档中抽象主题的统计模型。在这种情况下,文档可以是演讲、书籍、评论甚至推特的集合。简而言之,主题建模有助于发现描述某个实体的语义相近的单词/术语。例如,人们很自然地会想到“iPhone”和“lightning cable”会经常出现在关于苹果产品的评论中。

潜在狄利克雷分配(LDA)是一种主题建模技术。LDA 的深入描述是这里。

从上面的代码中,我选择了 K= 3,这意味着数据集被细分为 3 个具有代表性的集合。k 可以改为任何数字,但我把它设置为 3 个主题。有一些方法可以用来识别最佳集群数。

以下是我多年来在这些话题中收集到的一些词汇的摘要

话题三(2014,2018)——宪法,肯尼亚人,价值观,权力下放,和平,统一
话题二(2015,2016,2017)——行政,县,经济,人民,服务。
话题一(2019)——国家、安全、腐败、发展

从这个分析中我们可以很容易地推断出,总统在 2015-2017 年的演讲中强调了行政管理问题,以及为肯尼亚人的经济繁荣提供县级服务。他 2019 年的演讲以安全、发展和腐败为中心。2014 年和 2018 年强调了权力下放、维护宪法、和平和团结等。

进一步定量分析

除了上面的实验,我将对 2014 年至 2019 年的所有演讲进行一系列广泛的对比。我将使用一个叫做定量话语分析软件包( qdap) 的 R 软件包。该包规定了几种比较文本文档的方法。演讲将被转换成数据帧,然后用句子标记器分割成句子,然后用一个变量组合成一个数据帧,该变量指定每个演讲的年份。对于文本输入,需要以下过程

1)从 Qdap 应用 qprep() 函数
—bracketX()#应用括号移除
— replace_abbreviation() #替换缩写
—replace _ number()#数字到单词,例如“100”变成“一百”
— replace_symbol()#符号变成单词,例如@变成“at”

2)替换缩写(不要不要 )
3) strip() —删除不需要的字符,句号和问号除外。
4)发送拆分—将文本拆分成句子,然后添加到分组变量中,即演讲的年份。这也创建了话轮(tot) 变量作为句子顺序的指示器。该位在对话分析中至关重要,例如在问答会话中。

说够了,直接进入有趣的部分。执行上述操作的代码如下

从输出中可以看出,最常见的术语如下所示

Plot showing the most frequent words in Uhuru’s SON speeches between 2014–2019

下面是这些词多年来的使用频率的可视化表格。 Wordmat 方法将此过程简化如下。

我们现在可以获得关于数据集的完整单词统计信息,如下所示

Word statistics summary

从上面的剧情来看,2016 演讲最长(n.sent)。他最短的一次演讲是 2014 年的。可能总统害怕围绕他 2014 年演讲的喋喋不休,因为他记得这是他在 2013 年选举后的第一个儿子。上图中统计变量的描述见此处。请检查一下。

极性

极性被定义为具有两种相反或矛盾的倾向、观点或方面的状态。另一方面,文本情感通常是积极的、消极的或中性的。从下表来看,总统的讲话基本上是积极的。

然而,他 2019 年围绕国家、安全、腐败、发展的演讲是最积极的,标准化平均极性为 0.482 。在这种情况下,标准化平均极性是平均极性除以标准差。句子的极性总结在这个图中。

2014 Speech was deemed most negative with the 2019 one most positive .

最肯定的否定句是“遭受严重挫折导致恐怖袭击”而最肯定的是“代表总发电量增长百分之三十。”有道理哈!获得这一推论的代码如下

可读性

演讲的可读性遵循自动可读性指数。这只是对文本阅读难度的估计。这是通过测量文本在单词和句子长度、音节数等方面的复杂性来实现的。每个可读性指数给出了一个估计的等级水平。这理想地代表了用英语进行的正规教育的年数。

与其他演讲相比,2018 年的国情咨文可读性最高,因为它比 2014 年的略长。其他演讲在可读性方面表现出稳定性,特别是 2014 年和 2017 年的演讲。2015 年的演讲需要研究生/高级本科水平(正规教育 18 年级)的人才能很好地理解。

Automated Readability Index table

演讲中的多样性

应用于对话的多样性是衡量语言丰富程度的一个尺度。具体来说,它在考虑单词的数量和多样性的同时,测量词汇的扩展程度。那么,随着时间的推移,总统的演讲有多大的不同呢?从下面的表格和图表来看,这些演讲并不过分多样化。

Plot showing how diverse the speeches were over time .

这意味着总统在他的演讲中使用了几乎相同的语言。为了清晰地表达他的议程,可能这些年来用词都是一样的。会不会只是政治语言?

最后一个有趣的情节与单词/术语随时间的分散有关。有些词会随着时间的推移而淡化或增加。只要单词存在于语料库中,选择要查看的单词就是用户驱动的。我看了看他演讲中分散的词语、【安全】、【就业】、【经济】、【青年】、【妇女】、【腐败】,我个人觉得国家元首更有可能强调这些词语。

从下面的图中可以看出,“腐败”、“安全”以及某种程度上的“经济”是总统六年来演讲的特点。有趣的是,总统在 2014 年没有谈到“就业”,而是强调了安全。简而言之,从这个情节中可以做出许多推论。

Dispersion of terms over time in the speeches.

结论

以上分析得出了乌胡鲁·肯雅塔演讲中有趣的见解,从主题到多样性。Qdap 包有助于并排语音比较。我期待听到肯尼亚人在演讲结束后的反应,因为当时推特上有很多活动。多样性情节可能在演讲和肯尼亚人当时的想法之间是有意义的。

终极人工智能战略指南

原文:https://towardsdatascience.com/ultimate-ai-strategy-guide-9bfb5e9ecf4e?source=collection_archive---------5-----------------------

Strategy and AI are terms that are hard to pin down — they mean different things to different people. Combine AI and Strategy — 人工知能 战略 — and now you have a harder problem to tackle! The goal of this post is to bring in the best advice out there about AI strategy and add a practitioner’s point of view for a successfully crafting AI strategy.

这篇文章分为三个部分。战略和规划,构建模块——启动和维持人工智能的技术、人员/文化和路线图。

在过去的几年里,人工智能将成为商业的一个主要因素已经变得非常清楚。Gartner 将人工智能纳入了 2019 年十大战略技术趋势。大多数公司都敏锐地意识到,他们至少应该有一个人工智能战略。不说别的,追随人工智能对手的倾向很高[1]。

围绕这项技术的激烈竞争表明,观望策略可能是一个代价高昂的错误。为了从人工智能到 2030 年将产生的 1 万亿美元的全球利润池中分得一杯羹,麦肯锡全球研究所表示,公司应该在未来三年内开始大规模采用人工智能。

然而,企业正在努力制定正确的人工智能战略,这非常像他们在 90 年代末采用电子商务时遇到的挑战。新生技术的采用可能会导致许多问题——选择或花费在错误的计划上,没有找到合适的人才,选择了错误的方向。

战略与人工智能基础

首先,让我们明确战略的定义。我喜欢鲁梅尔特定义战略的方式,并将遵循他的不废话、务实的方法。在《好策略,坏策略》中,鲁梅尔特写道,一个策略有三个关键部分,它们构成了策略核心

  1. 诊断——出了什么问题,为什么?将技术与商业战略联系起来
  2. 指导政策—基础、治理、文化、道德
  3. 一致的行动—资源分配、实施、购买/建造决策、流程编排、人才培养/雇用/保留、文化和变革管理

其次,让我们来定义人工智能:广义上讲,人工智能包括用于教计算机学习、推理、感知、推断、交流和做出类似于或优于人类的决策的技术。人工智能领域包括智能自动化、机器学习(经典机器学习和现代深度学习,也称为深度神经网络)和机器人技术。自动驾驶汽车结合了许多现代人工智能的象征。

这是我的一行人工智能商业方程式。

A I =数据+算法+计算→业务问题→结果

困难的问题是制定一个适合你特定业务环境的人工智能策略——也就是说,它考虑了所有的外部因素和内部因素。吴恩达建议“成为你所在行业的领先人工智能公司,开发独特的人工智能能力将让你获得竞争优势。”

安德鲁补充说,人工智能如何影响你公司的战略将因行业和情况而异。

许多专家指出,你不能把人工智能战略作为第一步,因为你需要发展对人工智能的理解,而这需要在不确定的情况下进行实验。这有通过 AI 的所谓良性循环学习的好处。

From Andrew Ng — AI Transformation Playbook [4] — Link

就像任何坚固建筑的建筑要求一样,你需要从地面条件开始,并确保你建立一个坚固的基础。否则,无论你建造什么上层建筑,将来都会遇到代价高昂的问题。

接下来的部分将更多地讨论如何利用适合您情况的数据、算法和计算基础设施来构建数字基础。你需要具有不同背景、教育和技能的人——例如,你需要具有数据专业知识和机器学习知识的人,但也需要擅长沟通业务和技术问题的人,也称为“翻译”你需要强大的流程。

对人工智能的好处和局限性要现实。人工智能有很好的用例,也有可能让你陷入没有清晰价值路径的兔子路。一家公司可以采取一种渐进的方式,比如在参与更复杂的项目之前,尝试机器人流程自动化。

“人工智能将改善产品和流程,并使决策更加明智——这是重要但基本上不可见的任务。”托马斯·达文波特[10]

正如鲁梅尔特指出的,看看糟糕策略的例子会有所帮助,这样你就可以避免它。以下是一些常见的不良策略。

  • 把目标误认为战略——不要只是说你想要人工智能的领导地位,要创造条件让你达到目标
  • 模糊的战略目标——一长串要做的事情,却没有如何实现的明确计划,缺乏对精力和资源的关注
  • 缺乏协调的行动-重复工作、所有权政治、发出混合信号的决策、高级管理人员缺乏对人工智能的基本理解
  • 无法选择和区分优先顺序——哪些项目适合人工智能?我们应该选择什么样的管理和组织结构?

了解构建模块—技术

记住,战略就是采取行动克服障碍或抓住机遇。任何人工智能努力都将依赖于三个主要组成部分:数据、基础设施和人才。

  • 数据是当今人工智能驱动洞察力的基本元素——在许多情况下超过算法本身。需要付出巨大的努力和投资才能让您的数据基础正确。提高数据质量和管理数据是一项复杂而长期的工作。对于所有行业的管理者来说,数据所有权都是一个令人头疼的问题。一些数据是专有的,其他数据是跨数据源的碎片,需要整合并与多个其他组织达成协议,以便获得更完整的信息来训练人工智能系统。

跨客户群和渠道链接数据,而不是让数据在孤岛中枯萎,对于创造价值尤为重要。——麦肯锡[15]

  • 计算基础设施,包括软件和硬件,必须到位以有效运行机器学习模型。ML 需要专门的硬件(GPU、FPGA 或 ASIC),无论是在云中还是在内部(由于法规或其他业务原因)。)
  • 人工智能在有效利用机器学习方面至关重要。虽然不是每个公司都会寻求建立一个内部人工智能组织,但接触经验丰富的数据科学家、数据工程师、数据产品经理和人工智能开发运营专家是推动人工智能价值并将其扩展到盈利能力的关键。

吴恩达[4]建议说,一个公司要想在人工智能方面表现出色,它必须具备:

在多个有价值的人工智能项目上系统执行的资源——无论是外包的还是内部的技术和人才。

对人工智能有足够的了解:应该对人工智能有一个总体的了解,有适当的过程来系统地识别和选择有价值的人工智能项目。

战略方向:为了在人工智能驱动的未来取得成功,公司的战略是否大体一致

建筑材料——人与文化

你可能认为技术是人工智能战略的关键,但是人和文化对你的人工智能战略的成功和技术一样重要。在 O'Reilly 最近的一份调查报告中,很明显文化是人工智能采用的主要挑战。首先,人工智能需要不同的团队一起工作,如果合作文化不存在,人工智能计划就会受到影响。

人工智能还意味着对人们的工作和流程的改变和破坏。伴随人工智能的自动化可以取代许多工作,并迫使其他人学习新技能。大多数时候它是一个黑盒,对于某些场景,它的价值是未经证实的。难怪许多工作人员担心人工智能,并随着人工智能的实施感到脱离了他们的舒适区。

算法需要新的治理模式。正如任何文化变革一样,在做出重大改变之前,要小心谨慎。

根据 O'Reilly Media 的调查结果,不承认需求、缺乏数据和人才短缺的企业文化阻碍了人工智能在各组织中的广泛采用。

瓶颈。大量受访者(23%)表示,公司文化是采用人工智能的主要障碍,19%表示最大的问题是缺乏数据或数据质量,18%表示缺乏技术人员和难以雇用人才,17%表示难以确定适当的业务用例,8%表示是技术基础设施挑战。

人才招聘和管理仍然是一个关键因素。在你开始招聘之前,定义一下合适的团队是什么样的?你需要有深度、多种技能、经验丰富、多元化的人。正如本帖[12]所指出的,正确的团队应该包括领域专家和社会科学家,他们可以提供互补的观点并支持技术团队。不要沉迷于雇佣 AI 的摇滚明星而不创造成功的条件。

正如在[6]中提到的,人工智能技术管理还有更多。

人工智能技术的管理还涉及新的领导技能,包括实施嵌入人工智能的现代流程所需的技能。成功接受人工智能的公司致力于转型计划,高层管理人员接受变革,跨职能管理团队准备重新定义他们的流程和活动。

创建和鼓励跟踪和揭示人工智能决策的方法——最好使用行动审计跟踪和可视化或解释结果的功能。让设计师和 UI / UX 专家参与进来。确保非技术经理很好地理解解释。

当然,良好的沟通或缺乏沟通是问题的主要原因[9]。

人工智能战略之所以失败,是因为人工智能是一种手段,而不是目的。“你有人工智能战略吗?”就像问“我们有 Excel 战略吗?”但对于公司来说,要想摆脱炒作,专注于人工智能提供的真正潜力,他们必须从如何沟通开始。

要注意的差距

注意 3 个关键差距:业务-IT 差距、数据分析差距和老手-新手差距(稍后会有更多关于人员和文化的部分)。在人工智能中建立信任和检测并消除偏见仍然是人工智能采用的最大挑战之一。

正如 Moldoveanu 在这篇 HBR 的文章[9]中提到的,技术人员和商业人士之间有非常不同的工作方式。

开发人员希望清晰、精确的指令能够很容易地翻译成代码或伪代码。业务发展主管为他们提供故事和趣闻。

Credit: Avanade.com

还有一个不容忽视的风险因素。如果你的人工智能策略有负面后果或监管问题,它可能会适得其反。请看[13]了解更多信息,以及[14]如何降低这种风险。

道德、公平和包容性需要认真考虑。在华盛顿邮报的专栏中,黑石集团首席执行官苏世民推荐了一种道德驱动的人工智能方法,告诉消费者人工智能何时被使用,避免偏见,解决隐私问题,并寻求为被技术取代的工人创造机会。

这些都是热门话题,有许多不同的观点,详细的讨论超出了本文的范围——参见我关于公平和负责任的人工智能的初级读本[11]中对关键问题的总结。

启动和维持人工智能计划的路线图

以上几节谈到了技术、人员、文化和道德。现在,让我们讨论一些部署和扩展人工智能计划的实用方法以及企业面临的常见挑战。成功执行战略的关键成功因素包括有效的流程和治理、管理资源和规避风险。本节包括一系列工具和资源,帮助你走上人工智能应用的正确道路。

  • 共同的挑战
  • 结构
  • 推荐
  • 清单
  • 数字成熟度评估

挑战——不要低估人工智能成功所需的挑战和努力

有了这么多的宣传和炒作,公司可能会很容易加入进来,认为人工智能可以很快产生有利的结果。研究表明,组织往往会低估克服复杂性和让人工智能起飞所需的时间。

人工智能的实验和学习可能比其他数字计划需要更长的时间,成功和失败的可变性更高。

根据 2017 年年度企业调查的结果,目前正在试点人工智能项目的公司中,58%的受访者表示花了两年或更长时间才达到试点阶段,只有 28%的受访者报告说在第一年就通过了规划阶段。

一些组织迷失在许多不同的原型和 POC 中,无法扩展—您不会经常听到失败的项目或计划,它们开始时有很多讨论,但后来因为结果的质量或缺乏明确的 ROI 而失败。较大的组织在创建卓越中心和提供监督但允许业务单位自治的组织结构方面取得了成功。

通过与你的同行交谈和倾听从业者,而不仅仅是倾向于过分强调成功故事的分析师和作者,来获得一些现实。

信任是一个主要因素。你如何让非技术团队相信人工智能解决方案是可靠和可依赖的?深度学习是一个热门领域,但众所周知,很难解释它如何做出决定。要做到这一点,需要精心的规划和沟通。

如果你的人工智能策略引发负面后果或导致监管问题,它可能会适得其反。请看[13]了解更多信息,以及[14]如何降低这种风险。

人工智能战略规划

这个简单的图表抓住了人工智能战略计划的关键要素。

Credit: Gartner, Inc. [5]

人工智能框架

最好从业务成果的角度来考虑人工智能战略,然后再回到常见的企业功能和解决方案领域。例如,如果你有一个很好的聊天机器人用例,那么这项技术可以被多个群体使用。

管理人工智能团队

存在许多模型——集中式和分布式模型各有利弊。

AI 策略建议

  1. ****数字成熟度:你在数字成熟度曲线上处于什么位置?你如何能加速它,以便你能加快人工智能能力的步伐?
  2. ****评估业务潜力:什么是正确的用例?是否有足够的价值?深入思考用例,评估多种场景
  3. 渐进方法:对人工智能之旅采取分阶段的方法。在短期内,专注于具有成熟技术的用例;中期,试验技术以评估其价值;从长远来看,与尖端技术合作可以给企业带来先发优势。记住,人工智能技术还不成熟,不要期望马上就有投资回报
  4. 领导能力:抵制让技术团队单独负责人工智能项目的诱惑。发展应该由商业和技术领导者共同领导[麦肯锡]
  5. ****制造 vs 购买:你应该建造、购买还是外包?你有理解各种新方法的天赋吗?正如任何被大肆宣传的新技术一样,新创造的解决方案和顾问并不缺乏。在整个组织中发展核心领导力和知识,同时根据需要从外部专家那里获得帮助

人工智能战略清单

这里有一个 Gartner 关于人工智能采用的简单清单。

Credit: Gartner, Inc. [5]

人工智能数字成熟度评估

即使是在有着大量集成新技术和管理数据历史的行业,人工智能采用的障碍也可能难以克服。人工智能需要更激进的思维,因为它影响了基于知识和判断的职业。这篇来自麻省理工斯隆评论的文章问道:是什么阻止了组织采用 AI?

** [## 用人工智能重塑商业

关于作者:Sam Ransbotham 是卡罗尔学校信息系统系的副教授…

sloanreview.mit.edu](https://sloanreview.mit.edu/projects/reshaping-business-with-artificial-intelligence/)

它定义了四个不同的组织成熟度集群:先锋、调查者、实验者和被动者

  • 先锋(19%): 既了解又采用 AI 的组织。这些组织在将人工智能纳入其组织的产品和内部流程方面处于领先地位。
  • 调查人员(32%): 了解人工智能但没有在试点阶段之后部署它的组织。他们对人工智能可能提供什么的调查强调先看后跳。
  • 实验者(13%): 在没有深入了解的情况下,正在试点或采用 AI 的组织。这些组织在实践中学习。
  • 被动型(36%): 对 AI 没有采用或了解不多的组织。他们还没有找到符合他们投资标准的可靠的商业案例。领导层可能不同意。

结论

这篇文章展示了人工智能策略的许多方面。最终,最重要的是愿景和领导力、开放性和变革能力、长期思维、业务和技术战略的紧密结合,以及克服障碍和适应新技术的文化。

参考资料:

  1. 雅克·布欣。观望可能是一种代价高昂的人工智能策略。麻省理工斯隆评论,2018。https://Sloan review . MIT . edu/article/wait-and-see-be-a-cost-ai-strategy/
  2. 好策略,坏策略。皇冠出版社,2011 年。(也可以看这篇关于这本书的 r 兴高采烈的帖子。)
  3. 微软 AI 商学院。在线看https://www.microsoft.com/en-us/ai/ai-business-school
  4. 吴恩达。AI 改造剧本(可从https://landing.ai/ai-transformation-playbook/获得),登陆 AI。2019.
  5. Bern Elliott,在企业中应用人工智能的框架(网络研讨会演示文稿),Gartner.com,2018 年。
  6. 雅克·布欣和埃里克·哈赞。从人工智能中获得最大收益的五种管理策略。McKinsey.com 和麻省理工斯隆管理评论,2017。https://www . McKinsey . com/mgi/overview/in-the-news/five-management-strategies-for-get-the-most-from-ai
  7. 人工智能战略家指南。普华永道战略+业务,2017。
  8. 编辑惠特·安德鲁斯。构建人工智能商业案例。首席信息官在企业中实施人工智能的战略和商业案例指南。Gartner.com。2018.
  9. 米尼亚·莫尔多瓦努。为什么人工智能表现不佳,公司可以做些什么。HBR,2019。https://HBR . org/2019/03/why-ai-表现不佳,公司能做些什么?
  10. 托马斯·达文波特。人工智能的优势:如何将人工智能革命付诸实施。麻省理工出版社。2018.
  11. 巴巴尔·巴蒂。公平负责的 ML 和 AI 入门。https://towards data science . com/ai-policy-making-part-4-a-primer-on-fair-and-responsible-ai-28f 52 b 32190 f
  12. 卡西·科兹尔科夫。为什么企业在机器学习上失败。https://hacker noon . com/why-business-fail-at-machine-learning-fbff 41 c 4d db
  13. 迈克尔斯潘塞。2019 年人工智能的危险。https://medium . com/future sin/the-dangeries-of-artificial-intelligence-in-2019-19e 14 fa 45 aa 4
  14. 伯恩哈德·巴贝尔、凯文·布勒、亚当·皮冯卡、布莱恩·理查德森和德里克·瓦尔德罗。衍生机器学习和人工智能。麦肯锡,2019。https://www . McKinsey . com/business-functions/risk/our-insights/derisking-machine-learning-and-artificial-intelligence
  15. 迈克尔·楚伊(Michael Chui)、詹姆斯·马尼伊卡(James Manyika)、迈赫迪·米雷马迪(Mehdi mire madi)尼古拉·亨克(Nicola us Henke)、丽塔·钟(Rita Chung)、彼得·内尔(Pieter Nel)和桑卡普·马尔霍特拉(Sankalp Malhotra)。麦肯锡,2018。https://www . McKinsey . com/featured-insights/artificial-intelligence/notes-from-the-ai-frontier-applications-and-value-of-deep-learning**

数据搜集、清理和可视化初学者终极指南

原文:https://towardsdatascience.com/ultimate-beginners-guide-to-scraping-and-cleaning-twitter-data-a64e4aaa9343?source=collection_archive---------2-----------------------

如何简单地通过清理和预处理数据,让您的模型从不起眼变得令人惊叹

Photo by Nitin Sharma from Pexels

如果你有一个结果可以接受但并不惊人的模型,看看你的数据吧!花时间以正确的方式清理和预处理您的数据可以让您的模型成为明星。

Photo by Burst from Pexels

为了更详细地了解搜集和预处理,让我们来看看“你就是你发的微博:通过 Twitter 使用检测社交媒体中的抑郁症”中的一些工作这样,我们可以真正检查抓取推文,然后清理和预处理推文的过程。我们还将做一些探索性的可视化,这是一种更好地了解您的数据的方式!我们将在这里做一些最基本的清理和预处理工作:当你建立你的模型时,真正把这些 Tweets 按顺序整理好是你自己的事!

[## 你在推特上说什么就是什么

通过 Twitter 使用检测社交媒体中的抑郁症

towardsdatascience.com](/you-are-what-you-tweet-7e23fb84f4ed)

一点背景

超过 3 亿人患有抑郁症,只有一小部分人接受了适当的治疗。抑郁症是全球残疾的主要原因,每年有近 80 万人死于自杀。自杀是 15-29 岁人群的第二大死因。抑郁症的诊断(和随后的治疗)经常被延迟、不精确和/或完全错过。

不一定要这样!社交媒体为转变早期抑郁症干预服务提供了前所未有的机会,特别是在年轻人中。

每秒钟,Twitter 上大约有 6000 条推文,相当于每分钟发送 35 万条推文,每天 5 亿条推文,每年约 2000 亿条推文。皮尤研究中心指出,目前,72%的公众使用某种类型的社交媒体。该项目捕捉并分析与抑郁症状的发作和持续相关的语言标记,以建立一种可以有效预测抑郁的算法。通过建立一种可以分析表现出自我评估抑郁特征的推文的算法,个人、父母、护理人员和医疗专业人员将有可能分析社交媒体帖子,以寻找标志着精神健康恶化的语言线索,这远远早于传统方法。分析社交媒体帖子中的语言标记可以进行低调的评估,这种评估可以补充传统服务,并且可以比传统方法更早地意识到抑郁迹象。

我们从哪里开始?

我们需要数据!

Photo by Quang Nguyen Vinh from Pexels

收集数据

为了建立一个抑郁症检测器,需要两种推文:不一定表明抑郁症的随机推文和表明用户可能患有抑郁症和/或抑郁症状的推文。随机推文的数据集可以来源于 Kaggle 上可用的sensition 140 数据集,但对于这种二进制分类模型,这种利用 sensition 140 数据集并提供一组二进制标签的数据集被证明是建立稳健模型的最有效方法。没有公开可用的表明抑郁的推文数据集,所以使用 Twitter 抓取工具 TWINT 检索“抑郁”推文。手动检查抓取的推文的相关性(例如,推文表明情绪而非经济或气氛抑郁),并清理和处理推文。通过搜索与抑郁症特别相关的术语,特别是 De Choudhury 等人在 unigram 中确定的词汇术语,来收集推文。艾尔。

TWINT 是一款非常简单易用的工具!

您可以使用以下命令从命令行下载它:

pip install twint

例如,如果您想要搜索 2019 年 7 月 20 日的术语“抑郁症”,并将数据存储为名为“抑郁症”的新 csv,您可以运行类似以下的命令:

twint -s "depression" --since 2019-07-20 -o depression —csv

一旦你收集了推文,你就可以开始清理和预处理它们。您可能会得到大量不需要的信息,比如对话 id 等等。您可以决定创建多个想要合并的 CSV。我们会谈到这一切的!

模特表现如何?

一开始?没那么令人印象深刻。在对数据进行基本的清理和预处理之后,最好的结果(即使在花费时间对模型进行微调之后)徘徊在 80%左右。

在我检查了词频和二元模型后,这个原因真的很有意义。探索您的数据!当我看到单词本身时,我意识到以正确的方式清理和准备数据集需要大量的工作,并且这样做是绝对必要的。部分清洁过程必须手动完成,所以不要害怕进去弄脏你的手。这需要时间,但是值得!

最后呢?使用逻辑回归对该模型的准确性进行评估,并与二元分类基线模型进行比较。分析模型的准确性,并运行分类报告以确定精确度和召回分数。数据被分成训练集、测试集和验证集,模型的准确性是根据模型对测试数据的性能来确定的,测试数据是分开保存的。虽然使用相同的数据、学习率和时期,基准逻辑回归模型的性能为 64.32%,但 LSTM 模型的性能明显更好,为 97.21%。

那么,我们是如何从抓取的推文得到结果的呢?

练习,练习,练习!(还有一些正经工作。)

Photo by DSD from Pexels

(如果你是数据科学、机器学习和人工智能的新手,你可能想看看 NumPy 的终极初学者指南!)

[## NumPy 初学者终极指南

开始使用 NumPy 需要知道的一切

towardsdatascience.com](/the-ultimate-beginners-guide-to-numpy-f5a2f99aef54)

基本清洁和预处理

比方说,我们在 Twitter 上搜索“抑郁”、“沮丧”、“无望”、“孤独”、“自杀”和“抗抑郁”等搜索词,并将这些搜索到的推文文件保存为文件“tweets.csv”中的“抑郁”等。

我们将从几个进口开始

**import** **pandas** **as** **pd**
**import** **numpy** **as** **np**

**import** **pandas** **as** **pd**  
**import** **numpy** **as** **np**
**import** **matplotlib.pyplot** **as** **plt**
plt.style.use('fivethirtyeight')

%matplotlib inline
%config InlineBackend.figure_format = 'retina'
**import** **re**
**from** **nltk.tokenize** **import** WordPunctTokenizer
tok = WordPunctTokenizer()

我们将阅读我们的一个 CSV 文件,并看看头部。

hopeless_tweets_df = pd.read_csv('hopeless/tweets.csv')
hopeless_tweets_df.head()

首先,我们应该去掉数据集中存储的任何不必要的信息。对于这个项目,我们不需要名称、id、对话 id、地理位置等等。我们可以通过以下方式将它们取出:

hopeless_tweets_df.drop(['date', 'timezone', 'username', 'name', 'conversation_id', 'created_at', 'user_id', 'place', 'likes_count', 'link', 'retweet', 'quote_url', 'video', 'user_rt_id', 'near', 'geo', 'mentions', 'urls', 'photos', 'replies_count', 'retweets_count'], axis = 1, inplace = **True**)

现在有了这个,就好处理多了!

现在,只需对您使用搜索词创建的所有 CSV 进行上述操作,我们就可以将我们单独的数据集合并为一个!

df_row_reindex = pd.concat([depression_tweets_df, hopeless_tweets_df, lonely_tweets_df, antidepressant_tweets_df, antidepressants_tweets_df, suicide_tweets_df], ignore_index=**True**)

df_row_reindex

在我们继续之前,让我们放弃重复

depressive_twint_tweets_df = df.drop_duplicates()

并将我们的数据集保存为新的 CSV 格式!

export_csv = depressive_twint_tweets_df.to_csv(r'depressive_unigram_tweets_final.csv')

更高级的预处理

在模型中使用数据之前,有必要展开缩写、删除链接、标签、大写和标点符号。需要处理否定。这意味着创建一个否定字典,这样被否定的单词就可以被有效地处理。链接和网址需要删除连同空白。此外,需要删除标准 NLTK 停用词以外的停用词,以使模型更加健壮。这些单词包括一周中的日子及其缩写、月份名称,以及单词“Twitter”,令人惊讶的是,当单词 clouds 被创建时,它作为一个突出的单词出现。然后将推文标记化,并使用 PorterStemmer 来阻止推文。

让我们去掉所有对我们没有帮助的东西!

当然是进口

**import** **pandas** **as** **pd**
**import** **numpy** **as** **np**
**import** **matplotlib.pyplot** **as** **plt**
**import** **seaborn** **as** **sns**
**import** **itertools**
**import** **collections
import** **re
import** **networkx** **as** **nx****import** **nltk** nltk.download(['punkt','stopwords'])
**from** **nltk.corpus** **import** stopwords
stopwords = stopwords.words('english')
**from** **nltk.corpus** **import** stopwords
**from** **nltk** **import** bigrams

**import** **warnings**
warnings.filterwarnings("ignore")

sns.set(font_scale=1.5)
sns.set_style("whitegrid")
**from** **vaderSentiment.vaderSentiment** **import** SentimentIntensityAnalyzer
analyzer = SentimentIntensityAnalyzer()%matplotlib inline
%config InlineBackend.figure_format = 'retina'

阅读您的新 CSV

pd.read_csv('depressive_unigram_tweets_final.csv')

把它变成熊猫的数据框

df2 = pd.read_csv('depressive_unigram_tweets_final.csv')

现在让我们看看是否有空值。我们来清理一下吧!

我们将快速删除推文中的停用词

df_new['clean_tweet'] = df_new['tweet'].apply(**lambda** x: ' '.join([item **for** item **in** x.split() **if** item **not** **in** stopwords]))

如果你愿意,你可以分析这些推文来获得 VADER 情绪分析分数!

df_new['vader_score'] = df_new['clean_tweet'].apply(**lambda** x: analyzer.polarity_scores(x)['compound'])

在那里,您还可以创建标签。对于二进制分类模型,您可能需要二进制标签系统。但是,要注意你的数据!情绪得分本身并不表明抑郁,假设负得分表明抑郁也太简单了。事实上,快感缺失是抑郁症极其常见的症状。中性或平淡的推文,如果不是更有可能,至少也是抑郁症的一个指标,不应被忽视。

出于实验的目的,您可能想要设置一个这样的情感分析标签。请随意使用它!

positive_num = len(df_new[df_new['vader_score'] >=0.05]) negative_num = len(df_new[df_new['vader_score']<0.05])df_new['vader_sentiment_label']= df_new['vader_score'].map(**lambda** x:int(1) **if** x>=0.05 **else** int(0))

如果你需要,扔掉你不需要的东西

df_new = df_new[['Unnamed: 0', 'vader_sentiment_label', 'vader_score', 'clean_tweet']]df_new.head()

继续保存一个 csv!

df_new.to_csv('vader_processed_final.csv')

我们继续玩吧!

df_new['text'] = df_new['clean_tweet']
df_new['text']

我们可以删除网址

**def** remove_url(txt):
    **return** " ".join(re.sub("([^0-9A-Za-z **\t**])|(\w+:\/\/\S+)", "", txt).split())all_tweets_no_urls = [remove_url(tweet) **for** tweet **in** df_new['text']]
all_tweets_no_urls[:5]

现在让我们把所有的东西都变成小写,把推文分开。

*#lower_case = [word.lower() for word in df_new['text']]*
sentences = df_new['text']all_tweets_no_urls[0].split()words_in_tweet = [tweet.lower().split() **for** tweet **in** all_tweets_no_urls]
words_in_tweet[:2]

手工清洗

这不好玩,也不漂亮,但是手工清洁是至关重要的。这花了几个小时,但是去掉了对热带低气压和经济低气压的引用改进了模型。删除电影标题的推文改进了模型(你可以在下面的二元图中看到“X 特遣队”)。删除包含搜索术语的引用新闻标题改进了模型。感觉要花很长时间才能完成,但是这一步对模型的健壮性产生了巨大的影响。

探索性可视化和分析

现在我们来看性格和词频!

分析数据集中最常见的单词相当容易。去掉停用词后,很明显有些词比其他词出现得更频繁。

来统计一下我们最常用的单词吧!

*# List of all words*
all_words_no_urls = list(itertools.chain(*words_in_tweet))

*# Create counter*
counts_no_urls = collections.Counter(all_words_no_urls)

counts_no_urls.most_common(15)

并把它们转换成数据帧。

clean_tweets_no_urls = pd.DataFrame(counts_no_urls.most_common(15),
                             columns=['words', 'count'])

clean_tweets_no_urls.head()

嗯。停用词太多。让我们来处理这些。

stop_words = set(stopwords.words('english'))*# Remove stop words from each tweet list of words*
tweets_nsw = [[word **for** word **in** tweet_words **if** **not** word **in** stop_words]
              **for** tweet_words **in** words_in_tweet]

tweets_nsw[0]

让我们再看一看。

all_words_nsw = list(itertools.chain(*tweets_nsw))  counts_nsw = collections.Counter(all_words_nsw)  counts_nsw.most_common(15)

好些了,但还不够好。这些单词中的一些并没有告诉我们太多。再做几个调整吧。

collection_words = ['im', 'de', 'like', 'one']
tweets_nsw_nc = [[w **for** w **in** word **if** **not** w **in** collection_words]
                 **for** word **in** tweets_nsw]

现在

*# Flatten list of words in clean tweets*
all_words_nsw_nc = list(itertools.chain(*tweets_nsw_nc))

*# Create counter of words in clean tweets*
counts_nsw_nc = collections.Counter(all_words_nsw_nc)

counts_nsw_nc.most_common(15)

好多了!让我们将它保存为数据帧。

clean_tweets_ncw = pd.DataFrame(counts_nsw_nc.most_common(15),
                             columns=['words', 'count'])
clean_tweets_ncw.head()

那看起来像什么?我们来形象化一下吧!

fig, ax = plt.subplots(figsize=(8, 8))

*# Plot horizontal bar graph*
clean_tweets_no_urls.sort_values(by='count').plot.barh(x='words',
                      y='count',
                      ax=ax,
                      color="purple")

ax.set_title("Common Words Found in Tweets (Including All Words)")

plt.show()

让我们来看看一些大人物!

**from** **nltk** **import** bigrams

*# Create list of lists containing bigrams in tweets*
terms_bigram = [list(bigrams(tweet)) **for** tweet **in** tweets_nsw_nc]

*# View bigrams for the first tweet*
terms_bigram[0]*# Flatten list of bigrams in clean tweets*
bigrams = list(itertools.chain(*terms_bigram))

*# Create counter of words in clean bigrams*
bigram_counts = collections.Counter(bigrams)

bigram_counts.most_common(20)bigram_df = pd.DataFrame(bigram_counts.most_common(20),                              columns=['bigram', 'count'])  bigram_df

某些二元模型也非常常见,包括微笑和宽阔,出现 42,185 次,害怕和孤独,出现 4,641 次,感觉和孤独,出现 3,541 次。

这只是清理、预处理和可视化数据的开始。在构建我们的模型之前,我们还可以从这里做很多事情!

一旦清理了推文,通过用清理过的推文创建单词云,很容易看出两个数据集之间的差异。仅通过 TWINT Twitter 的简短抓取,两个数据集之间的差异就很明显:

随机推文词云:

郁啾词云:

在这个过程的早期,很明显,为了获得更准确的结果,优化模型的最重要部分是数据收集、清理和预处理阶段。在对推文进行适当的清理之前,该模型的准确性并不令人印象深刻。通过更加仔细地清理和处理推文,模型的鲁棒性提高到了 97%。

如果您对了解数据清理和预处理的绝对基础感兴趣,可以看看这篇文章!

[## 数据清理和预处理完全初学者指南

如何在几分钟内为机器学习模型成功准备数据

towardsdatascience.com](/the-complete-beginners-guide-to-data-cleaning-and-preprocessing-2070b7d4c6d)

感谢阅读!和往常一样,如果你用这些信息做了什么很酷的事情,请在下面的评论中让每个人都知道,或者随时联系我们!

下一个 Golang 项目的终极设置

原文:https://towardsdatascience.com/ultimate-setup-for-your-next-golang-project-1cc989ad2a96?source=collection_archive---------8-----------------------

注:这最初发布在martinheinz . dev

对我来说,当开始一个新项目时,最大的困难总是试图“完美地”完成这个项目。我总是试图使用最好的目录结构,这样一切都很容易找到,导入工作也很好,设置所有命令,这样我总是一次点击/命令就可以完成所需的操作,为我正在使用的语言/库找到最好的 linter、formatter、测试框架…

这个清单还在继续,但我从来没有对这个设置感到满意过…除了这个最终的和最好的 Golang 设置!

注意:这个设置工作得很好,部分原因是它基于现有的项目,这些项目可以在 这里 这里 找到。

TL;博士:这是我的知识库—https://github.com/MartinHeinz/go-project-blueprint

目录结构

首先,让我们回顾一下我们的项目的目录结构。有几个顶级文件和 4 个目录:

  • pkg -让我们从简单的开始- pkg是一个 Go 包,它只包含全局版本字符串。这将替代在构建过程中根据提交哈希计算的实际版本。
  • config -接下来,有一个配置目录,其中包含所有必要的环境变量。任何文件类型都可以使用,但是我推荐 YAML 的文件,因为它们可读性更好。
  • build -该目录包含构建和测试应用程序以及为代码分析工具生成报告所需的所有 shell 脚本
  • cmd -真实源代码!按照惯例,源目录被命名为cmd,里面有另一个项目名称的目录——在本例中是blueprint。接下来,在这个目录中有一个运行整个应用程序的main.go,和它一起的还有所有其他被划分成模块的源文件(稍后会详细介绍)。

注:从一些反馈中,我发现很多人更喜欢使用 *internal* *pkg* 目录来存放他们所有的源代码。我个人觉得这是不必要和多余的,因此我把一切都放进 *cmd* ,但各归各的。

除了目录之外,还有相当多的文件,我们将在下面的章节中讨论它们。

Go 模块实现完美的依赖性管理

项目使用各种各样的依赖管理策略。然而,从版本 1.11 开始 Go 有了官方的依赖管理解决方案。我们所有的依赖项都列在go.mod文件中,这个文件可以在根目录中找到。这可能是它看起来的样子:

你可能会问“文件是如何被依赖关系填充的?”。很简单,你只需要一个命令:

该命令根据go.mod文件和 Go 源代码的状态重置主模块的供应商目录,以包含构建和测试所有模块包所需的所有包。

实际源代码和配置

现在我们终于开始讨论源代码了。如上所述,源代码被分成模块。每个模块都是源根目录下的一个目录。每个模块都有源文件和测试文件,例如:

这种结构有助于提高可读性和可维护性,因为它将代码分成了更容易遍历合理的块。至于配置,在这个设置中我使用了 Viper ,它是 Go 配置库,可以处理各种格式、命令行标志、环境变量等。

那么我们这里怎么用(蝰蛇)呢?我们来看看config套餐:

这个包由一个文件组成。它声明了一个保存所有配置变量的函数struct,还有一个加载配置的函数LoadConfig。它采用配置文件的路径,在我们的例子中,我们将使用路径到config目录,该目录位于项目根目录中,包含我们的 YAML 文件(如上所述)。我们如何使用它?我们在main.go中首先运行它:

简单快速的测试

仅次于代码本身的第二重要的东西?质量测试。为了愿意编写大量好的测试,您需要一个能让您轻松做到这一点的设置。为了实现这一点,我们将使用名为testMakefile目标,它收集并运行cmd子目录中的所有测试(所有带有_test.go后缀的文件)。这些测试也会被缓存,所以它们只有在相关代码发生变化时才会运行。这是至关重要的,如果测试太慢,你将(很可能)最终停止运行和维护它们。除了单元测试之外,make test还可以帮助您维护一般的代码质量,因为它还会在每次测试运行时运行gofmtgo vetgo fmt强制你正确格式化你的代码,而go vet使用试探法发现任何可疑的代码结构。示例输出:

总是在 Docker 中运行

人们经常说“它在我的机器上工作(而不是在云中)……”,为了避免这一点,我们有一个简单的解决方案——总是在 docker 容器中运行。当我说总是时,我是认真的——在容器中构建,在容器中运行,在容器中测试。其实上一节我没提,但是make test真的是“就】 docker run

那么,这里是怎么运作的?让我们从项目根中的Dockerfiles开始——我们有两个,一个用于测试(test.Dockerfile),一个用于运行应用(in.Dockerfile):

  • test.Dockerfile -在理想情况下,我们应该只有一个 docker 文件来运行和测试应用程序。然而,在运行测试时,可能需要对环境进行一些小的调整。这就是为什么我们在这里有这个图像——允许我们安装额外的工具和库,以防我们的测试需要它。例如,让我们假设我们有一个正在连接的数据库。我们不希望每次测试运行都启动整个 PostgreSQL 服务器,也不希望依赖主机上运行的一些数据库。因此,我们可以使用内存数据库进行测试。但是,你猜怎么着? SQLite 二进制要求。那么,我们该怎么办?我们只需安装gccg++,翻转CGO_ENABLED标志,就可以开始了。
  • in.Dockerfile -如果你在存储库中查看这个Dockerfile,它只是一堆参数和将配置复制到映像中-那么,那里发生了什么?当我们运行make container时,in.Dockerfile仅在Makefile中使用,在那里参数被填充。现在,是时候看看Makefile本身了,它为我们做了所有的docker事情。👇

用 Makefile 把它们结合在一起

很长一段时间以来,Makefiles对我来说似乎很可怕,因为我只见过它们与C代码一起使用,但它们并不可怕,可以用于很多事情,包括这个项目!现在让我们探索一下Makefile中的目标:

  • make test -工作流中的第一步-应用构建-在bin目录中构建二进制可执行文件:

  • make test -下一个是测试-它再次使用几乎相同的docker run,唯一的区别是test.sh脚本(仅相关部分):

上面几行是文件的重要部分。首先,它们使用给定的路径作为参数来收集测试目标。第二行运行测试并将输出打印到 std out。剩下的两行分别运行go fmtgo vet,收集错误(如果有)并打印出来。

  • make container -现在,最重要的部分-创建可部署的容器:

这个目标的代码非常简单,它首先替换in.Dockerfile中的变量,然后运行docker build来生成带有【dirty】【latest】标签的图像。最后,它将容器名打印到标准输出中。

  • 接下来,当我们有图像时,我们需要把它存储在某个地方,对吗?因此,make push所做的就是将图像推送到 Docker 注册表。
  • make ciMakefile的另一个好用途是在我们的 CI/CD 管道中利用它(下一节)。这个目标与make test非常相似——它也运行所有的测试,但是除此之外,它还生成覆盖报告,这些报告随后被用作代码分析工具的输入。
  • make clean -最后,如果我们想要清理我们的项目,我们可以运行make clean,这将删除由先前的目标生成的所有文件。

我将省略其余的,因为正常工作流程不需要它们,或者它们只是其他目标的一部分。

CI/CD 带来终极编码体验

最后,但绝对不是最不重要的— CI/CD 。有了这么好的设置(如果我自己这么说的话),省略一些花哨的管道将是一种耻辱,这些管道可以为我们做大量的事情,对吗?我不会对管道中的内容进行过多的详细描述,因为您可以在这里自己查看(我还包括了几乎每一行的注释,所以一切都有解释),但是我想指出几件事:

这个 Travis 构建使用矩阵构建和 4 个并行作业来加速整个过程

  • 构建和测试我们验证应用程序是否按预期工作
  • SonarCloud 生成覆盖报告,并将其发送到 SonarCloud 服务器
  • 这里,和上一个一样,我们生成报告并发送给 CodeClimate
  • 推送到注册表 —最后,我们将容器推送到 GitHub 注册表(敬请关注关于此事的博文!)

结论

我希望这篇文章能对你未来的编码冒险有所帮助。如果你想看到更多的细节,请点击查看仓库。此外,如果您有任何反馈或改进的想法,请不要犹豫,提交问题,签署回购协议或给一颗星,这样我知道再多做一点工作是有意义的。🙂

在下一部分中,我们将看看如何扩展这个蓝图来轻松构建 RESTful APIs,使用内存数据库进行测试,并设置 swagger 文档(您可以先睹为快,在库的[rest-api](https://github.com/MartinHeinz/go-project-blueprint/tree/rest-api)分支中)。

解除数据装瓶

原文:https://towardsdatascience.com/un-bottling-the-data-2da3187fb186?source=collection_archive---------32-----------------------

探索葡萄酒的大数据世界。

动机

在这篇博文中,我们将使用关于葡萄酒的数据来研究几种不同的数据探索方法!我们将展示一步一步的代码,并解释我们的过程。在我们开始深入研究代码之前,我们为自己提出了几个问题,我们希望回答关于葡萄酒数据集的问题:

  1. 哪些国家的葡萄酒评论最多?
  2. 世界上最好的葡萄酒来自哪里?
  3. 最贵的葡萄酒来自哪里?
  4. 酒价和积分有关联吗?
  5. 有哪些词描述了 10 大葡萄酒类型?
  6. 描述能预测葡萄酒的一个特征吗?

这些问题和其他发现将在博客文章的剩余部分使用自然语言处理(NLP)、文字云、地图可视化和 Python 中的其他计算来解决。

数据

我们在 Kaggle 上找到了我们的数据集“葡萄酒评论”。该数据集包含超过 130,000 条葡萄酒评论条目。每个条目都包含葡萄酒来自的国家,葡萄酒的描述,名称(葡萄来自的酒厂内的葡萄园),葡萄酒爱好者在 1-100 的范围内给葡萄酒评分的点数,一瓶葡萄酒的价格,葡萄酒来自的省或州,葡萄酒产区或葡萄酒种植区,葡萄酒评论的标题,用于酿造葡萄酒的葡萄的品种或类型,最后是酒厂。下面可以看到部分原始数据。

wine_reviews = pd.read_csv(“winemag-data_first150k.csv”)
wine_reviews.dropna() # drop any empty entries
del wine_reviews['Unnamed: 0'] # delete first column 
wine_reviews.head()

The first five entries from the Wine Reviews dataset.

哪些国家的葡萄酒评论最多?

排名前 10 位的国家有 143,344 篇评论,占所有评论的 95%。数据集中总共有 46 个国家。

在这个数据集中,美国拥有最多的葡萄酒评论,有 62397 条评论(41.34%)。这并不令人惊讶,因为数据集来自纽约的 wine fessor 公司。紧随美国之后的是意大利(15.56%)、法国(13.98%)、西班牙(5.48%)和智利(3.85%)。

下面的地图是交互式的,请访问 这个链接 来看看它在行动。

世界上最好的葡萄酒来自哪里?

令人惊讶的是,英国以平均 92.89 分的葡萄酒评论分数高居榜首。有趣的是,美国没有进入前十名。回顾频率数据,英国只有 9 篇评论,与美国的 62397 篇相比太少了。我们的数据有偏差,这不是最公平的比较。

下面的地图是互动的,请访问 这个链接 来看看它在行动。

最贵的葡萄酒来自哪里?

英国以平均 47.50 美元的价格成为最贵葡萄酒的第一名。法国紧随其后,平均价格为 45.61 美元,匈牙利以 44.20 美元紧随其后。美国排名第 8,均价 33 美元。

下面的地图是交互式的,请访问 这个链接 来看看它的作用。

酒价和积分有关联吗?

首先,我们可以查看一些价格和积分的汇总统计数据。

wine_reviews.describe()

我们来形象化一下酒价和积分的分布。

plt.figure(figsize=(15,5))
plt.subplot(1, 2, 1)
plt.hist(wine_reviews[‘price’], color='#ba281e')
plt.xlabel(“Price”)
plt.ylabel(“Frequency”)
plt.title(“Distribution of Wine Prices”)plt.subplot(1, 2, 2)
plt.hist(wine_reviews[‘points’], color='#ba281e')
plt.xlabel(“Points”)
plt.ylabel(“Frequency”)
plt.title(“Distribution of Wine Review Points”)plt.tight_layout()
plt.show()

我们现在可以看看变量 price 和 points 之间的关系。使用 seaborn 软件包,我们可以可视化变量之间的关系。

import seaborn as snsplt.figure(figsize=(10,14))
ax = sns.jointplot(x='price', y='points', data=x[x['price'] < 200], kind='hex', gridsize=20, cmap='Reds')
plt.tight_layout()
plt.show()

积分和价格之间存在正相关关系——随着葡萄酒价格的上涨,给予葡萄酒的积分也会增加。平均价格在 20 美元左右,平均积分在 88 分左右。我们还可以查看获得 100 分的葡萄酒的分布情况。我们看到即使是再便宜的酒也能拿满分!

# prices of wines that received perfect points 
perfect_score = wine_reviews[‘points’]==100
perfect_wines = wine_reviews[perfect_score]
plt.hist(perfect_wines['price'], color ='#ba281e')
plt.xlabel("Price")
plt.ylabel("Frequency")
plt.title("Wines with 100 Points")
plt.show()

有哪些词描述了 10 大葡萄酒类型?

利用词云,我们分析了 10 大葡萄酒类型的描述。我们去掉了像葡萄酒、瓶子、玻璃杯、香料、葡萄、倒酒、啜饮、品尝这样的词,这样我们只剩下了描述词。下面的代码展示了我们是如何创建这两个单词云的。其余的单词云也是用同样的方法创建的。

# creates the word clouds
bordeaux_wc = wordcloud.WordCloud(background_color=”white”, max_words=1000, mask=transformed_wine_mask, contour_width=3, contour_color=’firebrick’).generate(bordeaux_style_white_blend)syrah_wc = wordcloud.WordCloud(background_color=”white”, max_words=1000, mask=transformed_wine_mask, contour_width=3, contour_color=’firebrick’).generate(syrah)

从上面的词云可以看出,排名前 10 的葡萄酒的热门词包括果味、辛辣、干、甜味、香气、口感、药草、单宁。一些葡萄酒有更具体的描述:

  • 波尔多风格白葡萄酒:苹果、柑橘、蜂蜜、葡萄柚、酸度
  • 西拉:胡椒,复杂,甘草,年轻,优雅
  • 麝香葡萄:甜品,酸度均衡,杏子,金银花
  • Prugnolo: 皮革、烟、烟草、脆、厚

描述能预测葡萄酒的一个特征吗?

为了解决这个问题,我们研究了数据,寻找可用于预测的特征。我们发现变量品种在很大程度上呈偏态分布,而呈正态分布。我们决定用这个描述来预测一款酒的得分。

创建和训练模型: 首先,我们使用来自预训练的全局向量文本文件的单词嵌入对描述文本进行预处理,该全局向量文本文件根据单词之间的关系对单词进行评级。然后,我们使用 3 种不同的模型来评估如何根据描述预测点数。这些模型包括 1D 卷积神经网络(CNN)、具有长短期记忆(LSTM)层的 1D CNN 和具有门控递归单元(GRU)的 1D CNN。CNN 是阅读单词嵌入的基本模型。LSTM 擅长在单词序列中寻找模式。GRU 是另一种递归神经网络架构,与 LSTM 类似,GRU 擅长理解单词上下文。我们没有使用纯粹的 LSTM 模型,因为它们在情绪预测方面表现不佳。下面的代码是 1D 有线电视新闻网。

*# set parameters:*
max_features = vocab_size
maxlen = 132
BATCH_SIZE = 128
embedding_dims = 50
filters = 250
kernel_size = 3cnn = Sequential()

*# start with an efficient embedding layer which maps*
*# vocab indices into embedding_dims dimensions*
embedding_layer = Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=maxlen , trainable=**False**)

cnn.add(embedding_layer)

*# we add a Convolution1D, which will learn filters*
*# word group filters of size filter_length:*
cnn.add(Conv1D(BATCH_SIZE,
                 kernel_size,
                 padding='valid',
                 activation='relu',
                 strides=1))*# we use max pooling:*
cnn.add(GlobalMaxPooling1D())

*# We add a vanilla hidden layer:*
cnn.add(Dense(BATCH_SIZE))
cnn.add(Activation('relu'))

*# We project onto a single layer*
cnn.add(Dense(1))

cnn.compile(loss='mse',
              optimizer='adam',
              metrics=['accuracy'])

Model summary output for 1D CNN.

评估模型: 表现最好的模型是 1D CNN,其在验证集上获得了 30%的准确度和 3 点的平均误差(基于均方误差的误差)。我们还尝试在 5 分的范围内将分数分成几类。使用这种方法,模型的准确率为 62%,平均误差为 0.3 点。我们的结果告诉我们,对于一个给定的描述,很难预测一个精确的点值,因为有太多的变化。然而,我们似乎可以很好地预测一定范围内的描述。

问题: 给出的描述对预测有些什么问题。只有 20 位独特的审查者对该数据集做出了贡献。每个评论者都有自己的写作风格,使得预测问题变得更具挑战性。

反光

这个项目对我们来说是一个很好的机会,可以使用我们在大数据计算分析课上学到的大部分技能。不幸的是,我们无法访问不关注美国葡萄酒的数据集。如果时间允许,我们也想做一个针对美国的分析。我们希望使用更好的数据集来进行其他预测,例如查看葡萄酒的原产地如何影响其评级。

参考

[## 屏蔽的 word cloud-word cloud 1 . 6 . 0 . post 1+g 8217 e 20 文档

amueller.github.io](https://amueller.github.io/word_cloud/auto_examples/masked.html#sphx-glr-auto-examples-masked-py) [## 气泡图 D3 图形库

如何用 Javascript 和 D3.js 构建顶部带有标记的地图:从最基本的例子到高度定制化…

www.d3-graph-gallery.com](https://www.d3-graph-gallery.com/bubblemap.html) [## API 参考- seaborn 0.9.0 文档

在 FacetGrid 上绘制关系图的图形级界面。

seaborn.pydata.org](https://seaborn.pydata.org/api.html)

由 Derek Albosta、Woo Jung、Emma Sheridan 和 Erik Tacam 完成的大数据计算分析课程项目。这个项目的源代码可以在 GitHub 上找到。在 这里可以找到 的交互式地图可视化。