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

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

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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

将点连接起来(Python、Spark 和 Kafka)

原文:https://towardsdatascience.com/connecting-the-dots-python-spark-and-kafka-19e6beba6404?source=collection_archive---------7-----------------------

Python、Spark 和 Kafka 是数据科学家日常活动中的重要框架。让他们能够整合这些框架是至关重要的。

Photo By César Gaviria from Pexels

介绍

通常,数据科学家更喜欢使用 Python(在某些情况下是 R)来开发机器学习模型。在这里,他们有一个有效的理由,因为数据驱动的解决方案伴随着许多实验而来。进行实验需要与我们用来开发模型的语言进行大量的交互,python 中可用于开发机器学习模型的库和平台非常多。这是一个有效的论点;然而,当这些模型应用于生产时,我们会遇到问题。

我们仍然有 Python 微服务库如 Flask 来部署机器学习模型并将其作为 API 发布。然而,问题是,“这能满足实时分析的需要吗?在实时分析中,你需要在一毫秒的时间内处理数百万个事件?”答案是否定的。这种情况是我写这篇文章的动机。

为了克服上述所有问题,我已经确定了一组可以适当连接的点。在本文中,我试图将这些点联系起来,它们是 Python、Apache Spark 和 Apache Kafka。

这篇文章是按以下顺序组织的:

  • 讨论在 Linux 环境中设置 Apache Spark 的步骤。
  • 开始卡夫卡(更多详情请参考这篇文章)。
  • 创建一个 PySpark 应用程序,用于消费和处理事件并写回 Kafka。
  • 使用 Kafka-Python 生成和消费事件的步骤。

安装 Spark

最新版本的 Apache Spark 可以在 http://spark.apache.org/downloads.html 的买到

在我撰写本文时,Spark-2.3.2 是最新版本。

步骤 1 :使用以下命令将 spark-2.3.2 下载到本地机器

wget http://www-us.apache.org/dist/spark/spark-2.3.2/spark-2.3.2-bin-hadoop2.7.tgz

第二步:拆包。

tar -xvf spark-2.1.1-bin-hadoop2.7.tgz

第三步:创建软链接(可选)。

这一步是可选的,但却是优选的;方便以后升级 spark 版本。

ln -s /home/xxx/spark-2.3.2-bin-hadoop2.7/ /home/xxx/spark

步骤 4 :向 bashrc 添加 SPARK_HOME 条目

*#set spark related environment varibales*
SPARK_HOME="/home/xxx/spark"
export PATH=$SPARK_HOME/bin:$PATH
export PATH=$SPARK_HOME/sbin:$PATH

步骤 5 :验证安装

pyspark

如果一切都准确无误,控制台上会显示以下输出:

步骤 6 :启动本机主机

start-master.sh

Spark Master Web GUI(流动屏幕)可从以下网址访问:http://abc.def.com:8080/

Spark Master Web GUI — Image by Author

第七步:启动工人

start-slave.sh spark:*//abc.def.ghi.jkl:7077*

如果一切都准确,工人的条目将出现在同一个屏幕上。

Spark Master Web GUI with workers — Image by Author

开始卡夫卡

在这里,Kafka 是一个流媒体平台,有助于生产和消费 spark 平台的事件。

更详细的说明请参考我已经写过的关于卡夫卡的文章。

第一步:转到卡夫卡根文件夹

cd /home/xxx/IQ_STREAM_PROCESSOR/kafka_2.12-2.0.0/

第二步:启动卡夫卡动物园管理员

bin/zookeeper-server-start.sh config/zookeeper.properties

第三步:启动卡夫卡经纪人

bin/kafka-server-start.sh config/server.properties

第四步:创建两个 Kafka 主题( input_event 和 output_event)

Apache Spark (PySpark)上的事件处理

设置火花

第一步

首先在集群的每个节点中设置 python 包,并指定每个 worker 节点的路径。这里最好安装 Anaconda,它包含了大部分必要的 python 包。

spark-env.sh 中添加以下条目,以指定每个工作节点的路径。

export PYSPARK_PYTHON='/home/xxx/anaconda3/bin/python'

第二步

需要安装 spark 应用程序中使用的其他 python 依赖项。比如我们用 Kafka-python 把处理过的事件写回 Kafka。

这是安装 Kafka python 的过程:

在控制台中,转到 anaconda bin 目录

cd /home/xxx/anaconda3/bin/

执行以下命令

pip install kafka-python

第三步

从以下网址下载 Spark Streaming 的 Kafka 库:https://mvnrepository . com/artifact/org . Apache . Spark/Spark-Streaming-Kafka-0-8-assembly【稍后提交 Spark 作业需要用到这个】。

现在我们已经安排好了运行 Spark 应用程序所需的整个氛围。

创建并提交公园申请

创建 SparkContext

spark 上下文是访问 Spark 功能的入口点,并提供到 Spark 集群的连接。要创建 SparkContext,首先,我们应该创建 SparkConf,它包含传递给 SparkContext 所需的参数。下面的代码片段展示了如何创建 SparkContext。

这里,仅安排了主 URL 和应用程序名称,但不限于此。SparkConf 允许你控制更多的参数。例如,您可以指定驱动程序进程使用的内核数量、每个执行器进程使用的内存量等。

创建【流上下文 Kafka 经纪人输入流】

流上下文是访问 spark 流功能的入口点。流式上下文的关键功能是从不同的流式源创建离散流。以下代码片段显示了如何创建 StreamingContext。

*#batch duration, here i process for each second*
ssc = StreamingContext(sc,1)

接下来,我们为来自 Kafka 代理的 pulls 消息创建输入流。应该指定创建输入流的以下参数:

  • 从该流连接的 Zookeeper 的主机名和端口。
  • 此消费者的组 id。
  • “每个主题要使用的 Kafka 分区数”:指定该流并行读取的分区数。

下面的代码片段表达了如何为 Kafka 代理创建输入流。

处理事件并写回卡夫卡

在为 Kafka Brokers 创建流之后,我们从流中提取每个事件并处理这些事件。在这里,我演示了一个在大多数 spark 教程中引用的典型示例(字数统计),并进行了一些小的修改,以在整个处理期间保持键值并写回 Kafka。

以下代码片段描述了接收入站流并使用已处理的事件创建另一个流:

现在,剩下的就是给卡夫卡回信了。我们获取处理后的流,并通过对 stream 应用输出操作(这里我们使用 foreachRDD)写回外部系统。这将每个 RDD 中的数据推送到外部系统(在我们的用例中,推送到 Kafka)。下面的代码 snipe 解释了如何将每个 RDD 中的数据写回卡夫卡:

启动星火应用

脚本 spark-submit 用于启动 spark 应用程序。在启动应用程序期间,应指定以下参数:

  • master:连接 master 的 URL 在我们的例子中,它是 spark://abc.def.ghi.jkl:7077
  • deploy-mode:部署驱动程序的选项(在 worker 节点或本地作为外部客户机)
  • jars:回忆一下我们关于 Spark Streaming 的卡夫卡图书馆的讨论;这里我们需要提交这个 jar 来提供 Kafka 依赖项。

最后,我们必须提交我们在本节中编写的 PySpark 脚本,即 spark_processor.py

启动所有命令后,我们的 spark 应用程序将如下所示:

如果一切正常,控制台中将出现以下输出:

现在我们有了必要的设置,是时候进行测试了。在这里,我使用 Kafka-python 来创建事件,并使用在我以前的文章中已经讨论过的事件

以下是代码片段供您参考:

产生事件的代码

消费事件的代码

如果一切都准确无误,流程事件将按如下方式消耗并显示在控制台中:

最后的想法

本文的要点是,

  1. Python、Spark 和 Kafka 是数据科学家日常活动中的重要框架。
    2)本文帮助数据科学家用 Python 进行实验,同时在可扩展的生产环境中部署最终模型。

感谢您阅读本文。希望你们也能把这些点联系起来!

使用 Python 连接到 GraphQL API

原文:https://towardsdatascience.com/connecting-to-a-graphql-api-using-python-246dda927840?source=collection_archive---------2-----------------------

Photo by Perry Grone on Unsplash

让我们自动化并消除误差,尝试一步一步地消除前端。

graph QL 到底是什么? GraphQL 用最简单的话来说就是一种 查询语言 用于前端。我们发送一个请求并取回某些数据。GraphQL 也足够先进,可以对称为突变的数据进行更改。但这需要一篇全新的文章来解释。

所以我想直接连接到 GraphQL 的主要原因是因为我们有一个 web 应用程序,我们必须手动一个接一个地填写字段。如果我们知道这是重复的,那就不是最有效地利用我的时间。

我使用的老方法是通过 Selenium ,每当前端工程师做出一些改变时,这也会导致错误。所以我做了一些研究,决定为什么不直接通过 GraphQL 发送数据。我仍然从 SalesForce 获取数据,我有一篇文章向您展示如何做到这一点这里。然后我会处理所有的数据并发送给 GraphQL 端点。

但是我有点跑题了,让我们用 Python 连接到 GraphQL 并取回一些数据吧!

入门
假设你已经安装了 Python 你需要的主要模块有:
1 .requests (用于连接 GraphQL)
2。json(用于解析 GraphQL 数据)
3 .pandas(用于我们数据的可见性)

让我们将这些模块导入到新的 Python 脚本中。

import requests
import json
import pandas as pd

出于教程的目的,我们将连接到一个不需要认证的 GraphQL 端点。我们将连接到一个 Rick 和 Morty GraphQL API !

让我们从一些简单的东西开始,一个角色数据集就可以了。我想从他们每个人那里得到的信息是名字,地位,物种,类型和性别。我们可以将这个 GraphQL 查询设置为字符串,并将其设置为变量,如下所示:

query = """query {
    characters {
    results {
      name
      status
      species
      type
      gender
    }
  }
}"""

做这个的人让我们很容易联系到一起。我们每天最多收到 10000 个请求,所以请谨慎使用。接下来的几行代码我们设置 URL,向他们发送请求,也就是查询。如果成功,我们应该得到一个字符串格式的200textstatus_code

url = '[https://rickandmortyapi.com/graphql/'](https://rickandmortyapi.com/graphql/')
r = requests.post(url, json={'query': query})
print(r.status_code)
print(r.text)

r.text是一个字符串的格式。这就是模块json出现的地方。让我们将这个字符串转换成 JSON 格式,这样我们就可以将它移动到 DataFrame 中。

json_data = json.loads(r.text)

我们只想要名字,地位,物种,类型和性别。因此,在我们将它推入数据帧之前,因为它是一个嵌套的 JSON,所以我们想进一步进入嵌套。现在我们可以把它发送出去翻译成数据帧。我们可以用下面的代码做到这一点:

df_data = json_data[‘data’][‘characters’][‘results’]
df = pd.DataFrame(df_data)

我们的数据帧现在应该是这样的。

现在,它已经被转移到一个熊猫数据框架的可能性是无限的!

访问我的代码这里!

我这里还有家教和职业指导!

如果你们有任何问题、评论或顾虑,请不要忘记通过 LinkedIn 与我联系!

利用廉价的 GPU 计算:使用 windows 连接到 Vast.ai

原文:https://towardsdatascience.com/connecting-to-vast-ai-using-windows-f087664d82d0?source=collection_archive---------7-----------------------

Image courtesy: https://www.hostinger.com/tutorials/ssh-tutorial-how-does-ssh-work

冒险进入加密货币和数据科学的世界,我会建造自己的超级计算机绝非偶然。最酷的是,任何人都可以获得廉价的 GPU 计算,比 AWS 实例便宜 3 -10 倍。所有这一切都是由于 Vast.ai 平台使点对点共享 GPU 计算能力成为可能。

在接下来的系列文章中,我将展示如何在 Vast.ai 平台上开始一些不同的任务:

  • 使用 windows 连接到 Vast.ai:选择并 ssh 到你选择的装备
  • 启动 Jupyter 笔记本
  • 运行基准
  • 入门:折叠@Home
  • 入门:使用 hashcat
  • 入门:使用 fast.ai

选择并 ssh 到您选择的装备中

选择并导航到实例

  1. 在你的浏览器中,在https://vast.ai/console/create/选择你的图像和装备

首先,选择您的 docker 图像,如下所示。有几个选项可供选择,但是对于本教程,我从 docker hub 中选择了 fastai 映像,并选择了 Run interactive shell server,SSH

Selecting fastai docker image

然后,我们选择钻机的选择(116),并点击租赁,如下所示。

Select rig/instance of choice

2.导航到您刚刚创建的实例https://vast.ai/console/instances/。请注意,如果映像已经在主机装备上,根据主机连接速度和映像的大小,您的实例可能需要 30 秒到 15 分钟的加载时间。专业提示:让主持人为你预装图像,这样你每次不到一分钟就能开始。

3.转到实例并单击连接,这将显示 ip 地址和端口(它也显示在实例的顶部)。

ssh -p **515836**  [**root@ssh5.vast.ai**](mailto:root@ssh5.vast.ai) -L 8080:localhost:8080

稍后您将需要端口 515836 和 ip 地址root @ ssh 5 . vast . ai(注意端口和 ip 地址可能不同)。

Instances page where you can connect to your instance

安装 PuTTY 并生成 ssh 密钥

4.为 windows 下载并安装 PuTTYgen

5.使用 PuTTYgen 选择 RSA,然后按 generate 按钮生成公钥和私钥。

6.添加一个额外的安全密码,保存公钥和私钥,并将公钥复制到您的剪贴板。

7.前往 https://vast.ai/console/account/的,输入第六步生成的公钥

8.打开 PuTTY,输入步骤 3 中的 IP 地址和端口号。

9.转到连接→SSH →认证并选择您的私钥

10.导航回会话并保存您的配置,以便您稍后可以轻松加载。

连接到您的实例

11.单击打开,接受任何弹出窗口,并使用生成公钥时使用的密码登录。

12.撒野!!!!!!!!

如果你仍然有问题,请在下面的评论中联系我们,或者加入 Vast.ai Discord 社区。更多关于 Vastai 点对点系统的信息可以在常见问题中找到。

注意我不是 Vast.ai 的开发者,但是我有 rig (116 ),它是托管在这个平台上的,所以你可以随意表达你的爱😺。

联系:对数似然、交叉熵、KL 散度、逻辑回归和神经网络

原文:https://towardsdatascience.com/connections-log-likelihood-cross-entropy-kl-divergence-logistic-regression-and-neural-networks-40043dfb6200?source=collection_archive---------13-----------------------

本文将涵盖负对数似然、熵、softmax 与 sigmoid 交叉熵损失、最大似然估计、Kullback-Leibler (KL)散度、逻辑回归和神经网络之间的关系。如果您不熟悉这些主题之间的联系,那么这篇文章就是为您准备的!

推荐背景

  • 对神经网络的基本理解。如果你想了解更多这方面的背景知识,请阅读神经网络简介。
  • 透彻理解多类和多标签分类之间的区别。如果你不熟悉这个话题,请阅读文章多标签 vs .多类分类:Sigmoid vs. Softmax 。简短回顾如下:在多类分类中,我们希望将单个类分配给一个输入,因此我们将 softmax 函数应用于神经网络的原始输出。在多标签分类中,我们希望将多个类别分配给一个输入,因此我们对神经网络的原始输出应用元素式 sigmoid 函数。

问题设置:用神经网络进行多类分类

首先,我们将使用一个多类分类问题来理解对数似然和交叉熵之间的关系。这是我们的问题设置:

猫咪图片来源:维基百科。

可能性

假设我们已经选择了一个特定的神经网络架构来解决这个多类分类问题——例如, VGG ,雷斯网,谷歌网等。我们选择的架构代表了一系列可能的模型,其中该系列的每个成员具有不同的权重(不同的参数),因此代表了输入图像 x 和一些输出类预测 y 之间的不同关系。我们希望选择具有一组好的参数的家庭成员来解决我们的特定问题[image]->[飞机、火车或猫]。

选择好的参数来解决我们的任务的一种方法是选择最大化观察数据可能性的参数:

负对数可能性

负对数似然性实际上是似然性对数的负值:

参考设置、似然性和负对数似然性:“交叉熵和对数似然性”,作者安德鲁·韦伯

关于最大似然估计的旁注

为什么我们“最小化负对数似然性”而不是“最大化似然性”,当它们在数学上是相同的?这是因为我们通常最小化损失函数,所以我们谈论“负对数可能性”,因为我们可以最小化它。(来源:交叉验证。)

因此,当您最小化负对数似然时,您正在执行最大似然估计。根据维基百科上关于 MLE 的文章,

最大似然估计(MLE)是一种通过最大化似然函数来估计概率分布参数的方法,使得在假设的统计模型下,观察到的数据是最有可能的。参数空间中使似然函数最大的点称为最大似然估计。[……]从贝叶斯推理的角度来看,最大似然估计是最大后验估计(MAP)的一种特殊情况,它假设参数的先验分布是均匀的。

这是乔纳森·戈登在 Quora 上的另一个总结:

最大化(对数)似然相当于最小化二元交叉熵。这两个目标函数之间实际上没有区别,因此得到的模型或其特征之间也不会有区别。

当然,使用 softmax 交叉熵和所谓的多核似然性,这可以非常简单地扩展到多类情况,因此当对多类情况这样做时没有区别,例如在神经网络中。

MLE 和交叉熵的区别在于,MLE 代表了一种结构化和原则性的建模和训练方法,而 binary/softmax 交叉熵只是代表了应用于人们通常关心的问题的特例。

之后,撇开最大似然估计,让我们更深入地研究负对数似然和交叉熵之间的关系。首先,我们将定义熵:

交叉熵

章节参考:维基百科交叉熵,安德鲁·韦伯的《交叉熵和对数似然性》

库尔巴克-莱布勒(KL)发散

Kullback-Leibler (KL)散度通常被概念化为一个概率分布如何不同于第二个概率分布的度量,作为两个概率分布之间的距离的度量。从技术上讲,KL 散度不是一个真正的度量,因为它不符合三角形不等式,并且 D_KL(g||f) 不等于 D_KL(f||g) —但直觉上,这似乎是一种更自然的表示损失的方式,因为我们希望我们的模型学习的分布与真实分布非常相似(,即我们希望 KL 散度很小,我们希望最小化 KL 散度。)

这里是 KL 散度的等式,如果我们使用对 f(x) 的最优编码而不是对g(X)的最优编码,KL 散度可以被解释为传达随机变量 X (分布为 g(x) 的值所需的额外比特的预期数量

KL 发散的其他思考方式 D_KL (g||f):

  • 这是 g 相对于 f 的相对熵
  • 它是当一个人将自己的信念从先验概率分布 f 修正为后验概率分布 g 时所获得的信息的度量
  • f 近似 g 时丢失的信息量

在机器学习中, g 通常代表数据的真实分布,而 f 代表模型对分布的近似。因此,对于我们的神经网络,我们可以将 KL 散度写成这样:

请注意,第二项(蓝色)仅取决于固定的数据。因为第二项不依赖于可能性 y-hat(预测的概率),所以它也不依赖于模型的参数。因此,最小化 KL 散度的参数与最小化交叉熵和负对数似然的参数是相同的!这意味着我们可以最小化交叉熵损失函数,得到和最小化 KL 散度相同的参数。

章节参考:维基百科 Kullback-Leibler divergence,T2【交叉熵与对数似然】安德鲁·韦伯

那“乙状结肠交叉熵损失”呢?

到目前为止,我们已经关注了多分类问题环境中的“softmax 交叉熵损失”。然而,当训练多标签分类模型时,其中多个输出类是可能的,则使用“sigmoid 交叉熵损失”而不是“softmax 交叉熵损失”请参见这篇文章了解更多关于多标签与多类分类的背景。

正如我们刚刚看到的,交叉熵定义在两个概率分布 f(x)g(x)之间。但这在应用于输出层的 sigmoid 的上下文中没有意义,因为输出小数的总和不会是 1,因此我们实际上没有输出“分布”

根据迈克尔·尼尔森的书,第三章方程 63 ,一种有效的思考 sigmoid 交叉熵损失的方式是“每个神经元交叉熵的总和,每个神经元的激活被解释为二元概率分布的一部分。”

因此,对于 sigmoid 交叉熵的情况,我们将考虑一组概率分布,其中每个神经元在概念上代表两元素概率分布的一部分,而不是考虑所有输出神经元的概率分布(这在 softmax 交叉熵的情况下完全没问题)。

例如,假设我们将下面的图片输入到用 sigmoid 交叉熵损失训练的多标记图像分类神经网络:

Image Source: Wikipedia.

我们的网络具有对应于类别猫、狗、沙发、飞机、火车和汽车的输出神经元。

在将 sigmoid 函数应用于猫神经元的原始值之后,我们得到 0.8 作为我们的值。我们可以认为这个 0.8 是“猫”类的概率,我们可以想象一个隐含的概率值 1–0.8 = 0.2 是“没有猫”类的概率。这个隐含的概率值并不对应于网络中的实际神经元。这只是想象/假设。

类似地,在对狗神经元的原始值应用 sigmoid 函数之后,我们得到 0.9 作为我们的值。我们可以认为这个 0.9 是“狗”类的概率,我们可以想象 1–0.9 = 0.1 的隐含概率值是“没有狗”类的概率。

对于飞机神经元,我们得到的概率是 0.01。这意味着对于所有的输出神经元,我们有 1–0.01 = 0.99 的概率“没有飞机”——以此类推。因此,每个神经元都有自己的“交叉熵损失”,我们只需将每个神经元的交叉熵相加,就可以得到总的 sigmoid 交叉熵损失。

我们可以写出该网络的 sigmoid 交叉熵损失如下:

" Sigmoid 交叉熵有时被称为“二元交叉熵”. "本文讨论了多标签分类问题的“二元交叉熵”,并包括了等式。

逻辑回归、神经网络、交叉熵和负对数似然之间的联系

  • 如果神经网络没有隐藏层,并且原始输出向量应用了 softmax,则这相当于多项式逻辑回归
  • 如果神经网络没有隐藏层,并且原始输出是应用了 sigmoid(逻辑函数)的单个值,那么这就是逻辑回归
  • 因此,逻辑回归只是神经网络的一个特例!( refA , refB )
  • 如果神经网络确实具有隐藏层,并且原始输出向量应用了 softmax,并且使用交叉熵损失对其进行训练,则这是“softmax 交叉熵损失”,它可以被解释为负对数似然,因为 softmax 创建了概率分布。
  • 如果神经网络确实具有隐藏层,并且原始输出向量应用了元素式 sigmoids,并且使用交叉熵损失对其进行训练,则这是“sigmoid 交叉熵损失”,其不能被解释为负对数似然,因为在所有示例中不存在概率分布。输出的总和不等于 1。这里,我们需要使用上一节提供的解释,其中我们将损失概念化为一组累加在一起的每个神经元的交叉熵。

章节参考:统计堆栈交换

要了解更多信息,你可以看看维基百科上关于交叉熵的文章,特别是最后一部分,标题是“交叉熵损失函数和逻辑回归”本节描述了如何将逻辑回归中使用的典型损失函数计算为样本中所有交叉熵的平均值(“sigmoid 交叉熵损失”)。)交叉熵损失有时被称为“逻辑损失”或“对数损失”,sigmoid 函数也被称为“逻辑函数”

交叉熵实现

在 Pytorch 中,交叉熵有几种实现方式:

实现 A: torch.nn.functional.binary_cross_entropy(参见[torch.nn.BCELoss](https://pytorch.org/docs/stable/nn.html#torch.nn.BCELoss)):该函数的输入值已经应用了一个 sigmoid,例如

实现 B: torch.nn.functional.binary_cross_entropy_with_logits(参见[torch.nn.BCEWithLogitsLoss](https://pytorch.org/docs/stable/nn.html#torch.nn.BCELoss)):“该损失将一个 s 形层和 B 形层结合在一个单独的类中。这个版本在数值上比使用简单的 Sigmoid 后跟 BCELoss 更稳定,因为通过将运算合并到一个层中,我们利用了 log-sum-exp 技巧来实现数值稳定性。”

实现 C: torch.nn.functional.nll_loss(见[torch.nn.NLLLoss](https://pytorch.org/docs/stable/nn.html#torch.nn.NLLLoss)):“负对数似然损失。用 C 类训练一个分类问题很有用。[...]通过转发调用给出的输入应该包含每一类的对数概率。

实现 D: torch.nn.functional.cross_entropy(见[torch.nn.CrossEntropyLoss](https://pytorch.org/docs/stable/nn.html#torch.nn.CrossEntropyLoss)):“这个判据结合了 nn。LogSoftmax()和 nn。NLLLoss()在一个单独的类中。这在用 C 类训练分类问题时很有用。[...]输入应该包含每个类的原始的、未标准化的分数。

结论

正如我们在这里讨论的,负对数似然、交叉熵、KL 散度、神经网络和逻辑回归之间存在基本关系。我希望你喜欢学习这些不同的模型和损失之间的联系!

关于特色图片

因为这篇文章的主题是连接,所以特色图片是一个“连接体”连接体是“大脑中神经连接的综合图,可以被认为是它的‘线路图’。”“参考:维基百科。精选图片来源:人类连接体。

原载于 2019 年 12 月 7 日http://glassboxmedicine.com

深层神经网络中的连接模式

原文:https://towardsdatascience.com/connectivity-patterns-in-deep-neural-networks-787c90316a6d?source=collection_archive---------21-----------------------

本文将讨论一个推动神经网络设计进步的核心组件,即用于计算机视觉任务的卷积网络。LeNet-5、AlexNet 和 VGG 等经典 CNN 都有一种连接模式,即前一层的输出作为下一层的输入。这种顺序处理模式很容易理解,也是开始学习神经网络的好方法。

随后出现了 ResNet、Inception 和 DenseNet 等架构,它们极大地改变了这种连接模式。在所有这些网络中,计算仍然遵循顺序模式,其中一层在正向传递中仅计算一次输出,然而,该层的输出与经典模型的连接不同。

ResNet 提供了跳过连接,这是对 CNN 连接最直观的改变。这种跳过连接也称为身份映射,它从上一层获取输入,并将其向前传播一层。例如,以层 l1、l2 和 l3 为例。传统上,l1 输出只能从 l1 到 l2,但是通过跳过连接,l1 输出被克隆到 l3 的输入。

ResNet 的作者在他们的论文“深度剩余网络中的身份映射”中继续剖析他们的跳过连接,并测试向身份映射添加额外复杂性的影响,该论文通常被称为 ResNet-v2:

Empirical evaluations of different possible constructions of the ResNet identity mapping / skip-connection

在 ResNet 之后, DenseNet 呈现出非常相似的连接模式。在 DenseNet 中,不是让跳过连接向前传播一层,而是将所有先前的层向前跳过,作为未来层的输入。例如,层 l4 的输入是原始输入 l0+L1、l2 和 l3 的输出。先前的特征地图都被连接起来作为后面图层的输入。

Illustration of the DenseNet connectivity pattern

ResNet 和 DenseNet 都直观地提供了功能冗余的解决方案。在神经网络中必须通过顺序处理来保持状态的结果。不必学习保存信息的参数,而是将这些信息显式地复制到更高级的表示中。

顺便说一下,Inception 模型与 ResNet 和 DenseNet 有着根本不同的连接模型。先启块将相同的输入输入到多个层中,并组合这些输出,而不是将早期层的输出推到后面的层中。直观地说,这样做是为了试图保留视觉信息中一些自然明显的稀疏性。

Illustration of an Inception block

Inception 块也不一定与 ResNet 或 DenseNet 分离。初始块被封装在这种结构中,因此可以忽略内部的复杂性,并且它可以被视为具有输入和输出的标准层。该输出可以以类似于任何其他神经网络层的方式向前跳过。

关于什么将导致神经网络设计的突破,有许多思路,例如标准化、多任务学习和数据扩充。连通性模式很有趣,因为它们很好地适应了 AlexNet 等原始 CNN 中明显的模块化框架,此外还解决了消失梯度和特征冗余等问题。

思考连接模式如何适应元学习神经网络架构的框架是很有趣的。用包含在每层中的所有各种各样的超参数,例如滤波器尺寸和特征图的数量,来设计标准神经网络层的离散搜索空间是足够困难的。为初始模块和非固定跳过连接增加灵活性可以为元学习模型带来指数级的大搜索空间。

感谢阅读这篇文章!以下是讨论论文、ResNet、DenseNet 和 Inception network (GoogLeNet)的链接:

[## 用于图像识别的深度残差学习

更深层次的神经网络更难训练。我们提出了一个剩余学习框架,以减轻训练…

arxiv.org](https://arxiv.org/abs/1512.03385) [## 密集连接的卷积网络

最近的工作表明,卷积网络可以更深入,更准确,更有效地训练,如果…

arxiv.org](https://arxiv.org/abs/1608.06993)

使用 GANs 解决类不平衡数据集问题

原文:https://towardsdatascience.com/conquer-class-imbalanced-dataset-issues-using-gans-2482b52593aa?source=collection_archive---------14-----------------------

DC-甘生成图像的某些类类型,以改善图像分类

Created by Lluisa lborra from Noun Project

现实生活中深度学习应用的一个常见问题是,一些类在训练集中的样本数量明显高于其他类。让我们考虑一个制造商正在构建一个视觉检测系统来检测受损产品。没有哪个厂商会有好的产品形象那么多损坏的产品形象。这种差异被称为阶级不平衡。类别不平衡数据集在不同领域都很常见,如卫生、银行、安全和其他领域。对于这样的数据集,学习算法通常偏向于多数类,因此对于少数类实例有更高的误分类率。

有不同的策略来解决这个问题,例如过采样、欠采样、两阶段训练和成本敏感学习。与算法改进相比,为少数类生成人工数据的方法构成了更通用的方法。本文旨在利用深度卷积生成对抗网络(DC-GAN)来改善分类性能,从而缩小数据集中的这一差距。

甘斯就像魔方。一旦你知道解决立方体的诀窍,有多种方法可以得到完美的立方体。它可以快至 3.47 秒(3×3 魔方的当前世界纪录),如果你搞砸了,很容易发现。但是,如果你不知道解决立方体的诀窍,它可能要花很长时间。GAN 的失败时间和成本相当高(考虑到培训时间和资源的美元价值),尤其是当您的资源有限,并且您可能仍然不知道哪里出了问题时。一旦你知道了 GAN 的依赖性,就相对容易得到一个完美的解决方案。

在本文中,我们将探讨以下主题-

  1. 使 GANs 工作/稳定的提示和技巧。
  2. 如何定义甘?如何为 Kaggle 比赛的真实世界数据集塑造 GAN?
  3. 令人兴奋的 GANs 用例。

Created by Tresnatiq from Noun Project

使 GANs 工作/稳定的技巧和诀窍-

开发用于生成图像的 GAN 需要用于对给定图像是真实的还是生成的进行分类的鉴别器卷积神经网络模型,以及使用逆卷积层将输入转换为像素值的完整二维图像的生成器模型。

这些生成器和鉴别器模型在零和游戏中竞争。这意味着对一个模型的改进是以降低另一个模型的性能为代价的。结果是一个非常不稳定的训练过程,经常会导致失败。

虽然 GANs 的研究继续提高这些模型的基本稳定性,但有许多技巧可以训练它们并使它们稳定。

  1. 使用步长卷积>>不要使用最大池层数,而是使用卷积层中的步长在鉴别器模型中执行下采样。使用 Conv2DTranspose 和 stride 进行上采样。
  2. 移除全连接层>>鉴别器中不使用全连接层,而是将卷积层展平并直接传递到输出层。
  3. 使用批处理规范化>>在鉴别器和生成器模型中都建议使用批处理规范图层,但生成器的输出和鉴别器的输入除外。
  4. 建议仅在发生器中使用 ReLU、Leaky ReLU 和 Tanh >> ReLU,但对于允许小于零的值的 ReLU 鉴别器变化,建议使用 Leaky ReLU。此外,生成器使用双曲正切函数,鉴别器在输出层使用 Sigmoid 激活函数。
  5. 归一化输入>>归一化-1 到 1 之间的输入图像。为真实和虚假构建不同的小批量,即每个小批量只需要包含所有真实图像或所有生成的图像。
  6. 学习率>>对鉴别器(1e-3)和发生器(1e-4)使用不同的学习率。对两者都使用 Adam optimizer。
  7. Performance hack > >训练鉴别器两次,生成器一次。在发电机中使用 50%的压差。
  8. 早期跟踪故障>>鉴别器中损失 0.0 是故障模式。如果发生器的损耗稳步下降,很可能用垃圾图像愚弄鉴别器。当训练顺利进行时,鉴别器损耗具有低方差并随时间下降。

所有这些技巧,我们需要放在一起,以创造一个完美的甘。

Created by Lluisa Iborra from Noun Project

如何定义甘?如何为 Kaggle 比赛的真实世界数据集塑造 GAN?-

研究人员开发了多种口味的 gan,网上也有多种解决方案来解决类别不平衡问题,但所有这些主要是在玩具数据集上,如 MNIST,CIFAR-10 和 ImageNet。我一直在研究来自 Kaggle 竞赛的医学图像分类(糖尿病视网膜病变检测)数据集。该数据集有 4 个类,其中类 1 有 13k 个样本,而类 4 只有 600 个样本。Kaggle 竞赛获胜者最近使用的解决阶级不平衡问题的方法之一就是使用 DC-甘。我们将使用 DC-甘为 4 类糖尿病视网膜病变检测数据库创建人工样本。

让我们开始编码练习,并实现这些技巧来生成新的图像。所有的实验都是在 NVIDIA Quadro M400 GPU 上完成的。这款 GPU 有 8 GB 内存。GPU 在 Ubuntu 16.04 实例上为 GPU 1.8.0 配置了 CUDA 9.0、cuDNN 7.4、TF。

导入所有必要的环境。这段代码期望所有的包都预先安装好。

我已经从 Kaggle 下载了数据库。该数据库中的图像很难用肉眼区分,因此该数据集与所有玩具数据集非常不同。数据库有几个 zip 文件,我们需要将它们解压缩到包含各自图像的 train/test 文件夹中。列车图像的所有标签都在单独的 csv 文件中提供。

在下面的代码中,我们将读取一个包含图像标签和名称的 csv 文件。我们需要做一些健全的检查(添加。jpeg 扩展,删除所有大小为 0 KB 的图像,从数据帧中移除已删除图像的条目)。

在该数据集中,类别 3 和 4 是少数类别,因为它们在整个数据集中的代表性非常低。我们将训练 GAN 为第 4 课生成图像。

以下部分定义了鉴别器和生成器。鉴别器使用 2 x 2 步长的卷积层对输入图像进行下采样(技巧#1 和 2)。输出层使用 Sigmoid 激活函数来预测输入样本是真是假。该模型被训练为使用 Adam 优化器(技巧#4)来最小化二元交叉熵损失函数。

发生器由 Conv2DTranspose 定义,步长为 2 x 2,可将图像上采样至最高 128 像素。输出层使用双曲正切激活函数来确保输出值在[-1,1]的期望范围内(技巧#4)。我们有意对鉴别器和生成器使用不同的学习速率(技巧 6)。

define_gan() 函数使用已经定义的生成器和鉴别器模型,并创建一个新的逻辑模型。

下面的函数 load_real_samples() 将从数据集中读取实际数据并归一化图像(技巧#5),然后在调用 train()时将它们馈送到 generate_real_samples()

generate _ fake _ samples()函数生成带有随机像素值和假标签 0 的图像。

没有评估 GAN 性能的指标,生成的图像必须由操作员进行质量评估。这使得很难决定在哪里停止训练。

由于敌对的性质,发电机的属性在每个纪元后都在变化。一旦生成了可接受质量的图像,生成器可能不会提高性能,在许多情况下甚至会随着后续时期而降低性能。

使用 3 个选项来处理这个问题

  1. 定期评估鉴别器对真假图像的分类精度。
  2. 定期生成图像并保存,供操作员查看。
  3. 定期保存生成器模型以备后用。

所有这些操作将由summary _ performance()函数执行,以评估鉴别器模型。多个历元的训练 GAN 将同时每 10 个历元生成模型的快照 save_plat() 将继续保存图像。这将有助于回溯 GAN 图像生成的进程。

train() 函数定义如下,每个时期内的批次数量由批次大小分成训练数据集的次数来定义。

训练鉴别器模型被更新两次(每次用假的和真的样本),并且对于每批迭代生成器被更新一次(技巧#7)。

训练 GAN 时观察损耗至关重要,鉴频器损耗的突然下降表明发生器模型已经开始产生鉴频器可以轻易辨别的坏样本(技巧 8)。

为了可视化模型,我们可以使用 plot_model() 函数绘制它们。

summary() 功能也可用于查看模型布局和可训练参数的数量。调用 train() 函数开始鉴别器和发电机训练。

鉴别器模型

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 128, 128, 16)      448       
_________________________________________________________________
leaky_re_lu_1 (LeakyReLU)    (None, 128, 128, 16)      0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 64, 64, 8)         1160      
_________________________________________________________________
leaky_re_lu_2 (LeakyReLU)    (None, 64, 64, 8)         0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 32, 32, 16)        1168      
_________________________________________________________________
leaky_re_lu_3 (LeakyReLU)    (None, 32, 32, 16)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 16, 16, 8)         1160      
_________________________________________________________________
leaky_re_lu_4 (LeakyReLU)    (None, 16, 16, 8)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 2048)              0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 2048)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 2049      
=================================================================
Total params: 11,970
Trainable params: 5,985
Non-trainable params: 5,985
_________________________________________________________________

发电机模型

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_2 (Dense)              (None, 65536)             6619136   
_________________________________________________________________
leaky_re_lu_5 (LeakyReLU)    (None, 65536)             0         
_________________________________________________________________
reshape_1 (Reshape)          (None, 16, 16, 256)       0         
_________________________________________________________________
conv2d_transpose_1 (Conv2DTr (None, 32, 32, 128)       524416    
_________________________________________________________________
leaky_re_lu_6 (LeakyReLU)    (None, 32, 32, 128)       0         
_________________________________________________________________
conv2d_transpose_2 (Conv2DTr (None, 64, 64, 128)       262272    
_________________________________________________________________
leaky_re_lu_7 (LeakyReLU)    (None, 64, 64, 128)       0         
_________________________________________________________________
conv2d_transpose_3 (Conv2DTr (None, 128, 128, 128)     262272    
_________________________________________________________________
leaky_re_lu_8 (LeakyReLU)    (None, 128, 128, 128)     0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 128, 128, 3)       3459      
=================================================================
Total params: 7,671,555
Trainable params: 7,671,555
Non-trainable params: 0
_________________________________________________________________

培训流程将如下所示

.....
>319, 5/10, d1=0.692, d2=0.761 g=0.709
>319, 6/10, d1=0.822, d2=0.759 g=0.690
>319, 7/10, d1=0.733, d2=0.764 g=0.723
>319, 8/10, d1=0.662, d2=0.740 g=0.743
>319, 9/10, d1=0.701, d2=0.683 g=0.758
>319, 10/10, d1=0.830, d2=0.744 g=0.728
>320, 1/10, d1=0.749, d2=0.717 g=0.731
>320, 2/10, d1=0.677, d2=0.796 g=0.722
>320, 3/10, d1=0.766, d2=0.700 g=0.717
>320, 4/10, d1=0.676, d2=0.736 g=0.765
>320, 5/10, d1=0.792, d2=0.762 g=0.730
>320, 6/10, d1=0.690, d2=0.710 g=0.719
>320, 7/10, d1=0.807, d2=0.759 g=0.708
>320, 8/10, d1=0.715, d2=0.747 g=0.711
>320, 9/10, d1=0.719, d2=0.720 g=0.731
>320, 10/10, d1=0.695, d2=0.717 g=0.694
################# Summarize ###################
>Accuracy real: 35%, fake: 57%

经过 320 个时代,下面是我能够产生的图像质量。这个 GAN 的训练花了大约 30 分钟。更复杂的发生器和鉴别器模型可以产生更好质量的图像。

save_plot() will generate a 7 by 7 matrix of images

GAN 向完美立方体的进展

Created by Tresnatiq from Noun Project

现在,这些新生成的少数民族类图像可以添加到原始不平衡数据集中。这将有助于将不平衡的多类数据转换成平衡的数据集。这将提高模型的分类性能。

可以在这里找到针对这种不平衡数据集的图像分类算法

[## 对 CNN 模型更高精度的探索

在本帖中,我们将学习使用数据重新设计、超参数调整和模型改进准确性的技术…

towardsdatascience.com](/the-quest-of-higher-accuracy-for-cnn-models-42df5d731faf)

所有的 iPython 笔记本都可以在https://github.com/swanandM/DC-GAN-RetinopathyImages买到

图像分类笔记本https://github . com/swanandM/Diabetic-Retinopathy-Detection-with-TF

GANs 的精彩用例

GAN 在最初几年取得了令人印象深刻的进步。2017 年,甘能够创作出 1024 x 1024 大小的图像,几乎可以骗过所有人。尽管这种技术会产生严重的社会信任问题,但考虑到这些天发布的假新闻的数量。工程师在开发任何会引起社会动荡的应用程序之前必须小心谨慎。

Towards the automatic Anime characters creation with Generative Adversarial Networks

为游戏和电影创作动画需要付出巨大的努力。甘可以在没有任何专业技能的情况下自动生成这些动画角色。除此之外,一个专业的动画创作者可以从这些设计中获得灵感。

CycleGAN

CycleGAN 可以将图像从一个域转换到另一个域。

PixelDTGAN

PixelDTGAN 用于根据名人照片生成营销图像。这也用作基于图像的建议工具。

StackGAN

文字转图像是域转移 GAN 的应用之一。这有巨大的应用,包括照片编辑和计算机辅助设计。

DTN

根据图片创建表情符号是 Snap chat 和 Instagram 等平台已经使用的知名应用之一。

参考文献

  1. 使用条件生成对抗网络进行不平衡学习的有效数据生成
  2. 如何开发 GAN 以生成 CIFAR10 小型彩色照片
  3. 甘的一些炫酷应用
  4. 如何训练一个甘?

意识是一个强大的无监督学习框架

原文:https://towardsdatascience.com/consciousness-is-a-powerful-unsupervised-learning-framework-250d1cfc9ca0?source=collection_archive---------13-----------------------

Photo by Sebastian Unrau on Unsplash

你是丛林中的生物。当茂密的灌木丛在争夺穿过树冠的午后阳光时,震耳欲聋的蝉鸣不断提醒人们,一切都在密谋吃掉你。

在寻找吃的东西的时候(毕竟你不比其他任何东西好),你瞥见远处有动静。你将目光锁定在它的方向。它是食肉动物!当它爬行的时候,你看不见它,因为它躲在树后。

意识如何帮助你的事业?

没有意识:
你感到害怕。你有一种想藏起来的冲动,于是你爬进了你能找到的第一个洞。几分钟后,你又开始感到安全了。你离开临时避难所,继续寻找食物。砰!在等待的几分钟里,捕食者向你靠近,现在它已经把你叼在嘴里了。你所有的美丽世故都被用于它的化学能。

用意识:
你感到害怕。你一直盯着那棵树。当掠食者重新出现在树的左边时,你似乎没有被发现。你躲在一棵树后,计划一条安静的路径,让你和可能非常糟糕的一天保持更大的距离。当你在你的道路上导航时,经常回头看捕食者可以让你适应它险恶路线上的任何变化。你从一个隐藏点跳到另一个隐藏点,直到你们都不在感知范围内。你开始再次感到安全,继续寻找食物,保持你所有美丽的成熟。

我将解释意识是如何工作的,并在最后解释意识在这个丛林场景中运作的各个方面。

意识利用自身的知识和对环境的理解来实现学习、计划和适应的机制。

我之前写过理解是一种模拟。理解使用感官信息来检测代表环境中元素的模式。当组成环境的各种元素在模拟中建模时,理解就形成了。为了发展意识,模拟必须足够全面,包括模拟器作为一个元素。

Photo by Daniil Kuželev on Unsplash

通过将模拟器作为一个元素,模拟获得了看似神奇的预测能力。

因为模拟器可以选择自己的动作,所以模拟器可以以接近 100%的准确率进行预测。此外,模拟器选择的动作具有特定的感官效果。例如,如果理解了一个视觉场景,向左移动一步将改变以可预测的方式观察该场景的角度。因此,行动的感官后果,如向左迈一步,是可以预测的。

如果一个动作的感官结果是可以预测的,那么用于理解常规感官信号的相同过程也可以用于预测的感官信号。对预测的感觉信号的理解是对近期未来的模拟。

对未来的模拟是强大的,因为我们可以用它来创造工作记忆。工作记忆是一种连续的模拟,可以保存元素并修改它们。例如,你正在使用你的工作记忆来理解我,在你的大脑内存在着一个思想模拟,它保存着我正在描述的各种元素。随着每一个经过的句子,这些元素被修改以创建新的理解(我在之前关于理解的帖子中更详细地描述了语言理解)。

我们如何从模拟未来的能力中创造工作记忆?未来的模拟可以预测感官输入。因此,感觉输入可以被预期,而不是被观察。

为了预测感官输入,模拟器的模型被用来产生“反信号”预期的反信号从实际的感觉输入中减去预期的感觉输入,如未来模拟所预测的。这种操作将感官输入从一个被动的信息流转换为一个新的信号,这个新的信号代表了所有意料之外的东西。反过来,“未预料到的”信号是更新模拟的完美信号。这个框架实现了一个连续的模拟(即工作记忆),它接收任何未预料到的或新的更新。

这种持续的模拟就是意识。然而,为了使反信号成功地创建更新信号,未来模拟和当前时刻之间的时间差(当它发生时)必须大于进行未来模拟和发送反信号所需的时间。如果在你可以利用信息做任何事情的时候,预测未来已经过去了,那么预测未来是没有用的。

模拟越复杂,预测未来的时间就越长。因此,未来模拟的复杂度有一个特定的复杂度限制,由未来模拟&反信号产生的速度决定。这个原则支配着意识体验的最大广度。

如果计算机曾经被制造成有意识的,由于它们的速度,它们将比我们更有意识。

Photo by Tianyi Ma on Unsplash

既然解释了意识的机制,那么我们如何利用它进行无监督学习呢?通过使用更新信号。

在每一个当下时刻,新的感官信息验证或否定理解的特定元素。如果理解很差,将会有许多错误,并且更新信号将携带误解的信息。如果理解是精确的,未来的模拟将与其对应的当前时刻相匹配,并且更新信号将是可以忽略的。

意识通过最小化更新信号来实现无监督学习。理解更新信号就是理解误解。因此,更新信号既是理想的损失函数,也是优化模型的理想信息

如前所述,这是丛林生物如何利用意识生存的:

  1. 这种丛林生物能够将捕食者保持在工作记忆中,以保持其对树的注视。
  2. 规划安静路线的能力需要模拟未来的能力。
  3. 更新捕食者的位置和路径的概念需要更新信号。
  4. 作为一个感觉半径的认知中心意味着对自我(即模拟器)的意识。

用 Flask 构建 HTTP 数据管道

原文:https://towardsdatascience.com/constructing-http-data-pipelines-with-flask-27fba04fbeed?source=collection_archive---------16-----------------------

许多数据科学工作倾向于关注那些非常明显的属性,如训练模型、验证、统计……然而,如果没有可用的数据,所有这些技能最终都像是在泥沼中冲刺。如今用于在网络上传输数据的最大工具之一是 Flask。Flask 是一个非常棒的工具,通常用于在 Python 中创建数据驱动的 web 应用程序和管道。Flask 有大量的内置功能,可以与 SQL、Json 和 HTML 一起使用,这使得它非常适合 web 上的后端使用。

请求和返回

为了拥有一个完全基于云的管道,以及相应的回报,我们需要了解 Flask 的请求和返回系统。对于计算型或信息型返回管道,通常会保留默认路线,或者:

[@app](http://twitter.com/app).route('/')

这意味着 Flask-app 的目录没有被更改,并允许我们在访问路由时执行一个函数。这可以比作“Index.html”

当然,我们知道我们在哪里,但是我们如何将超文本传输协议应用到 Flask 以接收数据和传输结果呢?为此,我们需要向我们的项目添加请求:

from flask import Flask, render_template, request

对于这个特殊的例子,我和我的一些同事一起做一个项目;全栈开发者、UI/UX 开发者、前端开发者。和往常一样,我有一个 Github 回购的源代码链接。我的任务是创建一个算法,该算法将获取房屋的某些属性,并返回一个预测,用户可以将该预测保存到他们的帐户中。最大的挑战是以一种特定的方式设置事情,以便他们的请求和我的回报可以正确地排列。如果你想看整个项目的 Github,这里是。

有了这个方法,我构建了我的 Sklearn 管道,并把它分配出去。让这变得困难的是数据中包含的大量观察结果…这很难处理,尤其是首先很难阅读。如果你不确定这样的事情是如何做的,你可以在这里查看笔记本。

我选择的模型是 XGBoost 回归器,对于这种情况,它有自己的优点和缺点。最大的缺点是一个不重要的特性会扭曲结果。我只用了几个特征,就像我们数据科学家所做的那样,我可以用统计数据证明这些特征对模型的结果有重大影响,然后用标准标量把它放入管道,以提高一点准确性。

最后请求!

你曾经看过地址栏,并在谷歌搜索中读出网址吗?您可能会看到类似这样的内容:

search=hello%where%are%we?

这是因为 Google 的整个网站都是建立在 HTTP 请求之上的,当然这和返回管道有一点不同,但是不管怎样,这就是这个方法的价值范围。

我们可以使用函数从 flask 请求传输协议 URL 信息

request.args

所以在我的项目中,我做了这样的事情:

try:        
  bathrooms = request.args['bathrooms']        
  bedrooms = request.args['bedrooms']        
  squarefeet = request.args['squarefeet']        
  yearbuilt = request.args['yearbuilt']    
except KeyError as e:        
  return ('Some Values are missing')

这只是在当前的 http 请求中请求参数,以便将参数引入 Python。因此,如果我们请求应用程序的路线,比如:

ourapp.com/?[bedrooms=5&bathrooms=2&squarefeet=1500&yearbuilt=1988](https://predictorman.herokuapp.com/?bedrooms=5&bathrooms=2&squarefeet=1500&yearbuilt=1988)

我们的请求会带来:

bedrooms = 5
bathrooms = 2
squarefeet = 1500
yearbuilt = 1988

很酷,对吧?你也可以在这里测试一下。但现在我们进入了利用这条管道的有趣部分,即返回所请求的信息。还记得我们基于工作的管道吗?我们现在可以把它带进我们的 Flask 应用程序

from joblib import load
pipeline = load('alg.sav')

我最终将所有的值都放入一个观察数据框中,因为这似乎是最容易处理的。最后但同样重要的是,我们可以使用管道进行预测,并返回结果:

estimate = pipeline.predict(dcry)        
return str(int(estimate))

因此,我们在应用程序的路径目录下的最后一个功能是:

def template():
    try:
        bathrooms = request.args['bathrooms']
        bedrooms = request.args['bedrooms']
        squarefeet = request.args['squarefeet']
        yearbuilt = request.args['yearbuilt']
    except KeyError as e:
        return ('Some Values are missing')
    try:
        bathrooms = float(bathrooms)
        bedrooms = float(bedrooms)
        squarefeet = float(squarefeet)
        yearbuilt = int(yearbuilt)
    except ValueError as e:
        return ('That aint a number, Cowboy.')
    else:
        dcry = pd.DataFrame({"YearBuilt": [yearbuilt],        "LotSize": [squarefeet],"Bedrooms": [bedrooms],        "Bathrooms": [bathrooms]})
        pipeline = load('alg.sav')
        estimate = pipeline.predict(dcry)
        return str(int(estimate))

最后

这些管道绝对可以成为任何数据驱动的应用程序的基础。拥有一个独立的实体的好处是显而易见的,尽管这也可以在本地应用程序中实现。无论你是想返回 k-best 结果,还是想预测一栋房子的价格,数据管道都是一种非常好的方式,可以完全独立地在幕后完成。

建构主义机器学习

原文:https://towardsdatascience.com/constructivist-machine-learning-7c2192883c2d?source=collection_archive---------38-----------------------

让机器学习更接近人类的愿景

Photo by The Roaming Platypus on Unsplash

有没有办法用建构主义的方式重新解读机器学习?更重要的是,我们为什么要这么做?

这两个问题的答案都很简单。是的,我们可以做到,这样做的动机可能会解决现代机器学习的一个关键缺陷,即,让它更接近人类对现实的解释。

认知功能的关键部分是模型。

人类能够建立非常复杂的模型,这要归功于我们大脑的工作方式。功能主义心理学已经表明,心理模型能够不断构建假设的结构来预测环境,并不断修改它们。

我们可以依靠 Stachoviak (1973)的一般模型理论来尝试理解什么是现实和认知。

学习由构建、解构和重构模型构成。建构主义理论认为不存在独立于人类的现实,知识是个人获得的。如果你从这个角度思考机器学习,它基本上不属于任何以人为本的现实解释。

但是,您可以映射:

  • 构造(创建,想象)为无监督学习
  • 重建(复制、模仿)为监督学习
  • 解构(反映、怀疑)反而没有清晰地映射出来。它部分映射到在线学习,但不是全部。这也是因为您需要研究模型、抽象、比较、区分它们,并选择/丢弃无效的模型。

实际上,在机器学习算法中实现一些建构主义方法是可能的。例如,这里有一个简单的方案,您可以查看两个分类模型。我们查看模型的时间(T)、主题(适马)和目的(Z)。两个模型下面的表格显示了不同的情况(当三个方面中的一个不同时)以及它在建构主义过程方面意味着什么。

这个故事源自 Thomas Schmid(莱比锡大学)在斯坦福大学举行的关于 KB & AI 2019 的 AAAI 人工智能春季研讨会上基于他的论文所做的演讲。

联系我们

原文:https://towardsdatascience.com/contact-us-83c96b92f285?source=collection_archive---------16-----------------------

问题、投诉、反馈和想法

About Us | FAQs — Photo by Corinne Kutz

发表在《走向数据科学》

你有兴趣在《走向数据科学》上发表你的文章吗?在提交帖子之前,请务必阅读我们的规则和指南。此外,我们只发表遵循媒体的策展指南的文章,所以请确保您通读了这些指南!

投诉或报告问题

我们犯了错误吗?我们确实会犯错误,并且愿意检讨错误。你可以直接发邮件给我们:publication@towardsdatascience.com。此外,您可以:

  • 举报帖子&用户直接到媒体。
  • 举报侵犯版权在这里。
  • 在此向 Medium 的支持团队报告 IT 问题(如与登录或会员资格相关的问题):help.medium.com。

如需其他信息,请联系我们

还没看到你要找的东西吗?你可以在这里找到我们所有的常见问题。

我们最常被问到的一些问题包括:

  • 我需要付费阅读你的出版物吗?
  • 你只用英文出版吗?
  • 我可以发送我已经在 Medium 上发表的帖子吗?

…以及更多。

如果还是找不到你的答案,可以在这里联系我们。请注意,我们不会回复那些已经在我们的常见问题解答中回答过的问题。

使用 Docker-Compose 将您的整个数据科学环境(或任何您想要的东西)容器化

原文:https://towardsdatascience.com/containerize-your-whole-data-science-environment-or-anything-you-want-with-docker-compose-e962b8ce8ce5?source=collection_archive---------7-----------------------

用一个简单的文件和几个命令行从多个交互的容器构建应用程序的入门指南。

Source: Pixabay

在本文中,我想与您一起探索如何创建一个容器化的数据科学环境或您可能想要的任何其他系统,您可以快速部署到任何运行 Docker 的机器上,可能是您的笔记本电脑或云计算机。为此,我想向您演示的工具是 Docker-Compose ,它是 Docker 的补充,用于构建和运行由多个容器构成的应用程序。本文中我想与您一起构建的示例系统将由三个组件组成:一个用于进行实验的 Jupyter Notebook 服务器,一个用于记录和组织实验参数和指标的 MLflow 跟踪服务器,以及一个作为后端的 Postgres 数据库我的主要目的是给你一个 Docker-Compose 的概念和如何使用它,并假设你至少对 Docker 有一个基本的了解,或者可能是对它的用途和工作原理有一个初步的了解。如果没有,让我们快速了解一下为什么您应该为另一项技术而烦恼。

为什么要用 Docker 和 Compose 呢?

当你已经安装好了所有的东西并且设置得很好的时候,你可能会问自己为什么要使用 Docker。简而言之,没有太多的流行词——宾果:对我来说,真正开始尝试了解 Docker 和 Compose 的动机是建立一个与本文中我将向您展示的环境类似的环境,托管在服务器上的某个地方,以便我可以从任何地方访问它。因为我在配置和设置方面没有天赋,所以我想在我的笔记本电脑和 Docker 容器中舒适地尝试一下,在那里我不会破坏任何东西,然后在我准备好的时候把它放到云中。我也仍然不确定云提供商,所以我真的很喜欢这个想法,能够快速拿起我的设置并移动到其他地方。
当我告诉一位同事这个小项目时,他也很感兴趣,因为他认为在为学生举办研讨会或举办研讨会时,当您可能需要让您的设置突然在许多计算机上运行时,或者您可能只是想让它在按需部署时,这是一个很好的东西。

我还发现让我的生活变得容易得多的另一件事是,你可以多么可靠地用容器再现结果。如果你从事软件工作,当遇到任何设置问题时,你很可能迟早会遇到这句名言“它在我的机器上工作”。容器使这成为过去,因为它们的行为是非常可预测的,无论你在哪里部署和运行它们,你都会得到相同的结果,当它“在我的机器上工作”时,它也很可能在你的机器上工作。

对我来说,将 Compose 添加到工具箱的动机是,一旦您想要将多个容器连接在一起以便彼此交互,事情就变得不那么琐碎了。Docker-Compose 是一个简单的工具,它允许你描述多个容器的集合,这些容器可以通过它们自己的网络以一种非常直接的方式进行交互,这正是我所需要的。你可以在一个小小的 YAML 格式的文件中指定一切,将容器定义为服务,定义来存储数据,设置端口转发,这比只使用 Docker 还要简单即使你只使用一个容器,我也发现它非常方便,我现在几乎只使用它。Docker 的所有桌面发行版中都包含了 Compose,所以如果你有一个正在运行的版本,你可以马上试用。

简单的 Jupyter 服务

作为起点,我们将创建一个由单个容器组成的简单系统。让我们从 Jupyter 笔记本开始,定义一个 docker 文件,其中包含笔记本服务器和一个 docker-compose.yml 文件,该文件描述了如何构建和运行 Docker 映像并将笔记本服务器端口暴露给主机,以便我们可以连接到它。Jupyter 很容易上手,因为它背后的团队已经提供了很好的图像,只需添加您可能需要的工具,就可以开始了。使用 Docker-Compose,您可以使用 Docker HUB 等存储库中的现成映像,或者从 Docker 文件构建本地映像。

让我们从项目结构开始,我们有一个 docker-compose.yml 文件,我们将在其中指定我们的系统,我们还有一个 docker 文件,目前只用于我们的笔记本,在我们希望构建和运行的单独文件夹中。

data-toolbox
|- jupyter-notebook-docker
|    |- Dockerfile
|- docker-compose.yml

笔记本 Dockerfile 是 Jupyter 团队在 Docker HUB 上发布的 scipy 图片的简单扩展。 scipy-notebook 镜像已经包含了许多有用的库,比如 numpypandasmatloblibseaborndask 等等,并且还启用了 Jupyter Lab 。我们将向映像中添加两个库, mlflow ,因为我们想要客户端——库的一部分,我们将使用它来连接到 mlflow 跟踪服务器(我们将在下一步设置),以及 psycopg2,库,它将允许我们轻松地连接到我们将在最后设置的 Postgres 数据库。为此,我们只需添加一个 RUN 命令,让 conda 包管理器将 mlflowpsycopg2 添加到环境中。
例如,如果您有兴趣使用 Spark 构建一个设置(您甚至可以在使用 Docker SwarmKubernetes 的集群设置中完全容器化该设置),Jupyter 团队也可以使用 Spark 笔记本映像进行扩展。

A simple Dockerfile, extending from the scipy-notebook and adding some libraries

最后但同样重要的是 docker-compose.yml 文件,还不是很令人兴奋。部分服务描述了我们系统的 Docker 映像,现在我们刚刚添加了一个条目,我们称之为笔记本,在其中我们指定将使用哪个 Docker 文件。在这种情况下,指令说:“在 jupyter-notebook-docker 文件夹中构建 docker 文件,并使用结果图像”。我们还指定我们希望笔记本服务器端口 8888 转发到主机上的同一个端口,以便我们可以连接到我们的笔记本。端口规范的顺序是主机:容器。如果您不想添加任何库,而只想使用预先制作的映像,您可以使用 image 命令,而不是 build ,并指定一个像 jupyter/scipy-notebook 这样的映像。我建议看一下 docker-compose 文件参考,以便更好地理解哪些命令是可用的。

The docker-compose.yml describing a “notebook” service made from a local Docker image

现在,剩下要做的就是构建和运行项目。为了让 Docker-Compose 构建您的本地映像,当您与您的 docker-compose.yml 文件位于同一个文件夹中时,您只需在命令行中键入以下内容。

docker-compose build

如果一切正常,构建成功,你就可以用 compose 命令启动你的系统了。

docker-compose up

如果这也行得通,你现在应该可以通过在浏览器中访问 localhost:8888 来连接到你的新 Jupyter 笔记本了。在 Jupyter images 中,默认情况下启用身份验证,因此确保在启动容器时从日志中复制令牌。

Connecting to localhost:8888 reveals Jupyter running in the container

正如你所看到的,组合可以使运行一个容器变得更容易,因为你可以指定端口转发等。只需用更短的命令运行它,而不需要编写脚本文件。

添加 MLFlow 跟踪服务器

现在变得更有趣了,我们将 MLflow 跟踪服务器添加到组合中,以便我们可以记录实验运行、参数和指标,并组织我们的模型工件。为此,Jupyter 笔记本服务器需要能够与运行在不同容器中的 MLfLow 服务器通信。首先,让我们为新的 docker 文件添加另一个文件夹,这样您的项目结构看起来如下所示。

data-toolbox
|- jupyter-notebook-docker
|    |- Dockerfile
|- ml-flow-docker
|    |- Dockerfile
|- docker-compose.yml

首先,我们再次创建一个简单的 docker 映像,这次运行 MLflow 跟踪服务器。为此,我们扩展了预装 python 3.7 的 python:3.7.0 Docker 映像,它是创建任何类似于此的 Python 相关映像的良好起点。我们所要做的就是通过 pip 安装 MLflow,为它创建一个目录来写入所有数据,然后用命令 mlflow server 启动服务器。基本就是这样。您可以看到 backend-store-uri 选项,它用于告诉 MLflow 在哪里存储数据,这里我们使用一个文件夹,但该选项也接受数据库 URIs 和其他内容,我们将在后面使用。查看跟踪服务器文档以找到关于配置的更多细节。

The Dockerfile for a simple MLflow tracking server

现在来看一个稍微有趣一点的 docker-compose 文件。我们添加了第二个服务,我们称之为 mlflow ,并让它指向 ml-flow-docker 文件夹中的 docker 文件,我们在“系统内部网络”中暴露容器的端口 5000,并再次将其转发到主机的同一个端口,以便我们可以检查我们的实验运行,并查看我们的指标的酷图等等命令 expose 只将 Compose 创建的系统内部网络中的端口公开为端口,我们知道将端口转发给主机。

因为我们还在运行笔记本服务器的容器中安装了 MLflow,所以我们可以设置一个环境变量,告诉 MLflow 客户端默认跟踪实验的位置。当我们正确设置这个变量时,我们不必在每次想要使用跟踪时通过 python API 在笔记本中设置它。Compose 允许您从合成文件中设置这些变量。这里,我们将环境变量 MLFLOW_TRACKING_URI 设置为 MLFLOW 跟踪服务器的地址。由于 Compose 自动为我们的服务创建一个带有域名的网络,我们可以简单地将跟踪 URI 称为服务名,相关端口——ml flow:5000——因为我们为跟踪服务器 mlflow 命名了服务。

The docker-compose.yml file now with an MLflow tracking server which is reachable from the Jupyter notebook

如果我们现在再次在命令行中输入可信的 docker-compose 命令 build,我们将能够连接到 localhost:8888 并连接到我们的 Jupyter 笔记本,用 mlflow 创建一个新的实验并记录一些东西。我们还应该能够连接到 localhost:5000,并查看我们的 MLflow UI 和我们刚刚创建的实验。

Creating a new experiment in MLflow and logging some stuff from a Jupyter Notebook.

We can see our logged experiment data in the MLflow UI running in the other container.

连接数据库

现在到了最棘手的部分,我们将为跟踪服务器添加一个数据库后端,因为对数据库日志的支持是在 0.9.1 中添加的,并承诺在跟踪和查询速度方面比文件存储高得多。数据库也很酷,有一个这样的数据库可以有效地存储和查询表格数据集。将跟踪数据存储在数据库中也有好处,我们可以直接从中查询和分析实验指标,如果您想做 MLflow UI 没有提供的任何事情,这可能是必要的,目前仍然很多。

添加数据库映像本身并不难,Postgres alpine 映像就是您真正需要的,一个运行 PostgresDB 的非常精简的映像。尽管如此,我们仍将从 Postgres 映像扩展并创建我们自己的 docker 文件,主要是因为我们希望将一个初始化脚本复制到映像中的一个文件夹中,以便 Postgres 在启动时初始化 mlflow 数据库。在 compose 文件中,我们像往常一样再次添加一个新服务,并将其命名为 postgres,我们还为 postgres 指定了环境变量,以便在启动时创建一个具有给定名称和密码的超级用户,当我们将数据库 URI 添加到跟踪服务器时,我们将需要它。由于 Postgres 映像已经默认公开了数据库端口,所以我们不需要向合成文件添加一个 expose 命令,但是我们可以再次将端口转发给主机来检查数据库。项目结构、docker 文件和合成文件现在如下所示。

data-toolbox
|- jupyter-notebook-docker
|    |- Dockerfile
|- ml-flow-docker
|    |- Dockerfile
|- postgres-docker
|    |- Dockerfile
|    |- init.sql
|- docker-compose.yml

Dockerfile for the PostgresDB, copying the init.sql into the init folder

The init.sql file, initializing the database for MLflow

The docker-compose file, now with the Postgres database added

为了使用 Postgres 数据库作为 MLflow 的后端,我们需要在启动 MLflow 服务器时将数据库 URI 配置为后端存储 uri 。此外,由于后端存储 uri 现在指向一个数据库,MLflow 将抱怨它不能在那里存储工件,所以您还需要提供一个默认工件根来指定工件存储的位置。请记住,如果您提供一个文件路径,而不是一个 NFS 或云存储解决方案(如 AWS S3)的地址,工件将存储在客户端,所以在运行笔记本的容器中,在我们这里指定的文件夹下,因为它基本上只是告诉客户端在哪里存储工件。跟踪服务器文档概述了目前工件存储的可能性。

The Dockerfile for the MLflow Server, now with a Postgres database backend configured

尽管您可以用 depends 命令告诉 Docker-Compose 以何种顺序启动服务,但这并不总是足够的。Compose 将看到一个容器启动,但不会等待它准备就绪,因为这对每个容器来说意味着其他事情,对于数据库来说,一旦 PostgresDB 接受连接,我们就认为容器准备就绪。不幸的是,数据库需要一段时间启动,MLflow 服务器立即检查数据库连接,发现没有开放的端口接受指定 URI 下的连接,然后关闭。太好了,现在怎么办?

感谢比我聪明得多的人,例如,你可以得到一个非常方便的 shell 脚本wait-for-it . sh它允许你等待任何服务接受 TCP 连接,然后执行任何其他命令。显然,这只是实现这一点的一种方式,请随意留下你在评论中找到的其他方法,因为我很好奇其他人是如何解决这个问题的。

要合并脚本,我们只需下载它,将其放入包含跟踪服务器 Dockerfile 的文件夹中,并稍微更改 Dockerfile 以将脚本复制到映像中,设置执行标志以便它具有运行权限,然后我们使用脚本启动 MLflow 服务器,假设 Postgres 接受连接。默认情况下,脚本会在 15 秒内每秒尝试连接一次,这已经足够了。提示:我花了一段时间才弄明白,当你在 Windows 上把文件复制到镜像中时,确保它有 LF 作为行尾,而不是 CRLF,这会导致 bash 在容器中“找不到文件”。

The final Dockerfile for the MLFlow Tracking Server, waiting for the database to be up

让您的数据持久化

关于 Docker 容器的有趣的事情是,如果你关闭它们,你的数据、你的 Jupyter 笔记本、你在 MLFlow 中的指标以及数据库中的所有东西都不见了。每次启动编写环境时,您都可以从头开始。这很好,但并不总是你想要的,通常情况下,人们似乎不喜欢每次打开电脑就从头开始工作。这就是为什么我们必须让 Docker 容器将它们的数据写入一个持久存储,通常是主机磁盘。然后,当您再次启动容器时,您的数据仍将在那里。

有两种通用的方法可以实现这一点,一种是直接将主机的文件路径绑定到容器中的文件路径,另一种也是推荐的,也是稍微简单一点的方法,就是使用 Docker volumes。卷是由 Docker 管理的主机文件系统上的空间,与绑定文件路径相比有一些优势,例如,它们独立于主机文件结构,这意味着当移动到新机器时,您不需要更改任何内容,并且使用不同的卷驱动程序您还可以写入远程存储位置,而不是主机。我发现的另一个伟大的事情是,它们也可以在 Windows 主机上无缝地工作,否则当你试图简单地与 Docker 共享对本地文件夹的访问时,你会经常遇到问题。

无论您选择哪个选项,您唯一需要弄清楚的是容器将数据写入哪个目录,然后在那个位置挂载一个卷。例如,对于笔记本服务器,笔记本启动并将其数据写入文件夹 /home/jovyan 。如果我们在该点装载一个卷,数据将被写入容器外的卷中,并保持持久。为了让 Docker Compose 创建卷,我们只需添加一个名为 volumes 的部分,然后指定卷应该具有的一些名称,然后将它们绑定到文件中相应服务部分下的容器中的正确路径。最后,包含容器的卷挂载的最终合成文件如下所示。

The final docker-compose.yml for our environment

如果您想知道当您让 docker 管理卷时,您的数据最终在哪里,您可以使用下面的 Docker 命令检查它们。请注意,您创建的卷的名称不会与您在合成文件中指定的名称完全相同。相反,当 Compose 创建卷时,它会在前面加上项目的名称,默认情况下是包含合成文件的目录的名称。在我们的例子中,项目目录被称为 data-toolbox ,因此为了检查文件存储卷,例如,我们将使用下面的命令。

docker volume inspect data-toolbox_file-store

您将得到类似如下的结果,在挂载点下,您可以看到该卷的数据将存放在主机上的什么位置。

[
    {
        "CreatedAt": "2019-06-17T18:51:53Z",
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "data-toolbox",
            "com.docker.compose.version": "1.23.2",
            "com.docker.compose.volume": "file-store"
        },
        "Mountpoint": "/var/lib/docker/volumes/data-toolbox_file-store/_data",
        "Name": "data-toolbox_file-store",
        "Options": null,
        "Scope": "local"
    }
]

结论

我希望我能够用这个小例子来演示如何轻松地创建一个由多个容器组成的系统,该系统可以通过网络进行交互,并且可以大量共享数据。如果你已经跟随了,你现在应该有一个小型的容器化环境,你可以在你的笔记本电脑上玩,或者甚至可以放在一个服务器上,如果你愿意的话,可以认真地工作。您还应该能够扩展它,以添加您的环境中可能需要的更多东西,如不同的数据库、仪表板、消息队列和流服务器、Spark、构建工具或谁知道什么,您的想象力是有限的,我鼓励您尝试一下。使用 Docker 容器的好处是,你不能破坏任何东西。您可能会在某个时候耗尽磁盘空间,因为图像和容器会变得很大,如果您不运行一些命令来清理它们并不时地关闭它们,它们就会堆积起来。

一旦你熟悉了它,我发现让它快速运行起来变得很有趣。我不再在我的笔记本电脑上安装本地数据库进行开发,我提取一个 Docker 映像并运行它,如果我想保留数据,我会添加一个卷,如果不想,我就不这样做。如果你想更深入地了解这个问题,Docker 容器可以使很多事情变得更容易和更快,从构建管道到分布式系统和软件测试,等等。像微服务架构这样的东西只有在使用容器的情况下才真正可行。它可能会让你的生活变得更轻松,或者提高你的工作效率。

非常感谢您的阅读。

语境理论 I:会话结构

原文:https://towardsdatascience.com/context-theory-i-conversation-structure-98713ad42175?source=collection_archive---------19-----------------------

"Must a name mean something?" Alice asked doubtfully. 
"Of course it must,"  Humpty Dumpty said with a short laugh; "my name means the shape I am -  and a good handsome shape it is, too. With a name like yours, you might  be any shape, almost."
                          Through the Looking Glass, Lewis Carroll

在上一篇文章中,我们发现了与语境理论相关的基本语言学概念。在这篇文章中,我们将关注对话结构,为什么一些话语可以跟随一些话语而不尴尬,修补是如何组织的…什么使对话有意义。

一次对话绝对不仅仅是分享话语;根据马丁·布伯,“对话是两个或两个以上实体之间的相互交谈……它是持续交流的有效手段,而不是有目的地试图得出某种结论或表达某种观点。”

在探索个别话语的意义之前,让我们从整体上来看对话的意义。记住,我告诉过你上下文大于其组成部分的总和(尽管我们还不确定那些组成部分到底是什么)

当然,对话的意义取决于

  • 参与者是谁
  • 他们在哪里
  • 他们为什么在那里
  • 语言使用的语境。

那么语言的选择就不是任意的,而是由语境因素系统地驱动的。著名语言学家海姆斯在他的说话模型中对这个问题做了如下更好的解释:

场景是指对话发生的物理和心理环境,在大学大楼,在奶奶家或在医院;在一个有趣的,严肃的,专业的或浪漫的情绪,也许在某种意义上的文化氛围。

参与者是关于参与者的信息,他们的文化和社会背景。显然,老师对学生说话的方式不同于克拉拉阿姨对她的孙子乔说话的方式。

对话的目的和结果。哈利想在同事莎莉的生日聚会上向她表白,然而在赠送礼物时,他没有说“我爱你莎莉”,而是只能说“很高兴见到你”,然后她尴尬的沉默了。不幸的是,最初的目标和结果大相径庭。

CT 序列是话语的序列。

ey 指的是演讲的精神,即快乐、悲伤或热情。

工具是交流的渠道——书写、说话、发信号,有时是凝视,有时是 WhatsApp 信息或短信。线上的方式比较新,但是很常见的渠道。

orms 是一种社会规范。例如,法语、土耳其语、德语和许多其他语言都有一个表示尊敬的第二人称复数形式: voussizSie

enre 是一种家庭间的对话、闲聊、调情或趣闻。就像音乐一样,演讲也有几种类型。与音乐不同,有些语音类型很难定义。

我告诉过你,语言可能没有那么自成一体,肯定有环境效应。此外,我们的大脑认为世界的中心是他/她自己。当我们谈论相对时间或地理位置时,参考点总是现在的和这里的。这些是日常用语中的常用短语:**

*My home                   Tomorrow             Me
My office                 Last week            Your boyfriend
Here                      After my birthday    My mom
Over there                Recently
Opposite to the street    Soon*

这些短语到底指的是哪里、什么时候和谁?更好的情况是,想象一下在一个瓶子里发现一条信息,上面写着,“我的食物用完了,很可能我会在两天内死去。请救救我,我在旧灯塔附近的一个岛上。没有任何日期和地图。你会去找消息的主人吗?没有参考点你怎么知道他是不是已经死了?

本文中最以自我为中心的术语是指示语。如果一个词的语义是固定的,但其指称意义根据时间和/或地点、参考时间/点而变化,那么这个词就是指示词。

Center of our semantic worlds: Ourselves, image source:Wikipedia

*I         this      today
you       that      tomorrow
we        here      now
          there
personal  spatial   temporal*

是典型的指示词,注意代词的存在。代词通常在 NLU 任务中被低估,要么在停用词过滤模块中完全消亡,要么没有引起太多关注。的确,一般来说,它们携带的信息不多,但在短文中,它们可以很大程度上改变意思。

地图应用程序、导航设备、像 我们的 Chris 这样的驾驶助手、打车应用程序和拼车应用程序应该可以解决几乎所有查询中的空间指示。考虑以下对话片段:

*Customer: I ordered a taxi 5 mins ago, where is it now?
Bot: It's on the way, arrives in 4 mins.
Customer: Can he come opposite side of the park?*

这里,很明显“公园的对面”是靠近客户位置的公园(在我的例子中是蒂尔加滕😁).我们的 Chris 每天都面临这样的问题,并成功地解决了它们:

*Hey Chris, navigate home
Navigiere ins Büro
Navigate to work
Navigate to my place*

时间指示语在顾客抱怨中更常见(昨天、5 天前、明天、1 周前),空间指示语在帮助顾客认路时更常见。空间指示要困难得多,时间指示的确可以被 CFG s 解析;而空间指示语包括地理语义。(我们不告诉任何人我们是如何为克里斯做到的,这是纯粹的黑魔法😉).

正如人们所看到的,作为一种言语行为的对话有许多成分,但我们为什么要聚在一起说话呢?为了进行有意义的对话,参与者应该在同一个场地见面。首先,双方应该愿意交换一些信息,并在一些共同的基础上会面;应该有一些相互的认识和相互的假设。此外,在对话过程中,他们应该向其他参与者示意他们听到了什么以及他们听到了什么;听者必须为说话者的话语建立基础。误解修复是这一过程的一部分,同时也是对话管理中的一项巨大任务。考虑下面的对话部分,为更像人类的对话体验而添加到设计中的基础模式:

*Customer: I want to buy a ticket for tomorrow.
Bot: So *you fly tomorrow*, where are you going?  (confirm what the bot heard)
Customer: To Munich.
Bot: *OK, great*. What time exactly? (confirm that the bot heard the previous utterance)*

人类通过阅读句法、韵律、语调、停顿、手势、一些话语标记以及可能的凝视信号来“知道”谁应该在对话中发言、何时发言以及发言多长时间,话轮转换发生。请注意,有些信号是关于“成为人类”的,人类不仅可以通过文字或口语来阅读他人。一个轻微的停顿或者一个眼神就足以明白对方完了。几千年以来,人类就有阅读他人的能力,由于进化过程,这些基因正在消失。你的聊天机器人设计怎么样?在与客户通电话时,他能知道轮到自己说话吗?(感谢谷歌 Duplex 在这里,谁肯定知道在哪里加入对话。)

本文的最后,也可能是最重要的概念是顺序组织。当我们想给一个话语赋予意义时,这个话语在互动中的位置和它的话语一样重要。一个句子的意思当然会有所不同

*is this utterance opening a dialog?
is it response to some prior utterance?
is it repair of some prior utterance?
or is it opening a new context?*

,不信你亲眼看看:

*Customer: *Hello*!                       (greeting)
Bot:      Hello, how can I help you?Bot: Would you like to order a taxi now?
Customer: *Helllooooo*, I already ordered a taxi 5 mins ago! (ah no)Bot: Would you like to place an order right now?
Customer: *Yes*, please.
Bot: OK, then I'm reserving your seat for Atlanta 9:00AM flight tomorrow.
Customer: *Yes*, but I'm not going to Atlanta, I go to Athens.*

不同种类的邻接对衍生出不同的含义。在第二个例子中,问答邻接对的字面意思是是,,而第二个邻接对是一个错误恢复对,在这个上下文中实际上不携带太多信息,而是用作上下文延续符。

另一个概念与上下文恢复有关,修复组织的确是对话式人工智能中的一个至关重要的话题。我们都有对自己的设计“抱歉,我没明白”的时候(意外时有发生😶),问题是一个人能否从困境中恢复过来,尽快回到之前的语境?当出现问题时,要么是用户发起纠正,要么是聊天机器人想要澄清情况。请看以下对话片段:

*Customer: Please play Crazy from Britney.
Bot:      I'll put on Seal right away.
Customer: No, Britney Spears.
Bot:      Alright, You Drive Me Crazy from Britney comes.Customer: Put on some good vibes, please.
Bot:      Sorry I didn't quite get that, can you maybe rephrase your sentence?
Customer: Play some music please.
Bot:      Sure, what would you like to listen?*

一个典型的修复轨迹由以下动作序列组成:故障、修正启动和修正。最重要的是不要因为迷失在修复轨迹中而丢失先前的上下文:

*- I want to order 2 cheeseburgers please.
- Ketchup or mayo?
- One with ketchup, other with mayo please.
- Sorry I didn't quite get that.            (here the order is not comprehended)
- Which part you didn't understand?
- Sorry I didn't quite understand, can you maybe rephrase? 
(this is the point of losing it, bot forgets about the order and focuses on recovering the very last utterance)*

亲爱的读者,我们已经完成了语言学和结构基础;然而我们渴望更多。在本系列接下来的几集里,我们会发现语义框架、上下文的“类型”、如何参与以及具体参与什么……更多的计算问题。在一天结束的时候,我们都喜欢 PyTorch 代码,对吗😉

更多信息,请加入我们在https://chris.com的精彩克里斯工程活动。我们为对话式人工智能带来了一场革命,并创造了一种独特的产品。你也可以随时登陆 https://duygua.github.io 来看我。同时保持快乐和和谐!

参考

  • 布伯,马丁。1958.我与你。纽约:斯克里布纳。
  • 海姆斯博士,1974 年。社会语言学基础:人种学方法。费城:宾夕法尼亚大学出版社。

语境理论 I:导论

原文:https://towardsdatascience.com/context-theory-i-introduction-9d121194bd48?source=collection_archive---------17-----------------------

计算语用学的语言学基础导论

"That's a great deal to make one word mean", Alice said in a thoughtful tone.
"When I make a word do a lot of work like that", said Humpty Dumpty, "I always pay it extra".
                          Through the Looking Glass, Lewis Carroll

自早期的状态机和意图分类组合以来,onversational AI 已经走过了漫长的道路。端到端的培训策略和强化学习研究加速取代了不可扩展的预定义意图和硬编码状态。然而,对于聊天机器人的最终用户来说,事情远非完美无缺。在这方面,对话管理组件显示出很大的改进潜力,像真正的人一样进行对话的关键在于跟上对话。

几乎每个人都可以对一些预定义的意图进行分类。更大的问题是:你能对上下文相关的意图进行分类吗?例如,当许多简短的回答存在于几乎所有的口语中,携带的信息不多,其含义通常严重依赖于上下文,但仍然可以极大地改变对话的方式,并对整个上下文做出巨大贡献时,你该怎么办?

当产生一个答案时,人们也许可以抓住语法衔接和词汇衔接…但是语法和词汇选择是使文章连贯的唯一因素吗?

在这一系列的文章中,我将解释语境理论和计算语用学的基础,主要是为了实用的目的;用于聊天机器人和其他形式的智能助手的对话管理组件。这样,我们可以更好地进行 NLU,更好地模拟对话状态,并生成连贯的答案……从而几乎模仿人类。

开玩笑的。

亲爱的读者们,计算语境理论这种东西并不存在,我也怀疑它是否会存在。与语言学中被充分研究的部分,如句法理论相反,语境缺乏一个定义明确的单位。句法理论享有成分等单位。因此,语法标记、依存语法和短语结构语法吸引了大量的研究。总体结果令人满意,在流行的 NLP 库中有几个基于统计和规则的解析器实现,包括斯坦福 NLP 和 SpaCy 。让我们看一个由 SpaCy 解析器生成的依赖关系的例子:

A typical dependency parse

正如人们所看到的:

  • 语法标签定义明确
  • 依赖关系是明确定义的

如果我们想对上下文做同样的事情呢?

如果一个人有足够的 GPU 能力和一个统计框架,以统计的方式建模依赖关系一点也不困难(好吧,这也不是小事)。然而,如果您想要对上下文建模,您将建模什么呢?到目前为止,构成对话上下文的组件是什么?实体、关系、共同参照、对话记忆、社会规范、对话背景、对话地点和时间、参与者的精神状态和情绪——我们如何对它们建模?

也许我们可以为对话历史建立一个记忆单元——但是参与者的记忆呢?可能参与者 I 前一天晚上睡得不好,感觉很累,当天根本不想交谈,因此只给出简短的回答。也许参与者 II 最近被女朋友甩了,他根本不想谈论女人。你是如何塑造别人的人生经历和心态的?

文化规范或日常生活的一般事实呢?时间和空间依赖?显然,对话发生在工作场所还是咖啡馆很重要。同样的,我想你不会像对你妈妈那样对你的老板说话。

只有一个连续稠密表示还是几个向量?仿真陈述的图形嵌入?

不同的语言学家试图定义什么是语境,以发展他们自己的理论。例如,威多森将语境定义为:

"实际语言使用环境中被认为与意义相关的那些方面"。

G.尤尔给出了一个相当无风险的定义:

在他的指称研究中,“语境是使用一个词的物理环境”。

目的不同,研究重点不同,但有一个非常重要的方面是共同的:环境。人们不能把所说的话与说这话的环境分开。谁要是宣称“语言是一个自成体系的系统”,未必真的正确。语言包括语言学、文化、时间、空间、环境和常识。这就是我们在这个系列中要彻底探索的。

Language not being a self-contained system

在考虑了所有这些计算和语言问题之后,只剩下一个问题:我们到底想把什么建模成上下文?

所谓的“语境”到底是什么?

为了给语境概念找到一个合理的“单位”,我们先来过一遍一些基本概念:

连贯性是你想要寻找的术语,如果你想知道是什么让一篇文章在语义上有意义的话。连贯包括句法特征、常识、常识和逻辑联系。参见示例:

S1: Last week I visited the Sandro shop in KaDeWe. I was not able to fit into any of the dresses.
S2: Oh yes, that's how French sizing is.

在这里,显然第二个说话者知道世界上的常识,桑德罗巴黎是一家法国服装零售商。然后他能够依次对这个问题发表评论。

这个例子怎么样:

S1: Have you met Mike's wife? She's gorgeous.
S2: I didn't know that he's married. He is not wearing a wedding ring.

这段对话看起来非常简单和普通,尽管它包含了一个重要的陷阱。在第二行中,第二个说话者得出了逻辑结论

has-a(Mike, wife) => married(Mike)

通过他们的常识。第二个结论是基于一个文化参照,即已婚者戴结婚戒指。尽管看起来微不足道,但考虑到普通人每天都会得出许多逻辑结论,我们如何表达常识在计算上并不那么简单。我们将在本系列的后面讨论这个问题。

连贯是一个大操场,是逻辑、知识表示、语法、语义的结合;结合大脑的不同部分,尽管被列在语言学之下。然而衔接实际上是一个纯粹的语言学概念。衔接是语法和词汇上的联系,在语义上把语篇粘合在一起。衔接拥有定义明确的工具,在本文中我将讨论指称和省略。

什么是引用?我们可以粗略地说,它是一个指针,在当前的话语语境中,在两个参与者的世界中,一个说话者抓住某个东西。不要扬起你的眉毛,我们仍然在发现“世界”是什么😊。更专业地说,指称表达是说话者用来指称某事物的语言表达。所指的东西叫做所指物。

指称可以是前指或后指。回指指的是在上下文中向后指的行为,而下指的字面意思是向下,来自καταφορά(“向下运动”)。比较示例:

Yesterday I saw *Jim* at the supermarket. **He** was with his lovely dog.
In **his** last years, *Picasso* created many paintings.

这里所指的术语是代词,是先行词吉姆的回指。由于我们对会话界面的语境理论感兴趣,我们更多地看到了回指类型。在第二句中,代词 his 是一个后移代词 Picasso 。也许古希腊人的灵感来自对话的“上语境”和“下语境”——谁知道呢?😉

另一个源自希腊语的术语省略号(字面省略)在口语中大量出现:当一个短语从上下文来看“显而易见”时,我们就简单地省略它。

Should I call you tomorrow or ˢʰᵒᵘˡᵈ you ᶜᵃˡˡ me?Susanna is working full day on Mondays, ˢʰᵉ ᶦˢ ʷᵒʳᵏᶦⁿᵍ a half day on Fridays.- I'm writing a blog.
- For how long ʰᵃᵛᵉ ʸᵒᵘ ᵇᵉᵉⁿ ʷʳᶦᵗᶦⁿᵍ ᵃ ᵇˡᵒᵍ?

省略的一种常见且被广泛研究的形式是动词短语省略、或简称 VP-省略。在这种结构中,省略了一个非限定动词短语。参见示例:

I won't do it, but my colleague will ᵈᵒ ᶦᵗ.She can do it if she wants to ᵈᵒ ᶦᵗ.I fell asleep and she did, too.    'fell asleep' replaced by 'did'

我们如何给这类句子赋予意义?一种可能性是,我们的大脑进行了严格的语法替换,例如在第三句中,为了将含义添加到做了,我们寻找以前的 VP,发现睡着了。另一种可能性是,我们不是进行语法重建,而是检索当前的语义上下文。在第二种情况下,我们执行连续上下文向量的检索,而不是词性标注。虽然我们可以完全理解我们自己语言的语法,但我们可以使用一些检索任务,不是吗?😉最终,人脑可以用不同的方式处理语义。让我们希望我们能在整个系列中保持一致。

Brain, the most complicated semantic machine: syntactical parsing vs recent context retrieval

另一个话语概念,确定性/不确定性实际上是小学水平的语法信息——然而,就什么是可推断的信息,什么不是而言,它非常有用。我们都知道英语的定冠词(the)和不定冠词(a,an)。然后,定冠词和不定冠词被用于名词短语:女孩、苹果……当我们想在上下文中引入一个新的实体时,我们使用不定冠词。后来,如果我们想指这个实体,我们要么把它和定冠词一起用,要么用代词,要么用指示词。例如:

 Customer: I have bought 2 pairs of shoes, I want to return one
 Bot:      OK, please give me your tracking number
 Customer: 3EF1233AG
 Bot:      There is **a black Lanvin pair** and **a zebra Escada**. Which one would you like to give back?
 Customer: **The black pair**, please.

在这里,顾客的回答是完全连贯和可以理解的,因为一行前就已经介绍了这双黑色的鞋子。因此,在这一点上,客户和机器人都熟悉所谈论的对象。

事实上,相反的情况也适用:只有当所指实体的存在已经由当前上下文给出时,确定用法才有意义。你能想象这句话是怎么说的吗😊:

I saw **the movie** last week. **A movie** was not interesting at all.

我的母语是一种没有任何冠词的语言,既没有定,也没有不定。在英语翻译过程中,只有上下文告诉你在哪里插入文章。如果你想正确地说出上面的句子,你应该这样说:

Geçen hafta bir filme gittim. Hiç güzel değildi.

第二句话,虽然没有定冠词,但意思还是懂的。偶尔,我们在特定的情况下使用单回指:

Bot: Hangisini geri vermek istiyorsunuz?
Müşteri: Siyah olanı.   (the) black one

无论如何,熟悉程度不仅仅取决于冠词的用法,它还取决于整个上下文。就像土耳其语到英语的翻译一样,语境为确定性/不确定性提供线索。语境作为一个“整体”比其组成部分的总和更强大;如果某些成分缺失了,我们仍然可以从语篇语境中填补空缺。

亲爱的读者,我们已经到了文章的结尾,但我们仍然不太确定如何表示一个上下文对象,或者更确切地说,上下文对象到底是什么。我们将在本系列的下一篇文章中继续寻找更多的顺序性、更多的语义和更重要的语用学。也许汉姆蒂是对的,毕竟,我们必须付出额外的努力来解决做了很多工作的话,谁知道呢?

更多信息,请参加我们在https://chris.com举办的最佳克里斯工程活动。我们打造下一代驾驶员助手,为对话式人工智能带来一场革命。也可以上 https://duygua.github.io 来找我。在那之前保持快乐和和谐。

参考

  • 马修和蒙塔尼,伊内斯。2017.spaCy 2:利用 Bloom 嵌入、卷积神经网络和增量解析的自然语言理解。 https://spacy.io
  • Manning、Christopher D .、Mihai Surdeanu、John Bauer、Jenny Finkel、Steven J. Bethard 和 David McClosky。2014.斯坦福 CoreNLP 自然语言处理工具包见计算语言学协会第 52 届年会会议记录:系统演示,第 55–60 页。
  • H.威多森。1996.语言学,牛津语言研究入门,ISSN 1754–7865
  • 吉莉安·布朗,布朗·吉莉安,乔治·尤尔。1983.话语分析,剑桥语言学教科书

自然语言处理序列标注的上下文嵌入

原文:https://towardsdatascience.com/contextual-embeddings-for-nlp-sequence-labeling-9a92ba5a6cf0?source=collection_archive---------12-----------------------

用于序列标记的上下文字符串嵌入

Photo by Edward Ma on Unsplash

文本表示(即文本嵌入)是解决自然语言处理任务的一个突破口。起初,单个单词向量代表一个单词,即使在上下文中携带不同的含义。例如,“华盛顿”可以是一个地点、名称或州。“华盛顿大学”

Zalando 发布了一个惊人的 NLP 库,flair,让我们的生活更轻松。它已经实现了他们上下文字符串嵌入算法和其他经典的和最新的文本表示算法。

在这个故事中,您将通过一些示例代码理解用于序列标记的上下文字符串嵌入的架构和设计。

建筑和设计

总体设计是将一个句子传递给字符语言模型来检索上下文嵌入,这样序列标注模型就可以对实体进行分类

Architecture and Design (Akbik et al., 2018)

语境嵌入

与经典的单词嵌入不同,Akbik 等人将其称之为语境化的单词嵌入。换句话说,单词嵌入捕获了上下文中的单词语义,因此即使是同一个单词,在不同的上下文中也可以有不同的表示。你可以从语言模型(ELMo) 中找到语境化的词向量(CoVe) 和嵌入,以了解更多细节。Albik 等人将他们的嵌入命名为上下文字符串嵌入

字符语言模型

与其他模型不同,它基于字符级标记化,而不是单词级标记化。换句话说,它将把句子转换成字符序列,并通过语言模型来学习单词表示。

Contextual Embeddings of “Washington” (Akbik et al., 2018)

以“Washington”为例,双向 LSTM 模型允许“Washington”从前一个单词(即 George)和后一个单词(即 birth)中检索信息,从而可以计算句子上下文中的向量。

向量由前向神经网络和后向神经网络级联而成。对于前向神经网络,将提取单词中最后一个字符(即“n”)之后的隐藏状态。单词中第一个字符(即“W”)前的隐藏状态将从反向神经网络中提取。

堆叠嵌入

与其他研究一样,Akbik 等人利用堆叠嵌入获得了更好的结果。堆叠嵌入意味着组合多个嵌入来表示一个单词。

例如,Akbik 等人连接上下文嵌入和手套嵌入来表示用于序列标记的单词。

序列标签

来自字符语言模型的上下文嵌入和手套嵌入被传递到双向 LSTM-CRF 架构,以解决命名实体识别(NER) 问题。

实验

Experiment Result between previous best result (Akbik et al., 2018)

履行

命名实体识别(NER)

只需要执行以下命令来加载预先训练的 NER 标记。

from flair.data import Sentence
from flair.models import SequenceTaggertagger = SequenceTagger.load('ner')

之后,您可以简单地将句子传递给句子对象,然后执行预测。

sample_texts = [
    "I studied in University of Washington.",
]for text in sample_texts:
  print('-' * 50)
  print('Original Text')
  print(text)

  print('NER Result')
  sentence = Sentence(text)
  tagger.predict(sentence)
  for entity in sentence.get_spans('ner'):
    print(entity)

结果是

Original Text:
**I studied in University of Washington.**
NER Result:
**ORG-span [4,5,6]: "University of Washington."**

情感分类

它和 NER 一样容易。

from flair.data import Sentence
from flair.models import TextClassifierclassifier = TextClassifier.load('en-sentiment')

将句子传递给预先训练的分类器

sample_texts = [
    "Medium is a good platform for sharing idea",
]for text in sample_texts:
  print('-' * 50)
  print('Original Text')
  print(text)

  print('Classification Result')
  sentence = Sentence(text)
  classifier.predict(sentence)
  print(sentence.labels)

结果是

Original Text:
Medium is a good platform for sharing idea 
Classification Result:
 [POSITIVE (0.7012046575546265)]

拿走

要访问所有代码,你可以访问这个 CoLab 笔记本。

  • 除了预训练的 flair 上下文嵌入,我们不仅可以应用经典的嵌入方法,如 GloVe、word2vec,还可以应用最新的嵌入方法,如 ELMo 和 BERT。你可以去看看这个指南做参考。
  • 我们还可以非常容易地实现堆叠嵌入。只需要很少的代码。可以访问这个指南进行参考。
  • 如果你想在你的数据上训练定制模型,这个指南会对你有用。

参考

Akbik A .,Blythe D. Vollgraf R. 2018。用于序列标记的上下文字符串嵌入。

py torch 的天赋

使用神经网络的文本对话中的上下文情感检测

原文:https://towardsdatascience.com/contextual-emotion-detection-in-textual-conversations-using-neural-networks-381e3d8490c4?source=collection_archive---------15-----------------------

如今,与对话代理交谈正成为日常事务,对话系统生成尽可能像人类一样的响应是至关重要的。作为一个主要方面,主要的注意力应该放在为用户提供情感上的反应上。在本文中,我们将描述文本对话中情感检测的递归神经网络架构,它参与了 SemEval-2019 任务 3“emo context”,即语义评估年度研讨会。任务目标是在三回合对话数据集中对情绪(即高兴、悲伤、愤怒和其他情绪)进行分类。

文章的其余部分组织如下。第 1 节简要概述了 EmoContext 任务和提供的数据。因此,第二和第三部分集中于文本预处理和单词嵌入。在第 4 节中,我们描述了提交中使用的 LSTM 模型的架构。最后,给出了系统的最终性能和源代码。该模型使用 Keras 库在 Python 中实现。

1.培训用数据

SemEval-2019 任务 3“emo context”侧重于文本对话中的上下文情感检测。在 EmoContext 中,给定一个文本用户话语以及对话中的两次语境,我们必须分类下一个用户话语的情绪是“快乐”、“悲伤”、“愤怒”还是“其他”(表 1)。只有两个对话参与者:一个匿名的人(tune-1 和 Turn-3)和基于人工智能的聊天机器人 Ruuh (Turn-2)。详细描述见( Chatterjee et al .,2019 )。

Table 1. Examples showing the EmoContext dataset (Chatterjee et al., 2019)

在比赛期间,我们访问了任务组织者提供的 30160 篇人类标记的文本,其中大约 5000 篇样本来自“愤怒”、“悲伤”、“快乐”类,15000 篇来自“其他”类(表 2)。开发和测试集也是由组织者提供的,与训练集相反,它们有一个真实的分布,每个情感类大约占 4%,其余的是“其他”类。数据由微软提供,可在官方 LinkedIn group 中找到。

Table 2. Emotion class label distribution in datasets (Chatterjee et al., 2019).

除了这些数据,我们还收集了 90 万条英语推文,以便为每种情绪创建一个 30 万条推文的远程数据集。为了形成距离数据集,我们基于 Go 等人(2009)的策略,在该策略下,我们简单地将推文与情绪相关的词的存在相关联,如“#愤怒”、“恼火”、“高兴”、“悲伤”、“惊讶”等。查询词列表基于 seme val-2018 AIT DISC(duppa da et al .,2018 )的查询词。

EmoContext 的关键性能指标是三种情绪类别的微观平均 F1 分数,即“悲伤”、“快乐”和“愤怒”。

2.文本预处理

在任何训练阶段之前,文本都经过文本工具Ekphrasis(Baziotis et al .,2017 )的预处理。该工具有助于执行拼写纠正、单词规范化、分段,并允许指定哪些标记应该被省略、规范化或用特殊标签注释。我们在预处理阶段使用了以下技术。

  • URL、电子邮件、日期和时间、用户名、百分比、货币和数字都被替换为相应的标签。
  • 重复的、删节的、拉长的和大写的术语都用相应的标签标注。
  • 基于内置的单词统计语料库自动纠正拉长的单词。
  • 基于内置的单词统计语料库执行标签和缩写解包(即,分词)。
  • 为了减少各种情绪,使用了手动创建的字典来替换从文本中提取的术语。

此外,Emphasis 提供了 tokenizer,它能够识别大多数表情符号、表情符号和复杂的表达方式,如经过审查、强调和拉长的单词,以及日期、时间、货币和首字母缩写词。

Table 3. Text pre-processing examples.

3.单词嵌入

单词嵌入已经成为 NLP 系统的任何深度学习方法的基本部分。为了确定最适合情绪检测任务的向量,我们尝试了 Word2Vec ( Mikolov 等人,2013 )、GloVe ( Pennington 等人,2014 )和 FastText ( Joulin 等人,2017 )模型以及 DataStories 预训练的词向量( Baziotis 等人,2017 )。Word2Vec 的关键概念是在向量空间中非常接近地定位在训练语料库中共享公共上下文的单词。Word2Vec 和 Glove 模型都从单词的共现信息中学习单词的几何编码,但本质上前者是预测模型,后者是基于计数的模型。换句话说,虽然 Word2Vec 试图预测目标单词(CBOW 体系结构)或上下文(Skip-gram 体系结构),即最小化损失函数,但 GloVe 计算单词向量,对共现计数矩阵进行维数缩减。FastText 与 Word2Vec 非常相似,除了它使用字符 n 元语法来学习单词向量,因此它能够解决词汇表之外的问题。

对于上面提到的所有技术,我们使用了作者提供的默认训练平台。我们基于这些嵌入中的每一个训练一个简单的 LSTM 模型(dim = 64 ),并使用交叉验证比较有效性。根据结果,预训练嵌入的数据集表现出最好的平均 F1 分数。

为了用单词的情感极性来丰富所选择的单词嵌入,我们考虑通过在自动标记的距离数据集上对嵌入进行微调来执行距离预训练短语。使用预培训的重要性在( Deriu 等人,201 7)中得到证明。我们使用遥远的数据集训练简单的 LSTM 网络来分类愤怒、悲伤和快乐的推文。嵌入层在第一个训练时期被冻结,以避免嵌入权重的显著变化,然后在接下来的 5 个时期被解冻。在训练阶段之后,微调的嵌入被保存用于进一步的训练阶段,并且公开可用。

4.神经网络体系结构

递归神经网络(RNN)是专门用于处理顺序数据的人工神经网络家族。与传统的神经网络相比,rrn 被设计成通过共享它们处理序列的内部权重来处理序列数据。为此,RRNs 的计算图包括循环,表示先前信息对当前信息的影响。作为 RNNs 的扩展,长短期记忆网络(LSTMs)在 1997 年被引入( Hochreiter 和 Schmidhuber,1997 )。在 LSTMs 中,递归单元以特定的方式连接,以避免消失和爆炸梯度问题。传统的 LSTMs 只保存过去的信息,因为它们只在一个方向上处理序列。双向 LSTM 结合了两个反向移动的隐藏 LSTM 层的输出,其中一个通过时间向前移动,另一个通过时间向后移动,从而能够同时捕获来自过去和未来状态的信息( Schuster 和 Paliwal,1997 )。

Figure 1: The architecture of a smaller version of the proposed architecture. LSTM unit for the first turn and for the third turn have shared weights.

图 1 提供了我们方法的高级概述。所提出的神经网络结构包括嵌入单元和两个双向 LSTM 单元(dim = 64)。前一个 LSTM 单元旨在分析第一用户的话语(即会话的第一和第三轮),后一个旨在分析第二用户的话语(即第二轮)。这两个单元不仅学习语义和情感特征表示,还学习如何捕捉用户特定的对话特征,这允许更准确地对情感进行分类。在第一步,使用预先训练的单词嵌入将每个用户话语馈送到相应的双向 LSTM 单元。接下来,这三个特征图被连接在一个展平特征向量中,然后被传递到一个完全连接的隐藏层(dim = 30),该隐藏层分析所获得的向量之间的相互作用。最后,这些特征通过 softmax 激活函数继续通过输出层来预测最终的类标签。为了减少过拟合,在嵌入层之后添加了具有高斯噪声的正则化层,在每个 LSTM 单元(p = 0.2)和隐藏全连接层(p = 0.1)之前添加了丢弃层(斯里瓦斯塔瓦等人,2014 )。

5.结果

在搜索最佳结构的过程中,我们不仅试验了层中的单元数量、激活函数和正则化参数,还试验了神经网络的结构。关于这个短语的详细信息可以在原文中找到。

上一节中描述的模型展示了 dev 数据集上的最佳得分,因此它被用于竞赛的最终评估阶段。在最终的测试数据集上,情感类的微观平均 F1 分数达到 72.59%,而所有参与者的最高分数为 79.59%。然而,这远远高于任务组织者发布的官方基线,即 58.68%。

模型的源代码和单词嵌入可以在 GitHub 获得。

[## sis metanin/emo sense-seme val 2019-task 3-emo context

该存储库包含用于 SemEval-2019 任务 3 的 EmoSense 提交的模型的源代码…

github.com](https://github.com/sismetanin/emosense-semeval2019-task3-emocontext)

文章的完整版本和任务描述论文可以在 ACL 选集找到。
训练数据集位于 LinkedIn 的官方竞赛组。

引用:

[@inproceedings](http://twitter.com/inproceedings){
    smetanin-2019-emosense, 
    title = "{E}mo{S}ense at {S}em{E}val-2019 Task 3: Bidirectional {LSTM} Network for Contextual Emotion Detection in Textual Conversations", 
    author = "Smetanin, Sergey", booktitle = "Proceedings of the 13th International Workshop on Semantic Evaluation", 
    year = "2019", 
    address = "Minneapolis, Minnesota, USA", 
    publisher = "Association for Computational Linguistics", 
    url = "[https://www.aclweb.org/anthology/S19-2034](https://www.aclweb.org/anthology/S19-2034)", pages = "210--214"
}

用 Python 从头开始连续遗传算法

原文:https://towardsdatascience.com/continuous-genetic-algorithm-from-scratch-with-python-ff29deedd099?source=collection_archive---------3-----------------------

遗传算法是一种受自然启发的强大优化技术。遗传算法模仿进化来寻找最佳解决方案。与大多数优化算法不同,遗传算法不使用导数来寻找最小值。遗传算法最显著的优点之一是它们能够找到全局最小值而不会陷入局部最小值。随机性在遗传算法的结构中起着重要的作用,这也是遗传算法不断搜索搜索空间的主要原因。标题中的连续意味着我们要创建的遗传算法将使用浮点数或整数作为优化参数,而不是二进制数。

Flowchart of genetic algorithms

遗传算法创建随机生成的候选解的初始群体,评估这些候选解,并计算它们的适应值。解的适应值是决定解有多好的数值,适应值越高,解越好。下图显示了一个有 8 个人的示例生成。每个个体由代表优化参数的 4 个基因组成,并且每个个体具有适应值,在这种情况下,适应值是基因值的总和。

An example of a generation

如果初始种群不满足终止准则的要求,遗传算法产生下一代。第一次遗传操作是选择;在这个操作中,将会进入下一代的个体被选择。在选择过程之后,配对操作开始。配对操作将选定的个体两两配对,以进行交配操作。交配操作采用配对的亲代个体并产生后代,后代将替换在选择操作中未被选择的个体,因此下一代具有与上一代相同数量的个体。重复该过程,直到满足终止标准。

在本文中,使用 Python 标准库和 Numpy 从头开始创建遗传算法代码。前面讨论的每一种遗传操作都是作为函数创建的。在我们开始遗传算法代码之前,我们需要导入一些库作为:

import numpy as np
from numpy.random import randint
from random import random as rnd
from random import gauss, randrange

初始人口

遗传算法通过创建候选解的初始群体来开始优化过程,候选解的基因是随机生成的。为了创建初始群体,必须创建一个创建个体的函数;

def individual(number_of_genes, upper_limit, lower_limit):
    individual=[round(rnd()*(upper_limit-lower_limit)
                +lower_limit,1) for x in range(number_of_genes)]
    return individual 

该函数将基因数量、基因的上限和下限作为输入,并创建个体。在创建了创建个体的函数之后,需要另一个函数来创建群体。创建群体的函数可以写成:

def population(number_of_individuals,
               number_of_genes, upper_limit, lower_limit):
    return [individual(number_of_genes, upper_limit, lower_limit) 
        for x in range(number_of_individuals)]

使用这两个函数,可以创建初始群体。在遗传算法产生第一代后,计算个体的适应值。

适合度计算

适应度计算函数决定了个体的适应度值,如何计算适应度值取决于最优化问题。如果问题是优化一个函数的参数,那么该函数应该被实现为适应度计算函数。优化问题可能非常复杂,可能需要使用特定的软件来解决问题;在这种情况下,适应性计算功能应该运行模拟,并从正在使用的软件中收集结果。为了简单起见,我们将回顾文章开头给出的生成示例。

def fitness_calculation(individual);
    fitness_value = sum(individual)
    return fitness_value

这是一个非常简单的适应度函数,只有一个参数。可以为多个参数计算适应度函数。对于多个参数,归一化不同的参数是非常重要的,不同参数之间的幅度差异可能导致其中一个参数对于适应函数值变得过时。可以用不同的方法来优化参数,归一化方法之一是重新缩放。重新缩放可以表示为:

Function for normalizing parameters

其中 m_s 是参数的换算值,m_o 是参数的实际值。在此函数中,参数的最大值和最小值应根据问题的性质来确定。

在参数被归一化之后,参数的重要性由适应度函数中给予每个参数的偏差来确定。给定参数的偏差总和应为 1。对于多个参数,适应度函数可以写成:

Multi-parameter fitness function

其中 b 表示适应度函数的偏差,而 p 表示归一化参数。

选择

选择函数获取候选解的群体及其适应度值(一代),并输出将进入下一代的个体。可以将精英主义引入到遗传算法中,遗传算法会在一代中自动选择最佳个体,因此我们不会丢失最佳解。有几种选择方法可以使用。本文给出的选择方法有:

  • 轮盘选择:在轮盘选择中,每个个体都有机会被选中。个体被选中的几率是基于个体的适合度值。更健康的人更有可能被选中。

Roulette wheel selection figure

轮盘游戏轮盘选择的函数获取累积和以及选择过程中随机生成的值,并返回所选个体的号码。通过计算累积和,每个个体都有一个介于 0 和 1 之间的唯一值。为了选择个体,随机产生一个 0 到 1 之间的数字,并且选择接近随机产生的数字的个体。轮盘赌函数可以写成:

def roulette(cum_sum, chance):
    veriable = list(cum_sum.copy())
    veriable.append(chance)
    veriable = sorted(veriable)
    return veriable.index(chance)
  • 最适合的一半选择:在这种选择方法中,候选解中最适合的一半被选择出来进入下一代。

Fittest half selection figure

  • 随机选择:在这种方法中,个体随机选择。

Random selection figure

选择函数可以写成:

def selection(generation, method='Fittest Half'):
    generation['Normalized Fitness'] = \
        sorted([generation['Fitness'][x]/sum(generation['Fitness']) 
        for x in range(len(generation['Fitness']))], reverse = True)
    generation['Cumulative Sum'] = np.array(
        generation['Normalized Fitness']).cumsum()
    if method == 'Roulette Wheel':
        selected = []
        for x in range(len(generation['Individuals'])//2):
            selected.append(roulette(generation
                ['Cumulative Sum'], rnd()))
            while len(set(selected)) != len(selected):
                selected[x] = \
                    (roulette(generation['Cumulative Sum'], rnd()))
        selected = {'Individuals': 
            [generation['Individuals'][int(selected[x])]
                for x in range(len(generation['Individuals'])//2)]
                ,'Fitness': [generation['Fitness'][int(selected[x])]
                for x in range(
                    len(generation['Individuals'])//2)]}
    elif method == 'Fittest Half':
        selected_individuals = [generation['Individuals'][-x-1]
            for x in range(int(len(generation['Individuals'])//2))]
        selected_fitnesses = [generation['Fitness'][-x-1]
            for x in range(int(len(generation['Individuals'])//2))]
        selected = {'Individuals': selected_individuals,
                    'Fitness': selected_fitnesses}
    elif method == 'Random':
        selected_individuals = \
            [generation['Individuals']
                [randint(1,len(generation['Fitness']))]
            for x in range(int(len(generation['Individuals'])//2))]
        selected_fitnesses = [generation['Fitness'][-x-1]
            for x in range(int(len(generation['Individuals'])//2))]
        selected = {'Individuals': selected_individuals,
                    'Fitness': selected_fitnesses}
    return selected

配对

配对和交配在大多数遗传算法应用中被用作单个操作,但是为了创建更简单的函数并且能够容易地使用不同的交配和配对算法,这两个遗传操作在该应用中被分开。如果在遗传算法中存在精英,精英必须是函数的输入以及被选择的个体。我们将讨论三种不同的配对方法;

  • 最适:在这种方法中,个体两两配对,从最适个体开始。通过这样做,健康的个体被配对在一起,但是不健康的个体也被配对在一起。

Fittest pairing figure

  • 随机:在这种方法中,个体被两两随机配对。

Random pairing figure

  • 加权随机:在这种方法中,个体两两随机配对,但更适合的个体被选中配对的几率更高。

Weighted random pairing

配对函数可以写成;

def pairing(elit, selected, method = 'Fittest'):
    individuals = [elit['Individuals']]+selected['Individuals']
    fitness = [elit['Fitness']]+selected['Fitness']
    if method == 'Fittest':
        parents = [[individuals[x],individuals[x+1]] 
                   for x in range(len(individuals)//2)]
    if method == 'Random':
        parents = []
        for x in range(len(individuals)//2):
            parents.append(
                [individuals[randint(0,(len(individuals)-1))],
                 individuals[randint(0,(len(individuals)-1))]])
            while parents[x][0] == parents[x][1]:
                parents[x][1] = individuals[
                    randint(0,(len(individuals)-1))]
    if method == 'Weighted Random':
        normalized_fitness = sorted(
            [fitness[x] /sum(fitness) 
             for x in range(len(individuals)//2)], reverse = True)
        cummulitive_sum = np.array(normalized_fitness).cumsum()
        parents = []
        for x in range(len(individuals)//2):
            parents.append(
                [individuals[roulette(cummulitive_sum,rnd())],
                 individuals[roulette(cummulitive_sum,rnd())]])
            while parents[x][0] == parents[x][1]:
                parents[x][1] = individuals[
                    roulette(cummulitive_sum,rnd())]
    return parents

交配

我们将讨论两种不同的交配方法。在下面给出的 Python 代码中,两个选定的父个体创建了两个子个体。我们将要讨论两种交配方法。

  • 单点:在这种方法中,单点之后的基因被另一个亲本的基因替换,从而产生两个后代。

Single point mating

  • 两点:在这种方法中,两点之间的基因被替换为另一个亲本的基因,从而产生两个后代。

Two points mating

交配功能可编码为:

def mating(parents, method='Single Point'):
    if method == 'Single Point':
        pivot_point = randint(1, len(parents[0]))
        offsprings = [parents[0] \
            [0:pivot_point]+parents[1][pivot_point:]]
        offsprings.append(parents[1]
            [0:pivot_point]+parents[0][pivot_point:])
    if method == 'Two Pionts':
        pivot_point_1 = randint(1, len(parents[0]-1))
        pivot_point_2 = randint(1, len(parents[0]))
        while pivot_point_2<pivot_point_1:
            pivot_point_2 = randint(1, len(parents[0]))
        offsprings = [parents[0][0:pivot_point_1]+
            parents[1][pivot_point_1:pivot_point_2]+
            [parents[0][pivot_point_2:]]]
        offsprings.append([parents[1][0:pivot_point_1]+
            parents[0][pivot_point_1:pivot_point_2]+
            [parents[1][pivot_point_2:]]])
    return offsprings

突变

最后的遗传操作是随机突变。随机突变发生在被选择的个体及其后代中,以提高下一代的多样性。如果遗传算法中存在精英主义,精英个体不会经历随机突变,因此我们不会失去最佳解决方案。我们将讨论两种不同的突变方法。

  • 高斯:在该方法中,经历突变的基因被替换为根据原始基因周围的高斯分布生成的数字。

  • 重置:在该方法中,原始基因被随机生成的基因所替代。

Reset mutation figure

变异函数可以写成:

def mutation(individual, upper_limit, lower_limit, muatation_rate=2, 
    method='Reset', standard_deviation = 0.001):
    gene = [randint(0, 7)]
    for x in range(muatation_rate-1):
        gene.append(randint(0, 7))
        while len(set(gene)) < len(gene):
            gene[x] = randint(0, 7)
    mutated_individual = individual.copy()
    if method == 'Gauss':
        for x in range(muatation_rate):
            mutated_individual[x] = \
            round(individual[x]+gauss(0, standard_deviation), 1)
    if method == 'Reset':
        for x in range(muatation_rate):
            mutated_individual[x] = round(rnd()* \
                (upper_limit-lower_limit)+lower_limit,1)
    return mutated_individual

创造下一代

下一代是用我们讨论过的遗传操作创造出来的。在产生下一代的过程中,精英主义可以被引入遗传算法。精英主义是创造下一代的 python 代码,可以写成;

def next_generation(gen, upper_limit, lower_limit):
    elit = {}
    next_gen = {}
    elit['Individuals'] = gen['Individuals'].pop(-1)
    elit['Fitness'] = gen['Fitness'].pop(-1)
    selected = selection(gen)
    parents = pairing(elit, selected)
    offsprings = [[[mating(parents[x])
                    for x in range(len(parents))]
                    [y][z] for z in range(2)] 
                    for y in range(len(parents))]
    offsprings1 = [offsprings[x][0]
                   for x in range(len(parents))]
    offsprings2 = [offsprings[x][1]
                   for x in range(len(parents))]
    unmutated = selected['Individuals']+offsprings1+offsprings2
    mutated = [mutation(unmutated[x], upper_limit, lower_limit) 
        for x in range(len(gen['Individuals']))]
    unsorted_individuals = mutated + [elit['Individuals']]
    unsorted_next_gen = \
        [fitness_calculation(mutated[x]) 
         for x in range(len(mutated))]
    unsorted_fitness = [unsorted_next_gen[x]
        for x in range(len(gen['Fitness']))] + [elit['Fitness']]
    sorted_next_gen = \
        sorted([[unsorted_individuals[x], unsorted_fitness[x]]
            for x in range(len(unsorted_individuals))], 
                key=lambda x: x[1])
    next_gen['Individuals'] = [sorted_next_gen[x][0]
        for x in range(len(sorted_next_gen))]
    next_gen['Fitness'] = [sorted_next_gen[x][1]
        for x in range(len(sorted_next_gen))]
    gen['Individuals'].append(elit['Individuals'])
    gen['Fitness'].append(elit['Fitness'])
    return next_gen

终止标准

在一代被创建之后,终止标准被用于确定遗传算法是否应该创建另一代或者应该停止。可以同时使用不同的终止标准,并且如果遗传算法满足标准之一,则遗传算法停止。我们将讨论四个终止标准。

  • 最大适应度:该终止标准检查当前世代中最适应的个体是否满足我们的标准。使用这种终端方法,可以获得期望的结果。如下图所示,最大适应度极限可以被确定为包括一些局部最小值。

  • 最大平均适应度:如果我们对一组解感兴趣,可以检查当前代中个体的平均值,以确定当前代是否满足我们的期望。
  • 最大代数:我们可以限制遗传算法产生的最大代数。
  • 最大相似适应值:由于精英主义,一代中最优秀的个体可以不发生变异而进入下一代。这个个体也可以成为下一代中最好的个体。我们可以限制同一个体成为最佳个体的数量,因为这可能意味着遗传算法陷入了局部极小值。用于检查最大适应值是否已经改变的函数可以写成:
def fitness_similarity_chech(max_fitness, number_of_similarity):
    result = False
    similarity = 0
    for n in range(len(max_fitness)-1):
        if max_fitness[n] == max_fitness[n+1]:
            similarity += 1
        else:
            similarity = 0
    if similarity == number_of_similarity-1:
        result = True
    return result

运行算法

既然遗传算法所需的所有函数都准备好了,我们就可以开始优化过程了。以每代 20 个个体运行遗传算法;

# Generations and fitness values will be written to this file
Result_file = 'GA_Results.txt'# Creating the First Generation
def first_generation(pop):
    fitness = [fitness_calculation(pop[x]) 
        for x in range(len(pop))]
    sorted_fitness = sorted([[pop[x], fitness[x]]
        for x in range(len(pop))], key=lambda x: x[1])
    population = [sorted_fitness[x][0] 
        for x in range(len(sorted_fitness))]
    fitness = [sorted_fitness[x][1] 
        for x in range(len(sorted_fitness))]
    return {'Individuals': population, 'Fitness': sorted(fitness)}pop = population(20,8,1,0)
gen = []
gen.append(first_generation(pop))
fitness_avg = np.array([sum(gen[0]['Fitness'])/
                        len(gen[0]['Fitness'])])
fitness_max = np.array([max(gen[0]['Fitness'])])
res = open(Result_file, 'a')
res.write('\n'+str(gen)+'\n')
res.close()finish = False
while finish == False:
    if max(fitness_max) > 6:
        break
    if max(fitness_avg) > 5:
        break
    if fitness_similarity_chech(fitness_max, 50) == True:
        break
    gen.append(next_generation(gen[-1],1,0))
    fitness_avg = np.append(fitness_avg, sum(
        gen[-1]['Fitness'])/len(gen[-1]['Fitness']))
    fitness_max = np.append(fitness_max, max(gen[-1]['Fitness']))
    res = open(Result_file, 'a')
    res.write('\n'+str(gen[-1])+'\n')
    res.close()

结论

遗传算法可以用来解决多参数约束优化问题。像大多数优化算法一样,遗传算法可以直接从 sklearn 等一些库中实现,但从头创建算法提供了一个关于它如何工作的视角,并且该算法可以针对特定问题进行定制。

感谢您的阅读,希望这篇文章对您有所帮助。

遗传算法是由约翰·h·霍兰德首先提出的,你可以在这里找到他的原著;

https://MIT press . MIT . edu/books/adaptation-natural-and-artificial-systems

如果你也想了解更多关于遗传算法的知识,你可以看看这两本书;

[## 遗传算法基础|奥利弗·克莱默|斯普林格

这本书向读者介绍遗传算法,重点是使概念,算法,和…

www.springer.com](https://www.springer.com/gp/book/9783319521558)

https://www . Wiley . com/en-us/Practical+Genetic+Algorithms % 2C+2nd+Edition-p-9780471455653

为我们的收藏做贡献

原文:https://towardsdatascience.com/contribute-to-our-collections-94aafae1494f?source=collection_archive---------16-----------------------

作家指南

将您的最新文章添加到我们的收藏中

我们的收藏收集了关于数据科学不同方面的令人兴奋的不同观点。目前,我们有五个系列可供您选择:

  • 现实世界中的数据科学 数据科学中最紧迫的问题是什么,我们可以做些什么来解决这些问题?
  • 数据新闻学。 数据科学如何帮助我们理解世界和媒体。
  • 深入剖析 以有趣且完整的(端到端)数据分析为特色。
  • 内哀 。人工智能是如何工作的,它能解决什么问题,有什么潜在的风险,它对我们其他人意味着什么?
  • 体育分析学。 数据科学与竞技的交集。

如何将您的帖子添加到我们的收藏中?

  1. 确保你的职位非常合适
  2. 给你的帖子添加标签:“现实世界中的 DS”、“数据新闻”、“深度分析”、“Inside AI”,或者“运动”。此标签会自动将您的帖子添加到我们的收藏中。
  3. 添加一个带有收藏名称的 kicker(和一个链接):

如何添加踢球者?(看我们的视频)

  1. 添加标题
  2. 添加副标题(在标题下方)
  3. 添加一个踢球者。这就像在你的标题上面加了一个副标题。
  4. 不要忘记将你的 kicker 链接添加到我们的收藏页面!

干得好!

控制数字分析中的多重比较

原文:https://towardsdatascience.com/controlling-multiple-comparisons-in-digital-analytics-92a879c4cbc6?source=collection_archive---------19-----------------------

做出的推论越多,就越有可能出现错误的推论。已经开发了几种统计技术来防止这种情况发生,允许直接比较单一和多重比较的显著性水平。”

在进行实验时,我们作为数据分析师或科学家的目标要求我们尽可能多地从我们的发现中学习。这可以通过多种方式实现,但通常我们会通过确定尽可能多的有用指标或通过执行适当的事后细分来实现。这两种技术都有助于我们以不同的方式更多地了解我们的受众。在定义指标的情况下,我们可能希望确定我们的数字平台的变化如何影响主要指标,但作为结果,变化可能如何影响我们页面的其他重要方面(例如,对健康指标的损害)。关于细分,我们可以进行后续的统计分析,以确定重要或不重要发现的路径;例如,页面性能的整体积极变化是否归因于某个设备或平台的性能?或者某个特定的人群。以上所有这些都意味着深入挖掘你的发现,并综合切实的见解来创造未来的假设。然而,这是有代价的…

Figure 1. Possible test outcomes from experimentation, presenting both Type 1 and Type 2 errors

您在分析中包含的比较越多,您观察到第一类错误的可能性就越大,这也称为假阳性。这篇文章将首先概述在你的分析中加入比较如何影响你的统计发现,以及可以用来控制这个因素的方法。如果你在实验过程中采用了 95%的置信水平,你就接受了一个单一指标 5%的假阳性率。然而,只要您查看一个以上的指标,检测到误报的可能性就会增加。所以比较越多,假阳性越多。

Figure 2. Visual representation taken from Skyscanner Engineering depicting the increase in false positive rate when including more metrics in analysis.

图 2 取自 Skyscanner 的 公开分析,他们通常在实验记分卡中采用 14 个指标。它描述了一个没有实际影响的实验(A 对 A;AA 测试),以及它对一个指标产生显著影响的概率,作为分析中增加指标数量的函数。当在程序中采用 14 个指标时,任何一个实验都有大约 50%的机会出现一个或多个假阳性。

这种夸大的假阳性率的概念也可以应用于多变量测试(MVT),在这种测试中,你要用多种条件进行试验。同样,事后细分(可通过您的分析集成将单个指标划分为设备、平台、地理和/或人口细分)也会提高您的误报率。此外, Skyscanner 称“如果你观察一项实验如何改变 20 个不同国家中每一个国家的一个指标,你会发现至少有一个国家在 60%的时间里受到了显著影响,即使你的实验没有任何实际效果。”进一步支持控制多重比较的需要。

幸运的是,目前存在许多统计方法,可以用来减轻多重比较问题;这通常涉及在进行分析之前调整您选择使用的显著性阈值,以便确定检测结果为阳性所需的 p 值也是实验考虑的比较次数的函数。

正如我们所知,统计假设检验是基于拒绝零假设,如果观察数据在零假设下的可能性相对较低。如果测试了多个假设,则罕见事件的机会增加,因此,错误拒绝零假设(即,犯 I 型错误)的可能性增加。因此,诸如 Bonferroni 校正之类的方法通过在 a/n 的显著性水平上测试每个单独的假设/比较来补偿上述增加,其中 a 是期望的α水平,而 n 是比较的次数。Bonferroni 校正控制着家族误差率(FWER ),即当您的实验没有真正的积极效果时,您的比较中至少有一个出现显著性的概率。FWER 是拒绝至少一个真假设的概率,即,做出至少一个假阳性发现(I 型错误)的概率。

我将在下面分解一个例子,看看你的数字分析实验会是什么样子。

您关心的是英国 3 个地区之间的单个指标的统计显著性,alpha 水平为 95%:

n = 3

= 0.05

因此,在应用 Bonferroni 校正时,您将测试每个地理区域/比较,如下所示:

= 0.05/3

= 0.015

然后将该值用作校正后的 p 值,只有当测试结果小于 0.015 时,您才会认为该测试结果具有统计学显著性。这种校正后的 p 值可以很容易地纳入任何自定义电子表格或统计计算器中,用于确定分析的统计效果。

关于 FWER 的控制,Bonferroni 被广泛认为是控制多重比较的保守方法,如果有大量正相关的测试和/或比较。这是因为假设每个比较对于所有比较都是彼此独立的。这必然意味着所做的修正是以增加呈现假阴性(II 型错误)的概率和降低你的统计能力为代价的。然而,统计学家的普遍共识是,低估实验的真实效果比严重高估效果更好——因此,采取保守的校正比接受大量假阳性测试结果更好。

总之,在数字分析领域工作时,你会尽可能多地综合你的实验发现。然而,执行更精细的比较会导致确定假阳性的可能性随之增加。因此,可以在事后分析中使用 Bonferroni 校正等方法来调整 p 值,以考虑指标或实验比较的增加。尽管这种方法被广泛认为是解决多重比较的一种保守方法,但它在大量的科学实践中被使用,并且适用于实验比较之间共线性程度较低的情况。

Conv 假人网

原文:https://towardsdatascience.com/conv-nets-for-dummies-a-bottom-up-approach-c1b754fb14d6?source=collection_archive---------15-----------------------

直观的方法

有许多很棒的在线文章解释了从初学者到高级水平的卷积神经网络(或“CNN”)。这篇文章是为初学者写的,旨在采取一种不同于大多数人的方法:自下而上地解释 CNN 的机制和系统。我的假设是,许多工程师按照解决方案被创建的顺序来学习它们:一次添加一个新功能来构建最终产品。

本文将分为三个部分。

  • 首先,解释一下 CNN 要解决的问题。
  • 第二,逐一解释 CNN 的算法(“层”)。
  • 第三,这些层的使用顺序和原因。

第一部分:CNN 的设计初衷是什么?

计算机视觉奥林匹克是一年一度的竞赛,绰号为“图像网络挑战”(ILSVRC)。从 2010 年开始,这项任务一直是建立一个能够正确识别图像中物体的计算机程序。也就是说,如果我给你的程序一张蝴蝶的图片,它应该返回字符串“butterfly”

这个过程几乎是人脑瞬间完成的。不用我说,你已经知道上面的图像是什么了。那是因为人类看到狮子的那一刻,大脑就把它识别为一个截然不同的物体,并立刻将其归类为“狮子”。从生存的角度来考虑这些好处并不困难。ImageNet(名为“AlexNet”)的 2012 年获奖者将这种人类技能作为他们设计的基础。他们通过研究关于大脑识别物体的神经科学理论,创建了一个成功的 CNN。

那么大脑是如何把上面的图像变成“一块地里的三只狗?”我们做的一件事是识别背景的绿色和狗的棕色皮毛之间的清晰边缘。利用这个我们可以识别出狗的大致轮廓:两只耳朵伸出来,身体很长。这个轮廓内部的其他形状帮助我们确定它是一只狗而不是一只狐狸(考虑舌头、嘴和鼻子的形状等)。狗的颜色也帮助了我们。因此,假设我们想像人类一样处理识别形状的问题,我们可能想从制造一种算法开始,这种算法将识别图像中的某些形状或边缘。这是第二部分的切入点。

输入细节

对于这个问题,理解输入数据的形状是很重要的。对计算机来说,图像是一个三维(宽×高×深)矩阵,值在 0-255 之间。4K 彩色图像的尺寸为 4096×2160×3。也就是说,它的像素宽度像素高度三个颜色通道 RGB。这些值表示每个像素的每种颜色的强度。为了简化,本文将主要考虑深度为 1 的黑白图像。

A visual representation of a 6×6×3 image

第二部分:CNN 的层次

卷积神经网络可以分解成几个部分。这些组件可以被认为是独立的算法,通常被称为“层”首先,单独考虑各层。第 3 节将在后面讨论它们是如何结合的。有三层我们来看看 (A,B,C)

层 A:卷积

正如第 1 节中提到的,我们可能想要识别图像内部的边缘或颜色。例如,我们可能想要检测如下图所示的曲线。可以使用值矩阵来表示曲线(就像输入一样)。 滤镜的深度总是等于图像的深度。

现在我们要测试图像是否包含这个形状。代表这个形状的矩阵被称为过滤器。它也被称为神经元或内核。让我们使用我们的滤镜来测试下面这个简单的图形:

如果我们关注与过滤器具有相同尺寸(W×H×D)的图像部分,我们可以计算图像部分值和过滤器值的点积。首先,让我们检查包含我们要测试的形状的图像区域。我们关注的区域被称为感受野:

现在执行过滤器和感受野之间的点积:

这个部分的点积计算为 218535,这是一个非常大的数字。如果图像中的形状与过滤器的形状不太相似,这个数字会更小。在下面的示例中,由于图像中的形状与滤镜的形状不匹配,点积计算出的值要低得多(计算出的值为 0)。

事实上,点积越大,过滤器和图像的截面越相似。因此,我们可以使用过滤器和图像部分的点积来测试特定形状的位置。获得正确的过滤器值是很重要的,因为您想要测试适当的形状。我们在 CNN 中“训练”的值正是这个:过滤器的矩阵值。在对一组图像进行训练之前,通常会随机初始化这些值。注意,过滤器的值也可以是负数。

但是我们如何存储这些信息呢?我们希望为图像中有曲线的地方保留某种形式的记录。我们如何存储左上方有一条曲线,而右侧没有?

Taken from this very helpful repo on GitHub

对于每个感受野,点积计算存储在另一个称为激活图的矩阵中。

它被称为,因为激活图上的任何位置都将表示形状(过滤器)与实际图像的相应位置的匹配程度。换句话说,地图显示了图像中某个形状出现的位置。

一个滤镜的激活图深度始终为 1。

B 层:池化

池层的目的是减少激活图的空间大小。这不仅减少了必要的计算量,而且防止了过度拟合。合用的想法很简单。我们想把大矩阵缩小成小矩阵。最常用的池技术是最大池

这种方法的思想是只保留激活图中较小区域的最大值,而去掉其余的。在上面的橙色区域中,7 是最大值,因此它被保留,而 5、3 和 2 被丢弃。

C 层:完全连接

全连接层总是卷积神经网络的最后一层。这是因为它是将图像上完成的转换关联到实际类别(如“狮子”和“鼠标”)的层。

这一层是传统的多层感知器。理解多层感知器对于从总体上理解机器学习模型很重要(在这里用图像找到一个很棒的解释!)。CNN 的全连接层只是其应用的众多情况之一。因此,我敦促你寻找另一个更深入的教程。现在,我将重点讨论这一层的输入和输出。

全连接层的输入是一个值矩阵,包含某些复杂形状的位置信息。它实际上指出了这些形状在图像上的位置。

我们如何获得这种输入将在第 3 节中变得更加明显。然而,现在要记住的重要事情是,输入指示复杂图案的位置,这些复杂图案帮助我们猜测图像是由什么组成的。我们称这些复杂的模式为可训练分类器。模型学习寻找的确切的可训练分类器可能与上面给出的说明性例子有很大不同。

为什么我们不 使用全连接层?

好吧,虽然全连接层可能能够“分析”已经识别的形状的组合,但是它不能理解单个像素。这是因为单个像素与图像包含的内容无关,而复杂的形状却相关。很少有猫的图像包含轮子的形状。

全连接层的输出是我们决定训练模型的每个类别的概率向量。例如,如果我们强迫一个模型将一幅图像分类为“猫”、“狮子”或“汽车”,那么输出可能是一个向量,例如[0.91,0.08,0.01]。这意味着有 91%的可能性图像是一只猫,8%是一只狮子,1%是一辆汽车。然后,我们选择最有可能的类别作为我们对该图像的“猜测”。 这个向量中的元素之和总是加 1。 (如果你对为什么和多层感知器的激活功能有关感兴趣)。

简而言之,输出权重来源于图像中的可训练分类器的内容,以及它们相对于彼此的位置。这突出了一组好的图片对训练的重要性。如果模型从未从侧面看过汽车,它可能会将这样的图像误分类为不是汽车。然而,我们所做的工作意味着我们不需要从每个角度去看

第三节:合并图层

有几种方法可以将第 2 节中描述的图层组合成对图像分类有用的东西。在这里,我们看看如何结合多个卷积层来识别复杂的形状,以及 CNN 中使用的第四个“层”:非线性函数。最后,我们将看看一些成功的 CNN 及其一般架构。

在 2A 一节中,我们讨论了卷积层,并以一个简单的形状为例来测试图像。实际上,过滤器看起来有点不同。左边是一个来自 CNN 的斯坦福课程的例子。这是过滤器外观的更精确的可视化。

认识到这些模式是一个好的开始,但它们可能不会识别出什么是“狮子”或“猫”为此,我们需要用这些简单的形状构建更复杂的形状。

为了识别下面的形状,我们可以像前面一样为它创建一个过滤器。如此复杂的过滤器的问题是,它可能无法识别相似但不完全适合的形状,或者它可能会错误地触发看起来不像过滤器的形状。

更简单的过滤器可以更好地避免这些问题。因此,它们保持简单。相反,我们在一个卷积层中对图像应用多个滤波器,并且仅当它们被检测到并被单独记录在激活图中时,才在下一层中组合它们。

原始图像上的两个单独的形状(过滤器 1 和 2)在激活图中被识别为较高的值(根据点积计算)。然后,我们可以创建一个与第一层的输出深度相同的过滤器来组合这些过滤器。在上面的例子中,这个深度是 2,因为我们使用了 2 个过滤器。在其他架构中,这可能更大;这完全取决于我们在第一层使用多少过滤器。在我们的例子中,第二层的滤波器可以非常简单。我们希望通过查看激活图 1 找到形状 1 的出现,通过查看激活图 2 找到形状 2 的出现。将这些投影到 2D 图像上应该会产生它们的并排组合。因此,我们可以识别图像中具有更复杂形状的区域。

然后,这个过程会根据您的需要重复多次。重复更多次意味着网络可以学习越来越复杂的形状。目标是学习检测复杂的特征,这些特征可以成为一系列对象的可训练分类器。考虑以下汽车的复杂特征:

上述具体特征并不一定是参与 ILSVRC 竞争的网络所要“寻找”的。它们只是帮助我们人类理解 CNN 下正在发生的事情的可视化。

那么,为什么要为这个“非线性函数”而烦恼呢?

如果你熟悉其他神经网络结构,你不会对在卷积层之间使用非线性函数感到惊讶。但这是为什么呢?非线性函数有什么作用?

简单的回答就是卷积是线性变换。对此有简单的数学解释(比如这个),如果你还不相信的话,我建议你读一读。

现在,如果我们一个接一个地执行多个线性变换,最终的过程可以简化为单个线性变换。因此,为了避免卷积层折叠成单个变换,我们可以在每个卷积之间引入非线性元素。

许多 CNN 中使用的一个成功的非线性函数是 ReLU。这是一个简单的函数“max(0,x)”,其中 x 是输入值,应用于整个矩阵的元素。它把任何负值变成 0。

把这些放在一起,设计 CNN 的架构

现在,您已经了解了所有的构建模块。我们(1)采取一个形象,并适用于卷积层。然后,我们(2)对输出应用非线性函数,以便(3)用另一个卷积层重复。在几个卷积和非线性对层之后,我们(4)应用汇集层以降低复杂性并避免过拟合。重复几次(步骤 1-4 ),我们已经确定了一些可训练的分类器,并且可以(6)将输出矩阵发送到完全连接的层中。它输出我们想要训练的每个类别的概率权重。该过程总结如下:

Again, taken from Stanford’s course on CNNs

所有关于层数、超参数和它们的顺序的选择将唯一地识别一个网络。有许多开源和著名的网络,有不同的目的和成功的程度。我们已经讨论了 AlexNet,ILSVRC 2012 的获胜者。另一个专注于识别更复杂的可训练分类器的网络称为 VGG。

就是这样!在这一点上,我们理解了 CNN 如何解决我们在顶部确定的问题:将它以前没有见过的图像分类到主题类别中。

如果你喜欢这篇文章,请考虑给它一点掌声。这真的帮助了我,激励我去做更多!

对话式人工智能:设计和构建一个上下文人工智能助手

原文:https://towardsdatascience.com/conversational-ai-design-build-a-contextual-ai-assistant-61c73780d10?source=collection_archive---------3-----------------------

Photo by Alex Knight on Unsplash

虽然对话式人工智能自 20 世纪 60 年代以来就已经存在,但近年来它正经历一场新的焦点。虽然我们仍然处于智能对话式人工智能的设计和开发的早期,但谷歌非常正确地宣布,我们正在从移动优先转向人工智能优先的世界,在这个世界中,我们希望技术能够自然对话,考虑上下文,并具有进化能力。换句话说,我们期望技术能够学习和进化。

今天,大多数聊天机器人可以处理简单的问题,并根据基于规则的对话处理,以预先构建的响应进行响应。例如,如果用户说 X,用 Y 来响应;如果用户说 Z,调用 REST API,依此类推。然而,在这个节骨眼上,我们对对话有更多的期待。我们想要超越回答简单问题或发送推送通知的上下文助手。在这个系列中,我将带你经历一个设计、开发和部署情境化人工智能助手的过程,这个助手设计策划旅行体验。

首先,让我们来谈谈上下文助手的成熟度水平,从它们的能力来解释:

对话式人工智能成熟度级别

一级成熟度:在这个级别,聊天机器人本质上是一个传统的通知助手;它可以用预先构建的响应来回答问题。它可以向你发送某些事件的通知,或者提醒你明确表示感兴趣的事情。例如,一个 1 级旅行机器人可以为你提供一个预订旅行的链接。

2 级成熟度:在这个级别,聊天机器人可以回答常见问题,但也能够处理简单的后续问题。

第三级成熟度:在这一级,上下文助手可以与你进行灵活的互动,并提供比预先构建的答案更多的答案,因为它知道如何响应意外的用户话语。此时,助手也开始理解上下文。例如,旅行机器人将能够带你走过几个受欢迎的目的地,并做出必要的旅行安排。

第 4 级成熟度:在这一级,上下文助手已经更了解你了。它会记住您的偏好,并可以提供个性化、情境化的建议或“轻推”,以更加主动地提供护理。例如,在你着陆后,助理会主动伸出手帮你订一辆车。

第 5 级及以上:在这一级,上下文助手能够监控和管理许多其他助手,以便运行企业运营的某些方面。他们能够针对特定的旅游体验开展促销活动,根据历史趋势更有效地锁定特定的客户群,提高转化率和采用率,等等。

对话式人工智能源于自然语言处理…

自然语言处理(NLP)是人工智能的一种应用,它使计算机能够处理和理解人类语言。机器学习的最新进展,更具体地说,它的子集深度学习,使计算机更好地理解自然语言成为可能。这些深度学习模型可以分析大量文本,并提供文本摘要、语言翻译、上下文建模和情感分析等功能。

自然语言理解(NLU)是将自然语言转换成结构化数据的自然语言处理的一个子集。NLU 能够做两件事——意图分类和实体提取。

当我们阅读一个句子时,我们会立即理解该句子背后的含义或意图。意图是用户试图传达或实现的东西。意图分类是一个两步过程。首先,我们向 NLU 模型输入带标签的数据,这些数据提供了已知意图的列表以及与这些意图相对应的例句。一旦经过训练,该模型能够将它看到的新句子分类为预定义的意图之一。实体抽取是识别给定文本中关键信息的过程。时间、地点和人名等都提供了与意图相关的附加上下文和信息。意图分类和实体提取是对话式人工智能的主要驱动因素。

出于本文的目的,我们将使用 Rasa,这是一个开源堆栈,提供了构建上下文 AI 助手的工具。Rasa 堆栈中有两个主要组件将帮助我们构建旅行助手——Rasa NLU 和 Rasa core。

Rasa NLU 提供意图分类和实体提取服务。Rasa 核心是堆栈的主要框架,提供由机器学习支持的对话或对话管理。假设已经训练了 NLU 和核心组件,让我们看看 Rasa 堆栈是如何工作的。

让我们用这个对话的例子:

NLU 组件标识用户打算参与基于假期的旅行(意图分类),并且他或她是唯一一个进行此旅行的人(实体提取)。

核心组件负责控制对话流。基于来自 NLU 的输入、对话的当前状态及其训练的模型,核心组件决定下一个最佳的动作过程,该动作过程可以是向用户发送回复或者采取动作。Rasa 基于 ML 的对话管理是上下文感知的,不依赖于硬编码规则来处理对话。

安装和设置

现在,让我们安装 Rasa,并开始为我们的旅行助理创建初始训练数据集。

Rasa 有两种设置方式。您可以使用 python/pip 在本地机器上安装 Rasa 堆栈,也可以使用 docker 通过预配置的 docker 映像来设置 Rasa 堆栈。我们将使用 python 和 pip 安装 Rasa 堆栈。

如果您的机器上没有安装 python,您可以使用 Anaconda 来设置它。请注意,您需要 python 3.6.x 版本来运行 Rasa 堆栈。python 的最新版本(本文发布时是 3.7.x)并不完全兼容。

运行以下命令安装 Rasa 核心:

pip install -U rasa_core

通过运行以下命令安装 Rasa NLU:

pip install rasa_nlu[tensorflow]

现在让我们通过克隆 Rasa 提供的启动包来实现我们的应用程序:

git clone [https://github.com/RasaHQ/starter-pack-rasa-stack.git](https://github.com/RasaHQ/starter-pack-rasa-stack.git) travel-bot

克隆完成后,运行这些命令来安装实体提取所需的包和 spaCy 英语语言模型。

pip install -r requirements.txt \
  && python -m spacy download en

在这一点上,我们有一切我们需要开始发展我们的旅行助理。让我们看看在搭建过程中创建的文件夹结构和文件。

“domain.yml”文件描述了旅行助手的域。它指定了助手理解和操作的意图、实体、插槽和响应模板的列表。让我们更新文件,添加一组与我们的旅游领域相对应的初始意图。这里有一个片段:

intents:
  - greet
  - request_vacation
  - affirm
  - inform
...entities:
  - location
  - people
  - startdate
  - enddate
...slots:
  people:
    type: unfeaturized
  location:
    type: unfeaturized
...actions:
  - utter_greet
  - utter_ask_who
  - utter_ask_where
  - utter_confirm_booking
...templates:
  utter_ask_who:
    - text: "Fun! Let's do it. Who's going?"
  utter_ask_where:
    - text: "Perfect. Where would you like to go?"
...

“data/nlu_data.md”文件用一组例子描述了每一个意图,然后将这些例子提供给 nlu 拉萨进行培训。这里有一个片段:

## intent:request_vacation
- I want to go on vacation
- I want to book a trip
- Help me plan my vacation
- Can you book a trip for me?
...## intent:inform
- just me
- we're [2](people)
- anywhere in the [amazon](location)
- [Paris](location)
- somewhere [warm](weather_attribute)
- somewhere [tropical](weather_attribute)
- going by myself
...

“data/stories.md”文件为 Rasa 提供了用户和旅行助手之间的示例对话,可以用来训练其对话管理模型。这里有一个片段:

## vacation happy path 1
* request_vacation
    - utter_ask_who
* inform{"people": "1"}
    - utter_ask_where
* inform{"location": "paris"}
    - utter_ask_duration
* inform{"startdate": "2019-10-03T00:00:00", "enddate": "2019-10-13T00:00:00"}
    - utter_confirm_booking
* affirm
    - goodbye
...

Rasa 在配置 NLU 和核心组件方面提供了很大的灵活性。现在,我们将为 nlu 使用默认的“nlu_config.yml ”,为核心模型使用“policies.yml”。

运行以下命令来训练拉莎·NLU:

make train-nlu

运行以下命令来训练 Rasa 核心:

make train-core

我们现在可以通过命令行运行服务器来测试 Rasa:

make cmdline

Rasa stack 提供挂钩,将我们的助手连接到各种前端通道,如 Slack 和脸书。让我们将我们的旅行助手配置和部署到 Slack。

配置时差

让我们从在 slack 中创建一个新应用开始

  • 在功能下,进入“OAuth & Permissions”,添加权限范围,如“chat:write:bot ”,并保存您的更改
  • 转到“机器人用户”,添加一个机器人用户并保存您的更改
  • 返回“OAuth & Permissions”并将应用程序安装到您的工作区
  • 将“Bot 用户 OAuth 访问令牌”复制到您的工作区的令牌下
  • 回到本地机器上的“travel-bot”文件夹,创建一个新的“credentials.yml”文件。将令牌粘贴到文件中,如下所示:
slack:
  slack_token: "xoxb-XXXXXXXXXXX"

我们需要把这些凭证交给 Rasa。为了让我们的生活更轻松,让我们更新“travel-bot”文件夹下的“Makefile ”,添加一个名为“start”的新命令

...
start:
    python -m rasa_core.run \
    --enable_api \
    -d models/current/dialogue \
    -u models/current/nlu \
    -c rest --cors "*" \
    --endpoints endpoints.yml \
    --credentials credentials.yml \
    --connector slack

警告:根据您的要求,在将您的 bot 部署到生产环境之前更新“cors”设置。

让我们通过调用以下命令来启动服务器:

make start

我们的旅行助手现在运行在本地端口 5005 上,它被配置为通过 REST APIs 与 slack 对话。我们需要使这些端点对外部世界可达。让我们使用 ngrok 让我们的服务器对 Slack 可用。Ngrok 有助于建立一个到我们本地服务器的安全通道,以便快速开发和测试。安装 ngrok 后,在新的命令行终端中运行以下命令:

ngrok http 5005

记下 ngrok 提供的“https”URL。回到 Slack 应用程序管理用户界面:

  • 启用“事件订阅”。在“请求 URL”文本框中,粘贴您的 ngrok URL 并将“/webhooks/slack/webhook”添加到该 URL 的末尾。通过订阅类似“message.im”的 bot 事件来完成事件订阅,并保存您的更改
  • 或者,启用“交互式组件”并传递您在上一步中使用的相同请求 URL。请务必保存您的更改

至此,我们已经完全配置好了我们的 bot 助手来与 Slack 交互。为了测试旅行助手,放松你新创建的旅行机器人。

下一步是什么?

在本系列的下一部分中,我们将深入研究我们的 NLU 管道、自定义组件,如 Google 的 BERT 和递归嵌入对话策略(REDP),以及上下文、注意力和非线性对话等概念。

对话式人工智能:设计和构建上下文助手——第 2 部分

原文:https://towardsdatascience.com/conversational-ai-design-build-a-contextual-assistant-part-2-80ec342e86ac?source=collection_archive---------15-----------------------

Photo by Alex Knight on Unsplash

在本系列的第一部分中,我们介绍了对话式人工智能的不同成熟度,并开始使用 Rasa 构建一个旅行助手。在这篇文章中,我们将看看如何构建快乐和不快乐的对话路径,各种机器学习策略和配置来改善你的对话模型,并使用基于迁移学习的语言模型来生成自然对话。

Rasa 最近发布了 1.0 版本,其中他们将核心和 NLU 合并成一个包。在本文中,我们将使用 Rasa 1.0。

你能做什么,库珀?

因为这个助手的主要目的,让我们把它命名为 Coop,是为了预订很棒的假期,Coop 需要来自用户的关键信息来这样做。出于本文的目的,让我们假设 Coop 只需要人数、度假目的地以及所述假期的开始和结束日期。在下一次迭代中,我们希望从用户那里提取更多的信息,包括他们的兴趣、预算、年龄、行程限制,以及我们为他们创造有计划的旅行体验所需的任何其他信息。有了这些初步的知识,让我们看看如何让 Coop 通过与用户的自然对话来收集这些信息。

用槽保存信息

Rasa 使用插槽来保存用户提供的信息以及其他信息。插槽,本质上是键值对,可以用来影响与用户的对话。可以通过多种方式设置插槽的值——通过 NLU、互动卡和动作。Rasa 将此定义为槽填充。插槽在“domain.yml”文件中定义。每个插槽都有一个名称、类型和一个可选的初始值。下面是 Coop 的 domain.yml 文件的一个片段:

...
slots:
  enddate:
    type: unfeaturized
  location:
    type: unfeaturized
  num_people:
    type: unfeaturized
  startdate:
    type: unfeaturized
...

注意,我们将每个槽的类型设置为“未授权”,因为我们不希望槽值影响我们的对话流。

用表单填充插槽

为了代表用户执行操作,就像我们试图用 Coop 做的那样,我们需要填充多个连续的槽或关键信息。我们可以使用 FormAction。FormAction 本质上是一个 python 类。它获取需要填充的空位或需要回答的问题的列表,并向用户询问所述信息以填充每个空位。请注意,FormAction 只要求用户提供填充尚未设置的槽的信息。

让我们来看看快乐之路。一条愉快的道路是,上下文助手能够从用户那里不受干扰地收集它需要的信息。换句话说,用户回答问题时不会偏离他们的路径,如下所示。

a happy path

为了启用 FormAction 机制,您需要将“FormPolicy”添加到通常名为“config.yml”的配置文件中:

...
policies:
  - name: FormPolicy
...

接下来,让我们定义我们的自定义表单类:

class BookingForm(FormAction):
    def name(self):
        # type: () -> Text
        """Unique identifier of the form"""
        return "booking_form" @staticmethod
    def required_slots(tracker: Tracker) -> List[Text]:
        """A list of required slots that the form has to fill""" return ["num_people", "location", "startdate", "enddate"] def submit(self,
               dispatcher: CollectingDispatcher,
               tracker: Tracker,
               domain: Dict[Text, Any]) -> List[Dict]:
        """Define what the form has to do
            after all required slots are filled""" dispatcher.utter_template('utter_send_email', tracker)
        return []

从上面的代码片段可以看出,我们的自定义表单类应该定义三个方法——name、required_slots 和 submit。这些方法是不言自明的。

现在让我们告诉我们的模型调用预订表单动作。打开 stories.md 文件,添加一个或多个快乐之路故事:

...
* request_vacation
    - booking_form
    - form{"name": "booking_form"}
    - form{"name": null}
...

插槽和实体,最好的关系类型

我们在 Coop 中定义了几个有趣的插槽。“位置”槽用于保存关于用户度假目的地的信息。我们还定义了一个同名的实体。当 Rasa NLU 识别用户消息中的“位置”实体时,它将填充“位置”槽。为了让它能够这样做,我们需要训练 NLU 提取位置实体。虽然这非常令人兴奋,但训练 NLU 模型来识别通用实体(如位置)是一个耗时的过程,需要大量数据。这就是 Rasa NLU 管道的开箱即用“SpacyEntityExtractor”组件拯救我们的地方。这个预先训练的组件是一个命名实体识别器,它识别各种常见的实体(称为维度),如个人、组织、城市和州。

让我们来看看如何将这个组件挂接到我们的位置槽中。我们首先向 NLU 管道添加“SpacyEntityExtractor”组件。编辑“config.yml”文件。

language: en
pipeline:
...
- name: "SpacyEntityExtractor"
  dimensions: ["GPE", "LOC"]

Rasa 在 FormAction 类中提供了一个名为“slot_mappings”的方法,可用于进一步配置填充插槽的方式。在我们的例子中,我们可以使用这种方法来确保“位置”槽按以下顺序填充:

  1. 使用由我们的 NLU 模型识别的“位置”实体
  2. 如果第 1 步失败,使用由“SpacyEntityExtractor”标识的“GPE”维度
  3. 如果第 2 步失败,使用由“SpacyEntityExtractor”标识的“LOC”维度
def slot_mappings(self):
        # type: () -> Dict[Text: Union[Dict, List[Dict]]]
        """A dictionary to map required slots to
            - an extracted entity
            - intent: value pairs
            - a whole message
            or a list of them, where a first match will be picked""" return {"location": [self.from_entity(entity="location"),
                         self.from_entity(entity="GPE"),
                         self.from_entity(entity="LOC")]}

你可以在这里阅读更多关于预定义函数的信息。

Coop 域中其他有趣的槽是“startdate”和“enddate”。顾名思义,这些时间段代表用户对假期开始和结束日期的选择。我们可以使用“DucklingHTTPExtractor”组件,而不是训练我们的 NLU 模型来识别和提取这些数据,并在此过程中潜在地解决实体歧义。这个预训练组件是一个命名实体识别器,它识别各种常见的实体,如时间、距离和数字。类似于我们如何配置“SpacyEntityExtractor”,应该将“DucklingHTTPExtractor”组件添加到我们的 NLU 管道中。编辑“config.yml”文件。

language: en
pipeline:
...
- name: "DucklingHTTPExtractor"
  url: [http://localhost:8000](http://localhost:8000)
  dimensions: ["time", "number", "amount-of-money", "distance"]

从上面的配置可以看出,“DucklingHTTPExtractor”应该在指定的主机和端口上运行。你可以用 docker 来运行小鸭服务。

请注意,FormAction 类允许我们定义自定义验证,用于验证用户提供的信息。例如,我们希望确保开始日期早于结束日期。这些验证方法应该根据约定来命名。如果您有一个名为“enddate”的 slot,那么您希望定义一个名为“validate_enddate”的方法,以便 Rasa 调用它。

def validate_enddate(self,
                     value: Text,
                     dispatcher: CollectingDispatcher,
                     tracker: Tracker,
                     domain: Dict[Text, Any]) -> Optional[Text]:
    """Ensure that the start date is before the end date."""
    try:
        startdate = tracker.get_slot("startdate")
        startdate_obj = dateutil.parser.parse(startdate)
        enddate_obj = dateutil.parser.parse(value) if startdate_obj < enddate_obj:
            return value
        else:
            dispatcher.utter_template('utter_invalid_date', tracker)
            # validation failed, set slot to None
            return None
    except:
        print("log error")
        return None

write conversation that’s relaxed and informal

不愉快的道路是规则,而不是例外

格式操作对于从用户那里收集信息和代表用户执行操作非常有用。但是,正如你所知道的,用户行为是不可预测的,对话是混乱的。你可以用 30,000 种不同的方式询问天气;我最喜欢的方式之一是当人们说“今天会下倾盆大雨吗?”用户很少不离题地提供所需的信息,参与闲聊,改变主意,纠正他们的答案,问后续问题等等——如果你正在构建强大的对话式人工智能,所有这些都是有效的,预期的,需要处理的。这些偏离被称为不愉快的道路。我强烈推荐通过 CLI 使用交互式学习来训练您的模型处理不愉快的路径。

以下是在交互模式下运行 Rasa 的命令:

rasa interactive --endpoints endpoints.yml

完成后,您可以保存训练数据并重新训练您的模型。这里有一个不愉快的道路故事的例子。

* request_vacation
    - booking_form
    - form{"name": "booking_form"}
    - slot{"requested_slot": "num_people"}
...
* form: inform{"location": "paris", "GPE": "Paris"}
    - slot{"location": "paris"}
    - form: booking_form
    - slot{"location": "paris"}
    - slot{"requested_slot": "startdate"}
* correct{"num_people": "2"}
    - slot{"num_people": "2"}
    - action_correct
    - booking_form
    - slot{"requested_slot": "startdate"}
* form: inform{"time": "2019-07-04T00:00:00.000-07:00"}
...

Rasa 提供了多种策略,可用于配置和培训其核心对话管理系统。“嵌入”策略,也称为循环嵌入对话策略(REDP),可用于有效地处理不愉快的路径。此外,它还提供了可用于微调模型的超参数。你可以在这里阅读更多关于 REDP 的信息。

我对 Coop 使用了嵌入策略。

...
policies:
  - name: EmbeddingPolicy
    epochs: 2000
    attn_shift_range: 5
...

现在,让我们来看看一条涉及纠正和解释的不愉快的道路。更正是指用户对之前的回答或陈述进行修改。例如,如果他们打错了电话号码并希望更正它。当用户想知道助手的问题背后的原因时,他们会给出一个解释。

powerful conversational AI that can handle unpredictable behavior

在上面的例子中,注意 Coop 是如何引导谈话回到手边的主题的。对话模型学习处理更正,并解释为什么它需要某些信息,本质上是将用户带回到快乐的道路上。

NLG 是超级大国

自然语言处理(NLP)有两个重要领域与对话式人工智能有关。首先,有试图理解用户所说的方面;用户的意图是什么?第二,以自然和对话的方式生成和响应用户。自然语言生成(NLG)的最终目标是教会模型将结构化数据转化为自然语言,然后我们可以使用自然语言在对话中回应用户。

诚然,你可以创建人物角色,写出精彩的对话,让你的助手听起来像是在自然地交谈。但那可能需要写很多故事和规则。虽然规则是伟大的、稳定的和可预测的,但它们需要大量的工程设计,并且难以扩展和维护。他们也缺乏你在人类对话中发现的自发性和创造性。

通过用数据和它需要生成的语言的例子训练大规模无监督语言模型,该模型最终形成了自己的规则,知道它应该做什么,并有更多的自由来发挥创造力。我调整了一个现有的基于迁移学习的语言模型来生成闲聊。有了更多的例子和数据,这个模型可以生成自然语言来概括文本和回答问题,而不需要任何特定的任务训练。

NLG aka computer generated chitchat

在上面的例子中,请注意 Coop 如何在用户聊天时不断引导他们回到快乐的道路上。对话模型学会处理狭义和广义的上下文,忽略多余的信息。

但是 C 代表对话

写好对话对对话式人工智能至关重要。在你向外界发布你的语境助手之前,除了拥有高性能的 NLG 之外,你还想投资写一份清晰简洁的文案,它要有正确的语调、相关的语境方言、能引起你的观众共鸣的人物角色。良好的对话可以取悦用户,建立品牌忠诚度,并确保高用户保留率。您还想考虑为用户提供菜单按钮和快速回复来点击和触发某些事件,以尽量减少用户输入。它们是建议选项和引导用户走上快乐之路的好方法。

为对话式人工智能撰写文案是一件值得关注的事情,超出了本文的范围。点击阅读更多关于编写机器人副本的信息。Coop 目前没有太多的对话或 UI 选项,但随着我们收集真实数据,我们将尝试理解用户行为,在与真实用户交互时进一步调整我们的自定义 NLG 模型,专注于编写好的文案,并在接下来的几次迭代中不断改进。

下一步是什么

在本系列的最后一部分,我们将讨论可以用来测试和评估我们的模型的各种测试策略。我们还将讨论将 Coop 部署到生产环境中,之后我们将进行监控并不断改进。

对话情感分析

原文:https://towardsdatascience.com/conversational-sentiment-analysis-52eabd20155b?source=collection_archive---------14-----------------------

用于确定对命名实体的情感的方法

介绍

我最近制作了一个电影推荐器,它将用户写的关于喜欢和/或不喜欢的电影的文章作为输入。在这个项目开始的时候,我认为决定用户喜欢和不喜欢哪部电影很简单。毕竟,用文字来确定某人喜欢还是不喜欢一部电影,似乎并不太雄心勃勃。在 python 中,有各种各样的包可用于情感分析,因此必须有现成的东西来完成这项工作。

事实证明,使用文本来确定某人是喜欢还是不喜欢一部电影,或者任何命名的实体,是非常复杂的。这在对话环境中尤其如此,在这种环境中,结构是自由的,很少有假设可言。将对话环境与产品评论环境进行比较有助于说明这一点。

产品评论中的情感

对于产品评论,通常最重要的是对被评论产品的看法,通常产品是主要话题。因此,有可能做出一个简化的假设,即评论的总体情绪反映了评论对产品的情绪。使用这种假设,有可能在相对较少的预处理的情况下将文本输入到情感分析包中,并获得良好的结果。因此,产品评论的情感分析是一个常见的 NLP 介绍项目。

Product reviews also happen to be conveniently labeled with user assigned scores

谈话中的情感

然而,在交谈中讨论产品时,通常会对许多产品进行比较和对比。此外,一个人对每种产品的看法可能大相径庭。在交谈中,我们能够为产品评论做出的简化假设并不成立。即使将对话文本分成句子也是不够的,因为在同一个句子中提到许多产品是很常见的。以这句话为例,“我喜欢汉堡包,但讨厌泡菜。”显然,这句话的总体情绪(净中性与高极性)没有准确反映对汉堡包或泡菜的情绪。需要对语义结构进行更深入的研究,以便始终如一地正确分配情感。

经过一番搜索,我发现目前还没有可以开箱即用地进行实体级情感分析的软件包。事实上,这似乎仍然是一个活跃的研究领域。在这篇博文的其余部分,我将回顾我自己开发的一些方法来执行实体级情感分析。

密码

这篇博文的相关代码可以在我的电影推荐项目的链接的 GitHub repo 文件 entity _ perspective . py 中找到。那些希望深入研究的人可以看看 GitHub,或者克隆它供自己使用。查看我的电影推荐应用,了解这些方法的应用示例。

该代码利用了 NLTK 中的 VADER 情感分析和斯坦福依赖解析器。要使用我的代码,你需要在你的机器上安装 NLTK 和 VADER 情绪。此外,Stanford dependency parser 需要一个 Java 安装和一些模型文件,这些文件可以从这里下载。然后,必须在 entity _ impression . py 文件中提供 Java 安装和模型文件的路径。

Where paths to Java installation and Stanford Dependency Parser .jar files must be inserted

我开发的功能是为了在句子层面上分析对实体的情感。因此,使用这些功能分析文档或文档集的第一步是将每个文档分割成单独的句子。

拆分方法

在最简单的情况下,一个句子仅表达一种情感,并且该句子的整体情感反映了对任何命名实体的情感。例如,“我喜欢小猫和小狗”表达了对小猫和小狗同样积极的情感。不幸的是,大多数句子都比这复杂一点。

出于比较的目的,句子通常包括对多个命名实体的引用。在这些情况下,在比较时分割句子并在每个分割中分析情感通常足以正确地将情感分配给每个实体。这就是拆分法。回到前面的例子“我喜欢汉堡包,但讨厌泡菜”,在这里使用 split 方法将基于“我喜欢汉堡包”将情感分配给“汉堡包”,基于“讨厌泡菜”将情感分配给“泡菜”。

我编写的实现 split 方法的函数相对简单。代码执行以下步骤:1)查找句子中的比较单词,2)在这些单词处拆分句子,3)查找哪些拆分包含命名实体,然后最后 4)确定每个拆分的情感。使用函数 compile _ split _ perspective 调用 split 方法。

邻域法

将情感分配给命名实体的另一种方式是通过查看出现在附近的单词。想想这句话“我爱篮球,尽管裁判很糟糕。”对“篮球”来说,最能表达感情的词是“爱”,对“裁判”来说,最能表达感情的词是“糟糕”。

对于邻域法,我编写的函数会找到一个句子中一个实体的所有实例,然后查看出现在附近的单词,直到确定情感。传播参数控制算法搜索实体的距离,衰减参数控制对远处的单词应用多少惩罚。传播和衰减参数的微调有助于在特定环境下优化性能。函数 compile _ neighborhood _ 情操调用这个方法。

树形方法

我要讨论的最后一个方法是树方法。树方法实际上非常类似于邻域方法。不同之处在于,不是查看出现在书面句子中的命名实体附近的单词,而是创建句子的依存关系树,并且使用出现在依存关系树中的命名实体附近的单词来建立情感。

在依存关系树中,除了句子的“根”以外,句子中的每个单词都被分配一个“父”单词。父词的子词被称为“依赖于”父词。形容词通常出现在依存关系树中,靠近它们所描述的名词,通常作为直系父母或子女。为句子创建依存关系树的行为被称为“依存关系解析”。在我的代码中,我使用了斯坦福依赖解析器。

想想这句话,“与那部糟糕的电影《雷神》不同,钢铁侠是我的最爱”。分裂法和邻域法都不能正确地将正面情绪分配给“钢铁侠”。但是,看一下这句话的依存树。该树正确地显示了“钢铁侠”与“喜爱”密切相关,“雷神”与“可怕”密切相关。

与邻域法类似,我的代码使用传播和衰减参数来控制算法在树中搜索的范围。我还创建了一个 DependencyTreeDict 类,它使用依赖解析器输出将单词映射到节点、父节点和子节点。该类包含根据单词在树中的关系轻松访问单词的方法。使用函数 compile _ tree _ perspective 调用通过 tree 方法编译情感。

组装

上述每种方法通常都会返回正确的结果,但在某些情况下会失败。幸运的是,每种方法都有其独特的优点和缺点。通过将这三种方法集成为一种,有可能创建一个更加健壮的算法。这是通过取三种方法的平均结果来实现的。就像人一样,这些方法一起使用比单独使用更有效。在代码中,所有三个方法的集合都是用函数 compile _ ensemble _ sensation 创建的。

结论

具有自由形式结构的对话环境中的情感分析很难做好。通常有许多感兴趣的命名实体,了解某人对每个实体的感觉是很有趣的。我已经描述了一些可以用来给命名实体分配情感的方法。这些方法可以通过导入我的 Github 上的 entity _ opinion . py 文件在你的项目中快速实现,不需要模型训练!我希望这有所帮助,并希望听到您的反馈。

将具有多个输出的深度学习模型从 PyTorch 转换为 TensorFlow

原文:https://towardsdatascience.com/converting-a-deep-learning-model-with-multiple-outputs-from-pytorch-to-tensorflow-a2d27a8e44f4?source=collection_archive---------10-----------------------

Reference: https://i.stack.imgur.com/4YBht.jpg

简介

前段时间,我写了一篇文章,描述了如何使用 ONNX 将一个简单的深度学习模型从 PyTorch 转换为 TensorFlow。虽然这适用于许多用例,但在某些情况下,您需要转换具有多个输出的模型(例如,对象检测模型)。在这里,我将展示如何将一个具有多个输出的模型从 PyTorch 转换为 TensorFlow。

整个转换过程的许多部分重复了我在上一篇文章中提到的内容,所以我将只提到为转换一个具有多个输出的模型而添加或修改的部分。

生成和准备数据

数据的主要区别在于现在有两组不同的实际输出,一组是连续变量,另一组是二进制形式。此外,我定义了两个函数来为数据生成两种不同类型的输出。下面的代码片段说明了生成数据并为模型训练和评估做准备的过程。

定义、培训和评估示例模型

所定义的模型类与上一篇文章中的非常相似,除了 forward() 方法返回两个输出张量,而不是一个。还为输出定义了两种不同的损失对象,连续输出的均方误差损失和二进制输出的二进制交叉熵损失。下面的代码片段显示了模型、损失和优化器是如何定义的。

训练和评估过程也是类似的,除了在执行反向传播和模型权重更新之前,必须计算两个输出的损失并将其相加。下面的代码片段包含了训练和评估模型的过程。

将模型转换为张量流

将模型导出到。onnx 格式也很相似,只是应该给输出头分配不同的名称。在本例中,名称“output1”和“output2”被分配给两个输出头,如下面的代码片段所示。

在 TensorFlow 中做推理

TensorFlow 中的推理步骤也与上一篇文章类似,只是做了一些小的改动,得到了两个输出,而不是一个,如下所示。输入和输出的占位符名称可以用我在上一篇文章中提到的相同方法找到。

如果一切顺利, print('output1:',output1)print('output2:',output2) 的结果应该与前面步骤中 print('dummy_output_1:',dummy_output_1)print('dummy_output_1:',dummy_output_1) 的结果相匹配。

结论

将具有多个输出的模型从 PyTorch 转换到 TensorFlow 可能比对具有单个输出的简单模型执行相同的过程更具挑战性,但仍然可以完成。我希望这篇文章能让您对使用 ONNX 转换更复杂的模型更有信心。

包含所有代码的 Jupyter 笔记本可以在这里找到。

将简单的深度学习模型从 PyTorch 转换为 TensorFlow

原文:https://towardsdatascience.com/converting-a-simple-deep-learning-model-from-pytorch-to-tensorflow-b6b353351f5d?source=collection_archive---------3-----------------------

Reference: https://towardsdatascience.com/applied-deep-learning-part-1-artificial-neural-networks-d7834f67a4f6

简介

TensorFlow 和 PyTorch 是两个比较流行的深度学习框架。有些人更喜欢 TensorFlow 以获得部署方面的支持,有些人更喜欢 PyTorch,因为它在模型构建和培训方面具有灵活性,而没有使用 TensorFlow 所面临的困难。使用 PyTorch 的缺点是,使用该框架构建和训练的模型不能部署到生产中。(2019 年 12 月更新:据称 PyTorch 的后续版本对部署有更好的支持,但我相信这是有待探索的其他事情。)为了解决部署使用 PyTorch 构建的模型的问题,一种解决方案是使用 ONNX(开放式神经网络交换)。

正如 ONNX 的关于第页所解释的,ONNX 就像一座桥梁,将各种深度学习框架连接在一起。为此,ONNX 工具支持模型从一个框架到另一个框架的转换。到撰写本文时为止,ONNX 仅限于更简单的模型结构,但以后可能会有进一步的补充。本文将说明如何将一个简单的深度学习模型从 PyTorch 转换为 TensorFlow。

安装必要的软件包

首先,我们需要安装 PyTorch、TensorFlow、ONNX 和 ONNX-TF(将 ONNX 模型转换为 TensorFlow 的包)。如果在 Linux 中使用 virtualenv ,你可以运行下面的命令(如果你安装了 NVidia CUDA,用 tensorflow-gpu 替换 tensorflow )。请注意,截至 2019 年 12 月,ONNX 尚不支持 TensorFlow 2.0,因此请注意您安装的 TensorFlow 版本。

source <your virtual environment>/bin/activate
pip install tensorflow==1.15.0# For PyTorch, choose one of the following (refer to [https://pytorch.org/get-started/locally/](https://pytorch.org/get-started/locally/) for further details)
pip install torch torchvision # if using CUDA 10.1
pip install torch==1.3.1+cu92 torchvision==0.4.2+cu92 -f [https://download.pytorch.org/whl/torch_stable.html](https://download.pytorch.org/whl/torch_stable.html) # if using CUDA 9.2
pip install torch==1.3.1+cpu torchvision==0.4.2+cpu -f [https://download.pytorch.org/whl/torch_stable.html](https://download.pytorch.org/whl/torch_stable.html) # if using CPU onlypip install onnx# For onnx-tensorflow, you may want to refer to the installation guide here: [https://github.com/onnx/onnx-tensorflow](https://github.com/onnx/onnx-tensorflow)
git clone [https://github.com/onnx/onnx-tensorflow.git](https://github.com/onnx/onnx-tensorflow.git)
cd onnx-tensorflow
pip install -e ..

如果使用 Conda,您可能希望改为运行以下命令:

conda activte <your virtual environment>
conda install -c pytorch pytorchpip install tensorflow==1.15.0pip install onnx# For onnx-tensorflow, you may want to refer to the installation guide here: [https://github.com/onnx/onnx-tensorflow](https://github.com/onnx/onnx-tensorflow)
git clone [https://github.com/onnx/onnx-tensorflow.git](https://github.com/onnx/onnx-tensorflow.git)
cd onnx-tensorflow
pip install -e ..

我发现使用 pip 安装 TensorFlow、ONNX 和 ONNX-TF 将确保这些包相互兼容。但是,也可以使用其他方式安装软件包,只要它们能在您的机器上正常工作。

要测试软件包是否已正确安装,可以运行以下命令:

python
import tensorflow as tf
import torch
import onnx
from onnx_tf.backend import prepare

如果您没有看到任何错误消息,这意味着软件包安装正确,我们可以开始了。

在这个例子中,我使用了 Jupyter Notebook,但是转换也可以在. py 文件中完成。要安装 Jupyter Notebook,您可以运行以下命令之一:

# Installing Jupyter Notebook via pip
pip install notebook# Installing Jupyter Notebook via Conda
conda install notebook

构建、培训和评估示例模型

接下来要做的是在 PyTorch 中获得一个可用于转换的模型。在这个例子中,我生成了一些模拟数据,并使用这些数据来训练和评估一个简单的多层感知器(MLP)模型。下面的代码片段展示了如何导入已安装的包,以及如何生成和准备数据。

然后,我为简单的 MLP 模型创建了一个类,并定义了层,这样我们就可以指定任意数量和大小的隐藏层。我还定义了一个二进制交叉熵损失和 Adam 优化器,用于计算训练期间的损失和权重更新。下面的代码片段展示了这个过程。

在构建模型并定义损失和优化器之后,我使用生成的训练集对模型进行了 20 个时期的训练,然后使用测试集进行评估。模型的测试损失和准确性不好,但这在这里并不重要,因为这里的主要目的是展示如何将 PyTorch 模型转换为 TensorFlow。下面的片段显示了培训和评估过程。

在训练和评估模型之后,我们需要保存模型,如下所示:

将模型转换为张量流

现在,我们需要转换。pt 文件到了一个。onnx 文件使用 torch.onnx.export 函数。这里我们需要注意两件事:1)我们需要定义一个虚拟输入作为导出函数的输入之一,2)虚拟输入需要具有形状(1,单个输入的维度)。例如,如果单个输入是具有形状(通道数、高度、宽度)的图像数组,那么伪输入需要具有形状(1,通道数、高度、宽度)。需要虚拟输入作为所得张量流模型的输入占位符)。下面的代码片段显示了以 ONNX 格式导出 PyTorch 模型的过程。我还将输入和输出名称作为参数,以便在 TensorFlow 中更容易进行推理。

拿到后。onnx 文件,我们需要使用 onnx-TF 的后端模块中的 prepare() 函数将模型从 ONNX 转换为 TensorFlow。

在 TensorFlow 中做推理

有趣的部分来了,这是为了看看合成的张量流模型是否能按预期进行推理。从加载张量流模型。pb 文件可以通过定义以下函数来完成。

定义了加载模型的函数后,我们需要启动一个 TensorFlow graph 会话,为输入和输出指定占位符,并将输入输入到会话中。

上面代码片段的输出如下所示。占位符的名称对应于在torch.onnx.export功能中指定的名称(用粗体表示)。

(<tf.Tensor 'Const:0' shape=(50,) dtype=float32>,)
(<tf.Tensor 'Const_1:0' shape=(50, 20) dtype=float32>,)
(<tf.Tensor 'Const_2:0' shape=(50,) dtype=float32>,)
(<tf.Tensor 'Const_3:0' shape=(50, 50) dtype=float32>,)
(<tf.Tensor 'Const_4:0' shape=(1,) dtype=float32>,)
(<tf.Tensor 'Const_5:0' shape=(1, 50) dtype=float32>,)
(**<tf.Tensor 'input:0' shape=(1, 20) dtype=float32>,)**
(<tf.Tensor 'flatten/Reshape/shape:0' shape=(2,) dtype=int32>,)
(<tf.Tensor 'flatten/Reshape:0' shape=(1, 20) dtype=float32>,)
(<tf.Tensor 'transpose/perm:0' shape=(2,) dtype=int32>,)
(<tf.Tensor 'transpose:0' shape=(20, 50) dtype=float32>,)
(<tf.Tensor 'MatMul:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'mul/x:0' shape=() dtype=float32>,)
(<tf.Tensor 'mul:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'mul_1/x:0' shape=() dtype=float32>,)
(<tf.Tensor 'mul_1:0' shape=(50,) dtype=float32>,)
(<tf.Tensor 'add:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'Relu:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'flatten_1/Reshape/shape:0' shape=(2,) dtype=int32>,)
(<tf.Tensor 'flatten_1/Reshape:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'transpose_1/perm:0' shape=(2,) dtype=int32>,)
(<tf.Tensor 'transpose_1:0' shape=(50, 50) dtype=float32>,)
(<tf.Tensor 'MatMul_1:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'mul_2/x:0' shape=() dtype=float32>,)
(<tf.Tensor 'mul_2:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'mul_3/x:0' shape=() dtype=float32>,)
(<tf.Tensor 'mul_3:0' shape=(50,) dtype=float32>,)
(<tf.Tensor 'add_1:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'Relu_1:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'flatten_2/Reshape/shape:0' shape=(2,) dtype=int32>,)
(<tf.Tensor 'flatten_2/Reshape:0' shape=(1, 50) dtype=float32>,)
(<tf.Tensor 'transpose_2/perm:0' shape=(2,) dtype=int32>,)
(<tf.Tensor 'transpose_2:0' shape=(50, 1) dtype=float32>,)
(<tf.Tensor 'MatMul_2:0' shape=(1, 1) dtype=float32>,)
(<tf.Tensor 'mul_4/x:0' shape=() dtype=float32>,)
(<tf.Tensor 'mul_4:0' shape=(1, 1) dtype=float32>,)
(<tf.Tensor 'mul_5/x:0' shape=() dtype=float32>,)
(<tf.Tensor 'mul_5:0' shape=(1,) dtype=float32>,)
(<tf.Tensor 'add_2:0' shape=(1, 1) dtype=float32>,)
**(<tf.Tensor 'output:0' shape=(1, 1) dtype=float32>,)**

如果一切顺利, print(output) 的结果应该与前面步骤中的 print(dummy_output) 的结果相匹配。

结论

ONNX 可以非常简单,只要你的模型不太复杂。这个例子中的步骤将对具有单个输入和输出的深度学习模型起作用。对于具有多个输入和/或输出的模型,通过 ONNX 进行转换更具挑战性。因此,转换多个输入/输出模型的示例必须在另一篇文章中完成,除非以后有新版本的 ONNX 可以处理这样的模型。

包含所有代码的 Jupyter 笔记本可以在这里找到。

将 D3.js 转换为 PDF 到 PowerPoint

原文:https://towardsdatascience.com/converting-d3-js-to-pdf-to-powerpoint-e98b15938bca?source=collection_archive---------16-----------------------

在商业报告中使用 D3.js 可视化的简单方法

在 D3.js 中创建了一个漂亮的可视化之后,我经常从我的营销同事那里收到同样的问题:你能给我发一份这个的幻灯片吗?。我通常解释说,这是一个程序化的图表,类似于一个网站,不幸的是,它不可能放在 PowerPoint 幻灯片上。到目前为止,我最好的建议是使用微软的 snipping 工具。但是我最近发现了一个非常有效的解决方案。

所以在我们开始之前,我们当然需要一个 D3.js 可视化。为此我制作了一张旭日图,展示了 2018 年蒙德勒兹年度净收入。这是一个非常有趣的图表。正如我们所见,他们 43.1%的净收入来自奥利奥等饼干。仅北美就占了这些销售额的 50%。那真的有很多饼干。

所以让我们把这种形象化的东西转化成我们可以在 PowerPoint 幻灯片中使用的东西。我们要做的第一件事是将带有 D3.js 可视化的 html 文件转换成 PDF。为此,我们只需要 PhantomJS ,一点 JavaScript 和一行批处理文件。这只需要三分钟。首先,我们下载 PhantomJS 并将 ZIP 文件解压到我们喜欢的文件夹中,例如 C:/PhantomJS/ 。无需安装。其次,我们下载 rasterize.js 脚本,放入我们的sunburst.html文件所在的文件夹。现在,我们打开编辑器并键入

C:/PhantomJS/bin/phantomjs rasterize.js sunburst.html sunburst.pdf

我们将这个文件保存为批处理文件,例如 convert.bat 。当运行批处理文件时,我们可以看到一个名为sunburst.pdf的新文件会在我们的文件夹中弹出。我们可能想在 rasterize.js 脚本的最开始微调页面宽度和高度以及页边距。对于我们的旭日图,我们选择了:

这已经很方便了。我们的同事已经可以用 PDF 比依赖于几个 JavaScript 包和 JSON 文件的 HTML 文件做更多的事情。

下一步是将我们新生成的 PDF 文件转换成可以在 PowerPoint 中使用的文件。记住,这里的关键词当然是无损。我们希望有清晰的形状和文本,否则我们可能会坚持使用剪切工具。对于下一步,我们想使用 Inkscape 。安装完成后,我们只需编辑之前的批处理文件并添加以下行:

"C:/.../Inkscape/inkscape" -f=sunburst.pdf --export-emf=sunburst.emf

只要我们现在运行批处理文件,我们的 PDF 就会被转换成 EMF 文件。EMF 是 PowerPoint 的原生矢量格式,其作用方式类似于 SVG 文件。这意味着我们现在可以打开我们的 PowerPoint 演示文稿,并将这个新生成的 EMF 作为图片插入。形状和文本是清晰的,我们甚至可以取消可视化分组和修改单个组件。

我相信你的同事会喜欢这个的!

从喀拉斯转化为 PyTorch 闪电

原文:https://towardsdatascience.com/converting-from-keras-to-pytorch-lightning-be40326d7b7d?source=collection_archive---------6-----------------------

Photo By: Nicole Crank

在本教程中,我们将把一个 Keras 模型转换成一个 PyTorch Lightning 模型,为你的深度学习忍者技能增加另一项能力。

Keras 为 Tensorflow 提供了一个极好的高级接口。现在,Keras 用户可以通过一个类似的名为 PyTorch Lightning 的高级界面试用 PyTorch。

然而,Lightning 与 Keras 的不同之处在于,与其说它是一个框架,不如说它是 PyTorch 的风格指南,它为用户(研究人员、学生、制作团队)提供了尝试疯狂想法的终极灵活性,而不必学习另一个框架,同时自动化掉所有的工程细节。

Lightning 与 Keras 的不同之处在于:

  1. 它不是一个框架,更像是一个风格指南。
  2. Lightning 没有隐藏网络和优化设计的细节。
  3. Lightning 自动化了所有工程,如提前停止、多 GPU 训练、多节点训练等…
  4. Lightning 为研究人员和生产团队提供了极大的灵活性,他们可能需要跨多个 GPU 进行负采样或建立自己的分布式环境。

为什么要学 PyTorch 闪电?

根据您团队的需求,能够同时使用 Tensorflow 和 PyTorch 是非常有用的。Lightning 的用户喜欢这个框架的灵活性。他们可以让事情变得非常简单,或者将训练行为修改为如何完成后退的步骤。

这种简单性和最大复杂性的平衡(对于那些需要它的人来说)使得 Lightning 成为一个独特的框架,使得用 PyTorch 进行生产和原型设计变得非常容易。

事实上,它甚至使深度学习研究更具可重复性(查看 NeurIPS 可重复性挑战)!

你好,在喀拉斯的 MNIST

要了解如何转换项目的核心,让我们看看典型的 MNIST·克雷斯的例子。

Source: Keras documentation

这段代码可以分成几个部分。

第一节:进口

第二部分:数据加载

第 3 节:模型定义

第四节: 培训

第 5 节:测试

上面的每个部分都有一个 PyTorch 闪电的等价物。但是在 Lightning 中,代码是在一个特定的接口中构建的,其中每个函数负责上面的一个部分。

照明模块

每一个研究想法都在不同的照明模块中实现。这是与 LightningModule 相同的 Keras 示例。

[## Lightning module-py torch-Lightning 0 . 6 . 0 文档

LightningModule 是 torch.nn.Module 的严格超类,但它提供了一个接口来标准化“成分”…

py torch-lightning . readthedocs . io](https://pytorch-lightning.readthedocs.io/en/0.6.0/lightning-module.html)

虽然表面上看起来更冗长,但是增加的行让您可以更深入地控制正在发生的事情。请注意以下事项:

  1. 通过 PyTorch 的美丽,现在你可以在前进的步骤中调试模型的流程。

事实上,您甚至可以通过改变调试器中的输入来尝试在实时中进行实验。在这种情况下,我们只想看看第二层之后的维度会发生什么,所以在调试器中,我们提供了一个张量,其中包含我们想要测试的维度。

2.训练步骤、验证步骤和测试步骤中发生的事情是分离的。例如,我们可以计算验证步骤的准确性,但不能计算训练步骤的准确性。

如果我们在做机器翻译之类的事情,我们可以在验证步骤中进行波束搜索来生成样本。

3.数据加载被很好地抽象在数据加载器之后。

4.代码是标准的!如果一个项目使用了 Lightning,您可以通过查看任何项目的培训步骤来了解正在发生的事情的核心!这是朝着帮助实现更多可复制的深度学习代码迈出的令人难以置信的一步。

5.这个代码是纯 PyTorch!上面没有抽象…这意味着你可以随心所欲地编写代码。

总之,LightningModule 集合了我们构建深度学习系统所需的核心成分:

  1. 计算(初始化,向前)。
  2. 训练循环(training_step)中会发生什么。
  3. 验证循环中发生了什么(validation_step)。
  4. 测试循环中发生了什么(test_step)。
  5. 要使用的优化器(configure _ optimizers)。
  6. 要使用的数据(训练、测试、评估数据加载器)。

运动鞋

请注意,LightningModule 没有任何关于 GPU 或 16 位精度或早期停止或日志记录或任何类似的东西…所有这些都是由培训师自动处理的。

这就是训练这个模型的全部!培训师为您处理所有事情,包括:

  1. 提前停止
  2. 自动记录到 tensorboard(或 comet、mlflow 等)
  3. 自动检查点

如果你照原样运行训练器,你会注意到一个名为 lightning_logs 的文件夹,你可以从中运行一个 tensorboard 会话:)

tensorboard — logdir=./lightning_logs

所有这些都是免费的!

事实上,Lightning 添加了一个漂亮的文本窗口,向您显示在这个特定的实验中使用了哪些参数。只要将 hparams 参数传递给 LightningModule,您就可以免费获得它。

现在,模型的每次运行都确切地知道它使用了什么超参数!

GPU 培训

闪电让 GPU 和多 GPU 训练变得琐碎。例如,如果您想在多个 GPU 上训练上述示例,只需向训练器添加以下标志:

使用上述标志将在 4 个 GPU 上运行该模型。

如果您想在 16 个 GPU 上运行,其中有 4 台机器,每台机器有 4 个 GPU,请将教练标志更改为:

并提交以下 SLURM 作业:

高级用途

对于学生,以及对深度学习有所了解的人来说,Lightning 非常容易使用。然而,对于高级用户,如研究人员和生产团队,Lightning 给你更多的控制。

例如,您可以这样做:

  1. 渐变裁剪
Trainer(gradient_clip_val=2.0)

2.累积梯度

Trainer(accumulate_grad_batches=12)

3.16 位精度

Trainer(use_amp=True)

4.截断反向传播通过时间

Trainer(truncated_bptt_steps=3)

还有关于 42 更高级的特性 …

高级使用++语言

但是也许你需要更多的灵活性。在这种情况下,您可以这样做:

  1. 改变后退步骤的完成方式。
  2. 改变 16 位的初始化方式。
  3. 添加您自己的分布式培训方式。
  4. 添加学习率调度器。
  5. 使用多个优化器。
  6. 更改优化器更新的频率。

还有很多很多东西。在引擎盖下,Lightning 中的所有东西都被实现为可以被用户覆盖的钩子。这使得培训的每个方面都具有高度的可配置性——这正是研究或生产团队需要的灵活性。

摘要

本教程解释了如何将 Keras 模型转换为 PyTorch Lightning,以供想要尝试 PyTorch 或寻求更大灵活性的用户使用。

闪电的关键在于:

  1. 对于 PyTorch 来说,它不是一个框架,而更像是一个风格指南。这是因为闪电暴露了核心 PyTorch,而不是将其抽象掉。
  2. 通过使用 Lightning 格式,您可以消除工程上的复杂性,并使您的代码具有可复制性。
  3. 对于新用户来说,Lightning 可能非常简单,但对于即使是最高级的研究团队来说,它也非常灵活。
  4. 虽然我们展示了一个 MNIST 的例子,但是 Lightning 可以实现任意复杂的方法。看看这个可乐罐!

使用 xmltree 将多层 xml 文件转换为 python 中的数据帧

原文:https://towardsdatascience.com/converting-multi-layered-xml-files-to-dataframes-in-python-using-xmltree-a13f9b043b48?source=collection_archive---------2-----------------------

Relativity by MC Esher ( 2015 The M.C. Esher Company- Baarn, Netherlands)

我发现使用任何有效的编程语言的最大优点之一是,这种语言有助于将抽象的数据结构分解成简单的数据点,程序员可以将这些数据点转换成任何方便的结构。数据结构仅仅是一种形式,它表现了一种不变的本质的可能排列。因此,当您作为程序员查看 excel 文件时,您会意识到 excel 仅仅是数据的“形式”,它呈现了数据“本质”的一种可能结构,而数据“本质”仅仅是点。

允许大型数据集以多层格式呈现的数据结构之一是可扩展标记语言,或者更通俗地称为 XML。本质上,xml 是一种标记语言,使数据对人和机器都可读。不用说,这带来了巨大的优势。这也允许在一个数据集内嵌套变量,即以层的形式呈现数据。例如,一个 xml 文档看起来像下面这样,

#A sample xml file <?xml version="1.0" encoding="UTF-8"?><scenario><world><region name="USA"><AgSupplySector name="Corn"><AgSupplySubsector name="Corn_NelsonR"><AgProductionTechnology name="Corn_NelsonR_IRR_hi"><period year="2015"><agProdChange>0.0043</agProdChange></period></AgProductionTechnology>
</AgSupplySubsector>
</AgSupplySector>
</region>
</world>
</scenario>

因此,您可以看到数据的各种属性以层的形式呈现。然而,使这些数据可读可能是一个挑战,尤其是在处理巨大的 xml 文件时。

问题- 在本文中,我展示了一个易于修改的 python 脚本,它解析一个包含 6 层的 xml,并在一个简单的数据帧中呈现数据,非常适合分析。本例中使用的 xml 文件是一个数据集,按国家、 、作物、流域、技术、年份和气体类型 显示温室气体排放量。在这个例子中,我使用了 python 中的 xmltree 包。样本数据集“ag_prodchange_ref_IRR_MGMT.xml”是 GCAM 模型数据系统的一部分,可在此处访问。该文件包含 31 个地区、大约 2000 个盆地、12 种作物类型和 15 种气体类型的数据。

我们希望将 xml 文件转换成如下所示的简单格式,

因此,解决这个问题最简单的方法是考虑编写一个分层的 for 循环来解析 XML 以接收输出,然后在 for 循环的最后一部分将数据转储到 dataframe 中。那么,我们开始吧。

首先,让我们导入包并使用 xmltree 读入数据。我们也将需要熊猫,因为我们将与数据帧。您将看到,我们最初在 xml 树中使用 parse 函数解析 xml 对象,然后将整个树转储到一个名为 root 的变量中。

**import** xml.etree.cElementTree **as** et
**import** pandas **as** pdtree=et.parse(**'all_aglu_emissions.xml'**)
root=tree.getroot()

现在,让我们为我们的层创建一些空列表。如上所述,有 6 层需要考虑,因此我们将创建对应于每层的空列表。

Year=[]
Gas=[]
Value=[]
Technology=[]
Crop=[]
Country=[]

让 for 循环开始!可以把它想象成一棵决策树,在这里你想要得到一个特定的值。所以,你要在特定地区、特定供应部门、特定技术类型、特定年份的天然气中寻找特定价值。下图描述了 for 循环。

A simple visual representation of the for loop we will write out in the code.

xml 树方便地允许用户通过迭代来解析元素。现在,具有挑战性的部分是创建一个内部存储器,以便 loop 记住每个部分的内容。否则,我们可能会陷入阿里阿德涅在《盗梦空间》中生动描述的境地,

等等,我们到底要进入谁的潜意识呢

Much like this scene in inception the for loop can mess up the files python remembers at each step

因此,在循环的每个阶段,我们都希望将迭代保存到一个变量中,这个变量将成为下一阶段循环的基础。我们的第一阶段是“区域”。我们将把这个阶段的结果保存到一个名为“根 1”的变量中。然后,我们将在第二阶段迭代这个新变量,并将结果保存到另一个名为“root 2”的临时变量中。因此,前两个级别的代码如下所示,

**for** reg **in** root.iter(**'region'**):
    root1=et.Element(**'root'**)
    root1=reg
    **for** supply **in** root1.iter(**'AgSupplySector'**):
        root2=et.Element(**'root'**)
        root2=(supply)

注意 et。元素(' root ')创建一个空的 xml 对象来存储我们的结果。另外,注意你声明的 for 变量很重要,所以记住上面的' x '和' reg'。我们稍后将需要它们来提取我们的属性。所以,把这个结构再扩展 4 个层次,

**for** x **in** root.iter(**'region'**):
    root1=et.Element(**'root'**)
    root1=x
    **for** supply **in** root1.iter(**'AgSupplySector'**):
        root2=et.Element(**'root'**)
        print(supply)
        root2=(supply)
        **for** tech **in** root2.iter(**'AgProductionTechnology'**):
            root3 = et.Element(**'root'**)
            root3=(tech)
            **for** yr **in** root3.iter(**'period'**):
                root4 = et.Element(**'root'**)
                root4=yr
                **for** gas **in** root4.iter(**'Non-CO2'**):
                    root5 = et.Element(**'root'**)
                    root5=gas

现在,对于最后一个级别,我们希望将实际值存储在 xml 文件中。这些可以在 xmltree 中使用提取特定属性的“attrib”函数提取。所以,回到我们的 xml 结构,每一层都包含特定的属性。例如,在下面的行中,区域部分包含一个名为“name”的属性,该属性被设置为 USA。

<region name="USA">

因此,为了提取名称,我们将编写以下代码行,

reg.attrib['name']

因此,按照这个逻辑,让我们从上面提取所有属性,并将它们分配给我们在第一步中生成的空列表。所以,代码变成了,

Technology.append(tech.attrib[**'name'**])
Value.append(em.text)
Gas.append(gas.attrib[**'name'**])
Year.append(yr.attrib[**'year'**])
Crop.append(supply.attrib[**'name'**])
Country.append(x.attrib[**'name'**])

请注意,该值不像其他列表那样具有属性函数。我们直接调用了一个名为‘text’的对象。这是因为该值存储在没有特定属性的图层中。所以我们可以直接访问对象。

<input-emissions>0.0043</input-emissions>

所以,我们上面的代码就变成了,

**for** x **in** root.iter(**'region'**):
    root1=et.Element(**'root'**)
    root1=x
    **for** supply **in** root1.iter(**'AgSupplySector'**):
        root2=et.Element(**'root'**)
        print(supply)
        root2=(supply)
        **for** tech **in** root2.iter(**'AgProductionTechnology'**):
            root3 = et.Element(**'root'**)
            root3=(tech)
            **for** yr **in** root3.iter(**'period'**):
                root4 = et.Element(**'root'**)
                root4=yr
                **for** gas **in** root4.iter(**'Non-CO2'**):
                    root5 = et.Element(**'root'**)
                    root5=gas
                    **for** em **in** root5.iter(**'input-emissions'**):
                        Technology.append(tech.attrib[**'name'**])
                        Value.append(em.text)
                        Gas.append(gas.attrib[**'name'**])
                        Year.append(yr.attrib[**'year'**])
                        Crop.append(supply.attrib[**'name'**])
                        Country.append(x.attrib[**'name'**])

现在,简单的部分。让我们使用填充的列表在 pandas 中创建一个数据帧。

df = pd.DataFrame({**'Year'**: Year,**'Gas'**:Gas,**'Value'**:Value,**'Technology'**:Technology,**'Country'**:Country,**'Crop'**:Crop })

如果我们打印出这个数据帧的头部,我们会得到,

Year        Gas         Value    Technology Country  Crop
0  1975  SO2_1_AWB   3.98749e-05  Corn_NelsonR     USA  Corn
1  1975    NOx_AWB   0.000285263  Corn_NelsonR     USA  Corn
2  1975     CO_AWB  0.0089533275  Corn_NelsonR     USA  Corn
3  1975  NMVOC_AWB  0.0005259348  Corn_NelsonR     USA  Corn
4  1975    CH4_AWB  0.0002027923  Corn_NelsonR     USA  Corn

这就对了。简单回顾一下,在将 XML 转换为 dataframe 时,需要记住一些原则,

  1. 永远记住 xml 本身的层次,包括每一层中的属性
  2. 编写 for 循环时,确保在每个阶段都将解析的数据保存到临时变量中。
  3. 在循环的最后一步将数据写到空列表中。
  4. 请记住,结构就是数据的形式。你在修改形式的同时保持了它的本质。

以上代码可以在这里找到-https://github.com/kanishkan91/ConvertXMLtoDataframepy

上例中使用的基本 xml 可以在这里找到-https://github . com/kanishkan 91/ConvertXMLtoDataframepy/blob/master/all _ aglu _ emissions . XML

一如既往,欢迎任何反馈。

将 Yelp 数据集转换为 CSV

原文:https://towardsdatascience.com/converting-yelp-dataset-to-csv-using-pandas-2a4c8f03bd88?source=collection_archive---------11-----------------------

Image source — Yelp

如何使用熊猫在 Jupyter 笔记本中加载大容量文件

第 13 轮 Yelp 数据集挑战赛于 2019 年 1 月开始,为学生提供赢得奖项和进行学术用途分析或研究的机会。

这篇文章一步一步地展示了如何加载 Yelp 数据集的巨大文件,特别是 5.2 千兆字节的 review.json 文件到一个更易于管理的 CSV 文件。review.json 文件中有超过 600 万条评论,在 Jupyter 笔记本中加载可能会很麻烦。

1。下载 Yelp 数据集
(来源:Yelp 数据集挑战https://www.yelp.com/dataset/challenge)

这个数据集包括 Yelp 获得的关于企业、评论、用户、签到、提示和照片的信息。文件为 8.69 未压缩的 json 格式(6 个 json 文件包括 business.json、review.json、user.json、checkin.json、tip.json 和 photo.json)。

解压yelp_dateset文件后,会出现另一个文件,在新文件的末尾加上.tar再次解压。这 6 个 json 文件应该与 Yelp 的数据集协议和第 13 轮描述的 2 个 pdf 文件一起出现。

2。在 Jupyter 笔记本中加载 Yelp 数据集

因为 review.json 不包含业务的详细信息,所以如果我们想要了解每个评论是针对哪种业务的详细信息,我们需要将评论文件与业务文件合并。

加载 business.json 文件

设置 business.json 环境路径以使用 Pandas 加载

import pandas as pdbusiness_json_path = 'data/business.json'
df_b = pd.read_json(business_json_path, lines=True)

business.json

清理 business.json 文件

仅保留数据集中仍在营业的企业

# 1 = open, 0 = closed
df_b = df_b[df_b['is_open']==1]

删除任何不相关的栏目(必须保留business_id,以便与评论合并)

drop_columns = ['hours','is_open','review_count']
df_b = df_b.drop(drop_columns, axis=1)

按类别划分业务

我们可以先使用类别查询相关业务,然后找到我们想要的相关评论。

对于这个例子,我们只对房车相关的业务感兴趣。

business_RV = df_b[df_b['categories'].str.contains(
              'RV Repair|RV Dealers|RV Rental|RV Parks|Campgrounds',
              case=False, na=False)]

查找相关类别

因为一个企业可以有多个类别,所以很难计算出有多少不同的类别(提示:1290 个不同的类别!)。我们可以使用熊猫 v0.25 中的explode功能来拆分类别。

# Make sure the Pandas version is above 0.25
# If not, upgrade Pandas version
# !pip3 install --upgrade pandas
pd.__version__

一旦我们确认我们有更新的熊猫版本,让我们开始变魔术吧。

df_explode = df_b.assign(categories = df_b.categories
                         .str.split(', ')).explode('categories')

然后我们可以列出所有单独的类别

df_explode.categories.value_counts()

找到包含RV的类别

df_explode[df_explode.categories.str.contains('RV',
                      case=True,na=False)].categories.value_counts()

Yelp Dataset — Pandas Explode to find RV related categories

在 Pandas 中加载大量文件

对于 Yelp 数据集这样的大文件,一次加载所有数据很可能会导致计算机内存崩溃。幸运的是,熊猫可以通过将文件分割成小块来加载大数据。

清理和加载 review.json 文件

设置 review.json 环境路径以使用 Pandas 加载。

review_json_path = 'data/review.json'

识别每一列的数据类型可以减少内存使用。
幸运的是,Yelp 为他们的数据集提供了文档,因此我们可以设置每一列的数据类型。

size = 1000000
review = pd.read_json(review_json_path, lines=True,
                      dtype={'review_id':str,'user_id':str,
                             'business_id':str,'stars':int,
                             'date':str,'text':str,'useful':int,
                             'funny':int,'cool':int},
                      chunksize=size)

这里,1,000,000 的块大小意味着熊猫每次将读取 1,000,000 行。在 review.json 的这个数据集中,有超过 600 万条评论(行)。减小块的大小可能更容易加载并更快地检查结果。

合并 Review.json 和 Business.json 文件

通过仅将相关企业合并到评论文件,最终数据集将仅包含来自这些企业的评论。

将新数据框转换为 CSV 文件

可以更容易地加载和共享更简洁的数据集。

csv_name = "yelp_reviews_RV_categories.csv"
df.to_csv(csv_name, index=False)

结论

这篇文章展示了我们如何轻松地将 Jupyter Notebook 中的 JSON 文件加载到 CSV 文件中,而不需要外部转换器。只有当我们知道如何正确阅读和使用数据时,数据才是有用的。彻底清理和处理数据将决定我们分析的质量。

接下来:使用散点文本可视化分析 Yelp 数据集

现在我们已经有了 CSV 文件,我们可以开始分析数据了!在我的下一篇文章中,我将展示如何用散点图空间可视化数据。

感谢阅读!我很乐意听到你的想法,在这里评论或给我发消息。用于此的代码位于我的 GitHub 库中。

ConvNet Playground:探索卷积神经网络的交互式可视化工具

原文:https://towardsdatascience.com/convnetplayground-979d441ebf82?source=collection_archive---------16-----------------------

探索应用于语义图像搜索任务的 CNN,并查看由预训练模型学习的模式的可视化。

ConvNet Playground is an interactive visualization for exploring Convolutional Neural Networks applied to the task of semantic image search. It allows you explore the performance of multiple pre-trained CNN architectures (and intermediate models based on each architecture) for feature extraction on images across various datasets.

对于数据科学家和工程师来说,重用预先训练的模型所学习的特征(迁移学习)是相当常见的。当这在实践中完成时,几个问题出现了——我使用什么模型架构?我是使用整个模型还是模型的子集?每个模型中的层学习什么模式,它们最适合什么任务?建立如何导航这些选择的直觉需要大量的实验,这可能是计算和时间密集型的。

为了帮助解决这个问题, ConvNet Playground 提供了一个环境,以支持探索和学习的方式探索这些选择的组合(结果)。我们希望该工具将有助于对 CNN 如何工作建立直觉感兴趣的爱好者、教授 CNN 的教育者和对展示 CNN 在图像分析任务中的价值感兴趣的技术专家。ConvNet Playground 是我们在 Cloudera 快进实验室建造的几个原型之一,以帮助我们的客户建立对机器学习如何工作的直觉。

注意:与该工具的某些部分交互并理解它们需要一些机器学习概念的知识。如果你想了解 CNN 的一些背景知识,推荐这篇文章和课程。

语义搜索——一个简单的实现

ConvNet Playground 专注于使用 CNN 进行语义图像搜索的任务。我们的(相当简单的)方法分两个阶段实现:(1)我们使用预先训练的 CNN(想想 VGG16、InceptionV3 等)从我们的数据集中的所有图像中提取特征。在 i mageNet )上进行预训练(ii。)我们计算相似性作为这些特征之间距离的度量。好的模型将提取正确捕获相似性的特征——相似图像的特征靠得很近,不相似图像的特征很好..相距甚远。当然,相似性是一个不断变化的概念,对于每个任务和相应的数据集可能会有所不同。

To implement semantic search, we start by extracting features from images in our dataset using pre-trained CNN models. Similarity is computed as the distance between these features.

执行搜索查询

The user can select an image and view a list of the top 15 images which are most similar to the selected image.

用户可以执行搜索查询(单击默认数据集中的图像),默认模型(InceptionV3)会确定与所选模型最相似的 15 个图像的列表。搜索界面还提供了一个搜索结果分数,它是与所选图像属于同一类别的返回结果的百分比,根据其在结果列表中的位置进行加权,即,与在列表末尾的正确结果相比,排列在结果列表顶部的正确结果得到更多分数。例如,对于是香蕉图像的搜索查询,如果所有返回的图像都属于同一类别(香蕉),则搜索分数将是 100%。请注意,这个分数是保守的——一些图片可能属于不同的类别,但也类似(例如,轿车、甲壳虫、法拉利都是汽车)。搜索分数可用于轻松比较每个搜索配置的性能。

修改搜索配置(高级选项)

Advanced options allows the user select datasets of varied complexity, select models and distance metrics for computing similarity. As each configuration is changed, the search results are updated in real time.

为了让用户进一步探索 CNN 的性能,用户可以使用 高级选项 开关修改他们的搜索配置——数据集、模型架构、距离度量。随着每个配置选项的修改,用户可以实时查看搜索性能的变化。

数据集:用户可以从 4 个不同复杂程度(图像内容、图像大小)的数据集中选择一个。 Iconic200 是从 Flickr (creative commons)收集的真实世界图像的数据集。它包含跨越 10 个关键词搜索的图像(拱门、香蕉、大众甲壳虫、埃菲尔铁塔、帝国大厦、法拉利、皮卡、轿车、巨石阵、拖拉机)。 Fashion200 是来自 Kaggle 时尚产品图片数据集的 200 张图片(10 个类别)的真实时尚单品的集合。图像的最大宽度为 300 像素。tinyimagenet 200包含 64px * 64px 图像,是 Tiny Imagenet 视觉识别挑战数据集的子集。 Cifar10 是流行的 cifar10 数据集的子集(200 张图像),包含来自 10 个随机选择的类的 20 张图像。每幅图像的尺寸为 32px 32px。

ConvNet Playground allows users to perform search queries on 4 datasets of varying complexity (content, resolution).

模型和层(中间模型):我们提供了九个模型(vgg16、vgg19、mobilenet、efficientnetb0、efficientnetb5、xception、resnet50、inceptionv3、densenet121)的结果,以及使用每个模型的 8 个层构建的一组中间模型。我们只用了八层,主要是为了减轻观众的认知负担,便于视觉比较。

The user can chose which models or intermediate models are used for feature extraction. Intermediate models are a subset of the main pre-trained model constructed from a given layer.

然而,选择使用哪些层的取决于以下因素——首先,我们关注具有可训练参数的卷积层,并且我们在每个模型中包括第一个和最后一个卷积层。最后,我们选择中间的六个卷积层作为随机样本。这些模型按照复杂性(参数数量)递增的顺序呈现,并显示出它们在生成正确识别相似图像的特征的能力方面的显著差异。**

距离度量:我们提供了使用四种不同的距离度量来测量从每个数据集中的所有图像中提取的特征之间的相似性的结果。这些包括余弦、欧几里德、平方欧几里德和闵可维距离。

嵌入的 UMAP 可视化

为了探索各种模型如何捕捉每个数据集的相似性,用户可以查看使用每个模型提取的特征的 UMAP 可视化。例如,很好地捕捉相似性的模型生成嵌入,其中每个类中的图像被聚集在一起,并且与其他不相同的类很好地分开。

Users can explore a UMAP visualization of embeddings extracted using each model. In the image above, the selected model (Inception V3, Layer 310) does a decent job of clustering each category in the dataset.

比较每个查询的模型性能

compare models 视图提供了一个界面,用于跨所有模型体系结构比较给定查询的性能(搜索结果得分)。

For each query, users can view graphs of how how all other models (and intermediate models) perform.

每个模型中各层学习到的模式的可视化

更好地理解为什么从模型中的层构造的中间模型对于不同的数据集表现不同的一种方法是检查在每个层学习的模式/特征。ConvNet Playground 通过 Model Explorer 视图支持这种检查。

The Model Explorer view allows users to explore patterns learned by layers in a pre-trained CNN model. In the example above, we see that channels in layer 2 in the VGG16 model have learned to detect colors and edges.

一些反思

你可以用预先训练好的模型走得很远

ConvNet Playground 中的所有特征提取都是使用在 imageNet 上预先训练的模型架构来执行的。没有进行微调。由于预先训练的模型可以提供很好的价值,并作为实验的一个令人信服的起点,下一个问题是您使用模型的什么层或子集?

我使用哪一层进行特征提取。

当重用表示(迁移学习)时,自由地使用整个模型(仅删除完全连接的层)或模型的子集可能会令人困惑。实现这一点的一种方法是考虑在每一层学到的模式对手头任务的适用性。例如,如果您的任务与低级特征相关(例如,检测形状、颜色、边缘),则后续层(例如,眼睛、面部、物体的一部分)学习的高级概念不太可能有用。

a.) Layer 2 in the VGG model, which has learned to detect colors and edges, incorrectly returns images with similar colors. b.) Layer 7 in an Inceptionv3 model, which has also learned to detect colors and edges, correctly returns of shirts with similar colors and edges. Insight: when the meaning of similarity is simple (e.g. colors and edges), intermediate models constructed from early layers work well, have fewer parameters and should be considered.

a.) Layer 2 in the VGG model, which has learned to detect colors and edges, incorrectly returns images with similar colors. b.) Layer 7 in an Inceptionv3 model, which has also learned to detect colors and edges, correctly returns of shirts with similar colors and edges. Insight: when the meaning of similarity is simple (e.g. colors and edges), intermediate models constructed from early layers work well, have fewer parameters and should be considered.

接下来,他们可以利用提取的嵌入的 UMAP 可视化来探索这些模型在捕捉各种数据集的相似性概念方面的表现。

AutoML/NAS 型号极具竞争力!!

通常的做法是使用 VGG16(前 5 名精度为 92.6 )作为图像分析任务的基础。在凉爽的138 米称重,VGG16 是参数低效。相比之下, EfficientNetB0 ,一个神经架构搜索(NAS,AutoML)模型,在 5.3M 参数(前 5 名精度 93.2) 中加权。ConvNet Playground 集成了两个 EfficientNet 模型变体,并将其应用于语义搜索(EfficientNetB0 5.3M 参数和 EfficientNetB5 30.6M 参数)..它们真的很好用,去试试吧!

Top performing models for image analysis between 2012 and 2019. We see that model architectures designed using neural architecture search approaches (autoML) models have become competitive in the last few years. Not just that, they achieve this with less parameters.

一些神经元/层学习非常奇怪的模式

如果你对挖掘预训练模型中的层感兴趣,并探索每个架构中的层学习了什么样的模式,那么…有足够多的东西让你忙起来!如果你发现一些有趣的东西(比如下面的频道已经学会在 densenet121 中明确检测眼睛的模式)..一定要在推特上分享!

This eye pattern learned by Channel 5, Layer 202 in densenet121. Check out the Model Explorer view, you might find some even more interesting patterns learned by other models.

请注意,该原型中的方法(使用来自预训练模型的特征)相对简单,因此具有局限性(规模、在搜索查询中匹配多个对象、准确性)。在实践中,我们可以通过微调给定数据集的专门模型来扩展这种实现,利用附加信息(例如文本描述、交互日志、购买日志等)来构建更有意义的嵌入,或者使用两阶段方法来匹配搜索查询中的多个对象(提取对象裁剪并用作搜索查询)。

承认

ConvNet Playground 建立在许多相关项目和工具的基础上,旨在通过交互式体验使神经网络更容易访问。这些相关的项目包括特征可视化、 Tensorflow 游乐场、 可教机器、 Keras.js 等等。ConvNet Playground 使用 lucid 和 lucid4keras 库来可视化层中通道学习到的特征, leader-line 用于绘制 svg 线, carbon 设计系统用于布局。本项目中使用的预训练模型来自 Keras 应用模块,EfficientNets 实施来自此处。感谢格兰特·卡斯特对 Three.js 的宝贵指点,以及快进实验室团队的其他成员的反馈和指导!

ConvNet Playground 是我们最近在 Cloudera Fast Forward Labs 进行的关于用于图像分析的深度学习的研究报告的一部分。我们的报告更加详细(什么任务用什么模型,如何选择一个好的模型,OSS 工具和框架,可解释性等等)。).如果您有兴趣获取完整报告(可通过订阅我们的研究和咨询服务获得),请联系。

如果你觉得这个工具有用或者有反馈要分享,请随时联系我们。

卷积神经网络——初学者指南

原文:https://towardsdatascience.com/convolution-neural-networks-a-beginners-guide-implementing-a-mnist-hand-written-digit-8aa60330d022?source=collection_archive---------2-----------------------

这篇文章的目的是介绍卷积神经网络的基本概念。这篇文章的最终目标是实现一个 MNIST 手写数字分类器,所以一切都要牢记在心——卷积层最大池层RelU 激活函数全连接层、漏失层、交叉熵损失函数等。

这篇文章是关于卷积神经网络(CNN)介绍的 2 部分系列文章的一部分。

第一部分——围绕 CNN 的基本概念

第二部分— Pytorch 实现 CNN 对 MNIST 手写数字进行分类

1.卷积层

在深入了解什么是卷积层之前,让我们先了解一下为什么要使用它们。

为什么使用卷积层?

在 Yann LeCun 于 1998 年提出卷积概念用于数字分类之前,人们使用其他方法如支持向量机、knn、逻辑回归等对图像进行分类。在这些算法中,像素值被视为特征,即对于 28×28 的图像,将有 784 个特征。

在卷积开始流行之前,人们已经使用了很多算法来进行图像分类。人们过去常常从图像中创建特征,然后将这些特征输入到像 SVM 这样的分类算法中。一些算法还使用图像的像素级值作为特征向量。举个例子,你可以训练一个具有 784 个特征的 SVM,其中每个特征是一个 28x28 图像的像素值。这样我们就失去了很多像素之间的空间相互作用。我们仍然可以像卷积层自动做的那样从图像中手动选择特征,但这将非常耗时。卷积层使用来自相邻像素的信息,通过卷积将图像下采样为特征,然后使用预测层来预测目标值。

卷积层是如何工作的?

我们使用多重卷积过滤器内核来运行图像并计算点积。每个过滤器从图像中提取不同的特征。

让我们考虑一个大小为 3x3 的过滤器和一个大小为 5x5 的图像。我们在匹配内核大小的图像像素值和内核本身之间执行元素乘法,并将它们相加。这为我们提供了特征单元的单个值。

Convolution operation step — 1

**2 * 1+4 * 2+9 * 3+2 (-4)+1 * 7+4 * 4+1 * 2+1 (-5)+2 * 1 = 51

过滤器继续在图像上运行,并产生新的值,如下所示。

Convolution operation step — 2

**4 * 1+9 * 2+1 * 3+1 (-4)+4 * 7+4 * 4+1 * 2+2 (-5)+9 * 1 = 66

诸如此类…

Convolution operation step — final

**2 * 1+9 * 2+2 * 3+5 (-4)+1 * 7+3 * 4+4 * 2+8 (-5)+5 * 1 =-2

在上面的例子中,我们将内核滑动了 1 个像素。这叫跨步。我们可以让内核移动不同的步幅值来提取不同种类的特征。

我们选择的步幅也会影响提取的特征的大小。计算特定内核尺寸的特征尺寸的公式如下:

特征大小=((图像大小-内核大小)/步幅)+ 1

我们可以输入上述示例的值并验证它。

特征尺寸=((53)/1)+1 = 3

因此,步幅为 2 时,大小为 5×5 的图像上大小为 3×3 的核将只能提取大小为 2 的特征。

Convolution operation kernel size 3 and stride 2

如果您希望特征与输入图像的大小相同,该怎么办?你可以通过填充图像来实现。填充是一种简单地在图像边缘添加零以增加其尺寸的技术。填充允许我们强调边界像素,从而减少信息损失。

这里是一个具有大小为 5×5 的输入图像的例子,该输入图像被填充到 7×7,即填充大小为 1,并且被大小为 3×3 的核以 1 的步幅进行卷积,从而产生大小为 5×5 的特征。

Convolution operation kernel size 3, stride 1 and padding 1

当考虑填充图像时,计算特定内核尺寸的特征尺寸的公式如下:

*特征尺寸=((图像尺寸+ 2 填充尺寸-内核尺寸)/步幅)+1

我们可以输入上例的值并验证它。

特征尺寸=((5+2 * 13)/1)+1 = 5

对于具有 3 个通道(即 rgb)的图像,我们对所有 3 个通道执行相同的操作。

神经网络通过反向传播来学习这些核心值,以提取图像的不同特征。典型地,在卷积神经网络中,我们在每一层都有一个以上的内核。我们可以进一步使用这些特征图来执行不同的任务,如分类、分割、对象检测等。

这里有一些很好的卷积层的可视化效果-

2.最大池层

最大池化图层有助于减少卷积要素的空间大小,并且通过提供它们的抽象表示有助于减少过度拟合。这是一个的基于样本的离散化过程。

它类似于卷积层,但我们不是在输入和内核之间取点积,而是取被内核覆盖的输入区域的最大值。

下面的示例显示了 maxpool 层的操作,其内核大小为 2,跨距为 1。

Max pooling step — 1

Max pooling step — 2

诸如此类…

Max pooling step — final

还有一种叫做平均池的池,你取平均值而不是最大值。最大池有助于通过丢弃有噪声的激活来减少噪声,因此优于平均池。

3.RelU(整流线性单位)激活功能

激活函数向模型引入非线性,这允许它学习输入和响应变量之间的复杂函数映射。有相当多不同的激活函数,如 sigmoid、tanh、RelU、Leaky RelU 等。

RelU 函数是一个分段线性函数,如果大于 0,则直接输出输入,否则输出零。

ReLU(x)=max(0,x)

Credit: PyTorch docs

还有许多其他的激活函数,但是 RelU 是许多种类的神经网络最常用的激活函数,因为它的线性行为更容易训练,并且它通常实现更好的性能。

最大池层之前或之后的重新激活

嗯,MaxPool(Relu(x))= Relu(MaxPool(x))

所以它们满足了交际属性,可以用任何一种方式。实际上,RelU 激活函数在卷积层之后立即应用,然后输出被最大化汇集。

4.完全连接的层

在全连接层中,输入层节点连接到第二层中的每个节点。我们在 CNN 的结尾使用一个或多个完全连接的层。添加全连接层有助于学习卷积层输出的高级特征的非线性组合。

Fully Connected layers

通常在两个连续的全连接层之间使用激活函数脱落层,分别引入非线性和减少过拟合。

在最后一个完全连接的层,我们根据我们的应用选择输出大小。为了对 MNIST 手写数字进行分类,最后一层的大小为 10,即每个数字一个节点,我们将对输出进行 softmax 处理,得到一个 10 维向量,其中包含每个数字的概率(0-1 之间的数字)。

5.脱落层

Dropout 是一种正则化技术,用于减少神经网络上的过拟合。通常,深度学习模型在完全连接的层上使用 dropout,但也有可能在 max-pooling 层之后使用 dropout,从而创建图像噪声增强。

Dropout 使用来自伯努利分布的样本以概率 p 随机地将输入张量的一些连接置零。

Zeroing out the red connections

6.损失函数—交叉熵

损失函数是一种评估模型对数据集建模程度的方法。如果预测值偏离实际目标值,损失函数将输出一个较大的数字,否则将输出一个较小的数字。

由于我们的问题是多类分类,我们将使用交叉熵作为我们的损失函数。如果实际目标类别标签的预测类别标签概率较低,则它基本上输出较高的值。

Credits: Pytorch docs

放弃

虽然这篇文章涵盖了围绕用于图像分类的 CNN 模型的大多数概念,但它绝不是一个全面的指南。它主要面向初学者,最终目标是实现一个 CNN MNIST 手写数据分类器。

在下一部分 第 2 部分— Pytorch 实现 CNN 对 MNIST 手写数字进行分类 我们将通过实现一个卷积神经网络(CNN)网络来使用所有这些概念对 MNIST 手写数字进行分类。

卷积与相关

原文:https://towardsdatascience.com/convolution-vs-correlation-af868b6b4fb5?source=collection_archive---------1-----------------------

卷积神经网络是大多数计算机视觉应用(如自动驾驶汽车、面部识别系统等)的主干,它是一种特殊的神经网络架构,其中基本的矩阵乘法运算被卷积运算取代。他们专门处理具有网格状拓扑结构的数据。例子包括时间序列数据和图像数据,它们可以被认为是二维像素网格。

历史

卷积神经网络是福岛在 1980 年首次推出的,名为 Neocognitron 。它受到 Hubel 和 Weisel 提出的神经系统层次模型的启发。但是这个模型并不流行,因为它复杂的无监督学习算法被称为无老师学习。Yann LeCun 在 1989 年使用反向传播和 Neocognitron 的概念提出了一个名为 LeNet 的体系结构,它被美国邮政服务用于手写邮政编码识别。Yann LeCun 在这个项目上做了进一步的工作,最终在 1998 年发布了 LeNet-5,这是第一个现代的 convnet,它引入了我们今天仍在 CNN 使用的一些基本概念。他还发布了手写数字的 MNIST 数据集,这可能是机器学习中最著名的基准数据集。在 20 世纪 90 年代,计算机视觉领域转移了它的焦点,许多研究人员不再试图研究 CNN 架构。神经网络研究经历了一个寒冬,直到 2012 年,多伦多大学的一群研究人员在著名的 ImageNet 挑战赛中输入了一个基于 CNN 的模型(AlexNet ),最终以 16.4%的错误率获胜。从那时起,卷积神经网络不断向前发展,基于 CNN 的架构不断赢得 ImageNet,2015 年,基于卷积神经网络的架构 ResNet 以 3.57%的错误率超过了人类水平的 5.1%。

用词不当:

CNN 广泛使用的卷积运算是用词不当。所用的运算严格来说是相关运算,而不是卷积运算。这两个操作符略有不同,我们将分别研究它们以了解不同之处。

交叉相关:

相关是在图像上移动通常被称为核心的过滤遮罩并计算每个位置的乘积之和的过程。相关性是滤波器位移的函数。换句话说,相关的第一个值对应于滤波器的零位移,第二个值对应于一个位移单位,等等。

Figure 1.Cross-Correlation in 1-D

Figure 2.Cross-Correlation in 1-D

数学公式:

图 3 给出了使用滤波器 F 对图像 I 进行一维互相关运算的数学公式。假设 F 有奇数个元素会很方便,所以我们可以假设当它移动时,它的中心正好在图像 I 的一个元素的上面。所以我们说 F 有 2N+1 个元素,这些元素的索引从-N 到 N,所以 F 的中心元素是 F(0)。

Figure 3. The formula of Cross-Correlation in 1-D

类似地,我们可以将这个概念扩展到图 4 所示的 2-D。基本思想是相同的,除了图像和过滤器现在是 2D。我们可以假设我们的滤波器有奇数个元素,所以用(2N+1)x(2N+1)矩阵表示。

Figure 4. The Formula of Cross-Correlation in 2-D.

2D 的相关运算非常简单。我们只需要一个给定大小的过滤器,并将其放置在图像中与过滤器大小相同的局部区域上。我们继续这个操作,在整个图像中移动同一个滤波器。这也有助于我们实现两个非常受欢迎的属性:

  1. 平移不变性:我们的视觉系统应该是感知、响应或检测同一物体,而不管它出现在图像的什么地方。
  2. 局部性:我们的视觉系统聚焦于局部区域,而不考虑图像的其他部分正在发生什么。

互相关函数有一个限制或特性,当它被应用于一个离散的单位脉冲(一个全 0 且只有单 1 的 2D 矩阵)时,产生一个结果,该结果是滤波器的一个拷贝,但是旋转了 180 度的角度。

Figure 5. The complete correlation operation

卷积:

卷积运算与互相关运算非常相似,但略有不同。在卷积运算中,首先将核翻转 180 度,然后应用于图像。卷积的基本性质是将一个核与一个离散的单位脉冲进行卷积,在脉冲的位置产生一个核的副本。

我们在互相关部分看到,相关运算产生一个脉冲副本,但旋转了 180 度。因此,如果我们预旋转过滤器并执行相同的滑动乘积和运算,我们应该能够获得期望的结果。

Figure 6. Applying the convolutional operation on Image b in Figure 5.

数学公式:

使用核 F 在图像 I 上应用的卷积运算由 1-D 中的公式给出。卷积就像相关,除了我们在相关之前翻转滤波器。

Figure 7. Convolution Operation in 1-D.

在 2D 卷积的情况下,我们水平和垂直翻转滤波器。这可以写成:

Figure 8. Convolution Operation in 2-D.

卷积运算也遵循平移不变性局部性的相同性质。

Figure 9. The Correlation Operation demonstrated what many would refer to as convolution.

注意:

虽然这两种操作略有不同,但使用的内核是否对称并不重要。

结论:

在这篇文章中,我们简要讨论了卷积神经网络的历史和一些特性。我们讨论了各种文本中经常提到的卷积运算实际上是互相关运算的误称。这种差异非常微小,但非常有用,应该被每个刚进入、实践或经历过计算机视觉广阔领域的人所了解。我希望你喜欢这篇文章,如果有任何问题、疑问或讨论,请在 Twitter 或 Linkedin 上联系我。

参考资料:

  1. 深度学习书籍,作者:伊恩·古德菲勒、约舒阿·本吉奥和亚伦·库维尔。
  2. Rafael C. Gonzalez 的数字图像处理。
  3. 由 Aston Zhang、Zack C. Lipton、李牧和 Alex J. Smola 深入研究深度学习。
  4. 相关和卷积由大卫雅各布完成。
  5. 图 9 摘自https://towards data science . com/applied-deep-learning-part-4-卷积神经网络-584bc134c1e2 。
  6. https://spatial-lang.org/conv
  7. 迷因取自https://www . mihaileric . com/posts/convolutionary-neural-networks/。

卷积与互相关

原文:https://towardsdatascience.com/convolution-vs-cross-correlation-81ec4a0ec253?source=collection_archive---------18-----------------------

这篇文章将概述卷积和互相关的区别。这篇文章是网上唯一包含卷积和互相关的一步一步的例子的资源(据我所知,相信我,我做了很多搜索)。这篇文章还精确地讨论了指数,事实证明,如果你想通过例子证明卷积和互相关是如何相关的,那么正确使用指数是至关重要的。我花了很大一部分时间来准备这篇文章,为索引而紧张得要命,但现在它们都很漂亮,而且组织有序,供你欣赏。

首先,关于这个话题的一点动机…

动机

要理解 CNN 中的反向传播就要理解卷积和互相关的区别,要理解解卷积(一种 CNN 可视化技术),要理解解卷积和显著图(更可视化),要理解引导反向传播(更可视化),要理解 Grad-CAM (更可视化)因此,尽管“卷积与互相关”可能一开始看起来跑题了,但这篇文章实际上仍然是 CNN 热图系列的一部分。

关于 CNN 的回顾,请参见卷积神经网络介绍。

既然你的积极性很高,让我们开始吧!

高层总结

互相关和卷积都是应用于图像的操作。互相关意味着在图像上滑动一个核(过滤器)。卷积意味着在图像上滑动翻转的内核。机器学习库中的大多数卷积神经网络实际上是使用互相关来实现的,但它在实践中不会改变结果,因为如果使用卷积来代替,则在翻转的方向上会学习到相同的权重值。

跟踪指数

为了使卷积和互相关的例子和方程清晰,我们需要跟踪我们的图像索引、核索引和输出索引。

首先,这里有一个常用来解释卷积的图,其中内核(黄色)滑过图像(绿色)产生输出(粉红色):

(图片来源:这部动画出现在很多地方,包括这里和这里。)

当我们对图像进行索引时,我们称哪个像素为[0,0]?我们可以选择左上角,或者中心,或者其他任意的像素。类似的,我们在内核或者输出中怎么称呼[0,0]?

对于图像、内核和输出,我们将中心元素称为[0,0]。这个决定对于让公式很好地工作是很重要的。

盘旋

卷积设置:符号&方程

网上有很多关于卷积的方程,都有不同的符号和索引。例如:

在本文的剩余部分,我们将使用下面的符号,其中图像被称为 x ,内核被称为 h ,输出被称为 y :

这是宋浩安在他们关于 2D 卷积的有用帖子中使用的符号。

星号用于表示卷积运算。因此, x [m,n] h [m,n】意味着我们将图像 x 与内核 h 进行卷积,以找到输出 y 中位置[m,n]处的值。总和超过 I 和 j,它们是图像像素的索引。

这里有一个内核(过滤器)的绘图,其中我们看到内核的中心是[0,0],正如我们之前决定的。 m (红色)水平索引成列, n (绿色)垂直索引成行内核:

内核元素的索引显示在左边,红色和绿色。实际的内核数值表示为变量 a、b、c、d、e、f、g、h 和 I,如右图所示。(内核中的这些数值是 CNN 在训练过程中学习到的。)

最后,这里是 7 乘 7 的图像 x ,索引从-3 到 3:

这是图像 x 的右下角,放大是因为这是我们在示例中要关注的图像部分:

对于这幅图像,我写出了每个像素的索引。这些不是像素值,它们只是每个像素的[i,j]坐标。您可以想象这个图像有任意的像素值,因为在我们的例子中不需要图像像素值。

卷积例子(数学)

回想一下卷积公式:

这似乎表明,为了获得输出 y 中索引[m,n]处的值,我们需要查看图像中的所有像素。毕竟,I 和 j 是图像的索引,和的值从负无穷大到正无穷大。

然而,实际上,我们不需要所有的像素,因为对于特定的输出索引 m 和 n,选择特定的像素索引 I 和 j 将导致访问不存在的内核元素。因此,我们将只查看图像的像素,对于这些像素,等式h【m-I,n-j】的核心部分仍然有效。为了说明这个效果,在下面的例子中,我包括了像素索引 i = 3 和 j = 3;您可以看到,对于所选的输出元素 y [m=1,n=1],选择 i = 3 或 j = 3 会导致尝试访问不存在的内核元素(例如内核元素(1,2));参考前面的内核图片,你会看到它的索引从-1 到+1。因此,我们没有明确说明输出图的每个部分需要哪个图像索引 I 和 j;它隐含在公式中,基于 I 和 j 的选择将导致可接受的内核访问。

(注意,不是从“负无穷大到正无穷大”求和,这有点奇怪,因为没有图片具有无穷大的大小,我们可以改为写“-k 到+k”,但这具有暗示固定的 k×k 输入图像大小的缺点。)

事不宜迟,下面是卷积产生输出条目 y [m=1,n=1]的工作示例:

这里发生了什么事?

首先,我们试图在输出图 y 中找到单个位置的值,由索引 m = 1, n = 1 指定;我们想找到 y [1,1]。为了简单起见,我没有显示像素值 I 和 j(从-3 到+3)的每一个可能的组合,因为那样会变得非常混乱,并且我没有显示的所有组合都是“无效的”(也就是说,它们需要不存在的内核索引。)

图像中央有一条蓝线。在蓝线的左侧,我们将 m、n、I 和 j 的值以系统的方式直接代入卷积方程。在蓝线的右边,我们已经“求解”了左边的表达式,从而得到了与特定像素 x [#,#]相乘的 h [#,#]的最终索引。

卷积示例(绘图)

上面的等式可能看起来像一大堆晦涩难懂的东西,但是如果我们把它们组织成一张图片,我们会突然明白为什么它们很酷。在下面的图片中,我显示了图像的右下角 x 并明确写出了相关的像素索引。然后,我将内核 h 与相关位置的图像对齐,并使用卷积方程的结果来填充内核索引 h [#,#],以便右边的 h [#,#]与右边的 x [#,#]对齐。最后,我已经参考了原始的内核图片(在本文的前面)来计算哪些内核数值(a、b、c 等等)对应于哪些内核索引…瞧!!!我们已经表明卷积“翻转内核”:

所以,如果你曾经读过任何关于“实卷积如何使用翻转核”的东西,现在你明白为什么了,在数学上。

与卷积相比的互相关

当你想到“卷积”时,你可能会想到互相关,因为互相关意味着在图像上滑动内核而不翻转内核。以下是互相关和卷积的并列等式,您可以比较它们:

正如你所看到的,在表达式h【m-I,n-j】或h【m+I,n+j】中,关键的区别是加号与减号。这一差异最终决定了(a)内核是否翻转,( b)为输出贴图的每个元素处理哪些像素。

在上图中,我们可以看到以下内容:

  • 为了获得 y [m=1,n=1]处互相关的输出值,我们需要查看绿色中的像素(因为这些是内核索引有意义的唯一像素。)
  • 然而,为了获得卷积y【m = 1,n=1】的输出值,我们需要查看一组不同的像素,用红色包围起来(因为这些是现在内核索引有意义的唯一像素。)
  • 事实证明,如果我们想使用同一幅输入图像来完成一个工作示例,那么同一幅输入图像对应于不同的卷积和互相关输出图。这是因为卷积从右下角开始,从下向上/从右向左进行,而互相关从左上角开始,从上向下/从左向右进行。因此,我们关注的图像部分(红色方框部分)对应于卷积输出 y[1,1],但对应于互相关输出 y[-1,-1]。

作为对该问题的进一步总结,以下两个图显示了输入图像的哪一部分用于创建输出图的不同部分,用于互相关与卷积:

交叉相关

互相关示例(数学)

最后,在这样的背景下,这是我们关注的图像“红色区域”的工作示例。在互相关中,这个补丁用于找到在 y [m= -1,n= -1]的输出:

互相关示例(图纸)

同样,我们可以使用上面的数学来填充一张图片,向我们展示在图像和内核级别上发生了什么。我们可以看到,通过将适当的内核索引与输入图像索引对齐,我们最终得到“面向原始方向”的内核,即在互相关中,内核是而不是翻转的。

总结

卷积和互相关都涉及在图像上滑动核来创建输出。

  • 在卷积中,内核是翻转的
  • 在互相关中,内核不翻转
  • 卷积的大部分动画和解释其实都是在呈现互相关性,“卷积神经网络”的大部分实现其实都是利用了互相关性。在机器学习环境中,这不会改变模型的性能,因为 CNN 权重只是被学习翻转了。

要在示例中很好地使用公式,您需要:

  • (1)适当选择指标。图像的中心元素、内核和输出都是[0,0]
  • (2)注意,图像的固定碎片对应于卷积与互相关中输出图的不同索引。这是因为在卷积中,内核自下而上/从右向左遍历图像,而在互相关中,内核自上而下/从左向右遍历图像。

理解卷积和互相关之间的区别将有助于理解反向传播在 CNN 中是如何工作的,这是未来帖子的主题。

参考

  • 卷积与互相关,来自 Udacity“计算摄影”的视频(还有,第 10 课的所有内容,一个包含示例、动画和公式的视频系列)
  • 深度学习全书第九章(总结公式)
  • 曾 793 Akbas 第 3 周 CNN 和 RNNs (汇总公式)
  • 宋浩安的 2D 卷积示例(带索引的示例)
  • 宋浩安的卷积(带索引的例子)

关于特色图片

图片来源:佩吉培根在半空后空翻。记住…实卷积翻转内核。

原载于 2019 年 7 月 26 日http://glassboxmedicine.com

用于图像降噪的卷积自动编码器

原文:https://towardsdatascience.com/convolutional-autoencoders-for-image-noise-reduction-32fce9fc1763?source=collection_archive---------0-----------------------

在“自动编码器异常检测变得简单中,我提到自动编码器已经广泛应用于降维图像降噪。从那时起,许多读者问我是否可以使用自动编码器来降低图像噪声。这就是这篇文章的动机。

在神经网络世界中,对图像数据建模需要一种特殊的方法。用于对图像数据建模的最著名的神经网络是卷积神经网络(CNN,或 ConvNet)。可以更好的保留一幅图像像素之间的连通信息。CNN 中各层的特殊设计使其成为处理图像数据的更好选择。

CNN 设计可用于图(1)所示的图像识别/分类,或用于图(2)所示的图像降噪或着色。在图(1)中,我们通过将许多图像样本作为输入并将标签作为输出来训练 CNN 模型。然后我们用这个训练好的 CNN 模型对一个新的图像进行识别,看它是“狗”,还是“猫”等等。CNN 也可以用作图像降噪或着色的自动编码器。

当 CNN 用于图像降噪或着色时,它应用于自动编码器框架中,即,CNN 用于自动编码器的编码和解码部分。图(2)显示了一个 CNN 自动编码器。每个输入图像样本是具有噪声的图像,并且每个输出图像样本是没有噪声的对应图像。我们可以将训练好的模型应用于有噪声的图像,然后输出清晰的图像。同样,它可以用于训练图像着色的模型。图(2)是一个使用 CNN 自动编码器为图像着色的例子。

Figure (2)

在这篇文章中,让我先简单介绍一下图像数据,因为并非所有读者都熟悉图像数据领域(如果您已经熟悉了,请随意跳过这一部分)。然后,我描述了一个简单的标准神经网络的图像数据。这将允许我演示为什么卷积自动编码器是处理图像数据的首选方法。最重要的是,我将演示卷积自动编码器如何减少图像中的噪声。我在这篇文章中使用了 Keras 模块和 MNIST 数据。笔记本可以通过 Github 链接获得。 Keras 是一个高级神经网络 API,用 Python 编写,能够在 TensorFlow 之上运行。这篇文章是我之前的文章“什么是图像识别”的延伸。“我鼓励你去看一看。

我认为提及三大数据类别是有帮助的。这三个数据类别是(1)多元数据(与串行数据相反),(2)串行数据(包括文本和语音流数据),以及(3)图像数据。深度学习有三种基本变化来解决每个数据类别: (1)标准前馈神经网络,(2) RNN/LSTM,以及(3)卷积神经网络(CNN)。对于正在寻找每种类型教程的读者,建议查看《用回归友好的方式解释深度学习》的(1),当前文章《RNN/LSTM/GRU 股价预测技术指南》的(2),以及《用 PyTorch 进行深度学习不是折磨》,《什么是图像识别?、使用自动编码器的异常检测变得容易、用于图像降噪的卷积自动编码器(3)。您可以将摘要文章“ Dataman 学习之路——培养您的技能,推动您的职业发展”加入书签。

理解图像数据

如图(A)所示,图像由“像素”组成。在黑白图像中,每个像素由一个从 0 到 255 的数字表示。今天大多数图像使用 24 位或更高的颜色。RGB 彩色图像意味着像素中的颜色是红色、绿色和蓝色的组合,每种颜色的范围从 0 到 255。RGB 颜色系统从红色、绿色和蓝色的组合中构建所有颜色,如该 RGB 颜色生成器所示。所以一个像素包含一组三个值 RGB(102,255,102)指颜色 #66ff66。

Figure (A)

800 像素宽、600 像素高的图像具有 800 x 600 = 480,000 像素= 0.48 兆像素(“兆像素”是 100 万像素)。分辨率为 1024×768 的图像是具有 1,024 列和 768 行的网格,因此包含 1,024 × 768 = 0.78 兆像素。

[## 通过我的推荐链接加入 Medium-Chris Kuo/data man 博士

阅读 Chris Kuo/data man 博士的每一个故事。你的会员费直接支持郭怡广/戴塔曼博士和其他…

dataman-ai.medium.com](https://dataman-ai.medium.com/membership)

MNIST

MNIST 数据库(改进的国家标准和技术研究所数据库)是一个手写数字的大型数据库,通常用于训练各种图像处理系统。Keras 中的训练数据集有 60,000 条记录,测试数据集有 10,000 条记录。每条记录有 28 x 28 个像素。

他们长什么样?让我们用matplotlib和它的图像函数imshow()来显示前十条记录。

堆叠用于训练的图像数据

为了适合用于模型训练的神经网络框架,我们可以将所有 28 x 28 = 784 个值堆叠在一列中。第一条记录的堆叠列如下所示:(使用x_train[1].reshape(1,784)):

Figure (B): Part of the values

然后我们可以用标准的神经网络来训练模型,如图(B)所示。784 个值中的每一个都是输入层中的一个节点。但是等等,我们叠加数据的时候不是损失了很多信息吗?是的。图像中的空间和时间关系已被丢弃。这是很大的信息损失。让我们看看卷积自动编码器如何保留空间和时间信息。

Figure (B)

为什么卷积自动编码器适用于图像数据?

当分割和堆叠数据时,我们看到大量信息丢失。卷积自动编码器不是堆叠数据,而是保持输入图像数据的空间信息不变,并在所谓的卷积层中温和地提取信息。图(D)展示了平面 2D 图像被提取到一个厚正方形(Conv1),然后继续变成一个长立方体(Conv2)和另一个更长的立方体(Conv3)。此过程旨在保留数据中的空间关系。这是自动编码器中的编码过程。在中间,有一个全连接的自动编码器,其隐藏层仅由 10 个神经元组成。接下来是解码过程,使立方变平,然后变成 2D 平面图像。编码器和解码器在图(D)中是对称的。它们不需要对称,但是大多数从业者只是采用了这个规则,如“使用自动编码器的异常检测变得容易”中所解释的。

Figure (D)

卷积自动编码器如何工作?

上面的数据提取看起来很神奇。这是怎么回事?它包括以下三层:卷积层、reLu 层和池层。

Figure (E): The Feature Maps

  1. 卷积层

卷积步骤创建了许多称为特征地图特征的小块,如图(E)中的绿色、红色或深蓝色方块。这些方块保留了输入图像中像素之间的关系。让每个特征扫描原始图像,如图(F)所示。这个产生分数的过程叫做过滤

Figure (F): The Filtering Process

在扫描原始图像后,每个特征产生一个如图(G)所示的具有高分和低分的过滤的图像。如果完全匹配,则该方块得分高。如果匹配度低或不匹配,则得分低或为零。例如,红色方块在原始图像中找到了四个与该特征完全匹配的区域,因此这四个区域的得分很高。

Figure (G)

更多的过滤器意味着模型可以提取更多的特征。然而,更多的功能意味着更长的训练时间。因此建议您使用最少数量的过滤器来提取特征。

1.1 填充

特征如何确定匹配?一个超参数是填充,它提供了两个选项:(I)用零填充原始图像以适合该特征,或者(ii)丢弃原始图像中不适合的部分并保留有效部分。

1.2 步

卷积层包括另一个参数:步幅。它是在输入矩阵上移动的像素数。当跨距为 1 时,滤镜一次移动一个像素。我们将在 Keras 代码中看到它作为一个超参数。

2。重新执行步骤

校正线性单元(ReLU)是与典型神经网络中的步骤相同的步骤。它会将任何负值修正为零,以保证数学运算正确进行。

3。最大池层

池会缩小图像大小。在图(H)中,一个被称为池大小的 2×2 窗口扫描通过每个过滤的图像,并将该 2×2 窗口的最大值分配给新图像中的 1×1 正方形。如图(H)所示,第一个 2 x 2 窗口中的最大值是高分(用红色表示),因此高分被分配给 1 x 1 正方形。

Figure (H): Max Pooling

除了取最大值,其他不太常用的汇集方法包括平均汇集(取平均值)或总和汇集(总和)。

Figure (J)

合并后,会产生一个新的较小的过滤图像堆栈。现在,我们分割较小的过滤图像,并将它们堆叠成一个列表,如图(J)所示。

Keras 中的型号

以上三层是卷积神经网络的构造块。Keras 提供以下两种功能:

  • Conv2D(filters, kernel_size, activation = 'reLu', strides=1):kernel_size是 2D 卷积窗的高度和宽度。因为我们在图(E)中使用了一个 2 乘 2 的正方形,所以在我们的例子中,kernel_size 将是(2,2)。stride是在输入矩阵上移动的像素数。我们的步幅是 1,因为我们一次移动一个像素的过滤器。
  • MaxPooling2D(pool_size=(2,2)):在图(H)中,我们使用 2 乘 2 的窗口来表示池的大小。所以我们将在下面的代码中使用(2,2)。

您可以在卷积自动编码器中构建许多卷积层。在图(E)中,编码部分有三层,分别标记为 Conv1、Conv2 和 Conv3。所以我们会相应地建造。

  • 下面的代码input_img = Input(shape=(28,28,1)声明输入的 2D 图像是 28 乘 28。
  • 然后构建三层 Conv1、Conv2 和 Conv3。
  • 注意,Conv1 位于 Conv2 内部,Conv2 位于 Conv3 内部。
  • padding指定当滤波器不适合输入图像时该做什么。padding='valid'表示当滤镜不适合时,丢弃图像的部分;padding='same'用零填充图片以适合图片。

然后继续添加解码过程。所以下面的decoding部分有所有的编码和解码。

Keras API 需要声明模型和优化方法:

  • Model(inputs= input_img,outputs= decoded):给定输入数据input_img,模型将包括计算输出decoded所需的所有层。compile(optimizer='adadelta',loss='binary_crossentropy'):优化器像梯度下降一样执行优化。最常见的是随机梯度下降(SGD)、适应梯度(Adagrad)和 Adadelta(Adagrad 的扩展)。详见 Keras 优化器文档。损失函数可在 Keras 损失文件中找到。

下面我使用 x_train 作为输入和输出来训练这个模型。batch_size是样本数,epoch是迭代次数。我指定shuffle=True要求在每个时期之前混洗训练数据。

我们可以打印出前十幅原始图像和对这十幅图像的预测。

如何构建图像降噪卷积自动编码器?

图像降噪的思想是用噪声数据作为输入,它们各自的清晰数据作为输出来训练模型。这是与上述模型的唯一区别。让我们首先给数据添加噪声。

前十幅有噪声的图像如下所示:

然后,我们用有噪声的数据作为输入,干净的数据作为输出来训练模型。

最后,我们打印出前十个噪声图像以及相应的去噪声图像。

笔记本可以通过这个 Github 链接获得。

有没有我可以使用的预先训练好的 CNN 代码?

是的。如果你有兴趣学习代码, Keras 有几个预先训练好的 CNN,包括 Xception 、 VGG16 、 VGG19 、 ResNet50 、 InceptionV3 、 InceptionResNetV2 、 MobileNet 、 DenseNet 、值得一提的是这个大型图像数据库 ImageNet ,你可以贡献或下载用于研究目的。

[## 通过我的推荐链接加入 Medium-Chris Kuo/data man 博士

阅读 Chris Kuo/data man 博士的每一个故事。你的会员费直接支持郭怡广/戴塔曼博士和其他…

dataman-ai.medium.com](https://dataman-ai.medium.com/membership)

卷积神经网络:逐步指南

原文:https://towardsdatascience.com/convolutional-neural-network-a-step-by-step-guide-a8b4c88d6943?source=collection_archive---------6-----------------------

“人工智能、深度学习、机器学习——不管你在做什么,如果你不懂,就去学吧。因为否则,你会在三年内变成恐龙”——马克·库班,连续创业者

您好,欢迎, 野心家

如果你正在阅读这篇文章,并且对这个话题感兴趣,我假设你熟悉深度学习和机器学习的基本概念。

如果没有,也不用担心!该教程旨在从头到尾让你开始学习深度学习技能——从感知机到深度学习。

在本教程中,我们将触及神经网络、模型和算法的各个方面,一些用例、要使用的库,当然还有深度学习的范围。除此之外,还将讨论深度学习的其他重要概念。

第一步:先决条件

任何一个汤姆、迪克和哈里都不可能只是听说深度学习的奇迹,培养兴趣并开始一个教程。必须有一个好的学习方法,这就是为什么我们为你们奠定了基础工作。以下几点强调了在开始学习之前你需要做的事情:

  • R/Python 知识: 这是深度学习最常用和首选的两种语言。其中一个主要原因是两者都有足够的支持/社区。在你进入机器学习的世界之前,在你方便的时候选择其中的一个。毋庸置疑,Python 是领先领域;不过这里可以看到对比。
  • 对线性代数、微积分和概率的基本理解: 每堂课都有数量惊人的在线视频和课程,其中许多是免费的。我们并不建议你磨练技巧,只是为了更好地理解教程而复习一下。你可以试着从斯坦福的 CS231n 开始。
  • 神经网络和深度学习的初级诀窍: 正如我前面所说,网上有很多免费和付费的资源。无论如何,在线视频总是有帮助的。如果你想通读这个概念,我们建议你跟随神经网络和深度学习,这是绝对免费的。(此外,请注意深度学习初学者的 25 个必知术语&概念
  • 设置要求: 由于深度学习非常依赖计算概念,我们需要更快的机器在那个级别运行。所以,你现在需要的是:
  1. GPU (4+ GB,最好是 Nvidia)——它是当今深度学习应用的核心
  2. CPU(例如英特尔酷睿 i3 或更高版本也可以)
  3. 4 GB RAM 或取决于数据集

注意:(如果你想了解更多关于硬件的要求,可以去看看这个硬件指南,最重要的是,不要在这一步安装深度学习库。你将在本教程中被进一步告知。)

第二步:概念和技术方面的介绍

如何能一头扎进深度学习?本质上,这一切都始于神经网络,深度学习不过是那些网络的逻辑实现,从数据中提取有用的信息。从技术角度来说,它是一种对非结构化输入数据(如包括图像、声音、视频和文本在内的媒体)进行分类的谨慎方法。

首先,你需要决定哪种学习媒介最适合你的研究和学习深度学习。它可以是博客、书籍、视频或在线课程。我们列出了来源,让你从最简单的概念开始,这将帮助你逐渐掌握这个主题。

博客方法

  • 深度学习的基础——从人工神经网络开始

  • 深度学习教程:从感知机到深度网络

书本方法

  • 神经网络和深度学习(迈克尔·尼尔森的免费书籍)

  • 深度学习(麻省理工学院出版社的一本书)

视频方法

——深度学习简体

  • 神经网络班-舍布鲁克大学

在线课程方法

  • 神经网络由(11 月 27 日开始注册)

  • 吴恩达的机器学习(11 月 27 日开始报名)

  • 机器学习作者 Nando de Freitas(包含视频、幻灯片和作业列表)

亲爱的学习者,接受这样一个事实,即转变为深度学习专家需要大量的时间、许多额外的资源,以及在构建和测试模型方面的专门练习。然而,我们确实相信,利用上面列出的资源可以让你进入深度学习。

第三步: 选择你的冒险

在你掌握了基础知识之后,有趣的部分来了――深度学习最先进技术的实践经验。该领域提供了许多令人兴奋的应用和机会。深度学习的技术将根据你的兴趣和目的而变化,见下文:

计算机视觉/模式识别: 两者差别不大,因为模式识别也是计算机视觉的一部分,很多时候。然而,从广义上讲,计算机视觉仅包括分析图像,并用于对象检测、分割、基于视觉的学习等。而模式识别不限于图像。它是关于任何可以拥有一种模式的事物的分类。

若要了解,请访问此处:

计算机视觉的深度学习

CS231n:用于视觉识别的卷积神经网络

对于视频和用例:

计算机视觉详细讲座

语音和音频识别: 有没有说过“Ok Google”?我敢肯定,你做到了。它包括一个语音识别系统,可以帮助你在谷歌上找到你要找的东西。

从技术上讲,它由一种神经网络组成,这种网络涉及输入序列,以在网络图中创建循环,称为递归神经网络(RNNs)。它们被称为“递归的”,因为它们对序列的每个元素执行相同的任务,并且执行诸如机器翻译或语音识别之类的任务。

若要了解,请访问此处:

递归神经网络的不合理有效性

递归神经网络教程

了解 LSTM 网络(一种广泛使用的 RNN 变种)

对于视频:

递归神经网络的友好介绍

递归神经网络(RNN)

自然语言处理或 NLP: NPL 是一种计算机通过以智能和有用的方式模拟人类语言来阅读、分析和响应的方法。如今,技术广泛应用于多个行业领域,如广告、客户服务、保险等。实现人机交互过程的自动化。

NPL 层将用户请求或查询转换成信息,并从其数据库中搜索适当的响应。NLP 的一个高级例子是语言翻译――从一种人类语言到另一种语言。例如,英语到德语。

若要了解,请访问此处:

理解终极指南&实现自然语言处理

NLPFORHACKERS。IO

自然语言处理深度学习如何入门

对于视频:

自然语言处理简介

深度学习的自然语言处理

强化学习或 RL: 想象一个机器人被训练从它以前的行为中学习,并在需要时执行新的任务,那不是很好吗,而且是自动的!事实上,这是真的。

强化学习为计算机代理引入了类似的概念;无论在特定任务中是成功还是失败,代理人都会收到对某个对象的行为的奖励和惩罚。它获得关于它的知识,作为控制其行为的深度学习模型的一部分。

若要了解,请访问此处:

强化学习初学者指南(Java 版)

强化学习的简单初学者指南&其实现

对于视频:

深度强化学习

强化学习

第四步:选择正确的框架

我们在步骤 3 中讨论了深度学习技术的许多应用和用法。对于某些任务,传统的机器学习算法可能就足够了。但是,如果你正在处理大量的图像、视频、文本或语音,深度学习是你的福音和一切。然而,在深度学习中,对于许多人来说,哪个框架将是正确的选择。

记住,没有正确的框架,只有合适的框架。以下是您的选择标准应该主要依据的内容:

  • 预训练模型的可用性
  • 开源
  • 支持的操作系统和平台
  • 许可模式
  • 模型定义和调整的简易性
  • 调试工具的可用性
  • 易于扩展(例如,能够编写新的算法)
  • 与研究型大学或学术界有联系
  • 支持深度学习算法家族和模型

为了帮助您选择一个,让我带您简单浏览一下深度学习框架:

(a)****tensor flow:背靠 Google,TensorFlow 是基于数据流图表示的数值计算通用深度学习库。

-试试它的入门教程

-要安装 TensorFlow,请访问此处

-参考其文档

-看看它的白皮书

(b) Theano: 数学表达式编译器 Theano 是一种积极开发的架构,它有效地定义、优化和评估具有多维数组的数学表达式。

-试用一个入门教程

-要安装 Theano,请访问此处

-将文件放在手边

(c) Caffe: 虽然 Theano 和 TensorFlow 可以成为你的“通用”深度学习库,但 Caffe 是通过牢记表达式、速度和模块化来制作的。该框架由计算机视觉小组开发,能够实现简单灵活的深度学习来组织计算。对其更新,咖啡 2 也可用。

-要安装 Caffe,请访问此处获取 Caffe 和 Caffe2

-熟悉介绍性教程演示

-在这里你可以找到它的文档

(d) 微软认知工具包:微软认知工具包——以前称为 CNTK——是一个统一的深度学习工具包,可以跨多个 GPU 和服务器轻松实现和组合流行的模型类型,如 CNN、RNN、LTSM 等。

-要安装微软认知工具包,请访问此处

-如需教程,请点击此处的

  • 模型库各种用例的代码样本、配方和教程的集合。

请注意,上面列出的体系结构并不是当今使用的唯一流行的库。我们列举了一些主要特征:

  • 克拉斯

-用 Python 写的;一个极简和高度模块化的神经网络库

-能够在 Theano 或 TensorFlow 上运行

-支持快速实验。

  • 火炬

-科学计算框架

-为机器学习算法提供广泛支持

-基于 Lua 编程语言

  • 链条
  • Python 支持的,灵活直观的神经网络库

-根据运行定义的原则设计

-允许您在运行时修改网络

要了解更多基于标准的选择和对其他框架的详细审查,请访问页面- 如何选择深度学习框架(我们建议您将该链接加入书签,因为它会经常更新)。

第五步:探索深度学习

深度学习是一个复杂而突出的人工智能领域,真正的奇迹正在这里发生。引导深度学习领域的三个关键点是:

  1. 大量训练数据的可用性
  2. 强大的计算基础设施
  3. 学术界的进展

然而,要开创深度学习,你需要做的很简单:

  • 从第 2 步到第 4 步重复,每次都有不同的经历
  • 继续测试你的深度学习技能(例如 Kaggle
  • 加入深度学习社区并提问(例如 Google Group 、 DL Subreddit )
  • 关注最近的研究/研究人员(例如被引用最多的深度学习论文)

尾注

今天,几年前和我们一样也是学习者的研究人员,正在努力挑战技术领域的不可能性。一开始,你可能会发现学习概念有困难,但是,坚韧是关键。

你可能会发现自己对深度学习算法感到困惑,并认为为什么它没有像你预期的那样工作,或者为什么我会得到这个错误 ABC?…相信我,这很正常。如果需要,先尝试一个您认为可以在一小组数据上工作的示例算法。

在这个学习领域,尝试一切对你有意义的事情。当你获得新技能的时候,试着用你的头脑创造一些不同的东西。还记得电影《蜘蛛侠》中的对白吗——“能力越大,责任越大。”深度学习的趋势正在不停地上升。要在深度学习名人堂留下印记,宇宙向你敞开。出来展示你的才华吧,因为还有很多东西没有被发掘。

最后,我请求你们支持(鼓掌)这篇文章并分享它,这样我们就不会留下任何有抱负的人才,也不会错过任何即将到来的发明机会!!爱你们所有人…

卷积神经网络用于乳腺癌分类

原文:https://towardsdatascience.com/convolutional-neural-network-for-breast-cancer-classification-52f1213dcc9?source=collection_archive---------3-----------------------

深度学习用于解决女性中最常诊断的癌症

Photo by Tamara Bellis on Unsplash

被困在付费墙后面?点击这里阅读完整故事与我的朋友链接!

乳腺癌是全世界女性和男性中第二常见的癌症。2012 年,它占所有新癌症病例的 12%,占所有女性癌症的 25%。

当乳房中的细胞开始不受控制地生长时,乳腺癌就开始了。这些细胞通常会形成一个肿瘤,通常可以在 x 射线上看到或摸到一个肿块。如果细胞可以生长(侵入)周围组织或扩散(转移)到身体的远处区域,则肿瘤是恶性的(癌症)。

挑战

建立一种算法,通过查看活检图像自动识别患者是否患有乳腺癌。算法必须非常精确,因为人命关天。

数据

数据集可以从这里下载。这是一个二元分类问题。我把数据分开,如图所示-

dataset train
  benign
   b1.jpg
   b2.jpg
   //
  malignant
   m1.jpg
   m2.jpg
   //  validation
   benign
    b1.jpg
    b2.jpg
    //
   malignant
    m1.jpg
    m2.jpg
    //...

训练文件夹在每个类别中有 1000 个图像,而验证文件夹在每个类别中有 250 个图像。

Benign sample

Malignant sample

CNN 架构

让我们一步一步来分析卷积神经网络中的每一层。

投入

形状为[宽度、高度、通道]的像素值矩阵。假设我们的输入是[32x32x3]。

卷积

该图层的目的是接收要素地图。通常,我们从低数量的滤波器开始进行低级特征检测。我们越深入 CNN,我们使用越多的过滤器来检测高级特征。特征检测是基于用给定尺寸的过滤器“扫描”输入,并应用矩阵计算来导出特征图。

Convolution Operation

联营

这一层的目标是提供空间变化,这简单地意味着系统将能够识别一个对象,即使它的外观以某种方式变化。Pooling layer 将沿空间维度(宽度、高度)执行缩减采样操作,从而产生输出,例如 pooling_size=(2,2)的[16x16x12]。

Pooling Operation

完全连接

在完全连接的层中,我们展平最后一个卷积层的输出,并将当前层的每个节点与下一层的其他节点连接起来。完全连接层中的神经元与前一层中的所有激活都有完全连接,正如在常规神经网络中看到的那样,并以类似的方式工作。

CNN Overview

图像分类

完整的图像分类管道可以形式化如下:

  • 我们的输入是一个由 N 幅图像组成的训练数据集,每幅图像都被标记为两个不同类别中的一个。
  • 然后,我们使用这个训练集来训练一个分类器,以学习每个类的样子。
  • 最后,我们通过要求分类器预测一组它以前从未见过的新图像的标签来评估分类器的质量。然后,我们将这些图像的真实标签与分类器预测的标签进行比较。

代码在哪里?

事不宜迟,让我们从代码开始吧。github 上的完整项目可以在这里找到。

让我们从加载所有的库和依赖项开始。

接下来,我将图片加载到各自的文件夹中。

之后,我创建了一个由 0 组成的 numpy 数组来标记良性图像,同样也创建了一个由 1 组成的 numpy 数组来标记恶性图像。我还重组了数据集,并将标签转换成分类格式。

然后,我将数据集分成两组——分别包含 80%和 20%图像的训练集和测试集。让我们看一些良性和恶性图像的样本。

Benign vs malignant samples

我使用的批量值是 16。批量大小是深度学习中要调整的最重要的超参数之一。我更喜欢使用较大的批量来训练我的模型,因为它允许 GPU 并行性的计算加速。然而,众所周知,批量太大会导致泛化能力差。在一个极端情况下,使用等于整个数据集的批次保证了收敛到目标函数的全局最优。然而,这是以较慢地收敛到最优值为代价的。另一方面,使用较小的批量已被证明具有更快的收敛到良好的结果。这可以通过以下事实直观地解释,即较小的批量允许模型在必须看到所有数据之前就开始学习。使用较小批量的缺点是模型不能保证收敛到全局最优。因此,通常建议从小批量开始,获得更快的训练动态的好处,并通过训练稳步增加批量。

我也做了一些数据扩充。数据扩充的做法是增加训练集规模的有效方法。增加训练示例允许网络在训练期间看到更多样化但仍有代表性的数据点。

然后,我创建了一个数据生成器,以自动方式从我们的文件夹中获取数据并导入 Keras。为此,Keras 提供了方便的 python 生成器函数。

下一步是构建模型。这可以通过以下 3 个步骤来描述:

  1. 我使用 DenseNet201 作为预训练的重量,它已经在 Imagenet 比赛中训练过。学习率被选择为 0.0001。
  2. 在此基础上,我使用了一个 globalaveragepooling 层,然后是 50%的辍学,以减少过度拟合。
  3. 我使用了批量标准化和一个具有 2 个神经元的密集层,用于 2 个输出类别,即良性和恶性,使用 softmax 作为激活函数。
  4. 我用 Adam 作为优化器,用二元交叉熵作为损失函数。

让我们看看输出的形状和每一层所涉及的参数。

Model summary

在定型模型之前,定义一个或多个回调是有用的。相当方便的一个,有:ModelCheckpoint 和 ReduceLROnPlateau。

  • ModelCheckpoint :当训练需要大量时间来达到一个好的结果时,通常需要多次迭代。在这种情况下,最好仅在改善度量的时期结束时保存最佳执行模型的副本。
  • ReduceLROnPlateau :当指标停止改善时,降低学习率。一旦学习停滞,模型通常会受益于将学习速度降低 2-10 倍。这种回调监控一个数量,如果在“耐心”次数内没有看到改进,则学习率降低。

ReduceLROnPlateau.

我训练了 20 个纪元的模型。

性能指标

评估模型性能的最常见指标是精确度。然而,当只有 2%的数据集属于一个类别(恶性)而 98%属于其他类别(良性)时,错误分类分数实际上没有意义。你可以有 98%的准确率,但仍然没有发现任何恶性病例,这可能是一个可怕的分类器。

Loss vs epoch

Accuracy vs epoch

精确度、召回率和 F1 分数

为了更好地了解错误分类,我们经常使用以下指标来更好地了解真阳性(TP)、真阴性(TN)、假阳性(FP)和假阴性(FN)。

精度是正确预测的正观测值与总预测正观测值的比率。

召回是正确预测的正面观察值与实际类中所有观察值的比率。

F1-Score 是准确率和召回率的加权平均值。

F1 分数越高,模型越好。对于所有三个指标,0 是最差的,而 1 是最好的。

混淆矩阵

在分析误分类时,混淆矩阵是一个非常重要的度量。矩阵的每一行代表预测类中的实例,而每一列代表实际类中的实例。对角线代表已被正确分类的类别。这很有帮助,因为我们不仅知道哪些类被错误分类,还知道它们被错误分类为什么。

Confusion matrix

ROC 曲线

45 度线是随机线,其中曲线下面积或 AUC 是 0.5。曲线离这条线越远,AUC 越高,模型越好。一个模型能得到的最高 AUC 是 1,其中曲线形成一个直角三角形。ROC 曲线也可以帮助调试模型。例如,如果曲线的左下角更接近随机线,则暗示模型在 Y=0 处分类错误。然而,如果右上角是随机的,则意味着误差发生在 Y=1 处。

ROC-AUC curve

结果

Final results

结论

虽然这个项目还远未完成,但在如此多样的现实世界问题中看到深度学习的成功是令人瞩目的。在这篇博客中,我展示了如何使用卷积神经网络和迁移学习从一组显微图像中对良性和恶性乳腺癌进行分类。

参考资料/进一步阅读

[## 基于迁移学习的 Keras 图像分类

迁移学习的一站式指南

towardsdatascience.com](/transfer-learning-for-image-classification-in-keras-5585d3ddf54e) [## 在 Keras 中使用卷积神经网络(CNN)预测浸润性导管癌

使用卷积神经网络将组织病理学切片分类为恶性或良性

towardsdatascience.com](/predicting-invasive-ductal-carcinoma-using-convolutional-neural-network-cnn-in-keras-debb429de9a6) [## 乳腺癌组织病理学图像分类使用卷积神经网络与小…

尽管从组织病理学图像中成功检测恶性肿瘤在很大程度上取决于长期的…

journals.plos.org](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0214587) [## 基于深度学习的少数据图像分类

深度学习确实可以用更少的数据实现

becominghuman.ai](https://becominghuman.ai/deep-learning-for-image-classification-with-less-data-90e5df0a7b8e)

在你走之前

相应的源代码可以在这里找到。

[## abhinavsagar/乳腺癌-分类

使用卷积神经网络的良性与恶性分类器数据集可以从这里下载。pip 安装…

github.com](https://github.com/abhinavsagar/Breast-cancer-classification)

联系人

如果你想了解我最新的文章和项目,请关注我的媒体。以下是我的一些联系人详细信息:

  • 个人网站
  • 领英
  • 中等轮廓
  • GitHub
  • 卡格尔

快乐阅读,快乐学习,快乐编码!

基于 PyTorch 实现的图像分类深度学习

原文:https://towardsdatascience.com/convolutional-neural-network-for-image-classification-with-implementation-on-python-using-pytorch-7b88342c9ca9?source=collection_archive---------8-----------------------

http://terencebroad.com/nnvis.html

对人工智能算法的探究

介绍

本文将以图像分类为例来解释卷积神经网络(CNN)。它使用 Python 上的 PyTorch 框架提供了 CNN 算法的简单实现。网上有很多免费的课程。个人建议斯坦福的安德烈·卡帕西(@卡帕西)的课程。你会学到很多,这是一个循序渐进的过程。此外,它还提供了许多实现 CNN 架构的实用策略。

[## 用于视觉识别的 CS231n 卷积神经网络

斯坦福 CS231n 课程材料和笔记:视觉识别的卷积神经网络。

cs231n.github.io](http://cs231n.github.io/convolutional-networks/)

什么是卷积神经网络?

在深入研究卷积神经网络之前,有必要了解一下它们的概念。CNN 属于监督算法的范畴。该算法从训练数据中学习,例如,输入中的一组图像和输出中的它们的相关标签。

它包括向卷积神经网络提供训练集 x 的图像及其相关联的标签(目标)y,以便学习网络的功能 y=f(x)。在学习了网络函数的参数(即权重和偏差)之后,我们用看不见的图像来测试网络,以便预测它们的标签。卷积神经网络(CNN 或 ConvNet)的架构

我们在本文中使用的 CNN 架构是在本文中提出的。

Illustration of the image classification using CNN architecture

使用 PyTorch 库在 Python 中实现 CNN(如上图所示)

网络实现为一个名为 CNN 的类。它包含两个主要方法。第一种方法(init)定义网络的层组件。在第二种方法( forward )中,我们连接网络,并按照所需的顺序放置每个组件(如图所示)。

下面的 python 代码很简单。使用 Torch 的神经网络模块来定义网络。请注意,我们已经选择了网络的超参数,如填充(P)、步幅(S)和内核大小(F)。还有每层的过滤器数量,…

输入图像有四个维度,(批量大小、数量通道、高度、宽度)。该算法输出具有 10 个值的数组,对应于图像的预测标签的分数(或能量值)。因此,最大分数是为测试图像保留的预测标签(或类别)。

在下面的要点中,我们将解释算法每一层的作用:

  • Conv 层:这是算法的主层。它包括提取输入图像中的关键特征(锐边、平滑度、圆形等)。这是通过用一个或多个滤波器对输入图像进行一组二维卷积来实现的。注意,卷积是针对输入图像的每个通道同时执行的,例如,彩色图像具有 C=3 个通道,RGB:红色、绿色和蓝色。出于实用目的,滤波器设置为奇数大小 CxFxF,例如 3x3x3、3x5x5。这个操作的输出是一个标量值,一个人工神经元。http://cs231n.github.io/convolutional-networks/#conv 的中给出了卷积层的说明性动画。

Source: http://cs231n.github.io/convolutional-networks/#conv

此外,Conv 层被重复应用以提取表征输入图像的精细特征。Conv 层的输出被称为特征图(或激活图),其中每个空间位置(或像素)代表一个人工神经元。

  • ReLU(整流器线性单元):将负值硬阈值化为零,正值不变,即 ReLU(x)=max(0,x)。该图层保留了要素地图的动态范围。

  • Maxpooling layer :对特征图进行空间下采样,只保留最相关的信息。有关此操作的直观说明,请参见下图。从实用的角度来看,大小为 2x2、步幅为 2 的池在大多数应用程序中都能产生良好的效果。话虽如此,其他类型的池存在,例如,平均池,中位数池,总和池,…

CNN 的 Python 实现怎么样?

对于本文,我使用神经网络框架 PyTorch 来实现上面详述的 CNN 架构。

完整的代码可以在我的 GitHub 资源库中找到:

[## MNIST 图像分类

该存储库包含用于 MNIST 数据集影像分类的笔记本…

github.com](https://github.com/amineHY/Image-classification-of-MNIST/blob/master/pytorch_mnist_deep_cnn.ipynb)

希望代码非常容易理解,因为它以直观的方式提到了我们前面讨论的所有层。

Implementation of the convolutional neural network depicted in the picture above in PyTorch

请注意,方法输入中提到的所有数字都是参数。它们定义了 CNN 的架构:内核大小、步幅、填充、每个 Conv 层的输入/输出。下面的代码定义了一个名为 CNN 的类,我们在其中按顺序定义了 CNN 架构。

上述代码的输出总结了网络架构:

CNN(
  (layer1): Sequential(
    (0): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Dropout(p=0.30)
  )
  (layer2): Sequential(
    (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Dropout(p=0.30)
  )
  (layer3): Sequential(
    (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=1, dilation=1, ceil_mode=False)
    (3): Dropout(p=0.30)
  )
  (fc1): Linear(in_features=2048, out_features=625, bias=True)
  (layer4): Sequential(
    (0): Linear(in_features=2048, out_features=625, bias=True)
    (1): ReLU()
    (2): Dropout(p=0.30)
  )
  (fc2): Linear(in_features=625, out_features=10, bias=True)
)

MNIST 数据集:导入训练集和测试集

为了获得 MNIST 图像,我们使用了一种 torchvision 库的方法。只需复制粘贴这段代码来下载数据。基本上,加载了两个数据集。训练数据集用作计算网络参数的基础事实。测试图像

训练 CNN

这是监督算法的一个重要阶段。通过向算法提供许多图像示例及其相关标签,我们教会算法寻找每一类的模式。这是通过计算滤波器的参数(权重和偏差)来完成的。

网络的训练由向前和向后两个主要步骤组成:

  • 在正向传递期间,我们通过训练集的图像来馈送网络,并计算直到网络末端的特征图,然后我们计算损失函数来测量解(预测标签)离地面真实标签有多远/多近。
  • 后向过程执行损失函数梯度的计算,并更新滤波器的参数。

我们还需要定义一个损失函数,例如交叉熵损失函数,以及一个优化算法,例如梯度下降、SGD、Adam (自适应矩估计 ) …

Source: https://arxiv.org/pdf/1412.6980.pdf

  • 训练深度学习算法要记住什么:

—初始化参数(权重:w,偏差:b)
—迭代优化损失以学习参数(w,b)
—计算损失函数及其梯度
—使用优化算法更新参数(例如,Adam)
—使用学习的参数来预测给定输入图像的标签

使用 PyTorch 在 Python 中训练 CNN 的 Python 实现

训练监控:绘制损失函数和精确度

绘制这些图有助于监控和理解算法的收敛性。由于优化算法(Adam)的目标是最小化损失函数,所以损失图在训练期间减小,这正是我们想要的。在右侧,该图显示了训练期间分类准确度的演变。我们对算法训练得越多,分类精度就越好。注意精度在大约 90%和 100 %之间波动。超参数的更好调整将提供精确的分类。

显示分类结果

由于 CNN 的训练,该算法现在能够理解这些图像的内容。

结论

本文试图简要解释卷积神经网络,而不深入数学发展。每一步都提供了一个插图,并附有直观的解释,以及 MNIST 数据集图像分类的应用。最后,给出了一个使用 PyTorch 库的 python 实现,以提供一个具体的应用实例。希望你会发现它有趣且易于阅读。

下一步怎么办?

  • 请在评论区告诉我你的想法,或者直接在 LinkedIn 上给我发消息。
  • 阅读我在 medium 上的另一篇文章:你在部署之前优化过你的深度学习模型吗?

如何用 Python (TensorFlow Eager API)训练卷积神经网络

原文:https://towardsdatascience.com/convolutional-neural-networks-an-introduction-tensorflow-eager-api-7e99614a2879?source=collection_archive---------18-----------------------

Keep an eye out for Deep Learning. Source: Pixabay.

卷积神经网络是过去十年深度学习经常成为头条新闻的一部分。今天我们将使用 TensorFlow 的 eager API 训练一个图像分类器来告诉我们一幅图像中包含的是一只狗还是一只猫。

由于人工神经网络在许多领域具有前所未有的能力,它最近已经颠覆了几个行业。然而,不同的深度学习架构在每个方面都很出色:

  • 图像分类(卷积神经网络)。
  • 图像、音频和文本生成(GANs、RNNs)。
  • 时间序列预测(RNNs,LSTM)。
  • 推荐系统。
  • 巨大的等等(例如,回归)。

今天我们将关注列表中的第一项,尽管每一项都值得单独写一篇文章

什么是卷积神经网络?

在多层感知器(MLP)中,香草神经网络,每层的神经元连接到下一层的所有神经元。我们称这种类型的层为完全连接的层。

A MLP. Source: astroml

卷积神经网络是不同的:它们有卷积层。

在完全连接的层上,每个神经元的输出将是前一层的线性变换,由非线性激活函数组成(例如, ReLuSigmoid )。

相反,卷积层中每个神经元的输出只是前一层神经元的一个(通常很小)子集的函数。

Source: Brilliant

卷积层上的输出将是对前一层神经元的子集应用卷积的结果,然后是激活函数。

什么是卷积?

给定一个输入矩阵 A (通常是前一层的值)和一个被称为内核滤波器 K 的权重矩阵(通常小得多),卷积运算将输出一个新的矩阵 B

by @RaghavPrabhu

如果 K 是一个 CxC 矩阵,那么 B 中的第一个元素将是以下结果:

  • A 的第一个 CxC 子矩阵。
  • 将每个元素乘以其在 K 中的相应权重。
  • 添加所有产品。

这最后两个步骤相当于展平 A 的子矩阵和 K ,并计算结果向量的点积。

然后我们向右滑动 K 以获得下一个元素,依此类推,对每一行重复这个过程。

Convolution visualization by @RaghavPrabhu

根据我们的需要,我们只能从以第 Cth 行和列为中心的内核开始,以避免“越界”,或者假设“A 之外”的所有元素都有某个默认值(通常为 0)——这将定义 B 的大小是小于 A 还是相同。

如你所见,如果 A 是一个 NxM 矩阵,那么现在 B 中每个神经元的值将不取决于 NM* 权重,而只取决于其中的 CC* (少得多)。这使得卷积层比全连接层轻得多,有助于卷积模型学习得更快。

当然,我们最终会在每一层上使用许多内核(得到一堆矩阵作为每一层的输出)。然而,这仍然需要比我们的老 MLP 少得多的重量。

为什么会这样?

为什么我们可以忽略每个神经元如何影响大多数其他神经元?嗯,这整个系统成立的前提是每个神经元都受到其“邻居”的强烈影响。然而,远处的神经元对它只有很小的影响。

这个假设在图像中直观上是真实的——如果我们想到输入层,每个神经元将是一个像素或一个像素的 RGB 值。这也是为什么这种方法对图像分类如此有效的部分原因。

例如,如果我拍摄一张照片中有蓝天的区域,很可能附近的区域也会使用相似的色调来显示天空。

像素的相邻像素通常具有相似的 RGB 值。如果他们没有,那么这可能意味着我们在一个图形或物体的边缘。

如果你用笔和纸(或计算器)做一些卷积,你会意识到如果在某种边缘上,某些内核会增加输入的强度。在其他边缘,他们可以减少它。

作为一个例子,让我们考虑下面的内核 VH :

V 过滤垂直边缘(上面的颜色与下面的颜色非常不同),而 H 过滤水平边缘。注意一个是另一个的转置版本。

卷积示例

这是一窝小猫未经过滤的照片:

如果我们分别应用水平和垂直边缘滤镜,会发生以下情况:

我们可以看到一些特征变得更加明显,而另一些逐渐消失。有趣的是,每个过滤器展示了不同的功能。

这就是卷积神经网络如何学习识别图像中的特征。让它适合自己的内核权重比任何手动方法都要容易得多。想象一下,试图用手弄清楚你应该如何表达像素之间的关系…

为了真正掌握每个卷积对一张图片的影响,我强烈建议你在这个网站上玩一玩。它对我的帮助比任何书籍或教程都大。去吧,把它收藏起来。很好玩。

好了,你已经学了一些理论。现在让我们进入实际部分。

如何在 TensorFlow 中训练一个卷积神经网络?

TensorFlow 是 Python 最流行的深度学习框架。我也听说过 PyTorch 的优点,虽然我从来没有机会尝试。

我已经写了一篇关于如何用 TensorFlow 的 Eager API 训练神经网络的教程,重点是自动编码器。

今天会有所不同:我们将尝试三种不同的架构,看看哪一种做得更好。像往常一样,所有的代码都可以在 GitHub 上获得,所以你可以自己尝试或者跟着做。当然,我还会展示 Python 代码片段。

数据集

我们将训练一个神经网络来预测一幅图像是包含一只狗还是一只猫。为此,我们将使用 Kaggle 的猫狗数据集。它包含 12500 张猫和 12500 张狗的图片,分辨率各不相同。

用 NumPy 加载和预处理我们的图像数据

神经网络接收特征向量或矩阵作为输入,通常具有固定维度。我们如何从我们的照片中产生这种感觉?

幸运的是,Python 的图像库为我们提供了一种将图像作为 NumPy 数组加载的简单方法。RGB 值的高 x 宽矩阵。
我们已经在这篇文章中这样做了,所以我将重用这段代码。

然而,我们仍然必须解决固定维度部分:我们为输入层选择哪些维度?这很重要,因为我们必须将每张图片调整到所选的分辨率。我们不想扭曲太多的长宽比,以免给网络带来太多的噪音。

下面是我们如何看到数据集中最常见的形状。

为此,我对前 1000 张图片进行了采样,尽管当我查看 5000 张图片时,结果并没有改变。最常见的形状是 375×500,尽管我决定将它除以 4 作为我们网络的输入。

这就是我们的图像加载代码现在的样子。

最后,您可以用这个代码片段加载数据。我选择使用 4096 张图片作为训练集的样本,1024 张图片作为验证集的样本。然而,这只是因为我的电脑不能处理更多的内存大小。

如果你在家尝试,可以随意增加这些数字到最大值(比如训练用的 10K 和验证用的 2500 )!

训练我们的神经网络

首先,作为一种基线,让我们看看一个普通的 MLP 在这项任务中表现如何。如果卷积神经网络如此具有革命性,我预计这个实验的结果会是可怕的

这是一个单隐层全连接神经网络。

本文的所有训练都是使用 AdamOptimizer 完成的,因为它是最快的。我只调整了每个模型的学习率(这里是 1e-5)。

这个模型我训练了 10 个纪元,基本收敛到随机猜测。我确保打乱了训练数据,因为我是按顺序加载的,这可能会使模型产生偏差。

我使用 MSE 作为损失函数,因为它通常更直观地解释。如果你的 MSE 在二进制分类中是 0.5,你就等于总是预测 0 。然而,具有更多层或不同损失函数的 MLP并没有表现得更好

训练卷积神经网络

单个卷积层能有多大好处?让我们给我们的模型加一个看看。

对于这个网络,我决定添加一个单一的卷积层(24 个内核),然后是 2 个完全连接的层。

Max Pooling 所做的只是将每四个神经元减少到一个,四个之间的值最高。

仅仅过了 5 个时代,它已经比以前的网络表现得更好了。验证 MSE 为 0.36,这已经比随机猜测好得多了。但是请注意,我不得不使用一个小得多的学习率。此外,即使它在更少的纪元中学习,每个纪元花费更长的时间。该型号也重了很多(200 多 MB)。

我决定也开始测量预测和验证标签之间的皮尔逊相关性。这款车型得分 15.2%。

两个卷积层的神经网络

因为那个模型做得更好,我决定尝试一个更大的。我添加了另一个卷积层,并使两者都大了很多(每个 48 个内核)。这意味着模型可以从图像中学习更复杂的特征。然而,这也不出所料地意味着我的内存几乎爆炸。同样,训练花费了更长的时间(15 个周期半小时)。

结果非常好。预测和标签之间的皮尔逊相关系数达到 0.21,验证 MSE 低至 0.33。

让我们来测量网络的准确性。因为 1 是猫,0 是狗,我可以说“如果模型预测的值高于某个阈值 t ,那么预测。否则预测在尝试了 10 个简单的阈值后,这个网络的最大准确度达到了 61% 。

更大的卷积神经网络

显然,增加模型的大小可以让它学习得更好,所以我试着把两个卷积层都做得更大,每个都有 128 个滤波器。我没有改动模型的其他部分,也没有改变学习率。

这个模型最后达到了 30%的关联度!它最好的准确率是 67% ,这意味着它有三分之二的时间是正确的。我认为一个更大的模型可能更符合数据。然而,这个已经花了 7 分钟了,我不想离开下一个训练一上午。

通常,在模型的尺寸时间限制之间需要做出的权衡。大小限制了网络能够多好地适应数据(一个小模型不适应),然而我不会等 3 个小时让我的模型学习。

如果你有一个商业截止日期,同样的担心也适用。

结论

我们已经看到,在图像分类任务中,卷积神经网络比传统架构明显更好(T21)。我们还尝试了不同的指标来衡量模型性能(相关性、准确性)。

我们了解了模型的尺寸(防止欠拟合)和它的收敛速度之间的权衡

最后,我们使用 TensorFlow 的 eager API 来轻松训练一个深度神经网络,并使用 numpy 进行(尽管很简单)图像预处理。

在以后的文章中,我相信我们可以用不同的池层、过滤器大小、步长和不同的预处理进行更多的实验。

你觉得这篇文章有用吗?你会更喜欢学习其他的东西吗?还有什么不清楚的吗?请在评论中告诉我!

TwitterMediumdev . to上找我如果有什么问题,或者想联系我什么的。如果你想从事机器学习事业,下面是我的* 推荐阅读清单 *

原载于 2019 年 6 月 12 日http://www . data stuff . tech

卷积神经网络

原文:https://towardsdatascience.com/convolutional-neural-networks-e5a6745b2810?source=collection_archive---------5-----------------------

研究人员在研究图像处理算法时提出了 CNN 或卷积神经网络的概念。传统的全连接网络有点像一个黑匣子,它接收所有的输入,并将每个值传递给一个密集的网络,然后再传递给一个热输出。这似乎适用于少量输入。

但是,当我们处理 1024x768 像素的图像时,我们的输入是 3x1024x768 = 2359296 个数字(每个像素的 RGB 值)。消耗 2359296 个数字的输入向量的密集多层神经网络在第一层本身中每个神经元将具有至少 2359296 个权重——第一层的每个神经元 2MB 的权重。那太疯狂了!对于处理器和内存来说。在 20 世纪 90 年代和 21 世纪初,这几乎是不可能的。

这使得研究人员想知道是否有更好的方法来完成这项工作。任何图像处理(识别或操作)的首要任务通常是检测边缘和纹理。接下来是识别和处理真实对象。如果我们同意这一点,显然要注意的是,检测纹理和边缘真的不依赖于整个图像。人们需要查看给定像素周围的像素来识别边缘或纹理。

此外,用于识别边缘或纹理的算法(不管它是什么)在整个图像中应该是相同的。我们不能对图像的中心或任何角落或侧面使用不同的算法。检测边缘或纹理的概念必须是相同的。我们不需要为图像的每个像素学习一组新的参数。

这种理解导致了卷积神经网络的出现。网络的第一层由扫描图像的小块神经元组成——一次处理几个像素。通常这些是 9 或 16 或 25 像素的正方形。

CNN 非常有效地减少了计算。小“过滤器/内核”沿着图像滑动,一次处理小块。整个图像所需的处理是非常相似的,因此这非常有效。如果你对这个主题的详细研究感兴趣,可以看看马修·d·泽勒和罗布·弗格斯的论文

虽然它是为图像处理而引入的,但多年来,CNN 已经在许多其他领域得到了应用。

一个例子

现在我们对 CNN 的基本概念有了一个概念,让我们感受一下数字是如何工作的。正如我们所见,边缘检测是任何图像处理问题的首要任务。让我们看看如何使用 CNN 来解决边缘检测问题。

左侧是 16×16 单色图像的位图。矩阵中的每个值代表相应像素的亮度。正如我们所看到的,这是一个简单的灰色图像,中间有一个方形块。当我们试图用 3×3 滤波器(在中间)卷积它时,我们得到了一个 14×14 的矩阵(在右边)。

我们选择的滤镜会高亮显示图像中的边缘。我们可以在右边的矩阵中看到,与原始图像中的边缘相对应的值很高(正或负)。这是一个简单的边缘检测滤波器。研究人员已经确定了许多不同的过滤器,可以识别和突出显示图像的不同方面。在典型的 CNN 模型开发中,我们让网络自己学习和发现这些过滤器。

重要概念

看了美国有线电视新闻网的顶级节目后,让我们向前迈进一步。在我们进一步使用有线电视新闻网之前,这里有一些我们应该知道的重要概念。

填料

卷积滤波器的一个明显问题是,每一步都通过减少矩阵大小(缩小输出)来减少“信息”。本质上,如果原始矩阵是 N x N,而滤波器是 F x F,则得到的矩阵将是(N-F+1)x(N-F+1)。这是因为边缘上的像素比图像中间的像素使用得少。

如果我们在图像的所有边上按(F-1)/2 像素填充,N x N 的大小将被保留。

因此,我们有两种类型的卷积,有效卷积和相同卷积。有效本质上意味着没有填充。因此,每次卷积都会缩小尺寸。相同卷积使用填充,以保留矩阵的大小。

在计算机视觉中,F 通常是奇数。所以这个很管用。奇数 F 有助于保持图像的对称性,也允许中心像素,这有助于在各种算法中应用统一的偏置。因此,3x3、5x5、7x7 滤清器非常常见。我们还提供 1x1 滤波器。

交错卷积

我们上面讨论的卷积是连续的,因为它连续地扫描像素。我们也可以通过在图像中移动卷积滤波器时跳过 s 个像素来实现这一点。

因此,如果我们有 n x n 个图像和 f x f 个滤波器,并使用步长 s 和填充 p 进行卷积,则输出大小为:((n + 2p -f)/s + 1) x ((n + 2p -f)/s + 1)

当然,如果这不是一个整数,我们就必须向下或向上推。

卷积 v/s 互相关

互相关本质上是矩阵在自下而上的对角线上的卷积。翻转将关联性添加到操作中。但是在图像处理中,我们不会翻转它。

RGB 图像上的卷积

现在我们有一个 n x n x 3 图像,我们用 f x f x 3 滤波器对它进行卷积。因此,我们有一个高度,宽度和数量的渠道,在任何图像及其过滤器。在任何时候,图像中的通道数都与过滤器中的通道数相同。该卷积的输出具有(n-f+1)的宽度和高度以及 1 个通道。

多个过滤器

用三通道滤波器卷积的三通道图像给我们一个单通道输出。但是我们并不仅限于一个过滤器。我们可以有多个过滤器,每个过滤器都会产生一个新的输出层。因此,输入中的通道数应与每个滤波器中的通道数相同。并且滤波器的数量与输出中的通道数量相同。

因此,我们从 3 通道图像开始,以输出中的多个通道结束。这些输出通道中的每一个都代表由相应的滤波器拾取的图像的某个特定方面。因此,它也被称为一个功能,而不是一个渠道。在真实的深度网络中,我们还添加了一个偏差和一个非线性激活函数,如 RelU。

池层

池化本质上是将多个值组合成一个值。我们可以有平均池、最大池、最小池等。因此,具有 fxf 池的 nxn 输入将生成(n/f)x(n/f)输出。它没有需要学习的参数。

Max Pooling

CNN 架构

典型的中小型 CNN 模型遵循一些基本原则。

A Typical CNN Architecture (Source Wikimedia)

  • 交替卷积和池层
  • 逐渐减小帧尺寸并增加帧数量,
  • 接近末端的平坦且完全连接的层
  • 对所有隐藏层重新激活,然后对最后一层进行软最大化

CNN 架构中的一个突出概念是交替层将信息内容一个接一个地变为稀疏和密集。这有助于分离信息的各个部分。你可以把这想象成某人在玩一个棉花球。如果我们一次又一次地推拉这些线,我们自然会将各个线分开。类似地,CNN 可以分离图像中的单个成分。

随着我们转向大型和超大型网络,事情变得越来越复杂。研究人员为我们提供了更多可以在这里使用的具体架构。ImageNet 、 GoogleNet 和 VGGNet 就是其中的几个。

履行

通常实施 CNN 模型数据分析和清理,然后选择我们可以开始使用的网络模型。我们根据网络数量的布局、层的大小以及它们的连接性来提供架构,然后我们允许网络自己学习其余部分。然后,我们可以调整超参数来生成一个足以满足我们目的的模型。

让我们看一个卷积网络如何工作的简单例子。在之前的博客中,我们看了一下用完全连接的神经网络构建 MNIST 模型。如果您想详细了解如何使用 TensorFlow 和 Keras 构建深度模型,可以查看一下。现在让我们看看用卷积网络做同样的工作。

导入模块

我们从导入所需的模块开始。

获取数据

下一步是获取数据。出于学术目的,我们使用 Keras 模块中内置的数据集——MNIST 数据集。在现实生活中,这需要更多的处理。现在,让我们继续进行。

因此,我们加载了训练和测试数据。我们对数据进行整形,使其更适合卷积网络。本质上,我们将其改造成一个 4D 数组,该数组有 60000(记录数)个大小为 28x28x1 的条目(每个图像的大小为 28x28)。这使得在 Keras 中构建卷积层变得很容易。

如果我们想要一个密集的神经网络,我们会将数据重塑为 60000 x784——每个训练图像的 1D 记录。但是 CNN 的不一样。记住卷积的概念是 2D——所以没有必要将其展平成一维数组。

我们还将标签改为分类的独热数组,而不是数字分类。最后,我们归一化图像数据,以确保我们减少了消失梯度的可能性。

建立模型

Keras 库为我们提供了现成的 API 来构建我们想要的模型。我们从创建顺序模型的实例开始。然后,我们将各个层添加到模型中。第一层是处理 28×28 的输入图像的卷积层。我们将内核大小定义为 3,并创建 32 个这样的内核,以创建 32 帧的输出,大小为 26x 26(28–3+1 = 26)

其次是 2x2 的最大池层。这将尺寸从 26x26 减小到 13x13。我们使用最大池,因为我们知道问题的本质是基于边,我们知道边在卷积中显示为高值。

随后是另一个内核大小为 3×3 的卷积层,生成 24 个输出帧。每帧尺寸为 22x22。它后面又是一个卷积层。最后,我们展平这些数据,并将其提供给一个密集层,该层具有对应于 10 个所需值的输出。

训练模型

最后,我们用现有的数据训练模型。五个时期足以获得相当精确的模型。

摘要

上面的模型只有 932 + 924 = 504 个值需要学习。这太神奇了。一个完全连接的网络在第一层中每个神经元需要 784 个权重!因此,我们大大节省了处理能力,同时降低了过度拟合的风险。请注意,在此过程中,我们使用了我们对问题的了解。我们使用我们所知道的,然后训练模型去发现其余的。使用全连接或随机稀疏网络的黑盒方法永远不会以这样的成本获得这样的精度。

通过使用我们所知道的,我们把机器限制在已知的范围内。从头开始训练网络可能会开辟未知的途径。然而,最好是留给学术研究人员。如果我们想创造一些今天可以使用的东西,一个人应该很好地融合知识和发现。卷积神经网络帮助我们实现了这一点。

下次通勤时,你的手机会成为副驾驶吗?小型设备上的障碍物和车道检测。

原文:https://towardsdatascience.com/copilot-driving-assistance-635e1a50f14?source=collection_archive---------8-----------------------

副驾驶:车道和障碍物检测,在驾驶过程中提供主动协助。让智能手机的算法既可靠又灵活

Fig 1 Collision and lane change autonomous warning

尼尔转过身来,把石碑指给他的女儿看。一家三口开车去海边度周末。“我明白了,你要我写什么回信?”坐在后座的女儿皮娅问道。"你能读出他写的内容吗?"尼尔反问道。他们的掀背车以大约每小时 40 英里的速度行驶。尼尔瞥了一眼后视镜看着皮娅。由于一时疏忽,他没有注意到前面 5 秒钟处的 SUV 紧急刹车。

他安装在挡风玻璃上的手机有一个来自前置摄像头的应用程序记录。它实时监控车辆。就在 Neel 看着镜子的时候,3 秒钟的阈值被打破了,手机发出一声警告哔哔声,就在 Pia 喊“爸爸小心”的时候。

当这家人打开行李进入酒店时,他们庆幸的是,除了侧镜外,其他人都安然无恙。

全球每年道路事故死亡人数总计约 150 万,刚好相当于毛里求斯的人口。其中 90%发生在低收入和中等收入国家,这些国家拥有的汽车数量不到世界总量的一半。不到 0.1%的车辆配备了高级驾驶辅助系统(ADAS)车道检测和碰撞警告。它们在发展中国家几乎不存在。

新兴经济体的智能手机拥有率中值约为四轮车的 10 倍。虽然我们已经有半自动车辆在世界各地行驶。这篇文章检验了我们离使用移动计算平台作为 ADAS 副驾驶还有多远。

探测车道

如果我们必须教会计算机理解道路场景,第一步是车道检测。从汽车到斑马线,我们检测到的所有其他东西都存在于我们行驶的车道环境中。我们关心的是我们车道上前方车辆的保险杠距离。

我们可以利用车道的一些特征。车道线是平行的;它们是白色或黄色的。在很大程度上,它们在整个道路上是连续的,有一个标准的宽度。对于安装在挡风玻璃上的摄像机,它们通常在图像帧周围均匀分布。从一帧到另一帧,识别的曲线将是连续的。

安装在挡风玻璃上的摄像机拍摄场景的正面。在前视图中,随着我们向地平线上移动,明显的车道宽度减小。这对于计算距离来说不是很好。正是由于这个原因,我们将卫星送入低地球轨道,拍摄鸟瞰图像,进行地形计算。作为第一步,我们需要将 dash-cam 前视图转换为俯视图。

如果我们看下面的图片,车道线似乎在地平线上相交。这就是所谓的消失点。在俯视图中,消失点或地平线附近的点比它们在前视图中相距更远。我们必须将前视图中源图像的一组点映射到顶视图中的一组图像。我们可以手动选择四个这样的点(使用路面作为指导),我们知道这些点在俯视图中会形成一个矩形,但在前视图中会显示为菱形。这一步可以使用消失点作为参考自动完成,因为我们知道菱形的所有斜边都会相交于其上。自动化对于改变摄像机位置不是很稳定(每个 dashcam 素材都有不同的位置),可能需要对过程进行一些调整

Fig -2 Obtaining Images from gray-scale images

如果我们观察图像内部表面的边缘(见上图 2❶-❹),它们似乎形成了一条线,在消失点相交。我们将 canny 滤波器应用于灰度图像,以获得代表边缘的点云。Canny 计算每个像素的亮度梯度。然后它使用阈值来过滤掉一些噪音。如果我们用灰度图像的中值作为基准,这些阈值看起来是最好的。现在,在图像的上半部分可能会有标志,这可能会增加我们后续步骤的噪声,因此我们添加了一个菱形遮罩来过滤感兴趣的区域,如❹.所示

边缘点包含嵌入在噪声中的多条线。在这些明显的线条中有一些是空白的。这些明显的线的斜率有噪声。我们需要一种稳健的方法将边缘点转化为直线。霍夫变换用于识别图像中的线条和形状,在给定一组点的情况下,使用投票算法和约束条件来决定候选线条。我已经对这些控件的图像尺寸进行了基准测试,这似乎为不同帧尺寸的线条提供了合理的预测。

有时,驾驶车辆(自我车辆)的发动机罩,甚至部分仪表板可能会进入前视图。在任何处理之前,我们应该在第一阶段就把它们剔除掉。

透视变换

我们现在已经从边缘点获得了线(见下面的图 3)。使所有这些直线的垂直距离之和最小的点就是我们的消失点。我们使用数学构造来缓解它。我们随后使用这个消失点创建一组源点(红色多边形❷的角)来映射到目的点(俯视图❸).的角)我发现将顶视图尺寸设置为 360 X 360px 似乎足够好了,即使目标图像是 720 px 高。

Fig 3 Creating a birds-eye view

我们也可以将源点的顶部边缘移向消失点。这将增加车道线曲线所基于的路面。然而,随着我们越来越接近消失点,噪声增加,因为更大的图像空间(俯视图)被挤压到前视图中更小的像素区域中。你可以在顶视图中找到两个黑色的三角形尾巴,因为我们已经在前视图图像下面取了最后一个源点。这使我们可以在俯视图中使用完整的车道区域(直到自我车辆),因为它是使用透视变换从正面图像中展开的。因此,它会留下一个黑色的三角形伪影。

从透视图像中创建遮罩

透视图像(3 通道 RGB)还不可用。我们必须将它转换为一个掩码(掩码矩阵),从中我们可以提取车道信息。这是整个过程中最棘手的一步。你必须在不同的光照条件下驾驶过汽车:黎明、中午、夜晚、阴暗处、高速公路上的森林里等等。这些变化中的一些是逐渐的,而作为建筑物/天桥阴影的一些是非常突然的。虽然我们可以在 RGB 颜色空间(255,255,255)中隔离白色通道,但黄色有点棘手。迁移到 HL S(色调、亮度、饱和度)色彩空间更容易管理,我们将使用 HLS 转换的图像作为提取蒙版的起点。

Fig 4 Using Thresholds to create a mask

我们从为白色和黄色蒙版设置一个低/高阈值开始。如果一切都是静态照明和背景,这就足够好了。然而,随着背景和照明条件的变化,我们必须每隔几秒钟更新一次阈值。最敏感的因素是较低的亮度界限(HLS 中的 l ),选择一个不正确的数字(ⓐ——ⓓ,见上面的图 4 ),其他一切都将付诸东流。在我们应用阈值之前,最好有一个标准化步骤。我们可以通过计算该区域上的平均亮度(l ),并使用该平均值来调节我们用于计算掩模的阈值,来使用紧接在车辆❷前面的路面。查看下面的 gif 图,当汽车通过天桥时,该步骤如何恢复阈值。

Fig 5 Recovering from a shadow

检测车道起点和宽度

我们现在有了从顶视图获得的遮罩。我们必须开始从中提取车道信息。作为第一步,我们需要确定左右车道的起点。在屏蔽矩阵(列的总和)的直方图上的峰值给了我们这样的结果。有时车道可能会向左/向右弯曲,因此使用汽车附近的较低 portion❷(见下图 6)来计算直方图更为谨慎。

Fig 6 Detecting the lane start

在大多数道路上,车道的标准宽度为 3.5 到 3.75 米。我们可以使用此信息将顶视图图像中的像素坐标系映射到图像所代表的真实世界坐标系。使用这个比率,俯视图中的所有位置都可以转换成现实世界中的位置。因此,我们可以报告车辆的速度、发生碰撞的时间以及道路在某一点的曲率半径。

清扫窗户

在上一步中,我们已经确定了车道起点。在这一步中,我们必须提取包含车道线的像素。同样,我们使用下面描述的滑动窗口机制。第一步是进行一次水平扫描,获得由左右矩形包围的像素。随后,我们确定这些像素的中点,以确定下一步窗口的水平位置。(参见下面的图 7)我们不断重复这些步骤来提取下一行的像素,直到我们覆盖了整个图像。

我们必须设置窗口高度和宽度参数。高度由我们想要滑过框架的窗口数量决定。一般来说,窗口数量越多,曲线拟合得越好,窗口宽度也越大。设置太高,我们最终会浪费计算资源。通常,我发现每帧 25-35 个窗口是最佳的。将窗宽增加到很高将开始拾取来自人行道或路边植物的噪音。

Fig 7 Finding lane hotspots using window sweeping

这一步有些复杂。在一个窗口内,有时可能选择的像素太少,而在其他情况下可能选择的像素太多(回想一下,我们必须使用宽窗口来扫过)我们如何确定下一个窗口的 x 位置。在每一种情况下,我们都必须拒绝窗口中的信息,因为它是不可用的,并输入下一个窗口 x 位置的估计值。有三个选项可供选择:如果相邻行已被填满,我们可以将其位置偏移车道宽度并继续。否则,如果足够数量的行已经被填充,我们可以使用一般曲线来估计下一个位置。如果不成功,我们可以使用前一帧中获得的位置继续。如果万不得已,我们可以继续纵向发展。

有时,在一行的高亮像素之间可能会有一个间隙。如果我们忍受它,车道会因噪音而弯曲。最好拒绝这样的帧,并使用来自前一帧的信息来纠正它。每当我们拒绝整个帧时,谨慎的做法是重新校准我们用来创建掩码的阈值。在这个阶段的最后,我们有一组左右像素。

最佳拟合车道中心

我们已经获得了左侧和右侧车道坐标,现在我们必须对这些坐标拟合一条曲线。如果不是因为系统拾取的噪声,这应该很简单。如果我们从底部的几个窗口中取所有点,并让优化器为下一个点或曲线产生一个估计值,它可能最终会给阳光照射的点一个很高的权重,并产生一个不规则的曲线。缓和这种情况的一种方法是在每个窗口中使用(点的)质心,并使用质心来估计曲线(见下图 8)。我发现这对于噪声更鲁棒。

Fig 8 Determining the best fit lane

一旦我们得到一条曲线,我们将它与前一帧的曲线进行比较,以检查它们是否彼此接近。足够接近时,我们接受曲线,否则我们继续从先前的帧进行估计。在拒绝的情况下,我们设置一个计数器,一旦它记录出一个阈值,我们就接受该解决方案,即使它已经超过了最大可接受的偏差。这有助于我们捕捉系统错误并从中恢复。作为最后一步,我们使用移动平均来消除一些噪声,而不是直接进行曲线估计。

值得注意的是,左车道线和右车道线都可以估计两条独立的曲线。然而,使用中线估计在两个方面更好。首先,它汇集了两条车道的信息,即使其中一条车道线缺失或错误,这也有助于产生估计值。第二,车道线是平行的,将它们视为两个独立的实体会丢失这些信息。

切换车道和计算偏移

开车时,我们会变换车道,因此系统必须监控我们在车道上的位置,并在需要时触发车道变换。让我们弄清楚。对于每个车道,我们已经确定了车道的起始位置。它的中点给了我们车道的中心。俯视图中摄像机的中心给出了车辆中心的位置。我们可以通过使用之前计算的比率,将其从像素坐标系转换为真实世界的偏移。如果这个偏移量大于车道宽度的一半,我们就准备在下一帧中切换车道(见下面的图 9)。

fig 9 Changing Lanes

对于转换车道,我们将所有东西偏移一个车道宽度。我们保留车道线的旧坐标,为两条车道所共有,并重置另一条车道。在大多数情况下,它顺利发生。(参见下面的图 10)。

Fig 10-Switching from the right to the left lane | NH60 India

我们可以使用多项式系数来确定汽车当前位置的真实世界曲率半径(见下图 11)。这可以是对给出性感曲线的虚假帧的另一种检查,因为计算的半径不会在帧与帧之间突然改变。

Fig 11 radius of curvature

检测车辆

有许多方法用于物体检测。 YOLO 在平衡准确性和计算成本方面相当高效。然而,即使是 YOLO 也无法在移动处理环境中从实时视频流中挤出边界框。对象追踪器精确而快速,可以用有限的计算资源做实时流。我们可以让 YOLO 每隔一段时间制作一张目标地图并让一个目标追踪器大部分时间跟随它。除了从一个坐标系切换到另一个坐标系之外,这很容易实现。

Fig 12 Locating cars

在从追踪器到 YOLO 的切换过程中,我们应该能够在当前帧中定位先前识别的车辆(见上面的图 12)。YOLO 生产粘合盒。因此,我们必须创建一种方法来识别刚刚进入视野的新汽车,并将边界框分配给前一帧中识别的汽车 ID。我们使用 IOU 度量来分配具有现有 id 的头寸。

最后一步是计算车辆参数:位置速度、碰撞时间。如果我们将下边缘的中点作为车辆的位置参考(不完美,因为我们可能会斜着看车辆,但这是一个很好的估计),我们可以计算所有的参数。将坐标转换到俯视图中,我们可以获得真实世界中车辆离摄像机有多远。帧与帧之间距离的变化给出了速度的估计。如果车辆在车道上,汽车正在行驶(由简单的代数不等式确定),我们可以根据观察到的速度确定前车相对于本车减速时发生碰撞的时间(见下图 13)。

Fig 13 Front view and top view

我们基于到边界框的距离进行所有的测量。在大多数情况下,它准确地反映了真实的地面距离。然而,只要作为消失点测量的地平线上的点在帧之间保持一致,这就起作用。然而,我们在坑洼路面、斜坡上行驶,等等。所有这些都会扰乱消失点。这将导致车辆看起来比实际更远或更近。如果我们把系统设置成只有当我们行驶超过 20 KMPH 时才触发,我们就可以避免这些陷阱。我们设计的用例是巡航速度,所以这是可以接受的。

由 YOLO 和追踪器编码的边界框会增加噪声。有时盒子与车辆的轮廓太紧,而在其他盒子上与车辆轮廓更宽松。我们可以通过使用移动平均来估计位置,并使用稍大的周期来估计速度,从而减弱一些噪声。然而,不利的一面是,它降低了系统的一些响应能力。

物体检测的最后一个障碍是道路分隔物对其他车辆的阻碍。测量到车辆的距离时,假设边界框的下边缘与道路平面相交。这在大多数情况下是正确的,但是如果道路中间有一个分隔线或者一辆车挡住了视线,它会裁剪掉最终的边界框。车辆将出现在道路的更远处。这种判断错误会经常发生。然而,这不是一个交易破坏者。为了避免碰撞,我们主要关注与自我车辆在同一车道上的摄像机附近的车辆。我们可以忽略一些反向穿越马路的车辆,忍受一些计算上的失误。

够快吗?能快一点吗?

这在没有 GPU 的台式机或笔记本电脑上实时运行。处理速度对以下参数敏感:触发 YOLO 的时间、输入视频的帧速率和视频的像素分辨率。减少这些参数中的任何一个都会提高处理速度。我发现 Yolo 每 2 秒触发一次,以 360 像素、10 帧/秒的速度工作,比笔记本电脑上的实时帧速率要好。

在移动设备能够实时运行该算法之前,这仍然需要调整。好在还有弥补的余地。对象检测 YOLO 占用了每帧的大部分处理时间。它使用 VGG 网络构建的主体,可以替代较小的移动架构。这将在一些准确性和更快的处理之间进行权衡。我们也可以调整在一个自定义头只做车辆+行人+交通灯检测,而不是 80 类。

一些代码可以重构,以便在对象检测和车道检测之间共享。追求的方向之一是直接使用俯视图(缩放到 446 X 446)进行对象检测和跟踪。这有助于我们跳过在不同坐标系之间多次重新缩放的部分。

最后,如果我们抛开 dash-cam 记录器用例,专注于检测、报警和日志记录(可能立即有听觉音调,并在驱动器后有表格摘要),我们可以去掉用于产生增强视频的部分代码。这将使我们的速度提高一个数量级,允许移动设备处理实时信息。

这会导致什么?

汽车行业的监管环境正在发生变化。较低的排放标准加上较高的安全评估要求增加了合规成本。在监管不利的情况下,投资在便携式设备上运行的 ADAS 平台将间接有助于安全性,并以制造商极低的前期和运营成本改善整体客户体验。

运输经济的未来将建立在微观交易的基础上,而微观交易本身就需要区分谨慎和疏忽

汽车行业的终端用户角色也在重新定位。车主、司机和通勤者传统上是同一个人。在未来,这些角色将由不同的个人来执行。这是有道理的,因为每辆停放的车辆都是闲置资产。运输经济的未来将建立在微观交易的基础上,而微观交易本身就需要区分谨慎者和疏忽者。这就是主动辅助算法可以发挥作用的地方。从驾驶时的轻推行为开始,到根据驾驶分数历史确定保险费。

汽车工业的最终产品正在发生变化。这种变化需要新的技能和关系。电动汽车的部件数量比传统的汽油发动机少一个数量级。该行业可能会对其供应商群进行横向整合。在这种动态中,承担了开拓成本的先行者很可能在以后获得有利的标准和网络。ADAS 为传统玩家提供了一个机会,让他们在这一转变过程中押下较小但渐进的赌注。

最后,ADAS 的现有参与者,从创新者市场转向早期采用者的障碍之一是意识。创建一个半功能的智能手机应用程序是他们可以尝试的技巧之一。

并非所有当前的智能手机都支持主动辅助算法所需的处理能力。然而,在新兴经济体,每年有三分之一的智能手机被替换。这难道不是一个为基于移动设备的驾驶助手造势的有力案例吗?

其他链接:

  1. Colab 笔记本【在 youtube 视频上运行该过程,替换新视频的链接,调整设置】
  2. 包含全部代码的 Github 存储库

[## 视觉缓冲器/副驾驶

车辆位置+碰撞时间叠加在顶视图附文…

github.com](https://github.com/visualbuffer/copilot)

汽车行业一直在以惊人的速度适应变化。你一直在管理这些变化吗?我很想听听你对未来的看法。同样,如果您正在构建这些解决方案,我很想听听您的故事。请在我的 LinkedIn 上留言。

Python 中的共指消解

原文:https://towardsdatascience.com/coreference-resolution-in-python-aca946541dec?source=collection_archive---------6-----------------------

使用 NeuralCoref 将基于神经网络的共指消解集成到您的 NLP 管道中

在人类语言中,内水平意识在理解(解码)技能、写作(编码)技能和一般语言意识中起关键作用。内指包括语篇中的回指、下指和自我参照。

指代是指一个词为了其意思而回指文本中的其他概念。

*David went to the concert. He said it was an amazing experience.***He** refers to *David*.
**It** refers to the concert.

指代发生在一个词指代文本后面的想法时。

*Every time I visit her, my grandma bakes me cookies.***Her** refers to my grandma.

共指消解NLP (自然语言处理)相当于信息检索系统、会话代理和亚马逊的 Alexa 等虚拟助理中使用的内视感知。它的任务是将文本中涉及相同底层实体的提及进行聚类。

例如:

“我”、“我的”“她”属于同一类,而“乔”“他”属于同一类。

解析引用的算法通常寻找与引用表达式兼容的最近的前面提及。代替使用基于规则的依赖解析树,神经网络也可以被训练,其考虑单词嵌入和提及之间的距离作为特征。

neural refe是一个集成在 SpaCy 的 NLP 管道中的开源 python 包。您可以使用 pip 安装 NeuralCoref:

pip install neuralcoref

或来自虚拟环境中具有依赖关系的源:

SpaCy 和 NeuralCoref 可用于创建生产就绪的 NLP 应用程序,只需稍加微调。例如,让我们解析历史上的 美国诉尼克松 案,以检索引用美国前总统理查德·尼克松的事实:

输出:
事实计数:
108****

  1. 在指控白宫某些工作人员和总统的政治支持者违反联邦法规的起诉书后,特别检察官在美联储的领导下提出了一项动议。
  2. 继续。17(c)要求在审判前出示与总统和其他人之间准确确定的谈话和会议相关的某些磁带和文件的传票。
  3. 总统以行政特权为由,提出动议撤销传票。

该脚本使用 Urllib 抓取网页,并使用 Beautiful Soup 解析 HTML。我们将文本加载到我们选择的空间模型中;您可以从终端下载预先训练的空间模型,如下所示:

*python -m spacy download en_core_web_lg*

SpaCy 管道分配单词向量、上下文特定的标记向量、词性标记、依存解析和命名实体。通过扩展空间的注释管道,您可以解析共同引用。

您可以使用doc._.coref_clusters属性检索所有相关提及聚类的列表,并使用doc._.coref_resolved属性用每个聚类中的主要提及替换相关提及。

SpaCy 有一个内置的无监督句子标记器,可以将文本分成一系列句子。对于你感兴趣的主题(如总统),使用小写的词条化句子进行近似字符串搜索。

Reddit 首页评分与评论的相关性

原文:https://towardsdatascience.com/correlation-between-score-and-comments-on-the-front-page-of-reddit-a9e7b4f23b64?source=collection_archive---------18-----------------------

我不是 Reddit 的大用户,但当我在那里时,我通常只在几个子网站上闲逛(r/dataisbeautiful,r/geography,r/philadelphia,r/emo 和其他几个网站)。除了广受欢迎的数据 viz subreddit,这些数据都不会产生你在 reddit 首页看到的分数。

我说这些只是为了指出我没有挖掘出 Reddit 文化的所有细微差别。然而有一天,在仔细阅读了互联网的首页后,我确实有一个问题——一个热门帖子的分数和围绕它的对话量之间有关联吗?

It looks like r/worldnews really struck up some conversations!

首先,获取数据。我看了一下 Reddit 主页的 api,但没有看到在给定的日期和时间内拉顶部帖子的方法。所以我求助于 Wayback 机器的 API,它可以使用特定的日期和时间作为端点,并将返回最近的网页截图的 url。

The front page is pretty well archived it appears.

我非常自信地认为我可以为 2018 年收集大量数据,于是我跳到 R 并生成了一个完整的 URL 列表来调用 API。

library(lubridate)
dateRange <- gsub(“-”,””,seq(ymd(‘20180101’),ymd(‘20181231’), by = ‘1 day’, truncated=2))
base_url <- "[https://archive.org/wayback/available?url=reddit.com](https://archive.org/wayback/available?url=reddit.com)"#create list of api urls
url_list <- c()
for (date in dateRange) {
  full_url <- paste(base_url, "&timestamp=",date, "120000", sep="")
  url_list <- c(url_list, full_url)
}

现在我们可以调用 Wayback 机器来获取网页截图列表。

#create list of archive links
archive_list <- c()
archive_times <- c()for (url in url_list) {
  #get raw result from api call
  raw.result <- GET(url = url)
  raw.result$status_code
  #get raw content from results
  this.raw.content <- rawToChar(raw.result$content)
  #put content into list
  this.content <- fromJSON(this.raw.content)
  #extract archive url from list and add to archive_list
  archive_times <- c(archive_times, this.content$archived_snapshots$closest$timestamp)
  archive_list <- c(archive_list, this.content$archived_snapshots$closest$url)
}

这给了我们一个 365 个 URL 的列表,从每天中午开始捕获。现在开始真正的网络抓取。可能有更快的方法,但是我用一个老式的来循环,并使用 rvest 包来抓取该页面 25 个帖子中每个帖子的分数、评论数和 r/subreddit。

在将 r/subreddit 值添加到 datalist 变量之前,我通过检查来确保 r/subreddit 值的长度大于 0(即任何帖子实际上都被提取了),从而包含了一些简单的错误处理。

循环完成后,我使用 rbind 填充数据帧并过滤掉任何有问题的数据。

#create empty list
datalist = list()#loop through archive urls
for (i in 1:length(archive_list)) {
  #get all the html from the webpage
  webpage <- read_html(archive_list[i])
  #filter all the .things
  things <- webpage %>%
    html_node("#siteTable") %>%
    html_nodes(".thing")
  #get votes
  score <- things %>%
    html_node(".score") %>%
    html_text()
  #get number of comments
  comments <- things %>%
    html_node(".comments") %>%
    html_text()
  #remove " comments" and convert to number
  comments <- as.numeric(gsub(" comments","", comments))
  # get post subreddit
  subreddit <- things %>%
    html_node(".subreddit") %>%
    html_text()
  #get date of page
  date <- gsub("[http://web.archive.org/web/|/https://www.reddit.com/](http://web.archive.org/web/|/https://www.reddit.com/)", "", archive_list[i])if (length(subreddit) > 0) {
    print(paste(unique(date),length(subreddit),sep=" "))
    #create temp df
    temp <- data.frame(date = date, score = score, comments = comments, subreddit = subreddit)
    #add it to the list
    datalist[[i]] <- temp
  }
}#make a df from the datalist
main_data = do.call(rbind, datalist)
#remove incomplete posts
reddit_posts <- main_data %>% 
  filter(score != "•",
         !is.na(score),
         !is.na(comments)
         ) %>% 
  mutate(score = as.numeric(sub("k", "e3", score, fixed = TRUE)),
         subreddit = gsub(".*r/","r/",subreddit))

擦伤怎么样了?不算太坏。该网站在一年的 75%的时间里成功地发布了每日帖子。我没有对此进行彻底的调查,因为我有足够的数据来处理,但我认为 Wayback 机器在 Reddit 网站重新设计方面存在一些问题。

现在我们有了一个新生成的数据集,但是为了产生我想要的可视化效果,它需要一些争论。

  1. 找出将最多帖子发送到首页的八个子编辑
  2. 将来自非顶级订阅者的帖子的 subreddit 值更改为“其他”
  3. 对子编辑因子级别进行重新分类,使其以降序排列,末尾是“其他”。
#get top 8 subreddits
top_subs <- reddit_posts %>% 
  group_by(subreddit) %>% 
  summarise(count=n()) %>% 
  top_n(8, count) %>% 
  ungroup()#create vector of top_subs
top_subs <- as.character(top_subs$subreddit)#make notin operator
'%!in%' <- function(x,y)!('%in%'(x,y))reddit_posts_reduc <- reddit_posts %>% 
  mutate(subreddit = case_when(
    subreddit %!in% top_subs ~ 'other',
    TRUE ~ as.character(.$subreddit)
  ))#get list of factors in descending order
factor_order <- reddit_posts_reduc %>% 
  group_by(subreddit) %>% 
  summarise(count=n()) %>% 
  arrange(desc(count)) %>% 
  select(subreddit)#overwrite with list
factor_order <- as.vector(factor_order$subreddit) 
#remove "other" from first position
factor_order <- factor_order[-1]
#create new factor level list
factor_order2 <- factor_order
#update new factor list with ordering info
for (i in 1:length(factor_order)) {
  factor_order2[[i]] <- paste("#",i," ",factor_order[[i]], sep = "")
}
#append other to both factor lists
factor_order <- append(factor_order, "other")
factor_order2 <- append(factor_order2, "other")#update dataframe levels with update factor levels
reddit_posts_reduc$subreddit_f <- mapvalues(reddit_posts_reduc$subreddit, from = factor_order, to = factor_order2)
levels(reddit_posts_reduc$subreddit_f)

现在,是时候策划了。我把评论的数量标在 x 轴上,分数标在 y 轴上。我使用轴限制来说明异常值,最终结果是一个按子网格分组并标有相关系数的小多次波图。

#plot data
reddit_posts_reduc %>% 
ggplot(aes(
  x=score,
  y=comments,
  color=subreddit_f)
       ) +
  geom_point(size=3, alpha=0.4) +
  facet_wrap(~subreddit_f, ncol = 3) +
  geom_smooth(se=F) +
  theme_fivethirtyeight() +
  theme(axis.title=element_text()) +
  # labs(title = "Correlation between score and comments on front page",
  #      subtitle = "Posts from the front page of Reddit in 2018 plotted to show correlation between score and the number of comments. Posts are grouped by the eight subreddits that sent the most posts to the front page with all other posts grouped in other.",
  #      caption = "Data from Reddit via Archive.org\nChart by @jared_whalen"
  #      ) +
  theme(legend.position="none") +
  stat_cor(method = "pearson", label.x = 110000, label.y = 9000) +
  scale_y_continuous(label=unit_format(unit = "K", scale = 1e-3, sep=""),
                     limits=c(0,10000)) +
  scale_x_continuous(label=unit_format(unit = "K", scale = 1e-3, sep=""),
                     limits=c(0,150000)) +
  xlab("Score") +
  ylab("Number of comments"**)**

我从这个项目中得到的东西

  • 如何使用 Wayback 机器的 API 来抓取存档的页面
  • 更好地理解重新指定因子级别,以便在打印时自定义排序

这里是整个源代码的要点。

关联与因果——酒精如何影响预期寿命

原文:https://towardsdatascience.com/correlation-causation-how-alcohol-affects-life-expectancy-a68f7db943f8?source=collection_archive---------11-----------------------

我们应该多喝酒来长寿吗?

相关性并不意味着因果关系!

作为初级统计学家和数据科学家,我们反复听到这句话。但那实际上是什么意思呢?这个小分析借助于 R 和简单回归揭示了这个话题,聚焦于酒精如何影响健康。

狄俄尼索斯的困境

关于酒精对健康的影响以及它如何改变人的寿命,已经有很多研究了。只要在谷歌上输入“酒精预期寿命研究”,我们就会得到大约 11,000,000 个结果。有些人可能声称适度饮酒实际上对我们的健康有益,而大多数研究表明,即使每天一杯酒也会降低预期寿命。

这项分析研究了不同国家的饮酒量和平均预期寿命之间的关联模式,解释了可能的相关性,并提供了为什么这些相关性可能存在的见解。

我最初的假设是,预期寿命更高的国家也消费更多的酒精。起初这听起来可能有争议,但这可能是由于其他因素,如更高的生活质量,只有它的副产品是获得酒精饮料。

配料

这项任务使用了 3 个数据集:

  • Drinks.csv :各个国家 15 岁及以上人口每年人均饮酒量(啤酒、葡萄酒和烈酒)
  • life expectation . CSV:各个国家的预期寿命和其他健康因素
  • countries of world . xlsx:各个国家的地理和社会经济数据。

混合饮料

数据包含了 193 个国家的啤酒、葡萄酒和烈酒。这些数字存储为字符,因此我们可以将它们转换为数字数据类型。

缺失值在数据集中显示为问号,我们将用 NA 值替换这些符号。

我们需要一种有意义的方式来汇总这些服务:根据众所周知的刻板印象,法国人可能会消费更多的葡萄酒,而德国人可能会喝更多的啤酒。然而,我们需要一种方法在相似的范围内比较这些国家。

我编写了一个函数,使用以下公式计算每个国家纯酒精的总升数:

_ _ _ 酒精 = 啤酒 _ 份数∫(12∫0.0295∫0.05)+葡萄酒 _ 份数∫(5∫0.0295∫

我们最终得到了下表:

Table 1: Drinks dataset

生活中的期望

life_exp数据包含各种健康指标(出生时的预期寿命、60 岁时的预期寿命和健康预期寿命),显示了从 1990 年到 2013 年按性别分列的综合数据。

我关注的是 2012 年男女出生时的预期寿命,并加入了按国家分列的drinks数据。

在预期寿命和饮酒量之间进行一个简单的相关性测试,我们可以看到一个 0.521 的结果。

这标志着适度的高相关性,表明酒精消费量高的国家也有更高的预期寿命。我们将进一步调查这一现象。

我们是世界

countries的数据比其他两个稍微混乱一些。它被存储为一个。xlsx 文件。在导入过程中,我们跳过了第 1 页上的前 3 行不重要的内容。(现在)第一行包含标题,它的一部分也留在了第二行。

Table 2: Countries dataset

我将第一行和第二行合并成一个标题,清除了列名(空格、点等)。)并将必要的列转换为数字类型。最后,我将地理和社会经济数据与之前的数据集合并。

相关性和因果关系

让我们快速看一下不同的因素是如何与预期寿命相关联的:

Figure 1: Correlations of numeric features

如前所述,饮酒量(混合饮酒和分开饮酒)与预期寿命呈相对正相关。婴儿死亡率和死亡率当然是负相关的(人死得越多/越快,平均水平就越低)。

Figure 2: Highest positive and negative correlations

手机数量、文化水平和人均 GDP 也与寿命延长高度相关。这导致了我一开始的假设:教育程度更高、更富裕、技术装备更好的国家有更高的预期寿命。这些情况为公民提供了酒精饮料,他们比没有达到这一水平的贫穷国家消费更多的酒精饮料。

我们可以看到每个区域的相关性来证明这一说法:

Figure 3: Alcohol on Life Expectancy

这个假设似乎确实是对的。更发达的地区如欧洲美洲西太平洋(澳新等。)根据loess回归似乎有正相关。另一方面,由于经济/文化/宗教原因,像非洲和地中海东部这样的欠发达地区倾向于消费较少的酒精,他们的预期寿命不受饮酒量的影响。**

如果我们看看人均国内生产总值对预期寿命的对数回归,它显示了最清晰的画面:

Figure 4: GDP on Life Expectancy

摘要

我们首先可以看到饮酒与预期寿命的关系,以及为什么立即下结论是危险的。经过进一步的调查,我们发现,发达国家的人均寿命最高,他们也倾向于消费更多的酒精,但这并不一定意味着另一个。这就是为什么从相关性中暗示因果关系是非常危险的!

Source: https://xkcd.com/552/

编后记

这个项目是作为匈牙利中欧大学掌握数据科学过程课程的要求而完成的。R 代码和数据集可以在 GitHub 上我的ceu _ life-expectation存储库中找到。

相关性并不意味着因果关系

原文:https://towardsdatascience.com/correlation-does-not-imply-causation-92e4832a6713?source=collection_archive---------8-----------------------

肺癌会导致吸烟吗?

Photo by Sajjad Zabihi on Unsplash

正如我们今天所知,吸烟会导致肺癌。然而,这一事实在 20 世纪 50 年代并不完全清楚,当时首次研究表明吸烟和肺癌之间的相关性。其中一位怀疑论者是统计学家 R.A. Fisher,他推断因果关系可能正好相反:

“那么,有没有可能,肺癌——也就是说,必须存在的癌前状态,并且已知在那些将表现出肺癌的人中存在多年——是吸烟的原因之一?我认为不能排除。”

需要说明的是,费舍尔不仅是一名统计学家,还是一名烟瘾很大的人,所以他的观点很可能有失偏颇。然而,他有一个观点:相关性本身不足以确定因果关系。还有什么可以解释相关性?

香烟导致肺癌

通常,如果两个变量 A 和 B 相关,至少有四种可能的解释:

  1. a 导致 B
  2. b 导致 A
  3. a 和 B 都是由第三个变量 c 引起的。
  4. 机会(相关性是虚假的)。

那么香烟和肺癌之间的因果联系是如何建立的呢?在 50 年代和 60 年代,大量的研究证实了这种相关性。此外,研究还表明,重度吸烟者比轻度吸烟者患更多的癌症,烟斗吸烟者患更多的唇癌,而吸烟者患更多的肺癌。所有证据加在一起,使这个案子变得清楚了。1964 年,美国卫生局局长路德·特里正式宣布了这种因果关系:

“考虑到来自许多来源的持续的和越来越多的证据,委员会的判断是,吸烟在很大程度上导致了某些特定疾病的死亡率和总体死亡率。”

特里总结说,吸烟对健康有害。

source: xkcd

由第三个变量引起的相关性

有时,两个变量之间出现相关性仅仅是因为它们都是由第三个未观察到的变量引起的。教科书上的一个例子是纽约市冰淇淋销售量和谋杀率之间的相关性。显然,这种相关性是由第三个变量引起的:季节。夏天是冰淇淋和犯罪的黄金时间。

其他时候,由第三个变量引起的相关性可能不太明显。考虑雌激素水平和心脏病之间的联系:在 90 年代,研究表明女性的雌激素水平与心脏病风险呈负相关。这是一个重要的问题,因为心脏病是 65 岁以上妇女死亡的主要原因。那么,为什么不默认推荐激素替代疗法用于绝经后低雌激素女性呢?事实上,这是千年之交前的普遍看法。

然后,女性健康倡议报告了一项涉及 16 万多名女性的长期对照研究的结果,反驳了普遍的看法:激素替代疗法没有降低心脏病风险,在某些情况下甚至会适得其反。在这种情况下,第三个变量,绝经,影响心脏病的发病率和雌激素水平,导致观察到的相关性被误认为是因果关系。

另一个显著的例子是疫苗和自闭症之间的明显联系,这引发了持续至今的反疫苗运动。1998 年,医学杂志 The Lancet 发表了 Andrew Wakefield 博士的研究,声称发现了自闭症和 MMR(麻疹、腮腺炎、风疹)疫苗之间的联系。那篇论文有很多问题,最重要的是样本量很小——显然是人工挑选的——只有 12 个孩子。与第三个变量的相关性也可能是一个问题:自闭症症状的发展和第一次接种疫苗都发生在幼儿期,因此预计存在时间相关性。

由于其他研究人员指出了这项研究的缺陷,韦克菲尔德的论文很快被《华尔街日报》撤回。后来,韦克菲尔德不仅被指控为糟糕的科学,还被指控为蓄意欺诈。

虚假相关

你知道 1999 年至 2009 年间,每年掉进游泳池淹死的人数和尼古拉斯·凯奇的电影数量是相关的吗?

他的电影是不是烂到让观众想在自己的池子里自杀?不,这是一个虚假关联的例子,一个幸运的巧合。泰勒·维根在他的网站上有很多这样的例子。

当研究人员测试大量可能的联系时,伪相关性是一个严重的问题。在《不可思议的统计数据》中,我提到了瑞典 1992 年的一项研究,该研究将住在高压电线附近与儿童白血病联系起来:研究人员在 25 年的时间里调查了住在高压电线 300 米范围内的所有人,并在 800 多种不同疾病中寻找具有统计意义的发病率增长。当然,通过一次查看这么多不同的可能性,很有可能会偶然发现至少一次统计上显著的相关性。这就是所谓的看别处效应

结论:小心相关性

相关性本身并不意味着因果关系。有时这两个相关变量是第三个未被观察到的变量的结果,例如雌激素水平和心脏病风险之间的联系。有时,这种相关性可能是虚假的,例如电力线和儿童白血病之间的联系。

建立因果关系比寻找相关性需要更多的工作,因为这是一个更强有力的陈述。这就是推断的问题:因果关系只能推断,永远无法确切知道。

参考

  • 乔丹·艾伦伯格,如何不犯错:数学思维的力量
  • 饶&安德拉德,MMR 疫苗与自闭症

在我的个人资料页面上找到更多我的故事,例如:

[## 不可能的统计

圣经代码、投资基金、彩票和“看别处”效应的诅咒

towardsdatascience.com](/the-statistics-of-the-improbable-cec9a754e0ff) [## 不要根据结果来判断决定

马后炮如何影响我们的判断

medium.com](https://medium.com/swlh/dont-judge-decisions-by-their-outcomes-6f37bec6fd44)

相关性不是因果关系

原文:https://towardsdatascience.com/correlation-is-not-causation-ae05d03c1f53?source=collection_archive---------0-----------------------

从医疗保健到商业管理,为什么这些概念的混淆具有深远的影响

介绍

在相关数据中,一对变量是相关的,因为一个变量可能会随着另一个变量的变化而变化。这种关系可能会让我们认为一个事物的变化会导致另一个事物的变化。本文通过解释相关性、因果关系以及经常将二者混为一谈的偏见,澄清了这种错误的想法。

人类的大脑简化了输入的信息,所以我们可以理解它。我们的大脑经常基于轻微的关系或偏见对事物做出假设。但是这个思考过程并不是万无一失的。一个例子是当我们把相关性误认为因果关系时。偏见会使我们得出这样的结论:如果一件事和另一件事同时以同样的方式发生变化,那么这两件事必然会引起另一件事。本文通过探索这些主题和人类大脑的偏向性,澄清了相关性等于因果关系的误解。

关于相关性和因果关系

相关性是两个变量之间的关系或联系,其中一个变量发生变化,另一个变量也可能发生变化。但是一个变量的变化不会引起另一个变量的变化。这是一种关联,但不是因果关系。你从孩子到成人的成长就是一个例子。当你的身高增加时,你的体重也会增加。长高并没有让你变宽。相反,成熟到成年导致这两个变量增加——这就是因果关系。

商业中的因果关系

假设我们想给我们的一些客户提供促销或折扣。我们的营销部门想要最大化 delta,换句话说,促销带来的销售增长。所以我们需要决定哪些客户会给我们在促销或折扣上的投资带来最好的回报。我们想只向你的前 10%的客户提供吗?还是垫底的 10%?

你可能会认为推动更多销售的用户对你的商业成功更有责任。然而,这种假设可能是错误的。向哪些客户提供促销的最佳选择可能完全不同。在缺乏有效的实验或分析的情况下,你对这些问题没有准确的答案。

认知偏差

有许多形式的认知偏差或不合理的思维模式经常导致错误的结论和经济决策。这些类型的认知偏见是人们在商业和营销中假设错误原因的一些原因:

  • 确认偏差。人都想对。他们经常不能承认或接受他们在某些事情上是错的,即使这种态度会导致最终的伤害和损失。
  • 因果关系的错觉。过于看重自己的个人信念、过度自信和其他未经证实的信息来源,往往会产生一种伤亡的错觉。一个经济例子是最近的美国房地产泡沫。数百万人相信,以远高于其实际价值的价格购买房屋将继续带来投资回报,因为这种情况发生在过去。
  • 金钱。你想销售你的产品。如果赚钱的欲望蒙蔽了你的逻辑,你在营销和其他业务上的花费可能会超过你的投资回报。
  • 主要营销含义。营销统计和数据往往复杂且令人困惑。当不存在因果关系时,很容易看出变化的销售数字和企业中许多其他变量之间的关系。

实验

知道某物有价值需要实验。实验有助于你理解你是否做出了正确的选择。但是这是有代价的。如果你因为不给工作组带来价值的特性而拖了他们的后腿,你会赔钱。但是你会学到这个特性的重要性。

实验的价值在于完成这两件事:

  • 在不同的选择中做出决定。
  • 量化最佳选择的价值。

实验变量

一个科学有效的实验需要三种类型的变量:受控变量、独立变量和从属变量:

  • 控制的变量保持不变,因此可以在静态环境中测量彼此相关的其他变量。
  • 实验的独立变量是唯一可以改变的变量。
  • 因变量是自变量发生变化时观察到的结果。

任何不受控制的变量或中介变量都会影响实验的准确性。因此,为了正确评估实验结果,需要对它们进行识别和剔除。不可控变量的差异也会影响自变量和因变量之间的关系。

不受控制的变量增加了无关因素对实验结果的影响。相关性可能是假定的,假设可能是在不存在的地方形成的。精确的分析变得困难或不可能。从不受控制的变量中得出的结论的例子显示在儿童音乐课和随后的手机癌症例子中。

我们的大脑如何欺骗我们

很容易观察到相关数据的连续变化,并假设一个因素导致另一个因素。这是因为我们的大脑天生就有因果关系认知偏差。我们需要理解大量的输入数据,所以我们的大脑简化了这些数据。这个过程被称为启发式,它通常是有用和准确的。但并不总是如此。试探法出错的一个例子是,每当你相信相关性意味着因果关系。

虚假相关

这是一种数学关系,其中两个或两个以上的事件或变量相关联,但不是因果关系,这是由于巧合或某个第三个看不见的因素的存在

儿童和音乐课

在对人类大脑发展进行研究后,研究人员得出结论,参加音乐课的 4 至 6 岁儿童在与记忆和注意力相关的领域表现出大脑发展加快的证据。根据这项研究,我们有偏见的大脑可能会很快将这些点联系起来,并得出结论,音乐课可以促进大脑发育。但是还有其他变量需要考虑。孩子们上音乐课这一事实是财富的标志。所以他们可能接触到了其他已知能促进大脑发育的资源,比如良好的营养。

这个例子的要点是,研究人员不能仅从这么多数据中假设音乐课会影响大脑发育。是的,这显然有关联,但没有因果关系的实际证据。我们需要更多的数据来得到真正的因果解释。

癌症和手机

如果你研究一张显示癌症病例和手机数量的图表,你会注意到这两个数字在过去的 20 年里都上升了。如果你的大脑以因果关系认知偏见处理这些信息,你可能会认为手机导致癌症。但这太荒谬了。除了两个数据点都在增加之外,没有其他证据。在过去的 20 年里,很多其他的东西也增加了,它们不能全导致癌症或由手机使用引起。

可解释性

为了找到因果关系,我们需要可解释性。在人工智能和大数据分析的时代,这个话题变得越来越重要。人工智能提供基于数据的建议。有时候,人类看不到那些建议的任何理由,除了是一个 AI 做出的。换句话说,它们缺乏可解释性。

医学中的可解释性

FDA 不会批准缺乏解释力的癌症治疗。想一想这种情况。基于人工智能对你的基因组、你的癌症 DNA、数百万其他病例和更多数据的分析,即使你无法解释计算机的神经网络是如何提出确切的治疗方法的,你想要对你的癌症进行最好的治疗吗?或者你更愿意有一个你能解释原因的次优治疗?

医学可解释性可能是本世纪最大的话题之一。

单向对双向

相关性是双向的。我们可以说移动电话的使用与癌症风险的增加相关,癌症病例与移动电话的数量相关。基本上,你可以交换相关性。在因果关系中,我们可以说一项新的营销活动导致了销售额的增加。但是说销售的增加(在活动运行之后)导致了营销活动没有任何意义。

根据定义,任何因果陈述都是一种方式。这是一个很大的线索,关于你处理的是相关性还是因果性。

巨大的困境

在《教育对收入的因果影响》一书中,大卫·卡德说,更好的教育与更高的收入相关。但是他说的最重要的事情是,如果我们不能做一个实验,用我们所有的

变量不变,我们不能从相关性中推断因果关系。我们总能把可解释性带到桌面上。但是在现实生活中,有足够大的问题,基于可解释性的原因很难被证明。从科学的观点来看,它们只能被称为理论。

在缺乏实验证据的情况下,很难知道教育程度较高的工人所观察到的较高收入是由他们的高等教育造成的,还是收入能力较强的个人选择了接受更多的学校教育。

—大卫·卡德,教育对收入的因果影响

高收入会导致高等教育吗?高等教育会带来更高的收入潜力吗?我们不知道。但是,我们可以进行预测。我们可以利用这种相关性,根据一个人的教育程度来预测他的收入潜力。我们还可以根据他的收入预测他的教育程度。

好的预测是基于相关性的

考虑到本文的上下文,这听起来像是一个矛盾。相关性是指分析静态历史数据集,并考虑观察结果和结果之间可能存在的相关性。然而,预测不会改变一个系统。这就是决策。为了做出软件开发决策,我们需要理解如果您采取行动或不采取行动,它会对系统的发展产生什么影响。决策需要对行动的影响有一个粗略的了解。

什么是预测?

我们不会通过发展更好的随意理解来做出更好的预测。相反,我们需要知道我们用来做预测的技术的精确限制,以及每种方法能为我们做什么。

参考

Lovestats (2019)。“动画片。”LoveStats 博客。从 lovestats.wordpress.com 取回。

卡片,D..(1999)."教育对收入的因果影响。"劳动经济学手册,第 3 卷。

销售线索得分预测和成本效益分析

原文:https://towardsdatascience.com/cost-benefit-analysis-by-predicting-lead-score-and-expected-value-fb2082eef50a?source=collection_archive---------12-----------------------

现实场景中分析的真正优势

链接到笔记本全代码

内容
-成本收益分析
-期望值
-领先得分概率
-分类
-混淆矩阵
-准确率、召回率和 F-1 得分

问题陈述和解决方案

一家名为 X 教育的公司销售在线课程。任何时候有人访问他们的网站,他们要么注册课程,要么不注册。那些在看到课程信息后仍未注册的人被称为潜在客户。

现在,为了将这些潜在客户吸引回他们的课程,公司尝试了不同的策略,如电子邮件营销或特殊折扣等。问题是,举例来说,如果公司有 50 个潜在客户,并向所有 100 个客户发送电子邮件,可能只有 10 或 15 个客户会注册。因此,公司损失了金钱和精力,这需要我们稍后进行成本效益分析。

解决方案是使用预测模型来确定每个潜在客户参加课程的概率,以便公司只给那些高潜力的潜在客户折扣或发送电子邮件。

要查看完整的分析,请查看这个笔记本。它遵循一种分类方法,在这种方法中,模型使用称为 conversion(0,1)的目标变量进行训练,其中 0 表示客户不会返回,1 表示客户会返回。

随机森林和单热编码

一种热门编码是将分类变量转换为数值的方法,以便机器学习模型可以解释它。随机森林是一种集成方法,它通过选择变量子集作为预测因子来迭代工作,并试图减少模型的方差。在本书统计学习介绍中阅读更多关于随机森林的内容。

销售线索得分概率

通过应用机器学习模型,我计算出了每个潜在客户成为他们客户的概率,如下图所示。这些只是所有值的子集,我们可以按照概率从高到低的顺序排列。

混淆矩阵(准确性是一个神话)

上面我们看到了概率方面的结果,下面是二进制信息方面的结果,简单地说是或不是。

Accuracy = 80%

虽然准确率为 80%,但我们应该理解,这是以 0.5 的概率作为分类的阈值。换句话说,任何概率大于 0.5 的人都被认为没有流失,否则为流失。这是一个坏主意,因为可能 0.1 是正确的阈值,或者 0.2 或 0.3 才能获得最佳结果。

精确度、召回率、F-1 评分和 AUC 曲线

Precision :它说明了我们的模型中有多少正面预测值是真正正确的。(真正)除以(真正+真负)

回忆:也叫真阳性率,表示在所有阳性人群中,有多少人被正确预测。
(真阳性)除以(真阳性+假阴性)

假阳性率:所有阴性中,有多少是实际预测为阴性。

AUC 曲线(真阳性率和假阳性率之间的权衡)

简单地说,AUC 曲线解决了定义正确的基于阈值的分类的问题。它将阈值从 0.0%更改为 100.0%,而不是保持在 0.5%,并绘制了一个图表,使我们能够确定最佳可能结果。

这看起来可能很复杂,但关键是 0.58 左右的红线表示对结果进行分类的最佳阈值是 0.58。这意味着如果小于 0.58,则为 0 类,如果大于 0.58,则为 1 类,以产生可能的最佳精度。

预期值

根据业务用例,混淆矩阵的每个单元(真阳性、真阴性、假阳性和假阴性)可能对结果有不同的影响。例如,错误地将某人分类为患有癌症,而他后来发现他没有(假阳性)患有癌症,这可能会使他付出金钱和压力的代价,然而,错误地将某人分类为没有癌症,而他后来意识到他患有癌症(假阴性)将会使他付出生命的代价,后者显然更重要。因此,我们可以制定一种方法,其中混淆矩阵的每个单元格包含其概率,并且我们基于我们业务的历史价值将每个单元格乘以某个值“v”。请参见下面每个单元格的概率:

Probability for each cell

注意:我们还可以基于期望值定义分类器的决策边界。

成本效益分析

现在回到我们业务问题的初始阶段,让我们假设 X Education 的销售团队决定向所有被归类为潜在买家的潜在客户发送电子邮件通知。并且不会向被分类为非购买者的类别发送电子邮件。

发送每封电子邮件的成本:5 美元(假设)
如果客户购买,利润:100 美元(假设)

真实肯定:说客户会流失,我们没有发送电子邮件。
真否定:说客户不会流失我们发邮件,客户会购买。
误报:说客户会流失,但他没有,所以没有发送电子邮件,也没有产生利益。
假阴性:说客户不会流失,但他确实会流失,所以我们发出了电子邮件,但他没有购买。

真正:(0 成本,0 收益)= 0
真负:(5 成本,100 收益)= 100–5 = 95
假正:(0 成本,0 收益)= 0
假负:(5 成本,0 收益)= 0–5 =-5

Cost-Benefit Matrix

预期利润=概率矩阵和成本效益矩阵的乘积

对这些值求和后,我们得到:

结论

如果 X Education 使用我的模型对新客户进行分类,并向那些被分类为潜在买家的人发送电子邮件,它可以产生 70485 美元的总体预期利润。

注意:为了进一步分析,我们可以使用概率先验,以防我们有高度不平衡的类分布

成本函数:机器学习的基础

原文:https://towardsdatascience.com/cost-functions-the-underpinnings-of-machine-learning-549ac5edb211?source=collection_archive---------19-----------------------

这一关键概念决定了您将模型与数据相匹配的能力

将数据集拟合到模型是机器学习和数据科学的基础。通过这种方式,我们能够创造预测工具,帮助人们做出重要决策。

这通常是通过最小化模型生成的预测与模型训练、验证和测试阶段的实际数据之间的差异来实现的。

为此,我们必须能够识别模型预测和数据实际值之间的差异。为了使模型符合数据并创建有价值的预测工具,我们必须能够使用最小化函数快速计算出差异。

这是成本函数的目标。

什么是成本函数?

在数据科学中,成本函数计算模型预测和数据集之间的差异。

根据维基百科的定义,成本函数是“将一个事件或一个或多个变量的值映射到一个实数上的函数,该实数直观地表示与该事件相关的一些“成本”。从更实际的角度来说,它是一个函数,用来计算一个你将要最小化或最大化的参数。

在数据科学中,这通常意味着识别模型预测和训练数据集之间的差异。通过这种方式,您可以量化模型预测中的误差,并使用优化方法来最小化该误差。

在名称成本函数中,“函数”指的是计算一个值的函数,而“成本”指的是该函数正在计算的惩罚。

注意,成本函数的概念是非常灵活的,它可以被定制来匹配一种情况。而是写一个等式,抓住你真正关心的东西。

成本函数是如何使用的?

使用成本函数的一个例子是一个人模拟一栋建筑的能源性能。(S)他希望最小化能量消耗,并相应地写一个成本函数。但是最小的能源消耗将是一个从不加热或冷却空间的建筑!显然不能接受。

(S)他可以在成本函数中添加一项,该项也对居住者不舒服的小时数的结果进行惩罚。那么优化的结果将是使用最少能量的设计,同时仍然保持空间中的舒适性。这个成本函数可能看起来像这样:

成本=能源消耗+ 1,000,000 *不舒适时间

以这种方式,一个小时对居住者的预测不适相当于一百万单位的能量消耗。现在,系统的结果将是找到加热和冷却空间的最节能的方式,而不仅仅是避免加热/冷却空间以节约能源。

模型拟合中的代价函数有哪些例子?

您可以根据需要设计成本函数,以研究应用程序中最重要的内容。

这是一个非常具体的行业例子。一些更通用的数据科学示例包括:

  • 计算模型预测和数据点之间的误差总和,如了解线性回归的基本原理中所述。
  • 计算模型预测和数据点之间的误差平方和,如了解多元回归中所述。
  • 平均绝对误差 (MAE),它表示预测值和数据点之间的平均差异
  • 均方根误差 (RMSE),计算整个数据集的平均平方误差的平方根。

请记住,您可以根据需要设计您的成本函数,以研究在您的应用中什么是最重要的。这很重要,因为所有的成本函数都有不同的优点和缺点。

回想一下建筑能源模拟的例子,一个仅检查能源消耗的成本函数与一个仅查看不舒适时段的成本函数会产生不同的影响。没有能耗项的建筑没有压力来确保建筑的节能。一个没有不舒服的小时术语的建筑没有压力来确保建筑保持居住者的舒适。

将两者结合成一个单一的成本函数迫使模型关注两者。

我如何平衡一个多项成本函数?

由于该模型能够检查两者,因此确保在成本函数中对每一项给予适当的考虑就变得很重要。这是通过给每一项增加加权因子或乘数来实现的,它告诉成本函数你有多关心每一项。

在建筑能耗模拟示例中,能耗的权重系数为 1,不舒适时段的权重系数为 1,000,000。这基本上迫使模型确保不存在 0 小时的不适。

但是如果几个小时的不适可以节省能量呢?然后,您可以更改您的权重因子,以使模型结果在关注能耗和不舒适时间之间达到不同的平衡。

加权因子告诉成本函数你有多关心每一项。

一个更直接的数据科学例子是将 MAE 和 RMSE 结合在一个成本函数中,该函数用于将模型拟合到数据集。平均而言,MAE 的作用是使模型尽可能接近整个数据集。“平均”在这里是一个重要的术语。这可能导致模型在大多数点上非常接近,而在少数点上非常不准确。RMSE 产生了相反的影响。由于它使用误差平方的平均值,它迫使模型在每一点都有小误差。它避免了带有极少数极不准确点的模型,但可以牺牲平均模型精度来强制实现该目标。

为了平衡这两种方法的优点和缺点,一个模型拟合成本函数可以结合 MBE 和 RMSE。然后,您需要对成本函数中的两项应用加权因子,以根据您的应用需求平衡这两项。

包装它

为了创建有用的预测工具,我们必须能够创建紧密符合数据集的数学模型。为了创建紧密符合数据集的模型,我们必须能够量化我们的模型预测与实际数据的差异。

这就是成本函数的作用所在。成本函数是计算与情况相关的“成本”的公式。在模型拟合的情况下,成本函数通常计算模型中的误差。

成本函数是灵活的,并且可以包括多个项。这使您能够将不同的重要因素合并到一个成本函数中。一个例子是查看建筑物的能耗。结合能源消耗和不舒适时间的术语创建了一个成本函数,迫使模型最小化能源消耗,同时还确保人们保持舒适。在模型拟合中,成本函数可能想要结合平均绝对误差(MAE)和均方根误差(RMSE)。

多项成本函数需要一种方法来平衡这两项,根据你对其中一项的重视程度。加权因子是应用于每一项的乘数,相应地增加/减少该项的值。可以根据需要对每一项进行添加和调整,以确定成本函数和最小化结果中的期望平衡。

哥斯达黎加家庭贫困水平预测

原文:https://towardsdatascience.com/costa-rican-household-poverty-level-prediction-in-r-46b31c3d1801?source=collection_archive---------29-----------------------

基于机器学习的 R 中综合数据分析和预测

作者: Chaithanya Pramodh Kasula 和 Aishwarya Varala

A map of Costa Rica

导言:本报告详细介绍了回答与哥斯达黎加家庭贫困水平相关的几个研究问题的过程。它由数据源、通过可视化进行的探索性数据分析、模型开发、微调、解决数据不平衡问题的方法、性能指标和结果可视化组成。

背景:在一个州或一个地方,政府或银行为他们的社会福利项目确定需要帮助的家庭是很重要的。据观察,生活在经济落后地区的人没有必要的知识或不能提供必要的文件,如收入/支出记录,以证明他们有资格获得援助。

在拉丁美洲,一种被称为代理收入测试的流行方法被用来做这个决定。各机构查看一个家庭的可观察属性,如天花板材料、家庭房间数量、家庭人数等,以确定该家庭是否有资格获得援助。然而,准确性仍然是一个问题。因此,美洲开发银行向 Kaggle 社区提供了一套数据,以提出新的方法,有效地将他们引向需要社会福利援助的家庭。

数据来源:项目使用的数据集提取自 Kaggle。数据源的网址为:https://www . ka ggle . com/c/Costa-Rican-household-poverty-prediction/overview

数据描述:数据文件夹由 train.csv 和 test.csv 组成,分别为 9557 行和 23856 行。但是,test.csv 不包含确定贫困水平的“目标”列。因此,train.csv 单独用作大小为 3.08 MB 的数据集。列数为 143。每个记录都与一个人相关联。143 列的描述可以在上面提到的数据源的 URL 中找到。下面提供了一些列的描述。
目标:表示贫困等级 1 =极端贫困,2 =中度贫困,3 =弱势家庭,4 =非弱势家庭
Idhogar:每个家庭的唯一标识符。属于一个家庭的人由这一栏来标识。
v2a1:每户每月支付的租金。
房间:房子里房间的数量。escolari:受教育年限等。

相关研究问题:
R1: 我们能否构建一个模型来确定哥斯达黎加不同家庭的贫困水平?
R2: 我们能否确定决定一个家庭贫困程度的最重要因素/栏目/预测因素?
R3: 受教育程度、性别、户主、人数、家庭房间数、依赖程度、技术(手机、电脑、电视、平板电脑)与一个家庭的贫困程度有关系吗?

变量的数据类型:数据集中的变量有四种数据类型:

  1. 布尔型:整数布尔型(0 或 1),字符布尔型(是或否)。paredblolad、noelec 等栏目。
  2. 浮点数据类型。例如,贫困、过度拥挤等。
  3. 整数数据类型。比如年龄,房租,房间,tamviv 等。
  4. 字母数字。比如 Id,idhogar。

数据探索阶层分布:贫困水平分布(阶层分布)非常不平衡,如图 2 所示。属于类别“四”的行数占数据集的 65.72%,但属于类别“一”的行数仅占 0.074%。在图 3 所示的家庭级数据集中观察到了同样的不均匀分布。要详细了解家庭级数据集,请阅读“家庭数据集”一节。

monthly_rent_payment 列 NaN 值个数:【monthly _ rent _ payment】列有 6860 行包含 NaN 值。' own _ and _ fully _ paid _ house '、' own _ paying _ in _ partitions '、' rented '、' unsaky '和' other _ assigned _ lowed '列包含表示 0(假)或 1(真)的二进制值。从图 4 可以推断,拥有房子的有 5911 人,拥有房子但分期付款的有 961 人。这个事实在数据预处理过程中非常有用。

Fig. 2

Fig. 3

数据预处理:为了便于参考、理解和交流,将原来的列名重新命名为英文缩写。可以在“changed_column_names.csv”中找到它们。此后,将通过重命名的列引用数据。

缺失值处理和特征工程:从研究问题 R1、R2、R3 可以解释分析的单位是户。然而,数据集中的每条记录都描述了家庭中一个人的属性。属于同一个家庭的人可以通过“household_identifier”列分组,因为他们每个人都有相同的标识符值。“Household _ identifer”值对每个家庭都是唯一的。此外,“目标”等级(贫困水平)的相同值被分配给一个家庭中的所有人。

在数据集中的多个列中发现缺失值。根据“数据探索”部分对“每月租金付款”栏中出现的 NaN 值的解释,假设所有拥有房屋的人都不支付租金。只剩下 7 个人了。因为它们的计数太少,所以所有在‘monthly _ rent _ payment’列中具有 NaN 值的行都被替换为零。

列“number _ of _ tablets _ household _ owns”也包含 NaN 值。“拥有平板电脑”一栏表明一个家庭是否拥有平板电脑。如果家庭没有平板电脑,则“平板电脑数量 _ 家庭拥有数”列中的值将被替换为零。对于每个家庭,计算“上学年数”和“在校年数”栏的平均值,并分配给户主。“依赖关系”列中的字符布尔值(是或否)已分别替换为 1 或 0。对“edjefe”和“edjefa”列执行了相同的操作。

Fig. 4

Fig. 5 — Correlation plot between highly correlated features

从数据集中删除重复的列。例如,有两列具有相同的名称“age_squared ”,它们彼此重复。只是,保留了其中一个。此外,还有许多列是现有列的平方值,如 oversmooth _ squared、dependency_squared 等。所有这些列都已从数据集中删除,因为它们没有为模型提供额外的信息。此外,类别变量“目标”由数字格式为 1、2、3 和 4 的贫困水平组成。它们分别被替换为单词 1、2、3 和 4。各栏(if _ 继子 _or_doughter、if _ 儿子 _or_doughter_in_law、if _ 孙子 _or_doughter、if _ 父亲 _ or _ 岳母 _law、if _ 哥哥 _ or _ 姐姐、if _ 哥哥 _ or _ 姐姐 _in_law、if_other_family_member、if _ 配偶 _or_partner、if _ 儿子 _or_doughter、if _ 母亲 _ or _ 父亲)不重要,不属于回答研究问题的范围,因此已被删除。“DP lyr”(Wickham 等人,2017 年)和“stringr”(Wickham,2019 年)软件包用于数据预处理。“gg plot”(Wickham,2016 年)和 Tableau (Tableau Software,2019 年)软件包用于数据可视化。“corrplot”软件包(魏等,2017)用于绘制相关矩阵。

使用相关性来减少特征:已经为预处理阶段之后剩余的 119 列构建了相关性矩阵。如此巨大的情节的可视化是笨拙的。因此,相关值大于 0.98 的高度相关的特征已经从矩阵中提取出来并被单独绘制。由于软件不能绘图,不能合并过长的列名,所以在图 5 中用数字表示。图中的数字 1 到 14 对应于“家庭大小”、“家庭大小”、“家庭中个人总数”、“家庭中个人总数”、“厕所连接下水道或污水池”、“家庭户主”、“区域布朗卡”、“鳏夫”、“无主要能源来源、用于烹饪、无厨房”、“主要材料、外墙上的天然纤维”、“电力、合作用”等栏构建相关图的目的是从数据集中移除高度相关的列,因为它们不提供任何附加值。从图 5 可以看出,“家庭规模”、“家庭规模”、“家庭中个人总数”、“家庭中个人总数”彼此高度相关。因此,这些列中只有一列包含在数据集中。

住户数据集:户主被视为每个住户的代表。因此,只有“if_household_head”列等于 1 的行才成为该数据集的一部分。在数据预处理期间,与单个人相关联的诸如“上学年数”的特征已经被适当地处理以反映家庭。该数据集共有 2973 行,此后将被称为家庭数据集。

使用随机森林建模:为了回答第一个研究问题,使用家庭数据集来训练随机森林。对于给定的实例,其贫困水平/目标是未知的,训练的模型将预测该行的类别。随机森林是一种集成学习技术,它通过从数据集中抽取样本(引导抽样)来构建不同长度的树。不属于结构一部分的剩余数据通常称为袋外(OOB)数据集。然后,构建的模型使用 OOB 数据集作为测试集,并自行评估其性能。假设这些行是相互独立的(就像我们的例子一样),那么在使用随机森林时就不需要单独执行交叉验证。这是在 OOB 数据的帮助下在内部隐式完成的。每个构造的决策树的 OOB 误差可以被平均以表示模型的总误差率。随机森林也能很好地概括并避免过度适应,这是决策树中观察到的主要问题之一。“caret”软件包(Kuhn 等人,2019 年)中一个名为“random forest”(Liaw 等人,2002 年)的软件包用于训练和测试数据。

将数据集拆分为训练集和测试集:由于类别不平衡问题,以 75:25 的比例随机拆分数据集用于训练集和测试集不会提取与测试集中的少数类别相关联的大量行。因此,所获得的性能指标并不十分可靠。因此,来自每个类的 75%的数据成为训练集的一部分,来自每个类的 25%的数据成为测试集的一部分。因此,来自每个类的 75%和 25%的数据分别构成了训练集和测试集。训练集和测试集中的结果行数分别为 2230 和 744。

训练:对于第一次迭代,112 列(预处理后剩下的列)用于训练。“id”和“household_identifier”列等字母数字特征已从训练集中删除。用于训练分类器的超参数是:“ntree=500”和“mtry=10”。测试了各种“mtry”值,但等于 10 的“mtry”会产生更好的性能。为了减少用于训练的列数,从已训练的模型中提取 MeanDecreaseinGini 值。基尼系数的平均下降值与特征的重要性直接相关。某一特征的基尼值的平均降幅越大,它在预测目标变量方面的重要性就越大。图 6 显示了 15 个最重要的特征。在接下来的迭代中,只有这 15 个特征用于训练。这通过将功能的数量从 112 个减少到 15 个来降低培训成本。

Fig. 6 — Top fifteen important features from the random forest model

Fig. 7 — OOB estimate and Confusion Matrix without Sampling

OOB 误差估计如图 7 所示。可以注意到,“四”的分类误差非常小。然而,“一”、“二”和“三”的分类误差很高。该模型在类 4 上训练得很好,因为类 4 的记录数量相对较高,因此误差较低。但是,由于与“一”、“二”和“三”类相关联的记录数量较少,模型没有被很好地训练,因此误差较大。

采样:为了调整数据集中类别的分布,采用了两种流行的技术,即欠采样和过采样。对一个类进行欠采样涉及只获取与多数类相关联的一小部分记录。为了说明,仅从类别“四”中提取一些记录,并使其成为数据集的一部分。属于其他少数民族阶层的记录不变。欠采样导致数据丢失。过采样包括合成/复制属于少数类的记录。

欠采样:对‘四’班进行了随机欠采样。35%属于“第四类”的记录是随机选择的,并且是数据集的一部分。因此,属于“四级”的记录数量从 1954 年减少到 684 个。没有对属于其他类的记录进行采样。在欠采样之后,图 8 和图 9 分别示出了训练集和测试集的类别分布。图 10 详细描述了欠采样数据集的 OOB 误差估计。可以观察到,当与图 7 相比时,类别“一”、“二”和“三”的 OOB 误差估计没有显著降低。“四”的等级误差增加了。由于所有类别的可用记录数量较少,因此该模型在任何类别上都表现不佳。因此,在记录数量较少的情况下对数据集进行欠采样是一种糟糕的方法,因为这会导致欠拟合。

Fig. 8

Fig. 9

Fig. 10 — OOB estimate and Confusion Matrix during Under-sampling

Fig 11 — OOB estimate and Confusion Matrix during Oversampling

过采样:对‘一’、‘二’和‘三’类进行了随机过采样。与提到的类别相关联的记录已经被适当地复制,以最小化类别分布的差异。过采样后,图 12 和图 13 分别表示训练集和测试集中的类别分布。该模型已经被重新训练,并且 OOB 误差估计表示在图 11 中。

Fig. 12

Fig. 13

可以注意到,总的 OOB 误差估计和相应的分类误差有显著的降低。因此,过采样少数类的记录促进了更好的模型训练和开发。图 14 和图 15 表示在欠采样和过采样期间,随着树的数量的增加,不同类别的训练错误率的变化。红色、绿色、蓝色和紫色分别代表“四级”、“一级”、“二级”和“三级”。黑线代表总的 OOB 误差率。在过采样期间,所有类的错误率随着树的数量的增加而降低。

测试:测试集中的记录总数为 488 条。它包含从每个类别中提取的 25%的记录。“目标”、“id”和“家庭标识符”列已从测试集中删除。结果数据被发送到训练好的随机森林分类器以获得结果。对于测试集中的每个记录,分类器利用通过训练获得的知识来预测该记录的类别。预测的标签将根据它们在“目标”类中的原始值进行评估,这些值决定了模型的性能。

性能度量:准确性是评估分类模型的主要度量之一。其定义如下:

Fig. 14

Fig. 15

然而,在分类问题中,不能仅使用准确度来评估分类器。可以通过混淆矩阵对所获得的结果进行更仔细的检查。混淆矩阵是不同类别的预测值和实际值的组合。可以从中推导出重要的度量标准,如精确度(特异性)和灵敏度(召回率)。敏感性也称为真阳性率。特异性也被称为真阴性率。现有类别的准确性、敏感性和特异性的值越高,模型就越好。

caret (Kuhn 等人,2019 年)软件包中的函数“混淆矩阵”用于通过提供实际值和预测值作为输入来获得混淆矩阵。图 16 和图 17 表示对于相应技术的混淆矩阵和分类器的性能。但是,必须调整总体中表示的度量,因为这些度量是针对提取的样本,而不是针对整个总体。因此,必须对获得的度量进行调整,以使它们反映实际总体。

对于一个样本,如果 C1、C2、C3 和 C4 分别表示“一”、“二”、“三”和“四”类的分类度量,那么,其整个/原始总体的加权度量值表示为:

其中 N1、N2、N3、N4 代表原始/实际人口规模,S1、S2、S3、S4 代表样本人口规模。因此,在欠采样数据上训练的分类器的加权准确率、加权特异性和加权灵敏度分别为 53.41%、78.65%和 18.01%。在过采样数据集上训练的分类器的加权准确率、加权特异性和加权召回率分别为 84.39%、93.24%和 84.44%。

评估 R3 提及的特征与贫困水平之间的关系:为了评估受教育程度、性别、户主、人数、家庭房间数、依赖性和技术(手机、电脑、电视、平板电脑)与贫困水平之间的关系,仅使用以下提及的特征训练模型。然后,使用经过训练的模型来预测测试集中的记录。新分类器的性能度量越接近旧分类器的性能度量(用前 15 个重要特征训练的模型),所提到的特征和“目标”(贫困水平)之间的关系越强。

Fig. 16

Fig. 17

通过过采样类“一”、“二”和“三”来训练新模型,但是仅使用特征“edjefa”、“edjefe”、“受教育年数”、“男性户主平方”、“依赖性”、“过度拥挤”、“meaneduc”、“受教育年数”、“家庭中女性总数”、“家庭中人员总数”、“移动电话数量”、“家庭中男性总数”、“如果家庭中有笔记本电脑或台式电脑”。图 18 详细描述了在测试集上获得的再训练模型的性能度量。

Fig. 18

Fig. 19

原始人群的总校正加权准确性、加权敏感性和加权特异性分别为 81.11%、0.8115 (81.15%)和 0.9059 (90.59%)。结果表明,这些特征表现出与“目标”类的强烈关联。它们的排序后的 MeanDecreaseGini 值如图 19 所示。在所选择的特征中,“上学年数”是最重要的特征,而“如果家庭有笔记本电脑或台式电脑”是最不重要的特征。

聚类:聚类技术便于根据相似性度量对记录进行分组。K-Means 是一种著名的聚类技术,它使用距离度量(通常是欧几里德距离)来对数据点进行聚类。质心是 K 均值聚类中最具代表性的点。“cluster”(rousse euw 等人,2019 年)、“facto extra”(Kassambara 等人,2017 年)和“purrr”(Henry 等人,2019 年)分别用于 K 均值算法、聚类可视化和肘图(图 20)。在“评估 R3 提及的特征与贫困水平部分之间的关系中使用的特征仅用于聚类,因为它们与 R3 提及的因素相关。K-Means 算法仅应用于上述特征。这里,分析的单位是一个人。输入聚类数被提供为 8,因为它看起来是肘图中膝盖上的弯曲(图 20)。用于随机森林的预处理数据也用于 K-Means。“目标”列从数据集中删除。

Fig. 20 — Elbow Plot

Fig. 21 — Visualization of K-Means Clusters

图 21 显示了 8 个集群的可视化。X 轴和 Y 轴表示由具有最高方差的两个主成分表示的记录的缩减维度。仅通过可视化的“factoextra”包使用 PCA 进行降维。在 K-Means 中,每个记录被分配到其最近的质心,该质心由一个聚类数表示。图中的每种颜色代表一个聚类。

比较一个记录和它的簇号,以便进一步分析。目的是发现 K-Means 是否具有将具有相似贫困水平的记录聚类在一起的能力。桌子。1 代表个人贫困水平在所产生的组群中的分布。可以推断,K-均值聚类在确定贫困水平方面并不有效,因为所得聚类与原始贫困水平之间没有关联。原因可以归结为不平等的类分布和数据的非线性。在最小化类内平方和的同时,该算法给予大类比小类更多的权重。因此,没有观察到明显的组。贫困水平分布在各个组群。为了检查输入聚类数的重要性,提供不同的值作为输入,并相应地生成 K 均值聚类。然而,集群数量的增加并没有导致有效集群的形成。作为实验,从训练的随机森林模型获得的前 15 个特征(都是连续变量)被用来代替 R3 的特征,以生成 K-均值聚类。这也没有显著改善结果。

Table 1 — Distribution of individual poverty levels in the clusters (when input number of clusters = 8)

调研问题答案:
R1 答案:
有。构建了随机森林分类器,以通过良好的性能指标成功确定哥斯达黎加家庭的贫困水平。随着更多数据的可用性,模型的性能可以得到改善。
R2 回答:是的。决定一个家庭贫困程度的 15 个最重要的栏目,按其重要性递减的顺序是:"上学年数"、"平均教育程度"、"年龄年数"、"抚养程度"、"过度拥挤"、"房子里所有房间的数量"、"移动电话的数量"、" edjefe "、"受教育年数、男性户主平方数"、"子女数、0 岁至 19 岁、家庭中的子女数"、"月租金支付额"、" edjefa "、"家庭中女性总数"、"卧室数"
R3 的回答:是的。问题 R3 中提到的与实体相关的特征与家庭贫困水平之间有着密切的关系。
R4 答案: K-Means 聚类技术在将具有相同贫困水平的记录聚类在一起时表现不佳。因此,在缺少“目标”列的情况下,并且利用 R3 中的给定特征,K-Means 聚类算法不能帮助为个人/个体分配类别标签。

参考文献: 哈德利·威克姆、罗曼·弗朗索瓦、莱昂内尔·亨利、基里尔·穆勒(2019)。dplyr:数据操作的语法。r 包版本 0.8.3。https://CRAN.R-project.org/package=dplyr

哈德利·威克姆(2019)。stringr:通用字符串操作的简单、一致的包装器。r 包版本 1.4.0。https://CRAN.R-project.org/package=stringr

H.韦翰。ggplot2:用于数据分析的优雅图形。2016 年纽约斯普林格出版社。Tableau 软件(2019)。从 https://www.tableau.com/取回

Taiyun Wei 和 Viliam Simko (2017 年)。r 包“corrplot”:相关矩阵的可视化(版本 0。84).可从 https://github.com/taiyun/corrplot获得

A.Liaw 和 M. Wiener (2002)。randomForest 分类和回归。r 新闻 2(3),18 - 22。

马克斯·库恩。供稿来自杰德·温、史蒂夫·韦斯顿、安德烈·威廉姆斯、克里斯·基弗、艾伦·恩格尔哈特、托尼·库珀、扎卡里·迈尔、布伦顿·肯克尔、R 核心团队、迈克尔·贝尼斯特、雷纳德·莱斯卡博、安德鲁·齐姆、卢卡·斯库卡、唐远、坎·坎丹和泰勒·亨特。(2019.分类和回归训练。r 包版本 6.0-84。https://CRAN.R-project.org/package=caret

Maechler,m .,Rousseeuw,p .,Struyf,a .,Hubert,m .,Hornik,K.(2019)。聚类:聚类分析基础和扩展。r 包版本 2.1.0。

Alboukadel Kassambara 和 Fabian Mundt (2017 年)。factoextra:提取并可视化多元数据分析的结果。r 包版本 1.0.5。https://CRAN.R-project.org/package=factoextra

莱昂内尔·亨利和哈德利·韦翰(2019)。函数式编程工具。r 包版本 0.3.2。【https://CRAN.R-project.org/package=purrr

Tableau 软件(2019)。从 https://www.tableau.com/取回

聊天机器人能让政府工作变得更容易吗?

原文:https://towardsdatascience.com/could-a-chatbot-make-working-in-government-easier-b75358f6d40f?source=collection_archive---------20-----------------------

在三周的时间里,我参与了哥伦比亚特区政府的一个研究项目。前两个星期用于用户研究和综合,最后一个星期围绕着设计我们研究中发现的一个问题的解决方案。我有一个简短的总结研究,导致我的设计如下。如果你对这个项目研究部分的更多细节感兴趣,你可以在这里阅读我的案例研究。

研究概述

第一周,我们在首席技术官办公室和地区总务部门对地区机构员工进行了 14 次 30-60 分钟的采访。接下来的一周,我们综合了我们所听到的。以下方法用于合成:

  • 关联映射到小组痛点、机会和进展顺利的事情
  • 热图查找主题
  • 人物角色、场景和客户旅程

这些主题导致了对三个机构的建议:DC 人力资源、地区总务以及合同和采购办公室(OCP)。在项目的最后一周,我们的团队分头关注不同的难点,并着手设计可能的解决方案。我关注的是我们发现的 OCP 最大的痛点。

规定

问题: OCP 难以提供一致的信息来指导其他机构的员工完成签约和采购流程。我决定进一步挖掘这个问题,看看是否有机会通过构建某种对话式用户界面(CUI)或平台工具来改善这种情况,这种工具可以为机构员工提供有意义的影响,并且可以在不到一周的时间内进行原型开发和测试。

在我们采访中给出的故事和例子中,我发现了受访者提出的机会,一点点自动化可以带来很大的不同。

有一种东西叫做商品代码,我认为这些需要更清楚一点。因为…根据您选择的商品代码,它应该会自动发送给特定的人进行审批。

—地区机构雇员

这是一个很好的机会来帮助改善 OCP 的问题,提供一致的信息:一个 CUI 可以为机构雇员提供一个一致的信息来源的商品代码,并确保他们选择正确。

那么,你可能会问什么是商品代码? 事情没有听起来那么复杂。基本上,它只是一个数字代码,确保对进出口商品或服务支付正确的税款。商品编码有一个国际标准,称为商品名称及编码协调制度(HS 编码),长度为 6 位数字,随着不同国家数字的增加,这一编码可以变得更加具体。对于美国进口的商品和服务,企业使用协调关税代码(HTS 代码),这只是一个 6 位的 HS 代码,后面跟着另外 4 位。

NIGP Code Search Results

区政府使用一个名为国家政府采购商品代码协会的七位数系统,缩写为 NIGP 代码。这些代码之所以重要,是因为当使用不正确的商品代码时,会产生许多负面影响。这可能会导致延误、货物错运,并可能导致罚款,甚至在某些情况下被指控欺诈。OCP 在他们的网站上有一个数据库搜索功能,但是正如一位受访者指出的,这些功能经常会被选错。很容易看出错误是如何产生的。快速搜索“椅子”,可以筛选出 171 个结果!

目标: 构建一个健壮的聊天机器人,它可以为代理机构的雇员提供正确的商品代码,并将带有该代码的采购订单发送给正确的人进行审批。

设计

我的第一步是勾画出用户获取正确代码所需的基本流程。

First Pass for User Flow

我开始用一个僵尸社会原型测试用户流,在那里我发现我需要更多的选项以防用户找不到他们需要的东西。例如,如果他们的搜索没有结果,他们可能想联系一个真实的人寻求帮助。我还发现,在这一点上,OCP 使用 NIGP 代码,而不是 HTS。接下来,我回去在白板上优化我的用户流。

Second Pass for User Flow

在第二次通过用户流之后,我在基于 Facebook Messenger 的聊天机器人工具 Chatfuel 中构建了一个交互式原型。我对这个交互式原型进行了用户测试,确保没有死角或令人困惑的副本。最后,我向客户演示了我的聊天机器人。

Interactive Chatbot Prototype

外卖食品

当谈到解决服务设计问题时,聊天机器人可能不是我们首先想到的,但它们可以是一个很好的起点,来定义用户需要做什么才能达到他们的目标。在设计限制方面,聊天机器人简化了可能性,并让我们思考一个结构化的双向对话到底能完成多少工作。

加密货币会引发向绿色能源的新转变吗?

原文:https://towardsdatascience.com/could-cryptocurrencies-initiate-a-new-transition-to-green-energy-f18c033dbff9?source=collection_archive---------18-----------------------

走向数据科学

比特币、以太和其他另类交易正在世界各地激增,现在已经成为我们日常生活的一部分。迄今为止,加密货币很可能引发一场有利于可再生能源的变革。

[## 绿色还是绿色,这是一个秘密问题!

加密货币能源范式的必要变革。

medium.com](https://medium.com/@smbilodeau/to-be-green-or-not-to-be-that-is-the-crypto-question-536f302f4498)

区块链模式变得越来越负责任,并完全依赖于分散系统的潜力。一些专家会更正式:区块链可以在替代能源的分配中发挥重要作用,就像在公共服务的发展中一样。区块链和/或加密货币与清洁技术的结合提供了很好的选择,包括人工智能、可再生能源和混合能源存储,特别是利用数据中心运营产生的废能回收和热量转换来提供能源。

但是其他人却不这么想。的确,比特币网络存在能耗问题。尽管每年要处理大约 1 亿笔金融交易,但它消耗了大量的能量。相比之下,传统金融业每年处理 5000 亿笔交易。如果我们考虑数据中心使用的能源量,比特币每笔交易消耗的能源比世界上所有银行消耗的总和还要多。

所以,这还是一个没有解决的问题。你怎么想?

我们就此交换吧!

Source: Smart Phases, Blockchain to boost Power Generation with Renewable, Energy Storage and Artificial Intelligence.

这篇文章是一系列关于区块链、人工智能和能量储存的文章的延伸,作者是荷兰的夏羽·比洛多。工程博士,对外经济合作中心。创始人&首席技术官、Smart Phases ( Novacab )、加拿大工程师协会会员以及能源中心和媒体的专家撰稿人。

数据分析能防止不必要的痛苦吗?

原文:https://towardsdatascience.com/could-data-analysis-prevent-unnecessary-suffering-lessons-to-learn-from-the-vaginal-mesh-scandal-793086d6bbcc?source=collection_archive---------34-----------------------

从阴道网丑闻中吸取的教训。

The most frequent words used in the titles of scientific articles concerning meshes for pelvic organ prolapse from 1999–2019. Complications high up.

在阴道网丑闻的余波中,纽约时报和 T2 卫报广泛报道了强生子公司 Ethicon 如何未能警告病人和外科医生他们的产品所带来的“风险”,给成千上万的妇女带来了可怕的痛苦。

一些接受经阴道网片手术修复盆腔器官脱垂(POP)的女性最终出现了可怕的并发症,如网片暴露和侵蚀(当网片刺穿阴道壁或切割内部组织时)、阴道瘢痕、瘘管形成、性交疼痛和盆腔疼痛。使这种手术特别危险的是,一旦植入永久性(不可降解)网片,它通常是不可逆的。它的完全移除是极其困难的,有时是不可能的,因为它已经融入了自然组织。

一个特别令人困惑的经历是阅读 2011 年的 FDA 安全报告(是的,2011 年!),其中说得很明白:“基于包括 11,785 名女性在内的 110 项研究的数据,大约 10%接受经阴道网片修补的女性在手术后 12 个月内经历了网片侵蚀”。该报告还向医生提出了一项建议:“在大多数情况下,POP 可以在没有网片的情况下成功治疗,从而避免了与网片相关的并发症。”

根据 2011 年的报告,NHS 的数据显示在 2011-2018 年间,每年仍有数千名女性接受这种手术,这让我感到惊讶。

更多…英国卫生和社会福利大臣在 2018 年 2 月的辩论中被问及是否会立即暂停使用涉及阴道网状植入物的医疗程序。他所在部门的一名成员回答说:“政府不支持暂停或禁止使用外科手术网片设备。“药品和医疗保健产品管理局(MHRA)认为,外科网片装置在按预期用途使用时,作为适当治疗途径的一部分,在考虑相关风险和益处的情况下,以及在外科网片装置符合欧盟现行法律要求的情况下,是可接受的安全装置。”在我看来,在回应中不说“阴道网眼”使这成为一个相当空洞的交流。外科网片装置可以应用于从疝气到整形外科的任何东西。

但是很快,事情发生了变化。2018 年 7 月 10 日,英国国家医疗服务体系致函英国所有医疗主任,建议立即高度警惕阴道网片限制期。2018 年 9 月 12 日,苏格兰政府指示所有卫生局完全停止所有经阴道网片手术,直到制定出新的‘限制使用协议’。2019 年 4 月 16 日,FDA 通知所有用于经阴道修补的手术网片制造商停止销售和分销他们的产品。那么,什么发生了变化?不是数据。主要是公众压力、澳大利亚法庭案件和新评论完成了这项工作。

作为一名女性(FDA 的同一份报告称,女性一生中患持久性有机污染物的风险估计为 30-50 %)同时也是一名科学家,阅读这篇文章让我感到很困惑。让我们暂时忽略销售产品的公司。为什么医疗机构对自己的发现反应如此缓慢?为什么从 FDA 的审查到一些改变需要 8 年时间?

我只能猜测“模糊”的数据是罪魁祸首。我想知道,如果自 2011 年以来所有要做手术的女性都能获得清晰的统计数据,并充分了解风险,她们会接受手术吗?当然,问题在于这些信息,即使可以获得,也被淹没在乏味的报告和充满术语的科学论文中(其中大部分甚至不为广大公众所知)。更别说和你的医生讨论这个了。我不知道我是否是唯一一个试图利用最近的系统综述与她的医生协商(一个不必要的)医疗程序的人,但我可以告诉你:我没有得到很好的接受。更好地获取数据能增强我们的能力吗?

Some of the scary complications have been in the titles of the relevant articles for years. Major complication ‘erosion’ appears since 1998, continuously.

作为一名目前正在开发生物材料及其生物效应数据库的科学家( DEBBIE ),我对从已发表的科学文章中提取生物材料的生物反应数据很感兴趣。这一过程通常被称为“生物固化”。几乎可悲的是,我们作为人类收集的如此多的好的、有价值的知识隐藏在几公里长的文本中,几乎没有人愿意去读,大多是在付费墙后面。那么,为什么我们开采金矿的速度如此之慢呢?为此,处理非结构化数据会面临许多挑战。第一个是自动化识别、提取和评估信息的复杂过程。接下来的问题是如何确保你的结论是可靠的(验证)。最后,使数据清晰并确保其公开需要真正致力于公众利益。我认为是后者在阴道网眼悲剧中起了作用。

我很想快速(也很懒……)看一下科学文献中的阴道网。做一个 PubMed 搜索(PubMed 是访问美国国家医学图书馆书目数据库 MEDLINE 的开放式搜索引擎),我检索了总共 2509 个与‘骨盆器官脱垂’和‘mesh’有关的记录,其中 2197 个有英文摘要。阅读成千上万的文章远远超出了大多数人的时间和耐心,除非你进行系统的审查,否则你甚至不可能阅读所有的标题。但是,即使使用文本挖掘工具包中最简单的现成工具,也可以获得关于文本的基本信息。在这里,我对呈现为词云的词频做了一个快速而简单的分析,并检查了文章标题中关键复杂因素的出现(是的,有很多)。如果你不知道你在找什么,你可以使用一个无监督的主题模型,如 hLDA(见下文),对你的样本中的主要主题有一个粗略的想法,并看到有关于感染、侵蚀和组织反应的报告。这只是为了好玩。想象一下,使用适当的文本挖掘管道在完整的文章上可以提取出大量的信息。

In the case of vaginal meshes, the FDA took the trouble to conduct an in-depth systematic review of relevant clinical trials, which is a rather excruciating manual task. Applying hierarchical latent dirichlet allocation topic model (hLDA) to infer some topics from text files is a quick and lazy way to have a less accurate, but a certain idea, of what’s in it. I did just that on the 2197 records with abstracts, minimally optimized the parameters, and anyone can see for themselves the result. Topics discovered with key terms such as ‘infection’, ‘erosion’, ‘tissue’ and ‘response’. The term ‘complication’ was identified as the fourth most important in the largest subtopic discovered in the corpus (1618 abstracts). This is just a starting point.

那么我们还在等什么呢?当然,现在是我们下定决心挖掘我们辛苦收集的科学知识的时候了。不仅仅是为了利润丰厚的 T2 药物研发,也是为了保护公众健康和更多基于证据的实践。为了科学家、医生和患者的利益,组织历史数据的紧迫性似乎比以往任何时候都更加重要,我们必须尽快加强这些努力。花点时间再读一遍那些并发症,想象一下所有本可以避免的痛苦。

财务鸣谢:DEBBIE 项目已经获得了欧盟 Horizon 2020 项目的资助,该项目是根据玛丽·斯科多瓦斯卡-居里赠款协议获得的,项目编号:751277

  • 这里的所有分析都是使用 R 包(ggplot,tidytext,tidyr,dplyr)和 python (nltk,hlda.sampler,matplotlib) 进行的
  • 要实现层次 LDA 主题模型,请参见hlda/hlda/sampler . py中清晰简单的示例代码
  • 从 PubMed 及其 Ebot 中检索文本
#make a word cloud on R from the article titles in df format
#identify words of interest and create a heatmaplibrary(tidytext)
library(wordcloud2)
library(ggplot2)df <- titles %>% unnest_tokens(word, title) %>% anti_join(stop_words) %>% count(word) wordcloud2(data=df, size=0.7, shape=elipse) df_complication <- df[df$word %in% c('complications','adverse', 'pain', 'fistula', 'scarring', 'erosion')]ggplot(df_complication, aes(x=year, y=word, fill=n))+geom_tile()+theme(text=element_text(size=16))

朱莉娅能取代斯卡拉吗?

原文:https://towardsdatascience.com/could-julia-replace-scala-77b73c345f6e?source=collection_archive---------12-----------------------

实话实说:我们中的很多人真的希望将 Scala 从我们的数据科学工作流程中移除。Spark 是管理企业级 Hadoop 和协调工人进行深度学习的一种很好的方式,然而,这种努力的开销明显比 R 和 Python 等传统统计语言更重。幸运的是,麻省理工学院开发的一种语言正在进行学术研究,它有很大的潜力将我们喜欢的 Spark、Python 和 R 的所有东西结合到一个方便的包中。

Spark 是 Scala 内置的多功能数据管理工具,也是数据科学家最常使用的可扩展语言。Spark 的主要优势来自大数据,因为它与 Hadoop 的集成以及快速的速度使其非常适合用于大型、未管理的数据集,这些数据集需要大量处理才能访问和操作。

然而,Spark 的继承性让它在很多方面都停滞不前,传统上这种语言对于机器学习操作来说是不可行的。Spark 的一个有争议的缺点是,Spark 比数据科学中通常使用的其他语言更难使用和阅读。通常使用的语言包括 R、Python、Matlab 和 Go 等。然而,这些语言中有很多都有自己的问题。在 Python 中,这通常是一项乏味的任务,或者根本不可能处理大型数据集。r 有它自己的缺点,这些缺点源于它的起源。

虽然我肯定不会说 R 很有挑战性(大多数时候),但是像 Python 这样的语言确实从创业的角度把 R 打下了基础。此外,R 也有自己的速度问题,尽管肯定比 Python 快。最后但并非最不重要的是,在 R…

但是当我们将所有这些缺点与 Scala 的缺点进行比较时,Scala/Spark 的启动曲线要困难得多,有时非常难以使用,并且更容易将数据分成不同的文件以读取不同的语言。

对于某些人来说,启动和易于阅读可能不是一个很大的缺点,但是下一个缺点对于数据科学来说绝对是一个很大的缺点。

浮点精度错误本质上是 Sparks 的中名,并且是您可能经常发现自己试图通过操纵软件的前几行来解决的问题。当然,这并不理想:这是一种带有浮点不精确性的统计语言,有时让人无法不弃船退回到 R 和 Python 的舒适环境中。

此外,考虑到它植根于 JVM,任何形式的递归都有许多问题,我已经解释了我对递归的热爱(尽管许多人对它有抱怨。)没有递归优化意味着在循环栈内部固有地需要递归的神经网络运行起来比考虑到递归的最新语言慢得多。有鉴于此,Java 和 SBT (Scala 构建工具)在设计时都必须考虑到统计学。

但是朱莉娅呢?

Julia 走在前面,它的结构是 BASIC、Python 和 MATLAB 的奇怪混合。这使得朱莉娅容易学习,也容易阅读。Julia 的优势在于它是一种统计语言,本质上是为了满足数据科学和机器学习的需求而从头开始构建的。最重要的是,Julia 有一个专门用于管理 Hadoop 的包,还有许多支持日常统计和机器学习的包。

Julia 非常适合一般的数据科学用途。Julia 是我用过的唯一一种统计语言,它处理大数据的能力一直让我感到惊讶。我曾经遇到过这样的情况,有些数据帧甚至用 R 和 Python 都无法读取,但在 Julia 内部却很容易清理、处理和学习。在我看来,一种能让你避免因缺乏计算能力而丢失数据的语言是一种很棒的语言。我只达到过我个人硬件的极限,从来没有达到过 Julia 的极限,主要是在通过数百万次观察进行深度学习的过程中以内存转储的形式,因为我只有 8g 的内存!

除此之外,浮点问题是不存在的,Julia 在处理数百万种“大浮点”数据类型时仍然表现出色。在可预见的未来,如果 Julia 成为数据科学工作的首选,我不会感到惊讶。

最后一点,不管你扔什么东西,Julia 都很快,递归的问题肯定不存在。正如我在三个不同循环(实际循环、递归循环和迭代循环)之间的速度测试中所展示的,Julia 的递归优化得非常好。

能够用一种语言轻松管理 Hadoop、操作和测试大数据以及编写和利用算法是一个巨大的优势。尽管我非常喜欢 Python、R、Scala/Spark,以及介于两者之间的任何东西,但我经常发现自己希望在使用它们的时候使用 Julia。朱莉娅很强大,非常强大,对我来说,这种力量是不可估量的。Julia 的速度快如闪电,处理大量数据,易于阅读,而且极其准确。朱莉娅是我喜欢的所有语言的完美结合。如果你只是对数据科学感兴趣,或者你碰巧是一名饱受战争摧残的 DS 老兵,我无法表达我对这门语言的热爱,也无法表达我对它是如何扭曲世界的一种尝试。

机器会变得有创造力吗?

原文:https://towardsdatascience.com/could-machines-become-creative-49f346dcd3a3?source=collection_archive---------25-----------------------

人工智能与知识工作

德克·克内梅尔和乔纳森·福利特

Figure 01: Creative output from AI, like artwork, has seen its proof of concept in recent years. What can we expect from AI in the years ahead? [Photo: by Martino Pietropoli on Unsplash]

人工智能自动化正在到来,它将影响知识工作者——作家、艺术家、设计师、科学家、经理和企业家。然而,即使当人工智能自动化完全取代了对人类的需求——比如它征服了像国际象棋和扑克这样的战略游戏——世界并没有终结,人类元素也没有消失。情况不同了。很大程度上更好,在某些方面更糟,但生活实际上还在继续。人类继续做我们的事。机器变得越来越好,越来越好。人工智能既神奇又被过度炒作。至少在几十年或几个世纪内,人类是安全的。

那么,在未来的几年里,我们能真正期待人工智能带来什么呢?人工智能将如何影响创造力和知识工作的世界?虽然人工智能肯定被用来创作艺术品,但这些作品更多的是好奇或概念验证。2016 年,J. Walter Thompson 的Next rembrant项目教会了人工智能像大师一样绘画。2018 年,纽约佳士得拍卖行首次出售人工智能制作的艺术品《埃德蒙·贝拉米的画像》。该印刷品本身是由法国艺术集体“明显”的人类开发的算法创建的。这些是最近取得的显著成就,但它们是孤立的行动。人工智能协作艺术成为主流没有明确的路径。

为了更清楚地了解人工智能何时可能开始改变各种创造性工作,我们采访了 AI Impacts 的 Katja Grace,这是一家专注于人工智能未来决策相关问题的研究机构。它是预测,广义地说,人工智能的进步和对社会的影响。Grace 是 2017 年一篇题为“人工智能何时会超过人类表现”的论文的第一作者。人工智能专家的证据。”

渐进还是冲刺?

技术进步通常很慢,当一个关键的新进展实现后,就会很快。但是慢的往往不像看起来那么慢,快的也不像我们想象的那么快。因此,不管人工智能如何演变,我们都应该期待它的表现没有我们想象的那么极端。

“你可以想象人工智能的进步是以一种渐进的方式发生的,每年都有比以前稍微好一点的人工智能。或者,你可以想象,在某个时候,我们有了一些惊人的洞察力,从而非常突然地拥有了非常好的人工智能。通常,人们预期后一种情况会发生,并相应地制定计划……我们感兴趣的是这两种情况发生的可能性有多大,”Grace 说。

从历史上看,有很多原因我们可能会认为人工智能将逐步发展。然而,有各种各样的理由期待有突然和令人惊讶的进展。什么可能使人工智能自动化的激增成为可能?“最近我们生活的数字化意味着有更多的数据 Grace 说。“深度学习让你使用大量硬件和数据来获得良好的结果。硬件的出现让科学得以快速发展。”

自动化知识工作

对于大多数人来说,自动化作为创造性工作的核心的想法要么是未知的,要么是不舒服的。然而,在 Grace 作为人工智能研究人员的工作中,自动化作为一种无处不在的力量的模型是清楚的:“我认为怀疑深度学习将自动化知识工作的部分原因是我们认为很可能某种东西最终将自动化知识工作,”Grace 说。“我们知道人类可以做知识工作。因此,或许让机器来做这件事也是可能的——除非你认为人类有某种神奇的意识火花,这是我们永远无法自动化的。”

“我认为许多人怀疑事实并非如此,所以问题是什么技术会让我们做到这一点?怀疑深度学习可能是这样的一个原因是,我们最近看到在自动化一些正常人类功能的一部分方面取得了很大进展,这些功能是我们以前无法做到的,是大多数工作的关键,例如,识别和处理图像、语音和写作。”

“我们已经看到深度学习做了一些看起来相当智能的事情,例如,很好地玩各种游戏。你可能会认为,让我们玩得好的那种技术,不会离我们做好一些相对简单的智力工作的需求太远。我想有些人认为这种技术可能会让我们拥有人工智能,它可以做人类能做的一切事情,但这更有争议。”

grace 2017 年的论文《AI 什么时候会超过人类的表现?来自人工智能专家的证据”,是基于一项对研究人员的调查,这些研究人员在 2015 年神经信息处理系统会议和 2015 年机器学习国际会议上发表了论文。一部分受访者被问及一个强调就业后果的问题。这个问题将劳动力的完全自动化定义为所有职业都完全自动化。那时,对于任何职业来说,机器都可以比人类工人更好、更便宜地完成任务。总体预测认为,50%的可能性在 122 年后,也就是 2138 年前出现。人工智能在各种知识工作中实现人类绩效的中值估计时间表包括:

  • 用 5 到 10 年的时间,写一篇高中作文
  • 在 10 到 15 年内,创作出一首排名前 40 的流行歌曲,并且
  • 在 25 年或更长的时间里,写一本纽约时报畅销书

鉴于 Grace 的论文预测了人工智能将在许多领域超越人类表现的时间框架,我们希望获得她对一些核心知识工作的意见——具体的创造性实践,如写作和音乐。

写作

人工智能多久才能达到人类的水平?“你可能会想象有助于写得更好的工具,但这些工具在过程中并不完全是自动的。或者你可以想象一些只为你做新闻的事情,”格雷斯说。“我预计相对而言,很快就会有更好的工具出现。”然而,“为了写得足够好,让作者对世界有一个连贯的了解,有一个他们试图传达的信息或目标,有一个他们试图传达给观众的想法,[这]似乎接近 AGI 全集。但是,我预计人工智能能够写出有趣的文字或者让人觉得值得一读的文字可能还为时过早。”

格雷斯认为,机器独立写作的局限性在于,它们无法将对世界的广泛理解应用到它们所写的东西上。我们将发现背景是人工智能的致命弱点——并且应该在未来十年继续存在——这是一条关键的粉笔线,有助于指导人工智能将做什么和不能够做什么。格蕾丝也将拥有上下文的能力等同于 AGI 的完整性,这意味着有一种人工的普遍智能使人类的能力黯然失色。这与科幻小说和机器将接管世界的叙事如出一辙。虽然这条主线确实是显而易见的,但将语境和 AGI 联系得太紧密是错误的。拥有广博的知识是一回事;拥有广泛行动的能力完全是另一回事。

Figure 02: How soon might AI write at a human level?
[Illustration: “The Artist’s Son Writing”, 1887, Paul Cezanne, National Gallery of Art, Open Access]

音乐

流行音乐呢?在调查论文中,“我认为很早就很有趣的一件事是,我们问 AI 什么时候能够基本上像泰勒·斯威夫特一样写一首泰勒·斯威夫特的新歌,这样一个忠实的泰勒·斯威夫特粉丝就无法区分这首新歌和她写的和表演的歌曲之间的区别。[研究人员调查]认为大约 10 年后。你可能会想,为了写作,为了真正成为一名作曲家,你需要理解你所说的话。这些机器学习研究人员可能只是对泰勒·斯威夫特没有很好的看法,他们认为这很快就会自动化。”

抛开所有关于泰勒·斯威夫特歌曲内容的笑话不谈,音乐和艺术都是当今人工智能自动化的目标。例如,Aiva(人工智能虚拟艺术家)是一位人工智能作曲家,他创作了用于电影、广告和游戏配乐的音乐,并且是第一位得到作者权利协会认可的虚拟艺术家。

Figure 03: Music is one creative area with numerous AI advances in automation.
[Photo: by Franck V. on Unsplash]

创造性人工智能的后果

创造性人工智能的高级开发有哪些风险或意想不到的后果?“制造一种技术可能很简单,它可以……做出非常高质量的决定,玩游戏玩得非常好,在现实世界中玩得非常好,(例如)赚很多钱。但如果这很容易,而我们还没有想出如何让他们完全按照我们的要求去做,我们可能会以一场巨大的混乱而告终,”格雷斯说。

“如果你可以看看如何建立一家通过生产东西赚钱的公司,但你没有想出让它关心你所关心的所有人类价值——比如河流是否被污染,你往往会以河流被污染而告终。同样,如果你制造的机器非常擅长优化某些东西,但并不真正知道你在乎什么,那么,在没有任何恶意的情况下,它们最终会摧毁你在乎的东西。”

这些听起来和工业革命产生的风险和后果是一样的。当然,即使实际的变化比它应该发生的或者我们可能喜欢的要慢得多,但是心态和意图还是在进化。最终,政策将赶上这一速度,我们将看到国家、企业,最终还有个人大张旗鼓地避免工业化给我们带来的那种破坏性的污染行为。以一种更全面正确的方式做事将会成为做事的基本方式。

那么,机器能变得多聪明,与人类智慧相比又如何呢?“我想问题是:人类有多聪明就有多聪明?怀疑的理由是,人类大脑似乎受到相当大的限制,因为它需要适应人类的大脑,母亲们需要能够生下她们的孩子——生物学上的这种事情——以及它使用了多少能量?…看起来我们的大脑中存在着生物限制,这意味着即使理论上有更高的智力水平,它们也不会给人留下更深刻的印象,”格雷斯说。“即使拥有比我们见过的最聪明的人还要聪明的机器,也会给世界带来巨大的变化。”

Creative Next 是一个播客,探索人工智能驱动的自动化对创意工作者,如作家、研究人员、艺术家、设计师、工程师和企业家的生活的影响。本文附 第一季第 12 集——AI 什么时候会超过人类的表现?

我帮助制造了一个机器人,教自闭症儿童手语——这是我学到的

原文:https://towardsdatascience.com/could-robots-teach-sign-language-to-children-with-autism-8a6d7c3eb23a?source=collection_archive---------37-----------------------

内部 AI

机器人专家和自闭症治疗提供者的试点研究

一年前的 2018 年春天,我进行了一项机器人向自闭症儿童教授手语的试点研究。这篇博文反映了研究的结果,以及我们团队设计机器人的过程。整个研究可通过以下方式获得:

阿克塞尔松,硕士,拉察,硕士,韦尔,博士,凯尔基,V. (2019)。自闭症儿童辅助手语机器人导师的参与式设计过程。在 2019 年第 28 届 IEEE 机器人与人类交互通信国际研讨会(RO-MAN) 。IEEE。接受了。

这项研究是基于我在阿尔托大学的硕士论文。

机器人技术、手语和自闭症儿童

首先,我们来回答第一个大问题:为什么要在自闭症治疗中使用机器人?自闭症患者对物体的注意力偏好超过对人的注意力偏好(Kerola 等人,2009 年),自闭症儿童对涉及技术或机器人组件的治疗表现出更大的兴趣(Robins 等人,2006 年)。此外,机器人的操作可以受到严格控制,这可以使自闭症患者的治疗不那么困难(Kozima 等人,2009 年)。

那么,第二个大问题:为什么要教自闭症儿童手语?患有自闭症谱系障碍(ASD)的人在交流方面存在问题:40-50%的 ASD 患者在成年后功能性沉默(Bogdashina,2004)。为了缓解这种情况,他们使用了增强和替代沟通(AAC)方法。辅助手语——手语的简化形式——是 AAC 最常见的形式(Tetzchner & Martinsen,2000)。其他常见的 AAC 形式是象征性的图片和照片。

An example of a symbolic picture communication system used by children with autism: “We do assignments.”

结合这两个领域——自闭症儿童机器人和自闭症儿童手语——的想法最初来自萨塔昆塔卫生保健区。萨塔昆塔是芬兰西南部的一个小地区,人口 225 000。该地区的质量经理已经了解到一个机器人正被用于向神经典型儿童教授手语(Uluer 等人,2015 年),并希望对自闭症儿童研究同样的方法。

Satakunta 发现我工作的公司( Futurice )制造了一个人形机器人。他们伸出了手,我们组建了一个跨学科团队,重新设计和修改 Futurice 的人形机器人,以适应这一目的。我们的团队有三名来自 Futurice 的机器人专家和三名来自 Satakunta 的自闭症治疗专家:一名神经心理学家、一名语言治疗师和一名质量经理。

我们应该如何设计机器人?

Futurice 制造的人形机器人是一个 InMoov 机器人。 InMoov 由法国雕塑家盖尔·朗之万设计。他将机器人的原理图和软件开源,任何人都可以在网上看到。利用这些,Futurice 建立了自己的 InMoov。Satakunta 想用 InMoov,因为它灵巧的双手使它能够签名。它类似人类的外观也是一个优势:Satakunta 的一位神经心理学家认为类似人类的机器人最适合这种解决方案。

The original form of the open source humanoid robot InMoov, designed by Gaël Langevin. Image Wikimedia Commons.

然而,InMoov 并没有准备好。为了使机器人适合自闭症儿童,我们需要修改它的形式、行为、互动和环境。我的工作是设计机器人的这四个维度。我还需要设计人机互动研究,让孩子们和机器人见面并签名。幸运的是,机器人软件和硬件的开源性质使得进行必要的修改相对容易。

我们想在设计机器人时考虑自闭症障碍的特点。ASD 的特征是交流和语言的问题,社会行为的问题,常规的不灵活,以及形成对周围环境的整体感知的问题。然而,自闭症是一个谱系,所以这些特征在不同的人身上有不同的表现。由于不同的演示,我们知道我们无法设计出一个让所有人受益的机器人。然而,我们想找到最好的解决方案,为大多数自闭症儿童服务。

在项目期间,该团队为机器人创建了五个设计准则,这将为自闭症儿童量身定制其设计。例如,自闭症专家提出了孩子在实验过程中可能会分心的担忧。该团队一致认为,为了避免让孩子困惑,机器人的行为应该是一致的和有条理的。这被定义为指导方针:“一致的、结构化的、简单的行为”。为了遵循这个指导方针,语言治疗师和我为机器人和孩子的互动创作了严格的脚本。所有五个指南都是在共同设计讨论中以类似的方式制定的。

用于自闭症儿童的机器人设计指南:

  1. 单形
  2. 一致、有条理、简单的行为
  3. 积极、支持、有益的经历和环境
  4. 模块复杂性
  5. 针对儿童偏好的模块化设计

设计指南帮助团队维持机器人的逻辑和统一设计,并为设计过程中做出的所有决定形成基线。

嵌入式伦理

当团队讨论机器人的设计和实验时,提出了几个伦理问题。这些伦理考虑被嵌入到最终的机器人中。

人身安全 —用户可能会被机器人夹伤或压伤。为了减轻这种担忧,我们决定在互动过程中阻止孩子们触摸机器人。为了做到这一点,我们决定让语言治疗师在房间里陪着孩子,如果需要的话,阻止他们接近机器人。

数据安全 —用户数据的安全至关重要,尤其是在医疗保健应用中。在这里,我们决定对参加研究的儿童的所有数据进行加密。我们也没有记录任何不必要的数据。

适当的行为强制——人们可以从机器人身上学到不礼貌的行为。比如孩子在与语音代理 Alexa 互动后,忘记使用“请”“谢谢”等礼貌用语。Alexa 没有明确要求礼貌的语言,导致人们对它表现不好。在这种情况下,我们不希望孩子们学会虐待机器人,并潜在地将这种不良行为推广到人类身上。我们决定治疗师会干预所有对机器人的不良行为。

用户之间的平等 —人工智能算法在过去已经被证明是种族主义或性别歧视的(例如 COMPAS,一种在美国使用的累犯率预测算法,偏向于非裔美国人)。如果机器人使用算法来运行,算法的设计者需要小心。另一个要考虑的是机器人的形式。机器人设计已被证明会强化性别刻板印象,“天才”机器人通常被贴上男性标签,“服务”机器人则被贴上女性标签。在我们的案例中,我们想设计一个不分性别的机器人,这样每个参与研究的孩子都会感到受欢迎。为了做到这一点,机器人没有性别符号。

透明 —如果用户了解机器人如何操作和决策,他们可以校准他们对机器人的信任程度。在我们的案例中,我们决定在研究结束时告知孩子们和他们的同伴机器人的遥控性质。这样,他们可以避免对当今机器人技术的现状以及如何将其应用于自闭症治疗形成错误的假设。

情感上的考虑——研究表明,人类会像对待活着的机器人一样对待它们,即使它们显然已经不存在了。人们与机器人形成情感纽带。在设计中应该考虑到这一点:这个用例需要多强的绑定?在这种情况下,我们不希望孩子或他们的同伴认为机器人正在取代孩子和治疗师之间的联系。为了确保这一点,语言治疗师会一直和孩子呆在房间里。

平衡之举

为一个复杂的领域(自闭症治疗)建立复杂的技术(机器人)是困难的。问题空间对团队的双方来说都是不直观的:自闭症专家不熟悉技术限制,机器人专家不了解用户群。设计是一种平衡行为:设计中看似微小的调整可能会导致大量的技术工作。反之亦然,一些在设计上意义重大的改变在技术上也很容易实现。这是我花了大部分时间的地方——将团队的不同观点协调成一个好的设计,在我们 6 个月的时间框架内切实可行。我们一起做出了一系列平衡用户体验和技术复杂性的决定。

The final InMoov with modifications: new Ada hands, lights attached to its right hand, and a screen on its chest

当设计一个社交机器人时,有大量的运动部件(无论是字面上的还是比喻上的)。机器人的特性都是互相影响的。机器人的操作环境影响它的行为,影响它与用户的互动,影响它的形式。将这些设计考虑因素分离出来,并将其具体化为不同的、可实施的技术任务是一项挑战。

从最初的形式修改机器人花了 4.5 个月(最初的构建在 9 个月内完成)。我们所有的修改都遵循了设计准则:例如,我们将机器人类似人类的声音改为机器人声音,给它一个“简单的形式”(准则 1)。

为了让 InMoov 成为更好的手语老师,我们做了一些大的调整。我们给它新的 Ada hands,由开放仿生学设计,由大都会应用科技大学建造。我们还在它的胸部嵌入了一个屏幕,并在它的手臂上安装了灯光。添加屏幕是为了提供另一种交流模式(AAC 中经常使用照片),添加灯光是为了吸引孩子的注意力。

10 个孩子和一个机器人

10 个孩子参加了实验。有些人和父母一起来,有些人和其他支持者一起来。两名机器人专家(包括我)在实验室旁边的房间里,操作机器人并通过摄像头观察实验。第三个机器人专家在场来解决任何可能出现的问题。语言治疗师和每个孩子都在实验室,促进孩子和机器人之间的互动,并在需要时进行干预。

The 9 words the robot signed, and the corresponding images on its screen

机器人表演了 9 个手势。有了⅓的标志,它胳膊上的灯也闪了一下。随着另一个⅓的迹象,它显示了相应的图像在其屏幕上的迹象。对这三种不同的设计条件进行了检查,以确定哪一种最有效。

我对每个孩子与机器人互动的不同感到惊讶。在整个实验过程中,一些孩子以近乎完美的准确度做手势,仅用 6 分钟就模仿了机器人的所有手势。有些人花了长达 28 分钟的时间,与每个标志作斗争。一个特别的孩子——他不太喜欢签名——不停地嘲笑机器人。在整个实验过程中,这个孩子一直试图拥抱或扑向机器人,语言治疗师和神经心理学家在后面追赶,及时阻止他。

A child signs with the robot (picture with permission).

The speech therapist signals to the robot operators that the child signed correctly (picture with permission).

孩子们模仿并关注机器人

我测量了孩子们的手语准确度和注意力集中程度。孩子们和他们的同伴也完成了关于他们对机器人的看法的调查。

我们学到了什么:

1。孩子们可以模仿机器人,并注意它

10 个孩子中有 7 个成功模仿过机器人至少一次。在 70%的时间里,他们一直盯着机器人,表明注意力集中。参与调查的 8 个同伴中有 8 个也注意到孩子们与机器人有联系。

2。机器人屏幕上的图像很好

机器人在 1/3 的时间里在屏幕上同时显示一幅图像。孩子们的同伴发现这些图像很有用,并认为它们可以帮助孩子们学习。

3。这个机器人被认为不错,但是有点吓人

孩子们和他们的同伴都认为孩子们对机器人的体验很好。然而,一些孩子和他们的同伴指出,孩子们觉得机器人很可怕。在未来的设计中,应该识别并减少造成恐怖感的因素。

4。标志的性能需要提高

语言治疗师和孩子们的同伴都指出,机器人没有很好地标记所有的单词,这可能会影响孩子们对它们的理解。

仍需学习的内容:

1。孩子们理解这些标志吗?

对于这个实验,我只测量了孩子们是否模仿了这些标志。未来的实验需要验证孩子们是否理解它们。

2。谁从机器人中受益最大?

并不是所有的孩子都对机器人有相似的反应。这种基于机器人的手语疗法不太可能对所有自闭症儿童都有用。未来的实验应该考察这种疗法适合谁。同伴的调查结果支持了这种不同的好处:8 个同伴中有 6 个认为机器人作为手语教师可能是有益的。

3。如何输入语言治疗师的命令?

未来要使用机器人,治疗师需要能够独立控制机器人。对于未来的实现,用于编程机器人行为和交互的遥控器或 UI 可能是有用的。

4。准则 4 和 5 将如何影响设计?

在这个实验中,我使用了机器人的静态设计。只有它的交互发生了变化(在不同的点使用它的屏幕和灯光)。未来的研究需要检验设计准则“复杂性模块化”(准则 4)和“特定于儿童偏好的模块化”(准则 5)。这些可以帮助机器人适应不同的用户。

机器人手语教师的未来

人们与机器人密切互动会招致批评。最突出的担忧是机器人取代人类。在这种情况下,机器人并不打算取代人类的护理,而是增加和支持人类的护理。

治疗会议对治疗师要求很高。他们需要计划和进行会议,同时处理潜在的不合作的参与者。在未来,技术工具可以用来减少治疗师的认知负荷。机器人表演手势,而治疗师可以专注于鼓励、辅导和管理孩子。随着认知负荷的减少,会议可能会更长,从而更深入。如果机器人位于孩子的家中,也可能达到同样的效果:孩子将获得一个一致的工具来练习手势,机器人不会因为重复的练习而感到无聊或沮丧。

据我所知,这是第一次使用机器人向自闭症儿童教授手语。我希望这项研究能继续深入下去。我希望我们的飞行员能为将来如何开发这个应用程序提供一些启发。

Science — especially pilot studies — sometimes requires improvisation: lights from the robot’s back were reflected on a window behind it, which might have distracted the children. We fashioned a light-reflection-blocker for the robot’s back, out of a towel stolen from our hotel (we did pay for it).

该项目由 Prizztech 的 Robocoast 和 ERDF 基金以及 Futurice 资助。

A short video about the project, by Digitalents Helsinki.

o .博格达什娜(2004 年)。自闭症和阿斯伯格综合症的交流问题:我们说同一种语言吗?。杰西卡·金斯利出版社。

k .凯罗拉、s .库扬帕和 t .蒂莫宁,2009 年。自闭症,第一版。PS-kusta NUS。

科济马,h .,米查洛夫斯基,M. P .,,中川,C. (2009)。坚持住。国际社会机器人学杂志1 (1),3–18。

Robins,b .,Dautenhahn,k .,和 Dubowski,J. (2006 年)。在自闭症儿童与人形机器人的互动中,外观重要吗?。交互研究7 (3),479–512。

Tetzchner,S. V .,& Martinsen,H. (2000 年)。增强式和替代式沟通介绍(第 87-89 页)。呜。

乌卢尔,p .,n .阿卡伦和 h .科塞(2015 年)。一种用于手语教学的新型机器人平台。国际社会机器人学杂志7 (5),571–585。

我们能进化出人工智能吗?

原文:https://towardsdatascience.com/could-we-evolve-an-artificial-general-intelligence-fcceac1e1ae4?source=collection_archive---------29-----------------------

也许试图设计它不是办法…

Image by Skeeze, Pixabay

在过去的十年里,机器学习和深度学习的实践者在狭义人工智能问题上取得了惊人的进展。计算机已经非常擅长各种各样的任务,例如检测图像中的东西,这在以前被认为只有人类才能做到。这些程序向前迈进了一大步,但是它们只适用于特定的任务。对他们正在做的事情没有真正的理解。一台能真正思考、真正理解的计算机的梦想仍未实现。

有些非常聪明的人试图在软件和专门的硬件中复制人脑的能力。这还没有完成,可能是因为我们仍然在研究大脑是如何工作的。

我想还有一个办法。我们不必设计它。我们只需要设计一个人工环境,鼓励它进化。我们自己的大脑进化是因为智力为我们的祖先提供了优势。一个适当设计的虚拟环境,由用遗传算法进化的单个软件代理组成,可能会进化出一个人工智能。这可能很昂贵,但以目前的技术来看,这可能是可行的。

我们实际上是在模拟在一个孤立的星球上进化的高级生命。我们不需要从单细胞生物开始——像原始哺乳动物一样,已经安装了感觉和运动的生物会更好。这样我们就有了一个自由的开端,并且我们对这些是如何工作的有一个很好的理解。

不管怎样,我们为什么进化得如此聪明?

关于原始人发展智力的原因,有几种理论。就能量而言,维持一个复杂的大脑是昂贵的。喂养它需要付出努力,较大的头部在出生时带来了挑战。为了进化,它必须为我们最早的后代提供显著的优势。

攀爬的空间意识至关重要,早期简单工具的使用开辟了新的食物来源。有一种理论认为,我们的智力进化很大程度上是因为生活在更大的社会群体中有优势,需要更高的功能来驾驭在这样一个群体中生存和繁殖的复杂性。也有可能是我们的智力使我们能够在快速变化的气候和环境中生存下来。

目前可用的积木

几年来,复杂的神经网络已经通过强化学习成功地学会了玩视频游戏。固定架构的神经网络一遍又一遍地玩游戏,从游戏中接收游戏分数形式的反馈,就像人类玩家一样。神经网络的权重被调整以优化它接收到的分数。人类设计师为神经网络设计布局,并让它运行。

遗传算法,其中设计解决方案的参数以与生物系统相同的方式进化,已被证明在许多问题上相当成功。解决方案的个体特征被编码在虚拟基因中,然后与具有不同基因的大量不同个体竞争。在每次运行结束时,最成功的个体会经历一轮虚拟的变异和交配,它们的“后代”会存活下来再次竞争。重组和突变慢慢引入新的基因,并在环境中进行测试。

Image by Free-Images, Pixabay

进场

如果我们将这些方法结合起来,就会有巨大的灵活性。代替人类设计神经网络结构,我们可以将它编码成一组基因,允许网络的设计改变。应该允许它在复杂程度上有很大的不同。我们不知道最优解是什么,所以可供选择的范围应该很大。

为了连接虚拟感觉,我们至少标准化了神经网络输入的子集。我们标准化这些是因为我们对进化新的感官不感兴趣,而是对使用这些感官的大脑感兴趣。

我们必须设计这样的系统,使得虚拟有机体为更大、更复杂的大脑招致能量成本——这不是免费的。有机体必须从大脑中获得竞争优势,这种优势超过了维持它的成本。

现在——这是最昂贵的部分——我们将数千或数百万的这些虚拟生物放入一个复杂的虚拟环境中,顺其自然。

那个虚拟环境是什么样子的?

就图形而言,它不需要很漂亮。用户界面只需要提供状态信息,所以图形渲染可能非常简单。关键在于底层模拟。

我们使用的环境在很大程度上取决于我们想要产生什么样的智能。我们可以利用不同的环境进化出不同强度的智能。例如,一个需要解决复杂数学问题的环境可能会产生一个更适合抽象思维的人工智能。一个主要要求是管理模拟城市的环境可能会训练一个人工智能在现实世界中完成这种工作。

为了这个思想实验的目的,我们将坚持我们可能需要进化出类似我们的东西。

世界是关键

我们的大脑进化成一种帮助我们在复杂、充满敌意的世界中生存的方式。我们的模拟环境需要相当复杂。作为起点,这里是我能想到的可能需要的东西。几乎可以肯定还有更多。

当然,我们不能模拟一个完整的生物群落直到单个细菌。我们必须专注于自然选择的关键驱动因素,以保持所需的计算易于管理。

世界上的能源和其他资源肯定是有限的,而且分布不均匀,就像它们在现实世界中一样。如果能源太容易获得,就没有必要竞争,也没有什么可以推动进化。需要有能杀死粗心的有机体的自然危险,包括自然灾害和食肉动物。

Image by David Mark, Pixabay

我们可能想要模拟宏量营养素——蛋白质、碳水化合物和脂肪——在不同食物来源中的不同比例。我们想让我们的生物成为杂食动物,给它们最大的灵活性来收集营养。大型猎物需要强大的防御能力,这将推动合作和武器工具的发展。

环境需要支持简单的工具制作——一些食物资源可能只有使用工具才能获得。代理人需要能够在他们的虚拟世界中与相当小的物体互动。我们已经在较小的规模上做了类似的事情——例如,一个探索奥秘的演示让用户扔纸飞机并与其他小物体互动。模拟一个巨大的世界需要巨大的计算能力,但技术上没有巨大的飞跃。

世界需要以现实的方式做出回应——例如,应该有可能在河流上筑坝来建造鱼笼,或者把东西堆起来组装成简陋的结构。跌倒和受伤应该是一个很大的缺点。

生物体需要一种标准的方式在短距离内与同伴交流。真实的生物使用声音和视觉交流,但我不确定是否需要模拟。在每个有机体中包含一个标准的通信通道就足够了,就像感官输入被标准化一样。我们的目标不是进化通信渠道——而是进化处理与附近生物通信所需的智能。

因为人们认为社会结构推动了更高智能的发展,所以环境中需要有挑战,只有作为一个群体来开发,才能提供优势。应该考虑一种战斗机制,因为不管你喜不喜欢,它都是前进的重要驱动力。同样地,生物必须包含不同攻击程度的基因编码。环境中资源的不均衡分配会推动迁移和战争,这两者都会带来强大的进化压力。

一种计分机制将跟踪环境中每种生物的相对表现,健康的个体将被允许交配和繁殖。遗传算法非常成功地模拟了有性生殖和突变机制,这将是在种群中产生变异的关键。

我们需要确保世界发生一些周期性的快速变化——也许是由火山爆发或彗星撞击引起的重大气候变化。这将为适应性提供进化压力,就像这种变化可能对我们产生的影响一样。

简而言之,我们需要一个用于构建大型在线多人游戏的当前技术的混搭,再加上虚拟现实和强化学习的一些功能。我们只需要把它做大。有了足够复杂的环境和正确的选择压力,AGI 是有可能进化的。

开放式问题和挑战

我认为,最大的挑战是所需计算的庞大规模。我们需要模拟一个庞大复杂的世界,然后是成千上万个复杂的虚拟生物。我们需要非常详细地模拟世界和这些有机体之间的相互作用,并在数千个模拟世代中这样做。不会便宜的。

一个有趣的可能性是允许人们设计他们自己的候选生物体的遗传基因,并把它们放入环境中,观察它们的表现。这将为这一过程增加一个博弈的层面,并有可能加速这一过程。当然,在任何情况下,人类代表他们的有机体干涉世界本身都不是一个好主意——这个过程需要被允许顺其自然。原版《星际迷航》系列中的主要指令将完全生效。

原始人从向父母学习中受益匪浅。目前还不清楚在模拟世界中如何实现这一点。一些基本的本能可能也需要硬编码。

另一个悬而未决的问题是,我们将如何与我们设法进化的人工智能交流。他们会用什么渠道?也许这需要从一开始就建立在这个世界上,并与有机体一起进化。

计算能力越来越便宜。随着专门的神经网络硬件变得可用并且更加可配置,我们可能会达到这样一个点,即尝试这样做变得非常合理。这将会花费大量的时间和金钱,但不会与我们真正关心的其他大规模人类努力相冲突。利用现有的软件和硬件,现在可以创建更简单的世界,在更小的范围内测试这个想法。我觉得这值得一试。

你怎么想呢?可行吗?你有改进的想法吗?

使用 Python 用不到 10 行代码计算汽车数量

原文:https://towardsdatascience.com/count-number-of-cars-in-less-than-10-lines-of-code-using-python-40208b173554?source=collection_archive---------5-----------------------

使用这个简单的代码制作你自己的汽车计数器

Blue Volkswagen Beetle (Photo by Tom Arrowsmith on Unsplash)

当你还是个孩子的时候,开车旅行时,你有没有玩过一个游戏,在这个游戏中你会数经过的车的数量?

那曾经是我小时候最喜欢的游戏。

在这篇文章中,我将教你如何用 Python 只用 10 行代码构建你自己的汽车计数器程序。

如果尚未安装以下 python 库,则需要进行安装:

opencv-python
cvlib
matplotlib
tensorflow
keras

以下代码用于导入所需的 python 库,从存储中读取图像,对图像执行对象检测,显示带有检测到的对象的边界框和标签的图像,计算图像中的汽车数量并打印出来。

import cv2
import matplotlib.pyplot as plt
import cvlib as cv
from cvlib.object_detection import draw_bboxim = cv2.imread('cars_4.jpeg')bbox, label, conf = cv.detect_common_objects(im)output_image = draw_bbox(im, bbox, label, conf)plt.imshow(output_image)
plt.show()print('Number of cars in the image is '+ str(label.count('car')))

(Left) Original image with cars (source), (Right) Output image with labelled cars

该图像的输出:

Number of cars in the image is 29

(Left) Original image with cars (source), (Right) Output image with labelled cars

该图像的输出:

Number of cars in the image is 22

(Left) Original image with cars (source), (Right) Output image with labelled cars

该图像的输出:

Number of cars in the image is 25

你的汽车计数器程序现在准备好了。你可以用它来做有趣的实验,比如计算每天经过你家车道的汽车数量。

Python 版本 3.6.9 用于运行这段代码。

运行此代码时安装的最重要的软件包版本如下:

cvlib: 0.2.2
opencv-python: 4.1.1.26
tensorflow: 1.14.0
matplotlib: 3.1.1
Keras: 2.2.5

以下是该计划 Jupyter 笔记本的 GitHub 链接:

[## sabi poks/博客帖子

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/sabiipoks/blog-posts/blob/master/Count_Number_of_Cars_in_Less_Than_10_Lines_of_Code_Using_Python.ipynb)

发现这个帖子有用吗? 在下面留下你的想法作为评论。

希望实现人脸检测。查看我在 上的帖子如何使用 python 在不到 3 分钟的时间内实现人脸检测。

希望实现对象检测。查看我的关于 物体检测的帖子,只用了 10 行 python 代码。

点击这里 阅读我其他关于 AI/机器学习的帖子。

要了解更多关于 cvlib 库的信息,可以访问下面的链接。

[## cvlib

用于 Python 的高级易用开源计算机视觉库。它的开发重点是实现简单的…

www.cvlib.net](https://www.cvlib.net/)

手动计算深度学习模型中的参数数量

原文:https://towardsdatascience.com/counting-no-of-parameters-in-deep-learning-models-by-hand-8f1716241889?source=collection_archive---------3-----------------------

Photo by Andrik Langfield on Unsplash

计算 FFNN、RNN 和 CNN 模型参数的 5 个简单例子

W 为什么我们需要再次计算深度学习模型中的参数数量?我们没有。但是,如果我们需要减少模型的文件大小,甚至减少模型推断所需的时间,了解模型量化前后的参数数量将会派上用场。(看视频这里关于深度学习的高效方法和硬件。)

计算深度学习模型的可训练参数的数量被认为是太琐碎了,因为你的代码已经可以为你做到这一点。但是我想把我的笔记留在这里,供我们偶尔参考。以下是我们将浏览的模型:

  1. 前馈神经网络
  2. 递归神经网络(RNN)
  3. 卷积神经网络(CNN)

与此同时,我将使用 Keras 的 API 构建模型,以实现简单的原型制作和简洁的代码,因此让我们在这里快速导入相关对象:

**from** keras.layers **import** Input, Dense, SimpleRNN, LSTM, GRU, Conv2D
**from** keras.layers **import** Bidirectional
**from** keras.models **import** Model

建立model后,调用model.count_params()验证有多少参数是可训练的。

1.FFNNs

  • i ,输入尺寸
  • ,隐藏层尺寸
  • o ,输出尺寸

对于一个隐藏层,

num_params
=
层间连接+每层偏置
=
(I×h+h×o)+(h+o)**

例 1.1:输入尺寸 3,隐藏层尺寸 5,输出尺寸 2

Fig. 1.1: FFNN with input size 3, hidden layer size 5, output size 2. The graphics reflect the actual no. of units.

  • i = 3
  • h = 5
  • o = 2

num _ params
=层间连接+各层偏置
=
(3×5+5×2)+(5+2)* =32*

 *input = **Input**((**None**, **3**))
 dense = **Dense**(**5**)(input)
output = **Dense**(**2**)(dense)
 model = **Model**(input, output)*

例 1.2:输入尺寸 50,隐藏层尺寸[100,1,100],输出尺寸 50

Fig. 1.2: FFNN with 3 hidden layers. The graphics do not reflect the actual no. of units.

  • = 50
  • h = 100,1,100
  • o = 50

num_params
=层间连接+各层偏置
=
(50×100+100×1+1×100+100×50)+(100+1+100+50)* =10451*

 *input = **Input**((**None**, **50**))
 dense = **Dense**(**100**)(input)
 dense = **Dense**(**1**)(dense)
 dense = **Dense**(**100**)(dense)
output = **Dense**(**50**)(dense)
 model = **Model**(input, output)*

2.RNNs

  • g ,单位内人数(RNN 1 人,GRU 3 人,LSTM 4 人)
  • h ,隐藏单位尺寸
  • i ,输入的尺寸/大小

由于每个 FFNN 都有h(h+I)+h**参数,所以我们有

num _ params =g×【h(h+I)+h**

示例 2.1:具有 2 个隐藏单元和输入维度 3 的 LSTM。

Fig. 2.1: An LSTM cell. Taken from here.

  • g = 4 (LSTM 有 4 个 FFNNs)
  • h = 2
  • i = 3

num _ params
=
g×【h(h+I)+h***
=4****×【2(2+3)+2】 =*

***input = **Input**((**None**, **3**))
 lstm = **LSTM**(**2**)(input)
model = **Model**(input, lstm)***

示例 2.2:具有 5 个隐藏单元、输入大小为 8(其输出被连接)的堆叠式双向 GRU+具有 50 个隐藏单元的 LSTM

Fig. 2.2: A stacked RNN consisting of BiGRU and LSTM layers. The graphics do not reflect the actual no. of units.

具有 5 个隐藏单元和输入大小 8 的双向 GRU

  • g = 3 (GRU 有 3 个 FFNNs)
  • h = 5
  • = 8

num _ params _ layer 1
=
2*****×
g×【h(h+I)+h(第一项因双向为 2)=)*

有 50 个隐藏单位的 LSTM

  • g= 4(LSTM 有 4 个 FFNNs)
  • h = 50
  • i = 5+5(双向 GRU 输出串接;GRU 的输出大小为 5,与隐藏单元的数量相同)

num _ params _ layer 2
=g×【h(h+I)+h*]
=
4×【50(50+10)+50】
*****

**total _ params= 420+12200 = 12620

 ****input = **Input**((**None**, **8**))
layer1 = **Bidirectional**(**GRU**(**5**, return_sequences=**True**))(input)
layer2 = **LSTM**(**50**)(layer1)
 model = **Model**(input, layer2)****

merge_mode默认为串联。

CNN

对于一层来说,

  • i ,输入地图(或频道)号
  • f ,滤镜尺寸(只是长度)
  • o ,输出地图(或通道)数量。这也由使用多少个过滤器来定义)

一个过滤器应用于每个输入映射。

num_params
=权重+偏差
=
[(f×f)×o+o
****

示例 3.1:使用 2 个 ×2 个滤镜的灰度图像,输出 3 个通道

Fig. 3.1: Convolution of a greyscale image with 2×2 filter to output 3 channels. Here, there are 15 parameters — 12 weights and 3 biases.**

  • i = 1(灰度只有 1 个通道)
  • f = 2
  • o = 3

num _ params
=
[(f×f)×o+o
=【1×(2×3】+******

 ****input = **Input**((**None**, **None**, **1**))
conv2d = **Conv2D**(kernel_size=**2**, filters=**3**)(input)
 model = **Model**(input, conv2d)****

示例 3.2:使用 2×2 滤镜的 RGB 图像,1 个通道的输出

每个输入要素地图有一个过滤器。得到的卷积是逐元素相加的,并且偏置项被加到每个元素上。这给出了具有 1 个特征图的输出。

Fig. 3.2: Convolution of an RGB image with 2×2 filter to output 1 channel. Here, there are 13 parameters — 12 weights and 1 bias.**

  • i = 3 (RGB 图像有 3 个通道)
  • f = 2
  • o = 1

num _ params
=
[(f×f)×o]+o
=【3×(2×2)×1]+1****

 ****input = **Input**((**None**, **None**, **3**))
conv2d = **Conv2D**(kernel_size=**2**, filters=**1**)(input)
 model = **Model**(input, conv2d)****

例 3.3:2 通道图像,2×2 滤波器,3 通道输出

每个输入要素地图有 3 个过滤器(紫色、黄色、青色)。得到的卷积是逐元素相加的,并且偏置项被加到每个元素上。这给出了具有 3 个特征图的输出。

Fig. 3.1: Convolution of a 2-channel image with 2×2 filter to output 3 channels. Here, there are 27 parameters — 24 weights and 3 biases.**

  • i = 2
  • f = 2
  • o = 3

num _ params
=
[(f×f)×o+o
=【2***×(2×3】)*******

 *****input = **Input**((**None**, **None**, **2**))
conv2d = **Conv2D**(kernel_size=**2**, filters=**3**)(input)
 model = **Model**(input, conv2d)*****

暂时就这样吧!如果您有任何反馈,请在下面留下您的评论!

深度学习相关文章

动画版 RNN、LSTM 和 GRU

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

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

经办人:图文并茂的关注

图文并茂:自我关注

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

数披萨:机器学习的度量标准

原文:https://towardsdatascience.com/counting-pizza-metrics-for-machine-learning-4c2ab61b5378?source=collection_archive---------13-----------------------

可视化理解机器学习指标

理解使用机器学习做出商业决策的正确指标很重要。分类说明某样东西是否是别的东西:比如说一张图片是否包含披萨切片。

精度和召回处理可量化的结果用于转化为商业模型的分类。不需要理解机器学习实际上是如何工作的。

任何接触涉及机器学习的商业模式的人都应该理解这些指标。包括创始人、管理层、业务发展和投资者。

对于决策者来说,为数据科学团队提供适合业务模型的指标非常重要。我希望向你们展示,任何会数数的人都能明白该用哪种度量。

假设你想诊断一种罕见的疾病。

  • 当你说一个病人有疾病时,你有多少正确的机会?
  • 你漏掉了多少病例?

对这些问题的回答推动了商业模式的发展。精确和召回是两个各自的答案。

本文旨在给出这些重要指标的直觉。当我们能把一个图像和一个概念联系起来时,直觉往往是最好的。所以让我们来考虑一个直观的例子:下图中有几片披萨?

The answer is 4 pizza slices. I ate the other 4. Oops.

现在让我们假设我们已经训练了一个卷积神经网络(CNN)来识别图像中的披萨。我不会告诉你它是如何工作的,没关系!CNN 带回来这些结果:

该模型预测了 5 个比萨饼切片。它正确地标记了 3 片比萨饼,但错误地将 2 片馅饼标记为比萨饼。它完全错过了一个比萨饼切片。仔细查看图像,直到您看到所有四个数字都匹配。

现在,让我们回顾一些术语,更深入地了解该模型的表现。精确度和召回率告诉我们从一个分类模型中我们得到什么样的预测。在计算比萨饼的情况下,这些类型的预测是:

  • 真阳性:模型预测比萨饼,它是比萨饼
  • 假阳性:模型预测比萨饼,它不是比萨饼
  • 假阴性:模型预测不是比萨饼,它是比萨饼
  • 真否定:模型预测不是比萨饼,它不是比萨饼

或者我们可以用表情符号来展示这些预测!(注意:馅饼表情符号在技术上是指“不是披萨”的任何东西)

美国有线电视新闻网正确预测了 3 个比萨饼切片是比萨饼,所以有 3 个真正的阳性。它错误地预测了实际上是馅饼的 2 片比萨饼,所以有 2 个误报。它漏掉了一片比萨饼,所以有一个假阴性。

  • 真阳性= 3
  • 假阳性= 2
  • 假阴性= 1

现在让我们开始计算模型的表现。精密测量正确性。在这里,正确性意味着:

当模特说披萨的时候,有多少是正确的?

现在我们来介绍一下精度的公式:

或者更直观(也更美味):

所以精度等于 3 / (3 + 2) = 0.6。这意味着当模型预测某样东西是比萨饼时,它有 60%的几率是正确的。另外 40%的时间里,它错误地预测了比萨饼,而实际上它是馅饼。

另一方面,回忆衡量完整性。在这里,完整性意味着:

在所有真正的比萨饼中,模型抓住了多少片?

现在我们来介绍一下召回的公式:

或者更形象地说:

所以召回率等于 3 / (3 + 1) = 0.75。这意味着在所有实际的比萨饼中,模型捕捉到了 75%的比萨饼切片。它漏掉了 25%的比萨饼切片,也就是图像右下方的那一片。

现在我们面临一个自然的问题:哪个指标对业务决策更重要?每个人都讨厌的答案,因为它太真实了:看情况。

更有意思的是,精确度和召回率直接相互竞争。随着精确度的提高,召回率趋于下降。随着回忆越来越好,精确性越来越差。

因此,如果我们希望模型永远不要说馅饼是比萨饼(100%精确),它将错过更多的比萨饼切片总数(更少的回忆)。这种情况经常发生在商业环境中,在这种环境中,一个错误的决策会带来巨大的代价。精准的座右铭是:

错过一个事件比对一个糟糕的事件采取行动要好。

如果我们希望模型捕捉到每一片披萨(100%召回),它会猜测更多的馅饼是披萨(精确度较低)。这种情况经常发生在商业环境中,错过一个事件会有很大的代价。召回的座右铭是:

抓住所有事件,有时是错误的,比总是正确的要好。

额外收获:更常见的指标

另一个常见的度量标准是普通的老式精确度。它衡量正确预测的比例,包括正面和负面预测。

这里要注意:在处理类不平衡的数据集时,这种度量会产生极大的误导。这基本上意味着一种类型的东西比另一种多得多。假设一个数据集包含 100 张比萨饼图片,而只有 5 张馅饼图片。

虽然它通常很少使用,但有时使用精度是合理的。如果一个数据科学家说一个模型达到了 99%的准确率,问问这实际上意味着什么。

毕竟,考虑一下 1%的人患有罕见疾病的情况。一个总是预测“没有疾病”的分类模型将有 99%的准确率。然而,这样的模型将永远捕捉不到那种疾病的病例(0%的准确率和召回率)。

现在让我们考虑同样关心精确度和召回率的情况。我们希望模型既高度正确又完整(这在实践中可能相当困难)。我们可以引入另一个指标,称为F1-得分

F1 分数在精确度和召回率之间创造了一个平衡的分数。基本上,它通过在精确度和召回率之间寻找一个值来平衡精确度和召回率,总是更倾向于较低的值。比萨饼分类器的 F1 分数是 67%,接近 60%的精确度,而不是 75%的召回率。

在大多数情况下,F1 分数是可取的,以确保我们有良好的精度良好的回忆。在某些情况下,可能没有必要。获得高精度和高召回率需要花费更多的时间、资源和金钱。高精度或高召回率本身可能以较低的成本适用于商业模式。

结论

由设计业务模型的人来决定何时使用什么度量标准。

您不必成为数据科学家,也能理解使用哪种指标。它只涉及回答以下问题:

机器学习的结果会让我的生意兴隆吗?

度量提供驱动业务模型的可量化结果。精确度、召回率和 F1 分数为理解分类模型的结果奠定了坚实的基础。

我希望我向你展示了任何会数数的人都能理解机器学习指标。我也希望你能从这篇文章中学到一些东西:

  • 度量=商业模式的燃料
  • 精确度=正确性
  • 回忆=完整
  • f1-分数=平衡分数
  • 准确性=潜在误导
  • 披萨=美味

py spark:count vectorizer | HashingTF

原文:https://towardsdatascience.com/countvectorizer-hashingtf-e66f169e2d4e?source=collection_archive---------0-----------------------

我在将商业实体与其相应的品牌名称进行匹配时,偶然发现了这些术语。但是,让我用一些更简单的例子向您介绍一下。

在深入研究 CountVectorizer 和 HashingTF 之前,让我们先大致了解一下它们是做什么的。

计数矢量器和哈希函数估计器用于生成术语频率向量。它们基本上将文档转换为数字表示,可以直接输入或进一步处理为其他算法,如 LDA、Jaccard 距离的 MinHash、余弦距离等。

假设我们的数据库中只有 2 个文档,我们希望将它们转换成一个特征向量。

我们可以继续使用特征提取算法,例如术语频率-逆文档频率(TF-IDF)

TF-IDF

这是一种将文档转换成向量的方法,使得向量反映术语对于语料库中的文档的重要性。

如果我们用 t 表示术语,用 D 表示文档,用 D 表示语料库

术语频率(TF(t,d)) :术语 t 在文档 d 中出现的次数

这里,TF(PYTHON,Document 1)= 1;TF(HIVE,文档 1) = 2

必须注意的是,HashingTF 和 CountVectorizer 都可以用来生成术语频率向量

文档频率(DF(t,D)) :包含术语 t 的文档的数量

这里 DF(PYTHON,Document 1)= 1;DF(HIVE,文档 1) = 1

然而,像 a、an 等这样的停用词。在语料库中出现频率很高,但没有特殊含义。为了解决这个问题,我们使用了逆文档频率(IDF)。

IDF(t,D) :术语提供多少信息的数值度量

这里 IDF(PYTHON,Document 1)= log((2+1)/(1+1))~ 0.405

类似地,IDF(HIVE,文献 1) ~0.405

TF-IDF:TF 与 IDF 的乘积。

这里 TF-IDF(PYTHON,文档 1,语料库)~ 0.405

同样,TF-IDF(HIVE,文档 1,语料库)~0.81

因此,TF-IDF 确保了在文档中具有高频率的术语将具有高 TF,但是如果一个术语在语料库中具有高频率,则它的重要性被 IDF 降低。语料库中所有文档中出现的术语将具有等于 0 的 TF-IDF。

正如我们已经看到的,HashingTF 和 CountVectorizer 都可以用来生成术语频率向量。因此,现在让我们深入了解每一种方法,了解它们的优点和缺点。

计数矢量器

CountVectorizer 将文本文档转换为提供令牌计数信息的向量。

让我们继续讨论前面讨论过的具有 2 个文档的相同语料库。我们想把文档转换成词频向量

*# Input data: Each row is a bag of words with an ID*
df = hiveContext.createDataFrame([
    (0, "PYTHON HIVE HIVE".split(" ")),
    (1, "JAVA JAVA SQL".split(" "))
], ["id", "words"])df.show(truncate = False)

首先,CountVectorizer 将生成一个词汇表,以防没有先验词汇表。例如,在这个例子中,CountVectorizer 将创建一个大小为 4 的词汇表,其中包括 PYTHON、HIVE、JAVA 和 SQL 术语。接下来是计数矢量器模型的拟合。在拟合过程中,CountVectorizer 将选择按词频排序的顶级词汇。该模型将产生一个稀疏向量,可以馈入其他算法。

*# Fit a CountVectorizerModel from the corpus*
from pyspark.ml.feature import CountVectorizer
cv = CountVectorizer(inputCol="words", outputCol="features")model = cv.fit(df)result = model.transform(df)
result.show(truncate=False)

为了便于理解,特征向量可以分成 3 个部分

  • 开头的数字代表向量的大小。在这里,是 4。
  • 第一列数字代表矢量索引。

例如,与频率为 1 的术语“SQL”相比,“JAVA”术语的频率为 2。因此,“JAVA”的索引是 1,而“SQL”的索引是 2

  • 第二列数字代表与这些指数相对应的值。

在文档 2 中可以看出,索引为 1 的‘JAVA’的值为 2,索引为 2 的‘SQL’的值为 1

然而,应该注意的是,由于“HIVE”和“JAVA”的频率相同,所以索引是可以互换的。

Here, ’HIVE’ has index 0 and ‘JAVA’ has index 1

Here, ’HIVE’ has index 1 and ‘JAVA’ has index 0

类似的,其他具有相同频率的术语也是如此。

HashingTF

HashingTF 将文档转换为固定大小的矢量。默认特征尺寸为 262,144。使用散列函数将术语映射到索引。使用的哈希函数是 MurmurHash 3。相对于映射的索引来计算项频率。

*# Get term frequency vector through HashingTF*
from pyspark.ml.feature import HashingTFht = HashingTF(inputCol="words", outputCol="features")result = ht.transform(df)
result.show(truncate=False)

从上面的例子中可以看出,向量的维数被设置为默认值,即 262,144。此外,术语“PYTHON”通过散列函数被映射到索引 134160,并且具有等于 1 的频率。类似地,可以获得关于其他术语的见解。

对比与结论

我们已经看到,CountVectorizer 和 HashingTF 都可以被实现来生成频率向量。然而,这两种实现各有优缺点。让我们仔细看看它们之间的差异,以选择最适合我们要求的算法。-

  • 通过 CountVectorizer 生成的向量的大小取决于训练语料库和文档,而通过 HashingTF 生成的向量的大小是固定的。默认大小为 262,144
  • 在计数矢量器的情况下,每个原始特征被映射到一个索引。然而,HashingTF 遭受潜在的哈希冲突,即 2 个或更多的项可能被映射到相同的索引,从而在哈希之后变得相同。然而,为了避免哈希冲突,我们可以增加目标特征的维数
  • 由于全局项到索引的映射,CountVectorizer 与使用哈希技巧的 HashingTF 相比,计算开销更大。
  • 很难解释通过 HashingTF 创建的向量,因为散列是不可逆的,所以无法恢复原始输入。但是,在使用 CountVectorizer 的情况下,可以恢复输入

显然,这两种算法之间有一个权衡。但是,我们可以得出结论,在拥有大量数据集的情况下,使用比 HashingTF 稍低的精度会更合适,而在需要反向映射的情况下,CountVectorizer 会更合适。

希望有所帮助:)

面向规模的 R 语言中 Web 抓取与函数式编程的耦合

原文:https://towardsdatascience.com/coupling-web-scraping-with-functional-programming-in-r-for-scale-1bc4509eef29?source=collection_archive---------27-----------------------

https://unsplash.com/photos/-lp8sTmF9HA

在这篇文章中,我们将看到如何使用 R 进行 web 抓取,同时,我们将利用 R 中的函数式编程来扩展它。这篇文章的性质更像是一种食谱格式,而不是文档/教程类型,因为这里的目标是解释 web 抓取如何有效地与函数式编程相结合

R 中的网页抓取

数据爱好者无需介绍网络搜集。当数据本身不可用时,这是收集数据的最可行和最基本的方法之一。

当你缺少数据,或者需要宏观经济指标,或者某个项目没有可用的数据,比如带有自定义文本数据集的 Word2vec / Language 时,了解网络搜集会非常方便。

一个漂亮的(类似 Python 中的 BeautifulSoup 包,用于 web 抓取。它与tidyverse的宇宙和超级方便的%>%管道操作员也很好。

样本用例

顾客对 Etsy.com 感受的文本分析。为此,我们将从trustpilot.com中提取评论数据。

下面是从 Trustpilot 的 Etsy 页面第一页抓取评论的 R 代码。网址:https://www.trustpilot.com/review/www.etsy.com?page=1

library(tidyverse) #for data manipulation - here for pipe
library(rvest) - for web scraping#single-page scrapingurl <- "[https://www.trustpilot.com/review/www.etsy.com?page=1](https://www.trustpilot.com/review/www.etsy.com?page=1)"url %>% 
  read_html() %>% 
  html_nodes(".review-content__text") %>% 
  html_text() -> reviews

这是一段相当简单的代码,我们传递 URL 来读取 html 内容。一旦内容被读取,我们使用html_nodes函数根据它的css selector property获取评论文本,最后从它的html_text()中取出文本并将其分配给 R 对象reviews

下面是reviews的输出示例:

很好。我们已经成功地收集了我们分析所需的评论。

但问题是我们得到的评论数量只有 20 条——正如我们在截图中看到的,我们已经得到了一条非英语评论,我们可能不得不在数据清理过程中将其排除。

这使我们有机会收集更多的数据来弥补上述数据损失,并使分析更加有效。

规模需求

使用上面的代码,我们只从第一页(也是最近的一页)开始。因此,由于需要更多的数据,我们必须将搜索范围扩大到更多的页面,比如说 10 个其他页面,在数据处理之前,这些页面将为我们提供 200 条原始评论。

传统方式

非常传统的方法是使用一个循环——通常是使用for循环从 1 到 20 迭代 url,以基于一个基本 URL 创建 20 个不同的 URL(字符串连接)。众所周知,这需要更多的计算,代码也不紧凑。

函数式编程方式

在这里,我们将使用来自包purrr的 R 的函数式编程支持,在与上述代码相同的数据管道中,以 R 的tidy方式执行相同的迭代。我们将使用purrr中的两个函数,

  1. map()是来自函数式编程范式的典型映射,它接受一个函数并映射到一系列值上。
  2. map2_chr()是 map 的发展,它接受函数的附加参数,并将输出格式化为字符。

下面是我们的函数式编程代码

library(tidyverse)
library(rvest)
library(purrr)#multi-pageurl <- "[https://www.trustpilot.com/review/www.etsy.com?page=](https://www.trustpilot.com/review/www.etsy.com?page=)" #base URL without the page numberurl %>% 
  map2_chr(1:10,paste0) %>% #for building 20 URLs 
  map(. %>% 
    read_html() %>% 
      html_nodes(".review-content__text") %>% 
      html_text()
  ) %>% 
  unlist() -> more_reviews

正如您所看到的,这段代码与上面的单页代码非常相似,因此它使得任何理解前面代码的人都可以更容易地用最少的先验知识来通读这段代码。

这段代码中的额外操作是,我们构建 20 个新的 URL(通过更改 URL 的查询值)并逐个传递这 20 个 URL 以进行 web 抓取,最后,作为回报,我们将获得一个列表,我们使用unlist保存所有计数必须为 200 的评论(每页 20 条评论 x 10 页)。

让我们看看输出是什么样子的:

是的,200 条评论。这实现了我们的目标,即收集(相当)足够的数据来执行我们上面提到的文本分析用例。

但是本文的重点是向您介绍 R 中的函数式编程,并展示它如何容易地适应现有的数据管道/工作流,它是如何紧凑,毫无疑问,它是如何高效(比典型的 for 循环)。希望这篇文章达到了它的目的。

  • 如果你更感兴趣,可以看看这个关于函数式编程的 Datacamp 课程
  • 这里使用的完整代码可以在 github 上找到

谢谢:整篇文章和代码的灵感来自 Saurav Ghosh 在 Bengaluru R 用户组 meetup 中参加的会议

面向人工智能、机器学习和深度学习的 TensorFlow 简介

原文:https://towardsdatascience.com/course-review-introduction-to-tensorflow-for-artificial-intelligence-machine-learning-and-deep-5ef1a85042b2?source=collection_archive---------19-----------------------

本次审查的结构:

  • 本课程总结
  • 本课程涵盖的知识和技能
  • 本课程与深度学习专业化的关系
  • 这是你的课程吗?
  • 我对这门课的主观评价

总结:

本课程是 deeplearning.ai 提供的 TensorFlow 在实践专业化方面的第一门课程,顾名思义,是对 TensorFlow 的介绍。中级水平,并将带领你一头扎进深度学习/计算机视觉/人工智能。

本课程涵盖的知识和技能

  • 了解使用 TensorFlow 的最佳实践和计算机视觉的理论基础。
  • 建立一个基本的神经网络。
  • 使用卷积来改进神经网络,包括使用池层和密集层。
  • 如何使用 google colab?

本课程与深度学习专业化的关系

我认为深度学习专业化是这门课程的先决条件。如果学生不了解深度学习,那么理解代码真正在做什么就有点难了。因为本课程更多的是实践,而不是覆盖太多的理论基础,例如,它不会教你如何详细计算约定和池层的大小,但教师会提供一个特定课程的链接。让我举例说明:在第 2 周的视频中,当 Laurence Moroney 教授使用 TensorFlow 构建卷积神经网络时,他提供了一个链接,指向 DeepLearningSpecialization 第四期课程中的一个讲座。

这是你的课程吗?

这是一门中级课程。它要求学生具备 Python 编码和高中水平数学的经验。它说,“先前的机器学习或深度学习知识是有帮助的,但不是必需的。”然而,在我看来,如果你想理解代码真正在做什么,深度学习的知识也是必需的。如果你已经完成了 DeepLearningSpecialization 或者你已经知道了深度学习的基本理论,但是不熟悉 TensorFlow,我会向你推荐这门课程;如果你之前用过 PyTorch,又想用 TensorFlow 弄脏手,我推荐你这个;如果你像我一样是一个雄心勃勃的数据爱好者,我也一定会向你推荐这门课程!如果你对这门课程感兴趣,并且正在寻找关于这门课程的信息,那么不要犹豫,这门课程就是为你设计的。

我对这门课的主观评价

劳伦斯·莫罗尼(Laurence Moroney)的教学风格很迷人,跟你的教授或者大学提供的其他课程不一样。劳伦斯能让这门课变得如此有趣。此外,我喜欢劳伦斯和安德鲁在每周讲座开始时的谈话。编码任务并不具有挑战性,除了谦虚,它们对我来说还算简单(我已经完成了 Andrew 的深度学习专业)。Laurence 还在 google colab 中提供了代码,这使得学习过程更加易于管理,学生可以非常快速地在 colab 中训练和测试模型。

而且和往常一样,你可以在我的 GitHub repo 里找到这门课的所有资料。

也发表在我的个人博客。

什么是协方差和相关系数及其意义?

原文:https://towardsdatascience.com/covariance-and-correlation-321fdacab168?source=collection_archive---------9-----------------------

协方差和相关性对于理解两个连续变量之间的关系非常有帮助。协方差说明两个变量是同向变化(正协方差)还是反向变化(负协方差)。协方差数值没有意义,只有符号是有用的。而相关性解释了一个变量的变化导致第二个变量的比例变化。相关性在-1 到+1 之间变化。如果相关值为 0,则意味着变量之间没有线性关系,但是可能存在其他函数关系。

让我们详细理解这些术语:

协方差:

在协方差的研究中,只有符号是重要的。正值表示两个变量的变化方向相同,负值表示它们的变化方向相反。

两个变量 x 和 y 之间的协方差可以计算如下:

其中:

  • x̄是 x 的样本均值
  • ȳ是 y 的样本均值
  • x_i 和 y_i 是样本中第 I 条记录的 x 和 y 值。
  • n 是样本中的记录数

公式的意义:

  • 分子:x 轴的差异量乘以 y 轴的差异量。
  • 协方差单位:x 的单位乘以 y 的单位
  • 因此,如果我们改变变量的单位,协方差将有新的值,但符号将保持不变。
  • 因此,协方差的数值没有任何意义,但是,如果它是正的,那么两个变量在相同的方向上变化,否则,如果它是负的,那么它们在相反的方向上变化。

相关性:

由于协方差只告诉方向,不足以完全理解关系,我们分别用 x 和 y 的标准偏差划分协方差,得到在-1 到+1 之间变化的相关系数。

  • -1 和+1 表明这两个变量具有完美的线性关系。
  • 负表示它们与相关系数值的因子成反比。
  • 正意味着它们彼此成正比,意味着与相关系数值的因子同方向变化。
  • 如果相关系数为 0,则意味着变量之间没有线性关系,但是可能存在其他函数关系。
  • 如果两个变量之间完全没有关系,那么相关系数肯定是 0,但是如果它是 0,那么我们只能说没有线性关系,但是可能存在其他函数关系。

x 和 y 之间的相关性可以计算如下:

其中:

  • S_xy 是 x 和 y 之间的协方差。
  • S_x 和 S_y 分别是 x 和 y 的标准差。
  • r_xy 是相关系数。
  • 相关系数是一个无量纲的量。因此,如果我们改变 x 和 y 的单位,那么系数值也将保持不变。

让我们借助下图来理解相关系数的意义:

请在下面的评论区分享你的想法/想法。如果你对这个话题有任何疑问,欢迎你用联系方式给我写信。我很乐意回答你的问题。

原载于 2019 年 1 月 15 日【http://ashutoshtripathi.com】

cov fefe & NLP——特朗普的推文会影响股市吗?

原文:https://towardsdatascience.com/covfefe-nlp-do-trumps-tweets-move-the-stock-market-42a83ab17fea?source=collection_archive---------20-----------------------

Source: John Cameron via Unsplash.

Twitter 是世界上最大的社交媒体服务之一,现在已经成为政治家、组织和公司向其追随者提供更新的平台。代表一家公司或一个政党的用户使用 Twitter 来表达对当前新闻的看法,推动他们的政治活动,甚至确认官方的政策决定。使用该网站向数百万粉丝传播想法的重要人物包括特斯拉创始人埃隆·马斯克、欧盟委员会主席唐纳德·图斯克和现任英国首相鲍里斯·约翰逊。社交网络的使用可能会产生巨大的财务/商业影响——例如,埃隆·马斯克(Elon Musk)在推特上发布消息称,他的电动汽车公司特斯拉(Tesla)私有化的“资金已有保障”,这引起了很多负面关注。特斯拉的股价上涨了 8.5% (1),这导致了证券交易委员会对马斯克的惩罚性调查。这导致马斯克被罢免了他创建的公司的董事长职务,并被罚款 2000 万美元——这一切都是因为一条推特。美国总统唐纳德·特朗普目前在推特上有 6680 万粉丝,账号为 "@realDonaldTrump" (2)。特朗普在他的推特账户上非常活跃,自 2016 年以来平均每天约 10 条推特(3)。特朗普在推特上直言不讳,经常发表针对他的批评者的“人身攻击”言论,特别是针对民主党。推特在此前的大选中发挥了巨大作用(2016 年举行),特朗普的言论最终促使对前竞争对手总统候选人希拉里·克林顿进行调查。

有效市场假说

从广义上来说,交易员和投资组合经理根据公司的基本面、管理层及其未来的预期价值来决定是购买、出售还是持有特定的股票(公司股票)。因此,跟上公司新闻是至关重要的,这可能涉及收益电话会议、新产品发布,以及最近通过推特发布的新闻。这与一个叫做‘有效市场假说’的观点相吻合。EMH 主张股票在证券交易所以其内在价值进行交易,也就是说,关于一家公司、其管理层和其估值的所有信息都持续体现在当前股价中。这意味着当特朗普发推文时,这些信息甚至会在成为头条新闻之前就反映在金融市场上。所以现在,让我们收集数据。

数据收集

为了分析特朗普的推文,我们通过 Python 模块 Tweepy 使用 Twitter API 收集了 2019 年 7 月 28 日至 2019 年 11 月 16 日的约 3000 条推文(包括转发)。为此,我们在 Twitter 上创建了一个开发人员帐户,然后使用 cursor 方法获取推文,并将它们放入数据帧中:

dtweets = tweepy.Cursor(api.user_timeline, id="realDonaldTrump", include_rts=True, count=200, tweet_mode="extended")df = pd.DataFrame(columns=["Date Created","RT Count", "Tweet"])

这些推文然后被预处理以“清洗”它们,删除超链接和表情符号。

def clean_tweet(tweet):
    return ' '.join(re.sub('(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)', ' ', tweet).split())#The long string of what seems like nonsense essentially takes away any characters that aren’t normal english words/letters.df["Clean Tweet"] = df['Tweet'].apply(lambda x: clean_tweet(x))

接下来,我们应用了一种叫做自然语言处理的技术。在高层次上,NLP 使用计算技术来分析句子,以实现特定的结果。虽然听起来可能很复杂,但您可能每天都在使用 NLP。常见的例子包括手机键盘上的预测文本、网页上的语言翻译和搜索结果。我们使用的 NLP 工具被称为【情绪分析】,它本质上决定了每条推文是正面的、中立的还是负面的。Python 模块“Textblob”旨在通过解析每个句子并给它一个介于-1 和 1 之间的分数来确定推文的情绪。例如,一条包含“错误”一词的推文通常会得到一个负分。此外,一条包含“谢谢”的推文通常会得到积极的评价。当然,有些情况下,一条推文可能并不总是被赋予正确的情绪,特别是对于经济变量。例如,当失业率实际上对经济更有利时,“高失业率”可能会被赋予积极的情绪。然而,对于这个任务,我们使用了默认的 Textblob 功能,因为它已经通过机器学习在大型数据集上进行了测试。下面是用于对推文进行情感分析的代码片段:

def analyze_sentiment(tweet):
    analysis = TextBlob(tweet)
    if analysis.sentiment.polarity > 0:
        return 'Positive'
    elif analysis.sentiment.polarity ==0:
        return 'Neutral'
    else:
        return 'Negative'

df["Sentiment"] = df['Clean Tweet'].apply(lambda x: analyze_sentiment(x))i=0
for tweet in dtweets.items(3000):
    analyze_sentiment(tweet.full_text)

    i+=1
    if i == 3000:
        break
    else:
        pass
#code stops at 3000 tweets subject to Tweepy's limits

本质上,这段代码定义了一个函数,该函数通过使用“if”和“else”语句,根据 tweet 的情感对其进行分类,并使用 Textblob 对其进行评分。然后,我们在 pandas dataframe 中为“干净的 tweet”创建一个新列,遍历每条 tweet。一旦我们运行了这段代码,数据帧应该看起来像这样(任何空的/无意义的干净的 tweets 都从我们的分析中删除了):

数据可视化

利用我们收集的数据,我们可以直观地解释它的分布。下面我们展示了唐纳德·特朗普每条推文的情绪分布。在分析的大约 3000 条推文中,662 条推文被给予负面情绪,798 条中立,1415 条正面情绪。

Source: Twitter, Python. Tweets collected using Twitter API & Tweepy.

下图显示,特朗普的推文频率从 2016 年的平均水平大幅增加(包括转发)。

Source: Twitter, Python. Tweets collected using Twitter API & Tweepy.

为了衡量这些推文对股市回报的影响,我们决定使用标准普尔 500 指数,这是在美国证券交易所交易的 500 家最大公司的加权平均值。重要的是我们使用回报率而不是原始价格,因为回报率使系列平稳 (可以使用 Dickey-Fuller 测试来证实这一点,但这里没有使用)

过滤数据

为了尽可能使用最具代表性的数据,我们根据特定的词过滤了与股市相关的推文,如“贸易”、“中国”、“鲍威尔”等,因为它们更有可能影响市场。单词和短语的完整列表如下:

"贸易"、"利率"、"通胀"、"经济"、"增长"、"操纵"、"货币"、"美元"、"中国"、"美联储"、"鲍威尔"、" Xi "、"关税"、"弹劾"。

这使得我们的推文总数减少到了 500 条左右。然后根据他们的情绪给这些推文打分。正面推文的得分为 1,负面推文为-1.2,中性推文为 0.1。这些分数后来被转换成一个序列,将每天所有推文的情感分数总和乘以当天标准普尔指数的回报。这意味着我们可以将这些系列放在一起进行比较,以找到相关性。当给出分数时,我们认为投资者是厌恶损失的——这意味着他们从损失中获得的悲伤大于他们获得的同等程度的快乐。这就是为什么负面推文比正面推文的量级高。此外,人们可能会认为一条中性的推文得分为 0——在这里,我们假设股市的稳态高于零,因为全球趋势增长率高于零。情绪得分的实际任意数字来自我自己的假设,并且仅被用作将情绪得分缩放到 S & P 回报的手段。

Source — My own calculations.

当我们将这两个系列结合在一起时,我们会得到下面的图表:

Source — Yahoo Finance (4), Twitter

解读

直观上,我们可以看到股市的走势和特朗普的推文似乎是一起动的。当在两个系列之间进行相关性分析时,0.68 的正相关性意味着特朗普的推文事实上确实随股市而动。然而,重要的是,相关性 并不意味着 因果关系。换句话说,我们不知道这种关系的走向。还有许多个体因素可能会影响股票回报,如利率、通胀预期和其他特殊因素。我们发现的对这种关系的解释更有可能是,推文与影响市场的事件相吻合,如令人惊讶的经济数据发布或市场对数据做出反应后的货币政策决定。此外,我们大约 500 条推文的样本量可能不足以得出最准确的结论。展望未来,也许控制某些因素的线性回归,如市场规模、动量和波动性,以及更大的样本量,可能会产生一些有趣的结果。因此,我们不能 100%肯定地说,特朗普的推文先发制人地影响了股市。然而,更有可能的是,推文的情绪与市场回报正相关。

感谢阅读! 如果你有什么见解,请不吝赐教。包含我用来做这个项目的源代码的完整 Jupyter 笔记本可以在我的 GitHub 仓库中找到。

参考资料:

[1]投资媒体。特斯拉股价如何在 80 天内跌了 100 美元。(2019).请访问:https://www . investopedia . com/investing/how-tes las-share-price-dropped-100-80-days/

[2]Twitter.com。唐纳德 j 特朗普(@realDonaldTrump)在推特上。(2019).可在:https://twitter.com/realDonaldTrump?购买 ref _ src = tw src % 5 egoogle % 7 ctw camp % 5 eserp % 7 ctw gr % 5 e author

[3] Newburger,E. JP 摩根创建了一个指数来跟踪特朗普的推文对金融市场的影响:“Volfefe 指数”。(2019)美国消费者新闻与商业频道。可查阅:https://www . CNBC . com/2019/09/08/Donald-trump-is-tweet-more-and-its-impact-the-bond-market . html

[4]雅虎财经历史数据。(2019).可在:https://finance.yahoo.com/

免责声明:本文表达的所有观点均为本人观点, 无任何关联,与先锋或其他任何金融实体无关。我不是一个交易者,也没有用本文中的方法赚钱。这不是财务建议。

卷积神经网络

原文:https://towardsdatascience.com/covolutional-neural-network-cb0883dd6529?source=collection_archive---------0-----------------------

从 basic 学习卷积神经网络及其在 Keras 中的实现

目录

  • CNN 是什么?
  • 为什么要用 CNN?
  • 几个定义
  • CNN 中的图层
  • Keras 实施

1.CNN 是什么?

计算机视觉每天都在快速发展。原因之一是深度学习。当我们谈论计算机视觉时,我们脑海中会出现一个术语卷积神经网络(缩写为 CNN),因为 CNN 在这里被大量使用。计算机视觉中 CNN 的例子有人脸识别、图像分类等。它类似于基本的神经网络。CNN 也有像神经网络一样的可学习参数,即权重、偏差等。

2.为什么要用 CNN?

前馈神经网络的问题

假设您正在处理 MNIST 数据集,您知道 MNIST 的每幅图像都是 28 x 28 x 1(黑白图像仅包含一个通道)。输入层的神经元总数将是 28×28 = 784,这是可以管理的。如果图像的大小是 1000 x 1000,这意味着你需要在输入层 10⁶神经元。哦!这似乎需要大量的神经元来运作。它在计算上是无效的。所以卷积神经网络或者 CNN 来了。简而言之,CNN 所做的就是提取图像的特征,并将其转换到低维,而不丢失其特征。在下面的例子中你可以看到初始图像的大小是 224 x 224 x 3。如果不进行卷积,那么在输入层中需要 224 x 224 x 3 = 100,352 个神经元,但是在应用卷积之后,输入张量维数减少到 1 x 1 x 1000。这意味着在前向神经网络的第一层只需要 1000 个神经元。

Fig. Downsampling

3.几个定义

在了解 CNN 之前,有几个你应该知道的定义

3.1 图像表示

想想图像,很容易理解它有高度和宽度,所以用二维结构(矩阵)来表示图像中包含的信息是有意义的,直到你记得图像有颜色,为了添加关于颜色的信息,我们需要另一个维度,这就是张量变得特别有用的时候。

图像被编码到颜色通道中,图像数据在给定点被表示为颜色通道中的每个颜色强度,最常见的是 RGB,这意味着红色、蓝色和绿色。包含在图像中的信息是每个通道颜色的强度到图像的宽度和高度,就像这样

Fig. RGB representation of a image

因此,红色通道在每个点上的强度以及宽度和高度可以表示为一个矩阵,蓝色和绿色通道也是如此,因此我们最终有三个矩阵,当这些矩阵组合在一起时,它们就形成了一个张量。

3.2 边缘检测

每个图像都有垂直和水平边缘,它们实际上组合在一起形成一个图像。卷积运算与一些用于检测边缘的滤波器一起使用。假设你有尺寸为 6×6 的灰度图像和尺寸为 3×3 的过滤器。当 6×6 灰度级图像与 3×3 滤波器卷积时,我们得到 4×4 图像。首先,将 3×3 滤波器矩阵乘以我们灰度图像的第一个 3×3 尺寸,然后我们将一列向右移动到末尾,之后我们移动一行,依此类推。

Convolution operation

卷积运算可以用下面的方式来表示。这里,我们的图像尺寸是 4 x 4,过滤器是 3 x 3,因此我们得到卷积后的输出是 2 x 2。

Visualization of convolution

如果我们有 N×N 的图像大小和 F×F 的滤波器大小,那么卷积后的结果将是

(N x N) * (F x F) = (N-F+1)x(N-F+1)(Apply this for above case)

3.3 步幅和衬垫

步幅表示在卷积的每一步中我们移动了多少步。默认情况下是一个。

Convolution with Stride 1

我们可以观察到输出的大小小于输入的大小。为了保持输入中输出的维数,我们使用填充。填充是将零对称地添加到输入矩阵的过程。在下面的示例中,额外的灰色块表示填充。它用于使输出的尺寸与输入的尺寸相同。

Stride 1 with Padding 1

假设“p”是填充

最初(无填充)

(N x N) * (F x F) = (N-F+1)x(N-F+1)---(1)

应用填充后

After applying padding

如果我们在带有填充的(N+2p) x (N+2p)输入矩阵中应用滤波器 F x F,那么我们将得到输出矩阵维数(N+2p-F+1) x (N+2p-F+1)。正如我们所知,应用填充后,我们将获得与原始输入尺寸相同的尺寸(N x N)。因此我们有,

(N+2p-F+1)x(N+2p-F+1) equivalent to NxN
 N+2p-F+1 = N ---(2)
 p = (F-1)/2 ---(3)

等式(3)清楚地表明,填充取决于滤波器的尺寸。

4.CNN 中的图层

CNN 有五个不同的层次

  • 输入层
  • 卷积层(卷积+ ReLU)
  • 汇集层
  • 全连接(FC)层
  • soft max/逻辑层
  • 输出层

Different layers of CNN

4.1 输入层

CNN 中的输入层应该包含图像数据。正如我们前面看到的,图像数据由三维矩阵表示。你需要把它改造成一列。假设您有一个尺寸为 28 x 28 =784 的图像,您需要在输入之前将其转换为 784 x 1。如果有“m”个训练示例,那么输入的维数将是(784,m)。

4.2.卷积层

卷积层有时被称为特征提取层,因为图像的特征是在该层中提取的。首先,将图像的一部分连接到卷积层,以执行我们前面看到的卷积运算,并计算感受野(它是输入图像的一个局部区域,与滤波器的大小相同)和滤波器之间的点积。运算结果是输出量的单个整数。然后,我们将过滤器在同一输入图像的下一个感受野上滑动一个步长,并再次进行相同的操作。我们将一次又一次地重复同样的过程,直到我们看完整个图像。输出将成为下一层的输入。

卷积层还包含 ReLU 激活,使所有负值为零。

4.3.汇集层

Source : CS231n Convolutional Neural Network

池层用于减少卷积后输入图像的空间体积。它用于两个卷积层之间。如果我们在卷积层之后应用 FC,而不应用池化或最大池化,那么它将是计算上昂贵的,我们不想要它。因此,最大池化是减少输入图像空间体积的唯一方法。在上面的示例中,我们在跨距为 2 的单个深度切片中应用了最大池。您可以观察到 4 x 4 维输入减少到 2 x 2 维。

池层中没有参数,但有两个超参数-过滤器(F)和步幅(S)。

一般来说,如果我们有输入维数 W1 x H1 x D1,那么

w2 =(W1 F)/S+1

H2 =(H1 F)/S+1

D2 = D1

其中 W2、H2 和 D2 是输出的宽度、高度和深度。

4.4.全连接层

全连接层包括权重、偏差和神经元。它将一层中的神经元连接到另一层中的神经元。它用于通过训练对不同类别的图像进行分类。

4.5.Softmax /逻辑层

Softmax 或逻辑层是 CNN 的最后一层。它位于光纤通道层的末端。Logistic 用于二分类,softmax 用于多分类。

4.6.输出层

输出层包含的标签是以一键编码的形式。

现在你对 CNN 有了很好的了解。让我们在 Keras 实现一个 CNN。

5.Keras 实施

我们将使用 CIFAR-10 数据集来构建 CNN 图像分类器。CIFAR-10 数据集有 10 个不同的标签

  • 飞机
  • 汽车
  • 伯德
  • 鹿
  • 青蛙
  • 卡车

它有 50000 个训练数据和 10000 个测试图像数据。CIFAR-10 中的图像大小为 32 x 32 x 3。它带有 Keras 库。

Fig. Model visualization

如果你用的是 google colaboratory,那么要确保你用的是 GPU。来检查你的 GPU 是否开着。尝试以下代码。

输出:

Found GPU at: /device:GPU:0

首先,导入所有必需的模块和库。

然后加载数据集,并将其分成训练集和测试集。

我们将打印 CIFAR-10 中的训练样本形状、测试样本形状和总类数。正如我们之前看到的,有 10 个类。为了举例,我们将打印来自训练集和测试集的两个示例图像。

输出:

找到输入图像的形状,然后将其整形为训练集和测试集的输入格式。之后,将所有数据类型转换成浮点数。

通过将训练数据和测试数据除以 255 来标准化 0-1 之间的数据,然后使用 to_catagorical() 函数将所有标签转换为一个热点向量。

使用一键编码显示类别标签的更改。

输出:

Original label 0 :  [6]
After conversion to categorical ( one-hot ) :  
[0\. 0\. 0\. 0\. 0\. 0\. 1\. 0\. 0\. 0.]

现在创建我们的模型。我们将添加卷积层,然后是池层。然后我们将连接密集(FC)层来预测类别。输入数据馈送到第一卷积层,该卷积层的输出充当下一卷积层的输入,依此类推。最后,数据被馈送到 FC 层,该层尝试预测正确的标签。

初始化所有参数并用 rmsprops 优化器编译我们的模型。有许多优化工具,例如 adam、SGD、GradientDescent、Adagrad、Adadelta 和 Adamax,请随意尝试。这里的批次是 256,包含 50 个纪元。

model.summary() 用于查看模型中各层的所有参数和形状。您可以看到,总参数为 276,138,总可训练参数为 276,138。不可训练参数为 0。

输出:

Model Summary

在编译我们的模型之后,我们将使用 fit() 方法训练我们的模型,然后对它进行评估。

输出:

经过训练,我们得到了 83.86%的准确率和 75.48%的验证准确率。其实一点也不差。

Loss vs Epochs graph

Accuracy vs Epochs graph

结论:

恭喜你!你通过了解卷积神经网络的基本概念,在 Keras 中制作了卷积神经网络。你可以随意改变它的超参数,并在评论区告诉我。

你可以在我的 Github 里找到所有代码

参考资料:

  1. CS231n 卷积神经网络
  2. Keras 文档
  3. 深度学习实验室
  4. 关于卷积神经网络的 deeplearning.ai 课程

使用蒙特卡罗模拟破解 82 岁的股票交易棋盘游戏

原文:https://towardsdatascience.com/cracking-an-82-year-old-stock-trading-board-game-using-monte-carlo-simulation-384c26eeff6c?source=collection_archive---------19-----------------------

棋盘游戏很有趣。股票交易很有趣。将它们放在一起,我们得到了 1937 年由 Copp-Clark 出版社出版的经典,股票代码。核心玩法很简单:在波动的市场中从经纪人那里买卖股票,并试图以比桌上所有人都多的总资产结束交易。

如果你从未听说过股票代码,那就去易贝、你当地的桌游咖啡馆,甚至你祖母的车库看看。看你能不能弄到一本,这是我个人的最爱。一边喝着啤酒,一边看着你朋友的孤注一掷投资组合策略破产,这是度过周五晚上的好方法。

游戏中的股票走势是由掷骰子触发的,这个公认简单的市场模型的不可预测性造就了一个令人兴奋和引人入胜的游戏。每个人都有自己独特的策略,他们的共同目标是积累最多的现金,看到这些策略成功(或破产)是很有趣的。

游戏规则

对于门外汉,我将简要地列出游戏规则。完整的规则可以在这里找到。

  • 有六种功能相同的股票:黄金、白银、债券、石油、工业和谷物
  • 股票以每股 1 美元开始,你有 5000 美元的启动资金
  • 每回合掷出三个骰子来决定股票走势;骰子 1 选择股票,骰子 2 决定上涨/下跌/分红,骰子 3 选择波动幅度
  • 股票价值变动 0.05 美元/0.10 美元/0.20 美元,股息按股票数量的 5%/10%/20%分配

  • 只有当一只股票达到 票面价值(1.00 美元)或以上时,才会支付股息
  • 如果一只股票跌到 0.00 美元,所有玩家都会立即失去他们在这只股票上的投资,股票会重新回到 1.00 美元
  • 如果一只股票涨到 2.00 美元,股票就会被分割,所有股东的股票都会翻倍,股票会重新回到 1.00 美元
  • 交易只发生在桌子周围七轮结束时的交易阶段;没有买卖限制,也没有交易费用
  • 游戏的时间限制是提前确定的,在一个交易阶段发生超过决定的结束时间后游戏结束(我们通常玩~90 分钟)

Photo credits: Scott Graham (Unsplash)

战略

这里有许多方法可以考虑。基本的风险管理本能告诉我们,将我们的资本分割成尽可能多的不同股票将使风险最小化,这一概念被称为投资组合多样化。

但是这些股票的进入点和退出点应该是什么呢?我们什么时候购买?我们什么时候卖?考虑股息因素后,哪些股票价值的预期回报最高?显然,票面价值或更高的股票更受青睐,因为获取分红将提高我们的回报,但我们应该在 1 美元以上多远的地方买入呢?$1.10?$1.40?

我对这个切入点的直觉是大约 1.20 美元

理想情况下,我想选择一个安全的高于票面价值的进入点,所以在一轮行情中不太可能跌破 1 美元。我想确保在股票滚动的情况下,不会牺牲股票分红的高概率。

但我也不希望起点太高。由骰子决定的股票价值时刻与股票价值不成比例——它们是常数。股价上涨+0.20 美元将产生 1.60 美元的股票 12.5%的投资回报率。但是,同样的+0.20 美元的涨幅会给 1 美元的股票带来 20%的投资回报率。价格越低,股票变动的潜在投资回报率就越高。

考虑到这些因素,我想在中间的某个地方实现平衡,我对这个切入点的直觉是 1.20 美元左右。该股即使遭遇 0.20 美元的价值冲击也能生存下来,并仍能支付股息,其投资回报率前景仍有很大的上升空间。

然而,作为一个好奇而迂腐的统计学家,我想测试一下我的直觉。我试着在谷歌上搜索是否有人已经做过类似的事情,但是没有效果。事实证明,为 20 世纪 30 年代的棋盘游戏进行随机建模并不是一个热门话题。我正在进入未知的水域。

不过,信封背面的数字处理还不够好。尽管这个市场模型是粗糙和基本的,但是有太多的随机因素在起作用,无法用手工计算出所有的统计数据。相反,我求助于蒙特卡罗模拟来计算不同策略的预期收益和方差。

仿真实现

这项调查是用 Python 进行的——完整的源代码可以在我的 GitHub 上找到在这里。

这个想法是为了模拟一种商品在交易阶段开始时每一个股票价值的几十万个回合(0.05 美元,0.10 美元,…,1.90 美元,1.95 美元)。

然后,我们可以采用这些模拟结果,并将它们汇编成统计数据,以量化风险水平。这构成了蒙特卡罗模拟的基础。这里值得关注的统计是期望值样本标准差。这只股票能为我带来多少回报?风险有多大?

模拟的参数有:

  • 交易阶段开始时的资产总值
  • 同桌人数
  • 在下一个交易阶段开始前在牌桌上的回合数

然后,将为玩家 × 回合掷骰子模拟所有可能的初始值,假设玩家将所有资本投入股票。我们做这个假设是为了大大简化模拟的复杂性。这将为我们提供所需的所有重要信息,我们可以在以后应用多样化试探法将预期收益和方差调整到特定的风险容忍度。

Code Snippet From the Simulation

仿真被序列化为pickles并存储在本地,以方便 sim 的扩展。模拟可以分块完成,并且总是被保存。

所有的游戏规则都完全包含在模型中,包括股息支付、股票崩溃和股票分割。

这个随机过程的结果被记录下来以供分析。

Photo credits: Agence Olloweb (Unsplash)

结果呢

在大约 12,000,000 次模拟(三分钟的计算)之后,我们的好奇心可以得到休息了。现金被设定为 5000 美元(游戏开始时您拥有的金额)。玩家被设定为 4 人,回合数为 7。

最初的结果非常有趣。对此,我知道 0.05 美元的股票会有一个相当不错的预期收益。股票如此便宜,一点点资本就能走很长的路。只需简单地增加 0.20 美元,就能让你的初始投资翻五倍。然而,这种策略有很多包袱。一次失误,你就可以和整个投资说再见了。这种策略有很大的差异。

剧情是这样的。

随着初始股价的上升,方差急剧下降,这对于前面讨论的原因是有意义的。然而,在 1.65 美元以上的范围内,它又开始逐渐上升。同样,这也符合我们的预期。当股票接近 2.00 美元时,它分裂的可能性增加。拆分使股票回到票面价值,可以说是一个危险区域。

预期收益在 1.00 美元时大幅飙升,因为收取股息的概率在这里出现了跳跃。

让我们仔细看看在这个图的中心周围实际上发生了什么,便宜股票的高方差使我们的观点有点倾斜。

这告诉我们,如果我们把所有的 5000 美元投资到 1.20 美元的股票,我们的预期利润是 701.75 美元,标准差是 1241.51 美元。理想情况下,我们在期望值和标准差之间找到了一个最佳平衡点。1.15 美元到 1.40 美元范围内的任何股票都相当不错,但如果我必须选择一个理想的风险组合,我会选择 1.30 美元的股票。

这是这个模拟的完整数字转储。

S = initial price, n = simulations, D = dividend yield, H = final holdings, P = D + H + (-initial cash) = profit

那么最优策略是什么呢?

根据这项调查的结果,在每个交易阶段的开始,注意力应该集中在恰好在 1.15 美元到 1.40 美元范围内的任何股票上。如果你持有这个范围之外的股票,如果可能的话,最好将它全部变现,将资金投入到这些更好的选择中。请记住,每一轮都像这样花时间重组你的所有资产可能会激怒你的朋友,但嘿,只要能赢就好,对吗?

注意力应该集中在位于 1.15 美元到 1.40 美元区间的股票上

如果有多只股票处于这个最佳状态,应该采用分散投资来免费降低风险,而不会影响预期利润。例如,在游戏开始时,将 1000 美元投入四只股票,500 美元投入另外两只股票是一个好主意。这样你可能不会得到很多早期的线索,但是在第一个交易阶段开始时,你将处于一个很好的位置来利用董事会的状态。

如果你想以额外的方差为代价提高预期利润,将一小部分资金投入廉价股票是实现这一目标的好方法。例如,如果游戏快结束了,你觉得自己不是第一名,那就买一些 0.10 美元或 0.15 美元的股票,试试运气。然而,大量这样做是极不明智的。偶尔,你会成为餐桌上的沃伦·巴菲特,但大多数时候,你只会落得一个钱包空空,自怨自艾的下场。

Photo credits: Brian Suman (Unsplash)

最后

所有这些分析真的有必要吗?这些结果与坚实的数学本能所能提供的结果有很大不同吗?不尽然,但这不是重点。

统计学就是要检验假设和怀疑——以客观和不可否认的方式揭示真相。看到所有与这些模拟相关的随机性都崩溃成一个漂亮的模式,这是一件令人非常满意的事情。

快乐的棋盘游戏!

赢得一场精彩的产品经理面试

原文:https://towardsdatascience.com/cracking-an-awesome-product-manager-interview-2baa902791a1?source=collection_archive---------2-----------------------

面试了脸书和初创公司的 200 多名项目经理后,我为候选人准备了一份清单。对于一个有抱负的项目经理来说,在面试中采取结构化的方法展示了他们的思维方式,揭示了一个人对项目经理角色的理解,并使他们能够扮演那个角色。与所有人分享!!

我以联合创始人的身份经营过两家数据产品初创公司,为在新兴市场拥有 3.2 亿用户的脸书管理产品,在 AOL 还是“互联网”的时候,它是 AOL 数据产品不可或缺的一部分,现在,我是 Airtel 的首席数据科学家,Airtel 是全球最大的电信公司之一,拥有超过 3.5 亿用户。到目前为止,我已经采访了大约 200 名产品经理(PM ),还指导了十几家印度和美国的初创公司建立他们的 PM、数据 PM (DPM)和数据科学团队。

多年来,我为候选人创建了一份清单,可以帮助他们在 PM 面试中保持最佳状态。对于一个有抱负的项目经理来说,在面试中采取结构化的方法展示了他们的思维过程,揭示了一个人对项目经理角色的理解,并使他们能够扮演那个角色。这对面试者和面试官都是一样的。我会说,在大约一半的面试中,我学到了一些新东西,在其中大约 10-20%的面试中,我对自己说“啊哈,我根本没有那样考虑问题”。

模拟面试

实践项目经理面试的方法是让一个朋友(最好是项目经理)问你“你将如何为 Y(用户描述)打造 X(产品类型)?”从了解你在为谁构建开始,来解决什么(“用例”)和为什么用户应该关心。然后你应该通过用例来构建产品为用户做什么

虽然可能会有其他问题,例如对产品市场的估计,或者有时是一个技术问题,例如设计一个应用程序,但上面的问题是最重要的。

三条黄金法则

在与面试官一起解决问题的过程中,记住三条规则:(1)提问以澄清——范围、假设、可能的场景,任何事情都是公平的,(2)大声说出你的思考步骤,(3)在进行下一步之前寻求面试官的肯定,尤其是在结果可能是多种可能性之一的情况下。

一旦功能清晰,与潜在用户群的一致性明显("产品市场适合"),你应该描述产品的视觉效果("设计思维"),以及你将如何把它推向市场并成长(成长")。最重要的是,如果你能开发出一个收入模型并估算出损益,就考虑录用你吧。**

真正的面试

大多数人都有自己的面试方式,你应该选择自己的风格和舒适度。以下是我的建议:

  • 调查公司和产品:听起来很明显,但是我见过太多的应聘者没有做基本的调查就来面试:公司、产品、收入、最近的新闻发布等等。不知道这些是没有借口的——如果你不知道这些,你几乎肯定会被取消资格。
  • 展示你多功能、人性化的一面:以积极的态度去参加面试。面试官在寻找一个多功能的人——产品,一些数据和工程,更多的合作伙伴关系,法律,营销,财务和高管/利益相关者管理。要戴这么多帽子,你需要是一个忙碌的、见多识广的、好奇的、固执己见的、谦逊的和友好的混合体。展现你人性的一面!
  • 建立最初的融洽关系:调查面试官:LinkedIn、Twitter、Medium、他们的社交轨迹、在 YouTube 上的谈话、过去的角色和成就,甚至是他们上过的学校或玩过的游戏。人是群居动物,每个人都喜欢花时间去了解他们和他们的背景的人。

既然你已经花了前 7-10 分钟热身,并且和面试官相处融洽,那就准备好回答“你将如何为 Y[用户描述]构建 X[产品类型]”的问题。

  • 首先,是用户:作为项目经理,你的关键角色是识别特定人群今天面临的特定问题,感同身受,设想一个改善他们状况的新解决方案,以足够的细节说明它,考虑利弊,重复功能和改进,并通过工程使它成为一个可构建的解决方案。整体体验将需要考虑用户如何了解解决方案及其关键特性("发现"),什么使其引人注目("产品市场适合"),以及尽快获得至少相当数量的解决方案以“啊哈!”喜悦时刻("新用户体验")。你还需要考虑迫使他们吸引他人参与体验的动力和网络效应(“成长策略*”)。*

Figure 1: First, it’s the user

  • 现在,移动到白板前想象:我不记得在没有白板的房间里进行面试*一个好的候选人没有在最初的 15-20 分钟内开始使用白板。原因很简单,一旦你有了用户故事,让面试官想象用户会看到什么。例如,如果它是一个分享视频的移动应用程序:勾画出主屏幕,显示用户将看到的信息,谈论屏幕之间的导航,以及如何让用户 在几分钟内发现关键功能,或者 10 个动作 。讲故事是面试这一部分的一个重要方面:谈论你将如何降低复杂性,并推动保持用户参与所需的行动。项目经理不需要成为设计大师,但 UX 感是必须的。*
  • 使用逻辑结构创建业务框架并进行现实检查:从市场评估开始。比如:在印度分享短格式视频(目前围绕抖音的热潮,Vigo video 等等)是不是一个针对年轻人的新 app?在印度这样一个快速增长、竞争异常激烈的市场中,获得一个用户需要花费多少成本?在这个市场中,大量风投资金正在追逐相对较窄的一部分城市年轻人,他们拥有相对较高的富裕程度,因此可以花钱进行应用内购买,或者被定向展示/赞助。或者,你应该把重点放在数量更多但第一次接触智能手机的农村年轻人身上吗?这两类用户的获取成本是多少(提示:他们可能相差 5-10 倍印度)?你可能的终身客户价值(LTV)是多少,尤其是如果涉及多个用户群体(男性/女性、年轻人/老年人、功能手机/智能手机)?支持用户的成本是多少?

此时需要一个快速的经济模型:你需要知道你的想法是否可行。一个简单的“LTV > CAC + S”(终身价值大于客户获取成本加上支持)是讨论的合适起点。

Figure 2: LTV > CAC + S. For every $50 invested, you can acquire a customer and return a $150, net off churn and support cost

你还应该深入研究一两个现实生活中的话题,尤其是对于高级职位,比如:如何衡量获取渠道的组合以优化预算,或者如何设计新的用户体验(“NUX”)以最大限度地减少应用程序前 30 天的流失。

  • 留意线索,随机应变,不断重复:虽然你应该明确地“领导”讨论,但留意面试官的反馈也很重要。一个好的面试官经常会中途给你数据点来挑战你的假设;你应该能够很快地整合这些并修改你的答案。这是你实际面试中最关键的部分,面试官通常会根据你运用新信息和随机应变的能力来决定是否面试。

Figure 3: Relatively modest amount of new information from the interviewer can change the outcome of the problem significantly

  • 快速结束:典型的面试过程会持续一个小时,其中大约 7-10 分钟用于介绍,最后 5-10 分钟用于回答候选人可能提出的任何问题。这就给真正的面试留出了大约 40 分钟的时间,其中面试官可能会探索 3-4 个领域,也可能会深入一两个领域。不管这是一个“广度”还是“深度”的问题;你应该提供一个结束。闭包是一个快速、近似的正确答案;它可以让面试官知道他们是否想深入探讨,或者进入下一个问题。
  • 大胆想象:伟大的项目经理都是想象力的大师。我参加的每一次面试,都希望候选人能说一些让我眼花缭乱的话。例如,假设有人问你,你将如何为脸书开发一项功能,以提高其在新兴市场的使用率。除了给出通常的特定于功能的答案,例如国际语言支持、特定的本地内容等。如果一个候选人假设脸书增长的障碍是一个沉重的产品(> 50MB),在低内存和低存储的低端 Android 手机上不能很好地运行,因此,需要剥离许多功能,制成 5 MB 以下的轻量级产品,她将被记住。
  • 现实一点:为什么这听起来是显而易见的,我见过一些严肃的 PMs 轰炸采访,他们的回答都是不现实的。这种情况通常有以下几个原因:( I)你走了一条狭窄的道路,独自讲述了你的假设和解决方案,而没有从面试官那里寻找线索;( ii)你没有根据提供的新信息重复你的答案,或者(iii)(有点不太可能),面试官从一开始就因为缺乏适当的热身而走神,从未进入“头脑风暴模式”。

结局

虽然这可能不适用于你参加的每一次面试,尤其是如果你参加的是同一家公司的一系列面试,你应该从面试官那里了解以下几点:

  • 检查面试官对工作的期望。你可能认为你是产品负责人,所有人都向你汇报。但事实上没有人为你工作——你仍然要负责送货
  • 试着感受一下团队文化。是像谷歌和特斯拉那样的工程主导型公司,像脸书和优步那样的项目管理主导型公司,还是像苹果那样的设计主导型公司?这会让你对公司的“等级秩序”有一个概念,以及在实际工作中会有什么样的期待
  • 询问是什么使一个人在集团和公司中成为“不可替代”项目经理。这个问题通常比你可以问的任何其他问题都更能揭示关于该职位的文化、工作实践和现实,并且是一个很好的“去/不去”检查点

面试愉快!!留下你对这些建议的想法,并请添加你自己的观察或学习。我们可以一起学习和提高。

结语:我计划写一系列关于数据科学、机器学习、产品管理和职业成功故事的博客。你可以跟着我把这些放进你的培养基里。

下一个故事: 用“印度级”技术为世界供电

上一篇: 人工智能对 2020 年的预测

用 Google AutoML Tables & Tensorflow 破解比特币

原文:https://towardsdatascience.com/cracking-bitcoin-with-google-automl-tables-tensorflow-fbe3f16ce9b2?source=collection_archive---------4-----------------------

谷歌已经在其云平台上推出了几款旨在自动化和改善机器学习培训和供应的产品。其中最新的— AutoML Tables 旨在“在结构化数据上自动构建和部署最先进的机器学习模型”。

我曾经是机器学习和自动化一切事物的粉丝,我想我会尝试一下,用另一种自己成为头条新闻的技术来折磨它——比特币。

这个想法很简单——比特币“挖掘”是试图猜测字符串正确组合的过程,这些字符串一旦经过哈希处理,就会生成一个有效的块。副产品是交易的处理,回报是比特币的宝藏。

那么为什么要对其应用机器学习呢?嗯,目前的挖掘方法本质上是“蛮力”强化计算,试图猜测算法的正确输入。然而,比特币的一个关键特征是区块链——迄今为止挖掘的每个区块的完整记录,以及用于挖掘它的输入参数。

事实上,区块链包含 50 万个“问题”的例子,以及解决方案。在机器学习领域,他们称之为“训练数据集”😃

区块链——准备训练数据

AutoML Tables 允许用户上传排列在表格中的大型数据集——大表数据集或更简单的——一个. csv 文件。

如前所述,挖掘比特币区块是对一组输入参数应用哈希算法(两次)的过程。这些参数经过哈希处理后,构成了“块头”的一部分,块头必须以多个前导零开头,这由难度决定。一旦产生的哈希有效,它就会存储在区块链中,供所有人查看(和验证)。它是一个 80 字节的字符串,由以下内容组成(单击图片了解更多信息):

添加描述

除了版本、Bits (target)和 hashPrevBlock 是固定的之外,其他参数由挖掘器决定并在散列时递增。然而,当与其他人合作挖掘时——时间和 MerkleRoot 也由挖掘池决定,留给我们的只是增加和猜测 Nonce。因此,它将作为我们的目标和我们的机器学习模型的输出,这很好,因为 AutoML 表只能有一列设置为目标。

为了将数据保存到一个. csv 文件中,我启动了一个完整的比特币节点,在等待它与网络同步后(等了又等..)—运行“bitcoin-cli getblock ”,进行一些剪切并保存到文件中,然后以之前的 Hash 作为输入再次运行,如此向后迭代区块链。结果看起来像这样:

添加描述

为 AutoML 表添加标题行以获取列名是很重要的。

谷歌云自动表

第一步是将我们的训练数据导入到 AutoML 表中。完成后,我们将看到“Schema”屏幕,在这里我们选择 ML 模型的“目标”——它将输出的字段。

添加描述

AutoML 还可以帮助从数据中提取验证集,应用加权列,甚至处理时间序列数据。

但是等等!我们已经发现了一个问题——AutoML 自动检测列数据类型,并挑选了几个字段作为“分类的”。这很好,但是在我们的例子中,因为值是唯一的,所以有多少训练行就有多少类别,而实时数据永远不会匹配任何类别!

如果我们进入分析页面,我们可以看到选择了太多类别(蛋糕是第 1 页,共 4 页..)

添加描述

这实际上是 AutoML 表的一个很好的特性——它允许我们在开始训练之前就发现数据中的问题。我们可以看到我们有许多不同的值(没有重复的行),以及每个字段与我们的目标的相关性,这在我们的例子中是低的,并且将产生差的结果。

由于重要字段的相关性较低,当我们进入训练阶段时,我们选择忽略更静态的列,以便我们的模型可以专注于重要的列:

添加描述

我开始训练这个模型,结果和预期的一样——非常高的平均误差,意味着我们的模型不会产生任何有意义的结果。

第二次尝试—逐字节

鉴于上述情况,我尝试将训练数据修改为非分类值。这也将允许我们使用 Tensorflow + Keras 在本地训练一个模型进行比较。

Tensorflow 希望输入采用 Bytearray 的形式,取值范围为 0 到 255。我把区块链的字段一个字节一个字节的拆分,结果看起来是这样的:

添加描述

我们的数据现在有 76 个字段,每个字段代表块头的 1 个字节,最后 4 个字节是最后一个数字字段——我们的目标 Nonce。

再次将数据导入 AutoML 表,它将显示为数字:

添加描述

看起来很有希望,与目标的相关性均匀分布在所有列中。不幸的是,培训又一次产生了糟糕的结果:

添加描述

巨大的错误率,高平均平均百分比误差(越低越好)。

验证-使用张量流

糟糕的结果是 AutoML 表中的错误,还是只是人工智能无法学习的训练数据的复杂性?为了验证这一点,我求助于古老的 Tensorflow & Keras 进行一些本地培训。

Tensorflow 以 Bytearray 的形式期待数据,正如我们在第二次尝试中所做的那样。这是如何准备的-

添加描述

我们训练一个全连接的神经网络,输出 4 个字节,我们将连接这些字节以形成我们的随机数-

添加描述

仅仅几个时期的训练结果就已经说明了同样的问题:

添加描述

请注意,尽管平均绝对误差没有 AutoML 表中的高,但精度却“固定”在 0.2757。

这不是巧合。因为我们正好输出 4 个字节,这个准确度分数只能意味着神经网络不能正确地学习和预测。

原因?要么是网络不够大——这不太可能,因为我们至少会看到不同时代之间的一些改进,

或者数据在输入和目标之间不包含可检测的相关性。

我想就这样吧!看到一个简单的 SHA256 和足够的“盐”如何产生足够的熵来使区块链真正健壮和不可破解,真是令人惊讶!

至少在我们推出大枪之前…请继续关注第二轮——用富士通量子退火器破解比特币!

德罗·詹斯勒

crawlab——网络爬虫的终极实时仪表板

原文:https://towardsdatascience.com/crawlab-the-ultimate-live-dashboard-for-web-crawler-6c2d55c18509?source=collection_archive---------14-----------------------

来监控你所有的爬虫!

最近,我发现了一个非常有趣而又强大的项目。虽然这个项目才开始 6 个月,但是已经有大约 24k 个赞了。该项目于 2019 年 3 月刚刚启动,从以下几点来看,它似乎很有前途。

  1. 能够为网络爬虫监控不同种类的语言。比如 Python,NodeJS,Go,Java,PHP 以及各种网络爬虫框架包括 Scrapy,Puppeteer,Selenium。
  2. 包括一个漂亮的实时仪表板。
  3. 能够可视化的数据抓取,他们可以通过点击一个按钮下载。
  4. 你只需输入 XPath 和 URL 就可以创建一个爬虫,即所谓的“可配置爬虫”(不幸的是,最新版本 v0.3.0 已经暂时禁用了这个功能,参考可以在这里找到

Pyspider vs Crawlab

以前我分享过 Pyspider 是最棒的监控工具之一,如果你没有读过,你可以点击下面的链接来阅读。

[## 为什么 Pyspider 可能是初学者最好的刮擦仪表板之一

py spider——竞争对手监控指标的实际应用

towardsdatascience.com](/pyspider-a-practical-usage-on-competitor-monitoring-metrics-c934d55f9c9a)

嗯,它们确实有一些相似之处,例如,它们都是爬虫程序的伟大仪表板,它们可以被调度,有一个令人印象深刻的仪表板来可视化…但是,如果你想知道显著的区别,在这里你去:

  1. Pyspider 在可视化抓取网站的旅程方面更胜一筹。
  2. 如果你想集成不同的语言或网络爬虫框架,Crawlab 更好。
  3. Crawlab 是用 Golang 写的,一般效率更高,速度更快。

案例研究—将 Scrapy spider 集成到 Crawlab

第 1 部分—安装 Crawlab

先决条件—在您的笔记本电脑上安装 Docker。

version: '3.3'
services:
  master: 
    image: tikazyq/crawlab:latest
    container_name: master
    environment:
      CRAWLAB_API_ADDRESS: "localhost:8000"
      CRAWLAB_SERVER_MASTER: "Y"
      CRAWLAB_MONGO_HOST: "mongo"
      CRAWLAB_REDIS_ADDRESS: "redis"
    ports:    
      - "8080:8080" # frontend
      - "8000:8000" # backend
    depends_on:
      - mongo
      - redis
  mongo:
    image: mongo:latest
    restart: always
    ports:
      - "27017:27017"
  redis:
    image: redis:latest
    restart: always
    ports:
      - "6379:6379"

复制上面的代码,保存为docker-compose . yml。然后在同一个目录中,在您的终端中键入命令 docker-compose up 。docker 映像将被下载到您的本地。

第 2 部分—启动 Crawlab 并登录

在您的浏览器上导航到 localhost:8080,您将能够看到如下所示的登录页面。

默认用户名:admin

默认密码:admin

第 3 部分—上传 Scrapy 项目

转到这个 URL ,然后点击添加蜘蛛按钮,如下图所示。

我正在为 gadgets now 网站使用我的爬虫。

上面的快照是我的 scrapy spider 目录,向下一级到包含 scrapy.cfg 的目录(用红框突出显示),然后压缩这 3 个项目。最后,上传 zip 文件。

第 4 部分—获取 MongoDB 的 IP 地址

检索该 docker 图像的 docker ID:mongo:latest。您可以使用下面的命令查看 docker id。

docker ps

然后按照下面的命令输入 docker id:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <input your docker id here>

接下来,您将在 docker 容器中获得您的 MongoDB 的 IP 地址。在我的例子中,IP 地址是 172.18.0.2。

第 5 部分—输入 IP 地址并修改 pipelines.py

import osfrom pymongo import MongoClientMONGO_HOST ='172.18.0.2'
MONGO_PORT = 27017 
MONGO_DB = 'crawlab_test'class GadgetsnowPipeline(object):
    mongo = MongoClient(host=MONGO_HOST, port=MONGO_PORT)
    db = mongo[MONGO_DB]
    col_name = os.environ.get('CRAWLAB_COLLECTION') 
    if not col_name:
        col_name = 'test'
    col = db[col_name]def process_item(self, item, spider):
        item['task_id'] = os.environ.get('CRAWLAB_TASK_ID')
        self.col.save(item)
        return item

这是修改后的 pipelines.py 的 Python 脚本。我想强调以下几点:

  1. 输入我们之前获得的 MongoDB 的 IP 地址:MONGO_HOST = ' 172.18.0.2 '。
  2. 复制上面的process_item函数,并将其替换到您原来的 pipelines.py 文件中。
  3. MONGO_DB 的值可以是 MongoDB 中您想要的任何数据库名称,对于我的例子,我将其设置为crawlab_test

第 6 部分—在 items.py 中添加两个新字段

task_id = scrapy.Field()
_id = scrapy.Field()

这两个字段需要添加到items.py中。

首先,task_id是您已经执行的每个任务的标识符,您可以在 spider - > spider_name - >任何任务- >概览选项卡中查看它。

其次,_id是 MongoDB 中每个对象的惟一标识符。

第 7 部分—运行您的蜘蛛

点击你新上传的蜘蛛,然后输入执行命令。因为我的 Scrapy 爬虫的名字是 gdgnow,所以我的命令应该是:

scrapy crawl gdgnow

然后,先点击保存按钮,再点击运行按钮开始刮削。

第 9 部分——可视化结果

以我的爬虫为例,上面的快照显示了我的爬虫的输出,最重要的是,您可以通过点击下载 CSV 按钮下载 CSV 格式的文件。

对于item_desc字段,它显示的是undefined,因为我的item_desc是 JSON 格式的,但是 Crawlab 还不支持输出 JSON 字段。如果您希望在输出数据中包含 JSON 字段,目前唯一的选择是登录包含 MongoDB 的 docker,crawlab 将数据传输到这个 docker 并从中提取数据。

展示相当惊人,向 Crawlab 的所有开发者致敬!

最后的想法

非常感谢你耐心阅读到最后。Crawlab 仍处于早期阶段,但它是一个非常有前途的爬虫框架,特别是在监视多个网络爬虫方面。

由于这只是对 Crawlab 的一个简单介绍,我还没有包括 Crawlab 的所有功能,例如,cron job,如何集成其他网络爬虫的框架等等。如果你真的想让我分享更多关于 Crawlab 的内容,请在下面的评论,我会为此再写一篇文章!

关于作者

低伟鸿是 Shopee 的数据科学家。他的经验更多地涉及抓取网站,创建数据管道,以及实施机器学习模型来解决业务问题。

他提供爬行服务,可以为你提供你需要的准确和干净的数据。你可以访问 这个网站 查看他的作品集,也可以联系他获取抓取服务

你可以在 LinkedIn 和 Medium 上和他联系。

使用 React 和 Flask 创建一个完整的机器学习 web 应用程序

原文:https://towardsdatascience.com/create-a-complete-machine-learning-web-application-using-react-and-flask-859340bddb33?source=collection_archive---------0-----------------------

Photo by Alvaro Reyes on Unsplash

我一直想开发一个完整的机器学习应用程序,其中我会有一个 UI 来提供一些输入和机器学习模型来预测这些值。上周,我就是这么做的。在这个过程中,我在 React 和 Flask 中创建了一个易于使用的模板,任何人都可以在几分钟内修改它来创建自己的应用程序。

项目亮点:

  1. 前端是在 React 中开发的,将包括一个表单提交输入值的单个页面
  2. 后端是在 Flask 中开发的,它公开预测端点,使用经过训练的分类器进行预测,并将结果发送回前端以便于使用

下面是 GitHub 回购。分叉项目并创建您自己的应用程序吧!

[## kb22/ML-反应-应用程序-模板

它是一个构建 React 应用程序并与 REST 端点进行交互以进行预测的模板。-kb22/ML-React-App-模板

github.com](https://github.com/kb22/ML-React-App-Template)

模板

反应

React 是一个 JavaScript 库,由脸书创建,旨在简化用户界面,使其易于开发和使用。它是前端开发的主要语言之一。你可以在这里读到它。学习 React 的最佳资源是它的文档本身,它非常全面且易于掌握。

烧瓶和烧瓶-RESTPlus

Flask 和 Flask-RESTPlus 允许我们在 Python 中定义一个服务,它将具有我们可以从 UI 调用的端点。你可以从我下面的文章中了解更多关于开发 Flask 应用程序的信息。

[## 使用 Flask、Flask RESTPlus 和 Swagger UI 处理 API

Flask 和 Flask-RESTPlus 简介

towardsdatascience.com](/working-with-apis-using-flask-flask-restplus-and-swagger-ui-7cf447deda7f)

描述

我用create-react-app创建了一个基本的 React 应用程序。接下来,我加载了bootstrap,它允许我们为每个屏幕尺寸创建响应性网站。我更新了App.js文件,添加了一个带有下拉菜单、PredictReset Prediction按钮的表单。我将每个表单属性添加到 state 中,并在按下Predict按钮时,将数据发送到 Flask 后端。我还更新了App.css文件,为页面添加了样式。

Template view

Flask 应用程序有一个 POST 端点/prediction。它接受 json 形式的输入值,将其转换为数组并返回到 UI。在实际应用中,我们将使用存储在classifier.joblib中的分类器使用相同的数据进行预测,并返回预测结果。

Prediction displayed on UI

Reset Prediction将从 UI 中删除预测。

启动模板

将回购克隆到你的电脑上,进入电脑,在这里打开两个终端。

准备用户界面

在第一个终端中,使用cd ui进入ui文件夹。确保您使用的是节点版本10.4.1。进入文件夹后,运行命令yarn install安装所有依赖项。

为了在服务器上运行 UI,我们将使用serve。我们将从全局安装serve开始,之后,我们将构建我们的应用程序,然后最后在端口 3000 上使用serve运行 UI。

npm install -g serve
npm run build
serve -s build -l 3000

您现在可以转到localhost:3000来查看 UI 已经启动并运行。但是它不会与仍未启动的 Flask 服务进行交互。所以,让我们开始吧。

UI

准备服务

在第二个端子上,使用cd service移动到service文件夹内。我们首先使用virtualenv和 Python 3 创建一个虚拟环境。你可以在这里阅读有关 virtualenv 的内容。激活环境后,我们将使用 pip 安装所有必需的依赖项。最后,我们将运行 Flask 应用程序。

virtualenv -p Python3 .
source bin/activate
pip install -r requirements.txt
FLASK_APP=app.py flask run

这将在127.0.0.1:5000启动服务。

Service

瞧啊。完整的应用程序现在可以正常工作了。耶!!

将模板用于自己的用例

为了理解为任何模型使用模板的过程,我将使用iris数据集并为其创建一个模型。该示例也可以在项目的example文件夹中找到。

创建模型

我在虹膜数据集上训练了一个DecisionTreeClassifier,它需要 4 个特征——萼片长度、萼片宽度、花瓣长度和花瓣宽度。然后,我使用joblib.dump()将模型保存到classifier.joblib。分类器现在可用于预测新数据。

更新服务

接下来,我在一个文本编辑器中打开了文件app.py(Sublime Text 就是其中之一)。我取消了对行classifier = joblib.load(‘classifier.joblib’)的注释,以便变量classifier现在保存训练好的模型。

在 post 方法中,我做了以下更新:

首先,我使用classifier.predict()得到预测。接下来,我为这些类创建了一个映射,0 表示Iris Setosa,1 表示Iris Versicolour,2 表示Iris Virginica。我终于返回了result键中的预言。

更新:正如马丁斯·恩塔尔斯指出的,我忘了说我们也需要更新模型,这样它才能正确工作,并且在 Swagger UI 中有更新的模型。

从要点中可以看出,我已经更新了字段名、它们的类型为Float、描述和帮助文本。同样的情况现在也将反映在 Swagger 中。

Updated model in Swagger UI

更新用户界面

该表单由行内的列组成。因此,由于我有 4 个特性,所以我在 2 行中添加了 2 列。第一行将有萼片长度和萼片宽度的下拉列表。第二行将有花瓣长度和花瓣宽度的下拉列表。

我首先为每个下拉列表创建了一个选项列表。

接下来,我定义了两行,每行两列。每个下拉选择看起来像下面的代码:

对于每个下拉菜单,我们必须更新<Form.Label></Form.Label>中的文本。我们还将命名每个选择组。假设名称是petalLength,那么我们设置值为{formData.petalLength},名称为“petalLength”。正如我们在上面的{petalLengths}中看到的,选项是使用我们在<Form.Control></Form.Control>中定义的名称添加的。一个<Form.Row></Form.Row>中的两个这样的组将构成我们的 UI。

状态也必须用formData中的相同名称更新,默认值为各个下拉列表中的最小值。构造函数如下所示。如您所见,状态已经更新为formData带有新的键。

添加新的背景图像和标题

在 app.css 中,将背景图片的链接改为自己的链接。我添加了一张 Unsplash 的花的图片。我还将标题更新为Iris Plant Classifier,并将页面标题也更新到了public文件夹中的index.html文件中。

结果

应用程序现在可以使用这个模型了。使用npm run build构建 UI 后,重启两个服务。该应用程序如下所示:

Main Page

对于某些特征值,按下Predict按钮,模型将其归类为Iris Setosa

有了新的特征值,模型预测植物为Iris Versicolour

结论

如您所见,在本文中,我讨论了一个 ML React 应用程序模板,它将使创建完整的 ML 应用程序变得简单快捷。

针对您自己的使用案例尝试该应用程序,并分享您的反馈。我很乐意收到你的来信。

为星际争霸 2 创建一个定制的健身房环境

原文:https://towardsdatascience.com/create-a-customized-gym-environment-for-star-craft-2-8558d301131f?source=collection_archive---------29-----------------------

在本帖中,你将能够学习什么是健身房环境,以及如何以地图 DefeatZerglingsAndBanelings 上的 PySC2 为例创建一个 OpenAI 定制的健身房环境。

OpenAI Gym x Star Craft 2

目前,有多种强化学习框架可用(例如,OpenAI 基线、稳定基线、TFAgent、多巴胺和 TensorForce 等。)各有利弊。然而,如果您想在各种应用程序环境下使用这些工具,最常见和最方便的方法是构建一个定制的健身房环境。

健身房环境

那么什么是健身房环境呢?

在我们开始回答之前,让我们回顾一下强化学习的过程。

强化学习基本上是一个马尔可夫决策过程(MDP ),在这个过程中,主体将根据对环境的观察采取一些行动,以换取反馈。根据反馈,无论是积极的还是消极的,代理人所使用的决策策略将相应地加强或削弱。

MDPs

MDP 需要两个关键组件,即行动和对环境的相应观察。由于不同的环境有不同的观察和行动空间,为了迎合环境不断变化的需求而重新发明各种算法是非常耗时和不切实际的。因此,提出一个可以表示各种设置并可以轻松插入多个框架的标准化环境似乎是一个可行的解决方案。

这就是健身房环境发挥作用的地方。健身房环境为强化学习过程提供了一个标准化的界面。

在健身房环境中,__init__函数是用于初始化环境。在训练过程中,动作通过一个step函数传递给环境,新的观察作为返回。动作观察空间都被编码到[gym.spaces](https://github.com/openai/gym/tree/master/gym/spaces)中,用标准化的数字表示。reset功能用于初始阶段或每集结束时重置环境。close学习过程结束时调用函数,正确终止环境。此外,您还可以定义一个render函数来在每一步之后渲染环境。

A gym environment structure

下面是一个健身房环境的框架代码:

建立一个定制的健身房环境

现在让我们用星际争霸 2 (SC2)建立一个定制的健身房环境。要了解更多关于 SC2 和 pysc2 的信息,请参考 deepmind git 资源库。

因为我们将使用来自 SC2 的原始观察和操作,所以我们需要安装 pysc2 的开发分支来完成这里的教程。

要安装 pysc2 的开发分支:

git clone [https://github.com/deepmind/pysc2.git](https://github.com/deepmind/pysc2.git)
git checkout -t origin/dev
pip install -e .

要启动一个定制的健身房环境,我们需要创建下面的文件结构,如 OpenAI 所述:

gym-foo/
  README.md
  setup.py
  gym_foo/
    __init__.py
    envs/
      __init__.py
      **foo_env1.py
      foo_env2.py**
      ...

配置 setup.py 文件和所有的 init。py 文件可以在这里查看。因为我们将主要关注于 foo_env.py 的实现,所以我包含了一个文件结构的框架,您可以直接下载。

envs 文件夹中,让我们创建一个名为defeat _ zeglings _ banelings _ env . py 的环境文件。这将是我们的健身房环境文件,我们将使用以下代码开始在这里创建我们的环境:

注意到kwargs被传递给了__init__函数。这用于使用特定设置初始化 pysc2 环境。

我们将使用观察和操作定义一个默认设置来初始化微型地图 DefeatZerglingsAndBanelings 的 pysc2 环境:

players由于设置需求,规范是需要的,虽然它在这里没有做任何事情。realtime如果用于训练,可以设置为假。

接下来,我们将开始初始化 gym 和 pysc2 环境:

env用于存储 pysc2 游戏环境的实例。marinesbanelingszerglings定义为保留对应的部队。我们为action_space定义了大小为 123 的离散动作,包括站位、上移、下移、侧移以及用不同的单位攻击不同的目标。对于observation_space,我们定义了一个 19x3 的 2D 矩阵,其下限和上限分别设置为 0 和 64。观察空间的每一行都将包含战场上每个单位的信息,包括坐标和 HP。

现在,我们需要从reset函数初始化环境,因为它将在最开始被调用:

如果self.env尚未设置,它将首先调用init_env函数,用特定设置初始化 pysc2 环境。然后一切都会恢复原状。原始观测值将由get_derived_obs函数处理,它将返回一个派生的 19x3 观测值矩阵。

接下来,我们将填充step功能。让我们看看完整的代码:

step函数中,take_action会消耗一个动作值(从 0 到 122),映射到一个游戏内动作并相应执行。之后,将计算导出的观测值。最后,返回四个值,包括导出的观察值、先前动作获得的奖励、用于重置环境的情节结束指示符和用于调试的诊断信息字典。

最后,我们即将在这里完成定制的健身房环境。由于我们不会触及render函数,剩下的唯一事情就是用close函数正确关闭 pysc2 游戏环境:

瞧啊。现在,我们为 SC2 定制了一个工作环境。完整的环境代码可以从这里下载。

如果您已经知道如何从这一点继续定制环境,那么您可以在这里停下来享受一下。否则,我会在下一节中包含一个简短的演示,演示如何使用我们创建的强化学习框架。

稳定基线

出于演示目的,我们将在这里使用稳定的基线。要安装稳定的基线,请遵循其官方文档页面中的说明。

除了安装稳定的基线,我们还需要设置我们自己刚刚创建的定制环境。为此,切换到 sc2env 根目录并输入以下内容:

pip install -e. 

一旦安装过程完成,我们就可以开始使用 PPO2(您选择的算法)轻松地在我们自己的环境中进行训练。

代码如下:

培训就像使用scikit-learn模型一样简单:

  1. 指定要使用的型号(本例中为 PPO2)。
  2. 使用.learn()开始学习。
  3. 使用.save()保存训练好的模型。

请注意,PySC2 环境需要absl包。

如果在 Windows 系统上运行,我们将能够在训练时看到渲染的游戏:

否则,如果它运行在 Linux 系统上,我们可以使用 headless 模式加快训练速度。

为了监控训练过程,tensorboard 得到了本机支持。我们需要做的就是在定义模型时指定日志目录。

摘要

现在你有了工具,但这并不意味着你将能够使用我们创造的环境直接获得智能人工智能。你还可以做更多的事情,让它变得有趣和聪明。你可以定义一些基本的动作,比如撤退或者攻击最近的。你可以提供更多的观察信息。你可以录制一些游戏,进行模仿学习或行为克隆。你也可以创建你自己的迷你地图来帮助你的 AI 建立一些课程来逐步学习技能。

Result from environment with predefined basic actions suggested above

最后,我们已经到了这篇文章的结尾。在这篇文章中,我包含了一个使用 pysc2 创建定制健身房环境的教程,并演示了如何使用具有稳定基线的定制健身房环境。

希望这些有帮助。敬请期待,再见~

使用 Google Data Studio 创建仪表板,并使用它制作自动报告

原文:https://towardsdatascience.com/create-a-dashboard-with-google-data-studio-and-make-automatic-reports-with-it-db42088ad879?source=collection_archive---------15-----------------------

Google Data studio 是一个免费的交互式仪表盘,可以帮助你创建报告。这是我刚刚创建的一个报告的例子。

我已经将仪表板连接到两个数据源:

  1. 谷歌分析(从客户网站获取数据)
  2. Youtube 频道

要使用 Google Data Studio,您只需要一个 gmail 帐户,接受条款和条件后,您就可以快速开始使用它。

创建新报告非常简单,您只需点击“空白报告”即可创建您自己的个性化报告,或者您可以使用现成的模板(您也可以在查看一些模板后创建您自己的个性化报告,以了解如何构建您自己的仪表板)。

Create your Blank Report or use a template

单击空白报告后,您将进入此页面,在此您可以为仪表板命名(左上角),还可以通过“创建新数据源”(右下角)连接到您的数据。如果您没有数据源可以使用,或者您只是想尝试一下,您可以使用 Google 提供的样本数据集。

Your Blank Report — Connect to the Data Source

谷歌已经为你的数据提供了便捷的接口,所以你应该很容易找到你想要的东西。以下是可用数据源连接器的示例:

Examples of some connectors

连接数据集后,您可以开始在报告中添加图表。请记住,您可以将同一个仪表板连接到多个数据源(一旦您添加了一个新图表,您就可以将它连接到您想要用于特定图表的特定数据源),因此您不需要为多个数据源创建多个仪表板。

要在报表中添加元素,真的很直观。只需点击您想要添加的图表,并将其放置在仪表板中您想要的位置,您还可以更改其大小,例如使其变大。还可以添加文本、图像和图形/线条。

Adding graphs

每个图表都可以在报告的右边部分进行个性化设置,在这里可以选择与哪个数据源相关、使用哪个指标以及个性化其风格。

Choose metrics and style for your graph

我们可以使用的一个很好的特性是数据范围。如果我们将此添加到报告中,将有可能更改我们要考虑用于分析的数据范围,并且它将自动更改基于此时间范围的所有图表,因此我们不需要为不同的时间间隔一次又一次地创建所有图表。

我们也可以使用记分卡,它有助于可视化某些特定的 KPI,不需要图表,如下例所示。

Scorecard

完成图表后,我们可以通过多种方式与他人分享:

Share the Report

按顺序,我们可以:

  1. 下载成 pdf 格式
  2. 创建自动邮件发送报告(您可以选择时间频率)
  3. 获取可共享的链接
  4. 有嵌入的代码把图表,例如在一些网页

希望这篇文章对您有用,并享受您的数据分析/报告!

如果你愿意支持我写其他类似的文章, 请我喝咖啡 😃

用 SQL 和 Javascript 创建一个漫威数据库,简单的方法

原文:https://towardsdatascience.com/create-a-marvel-database-with-sql-and-javascript-the-easy-way-573ccdf44673?source=collection_archive---------31-----------------------

维基百科是一个很好的数据来源,你可以在你的下一个项目中利用它

I know, this picture is mostly about DC, but this post is not only about Marvel and Lena Rose did a great job taking this picture.

在这篇文章中,我将解释如何使用维基百科、Javascript 和 SQL 创建一个漫威数据库(或 DC 数据库)。我们将制作一个灵活的工具,允许您创建不同的表格用于您的项目。这里解释的概念可以扩展到其他学科。这篇文章是写给那些没有时间学习维基数据系统中使用的修改的 sql 的复杂语法,但仍然想玩他们的数据的人的。

我拥有一个漫画数据库的最初原因是为了创建这种可视化效果,你将在本文结尾再次看到这一点:

Legend of Marvel & DC visualization: https://heberleh.github.io/comics-universe/

管道

这里的想法是通过以下步骤获得一个灵活的数据库:

  1. Wikidata 中查询表格并导出为 json 文件
  2. 创建一个 Alasql 数据库,并插入来自 json 文件的数据
  3. 使用创建的数据库执行 SQL 查询

1.从维基百科提取数据

维基百科背后有一个很棒的数据库和本体。点击此处进入查询系统:https://w.wiki/4iP

在上面的链接中,你会发现类似的内容(你会在那里找到更多相关信息):

在这段代码中,我选择的实体是漫画人物的实例,并且在虚构世界 漫威世界中。乍一看可能有点奇怪,但是这些代码都是维基百科本体的一部分。这就是他们如何处理冗余,并能组织和使一切工作!但是如何创建自己的查询呢?

首先,会帮助你。尝试键入wdt:<Ctrl+Space>。您注意到弹出了一个帮助工具提示。尝试键入的实例。您会看到'的'实例的代码是wdt:P31。使用同样的方法,现在对于一个,你将输入wdt:<Ctrl+Space>(这次没有“t ”!)和漫画人物,回车,瞧,你得到了代码wd:Q1114461

<Ctrl+Space> opens the helper

O 好的,亨利,但是我不知道我们可以用什么,我没有时间学习维基百科的语言……而且我理解你!因此,为了克服这一点,我们将在这里打开这一页巨头。这是维基百科条目代码 Q841372,庞然大物!现在看一看,看看有什么关于一个漫画人物的信息。将鼠标指针放在语句部分的项目上。例如,如果您将鼠标放在“实例”上,您将获得 P31 代码!因为它不是一个值,所以对这个值使用wdt

通过浏览该页面,您可以很好地了解可以使用哪些属性。暂停:如果你想创建一个数据库,但还不知道它会是什么,试试随机文章功能来获得见解。我们可以对任何维基百科页面做同样的事情。去官方维基百科网站搜索任何东西,比如说… 铝。现在检查左侧栏,寻找 Wikidata item 链接。

Wikidata link is in read on the left

单击,瞧,它显示了该项目的所有属性。我们看到我们通过使用wdt:P2067得到了质量,以及许多其他可能适用于其他类型金属的属性。

Each Wikidata entry has many properties. The tooltip tells you the property ID.

现在我们有了维基数据,我们将:

  1. 为感兴趣的属性创建查询
  2. 将结果下载为。json
  3. 始终跟踪 id(Wikidata 项目 URL)和标签

例如,我创建了一个性别查询。一个查询职业,以此类推。结果是一个文件夹有许多。我将把 json 文件加载到由许多表组成的数据库中。您可以对所有信息执行单个查询。在我的例子中,我希望它具有延展性,这样我就可以执行 JOIN、LEFT JOIN 和其他 SELECT 命令来获得不同的表。

事实上,我没有只获得漫威宇宙,而是丢弃了那个过滤器,获得了一个虚构角色实例的完整数据库(不仅仅是漫画角色——出于某种原因,这个不会查询美国队长)。所以,在我的 json 文件中,你可以找到漫威、DC 和其他人。生成的 jsons 在我的 GitHub 页面中找到。接下来,我将展示如何在 Javascript 中使用 json 文件和一个简单的 T21 SQL 数据库。

正如我在上一段中提到的,我的查询实际上是关于虚构角色类及其子类的。我还查询了伴侣和配偶,因此为此我使用命令|来定义两个 wdt:

注意,在上面的代码中,我不再过滤漫威了。对于更复杂的查询或处理列表,请参考 Wikidata 网站。另一个不错的选择是位于维基数据查询服务顶部的帮助按钮,在那里你可以找到例子和支持。

2.用 Javascript 创建 SQL 数据库

现在我们有了 json 文件,让我们将它们插入到 SQL 数据库中。为此,我们将使用一个名为 Alasql 的工具。使用 Alasql,您可以以不同的方式加载数据和创建表格(在这里阅读更多信息)。

这里,因为我们有来自 Wikidata 的 json,所以我们将对每个 JSON(文件)应用一个 SELECT 并插入到我们数据库的一个新表中,以便于访问。为了简化,我的代码将只包含两个表;你可以在这里找到完整的更新版本 。看起来是这样的:

我们准备好了。我们有一个数据库,可以通过调用let mydb = MarvelDB()来使用它,并像这样应用 SQL 命令:mydb.exec('SELECT DISTINCT abilityLabel from abilities')

3.最终代码和用法

我定义了一些测试来确保一切正常。它举例说明了我们数据库的用法。如果你不习惯测试,只考虑下面代码中的let result = this.db.exec(...)console.table(result),忽略其他部分。

上面的SELECT返回列charLabel,并重命名为name。它还连接了角色、性别和能力表,确保条目具有相同的角色 id ( char)。最后,它通过名为 agender 的特定性别进行过滤。关于这个数据库的更多例子,请到 GitHub 页面 -别忘了开始:)

本文描述了我为下面的可视化创建数据库的方式。你可以通过在台式机/笔记本电脑上访问这个网站与它互动(它可以在手机上打开,但互动是有限的)。

Marvel & DC visualization: https://heberleh.github.io/comics-universe/

这是我漫画人物系列的第一部分:

  1. 用 SQL 和 Javascript 创建漫威数据库,最简单的方法 [this]
  2. 可视化漫画人物的性别和超能力
  3. 用数据可视化比较漫威和 DC

欢迎添加私人注释和评论。谢谢你看我的文章!

创建多标签分类人工智能:创建我们的数据集[第 1 部分]

原文:https://towardsdatascience.com/create-a-multi-label-classification-ai-for-movie-stills-part-1-ec6c81279888?source=collection_archive---------14-----------------------

使用 Pandas 创建我们的数据集,使用 FastAI 库和 Python 进行深度学习以开发 REST API,我们将制作一个能够区分电影剧照中几个元素的 AI,并将其部署到生产中。

Françoise Dorléac and Jean-Paul Belmondo in “L’homme de Rio” (1964).

该项目将分为四个不同的条款:

  1. 从数据库中创建我们的数据集到熊猫;

2.使用 FastAI 创建一个能够标记电影快照的 AI;

3.用 Docker 把我们的 AI 作为 REST API 部署到生产中;

4.每个月做一个脚本重新训练我们的 AI。

介绍 Whatthemovie.com

创建于 2008 年的 Whatthemovie 是一个独特的电影问答游戏,人们上传电影剧照,其他人必须猜猜这张照片是从哪部电影中拍摄的。在十多年的时间里,该网站已经从我们的优秀用户上传的 30 000 部电影中积累了超过 470 000 张图片。

我们重视质量胜于数量。因此,并非所有提交的图像都会被接受。今天,我们可以拥有超过一百万张图片,但这不是我们的首要任务。上传的图像必须对测验有趣,测验本身应该在难度和电影类型方面保持平衡。

主要区域如下所示:

Can you guess what movie is behind this shot?

给你一张取自电影场景的图片,你必须猜电影的名字。旗帜意味着你不必输入原始标题来获得分数,你也可以用德语、法语、西班牙语等来写。我们支持多种语言的替代游戏,让来自世界各地的用户有机会与其他用户一起游戏和竞争。

改善上传阶段

在网站上上传新的电影剧照听起来可能很容易:你从我们的数据库中选择一部电影——或者添加一部新的——你上传你的图像,你就可以开始了。实际上,用户必须首先用任何可用的播放器从电影中自己拍摄快照,裁剪图像中潜在的黑条,并通过上面描述的上传阶段。

在上传阶段的最后一步,我们要求我们的用户添加标签,描述图像包含的内容,图像中有什么——图像是否显示街道、汽车等。这看起来也相对容易,但他们已经做了很多工作,我们的大多数上传者都懒得添加标签,这很不幸,因为相关标签对过滤照片很重要。

Anna Karina in “Le petit soldat” (1963). You can see the tags below the shot. When you click on one of them — like “b/w” for black and white — , you can see all the black and white movie snapshots uploaded on the website.

过滤黑白快照听起来可能没什么意思,但想想其他标签,如“戈尔”、“裸体”或“血液”。这些标签显示了明显的敏感内容,一些用户不希望看到这些图片——至少在没有询问他们的情况下。这就是为什么标记图像很重要。如果一个用户忘记在他的照片上添加“裸体”或“戈尔”标签,一个用户在工作中玩——很多都是这样!—可能会看到这个图像,没有人希望这种情况发生在开放的计划中。

事实上,我们已经在网站上添加了一个设置,让用户选择他们是否希望这种快照自动显示。但显然,如果一张快照没有被标记为敏感的——“血染”或“裸体”,它仍然会显示出来。这引出了我们今天的项目:当用户上传他们的快照时,我们能自动向他们建议标签吗?我们能否建立一个能够检测图像中相对常见元素的人工智能,以帮助人们标记他们的照片?我们能否检测图像中的裸体或血块材料,以防止明智的人看到它们?

在这个系列的第一部分,我们将从从我们的数据库创建一个数据集开始,并用 Pandas 清理它。然后,在第二篇文章中,我们将开始使用 FastAI 训练一个 AI,并尝试优化它,以在预测图像中的元素时获得我们可以获得的最佳结果。接下来,我们将找到一种方法,用 Docker 将我们的 AI 部署到生产中。最后,我们将尝试编写一个脚本,每个月用上传的新数据自动重新训练我们的 AI。

从玛丽雅姆到熊猫

我们的网站由 Ruby on Rails 提供支持,这使得数据库结构非常容易创建、理解和维护。在我们为这个项目处理的所有数据中,我们实际上只对两个表感兴趣:“shots”表和“tags”表。这些表格有我们需要的所有数据。前者有图像 ID 及其文件名。后者将所有标签添加到一个特定的“refID”——在我们的例子中,就是我们的图像 ID。

有几种方法可以将这些表格导出为我们关心的格式。熊猫,我们将要用来准备数据来训练我们的 AI 的库,可以读取几种文件类型,如 CSV 文件。这很幸运,因为 PhpMyAdmin 能够将表格直接导出为 CSV 文件。

Don’t forget to check “Put columns names in the first row” before exporting.

PhpMyAdmin 是一种很好的转换方式,但是我们更喜欢通过命令行进行导出,将 CSV 文件直接保存在服务器上。让我们首先使用 mysqldump 将我们的两个表导出到 SQL 文件:

现在我们已经导出了表格,我们可以使用 James Mishra 制作的这个伟大的 Python 脚本将它们转换成 CSV 文件:

我们现在准备好和熊猫一起工作了!

准备和清理我们关于熊猫的数据

我们现在有了格式良好的数据。我们可以开始使用 Pandas 来探索数据,只保留我们感兴趣的表中的列,并将这两个表合并,以获得一个非常好的数据集,为训练我们的 AI 做好准备。

安装熊猫并使用它的最好方法是安装 Anaconda 。这是一个很棒的软件包,默认附带了很多用于深度学习的图书馆,如 Pandas。你可以在本页找到如何安装。

安装 Anaconda 的另一个优势是默认包含的 Jupyter。Jupyter 可以让你直接在浏览器中进行一些 Python、Pandas 和机器/深度学习编码,这非常方便,因为你可以创建和显示数据图表,以检查它显示了什么,更好地决定保留什么等等。启动 Jupyter 很容易,只需在安装后的终端中键入jupyter notebook

加载数据

开始编码吧!一旦我们启动了 Jupyter,我们就必须导入我们需要的 libairies 在本例中,是 Pandas、Numpy 和 Matplotlib。

我们现在可以打开熊猫的 CSV 文件并开始挖掘。让我们先打开“标签”表。

With .head(), we can see the first rows of our table and its structure directly in Jupyter.

这里我们可以做的第一件事是删除我们不需要的列。“标记”表包含标记的“值”、标记链接到的快照的 ID——“ref _ ID”以及添加它的用户。当您通过 Ruby on Rails 的生成器创建新表时,它们会自动生成列“created_at”和“updated_at”。

让我们只保留“id”、“值”和“ref_id”列:

Only keep the values we care about!

在这个项目中,我们的目标不是找到图像中每一个可能的元素,而是找出最常见的元素,或者更准确地说,是网站上最常用的标签。通过熊猫和.value_counts()函数,我们可以很简单地发现:

Some of the most-used tags on the website.

显示这里使用的前 400 个标签可能有些夸张,但是我们已经可以在第一批结果中找到一些需要清理的数据。我们可以看到,在第 5 个位置,我们有标签“真棒上传”,或者在第 13 个位置,我们有“SotD”标签。这些标签在我们的例子中没有用,因为有些标签没有描述图像上的内容。其实都和网站的系统有关。

带有“精彩上传”标签的照片意味着它是由高级用户上传的,在这种情况下,图像被自动接受,没有投票,没有选择。因此,我们不想保留这个标签,并试图在新上传的图像上建议它—它已经自动完成了。

这同样适用于“SotD”标签,意思是“每日快照”。每天,评分最高的照片都会得到奖励、提升和上传者。它没有描述快照中的任何内容,所以我们不需要它。

另一个有趣的是“情侣”标签。一对夫妇很难被认出来。可能是两个男人,两个女孩,一个男人和一个女孩等等。此外,我们如何以及何时决定应用这个标签?当人与人之间很亲近的时候。接吻?拥抱?很难看出区别。更重要的是,因为我们的网站是一个问答游戏,所以标签必须只描述图像显示的内容,这一点很重要。标签不应该泄露任何关于我们试图猜测的电影的线索。如果一个上传者——他显然已经看过这部电影——添加了“情侣”标签,这就泄露了关于这部电影的一些信息,我们不希望这样。如果我们看到两个人接吻,这并不意味着他们是一对,也不意味着他们离得很近。

去掉我们不想建议的标签

在移除标签之前,我们可以合并非常相似的标签。例如,我们有带有“电话”标签或“电话”标签的照片。既然它描述的是同一个东西,我们可以把它们合并成一个单一的“电话”:

我们还对其他标签进行了同样的处理,如“飞机”和“飞机”或“红发人”和“红发人”,之后我们会删除表格中可能出现的重复标签,以确保一切都是干净的:

对于这个项目,我们决定保留那些至少被添加了 500 次以上的标签,并排除一些如上所述的标签。Pandas 提供了一个方便的函数来检查一个列的值是否是不同值列表的一部分,并且只保留这些值。在这里,我们想要相反的。我们希望从数据集中排除一系列标签。我们可以使用.isin()函数,该函数通常只返回值与列表元素之一匹配的行。但是如果我们在函数前面加上~,它会做我们正在寻找的事情,排除一系列标签——就像一个isNOTin()函数。

这次操作之后,我们还剩下 183 个不同的标签。我们现在可以在“tags”表中只保留包含其中一个带有.isin() 函数的行:

Our “tags” table is now ready to be merged!

将“标签”表与“照片”表合并

现在我们已经清理了我们的“标签”表,只保留了最常用和最有趣的标签,我们必须使用 Pandas 来创建一个包含标签和图像数据的独特的表。我们知道“tags”表中的“ref_id”列指的是“shots”表中图像的“id”。Pandas 使得合并两个不同的表变得容易,这两个表有一个与merge函数相同的“键”。

让我们首先加载并检查“shots”表的结构:

A few columns of our “shots” table.

这里我们只关心“id”列,它指的是网站上的镜头 ID,以及存储电影快照文件名的“shot_image_id”列。是时候合并两个表了!正如我们已经知道的,我们在这两个表之间有一个公共的键,所以这很容易。让我们用熊猫来做这项工作:

Both tables have been merged into one.

合并数据后,我们将再次删除最终数据集中我们不感兴趣的所有列。但是我们也要将每个图像的所有标签重新组合到一个单元格中。例如,您可以在上面看到 id 为“2”的图像有三个不同的行,这意味着它有三个不同的标签与之相关联—“值”列中的“床”、“腿”、“文本”。

我们将把给定图像的所有标签重新分组到一个单元格中,用逗号分隔:

Our final table: an image ID and its tags.

为了清楚起见,我们还将包含标记的列重命名为“tags”,将列“ref_id”设置为 index,并将其重命名为“id”。很好,现在我们的数据集已经准备好训练我们的 AI 了!通过使用tags_grouped.shape,我们看到我们的数据集中有 243 558 张图片,至少有一个相关的标签和 183 个不同的标签。

最后要做的是将数据集导出到 CSV 文件:

下一步是什么

在我们系列的第一篇文章中,我们使用熊猫从头开始创建了我们自己的数据集。在清理它并只保留有用的数据之后,现在是时候开始考虑如何使用这个数据集来创建和训练一个能够区分电影快照中不同元素的 AI,并向用户建议这些元素作为标签。这将是我们第二篇文章的主题。敬请期待!

创建多标签分类人工智能:训练我们的人工智能[第 2 部分]

原文:https://towardsdatascience.com/create-a-multi-label-classification-ai-train-our-ai-part-2-85064466d55a?source=collection_archive---------17-----------------------

在我们的第一篇文章中,我们从头开始创建和清理了一个关于熊猫的数据集,现在我们要用我们的数据训练一个人工智能来区分电影快照中的几个元素。

Gérard Depardieu and Patrick Dewaere in “Les Valseuses” (1974).

这个项目被分成四个不同的条款:

  1. 从数据库中创建我们的数据集到熊猫

2.使用 FastAI 创建能够标记电影快照的 AI;

3.用 Docker 把我们的 AI 作为 REST API 部署到生产中;

4.每个月做一个脚本重新训练我们的 AI。

我们在哪里?

通过上一篇文章,我们成功地创建了一个数据集,它将电影快照和描述图像内容的相应标签结合在一起。

提醒一下,该数据集由 243 558 幅图像组成,带有 183 个不同的标签。这是一个简单的 CSV 文件,如下所示:

Our dataset: an image ID and its associated tags.

我们现在将使用这个数据集来创建和训练一个人工智能,它将能够检测和建议用户上传的图像元素。但是怎么做呢?我们可以选择什么库来制作这个 AI?我们去哪里找快速训练我们的 AI 所需的 CPU 和 GPU 资源?

在这个系列的第二部分中,我们首先要找到并创建一个适合这个繁重任务的环境。然后,我们将选择 FastAI ,当今最有前途的深度学习图书馆之一,来制作我们的人工智能,并希望在文章结束时,我们可以导出一个好模型,以便在我们的网站上使用它。

设置环境

为了用 FastAI 训练我们的 AI,我们需要找到可以在短时间内处理超过 25 万张图像的最佳环境。我们的网站运行在两个专用的服务器上,有很好的硬件来服务 Ruby on Rails 应用程序。但是计算机视觉需要很多资源,尤其是一个好的 GPU——而我们的服务器没有。因此,我们需要找到一个平台,能够以便宜的价格甚至免费,按需为我们提供这些资源

这是幸运的,因为有两个主要的在线平台可以以非常简单的方式提供我们正在寻找的环境。

Kaggle,一个数据科学项目的地方

Kaggle 是一个知名的社区网站,供数据科学家在深度学习挑战中竞争。参加比赛后,你会得到一个数据集,你必须创建一个人工智能,在这个数据集上给出最好的结果。你可以随意使用任何深度学习库。

Kaggle is famous for hosting competitions where you can win thousand of dollars.

但是说 Kaggle 只是关于竞争是不正确的。事实上,Kaggle 还向数据科学家免费提供数百个数据集,学习该领域最常用的工具的课程,更重要的是,免费提供一个拥有丰富资源的现成环境

然后,你可以直接在其他数据科学家的网站上参加比赛,与他们展开较量。他们给你你需要的一切:一个类似 Jupyter 的界面,一些磁盘空间,一个好的 CPU 和一个 GPU。只需点击几下,你就可以开始训练一个人工智能!

FastAI,我们将在这个项目中使用的库,也可以在 Kaggle 上获得。实际上,这个项目很大程度上受到了这个内核的启发,你可以在那里找到 FastAI 的创造者杰瑞米·霍华德——用他的图书馆参加著名的星球:从太空了解亚马逊比赛。他只用了几行代码就获得了极好的结果。

你可以在他们的官网上找到关于如何在 Kaggle 上开始使用 FastAI 的不错的教程。

虽然 Kaggle 似乎是我们项目的完美之地,但它也有一些限制。我认为 Kaggle 是一个不错的网站,在那里你可以玩和尝试不同种类的东西。但对于严肃的深度学习项目,你将不得不转向一个真正的供应商,给你更多的灵活性,更多的资源。

谷歌云平台

由于我们希望能够导出我们的模型,并以自动方式每月重新训练我们的 AI,我们需要为我们的任务找到一个更好的主机,在那里我们可以根据我们的需要深度定制我们的环境。谷歌云平台似乎是解决这一问题的最佳场所。它以合理的价格提供许多服务。注册时你甚至可以免费获得一年 300 美元的积分。

The list of services GCP provides is ridiculously long.

与 GCP 合作肯定需要更多的时间和工作。您基本上必须创建一个虚拟机,并安装项目所需的一切。主要的优点是你可以自由地为你的项目创建任何类型的虚拟机。您可以建立一个拥有大量资源的虚拟机,甚至可以在世界范围内选择虚拟机所在的地区。

幸运的是,网上有很多教程可以帮助你开始学习 GCP。FastAI 有一个关于如何开始在谷歌云平台上使用他们的图书馆的专用教程。按照他们的指示,你应该有一个环境,里面有开始训练人工智能所需的所有工具。

当我们必须每月重新训练我们的模型时,将我们的环境放在云上肯定会使事情变得更容易。GCP 为他们提供的几乎所有服务提供 API,包括创建、启动和停止虚拟机。这是一个非常重要的特性,可以降低重新训练的难度。

用 FastAI 创建一个 AI

我们创建了一个运行在谷歌云平台上的虚拟机,配有一个很棒的 GPU——在我们的例子中是一个 NVIDIA Tesla P100,配有 16gb 的 VRAM。就像我们在以前的文章中用熊猫创建数据集一样,我们将使用 Jupyter 与 FastAI 进行交互。但首先,让我们谈谈这个令人敬畏的图书馆。

FastAI 库提供了一个高级 API,能够为许多不同的应用程序创建深度学习模型,包括文本生成、文本分析、图像分类和图像分割。FastAI 对于 Pytorch 就像 Keras 对于 Tensorflow 一样:一组更直观的抽象,使得用几行代码开发深度学习模型变得很容易。

FastAI 会为您处理许多参数或超参数,默认情况下会产生良好的性能——当然,一切都是可定制的。

但是 FastAI 不仅仅是一个图书馆,它还是一门很棒的进入深度学习的课程。该课程分为两部分,可在的网站上免费获得。它非常适合新手,因为它可以让你在没有大量领域知识的情况下快速玩深度学习模型。这个项目完全基于这个课程和 FastAI,所以感谢他们的出色工作!

现在我们开始编码吧!像往常一样,我们首先必须通过 Jupyter 导入我们需要的所有图书馆:

预处理数据集

我们要做的第一件事是预处理我们的数据集。预处理是非常重要的一步,尤其是在处理图像的时候。为了获得更好的性能,甚至为了让神经网络理解我们在喂它什么,我们必须将图像标准化并调整它们的大小。

在我们的项目中,我们正在处理来自电影的快照。电影可以有许多不同的长宽比。想想老电影:大多数都是用正方形格式制作的——4/3。但如今,它都是关于宽屏幕的——16/9——甚至更宽的宽高比,如 2.35 或 2.39。

The most-used aspect ratios in the cinema industry.

因此,为了使我们的人工智能更有效,预处理步骤是至关重要的:我们需要确保我们所有的数据在训练部分都具有相同的格式。为此,我们首先加载包含数据集的 CSV 文件:

通过这两行代码,FastAI 基本上读取了我们的数据集文件,并理解了我们的图像存储在一个名为“images”的文件夹中,后缀为“”。jpg”。ImageList是一个内置功能,让你轻松做计算机视觉。你可以在他们伟大的文档部分找到更多关于这个函数或者整个库的信息。

变量“data”现在包含了与数据集相关的所有内容。我们可以开始预处理了:

大部分的评论不言自明,但我会详细一点。我们要做的第一件事是使用split_by_rand_pct方法将数据集分成两部分:

  1. 一个训练集:它将包含用于训练我们的 AI 的图像和标签。我们将原始数据集的 90%用于训练集。
  2. ****验证集:AI 没有用来学习的图像和标签。这些图像仅由模型看到,以验证它是否正确学习以及性能是否变得更好。就此而言,我们使用原始数据集的 10%,因此值为“0.1”。

A visualisation of the splits. Test set is optional.

其次,我们用label_from_df方法告诉 FastAI 在哪里寻找每个图像的标签。在我们的例子中,标签位于 CSV 文件的第二列(不包括索引列),由逗号分隔。

接下来是有趣的部分,预处理。通过transform 方法——更具体地说是get_transforms()函数——我们要求 FastAI 对我们的图像执行一些工作,以便创建“更多”数据。这被称为数据扩充。当您的训练集中没有足够的数据时,这尤其有用。默认情况下,FastAI 将对其处理的训练图像应用一些技术,最常见的是仿射变换,如水平或垂直翻转、旋转等。还有非仿射变换,如调整大小,裁剪,亮度变化等。它将在每次迭代中基于单个图像创建新的图像变体。

Examples of data augmentation techniques: rotation, flip, brightness.

我们正在做的下一个转换是调整图像的大小,正如你所看到的,这对我们来说很重要。我们决定选择 224 像素乘 224 像素的正方形大小,因为它对于计算机视觉来说似乎是一个很好的值,特别是当我们在最后一行使用 ImageNet 标准化图像时。

我们决定选择数字“3”。它相当于“挤压”方法。其他可用的方法有“裁剪”、“填充”或根本不调整大小。

The difference methods available to resize our images.

我们选择了“挤压”方法,因为经过几次测试后,我们发现这是最适合我们的情况的方法,因为我们想在调整大小后保留原始图像的所有信息,而不管它们的原始大小和纵横比。每次都给了我们最好的结果。

最后,我们使用 ImageNet 统计来标准化我们的图像。标准化涉及使用著名的 ImageNet 数据集的平均值和标准差。使用平均值和标准差是一个非常标准的做法。因为它们是用一百万张图像计算出来的,所以统计数据相当稳定。这会使训练更快。

定义我们的神经网络结构

一旦我们完成了预处理,是时候创建我们的神经网络架构并开始训练我们的 AI 了。我们将在这个项目中使用迁移学习。迁移学习是一种技术,其中在一个任务上训练的模型被重新用于第二个相关的任务——在我们的例子中,检测电影快照中的元素。这种技术可以非常有用,例如,帮助那些没有知识从零开始创建他们的深度神经网络的人,无论是资源还是时间。或者只是为了避免完全重新编码,而我们可以使用一个现成的、适合我们的数据类型的类似模型。

我们将使用最近为图像分类创建的最有趣的模型之一,名为" Resnet " —其他可用的模型在这里列出。Resnet 是一种残差神经网络,有几种版本,深度可达 152 层——“resnet 152”。它在图像识别方面提供了令人难以置信的结果。

通过迁移学习,我们将获得这个已经训练好的模型的预训练权重,该模型已经在属于 1000 个不同类别的数百万张图像上进行训练,并使用这些已经学习的特征来预测新的类别,即我们的标签。这样做的主要优点是,我们不需要非常大的训练数据集来快速获得好的结果。

让我们以“Resnet152”作为预训练模型来制作我们的架构,创建一个广泛应用于计算机视觉的卷积神经网络。CNN 是一种深度学习算法,它可以将图像作为输入,为图像中的各个方面或对象分配重要性,并能够区分它们。非常适合我们!

Create our neural network structure : CNN, Resnet152 and two metrics: accuracy and FBeta.

我们定义了两个函数作为神经网络的度量,以帮助我们评估它是否表现良好。第一个是精度阈值。为什么是门槛?简单地说,因为在这里,我们不是在制作一个多类分类器,我们希望我们的人工智能只为每张图像预测一个类——概率最高的一个。我们正在制作一个多标签分类器,这意味着每幅图像可以有不同的类别——或者为零。

在我们的例子中,我们有 183 个不同的类。所以我们对每张图片的每一类都有一个概率。但是,我们不仅仅要挑选其中的一个,我们要从这 183 个班级中挑选出 n 。基本上,我们将每个概率与某个阈值进行比较。然后我们会说,任何高于这个阈值的东西,都意味着图像中确实有这个元素。杰瑞米·霍华德使用 0.2 作为他的竞争门槛,因为它似乎普遍工作得很好。我们决定听从他的建议。因此,给定图像的概率高于 0.2 的每个类别将被视为该图像的一部分。

第二个度量被称为“FBeta”。这是一个众所周知的指标,在数据科学家行业或 Kaggle 主办的比赛中广泛使用。当你有一个分类器,你会有一些假阳性和假阴性。你如何权衡这两件事来创造一个单一的数字,并评估性能?有很多不同的方法可以做到这一点,而“FBeta”是一个很好的方法,可以将它们组合成一个单一的数字。它考虑了精确度和召回率。你可以在这里阅读更多关于“T4”的信息。

Both precision and recall are used to compute FBeta.

The FBeta formula.

我们开始训练吧

我们现在已经有了一个现成的带有迁移学习的卷积神经网络,Resnet152 和两个指标。是时候训练我们的数据了!让我们从 10 个时期开始——一个时期意味着我们所有图像的一次迭代。

The results after 10 epochs.

没有那么多的工作,我们已经得到了相当好的结果!精确度看起来不错,FBeta 一直在上升。对你们中的一些人来说,Fbeta 分数可能看起来很低,但请记住,我们正在研究超过 183 个不同的类,我们并不试图创造一个完美的人工智能,它可以绝对预测图像包含的每个元素。我们正在努力使人工智能能够建议网站上最常用的标签,如“黑白”、“动画”、“男人”、“女人”等。

尽管如此,仍有改进的余地。我们可以尝试调整我们神经网络的学习速率,看看它是否能导致更好的结果。学习率是深度学习中一个非常重要的超参数。如果选择得不好,神经网络的表现就不会很好。默认情况下,FastAI 使用单周期策略,这意味着学习率将在每次迭代中先增加,然后降低。

The one-cycle policy in pictures. Source

单周期策略允许非常快速地训练神经网络,这意味着它将快速收敛到低损失值。但要让它发挥作用,我们需要找到最佳学习率,让单周期政策真正发挥作用。FastAI 提供了寻找最佳学习率的函数:

The loss seems to explode with a large learning rate.

我们可以从上面的图表中看到,大的学习率似乎没有帮助。其实学习率越大,损失越大。我们不希望这样。我们可以限制我们的学习速率来避免这种情况,并使用这个更新的参数重新开始训练。此外,我们不仅要重新开始训练,只有我们的神经网络的最后一层被更新。相反,我们这次将更新所有的权重,包括使用上面使用的函数unfreeze()的 Resnet 的 152 层权重。

We define a maximum learning rate to avoid having a loss that goes high.

Our results after 10 another epochs.

列车损失似乎变得更低,而 FBeta 似乎也变得更高。一切看起来棒极了!我们可以尝试另一种学习速率,训练更多一点,希望提高我们模型的性能,但我们已经可以看到我们最有可能处于最佳能力,介于欠拟合和过拟合之间。

The figure shows the optimal capacity that falls between underfitting and overfitting. When reached, we can stop the training. It’s called “early stopping”. Source: https://arxiv.org/pdf/1803.09820.pdf

事实上,在第四个时期之后,我们的验证损失开始高于训练损失。但更重要的是,它似乎没有减少,而在此期间,培训损失不断减少。我们甚至可以看到,验证损失在某个时期开始增加。这无疑是一个信号,表明我们可能已经达到了模型的最佳容量,我们应该停止这里的训练,否则我们可能会开始过度适应。

当您在相同的数据上训练过多的模型时,就会发生过度拟合。当需要在它从未见过的数据上测试你的模型时,在它的舒适区之外,模型开始表现不佳,因为它只习惯于识别训练数据,而不是其他。它不能很好地概括新的、看不见的数据。该模型学习特定于训练数据的模式,这些模式在其他数据中是不相关的。

对测试图像的预测

我们最好在这里停止训练,到此为止。我们可以先用save()函数保存我们的模型,然后导出我们的模型,其中包含所有优化的权重和偏差:

Save the model just in case we want to start again from this point and export the pre-trained model to use on production.

如果我们的人工智能在电影快照的建议标签上正确执行,我们可以快速测试各种数量的图像。我们将一百张人工智能从未见过的电影剧照放在一个文件夹中,并创建了一个快速的 Python 脚本来显示每张图像的预测标签及其各自的概率:

A few examples of the testing set with the predicted tags and their respective probability.

好像很管用!当然,它没有列出所有图像中可能显示的元素,但这从来不是我们的目标。我们想创造一个人工智能,当用户上传电影快照时,它可以向用户建议常用标签,我认为它工作得很好。几乎三分之二的时候,人工智能会提示图像中所有可能的元素。这并不意味着其余的时间它没有暗示任何东西,只是没有所有的元素——可能只有一两个标签。

一如既往,还有改进的空间,但对于第一款车型,我们对结果很满意。重要的是要记住,根据我们的人工智能,只有出现概率超过 20%的标签才会显示在这里。我们希望建议我们确信图像中确实存在的标签。

下一步是什么?

现在我们已经做了一个能够检测电影快照中元素的 AI,并在简单测试后导出了性能良好的模型,我们如何将这个单个文件转化为我们网站上的服务?我们如何在我们的服务器上实现人工智能,并与当前的 Ruby on Rails 后端交互?这将是我们下一篇文章的主题,我们将使用 Docker 在 Python 中创建一个 REST API,以允许我们的网站向 AI 发送请求,AI 将返回给定图像中存在的标签。敬请期待!

创建多页 Dash 应用程序

原文:https://towardsdatascience.com/create-a-multipage-dash-application-eceac464de91?source=collection_archive---------3-----------------------

制作仪表板是向编码人员和非编码人员传达数据科学项目价值的好方法!

对于我们这些从事数据科学工作的人来说,我们的数据技能往往伴随着前端开发技能的缺乏。由 Plotly 构建的 Dash 库提供了简单的 boiler plate 代码,用于开发 Python 中的交互式 web 应用程序。

寻找灵感,查看 仪表盘图库

在本文中,我将介绍构建一个基本的多页面 dash 应用程序的步骤。该项目的代码和数据可以在 this Github repo 中找到。

为什么是多页应用?

学习构建一个多页面应用程序是非常有用的,原因有很多。以下是一些例子:

  1. 允许为方法或背景信息添加单独的页面。
  2. 将一个复杂的数据项目分解到多个页面中可以带来流畅的用户体验。
  3. 可以用来建立一个在线投资组合!
  4. 理解工作流可以作为进入 web 开发世界的一小步。

应用程序结构:

项目目录:

index.py 最终是运行整个应用程序的文件。可以把它看作是项目的目录。每个页面将在单独的文件中构建,然后导入到 index.py 中。此工作流用于保持文件的简洁和可读性,并保持项目结构的组织性和灵活性。

D.R.Y 代码

该工作流有助于避免重复代码。例如,这个应用程序的每个页面都需要一个导航栏。组件只是被导入,而不是在每个文件中编写相同的代码。

创建目录和环境

首先,我们创建一个文件夹来保存我们所有的项目文件:

注意:我个人更喜欢使用 Visual Studio 代码或 Pycharm,但是为了使本演练易于理解,我们将坚持在终端中构建该应用程序。

在终端中:

mkdir dash_app
cd dash_app

接下来我们要做的是创建一个虚拟环境来构建应用程序。不,这在技术上不是一个要求,但是它消除了产生依赖错误的风险,并且通常是构建 web 应用程序时的最佳实践。

pip install virtualenv
virtualenv venv
source venv/bin/activate

(venv)现在应该出现在终端中的$符号之前。这意味着您现在正在使用您的虚拟环境。

随着虚拟环境的激活,我们需要安装我们将用于这个项目的库。

pip install pandas
pip install dash
pip install dash-bootstrap-components### These are dependences and are likely already installedpip install dash-core-components
pip install dash-html-components
pip install plotly

构建导航栏:

注意:导航栏和主页其余部分的代码直接从 dash bootstrap components 网站复制而来。

Dash bootstrap 组件将网页划分成网格,是组织 web 应用布局的有用工具。有关定位应用程序组件(网页上出现的任何内容)的更多信息,请点击此链接并查看 dbc 的使用。Row 和 dbc.Column

在终端中打开 vim 文本编辑器。

vim navbar.py
s

s 启用了编辑模式,这样我们就可以开始编写代码了!

在 navbar.py 中:

import dash_bootstrap_components as dbcdef Navbar():
     navbar = dbc.NavbarSimple(
           children=[
              dbc.NavItem(dbc.NavLink("Time-Series", href="/time-series")),
              dbc.DropdownMenu(
                 nav=True,
                 in_navbar=True,
                 label="Menu",
                 children=[
                    dbc.DropdownMenuItem("Entry 1"),
                    dbc.DropdownMenuItem("Entry 2"),
                    dbc.DropdownMenuItem(divider=True),
                    dbc.DropdownMenuItem("Entry 3"),
                          ],
                      ),
                    ],
          brand="Home",
          brand_href="/home",
          sticky="top",
        )return navbar

在上面的第六行中,href 参数告诉应用程序将哪个页面返回给用户(如果在开头放置 https://就可以导航到外部网站!)

在这行代码中,我们将 href 设置为“/time-series”。这将是我们的时间序列图的链接名称。

保存并退出文件。

Esc
:wq [ENTER]

主页:

vim homepage.py
## s to enable edit mode

在 homepage.py 中,我们首先需要导入所需的库。

import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html

我们还想从 navbar.py 导入 navbar 函数,并创建一个 Navbar 对象。

from navbar import Navbarnav = Navbar()

构建主页主体:

该页面的布局将是 2 个网格空间的网格。1 行,2 列。

第一栏:

  • 页眉
  • 段落
  • 纽扣

第二栏:

  • 页眉
  • 图表

额外加分:把图形改成图像。

body = dbc.Container(
    [
       dbc.Row(
           [
               dbc.Col(
                  [
                     html.H2("Heading"),
                     html.P(
                         """\
Donec id elit non mi porta gravida at eget metus.Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentumnibh, ut fermentum massa justo sit amet risus. Etiam porta semmalesuada magna mollis euismod. Donec sed odio dui. Donec id elit nonmi porta gravida at eget metus. Fusce dapibus, tellus ac cursuscommodo, tortor mauris condimentum nibh, ut fermentum massa justo sitamet risus. Etiam porta sem malesuada magna mollis euismod. Donec sedodio dui."""
                           ),
                           dbc.Button("View details", color="secondary"),
                   ],
                  md=4,
               ),
              dbc.Col(
                 [
                     html.H2("Graph"),
                     dcc.Graph(
                         figure={"data": [{"x": [1, 2, 3], "y": [1, 4, 9]}]}
                            ),
                        ]
                     ),
                ]
            )
       ],
className="mt-4",
)

下一位代码重要

因为我们正在构建一个多页面应用程序,我们需要能够将布局导入到其他文件中。为此,我们将构建一个主页函数,返回页面的整个布局。

注意:布局必须始终是一个破折号 html 组件。标准是将布局包装在一个 div 中。

def Homepage():
    layout = html.Div([
    nav,
    body
    ])return layout

在继续之前,让我们确保应用程序正常工作。为此,请将以下代码添加到页面底部。

app = dash.Dash(__name__, external_stylesheets = [dbc.themes.UNITED])app.layout = Homepage()if __name__ == "__main__":
    app.run_server()

保存并退出 vim。

Esc
:wq [ENTER]

太好了!现在让我们运行应用程序,以确保代码正常工作!

python homepage.py

如果应用程序失败,将打印出一条错误消息。习惯这个,很大程度上是应用构建的工作流程。对我来说,90%的时间是一个简单的语法错误。阅读错误信息并调试问题。(如果我的代码有问题,请在评论中告诉我!)

如果应用程序运行,将打印出几行。重要的一行应该是这样的:

Running on [http://127.0.0.1:8050/](http://127.0.0.1:8050/)

复制 http url 并将其粘贴到互联网浏览器中。

转眼间。一个应用诞生了!

在你欣赏你的作品一段时间后,关闭网络应用。

[CTR] C
##### It will look like this in terminal: ^C

应用

现在让我们建立我们的交互式图形页面!

首先,我们创建一个 app.py 文件。

vim app.py
## s to enable edit mode

接下来,导入应用程序的库、我们的 Navbar 函数以及伊利诺伊州的人口数据。

### Data
import pandas as pd
import pickle### Graphing
import plotly.graph_objects as go### Dash
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Output, Input ## Navbar
from navbar import Navbardf = pd.read_csv('[https://gist.githubusercontent.com/joelsewhere/f75da35d9e0c7ed71e5a93c10c52358d/raw/d8534e2f25495cc1de3cd604f952e8cbc0cc3d96/population_il_cities.csv](https://gist.githubusercontent.com/joelsewhere/f75da35d9e0c7ed71e5a93c10c52358d/raw/d8534e2f25495cc1de3cd604f952e8cbc0cc3d96/population_il_cities.csv)')df.set_index(df.iloc[:,0], drop = True, inplace = True)df = df.iloc[:,1:]

最后两行代码只是将日期列设置为索引,然后从数据集中删除该列的副本。

好,现在让我们建立一些组件!

导航条:

nav = Navbar()

标题:

我们将使用标题向用户提供一些说明。

header = html.H3(
    'Select the name of an Illinois city to see its population!'
)

下拉列表:

对于这个应用程序,我们将建立一个下拉菜单。在后台,下拉菜单被格式化为字典列表。这本词典有两个关键词。“标签”和“价值”。label =用户将在下拉菜单中看到的内容,value =返回给应用程序以查询数据的内容。

因为每一列都是伊利诺伊州的一个城市,所以我们将使用这个数据集的列名进行查询。

每一列都被格式化为“伊利诺伊州的城市”。让每个标签都包含“伊利诺伊州”有点大材小用,因为我们只寻找伊利诺伊州的城市。在下面的代码中,我们将删除每个词典标签的这部分额外文本:

options = [{'label':x.replace(', Illinois', ''), 'value': x} for x in df.columns]

现在,我们将字典列表直接插入到一个下拉对象中

重要: 任何交互的组件都必须有一个 id 名。你很快就会明白为什么了。此外,组件不能共享 id 名称。如果一个 id 被多次使用,将会抛出一个错误,应用程序将会中断。

dcc 中的参数。下拉功能有。

  • id: 组件的唯一标识符。格式化为字符串。
  • 选项:带有“标签”和“值”键的字典列表
  • value: 应用程序加载时下拉菜单设置的默认值。(我从数据集中随机选择了一个城市作为默认城市。)
dropdown = html.Div(dcc.Dropdown(
    id = 'pop_dropdown',
    options = options,
    value = 'Abingdon city, Illinois'
))

下拉完成!

输出空间:

这是我们输出图表的地方。

output = html.Div(id = 'output',
                children = [],
                )

这是所有的组件!

现在,就像我们制作主页一样,我们将制作一个名为“App”的布局功能。

def App():
    layout = html.Div([
        nav,
        header,
        dropdown,
        output
    ])return layout

好的,现在让我们制作图表。我们将创建一个 build_graph 函数,该函数将从下拉菜单中接受一个城市,并返回一个显示该城市人口趋势的图表。

def build_graph(city):data = [go.Scatter(x = df.index,
                        y = df[city],
                        marker = {'color': 'orange'})]graph = dcc.Graph(
           figure = {
               'data': data,'layout': go.Layout(
                    title = '{} Population Change'.format(city),
                    yaxis = {'title': 'Population'},
                    hovermode = 'closest'
                                  )
                       }
             )return graph

好吧!这个文件到此为止。确保保存并退出。

Esc
:wq [ENTER]

索引

现在,让我们用一个 index.py 文件将它们集合起来!

vim index.py
## s to enable edit mode

导入所有的库和函数。

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbcfrom app import App, build_graphfrom homepage import Homepage

接下来,我们声明一个 dash app 对象。为了美观,我们将通过传入 dbc.themes 外部样式表来使用主题。主题的名字总是大写的,并且包含在一个列表中。随意阅读可用的主题这里。

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.UNITED])

重要: 为了让我们的时间序列图具有交互性,我们要为下拉菜单和输出空间创建一个回调函数。但是,dash 不允许回调布局中不存在的组件。因为主页布局中没有下拉菜单或输出空间,所以我们必须更改应用程序的配置。

app.config.suppress_callback_exceptions = True

接下来,我们创建一个 dcc。Location 对象,在应用程序中不可见,但监视 url。这将告诉我们的应用程序根据用户点击的链接返回一个页面。

现在,创建一个内容空间,我们可以在这里返回主页或时间序列页面。

app.layout = html.Div([
    dcc.Location(id = 'url', refresh = False),
    html.Div(id = 'page-content')
])

复试

好吧!现在让我们使我们的应用程序具有交互性,这样当用户点击某些东西时,事情就会发生。

我们需要两次复试。一个用于返回应用程序的不同页面,另一个用于更新图表。

为此,我们声明@app.callback

在 app.callback 中,我们传递在文件顶部导入的输出函数。输出的参数是:

  1. 正在更新的组件的 id。
  2. 正在更新的组件的参数。(90%的情况下,您将更新一个 div,并且该参数将被设置为“children”)

注意:一个回调可以更新多个输出空间。只需将所有输出函数包装在一个列表中。

接下来,我们将输入函数传递给 app.callback。

    • 输入总是包含在列表中。即使只有一个输入*
  • 输入参数与输出参数相同

在这种情况下,我们输出到我们的“页面内容”div,并从我们的“url”位置输入。

[@app](http://twitter.com/app).callback(Output('page-content', 'children'),
            [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/time-series':
        return App()else:
        return Homepage()

现在我们为我们的时序图创建回调。

因为我们做了一个 build_graph 函数,所以这个回调超级简单。

[@app](http://twitter.com/app).callback(
    Output('output', 'children'),
    [Input('pop_dropdown', 'value')]
)
def update_graph(city):graph = build_graph(city)return graph

最后,让应用程序运行。

if __name__ == '__main__':
    app.run_server(debug=True)

注意,我已经设置了 debug=True。在部署应用程序时,您应该将其设置为 false,但我们正处于开发阶段,将 debug 设置为 True 会使应用程序的调试变得更加容易。

保存并退出:

Esc
:wq [ENTER]

并运行应用程序!

python index.py

结论

这是一个简单的例子,但是这些基础可以用来构建更加复杂和强大的应用程序!

发表评论,如果你有任何问题,请告诉我。

附:退出您的虚拟环境。

deactivate

在 OpenCV 和 Flask 中创建一个简单的图片搜索引擎

原文:https://towardsdatascience.com/create-a-simple-image-search-engine-in-opencv-and-flask-79384b78ee25?source=collection_archive---------26-----------------------

了解如何使用 OpenCV 提取图像中像素的颜色,然后通过 CSS 十六进制颜色代码搜索图像

我最近开始玩 OpenCV ,一个用于图像处理的开源计算机视觉库。幸运的是有 Python 绑定可用。更幸运的是,像阿德里安这样的人已经做了一个伟大的服务,他们发布了关于类似主题的书和博客。

那么这到底是怎么回事呢?嗯,这很简单,或者我说,是最简单的使用 OpenCV 加载图像并找到与该图像相关的颜色,并在基于 Flask 的 web 应用程序中显示见解的演示。这不是一个国家的艺术应用程序,也不是目前我打算做的方式,但嘿,这只是一个开始,而不是结束。除了把我对像素的基础学习转化成一个 产品 (Google!当心!!)

我不会深入 OpenCV 和 Flask 的细节,我将介绍应用程序实际上在做什么。

该应用程序由两部分组成:一个基于网络的应用程序,用于存储来自网络的图像并显示处理后的图像及其主色;一个命令行脚本,用于运行下载的图像并提取颜色代码。网页图像如下所示:

你通过颜色代码搜索图片,它会返回如下结果:

单个图像的视图看起来像:

让我们讨论系统的核心部分,也就是执行主要工作的命令行脚本。

def process_image(image_name):
    color_count = {}
    print('Processing the image {}'.format(image_name))
    path = 'website/static/uploaded_images/' + image_nameimage = cv2.imread(path)for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            (b, g, r) = image[i, j]
            h_value = rgb2hex(r, g, b)if h_value in color_count:
                color_count[h_value] += 1
            else:
                color_count[h_value] = 1
    return color_count

导入计算机视觉后,我们通过调用cv2.imread()从磁盘读取图像。数据以numpy数组的形式提供,因此使用它的shape方法来查找宽度、高度和通道等细节。顺便说一下,OpenCV 以 BGR 格式存储图像数据,而不是 RGB 颜色空间。一旦数据被检索为 BGR 格式,我们就使用一个定制的rgb2hex方法将 RGB 转换为十六进制颜色。该函数然后返回一个字典列表,其中包含十六进制的颜色代码及其频率,我们将使用它来查找图像中颜色的百分比。我还做了一个演示,可以在 youtube 视频中看到。

结论

这是 OpenCV 中的一个基本图像处理教程。它不是一个成熟的产品,因为它不能告诉你图片中独特的颜色。它只是告诉你基于像素颜色的信息,而不是基于 ML 算法执行颜色分割和聚类。

希望在接下来的几周内,我会就更高级的话题进一步讨论 OpenCV。

像往常一样,这些代码可以在 Github 上找到。

本帖原载 此处

如何在 R 中生成单词云

原文:https://towardsdatascience.com/create-a-word-cloud-with-r-bde3e7422e8a?source=collection_archive---------1-----------------------

如何以及何时使用它们的简单步骤

创建单词云的 4 个主要步骤

在接下来的部分中,我将向你展示如果你想用 r 生成一个单词云,需要遵循的 4 个简单步骤。

步骤 1:检索数据并上传包

要生成文字云,你需要下载 R 版本的文字云 包以及颜色的 RcolorBrewer 包。注意还有一个 wordcloud2 包,设计略有不同,应用也很好玩。我将向您展示如何使用这两个包。

install.packages("wordcloud")
library(wordcloud)install.packages("RColorBrewer")
library(RColorBrewer)install.packages("wordcloud2)
library(wordcloud2)

最常见的是,词云被用来分析 twitter 数据或文本语料库。如果你正在分析 twitter 数据,只需通过使用 rtweet 包上传你的数据(参见这篇文章了解更多信息)。如果你正在处理一篇演讲、一篇文章或任何其他类型的文本,确保将你的文本数据作为一个语料库加载。一个有用的方法是使用 tm 包。

install.packages("tm")
library(tm)#Create a vector containing only the text
text <- data$text# Create a corpus  
docs <- Corpus(VectorSource(text))

步骤 2:清理文本数据

在生成你的单词云之前,清理是必不可少的一步。事实上,为了让您的分析带来有用的见解,您可能需要从文本中删除特殊字符、数字或标点符号。此外,您应该删除常见的停用词,以产生有意义的结果,并避免最常见的频繁出现的词,如“I”或“the”出现在词云中。

如果你正在使用 tweets ,使用下面一行代码来清理你的文本。

gsub("https\\S*", "", tweets$text) 
gsub("@\\S*", "", tweets$text) 
gsub("amp", "", tweets$text) 
gsub("[\r\n]", "", tweets$text)
gsub("[[:punct:]]", "", data$text)

如果你正在处理一个文集,有几个软件包可以用来清理你的文本。下面几行代码向您展示了如何使用 tm 包来做到这一点。

docs <- docs %>%
  tm_map(removeNumbers) %>%
  tm_map(removePunctuation) %>%
  tm_map(stripWhitespace)
docs <- tm_map(docs, content_transformer(tolower))
docs <- tm_map(docs, removeWords, stopwords("english"))

步骤 3:创建文档术语矩阵

下一步你要做的是建立一个数据框架,在第一列中包含每个单词,在第二列中包含它们的频率。

这可以通过使用来自 tm 包的 TermDocumentMatrix 函数创建一个文档术语矩阵来完成。

dtm <- TermDocumentMatrix(docs) 
matrix <- as.matrix(dtm) 
words <- sort(rowSums(matrix),decreasing=TRUE) 
df <- data.frame(word = names(words),freq=words)

或者,特别是如果你使用 tweets,你可以使用 tidytext 包。

tweets_words <-  tweets %>%
 select(text) %>%
 unnest_tokens(word, text)words <- tweets_words %>% count(word, sort=TRUE)

第四步:生成单词云

字云 包是生成字云最经典的方式。下面一行代码向您展示了如何正确设置参数。例如,我选择研究美国总统在联合国大会上的演讲。

set.seed(1234) # for reproducibility wordcloud(words = df$word, freq = df$freq, min.freq = 1,           max.words=200, random.order=FALSE, rot.per=0.35,            colors=brewer.pal(8, "Dark2"))

可能发生的情况是,您的单词云裁剪了某些单词,或者干脆不显示它们。如果发生这种情况,请确保添加参数 scale=c(3.5,0.25) 并摆弄数字,使单词 cloud 合适。

词云的另一个常见错误是显示了太多不常用的词。如果是这种情况,请确保调整最小频率参数 (min.freq=…) ,以便使您的词云更有意义。

这个 wordcloud2 包使用起来更有趣,允许我们做一些更高级的可视化。例如,你可以选择你的文字云以特定的形状甚至字母出现(参见这个小插图获取有用的教程)。作为一个例子,我使用了相同的联合国演讲语料库,并生成了如下所示的两个单词云。很酷,对吧?

wordcloud2(data=df, size=1.6, color='random-dark')

wordcloud2(data=df, size = 0.7, shape = 'pentagon')

你应该使用单词云的 3 个理由

  • 文字云是杀手可视化工具。它们以简单明了的格式呈现文本数据,就像云一样,其中单词的大小取决于它们各自的频率。因此,它们在视觉上看起来很好,也很容易理解。
  • 字云是很棒的沟通工具。对于任何希望交流基于文本数据的基本见解的人来说,无论是分析演讲、捕捉社交媒体上的对话还是报告客户评论,它们都非常方便。
  • 字云见解深刻。视觉上引人入胜,单词云让我们能够快速得出一些见解,允许在解释它们时有一定的灵活性。它们的视觉形式刺激我们思考,并根据我们希望分析的内容得出最佳见解。

那么,什么时候该用词云呢?

是的,单词云是有洞察力的,伟大的交流和可视化工具。尽管如此,它们也有自己的限制,理解这一点是知道什么时候使用它们,什么时候不使用它们的关键。

单词云本质上是一种描述工具。因此,它们应仅用于捕捉基本定性洞察。视觉上吸引人,它们是开始对话、演示或分析的绝佳工具。然而,他们的分析仅限于洞察力,根本不具备更广泛的统计分析的能力。

我经常写关于数据科学和自然语言处理的文章。关注我的TwitterMedium查看更多类似的文章或简单地更新下一篇文章。 感谢阅读!

使用 Flask 和 Heroku 创建一个 API 来部署机器学习模型

原文:https://towardsdatascience.com/create-an-api-to-deploy-machine-learning-models-using-flask-and-heroku-67a011800c50?source=collection_archive---------4-----------------------

Photo by Ian Simmonds on Unsplash

机器学习模型是基于可用数据进行预测的强大工具。为了使这些模型有用,需要部署它们,以便其他人可以通过 API(应用程序编程接口)轻松访问它们来进行预测。这可以使用 Flask 和 Heroku 来完成——Flask 是一个微型 web 框架,不需要特定的工具或库来创建 web 应用程序,Heroku 是一个可以托管 web 应用程序的云平台。

要使用 Flask 和 Heroku 成功部署机器学习模型,您需要以下文件:model.pkl、app.py、requirements.txt 和一个 Procfile。本文将介绍如何创建这些所需的文件,并最终在 Heroku 上部署应用程序。该员额的主要部分如下:

  • 创建 GitHub 存储库(可选)
  • 使用大量数据创建和筛选模型
  • 创建烧瓶应用程序
  • 本地测试烧瓶应用程序(可选)
  • 部署到 Heroku
  • 测试工作应用程序

根据您在流程中所处的阶段,您可以随意跳过其中任何一项!

创建 Github 存储库(可选)

为了便于以后在 Heroku 上部署,您需要为这个项目创建一个 github 存储库,并克隆它以供本地使用。要创建新的存储库,请单击右上角的个人资料图标,单击“存储库”,然后单击“新建”。为您的存储库命名,使用自述文件初始化存储库,并添加一个许可证,如下例所示:

要克隆存储库,请转到存储库页面,单击“克隆或下载”并复制链接。在终端中,转到要克隆存储库的文件夹,并键入命令:

git clone link_to_repository

运行此命令会将存储库克隆到您的本地计算机上,您可以检查以确保文件夹是在正确的位置创建的。既然回购已经设置好了,我们就可以创建机器学习模型并对其进行处理了。

创建和筛选机器学习模型

首先,让我们使用 Titanic 数据集创建一个简单的逻辑回归模型。根据阶级、年龄、兄弟姐妹数量和票价等信息,该模型将预测是否有人在泰坦尼克号上幸存。如果你想了解我的例子,你可以在这里找到数据集的 csv 文件。在您的工作目录中创建一个 Jupyter 笔记本,并通过运行以下代码创建模型:

import pandas as pd
from sklearn.linear_model import LogisticRegression# create df
train = pd.read_csv('titanic.csv') # change file path# drop null values
train.dropna(inplace=True)# features and target
target = 'Survived'
features = ['Pclass', 'Age', 'SibSp', 'Fare']# X matrix, y vector
X = train[features]
y = train[target]# model 
model = LogisticRegression()
model.fit(X, y)
model.score(X, y)

上面的代码从 csv 数据创建了一个 pandas dataframe,删除了空值,定义了模型的特征和目标,将数据拆分为一个只包含特征的矩阵和一个包含目标的向量,并拟合逻辑回归模型,然后对其进行评分。

这就创建了一个模型,它可以以大约 70%的准确率预测泰坦尼克号乘客的存活率,然后可以使用:

import pickle
pickle.dump(model, open(‘model.pkl’, ‘wb’))

pickle 文件可以在 Jupyter 笔记本的同一个目录中找到。

编写烧瓶应用程序

打开您的 IDE(我使用 PyCharm)并创建一个新的。工作目录中的 py 文件名为app.py

flask 应用程序的代码可以在下面找到(python v3.7 版)。

**import** pandas **as** pd
**from** flask **import** Flask, jsonify, request
**import** pickle

*# load model* model = pickle.load(open(**'model.pkl'**,**'rb'**))

*# app* app = Flask(__name__)

*# routes* @app.route(**'/'**, methods=[**'POST'**])

**def** predict():
    *# get data* data = request.get_json(force=**True**)

    *# convert data into dataframe* data.update((x, [y]) **for** x, y **in** data.items())
    data_df = pd.DataFrame.from_dict(data)

    *# predictions* result = model.predict(data_df)

    *# send back to browser* output = {**'results'**: int(result[0])}

    *# return data* **return** jsonify(results=output)

**if** __name__ == **'__main__'**:
    app.run(port = 5000, debug=**True**)

代码的结构如下:

  • 装载酸洗模型
  • 命名烧瓶 app
  • 创建一个接收 JSON 输入的路由,使用训练好的模型进行预测,并以 JSON 格式返回预测,可以通过 API 端点访问。

在路由内部,我将 JSON 数据转换为 pandas dataframe 对象,因为我发现这适用于大多数(不是所有!)您希望用来进行预测的模型类型。您可以选择使用您喜欢的方法来转换输入,只要它与您的模型的.predict()方法一起工作。输入的顺序必须与用于训练模型的数据帧中的列顺序相匹配,否则在尝试进行预测时会出现错误。如果您正在接收的输入顺序不正确,您可以在创建数据帧后轻松地对其进行重新排序。

这里的要点是,您需要将从请求中获得的 JSON 数据转换成模型可以用来进行预测的数据结构。如何到达那里取决于你自己。

一旦将它粘贴到 app.py 文件中,您就可以从命令行运行 flask 应用程序(或者如果您使用 PyCharm,只需运行代码)。要从命令行运行应用程序,请使用:

python app.py

如果操作正确,您将看到类似这样的内容:

错误提示:如果这是您第一次创建 flask 应用程序,您可能会得到一个错误提示,提示您需要将 flask 安装到 python 环境中。使用!pip install flask并重试。

当你的 flask 应用程序启动并运行时,点击蓝色链接,你应该会看到这个——这很正常:

可选的,但是你真的应该:测试应用程序是否工作

requestsjson导入到你的 Jupyter 笔记本中,然后用你的本地服务器创建一个变量,如果它与下面的不同:

# local url
url = '[http://127.0.0.1:5000'](http://127.0.0.1:5000') # change to your url

创建示例数据并转换为 JSON:

# sample data
data = {'Pclass': 3
      , 'Age': 2
      , 'SibSp': 1
      , 'Fare': 50}data = json.dumps(data)

使用requests.post(url, data)发布样本数据并检查响应代码。您希望获得 200 的响应代码,以确保应用程序正常工作:

然后您可以打印请求的 JSON 来查看模型的预测:

模型预测值为 1,这意味着乘客生还🙌

完成测试后,按 ctrl+c 关闭 flask 应用程序。

创建 Procfile

Procfile 指定了 Heroku 应用程序在启动时执行的命令。要创建一个,在工作目录中打开一个名为 Procfile(没有扩展名)的新文件,并粘贴以下内容。

web: gunicorn app:app

仅此而已。保存并关闭。✅

创建需求. txt

requirements.txt 文件将包含 flask 应用程序的所有依赖项。要创建 requirements.txt,请在终端的工作目录下运行以下命令:

pip freeze > requirements.txt

如果您不是在一个新的环境中工作,这个文件将包含您当前环境中的所有需求。如果您稍后在部署应用程序时遇到错误,您可以删除导致错误的需求。

对于这个项目,requirements.txt 至少应该包含:

**Flask**==**1.1.1
gunicorn**==**19.9.0
pandas**==**0.25.0
requests**==**2.22.0
scikit-learn**==**0.21.2
scipy**==**1.3.1**

可选项:将文件提交到 GitHub

运行以下命令将文件提交给 git:

# add all files from the working directory
git add .

然后提交您的信息:

git commit -m 'add flask files'

最后,使用下面的命令将更改推送到 Github。可能会要求您输入您的 github 用户名和密码。如果您设置了 2FA,您将需要您的密钥作为密码。

git push origin master

至少,您的 Github repo 现在应该包含:

  • app.py
  • model.pkl
  • Procfile
  • requirements.txt

注意:所有这些文件都应该在工作目录级别,而不是在另一个文件夹中

部署到 Heroku

如果您还没有,请在www.heroku.com创建一个免费账户。

只需选择名称并点击“创建应用”即可创建新应用。这个名称并不重要,但它必须是唯一的。

对于部署应用程序的方式,您有几个选项。我试过 Heroku CLI 和 GitHub,我个人更喜欢 GitHub…但是我会把两个都展示出来,所以挑一个你想看的。

使用 Github 部署

点击下面的 github 图标,连接您的 github 帐户:

搜索正确的存储库,然后单击连接:

然后滚动到页面底部,单击“部署分支”

如果一切正常,您应该会看到这条消息🎉🎉

如果出现问题,请检查您的 requirements.txt,删除给你带来问题的依赖项,然后重试_(ツ)_/

使用 Heroku CLI 部署

在 Heroku CLI 部分,您将看到部署时需要遵循的说明。将每个命令粘贴到您的终端中,并按照任何提示进行操作,如登录。注意任何需要修改的命令,比如cd my-project/——其中my-project/实际上应该是您的项目目录。git remote 应该准确地设置为 Heroku 中的应用程序名称。

如果您成功地遵循了这些说明,您应该在 overview 页面上看到 build successful🎉🎉

如果没有,您可以通过从命令行运行heroku logs --tail来检查出了什么问题。

测试部署的模型并生成预测

如果你已经测试了你的 flask 应用程序,这些说明将会非常相似,除了现在使用 Heroku 应用程序的 url。

在你的 Jupyter 笔记本中导入requestsjson,然后创建一个变量来存储 Heroku 应用的 url(你可以在 Heroku 上点击应用页面右上角的“打开应用”来找到这个)。然后创建一些示例数据,并将其转换为 JSON:

# heroku url
heroku_url = '[https://titanic-flask-model.herokuapp.com'](https://titanic-flask-model.herokuapp.com') # change to your app name# sample data
data = {  'Pclass': 3
             , 'Age': 2
             , 'SibSp': 1
             , 'Fare': 50}data = json.dumps(data)

使用以下代码检查响应代码。响应代码 200 表示一切运行正常。

send_request = requests.post(heroku_url, data)
print(send_request)

Output: <Response [200]>

最后,看看这个模型的预测:

print(send_request.json())

Output: {‘results’: {‘results’: 1}}

如果使用不同的样本数据,输出结果会有所不同。在这种情况下,结果为 1 意味着模型预测乘客幸存,更重要的是 API 起作用了!

现在,人们可以通过 Heroku URL 访问您的 API 端点,并使用您的模型在现实世界中进行预测🌐

这里是 github repo ,包含部署这个 API 所需的所有文件和代码。

在 twitter @elizabethets 上找到我或者在 LinkedIn 上联系我!

来源:

[## 欢迎使用 Flask - Flask 文档(1.1.x)

欢迎阅读 Flask 的文档。开始安装,然后了解快速入门概述。有…

flask.palletsprojects.com](https://flask.palletsprojects.com/en/1.1.x/) [## 云应用平台| Heroku

无论您是在构建简单的原型还是关键业务产品,Heroku 的全托管平台都能为您提供…

heroku.com](https://heroku.com/) [## Procfile

Heroku 应用程序包括一个 Procfile,它指定了应用程序在启动时执行的命令。你可以用一个…

devcenter.heroku.com](https://devcenter.heroku.com/articles/procfile)

使用 fastai 创建和部署图像分类器,并在 15 分钟内渲染。

原文:https://towardsdatascience.com/create-and-deploy-an-image-classifier-using-fastai-and-render-in-15-mins-947f9de42d21?source=collection_archive---------22-----------------------

当我刚开始学习机器学习和深度学习时,我花了很长时间来学习如何建立一个图像分类器,我参加了所有的机器学习课程,学习了 pandas,numpy 和 sklearn,然后我意识到,使用这些,我仍然不能创建一个图像分类器,所以我必须学习深度学习,CNN 和 keras 框架,所有这些只是为了创建一个正常的 CNN 图像分类器。

但现在在 2019 年,要创建一个图像分类器,你需要学习的只是 Fastai,用不到 6 行代码,你就可以创建一个随时可以部署的图像分类模型,击败 SOTA 论文的大多数结果。

Fastai 是第一个为视觉、文本、表格数据、时间序列和协同过滤等所有最常用的深度学习应用提供单一一致接口的深度学习库。

直到现在一切都好!我们现在可以使用 fastai 来构建一个图像分类器。

但是等等,模型会留在控制台吗?就像我总是需要用 jupyter 笔记本来预测新图像一样?
我如何将模型部署为可从 web 访问?

呈现有答案。

Render 是一个统一的平台,通过免费 SSL、全球 CDN、专用网络和 Git 自动部署来构建和运行您的所有应用和网站。

你需要做的就是将你的模型训练后保存下来,添加到 Render 提供的模板中,(可以从 github 克隆),你的模型就部署好了。

例子:https://catdogfastai.onrender.com/

今天我将向你展示如何使用快速人工智能创建和训练一个模型来对猫和狗的图像进行分类,然后如何使用 render 将其部署在一个网站上。

我们开始吧!

首先,你必须准备一个数据集,从谷歌上获取一些猫和狗的图片,并把它们放在不同的文件夹中,给第一个命名为猫,第二个命名为狗。

现在让我们打开我们的 jupyter 笔记本,或者我们的 python 脚本,(随便什么让你的船漂浮)。

在开始编码之前,你首先要安装 PyTorch 和 fastai,

您可以使用以下方式安装它们:

if you are using anaconda:conda install -c pytorch pytorch-cpu torchvision
conda install -c fastai fastaiorpip install orpip install http://download.pytorch.org/whl/cpu/torch-1.0.0-cp36-cp36m-linux_x86_64.whl
pip install fastai

现在,在安装了所需的库之后,让我们开始吧。

首先我们要进口 fastai。

from fastai.vision import *

如果你是一名软件工程师,你可能会注意到我们从 fastai.vision 导入了* (all),这违背了良好的软件工程实践。
完全正确,但在数据科学领域,当我们构建模型时,最重要的事情是尽可能快地与事物进行交互,当涉及到将模型投入生产时,您可以从母库导入您需要的任何东西。

酷!现在我们必须导入数据。

path="/images/"np.random.seed(42)data = ImageDataBunch.from_folder(path+'.', train=path+'.',valid_pct=0.2,ds_tfms=get_transforms(), size=224,num_workers=4).normalize(imagenet_stats)

我们使用 ImageDataBunch 类来导入图像。

这是 fastai 上最强的特性之一,这个类不需要任何配置就可以自动处理很多事情。

valid_pct 指应用交叉验证时,训练期间验证数据的百分比。

我们为所有图像分配了 244 的大小,以及 4 个 CPU 工作线程。

最后的归一化函数用于归一化所有图像,因为如果所有图像的平均值为 0,标准差为 1,则我们的深度学习模型可以很好地拟合。(不需要在这方面深入探讨)

现在让我们检查一下我们的班级:

data.classes

Out[5]: ['猫','狗']

太棒了,现在我们的数据被导入,类被分配(猫和狗)。

让我们检查一下我们的 dataBunch 对象。

data.show_batch(rows=3, figsize=(7, 8))

我们的数据似乎已正确导入。

现在让我们创建我们的模型。在本例中,我们将使用 Resnet34,它是一个残差神经网络。

残余神经网络是一种人工神经网络,其建立在从大脑皮层中的锥体细胞已知的构造上。残余神经网络通过利用跳过连接或跳过某些层的捷径来做到这一点。

ResNet 设法在图像分类中击败了许多论文的 SOTA 结果,所以在我们的问题中使用它已经足够好了。

如果你没有得到 ResNet 的东西,你也不用担心。

from fastai.metrics import error_rate
learn = cnn_learner(data, models.resnet34, metrics=error_rate,model_dir="/tmp/model/")

我们这样创建我们的学习器,cnn_learner,我们指定 error_rate 作为一个度量来计算准确度。

而且我们添加了 models.resnet34 作为架构,是 fastai 提供的。

如果是第一次使用这个架构,那么当你运行这个代码片段时,它就会被下载。

好了,现在我们创建了我们的模型。

让我们训练它!!

defaults.device = torch.device('cuda') *# makes sure the gpu is used*
learn.fit_one_cycle(4)

Training results

最后一个时期的错误率是 0.15,这意味着我们的模型成功地将 85%的图像正确分类,注意到数据集中的一些图像是黑色图像或随机噪声图像。

酷,实际上我对这种准确性很满意,如果你不满意,请添加一些纪元。

现在,让我们保存模型,以便稍后在 web 中部署它。

learn.save("model")

好了,现在我们已经完成了模型的训练和保存。

让我们现在部署它。

首先你要去:https://github.com/render-examples/fastai-v3
并从这个库生成一个新的库。

现在你必须在渲染中创建一个免费账户:【https://render.com/register

上传你保存在某处的模型,例如: DropBox

现在回到 github > server . py 中的存储库

用您的 url 更改文件 url,用文件名更改文件名。

另外,不要忘记把职业改成['猫','狗'],或者你有的任何职业。

在 github 中保存你的代码(你甚至不需要在你的 pc 中克隆它)

现在转到呈现仪表板服务

单击新建 Web 服务

它会要求你授权给 github,授权之后,你所有的库列表就会出现。

点击你之前克隆的那个。

为您的应用程序添加一个名称,忽略付款部分,然后单击创建 Web 服务。

你要等待一段时间的应用程序被建立和部署,然后你可以从链接:yourappname.onrender.com 检查出来

这里有一个小演示:

结论

我们已经使用 fastai 制作了一个图像分类器,并使用 Render 进行了部署。那就像鞭子一样快。

如果您有任何问题、建议或批评,可以通过 Twitter 联系我:@ loulyadam

你可以在这里找到代码源:https://github.com/AdamLouly/CatDogRender

你可以在这个链接找到这里的猫狗数据集。

使用 R 创建趋势动画条形图

原文:https://towardsdatascience.com/create-animated-bar-charts-using-r-31d09e5841da?source=collection_archive---------3-----------------------

最近,动画柱状图开始在社交媒体上疯传,让许多数据爱好者想知道这些动画柱状图是如何制作的。这篇文章的目的是解释如何使用 R-R 和多用途的软件包来构建这样一个动画条形图。

享受 78%的 DataCamp 折扣

包装

在 R 中构建动画情节所需的包有:

  • ggplot2
  • gganimate

虽然以上两个是基本的软件包,但我们也在这个项目中使用了整个tidyversejanitorscales来进行数据操作、清理和格式化。

数据

用于本项目的原始数据集是从世界银行数据下载的。相同的 csv 文件可以在项目文件夹中找到。

关于数据:

这个数据包含了大部分国家几年(尤其是 2000 年到 2017 年)的 GDP 值。

数据预处理:

我们将使用下面的代码以期望的格式准备我们的数据。实际上,我们正在清理列名,将数字转换成数字格式,并使用 tidyr 的gather()函数将数据从宽格式转换成长格式。整理后的数据保存到一个新的 csv 文件gdp_tidy.csv中,以备后用。

library(tidyverse)
library(janitor)gdp <- read_csv("./data/GDP_Data.csv")#select required columnsgdp <- gdp %>% select(3:15) #filter only country rowsgdp <- gdp[1:217,]gdp_tidy <- gdp %>% 
  mutate_at(vars(contains("YR")),as.numeric) %>% 
  gather(year,value,3:13) %>% 
  janitor::clean_names() %>% 
  mutate(year = as.numeric(stringr::str_sub(year,1,4)))write_csv(gdp_tidy,"./data/gdp_tidy.csv")

动画情节

动画情节构建过程包括两个主要部分:

  • 使用 ggplot2 构建整套实际静态图
  • 使用 gganimate 以所需参数激活静态图

这两个主要步骤之后的最后一步是以所需的文件格式渲染动画,如 GIF 或 MP4(视频)。

加载所需的库

library(tidyverse)
library(gganimate)

数据处理:

在这一步中,我们将过滤数据集,仅保留给定年份的前 10 个国家。我们还将创建几个列来帮助我们在绘图中显示标签。

gdp_tidy <- read_csv("./data/gdp_tidy.csv") gdp_formatted <- gdp_tidy %>%
  group_by(year) %>%
  # The * 1 makes it possible to have non-integer ranks while sliding
  mutate(rank = rank(-value),
         Value_rel = value/value[rank==1],
         Value_lbl = paste0(" ",round(value/1e9))) %>%
  group_by(country_name) %>% 
  filter(rank <=10) %>%
  ungroup()

构建静态图

现在我们的数据已经准备好绘制了,我们将构建所有需要的静态图。正如你可能已经在这篇文章顶部的动画中看到的,我们将看到在给定的数据集中,GDP 排名前 10 位的国家在过去几年中是如何变化的。为此,我们需要为每一年建造单独的地块。

staticplot = ggplot(gdp_formatted, aes(rank, group = country_name, 
                fill = as.factor(country_name), color = as.factor(country_name))) +
  geom_tile(aes(y = value/2,
                height = value,
                width = 0.9), alpha = 0.8, color = NA) +
  geom_text(aes(y = 0, label = paste(country_name, " ")), vjust = 0.2, hjust = 1) +
  geom_text(aes(y=value,label = Value_lbl, hjust=0)) +
  coord_flip(clip = "off", expand = FALSE) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_reverse() +
  guides(color = FALSE, fill = FALSE) +
  theme(axis.line=element_blank(),
        axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks=element_blank(),
        axis.title.x=element_blank(),
         axis.title.y=element_blank(),
        legend.position="none",
        panel.background=element_blank(),
        panel.border=element_blank(),
        panel.grid.major=element_blank(),
        panel.grid.minor=element_blank(),
        panel.grid.major.x = element_line( size=.1, color="grey" ),
        panel.grid.minor.x = element_line( size=.1, color="grey" ),
        plot.title=element_text(size=25, hjust=0.5, face="bold", colour="grey", vjust=-1),
        plot.subtitle=element_text(size=18, hjust=0.5, face="italic", color="grey"),
        plot.caption =element_text(size=8, hjust=0.5, face="italic", color="grey"),
        plot.background=element_blank(),
       plot.margin = margin(2,2, 2, 4, "cm"))

我们不会详细讨论如何构建静态图,因为这与使用ggplot2构建普通图非常相似。正如你在上面的代码中看到的,theme()函数有几个关键方面是为了让它与动画配合得更好,比如——只画了垂直的网格线,图例、轴标题和其他一些组件都从图中删除了。

动画

这里的关键功能是transition_states(),它在前将各个静态图缝合在一起。view_follow()用于提供背景线(网格线)随着动画的进行而移动的视图。

anim = staticplot + transition_states(year, transition_length = 4, state_length = 1) +
  view_follow(fixed_x = TRUE)  +
  labs(title = 'GDP per Year : {closest_state}',  
       subtitle  =  "Top 10 Countries",
       caption  = "GDP in Billions USD | Data Source: World Bank Data")

翻译

随着动画被构建(准备好)并保存在对象anim中,是时候我们使用animate()函数渲染动画了。 animate()中使用的渲染器因所需输出文件的类型而异。

对于 GIF 文件格式:

# For GIFanimate(anim, 200, fps = 20,  width = 1200, height = 1000, 
        renderer = gifski_renderer("gganim.gif"))

对于视频(MP4)文件格式:

# For MP4animate(anim, 200, fps = 20,  width = 1200, height = 1000, 
        renderer = ffmpeg_renderer()) -> for_mp4anim_save("animation.mp4", animation = for_mp4 )

最终输出:

该项目的 GIF 输出:

总结:

因此,我们已经成功地构建了动画条形图,根据 GDP 值来可视化排名靠前的国家在几年内的变化情况。一旦数据预处理和数据操作步骤将输入数据重新整形为所需的格式,就可以很容易地根据您的目的修改这些代码。r 是任何形式的数据可视化的神奇工具,要了解更多请查看这个。这个完整的项目可以在 my github 上获得,你可以随意地使用它。

免费注册接收我的数据科学简讯— AI

免责声明: 此处使用的代码是从本栈溢出问题 动画排序条形图各条互相超越 的答案中长时间借用(可以说是启发、复制)

通过使用深度学习来听音乐,创建自动播放列表

原文:https://towardsdatascience.com/create-automatic-playlists-by-using-deep-learning-to-listen-to-the-music-b72836c24ce2?source=collection_archive---------11-----------------------

走向组织音乐的连续方式

Robert Dargavel Smith —高级机器学习硕士项目结束( MBIT 学校,西班牙马德里)

动机

周围有许多自动 DJ 工具,它们巧妙地将一首歌曲的速度与另一首歌曲的速度相匹配,并混合节拍。老实说,我一直觉得那种 DJ 很无聊:他们技术越好,听起来就越像一首没完没了的歌。在我看来,重要的不是你怎么玩,而是你玩什么游戏。这些年来,我收集了许多珍贵的唱片,并在电台和俱乐部做过一些 DJ。我几乎可以通过听一首歌几秒钟就判断出我是否会喜欢它。或者,如果正在播放一首歌曲,通常会立即想到一首与之相配的歌曲。我认为人工智能可以应用于这种“音乐直觉”,作为一种音乐推荐系统,只需简单地一首歌(当然,还需要有广博的音乐知识)。

几年前,iPod 有一个非常酷的功能,叫做 Genius ,它可以根据几首示例歌曲即时创建一个播放列表。苹果决定移除这一功能(尽管它在 iTunes 中仍然可用),大概是为了说服人们订阅他们的音乐流媒体服务。当然,Spotify 现在提供了这一功能,但就我个人而言,我发现它推荐的最好的是我已经知道的音乐,最差的是相当商业化和缺乏创意。我有一个很大的音乐库,我想念有一种简单的方式来说“继续播放这样的歌曲”(特别是当我开车的时候),以及一些帮助我发现新音乐的东西,甚至是在我自己的收藏中。我花了一些时间寻找替代解决方案,但什么也没找到。

实施细节

一种常见的方法是使用音乐流派来对音乐进行分类,但我发现这种方法过于简单和局限。罗克珊是雷鬼、流行还是摇滚歌手?那么所有不断发展的电子音乐细分领域呢?我觉得有必要找到一种更高维度、更连续的音乐描述,并且不需要标记每个音轨(即无监督学习方法)。

我做的第一件事是从 Spotify 上收集尽可能多的播放列表。(不幸的是,在一个类似的竞赛已经结束后,我有了这个想法,在这个竞赛中,获得了一百万首歌曲的使用权。)这个想法是,按播放列表分组会给个别歌曲带来一些背景或意义——例如,“80 年代迪斯科音乐”或“我最喜欢的海滩歌曲”。人们倾向于制作相似艺术家的歌曲的播放列表,具有相似的情绪、风格、流派或用于特定的目的(例如,用于健身房的锻炼)。不幸的是,Spotify API 并没有让下载播放列表变得特别容易,所以方法相当粗糙:我搜索了所有名称中包含字母“a”、字母“b”的播放列表,以此类推,直到“Z”。通过这种方式,我设法获得了 240,000 个播放列表,其中包括 400 万首独特的歌曲。我故意排除了所有由 Spotify 策划的播放列表,因为它们特别商业化(我相信艺术家可以付费在其中播放)。

然后,我使用 Word2Vec 算法创建了这些歌曲的嵌入(“ Track2Vec ”),将每首歌曲视为一个“单词”,将每个播放列表视为一个“句子”。(如果你能相信我,我也有同样的想法,独立于这些家伙。)我发现 100 维是个不错的尺寸。给定一首特定的歌曲,该模型能够令人信服地推荐同一艺术家或类似艺术家,或同一时期和流派的 Spotify 歌曲。由于独特歌曲的数量巨大,我将“词汇”限制在那些出现在至少 10 个播放列表中的歌曲,给我留下了 450,000 首歌曲。

Spotify API 的一个优点是,它为大多数歌曲提供了一个 URL,允许您下载 30 秒的 MP3 样本。我下载了所有这些 MP3,并把它们转换成一个梅尔声谱图(Mel Spectrogram )( T9)——每首歌的一个紧凑表示,它应该反映了人耳对声音的反应。就像一个人可以通过听几秒钟的歌曲想到相关的音乐一样,我认为仅仅 5 秒钟的窗口就足以抓住一首歌的主旨。即使是这样有限的表示,所有光谱图的压缩大小达到了 4.5 千兆字节!

下一步是尝试使用从 Spotify 收集的信息从光谱图中提取特征,以便有意义地将它们相互联系起来。我训练了一个卷积神经网络,以尽可能接近地(在余弦近似下)再现与给定频谱图(输入 x )对应的 Track2Vec 向量(输出 y )。我尝试了一维(在时间轴上)和二维卷积网络,并将结果与基线模型进行了比较。基线模型试图在不实际听音乐的情况下得出最接近的 Track2Vec 向量。这导致了一首歌,理论上,每个人都应该喜欢(或讨厌)一点;-) ( SBTRKT — Sanctuary ),余弦接近度为 0.52。在过度拟合之前,我能够从验证数据中获得的最好分数是 0.70。使用 300 维嵌入,验证分数更好,但基线分数也更好:我觉得基线分数更低、两者之间的差异更大更重要,这反映了更具多样性和辨别能力的潜在代表。当然,分数仍然很低,但期望一个声谱图可以捕捉到人类基于文化和历史因素分组在一起的歌曲之间的相似之处,这确实是不合理的。此外,一些歌曲在 5 秒钟的窗口中表现得相当糟糕(例如,在奎恩的“现在不要阻止我”的情况下,这一部分对应于布莱恩·梅的吉他独奏……)。我摆弄了一个自动编码器和一个可变自动编码器,希望迫使光谱图的内部潜在表现更加连续、清晰,从而更有意义。最初的结果似乎表明,二维卷积网络更好地捕捉光谱图中包含的信息。我也考虑过训练一个暹罗网络来直接比较两个光谱图。我把这些想法留给将来可能的研究。

最后,通过一个 MP3 文件库,我将每个 MP3 映射到每 5 秒时间片的一系列 Track2Vec 向量。大多数歌曲从开始到结束变化很大,所以一首接一首的推荐到处都是。同样,我们可以应用 Doc2Vec 模型来比较类似的文档,我为每个 MP3 计算了一个“MP3ToVec”向量,包括根据其 TF-IDF (术语频率,逆文档频率)权重的每个组成 Track2Vec 向量。这种方案更加重视针对特定歌曲的频繁出现的的推荐。由于这是一个 O ( n )算法,所以有必要将 MP3 库分成 100 个一批(否则我的 8000 个 MP3 将需要 10 天来处理!).我检查了一下,这对计算出的向量的影响可以忽略不计。

结果

您可以在本练习册的末尾看到一些结果,并自行判断。它特别擅长识别古典音乐、口语词、嘻哈和电子音乐。事实上,我对它工作得如此之好感到惊讶,以至于我开始想知道有多少是由于 TF-IDF 算法,有多少是由于神经网络。所以我创建了另一个基线模型,使用随机初始化权重的神经网络将光谱图映射到向量。我发现这种基线模型擅长识别流派和结构相似的歌曲,但是,当有疑问时,会提出一些完全不合适的东西。在这些情况下,经过训练的神经网络似乎会选择具有类似能量、情绪或仪器的东西。在许多方面,这正是我所寻找的:一种超越僵化的流派界限的创造性方法。为了 TF-IDF 算法的目的,通过摆弄确定两个向量是否相同的ε参数,有可能在流派(全局)和“感觉”(局部)特征之间找到良好的折衷。我还将结果与 Genius 在 iTunes 中生成的播放列表进行了比较,尽管这非常主观,但我觉得 Genius 坚持了流派,即使歌曲不太搭配,也不会做出那么“有灵感”的选择。也许大众来源的“可口可乐”测试需要成为最终的裁判。

当然,考虑到数据、计算能力和时间的限制,我认为结果可以作为概念的证明。

应用程序

除了自动(相对于俱乐部电台)DJ 的最初想法,你还可以做其他一些有趣的事情。例如,由于矢量映射是连续的,您可以轻松地创建一个播放列表,它平滑地“连接一首歌曲和另一首歌曲之间的点,通过您喜欢的任意多个路径点。例如,你可以通过放克和鼓贝斯从灵魂乐转到 techno。或者从摇滚到歌剧:-)。

另一个简单的想法是使用麦克风听音乐,并提出一组下一首歌曲来即时播放。与其与整个 MP3 音乐进行比较,不如只考虑每首歌的开头,这样音乐从一个音轨到另一个音轨会更自然。

你自己试试吧

git 库克隆或下载到您的计算机上。安装了所需的 python 包后

并且下载模型权重到你有 python 文件的目录,你可以处理你的 MP3(和 m4a)库。只需运行以下命令并等待…

它将创建一个名为“Pickles”的目录,并在子目录“mp3tovecs”中创建一个名为“mp3tovec.p”的文件。完成后,您可以使用

然后在浏览器中进入 http://localhost:8050 。如果加上参数--demo 5,就不用等到每首歌结束了。只需加载您希望播放列表所基于的 MP3 或 M4A;不一定非得是你音乐库里的一首。最后,有几个控件你可以摆弄(因为它是目前的编程,这些只有在下一首歌曲已经在播放时才生效)。“Keep on”决定了在生成播放列表时要考虑的先前曲目的数量,而“ducked”指定了要在混音中加入多少随机性。或者,您可以使用创建一个您选择的音乐之旅的 MP3 混音

其中“tracks.txt”是包含 MP3 或 M4A 文件列表的文本文件,这里,9 是您想要在每个文件之间生成的附加轨道的数量。

如果你对我用来训练神经网络的数据感兴趣,请随时给我发邮件。

[## teticio/Deej-A.I

只需音乐即可创建自动播放列表。

github.com](https://github.com/teticio/Deej-A.I.)

最初发表于T5【http://github.com】

使用 SeaBorn 创建基本的图形可视化

原文:https://towardsdatascience.com/create-basic-graph-visualizations-with-seaborn-18f622012a5a?source=collection_archive---------14-----------------------

基本但强大而美丽的图形

Photo by Isaac Smith on Unsplash

说到数据准备和熟悉数据,我们通常跳过的一步是数据可视化

虽然一部分原因可能是因为缺乏适用于我们使用的平台的良好可视化工具,但我们大多数人有时也会变得懒惰

对于我们大多数的绘图需求,我会阅读博客,使用 StackOverflow 解决方案,并在每次需要绘制简单图形时与 Matplotlib 文档讨价还价。

这让我想到了一篇用 Python 创建通用图形类型的博文。

但是作为一个拖延者,我总是把它推到我的脑后。

帮助我在 Python 中追求数据可视化需求的一件事是密歇根大学的这门关于数据可视化和应用绘图的课程,它是 Python 本身的一个很好的数据科学专业的一部分。强烈推荐。

所以我最终写这篇博文的基本目的是创建一个代码库,为我提供可以直接用于分析的现成代码。

没错。所以现在开始。

首先导入我们将需要使用的库。

import matplotlib.pyplot as plt #sets up plotting under plt 
import seaborn as sns #sets up styles and gives us more plotting options 
import pandas as pd #lets us handle data as dataframes

我们将使用包含以下信息的提示数据

tips = sns.load_dataset("tips")
tips.head()

带回归线的散点图

现在让我们将这些数据可视化。我们将在 seaborn 中使用 regplot 选项。

这需要一点代码,但我觉得它比 Matplotlib 或 ggPlot2 渲染的要好得多。我们在没有太多代码的情况下进行了大量定制。

但这并不是真正让我喜欢 Seaborn 的原因。

真正引起我注意的绘图类型是lmplot,它允许我们在分面模式中使用 regplot

:
你可以使用 color_palette() 函数构建自己的调色板。color_palette()将接受任何 seaborn palettematplotlib colormap的名称(jet 除外,你千万不要用它)。它还可以接受以任何有效 matplotlib 格式指定的颜色列表(RGB 元组、
十六进制颜色代码或 HTML 颜色名称)。返回值总是 RGB 元组的列表。这允许您在图形中使用自己的调色板。

条形图

直方图和分布图

它们构成了我工作流程的另一部分。让我们使用 seaborn 绘制正态直方图。为此,我们将使用函数。这个函数结合了 matplotlib hist 函数(自动计算一个好的默认 bin 大小)和 seaborn kdeplot()函数。它还可以拟合 scipy.stats 分布,并绘制数据的估计 PDF。

****

配对图

你需要看到变量之间是如何变化的。数据集中变量的分布是怎样的?这是与函数一起使用的图表。非常有帮助,使用它是一种乐趣。在这个例子中,我们将使用虹膜数据集

iris = sns.load_dataset("iris")
iris.head()

****

希望这篇文章对你有用,值得你花时间。你可以在 github 找到 iPython 笔记本

我试图让这尽可能简单,但你可能总是问我或查看文档中的疑问。

如果你有更多关于如何使用 Seaborn 的想法,请在评论部分提出建议。

随着我开始使用更多的可视化工具,并遇到其他像 seaborn 一样好的库,我肯定会尝试添加到这篇文章中。

另外,由于这是我的第一个可视化帖子,我想从密歇根大学调用一个关于数据可视化和应用绘图的好课程,这是一个很好的数据科学专业的一部分,Python 本身也不错。一定要去看看。

【https://mlwhiz.com】原载于

根据分类数据创建 Python 地图

原文:https://towardsdatascience.com/create-categorical-choropleth-with-python-122da5ae6764?source=collection_archive---------15-----------------------

有很多关于使用 Python 构建地理地图的好帖子,比如这个。然而,所有这些帖子都使用 choropleths 作为连续数据,这意味着使用带有颜色条的渐变来填充地图。由于我找不到很多关于如何使用分类信息构建地图的信息,所以我决定尝试自己构建一些东西,结果是这样的:

Map from categorical data, built with Python.

要求

为了构建此地图,您需要以下库:

  • Pandas 和 NumPy(使用数据框)
  • Geopandas(使用 shapefiles)
  • Matplotlib(绘制图表)

准备数据

获取数据

创建 geopandas 地图时,您总是需要两个文件。

第一个文件是 shapefile,它包含多边形以构建一个带有边界的空地图。你可以在网上找到无数不同地区和边界的 shapefiles。对于这个项目,我使用了一个以行政区为边界的纽约市形状文件。

fp = ‘geo_export_58b25928–032c-45c8-a41f-8345f112f4d4.shp’ map_df = gpd.read_file(fp)

The shapefile data.

数据导入后,您就可以预览地图的外观,而无需用数据填充地图。

map_df.plot()

A plot of the NYC shapefile.

现在让我们用我们的数据对不同的行政区进行颜色编码。

第二个文件是实际数据,即包含用于填充地图的值。在这种情况下,我在纽约市使用了包含 364.558 311 服务请求的文件。

df = pd.read_csv(‘NY_311_requests.csv’)

在这个文件中,每行代表一个请求(或投诉)。然而,我想看看各区最受欢迎的投诉类型。通过使用 groupby 我可以创建这个概览:

df_top_compl = df.groupby(‘Borough’)[‘Complaint Type’].apply(lambda x: x.value_counts().head(1)).reset_index()

Most frequent complaint by borough

合并数据

现在我们有了两个文件,我们可以将它们合并在一起,这样我们就有了地理数据和填充数据(投诉)的组合。由于两个数据框架都包含行政区,我们可以基于该列进行合并。然而,在数据文件中,行政区是用大写的写成的,所以我们也需要将它应用到 shapefile。

map_df[‘Borough’] = map_df[‘boro_name’].apply(lambda x: x.upper())

现在,两个文件都有一列具有相似的值,我们可以在该列上合并它们。(为了防止 shapefile 中的行政区没有匹配的填充数据,我还添加了一个 fillna()值。)

data_df = pd.merge(map_df, df_top_compl, how=’left’, on=’Borough’) data_df[‘level_1’].fillna(value=’No data’, inplace=True)

现在所有的数据都准备好了,我们可以创建地图了!

创建地图

准备颜色

在我们创建实际的地图之前,我们将为图例做一些准备。鉴于代码应该是动态的,以防数据发生变化,我们不能使用固定数量的图例颜色。所以我们要做的是用调色板中相应的颜色创建一个填充值的字典(在这个例子中是 matplotlib tab20b ),除了' No data '值,按照惯例它应该总是灰色的。

keys = list(data_df[‘level_1’].unique()) color_range = list(np.linspace(0, 1, len(keys), endpoint=False)) colors = [cm.tab20b(x) for x in color_range] color_dict = dict(zip(keys, colors)) color_dict[‘No data’] = ‘lightgray’

准备网格

由于我们需要绘制图例和地图,我们将把图形分成两列;左为图例右为地图。图例的左列必须再次按行拆分:每个值和相应的颜色一行。但是,由于项目应该是动态的,我们不能使用固定的行数,它应该适应填充值的数量。使用下面的代码,我们可以根据唯一填充值的数量创建一个轴列表

row_count = data_df[‘level_1’].nunique() ax_list = [] for i in range(row_count+1): ax_list.append(‘ax’ + str(i+1)) ax_string = ‘, ‘.join(ax_list)

基于该字符串和轴名称列表,我们可以创建具有 4 列和 N 行的plot grid

fig, (ax_string) = plt.subplots(row_count, 4)

在这 4 列中,我们将第一列用于图例,另外 3 列用于实际绘图(使用 colspan)。

例如,如果我们有 5 行(要绘制的唯一值),网格将如下所示:

Subplotgrid mockup.

绘制地图

这就是“传统”的连续数据图谱的不同之处。我们将使用一个循环来堆叠不同的地图,而不是绘制一个地图,以创建最终的结果。每个图层由一个区组成,每个区的颜色对应于它的值,使用我们之前构建的颜色字典。

ax1 = plt.subplot2grid((row_count,4),(0,1), rowspan=row_count, colspan=3) for index, row in data_df.iterrows(): plot = data_df[data_df[‘boro_code’] == row[‘boro_code’]].plot(color=color_dict[row[‘level_1’]], ax=ax1) ax1.axis(‘off’)

Map without legend.

地图看起来很棒,但是没有相应的图例显然是没用的。所以让我们把那部分也加上。

绘制图例

现在让我们在左栏添加一个图例。由于我们使用图层构建了地图,因此我们还需要以一种不太传统的方式构建图例。网格已经完成,包含了我们将要绘制的每个图例值的一行。现在在每一行将放一个彩色圆圈(使用一个小饼图)和一个字符串与相应的值。

row_counter = 0 for i in data_df[‘level_1’].unique(): plt.subplot2grid((row_count,4),(row_counter,0)) plt.pie([1],labels=[i],radius=0.4, colors=[color_dict[i]]) plt.axis(‘off’) row_counter += 1

Final result.

在那里!带有分类数据和相应图例的精美地图。如果数据发生了变化,您可以简单地重新运行脚本,图例中的颜色和值的数量都会很好地适应。

当然,你可以把它应用到你能找到的任何 shapefile 和数据上,只要你能合并这两个文件。

你可以在我的 GitHub 上查看并下载我的 Jupyter 笔记本。如果有不清楚的地方,请随时提问。

最后,我要感谢本杰明·库利,他的帖子给了我创作这个附加内容的灵感。

由于这是我在 Medium 上的第一篇帖子,任何评论或反馈都将受到极大的感谢。

关于我:我叫布鲁诺,是总部位于荷兰的人工智能技术纵向扩展公司dash mote的数据科学家。我们的目标是借助基于人工智能的解决方案,弥合图像和数据之间的鸿沟。
查看我在
上的其他作品 https://www.zhongtron.me 。

使用 Rasa Part-1 创建聊天机器人

原文:https://towardsdatascience.com/create-chatbot-using-rasa-part-1-67f68e89ddad?source=collection_archive---------1-----------------------

现实世界中的数据科学

安装并运行你的第一个 Rasa 机器人。了解 Rasa 框架。

Rasa 是一个开源的机器学习框架,用于构建 AI 助手和聊天机器人。大多数情况下,在 Rasa 中工作不需要任何编程语言经验。虽然有一个叫做“RasaAction Server 的东西,你需要在那里用 Python 写代码,它主要用来触发外部动作,比如调用 Google API 或 REST API 等。

rasa.com

Rasa 有两个主要模块:

  1. 拉莎·NLU用于理解用户信息
  2. 用于进行对话和决定下一步行动的 Rasa 核心

注意——现在 Rasa NLU 和 Rasa 核心源代码合并在一起。

Rasa X 是一个帮助你构建、改进和部署由 Rasa 框架支持的人工智能助手的工具。Rasa X 包括一个用户界面和一个 REST API。Rasa X 是 Rasa 的最新版本。

关于我:我是 Rasa 官方贡献者。

Rasa 组件

Rasa X —这是一个基于浏览器的 GUI 工具,它将允许您通过使用基于 GUI 的交互模式来训练机器学习模型。请记住,它是 Rasa 软件堆栈中的可选工具。有时,rasa 会从您的浏览器向 Rasa 发送使用统计信息— ,但它不会向您的系统外部发送训练数据,它只会发送您使用 Rasa X Train 的次数。

Rasa NLU —这是 Rasa 试图理解用户消息的地方,以检测您消息中的意图实体。Rasa NLU 有不同的组件来识别意图和实体,其中大多数都有一些额外的依赖关系。

  1. Spacy(需要单独安装)
  2. Tensorflow(默认情况下可用于 Rasa)

Rasa Core —这是 Rasa 尝试帮助您处理上下文消息流的地方。基于用户消息,它可以预测对话作为回复,并可以触发 Rasa 动作服务器。

Rasa 内部使用 Tensorflow,无论何时您执行“ pip install rasa ”或“ pip install rasa-x ”操作,默认情况下它都会安装 Tensorflow。

安装 Rasa

Ubuntu 16+,Mac OS 和 Windows 10 (Visual C++构建工具)

注意:如果您使用的是 windows,请确保您已经安装了 Visual c++构建工具。这是一些 python 包所必需的。一定要使用 miniconda 来避免系统中其他已安装的 Python 包或冲突的 Python 版本的问题。

在你的操作系统中安装 MiniConda(Anaconda 的一部分)

[## Miniconda - Conda 文档

安装程序有两种变体:Miniconda 是基于 Python 2 的,Miniconda3 是基于 Python 3 的。请注意…

conda.io](https://conda.io/miniconda.html)

安装 miniconda 后,按照下面的命令在 conda 中创建一个虚拟环境。这将允许您无错误地运行 Rasa。

conda install python=3.6
conda create -n rasa python=3.6
source activate rasa
pip install rasa-x --extra-index-url [https://pypi.rasa.com/simple](https://pypi.rasa.com/simple)

按照上面的命令,Rasa 和 Rasa X 都将安装在您的系统中。

在 Rasa 中创建新项目

打开终端,激活康达虚拟环境。现在转到一个目录并执行“ rasa init ”,它将在该位置创建一个 rasa 项目。“rasa x”将启动 Rasa X 应用程序

source activate rasa
rasa init

rasa init ”应该显示上面的消息,以防您做得很好,并且您的系统不包含任何错误。跟随交互式会话并继续按回车键到达最后一步。最后,它应该显示这条消息。

如果您在终端中执行“ ls -la ”,您可以看到 Rasa 创建的文件列表。现在做“rasa x”来启动 rasa。

Rasa 配置

让我解释一下文件,它是作为 Rasa 的初始项目结构创建的。

一个空文件,帮助 python 找到你的动作

actions.py自定义操作的代码。如果您希望 Rasa 通过 REST API 或 API 调用来调用外部服务器,您可以在这里定义您的自定义操作。请记住,您可以为 Rasa 自定义操作创建多个 Python 脚本。

config.yml '* '配置你的 NLU 和核心车型。如果你正在处理 Tensorflow 或 Spacy,你需要在这里定义这样的管道。要处理这个文件,你要表现出对机器学习和深度学习的了解。

credentials.yml连接其他服务的详细信息。如果你想在 Facebook Messenger 上构建 Bot,微软 Bot 框架,你可以在这里维护这样的凭证和令牌。所以基本上你只需要添加脸书、slack 和 Bot 框架相关的配置,rasa 会自动为你做 rest。请记住,您需要通过 https 域托管 Rasa。在开发过程中,您可以使用 ngrok 作为测试工具。

data/nlu.md‘*’你的 NLU 训练数据。您可以在这里定义意图。比如订披萨或者预定优步。你需要为此添加相关的句子。请记住,如果您正在使用 Rasa-X,您的培训意图和数据将会自动添加。

data/stories.md '* '你的故事。这是 Rasa 核心所必需的。有一种叫做“Rasa 中的对话流”的东西,其中 Rasa Core 控制着你和 chatbot 之间的对话流,因此对于这种流,你需要使用这些故事来训练 chatbot。因此,如果你想让你的聊天机器人在不同的背景(故事)下非常完美,你可以在这里添加这些故事。

domain.yml '* '您的助手的域。这个文件结合了聊天机器人可以检测到的不同意图和机器人回复列表。请记住,您可以在这里定义您的自定义操作服务器 python 方法名称(下划线格式),以便 Rasa 为您调用该 Python 方法。

endpoints.yml连接到 FB messenger 等频道的详细信息。这主要用于生产设置。您可以像 Redis 一样配置您的数据库,以便 Rasa 可以存储跟踪信息。

models/<timestamp>.tar.gz您的初始模型

玩示例聊天机器人

Rasa 用默认数据为您创建了一个示例机器人。所以现在您可以从 Shell/Terminal 开始使用它。首先,让我们从终端测试您的聊天机器人(记住要在终端中进行)

rasa shell

你可以输入“hi ”,在机器人的回复中,你会收到一些回应。

如何使用 Rasa-X

这是 Rasa 堆栈的最新成员。您可以使用 Rasa-X 在浏览器上尝试您的聊天机器人。可以下载训练数据。此外,您可以通过指导您的机器人来纠正您的训练数据。

rasa x

它将询问许可协议,您可以说“y”并继续。

在浏览器上打开此链接—http://localhost:5002/talk

在左边,你可以试着和你的机器人聊天,在右边你可以看到哪个意图和回复得到了回应。

关于 Rasa-x 的一些事实

当您在本地运行 Rasa X 时,您的培训数据和故事将从您的项目(例如data/nlu.md)中的文件中读取,并且您在 UI 中所做的任何更改都将保存回这些文件中。对话和其他数据存储在 SQLite 数据库中,该数据库保存在一个名为rasa.db的文件中。

观看此视频,了解有关 Rasa-X 的更多信息

如何使用 Rasa 自定义操作(操作服务器)

这是你的聊天机器人最真实的例子。假设你想在你的聊天机器人上增加一个功能,让你的机器人告诉你一个特定城市的最新天气预报,你会怎么做?答案是“Rasa 自定义操作”

一个动作可以运行你想要的任何代码。自定义操作可以打开灯,在日历中添加事件,检查用户的银行余额,或者任何你能想到的事情。

Rasa 将在预测到自定义操作时调用您可以指定的端点。这个端点应该是一个 web 服务器,它响应这个调用,运行代码,并可选地返回信息来修改对话状态。

在编辑器中打开“actions . py”(Visual Studio 代码可以是一个选项)

步骤 1 — 在“actions.py”中定义一个名为“ActionCheckWeather”的方法

**from** **rasa_sdk** **import** Action
**from** **rasa_sdk.events** **import** SlotSet

**class** **ActionCheckWeather**(Action):
   **def** name(self) -> Text:
      **return** "action_check_weather"

   **def** run(self,
           dispatcher: CollectingDispatcher,
           tracker: Tracker,
           domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:

      dispatcher.utter_message("Hello World! from custom action") **return** []

步骤 2-将此自定义操作与您的聊天机器人相链接。打开“domain.yml”。

在动作列表中添加“动作 _ 检查 _ 天气”动作。这应该是这样的

actions:- utter_greet- utter_cheer_up- utter_did_that_help- utter_happy- utter_goodbye- **action_check_weather**

现在,在故事中,将这个自定义操作添加为您的流。打开“ stories.md ”文件和这个新的自定义动作“action_check_weather”作为快乐路径流的一部分。

**## happy path*** greet- utter_greet* mood_great- action_check_weather

步骤 3 告诉 rasa 使用自定义操作服务器

打开“endpoints.yml”并添加以下行以启用自定义操作服务器

action_endpoint: url: "http://localhost:5055/webhook"

现在使用下面的命令重新训练你的 Rasa 聊天机器人。你需要重新训练你的机器学习模型,因为你在“stories.md”和“domain.yml”文件中做了一些修改。所以没有重新训练,你不能通知 Rasa 使用这些。

rasa train

现在使用以下命令再次启动 Rasa

rasa x

此外,使用以下命令启动 Rasa 操作服务器。Rasa X 和 Rasa run 操作应该在两个不同的终端中运行。

rasa run actions

你可以看到,你得到了用 python 写的自定义动作的回复。在同一个 python 脚本中,您可以连接到后端数据库并返回响应。此外,您可以使用额外的 python 包调用外部 API。

另外,你可以用 C#、NodeJS 和 Java 开发定制动作服务器。

如何为聊天机器人构建自定义前端

您可以使用 HTML5 和 CSS3 构建一个聊天机器人 GUI。可以像 ReactJS 和 JQuery 一样使用库。如果你愿意,你可以使用 Angular 作为你的前端 JavaScript 框架来为你的聊天机器人构建前端。

  1. 在 HTML5 和 CSS3 中构建 GUI
  2. 从前端调用 Rasa Rest API
  3. 好了

从 JavaScript 到 Rasa 后端的示例 API 调用

当我们开始构建生产级 Rasa 聊天机器人时,首先我们可以简单地使用下面的命令来启动 Rasa。

rasa run

上述命令将运行 Rasa 核心,并在端口 5005 上公开 REST API。

URL: [http://localhost:5005/webhooks/rest/webhook](http://localhost:5005/webhooks/rest/webhook)
Method: POST
Header: Content-Type: application/json
Body:
{
 “sender”: “Rasa1”,
 “message”: “hi”
}Response:
[
    {
       “recipient_id”: “Rasa1”,
       “text”: “Hey! How are you?”
    }
]

现在,您可以在前端应用程序中解析这个响应,并向用户显示这个响应。请记住,Rasa 将根据我们在请求正文中传递的名为“Rasa1”的唯一 id 来跟踪您的对话。

在本文的下一部分,我们将学习

  1. Rasa 插槽
  2. 使用 Docker 的 Rasa
  3. Rasa-X 进展
  4. Rasa 生产部署

你可以从我的 Github 获得完整的代码

[## bikashkumars/rasa

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/bikashkumars/rasa)

快乐的 Rasa 和快乐的机器学习——读者们。!!!

使用 Luigi & PySpark 和 CI/CD 创建数据科学管道

原文:https://towardsdatascience.com/create-data-science-pipelines-with-luigi-pyspark-and-ci-cd-6422129b310d?source=collection_archive---------25-----------------------

Photo by Victor on Unsplash

本文将为您提供关于使用以下 Python 包创建健壮的数据管道的所有细节:

  • 路易吉,管道公司的包裹
  • PySpark,一个通过 Python API 使用 Spark 的包
  • 熊猫,一个处理数据的包
  • Unittest,一个实现单元测试的包。

本文使用的所有代码,可以在下面的 GitHub repo 上找到:https://github.com/aalepere/luigi_spark_flask_cicd

什么是数据管道,我们为什么需要它们?

数据管道是一组连续应用于一个或多个数据源的数据处理。

数据处理的例子可以是:加载数据源,转换成定义的格式,应用完整性规则,替换丢失的值…

数据管道在机器学习领域非常重要。传统上,数据科学家倾向于以更“手动”的方式工作,通过文件和笔记本来操作数据。

然而,当需要将模型迁移到生产环境中时,这可能是一项困难的工作。

使用数据管道及其相关原理具有以下优势:

  • 再现性
  • 可配置的
  • 模块性
  • 准备生产

路易吉

Luigi 是允许创建数据管道的 python 包。传统上,当创建管道时,我们将事件列表链接起来,以所需的输出结束。Luigi packages 通过开箱即用的功能帮助您构建干净的数据管道,例如:

  • 依赖关系解析,换句话说,确保在移动下一个任务之前,所有上游任务都被正确执行。Luigi 允许创建干净的图形
  • 工作流程管理
  • 图形可视化
  • 并行化处理

【https://github.com/spotify/luigi

PySpark

PySpark 是 Spark 的 Python API。PySpark 允许我们通过 Python API 利用 Spark 的所有特性。在本次回购中,我们主要使用 Spark 的机器学习功能,包括:

  • 特征模块,一组可用于特征工程的数据转换(替换缺失值、离散化等)
  • 分类模块,一组分类模型(逻辑回归,随机森林…)

https://spark . Apache . org/docs/latest/API/python/py spark . html

测试& CI/CD

CI/CD 是一个框架,通过在开发阶段引入自动化来频繁地将代码/特性交付到产品中。CI/CD 的主要概念是持续集成、持续交付和持续部署。CI/CD 是集成新代码给开发和数据科学团队带来的问题的解决方案。通常,数据科学家在 Jupyter notebooks 等原型开发环境中工作,事实证明,很难轻松转移到生产环境中。

具体来说,CI/CD 在数据管道的整个生命周期(从集成和测试阶段到交付和部署)中引入了持续的自动化和连续监控。

创建任务

在 Luigi 中,要创建一个数据管道,我们需要创建一组任务,然后执行这些任务以产生期望的最终输出。

Luigi 任务由以下元素组成:

  • 输入,这定义了一个任务需要哪些输入。它通常是一个文件,但稍后我们会看到,通过使用字典,我们可以使用多个文件(即训练和测试)。
  • 输出,这定义了任务的输出,然后作为输入用于下游任务。
  • 运行,执行任务时需要运行的指令集
  • 需要,在执行当前任务之前需要执行的一组上游任务。这允许在任务之间创建依赖关系,有点像数据库设计中的主键和外键。
  • Main ,在某些情况下如使用 PySpark 时,将使用 Main 代替 run

数据分析

为了定义将要执行的转换,我们首先需要执行一些数据分析。将用于泰坦尼克号生存数据集的数据集。

  • 性,取两个值男性和女性。大多数机器学习算法只接受数值。因此,性别特征必须转换成数值(即男性→ 0,女性→ 1)
  • 年龄,有一些缺失的价值需要被取代。由于分布偏向年轻人,我们决定用中位数来代替缺失值。

  • 年龄是一个离散值,以决定观察其与存活率(每个年龄的存活数/总乘客数)的关系。正如您在下面看到的,信号非常嘈杂,因此我们希望离散化特征以获得连续的特征。

  • 离散化后,我们看到 bin 2 的存活率更高:在 26 到 33 岁之间。看起来他们在疏散泰坦尼克号时优先考虑了老人和孩子。

  • 票价,就像年龄也是酌情而定的。

我们可以添加更多的转换和特性,但这里的主要目的是解释数据管道的构建块。

任务

以下是将按顺序执行的任务的描述:

  • FileExists :检查初始的 titanic 数据集是否存在。

  • 启动:将所有字符串特征(即性别)转换为数字特征,并将数据集拆分为 70/30 的训练/测试。

  • 转换:应用数据分析部分描述的转换(替换缺失值和离散化)。这些转换都应用于训练集/测试集。

  • 模型:取 2 个转换集,用 train 拟合逻辑回归,并用测试对其进行评估。

运行管道

为了能够运行管道,我们需要告诉 Luigi 模块的名称和要执行的任务。

由于依赖关系的定义,我们只需告诉 Luigi 运行最后一个任务(即模型),Luigi 就会知道如何重建图并执行所有上游任务:

PYTHONPATH='.' luigi --module pipeline Model --local-scheduler 
--input-file "../source_data/titanic.csv" --output-path "data_out"

input_file 和 output_path 是 Luigi 参数,它允许我们选择将哪个数据集推入管道,以及将所有任务输出保存在本地驱动器的什么位置。

测试管道

如上所述,CI/CD 的原则之一是实现和部署的连续流,为了允许这样的模式,我们需要引入测试来确保代码质量,并且任何代码都不会破坏管道的所有组件。

设置

使用单元测试包,设置用于运行一段将被所有单元测试使用的代码。在我们的例子中,我们使用一个我们已经准备好的测试文件来运行数据管道,这个测试文件包含了所有需要测试的不同测试用例。

测试

下面是一个已经实现单元测试的例子:

  • 测试初始数据集在训练和测试之间是否正确分离

  • 测试性别特征是否正确映射到数值

CI/CD

在 GitHub 中,您可以设置动作,动作是一组指令,当代码被推送到 repo 时将执行这些指令。

[## 功能* GitHub 操作

GitHub Actions 现在拥有世界一流的 CI/CD,可以轻松实现所有软件工作流程的自动化。构建、测试和…

github.com](https://github.com/features/actions)

GitHub Actions 允许通过 CI/CD 实现软件工作流程的自动化。

直接从 GitHub 构建、测试和部署您的代码。进行代码审查、分支管理和问题分类。

下面是一个设置示例:

将新代码推送到 repo 后,将执行 CI/CD 工作流:

工作流将安装所有需要的 Python 包,用 flake8 检查语法质量,并运行所有测试。这确保了所有推送到 repos 的新代码不会破坏现有的管道。

使用 Flowpoints 创建深度学习模型

原文:https://towardsdatascience.com/create-deep-learning-models-with-flowpoints-d9b675d0e5af?source=collection_archive---------19-----------------------

构建和分享深度学习模型的直观方式。

我经常发现自己在解释我的模型是如何工作的。有时我试图用通俗的语言来表达,有时我只是把它解释为一个黑盒,有时我画出代表神经网络部分的互连节点。

引入流动点

Flowpoints 是一个开源的在线工具,用户可以在其中以流程图的方式建立深度学习模型。

通过在神经网络(flowpoints)中创建表示操作的节点,将这些节点相互连接,并更改它们的参数,可以快速创建深度学习模型。

相应的 Python 代码可以在浏览器中查看,或者只需点击一下就可以复制到剪贴板。

通过一个菜单,您可以选择代码是使用 TensorFlow 还是 PyTorch。

…您还可以轻松创建模型的共享链接!

一个简单的例子

所以我们来试试吧!在本例中,我们将创建以下模型,该模型将在 CIFAR10 数据集上接受训练。

What the final model looks like

对于那些喜欢先吃甜点的人来说: 这里是 成品模型,这里是 这个例子的 colab。

第一:创建一个新模型

从前往流量点开始。一个相当空的用户界面应该出现在你的屏幕上。

在侧栏中,单击库下拉菜单,然后选择 TensorFlow。现在我们模型的代码将使用 TensorFlow 代替 PyTorch。

接下来,点击主题下拉菜单,选择“橙色”。这没有实际价值,但是我们在这里用风格编码。

第二:给你的模型添加一些流点

向您的模型添加一些操作。单击蓝色+按钮创建一个新的流量点。出现第一个流点应该是“输入”。这个点将被用来告诉模型我们输入的形状。我们会回来的。

不要单击任何其他地方,多单击几次+按钮。一堆流点应该一个接一个地弹出,并自动连接。

如果您缺少连接:单击您想要获取输出的流点,按住 shift,然后单击您想要连接的流点。连接应该会立即显示出来。要移除连接,只需重复此过程。

创建尽可能多的流动点,并按照您喜欢的方式排列它们。或者只是复制图中的模型。

第三:改变图层类型

现在你已经有了一大堆线性运算。那些对我们没多大帮助。是时候告诉每个流点它应该做什么了。

点击第一个流点(“输入”),并选择侧边栏中的流点选项卡。确保“n_dims”框设置为 3,并且“尺寸”显示为 32,32,3。这些是 CIFAR10 数据集中图片的尺寸。

单击下一个流点(连接到输入的流点),并单击“层类型”区域。在这里,您将更改该流点的操作。首先删除该字段中的所有文本,然后键入“Conv”。应该会出现一个操作列表,Conv2d 非常接近顶部。选择此操作。

橙色和蓝色的小徽章表示相关图层在哪个库中可用。

流点的参数应改变,以匹配 TensorFlow 中 Conv2D 运算的参数。

将所有参数设置为有意义的东西(可以使用我的型号作为例子)。

对所有流动点重复此步骤,改变它们的层类型和参数,使它们有意义。

第四:看一看代码!

单击侧边栏中的“代码”选项卡,显示您当前型号的代码。它应该是这样的:

Screenshot of the UI with the “Code”-tab open

整个代码如下所示:

The entire code for the model in this walkthrough

大功告成!

要共享或保存您的工作,请执行以下操作:在屏幕左下方的小按钮堆栈中,单击链接共享按钮。将弹出一个对话框,要求您输入密码。这可以用来保护你的模型。如果您想创建一个公共链接(就像我在这个例子中所做的那样),只需将密码字段留空即可。

要为您的模型复制代码,请单击按钮堆栈中的复制按钮。会弹出一个通知,告诉你代码已经被复制到你的剪贴板上。您可以将其直接粘贴到您的管道中。您可以在我为这个小演练创建的 colab 中找到我的模型的代码:)

感谢阅读!

欢迎分享任何反馈,如果您发现 bug(代码是开源的)可以提出新问题,或者自己添加功能和补丁!

这里是回购的链接!

从 R 创建桌面通知,以提高您的数据科学生产力

原文:https://towardsdatascience.com/create-desktop-notifications-from-r-7aeefa90d649?source=collection_archive---------20-----------------------

虽然通知会分散我们对深层工作的注意力,但如果有效处理,通知也可以帮助我们变得更有效率。桌面通知是让用户了解任务完成或一些信息的一种非常好的方式。比方说,您的模型一直在运行,最后,您只需发送 AUC 分数的通知。拥有不是很好吗?有了这个 R 包notifier,就可以做到了。

关于通知程序:

[notifier](https://github.com/gaborcsardi/notifier)是 RStudio 知名 Gábor Csárdi 的 R 包。notifier可用于在 macOS、Windows 和 Linux 上发送来自 R 的桌面通知。notifier跨平台(Windows / Mac/ Linux)运行,但以下代码是在 macOS High Sierra 机器上编写和测试的。

通知程序安装和加载

notifier目前仅在 github 上可用,因此可以使用以下代码安装:

#install.packages("devtools") if devtools is not installed
devtools::install_github("gaborcsardi/notifier")

我们可以使用下面的代码将notifier加载到当前的 R 会话中(就像其他 R 包一样)。

library(notifier)

它是如何工作的?

如文档中所述,通知是这样显示的:

  • 在 macOS 上,通知程序使用终端通知程序工具,参见https://github.com/julienXX/terminal-notifier
  • 在 Linux 和*BSD 系统(包括 Solaris)上,使用 notify-send 命令行工具。这需要 Ubuntu/Debian 和类似系统上的 libnotify-bin 包,或者 RedHat/CentOS/Fedora 和类似系统上的 libnotify 包。
  • 在 Windows 8 或更新的 Windows 版本上,通知程序使用烤面包机工具,参见https://github.com/nels-o/toaster。
  • 在较旧的 Windows 版本上,通知程序使用 notifu 程序,参见https://www.paralint.com/projects/notifu。

基本用法

notifier非常简单,用一个函数创建一个通知,或者如该函数所说,“用通知”。函数notify()有以下三个参数:

*标题—消息标题。

  • msg —实际通知消息。
    *图像—图像,以及消息—可选。

你好世界

如同每个计算机编程练习一样,让我们从一个简单的 Hello World 通知消息开始。

#composing the first notification messagenotify(
  title = "Here goes the Title",
  msg = c("Hello","World")
  )

给出此通知(屏幕截图):

稍微有用一点

现在我们已经学会了如何从 R 发送桌面通知,让我们试着让通知有一些意义和用途。我能立即想到的是一个世界时钟或不同国家的时间。下面是我们如何做到这一点的代码。

这段代码只是获取当前的系统时间,并按照各自的时区对其进行格式化。记住,参数msg只接受字符类型,因此我们需要将日期类型转换为字符类型,默认情况下,我们已经使用了paste0

#composing a slightly complex and also useful notificationnotify(
  title = "World Clock",
  msg = c(paste0(" India - ", format(Sys.time(), format = "%H:%M:%S" ,tz = "Asia/Calcutta"),"\n",
                 paste0("Singapore - ", format(Sys.time(), format = "%H:%M:%S" ,tz = "Asia/Singapore"),"\n"))
          )
)

给出此通知(屏幕截图):

激励通知

由于我们已经使用 base-R 函数创建了一个稍微有意义的通知,让我们升级到一个可以激励我们的好通知——以引用的形式。为此,我们将使用另一个 R 包— randquotes 。

#composing a different use-case notification library(randquotes)
notify(
  title = "Quote of the Day",
  msg = c(randquote_simple())
)

给出此通知(屏幕截图):

进一步改进

通过使用 Task Scheduler(在 Windows 上)或 Shell Scripting Automation(在 Linux/Mac 上)定期自动发送通知,比如每天早上显示报价通知,可以进一步改善这种情况。

摘要

我希望这篇文章能帮助你了解这个 R 包通知程序,它使得从 R 发送桌面通知成为可能——我甚至不知道这是可能的。这篇文章中使用的完整代码可以在我的 github 上找到。如果你对学习处理 web 数据感兴趣,可以看看这篇关于处理 Web 数据的教程

请在评论中告诉我们你想尝试或已经尝试过的通知!

本文原载于 DS+

使用{fakir}创建虚假但有意义的数据

原文:https://towardsdatascience.com/create-fake-but-meaningful-data-using-fakir-b193df1f4c94?source=collection_archive---------25-----------------------

数据科学或机器学习新手面临的一个问题是,为你想教/学/实验的一组正确的问题找到一组正确的数据集。假设您想要教授时间序列,在这种情况下,您的垃圾邮件/火腿分类数据集将没有任何用处。你必须求助于提供数据集的社区,比如著名的 UCI ML repo 或 Kaggle 数据集。如果您只想在您的环境中快速创建一个虚假但有意义的数据集,该怎么办?

解决办法

这就是fakir来帮助我们的地方。fakir是由 科林·费伊(Think-R 的)制作的 R-package,他对 R 社区的贡献一直很好。

关于 fakir

正如文档中所说,fakir的目标是提供可以用来教授 r 的假数据集

安装和装载

fakir可以从 Github 安装(fakir在 CRAN 上还不可用)

# install.packages("devtools")
devtools::install_github("ThinkR-open/fakir")library(fakir)

用例:点击流/ Web 数据

点击流/网络数据是目前许多组织在分析中使用的一种东西,但很难获得一些点击流数据,因为没有公司愿意分享他们的数据。Google Analytics 测试帐户上有一个样本数据,但这可能对你在 R 或 R 的生态系统中学习数据科学没有任何作用。

这是一个典型的fakir可以帮助你的案例

library(tidyverse)
fakir::fake_visits() %>% head()## # A tibble: 6 x 8
##   timestamp   year month   day  home about  blog contact
##   <date>     <dbl> <dbl> <int> <int> <int> <int>   <int>
## 1 2017-01-01  2017     1     1   352   176   521      NA
## 2 2017-01-02  2017     1     2   203   115   492      89
## 3 2017-01-03  2017     1     3   103    59   549      NA
## 4 2017-01-04  2017     1     4   484   113   633     331
## 5 2017-01-05  2017     1     5   438   138   423     227
## 6 2017-01-06  2017     1     6    NA    75   478     289

这就是用fakir获得点击流样本(整理)数据的简单方法。另一件值得一提的事情是,如果你看一下fake_visits()文档,你会发现有一个带seed值的参数,这意味着,你控制着数据的随机化和复制。

fake_visits(from = "2017-01-01", to = "2017-12-31", local = c("en_US", "fr_FR"), 
    seed = 2811) %>% head()## # A tibble: 6 x 8
##   timestamp   year month   day  home about  blog contact
##   <date>     <dbl> <dbl> <int> <int> <int> <int>   <int>
## 1 2017-01-01  2017     1     1   352   176   521      NA
## 2 2017-01-02  2017     1     2   203   115   492      89
## 3 2017-01-03  2017     1     3   103    59   549      NA
## 4 2017-01-04  2017     1     4   484   113   633     331
## 5 2017-01-05  2017     1     5   438   138   423     227
## 6 2017-01-06  2017     1     6    NA    75   478     289

用例:法国数据

此外,在上述fake_visits()函数的用法中,您可能已经注意到另一个属性local,它可以帮助您选择French数据而不是英语。在我个人看来,如果你的任务是提高数据素养或使数据科学民主化,这是至关重要的。

fake_ticket_client(vol = 10, local = "fr_FR") %>% head()## # A tibble: 6 x 25
##   ref   num_client prenom nom   job     age region id_dpt departement
##   <chr> <chr>      <chr>  <chr> <chr> <dbl> <chr>  <chr>  <chr>      
## 1 DOSS… 31         Const… Boul… <NA>     62 Lorra… 88     Vosges     
## 2 DOSS… 79         Martin Norm… Cons…    52 Midi-… 46     Lot        
## 3 DOSS… 65         Phili… Géra… <NA>     28 Prove… 84     Vaucluse   
## 4 DOSS… 77         Simon… Cour… Plom…    29 Prove… 83     Var        
## 5 DOSS… 59         Rémy   Dela… <NA>     18 Breta… 29     Finistère  
## 6 DOSS… 141        Astrid Dumo… Ingé…    35 Midi-… 46     Lot        
## # … with 16 more variables: gestionnaire_cb <chr>, nom_complet <chr>,
## #   entry_date <dttm>, points_fidelite <dbl>, priorite_encodee <dbl>,
## #   priorite <fct>, timestamp <date>, annee <dbl>, mois <dbl>, jour <int>,
## #   pris_en_charge <chr>, pris_en_charge_code <int>, type <chr>,
## #   type_encoded <int>, etat <fct>, source_appel <fct>

在上面的例子中,我们使用了 fakir 的另一个函数fake_ticket_client(),它帮助我们给出一个典型的票务数据集(就像你从 ServiceNowZendesk 得到的那个)

用例:散点图

如果你厌倦了只使用iris数据集来演示或教授散点图,而你需要至少两个连续变量,现在我们可以用fakir的数据集来克服它。

fake_visits() %>% 
  ggplot() + geom_point(aes(blog,about, color = as.factor(month)))## Warning: Removed 47 rows containing missing values (geom_point).

(也许,不是一个很好的散点图来显示相关性,但嘿,你可以教散点图没有绘制花瓣长度和萼片长度)

摘要

如果你从事教学工作或者喜欢实验,并且不想使用陈词滥调的数据集,那么fakir是一个非常好的软件包。正如fakir包的作者在描述中提到的,[charlatan](https://github.com/ropensci/charlatan)是另一个这样的 R 包,它帮助生成有意义的虚假数据。

参考

  • [fakir](https://github.com/ThinkR-open/fakir) - Github
  • [fakir](https://thinkr-open.github.io/fakir/) -文档

如果你喜欢这个,请订阅我的 语言无关的数据科学时事通讯 并与你的朋友分享!

最初发表于programmingwithr.com, 经许可转贴

如何使用 JavaScript 创建简单的甘特图

原文:https://towardsdatascience.com/create-javascript-gantt-chart-55ff8ec08886?source=collection_archive---------3-----------------------

U 阿瑟 JavaScript 库创建甘特图,让您的项目管理更上一层楼

Source: Pexels

今年早些时候,我的团队正在寻找一个项目管理工具,它可以帮助我们根据一些特定的时间表绘制与我们的应用程序开发项目相关的各种任务。做了一些研究后,我们最终选定了甘特图。

然而,有些人认为 Gantts 很难制作。

不是真的!

感谢众多的 JavaScript 图表库,数据可视化现在变得简单、灵活、可嵌入。

在我们的情况下,我们选择了 AnyChart 的 JS Charts 库,因为它易于使用,文档丰富,用于试验的灵活代码平台,以及其他强大的功能。

在本教程中,我将带您了解如何使用这个数据可视化库创建一个简单的交互式甘特图。

这是我们将要制作的东西,你可以在教程的最后获得创建这样一个甘特图的完整代码:

用 4 个步骤创建 JS 甘特图

让我们动手使用 JavaScript 库创建一个简单的甘特图来安排和监控项目活动。

在本 JS 图表教程中,我们将遵循以下四个步骤:

  • 第一步:准备数据
  • 第二步:获取依赖关系
  • 第三步:声明图表容器
  • 第四步:渲染甘特图

步骤 1:准备数据

使用 JavaScript 构建甘特图的第一步是准备将要显示的数据。AnyChart 库要求使用树数据模型来表示数据。

在这个模型中,数据被组织成一个分层的树状结构,其中父子关系用于连接各种数据项。

因此,父数据项将有一个数据字段,其中子数据项被表示为一个数组。

让我给你看一个例子来说明我所说的:

var data = [{
	id: "1",
	name: "Development Life Cycle",
	actualStart: Date.UTC(2018, 01, 02),
	actualEnd: Date.UTC(2018, 06, 15),
	children: [{
			id: "1_1",
			name: "Planning",
			actualStart: Date.UTC(2018, 01, 02),
			actualEnd: Date.UTC(2018, 01, 22),
			connectTo: "1_2",
			connectorType: "finish-start",
			progressValue: "75%"
		},
		// more data goes here
	]
}];

步骤 2:获取依赖关系

AnyChart 利用了一种极简的、基于模块的方法,让您只获得那些对您的项目来说必不可少的依赖项,这极大地缩小了部署代码的大小,从而提高了性能。

为了创建甘特图,我们将在网页的 <标题> 部分添加以下核心和甘特图模块。

<head>
<script src="https://cdn.anychart.com/releases/8.6.0/js/anychart-core.min.js"> </script> 
<script src ="https://cdn.anychart.com/releases/8.6.0/js/anychart-gantt.min.js"></script>
</head>

步骤 3:声明图表容器

然后,让我们创建一个容器,甘特图将加载到其中。

<body><div id="container"></div><body>

注意,我已经给出了“容器”的 < div > 元素和 id 以供下一步引用。

步骤 4:呈现甘特图

最后,我们将按照以下步骤呈现甘特图:

  • 通过将准备好的数据传递给 anychart.data.tree() 方法来创建数据树。对于第二个参数,我们将其指定为“as-tree”
var treeData = anychart.data.tree(data, "as-tree");
  • 通过调用 anychart.ganttProject() 图表构造函数创建项目甘特图:
var chart = anychart.ganttProject();
  • 通过将创建的数据树传递给图表的 data() 方法来设置数据:
chart.data(treeData);
  • 将时间线的刻度配置到项目结束的日期:
chart.getTimeline().scale().maximum(Date.UTC(2018, 06, 30));
  • 引用我们之前设置的图表容器 id :
chart.container("container");
  • 开始绘制图表:
chart.draw();
  • 将指定的活动放在时间线的宽度内:
chart.fitAll();

下面是我用来创建上图中的甘特图的全部代码:

(也可以在 this CodePen repository 上查看代码)。

<html>
<head>
<script src="https://cdn.anychart.com/releases/8.6.0/js/anychart-core.min.js"> </script> 
<script src ="https://cdn.anychart.com/releases/8.6.0/js/anychart-gantt.min.js"></script>
</head><body><div id = "container" > </div><script>anychart.onDocumentReady(function () {
	// create data
	var data = [{
		id: "1",
		name: "Development Life Cycle",
		actualStart: Date.UTC(2018, 01, 02),
		actualEnd: Date.UTC(2018, 06, 15),
		children: [{
				id: "1_1",
				name: "Planning",
				actualStart: Date.UTC(2018, 01, 02),
				actualEnd: Date.UTC(2018, 01, 22),
				connectTo: "1_2",
				connectorType: "finish-start",
				progressValue: "75%"
			},
			{
				id: "1_2",
				name: "Design and Prototyping",
				actualStart: Date.UTC(2018, 01, 23),
				actualEnd: Date.UTC(2018, 02, 20),
				connectTo: "1_3",
				connectorType: "start-start",
				progressValue: "60%"
			},
			{
				id: "1_3",
				name: "Evaluation Meeting",
				actualStart: Date.UTC(2018, 02, 23),
				actualEnd: Date.UTC(2018, 02, 23),
				connectTo: "1_4",
				connectorType: "start-start",
				progressValue: "80%"
			},
			{
				id: "1_4",
				name: "Application Development",
				actualStart: Date.UTC(2018, 02, 26),
				actualEnd: Date.UTC(2018, 04, 26),
				connectTo: "1_5",
				connectorType: "finish-finish",
				progressValue: "90%"
			},
			{
				id: "1_5",
				name: "Testing",
				actualStart: Date.UTC(2018, 04, 29),
				actualEnd: Date.UTC(2018, 05, 15),
				connectTo: "1_6",
				connectorType: "start-finish",
				progressValue: "60%"
			},
			{
				id: "1_6",
				name: "Deployment",
				actualStart: Date.UTC(2018, 05, 20),
				actualEnd: Date.UTC(2018, 05, 27),
				connectTo: "1_7",
				connectorType: "start-finish",
				progressValue: "100%"
			},
			{
				id: "1_7",
				name: "Maintenance",
				actualStart: Date.UTC(2018, 05, 30),
				actualEnd: Date.UTC(2018, 06, 11),
				progressValue: "40%"
			},

		]
	}];
	// create a data tree
	var treeData = anychart.data.tree(data, "as-tree");

	// create a chart
	var chart = anychart.ganttProject();

	// set the data
	chart.data(treeData); // configure the scale
	chart.getTimeline().scale().maximum(Date.UTC(2018, 06, 30)); // set the container id
	chart.container("container"); // initiate drawing the chart
	chart.draw(); // fit elements to the width of the timeline
	chart.fitAll();
});</script>
</body>
</html>

自定义甘特图设计

AnyChart 提供了广泛的选项来定制数据可视化的设计,以满足您的个人偏好和需求。在数据域中,可以设置各种属性来自定义甘特图的外观。

例如,以下是我在上述甘特图示例中指定的一些数据字段:

  • id —设置每个任务的唯一标识符;
  • 名称 —设置每个任务的名称;
  • actualStart —设置每项任务的开始日期;
  • 实际结束 —设置每个任务的结束日期;
  • connectTo —是一种设置目标任务的连接器;
  • 连接器类型 —设置连接器的类型,可以是“开始-开始”、“开始-结束”、“结束-开始”或“结束-结束”;
  • 进度值 —以百分比形式设置每个任务的进度值。

此外,AnyChart 允许以下类型的任务,这些任务可以用不同的方式可视化:

  • 常规任务 —与其他任务没有关系;
  • 父任务 —与其他任务有父子关系;
  • 里程碑 —可视化持续时间为零的事件。它们可以通过在实际开始实际结束字段上设置相同的日期来指定。

将数据作为表加载

如果您想通过从关系数据库加载数据来创建图表,您可以将数据组织为带有父/子链接的表格

在这种情况下,每个项目的字段应该指定其父 id 值。此外,您应该将根项目的父项设置为 null、或者不指定它。

这就是我所说的:

(你也可以在 this CodePen repository 上查看代码)。

var data = [{
		id: 1,
		parent: null,
		name: "Root",
		actualStart: Date.UTC(2018, 01, 02),
		actualEnd: Date.UTC(2018, 06, 15),
	},
	{
		id: 2,
		parent: 1,
		name: "Parent 1",
		actualStart: Date.UTC(2018, 01, 02),
		actualEnd: Date.UTC(2018, 01, 22),
		progressValue: "90%"
	},
	{
		id: 3,
		parent: 2,
		name: "Child 1–1",
		actualStart: Date.UTC(2018, 01, 23),
		actualEnd: Date.UTC(2018, 02, 20),
		progressValue: "75%"
	},
	{
		id: 4,
		parent: 2,
		name: "Child 1–2",
		actualStart: Date.UTC(2018, 02, 23),
		actualEnd: Date.UTC(2018, 02, 23),
		progressValue: "60%"
	},
	{
		id: 5,
		parent: 1,
		name: "Parent 2",
		actualStart: Date.UTC(2018, 02, 26),
		actualEnd: Date.UTC(2018, 04, 26),
		progressValue: "80%"
	},
	{
		id: 7,
		parent: 6,
		name: "Child 2–1",
		actualStart: Date.UTC(2018, 04, 29),
		actualEnd: Date.UTC(2018, 05, 15),
		progressValue: "30%"
	},
];

另外,当您以表的形式加载数据时,不要忘记将 anychart.data.tree() 方法中的第二个参数从“as-tree”更改为“as-table”,因此整行如下所示:

var treeData = anychart.data.tree(data, "as-table");

以下是以表格形式加载数据时创建的甘特图的屏幕截图:

结论

就是这样!

如您所见,使用 AnyChart JavaScript 图表库创建甘特图简单而直接。

在本教程中,我只是简单介绍了甘特图的一些功能。我希望你已经了解了这种图表的惊人能力,以及它如何帮助你管理你的 web 开发任务。

当然,你可以看看易于遵循的 AnyChart 的甘特图文档,以了解更多调整甘特图以适应你的设计要求的方法,并帮助你跟踪你的项目管理活动。

万事如意。

用插入符号在 R 中创建预测模型

原文:https://towardsdatascience.com/create-predictive-models-in-r-with-caret-12baf9941236?source=collection_archive---------3-----------------------

Caret 是 C 分类AndREgressionTraining。它是一个完整的包,涵盖了创建机器学习预测模型的所有阶段。在本教程中,我将解释以下主题:

  1. 如何安装 caret
  2. 如何创建简单的模型
  3. 如何使用交叉验证来避免过度拟合
  4. 如何向数据添加简单的预处理
  5. 如何为您选择的模型找到最佳参数
  6. 如何查看模型中最重要的特征/变量
  7. 如何使用你的模型来预测

安装

安装 caret 就像在 r 中安装任何其他包一样简单。如果你使用的是 RStudio(推荐),你也可以点击工具栏中的“工具”>“安装包…”来安装它。

install.packages("caret")

创建简单的模型

我们将通过使用 train() 函数来实现这一点。函数 train() 是 caret 的核心函数。顾名思义,它用于训练模型,即将算法应用于一组数据,并创建代表该数据集的模型。

train()函数有三个基本参数:

  1. 公式
  2. 资料组
  3. 方法(或算法)

公式参数是你指定什么是因变量(你要预测的)和自变量(特性)的地方。下面我会详细解释如何写你的公式。

数据集参数是您的数据。

方法参数是指定使用哪个分类或回归模型的字符串。

在本教程中,我将使用 mtcars 数据集。它是内置的 R 数据集之一。下面是关于这个数据集的解释:

汽车趋势道路测试(mtcars)

描述

该数据摘自 1974 年的《美国汽车趋势》杂志,包括 32 款汽车(1973-74 款)的油耗以及汽车设计和性能的 10 个方面。

用 11 个变量的 32 个观察值格式化一个数据框。

  1. mpg:英里/(美国)加仑
  2. cyl:气缸数量
  3. disp:排量(立方英寸)
  4. 马力:总马力
  5. drat:后桥传动比
  6. 重量:重量(1000 磅)
  7. qsec: 1/4 英里时间
  8. vs: V/S
  9. am:变速器(0 =自动,1 =手动)
  10. 档位:前进档的数量
  11. 碳水化合物:化油器数量

让我们来看看数据框。

data(mtcars)    *# Load the dataset*
head(mtcars)

?mtcars         *# Get more information about this dataset*

现在,让我们创建回归模型,根据其他属性预测汽车模型可以行驶多少英里每加仑(mpg)。

公式可以写成“ x ~ y,z,w”其中 x 是因变量,我们这里是 mpg,y,z,w 是自变量。如果你想传递所有的属性,你可以把它写成“ x ~。****。

**library**(caret)*# Simple linear regression model (lm means linear model)*
model <- train(mpg ~ wt,
               data = mtcars,
               method = "lm")

*# Multiple linear regression model*
model <- train(mpg ~ .,
               data = mtcars,
               method = "lm")

*# Ridge regression model*
model <- train(mpg ~ .,
               data = mtcars,
               method = "ridge") *# Try using "lasso"*

这就是如何使用函数 train() 创建不同的基本模型。很简单,不是吗?

k 倍交叉验证

函数 train() 有其他可选参数。让我们学习如何通过向我们的 train() 函数添加参数tr control(train control)来向我们的模型添加重采样。

重采样过程可以通过使用 K 重交叉验证、留一交叉验证或引导来完成。在这个例子中,我们将使用 10 重交叉验证。为此,我们需要使用另一个插入符号函数, trainControl() 。检查下面的代码。

*## 10-fold CV**# possible values: boot", "boot632", "cv", "repeatedcv", "LOOCV", "LGOCV"* fitControl <- trainControl(method = "repeatedcv",   
                           number = 10,     *# number of folds*
                           repeats = 10)    *# repeated ten times*

model.cv <- train(mpg ~ .,
               data = mtcars,
               method = "lasso",  *# now we're using the lasso method*
               trControl = fitControl)  

model.cv ## The lasso 
## 
## 32 samples
## 10 predictors
## 
## No pre-processing
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 28, 30, 28, 28, 29, 29, ... 
## Resampling results across tuning parameters:
## 
##   fraction  RMSE      Rsquared   MAE     
##   0.1       4.660950  0.8873870  3.841383
##   0.5       2.824138  0.8735388  2.468004
##   0.9       3.243825  0.8400985  2.797594
## 
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was fraction = 0.5.

添加预处理

train() 函数还有另一个可选参数叫做预处理。它用于为您的数据添加一些预处理。

在本例中,我们将使用以下预处理:

  1. 中心数据(即计算每列的平均值,并从每个相应的值中减去它);
  2. 缩放数据(即将所有数据放在同一个刻度上,例如从 0 到 1 的刻度)

但是,还有更多的预处理可能性,如“BoxCox”、“YeoJohnson”、“expoTrans”、“range”、“knnImpute”、“bagImpute”、“medianImpute”、“pca”、“ica”和“spatialSign”。

model.cv <- train(mpg ~ .,
               data = mtcars,
               method = "lasso",
               trControl = fitControl,
               preProcess = c('scale', 'center')) *# default: no pre-processing*

?train    # if you need more information about the train function model.cv## The lasso 
## 
## 32 samples
## 10 predictors
## 
## Pre-processing: scaled (10), centered (10) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 29, 30, 29, 28, 29, 29, ... 
## Resampling results across tuning parameters:
## 
##   fraction  RMSE      Rsquared   MAE     
##   0.1       4.597673  0.9072492  3.821535
##   0.5       2.755728  0.8968303  2.411330
##   0.9       3.183950  0.8820037  2.778551
## 
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was fraction = 0.5.

寻找模型超参数

通过使用 tuneGrid 参数,我们可以找到模型的最佳超参数。该参数接收具有可能调谐值的数据帧。dataframe 列的名称与优化参数的名称相同。

为了生成可能的值,我将使用基本库中的 expand.grid 函数。为了解释 tuneGrid 的用法,我将使用岭回归法。

简短解释

随着λ的增长,岭方法将预测变量的系数向 0 收缩。收缩效应降低了模型的灵活性,也降低了其方差,但增加了偏差。岭回归的思想是找到λ的值,该值是偏差和方差之间令人满意的折衷。

使用下面的代码,我们可以找到 10^-2 到 10^10.之间岭回归的最佳 lambda 参数

*# Here I generate a dataframe with a column named lambda with 100 values that goes from 10^10 to 10^-2*
lambdaGrid <- expand.grid(lambda = 10^seq(10, -2, length=100))

model.cv <- train(mpg ~ .,
               data = mtcars,
               method = "ridge",
               trControl = fitControl,
               preProcess = c('scale', 'center'),
               tuneGrid = lambdaGrid,   *# Test all the lambda values in the lambdaGrid dataframe*
               na.action = na.omit)   *# Ignore NA values*

model.cv ## Ridge Regression 
## 
## 32 samples
## 10 predictors
## 
## Pre-processing: scaled (10), centered (10) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 28, 29, 28, 29, 30, 28, ... 
## Resampling results across tuning parameters:
## 
##   lambda        RMSE       Rsquared   MAE      
##   1.000000e-02   3.133764  0.8542752   2.700711
##   1.321941e-02   3.097225  0.8559508   2.670390
##   1.747528e-02   3.057315  0.8583961   2.637061
##   2.310130e-02   3.015005  0.8621809   2.600386
##   3.053856e-02   2.971543  0.8672769   2.562851... # too much output so i cut it out##   1.000000e+10  25.370412  0.8901093  23.047829
## 
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was lambda = 0.1629751.

当您调用 model.cv 时,您可以看到您测试的每个 lambda 值的度量 RMSE、Rsquared 和 MAE,并且模型还输出测试值中 lambda 的最佳选择。在这种情况下,λ= 0.1629751。

还有另一种搜索超参数的方法,不需要将值列表传递给 train() 函数。我们可以在 trainControl() 中使用 search = "random" ,该函数将自动测试一系列值。

fitControl <- trainControl(*## 10-fold CV*
                           method = "repeatedcv",
                           number = 10,
                           repeats = 10,
                           search = "random")  *# hyper-parameters random search* 

model.cv <- train(mpg ~ .,
               data = mtcars,
               method = "ridge",
               trControl = fitControl,
               preProcess = c('scale', 'center'),
               na.action = na.omit)

model.cv## Ridge Regression 
## 
## 32 samples
## 10 predictors
## 
## Pre-processing: scaled (10), centered (10) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 28, 29, 29, 29, 28, 28, ... 
## Resampling results across tuning parameters:
## 
##   lambda        RMSE       Rsquared   MAE      
##   7.830203e-05   3.428075  0.8533706   2.950310
##   9.214823e-05   3.427668  0.8533953   2.949997
##   8.645309e+00  15.314730  0.9024834  13.994384
## 
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was lambda = 9.214823e-05.

可变重要性

现在,让我们学习如何查看哪些是我们模型中最重要的变量。我们可以使用插入符号函数 varImpvarImp 的返回可以传递给函数 ggplot 以生成可视化。

ggplot(varImp(model.cv))

正如我们在图中看到的,位移变量对我们的预测模型最重要。

预言

最后,我们可以使用函数 predict 来预测汽车的性能,即每加仑汽油可以行驶多少英里。我将传递与生成模型相同的数据帧作为参数,只是为了展示函数是如何工作的。

在一个真实的项目中,你会使用一个更大的数据帧,并把它分成一个训练集和一个测试集,但这不是这里的目的。

predictions <- predict(model.cv, mtcars)

predictions##           Mazda RX4       Mazda RX4 Wag          Datsun 710 
##            22.59767            22.11103            26.25381 
##      Hornet 4 Drive   Hornet Sportabout             Valiant 
##            21.23520            17.69025            20.38318 
##          Duster 360           Merc 240D            Merc 230 
##            14.38382            22.49686            24.41665 
##            Merc 280           Merc 280C          Merc 450SE 
##            18.70104            19.19260            14.17669 
##          Merc 450SL         Merc 450SLC  Cadillac Fleetwood 
##            15.60112            15.74344            12.03039 
## Lincoln Continental   Chrysler Imperial            Fiat 128 
##            10.93585            10.49555            27.77480 
##         Honda Civic      Toyota Corolla       Toyota Corona 
##            29.89355            29.51135            23.64401 
##    Dodge Challenger         AMC Javelin          Camaro Z28 
##            16.94227            17.73144            13.30775 
##    Pontiac Firebird           Fiat X1-9       Porsche 914-2 
##            16.68855            28.29431            26.15559 
##        Lotus Europa      Ford Pantera L        Ferrari Dino 
##            27.63590            18.87023            19.69368 
##       Maserati Bora          Volvo 142E 
##            13.93917            24.37227

您可以将预测值与真实值进行比较。有一些指标可以用来判断你的模型是否是一个好的预测器,但是我们不打算在这里深入讨论。

感谢您的阅读。我希望这是一次有益而愉快的阅读。

在 Luigi 中创建您的第一个 ETL

原文:https://towardsdatascience.com/create-your-first-etl-in-luigi-23202d105174?source=collection_archive---------10-----------------------

本帖是 数据工程系列 的一部分。

在以前的帖子中,我讨论了用 Bonobo、Spark 和 Airflow 编写 ETL。在这篇文章中,我将介绍另一个由 Spotify 开发的 ETL 工具,名为 Luigi

之前我已经讨论过关于编写基本 ETL 管道的这里,这里这里和这里。Bonobo 在编写 ETL 管道方面很酷,但是这个世界并不全是编写 ETL 管道来实现自动化。还有一些其他的用例,在这些用例中,您必须按照一定的顺序执行任务一次或者定期执行。例如:

  • 监控 Cron 作业
  • 将数据从一个地方传输到另一个地方。
  • 自动化您的开发运维。
  • 定期从网站上获取数据,并为你令人敬畏的价格比较系统更新数据库。
  • 基于推荐系统的数据处理。
  • 机器学习管道。

可能性是无限的。

在我们进一步在我们的系统中实现 Luigi 之前,让我们讨论一下什么是气流及其术语。

什么是路易吉?

来自 Github 页面:

Luigi 是一个 Python (2.7、3.6、3.7 测试版)包,可以帮助你构建复杂的批处理作业管道。它处理依赖关系解析、工作流管理、可视化、处理故障、命令行集成等等。

让我们学习和理解基本组件和术语。

  • 目标:- 简单来说,一个目标持有一个任务的输出。目标可以是本地(例如:文件)、HDFS 或 RDBMS(MySQL 等)
  • 任务是实际工作发生的地方。任务可以是独立的,也可以是从属的。相关任务的示例是将数据转储到文件或数据库中。在加载数据之前,数据必须以任何方式存在(抓取、API 等)。每个任务都表示为一个 Python 类,其中包含某些强制成员函数。任务函数包含以下方法:
  • requires():-task 类的这个成员函数包含了当前任务之前必须执行的所有任务实例。在我上面分享的例子中,一个名为 ScrapeData 的任务将包含在requires()方法中,因此使一个任务成为一个依赖任务。
  • output():- 这个方法包含了任务输出将被存储的目标。这可能包含一个或多个目标对象。
  • run():- 这个方法包含了运行任务的实际逻辑。

图示将如下所示:

我们先写一个玩具 ETL。它什么也不做,只是把 Hello World 放到一个文本文件中,然后用你输入的名字替换 World。

第一个类或任务HelloWorld是 ETL 的提取部分,假设文本为 Hello World!来自外部来源(API、DB 等)并存储在文件helloworld.txt中。output()方法设定目标。因为目标是文件名为helloworld.txt的本地文件LocalTargetrun方法负责所有的处理逻辑。因为这个任务不依赖于任何任务,所以requires()返回一个None

第二个类NameSubstituter可以被认为是一个将原始文本转换成其他内容并保存到另一个文本文件中的类。因此,这个类(任务)负责 ETL 的 TL 部分。

name = luigi.Parameter()是将 ETL 参数化,便于从外部数据源接受数据。infile.read()从传入文件中读取数据,在我们的例子中,它是helloworld.txt和内容 Hello World!被保存在一个text变量中。文本世界,然后被替换为输入名称。文件名也遵循在output()方法中设置的特定格式。

好了,代码准备好了。是时候运行它了。我转到命令行并运行以下命令:

python luigitutorial.py --scheduler-host localhost NameSubstituter

哎呀!它坠毁了!

如您所见,错误消息很清楚:需要设置‘name’参数。

我们必须传递 name 参数。为此,我们将采取以下措施:

python luigitutorial.py --scheduler-host localhost NameSubstituter --name Adnan

你能看到笑脸符号吗?一切顺利!

现在让我解释一下这个命令。Luigi 使用一种不同的调度程序来调度作业。出于开发目的,使用了--local-schedular,但是如果您希望可视化监控过程,那么您应该使用--schedular-host在基于 web 的界面上监控它。确保运行运行本地 web 服务器的luigid守护进程。如果你不设置--schedular-host,它仍然会运行,但是你不能监控正在运行的任务,所以一定要小心!如果所有的点都连接得很好,你可以通过访问[http://localhost:8082/](http://localhost:8082/)来了解事情的进展

在访问中,您可以看到如下屏幕:

任务正在运行,您可以看到状态。万一你想知道我为什么加了sleep,你现在就可以猜到了。如果不增加延迟,你就无法想象它,因为它会执行得非常快。此外,请注意在细节部分中带有参数的NameSubstituter类的多个条目。这是因为它们被认为是独特的工作,而 HelloWorld 却不是。

如果您单击单个任务,您可以看到任务的依赖关系图。类似于气流。

您会看到文件名附加了输入名称。如果您还记得,我们已经这样设置了文件名。这是不必要的,你可以选择任何你想要的,因为我自己从一个例子。

哦,对了,任务运行一次。并不是每次运行都会生成文件。如果你想有一个新的开始,而不仅仅是删除所有的输入和输出文件。在这个例子中,例如,如果您想重新运行名为 Adnan 的 ETL,那么只需删除helloworld.txt.name_Adnan,而不是所有文件。如果您的输入文件内容被更改,那么也删除它。

结论

因此,您了解了 Luigi 如何使编写满足您需求的 ETL 变得更加容易。在下一部分中,我们将讨论一个真实世界的例子,就像我们对 Apache Airflow 所做的那样。像往常一样,代码可以在 Github 获得。

原载于 2019 年 11 月 18 日http://blog . adnansiddiqi . me

用 Apache Spark 和 Python 创建您的第一个 ETL 管道

原文:https://towardsdatascience.com/create-your-first-etl-pipeline-in-apache-spark-and-python-ec3d12e2c169?source=collection_archive---------1-----------------------

在这篇文章中,我将讨论 Apache Spark 以及如何在其中创建简单而健壮的 ETL 管道。您将了解 Spark 如何提供 API 来将不同的数据格式转换成数据框架和 SQL 以便进行分析,以及如何将一个数据源转换成另一个数据源。

什么是阿帕奇火花?

据维基百科:

Apache Spark 是一个开源的分布式通用集群计算框架。Spark 提供了一个接口,通过隐式数据并行和容错对整个集群进行编程。

来自官网:

Apache Spark 是用于大规模数据处理的统一分析引擎。

简而言之,Apache Spark 是一个用于处理、查询和分析大数据的框架。由于计算是在内存中完成的,因此它比竞争对手如 MapReduce 等快几倍。每天产生万亿字节数据的速度,需要一种能够高速提供实时分析的解决方案。Spark 的一些功能包括:

  • 比传统的大规模数据处理框架快 100 倍。
  • 易于使用,因为您可以用 Python、R 和 Scala 编写 Spark 应用程序。
  • 它为 SQL、流和图形计算提供了库。

Apache Spark 组件

火花核心

它包含 Spark 的基本功能,如任务调度、内存管理、与存储的交互等。

Spark SQL

它是一组用于与结构化数据交互的库。它使用类似 SQL 的接口与各种格式的数据进行交互,如 CSV、JSON、Parquet 等。

火花流

Spark 流是一个 Spark 组件,支持实时数据流的处理。实时流,如股票数据、天气数据、日志和各种其他内容。

MLib

MLib 是 Spark 提供的一组机器学习算法,用于监督和非监督学习

GraphX

它是 Apache Spark 用于图形和图形并行计算的 API。它扩展了 Spark RDD API,允许我们创建一个带有附加到每个顶点和边的任意属性的有向图。它为 ETL、探索性分析和迭代图计算提供了统一的工具。

Spark 集群管理器

Spark 支持以下资源/集群管理器:

  • Spark Standalone—Spark 附带的一个简单的集群管理器
  • Apache Mesos —一个通用的集群管理器,也可以运行 Hadoop 应用。
  • Apache Hadoop YARN—Hadoop 2 中的资源管理器
  • Kubernetes —一个用于自动化部署、扩展和管理容器化应用程序的开源系统。

设置和安装

从这里下载 Apache Spark 的二进制文件。您必须在系统上安装 Scala,并且还应该设置它的路径。

对于本教程,我们使用的是 2019 年 5 月发布的 2.4.3 版本。移动/usr/local中的文件夹

mv spark-2.4.3-bin-hadoop2.7 /usr/local/spark

然后导出 Scala 和 Spark 的路径。

#Scala Path
export PATH="/usr/local/scala/bin:$PATH"#Apache Spark path
export PATH="/usr/local/spark/bin:$PATH"

通过在终端上运行spark-shell命令来调用 Spark Shell。如果一切顺利,您将看到如下内容:

它加载基于 Scala 的 shell。既然我们要使用 Python 语言,那么我们必须安装 PySpark

pip install pyspark

一旦安装完成,你可以在你的终端上运行命令pyspark来调用它:

您会发现一个典型的 Python shell,但是它加载了 Spark 库。

Python 开发

让我们开始写我们的第一个程序。

from pyspark.sql import SparkSession
from pyspark.sql import SQLContextif __name__ == '__main__':
    scSpark = SparkSession \
        .builder \
        .appName("reading csv") \
        .getOrCreate()

我们导入了两个库:SparkSessionSQLContext

SparkSession 是编程 Spark 应用程序的入口点。它允许您与 Spark 提供的DataSetDataFrameAPI 进行交互。我们通过调用appName来设置应用程序名称。getOrCreate()方法要么返回应用程序的新 SparkSession,要么返回现有的 spark session。

我们的下一个目标是读取 CSV 文件。我已经创建了一个示例 CSV 文件,名为data.csv,如下所示:

name,age,country
adnan,40,Pakistan
maaz,9,Pakistan
musab,4,Pakistan
ayesha,32,Pakistan

代码是:

if __name__ == '__main__':
    scSpark = SparkSession \
        .builder \
        .appName("reading csv") \
        .getOrCreate()data_file = '/Development/PetProjects/LearningSpark/data.csv'
    sdfData = scSpark.read.csv(data_file, header=True, sep=",").cache()
    print('Total Records = {}'.format(sdfData.count()))
    sdfData.show()

我设置了文件路径,然后调用.read.csv来读取 CSV 文件。参数是不言自明的。.cache()缓存返回的结果集,从而提高性能。当我运行该程序时,它会返回如下内容:

看起来很有趣,不是吗?现在,如果我想读取一个数据帧中的多个文件呢?让我们创建另一个文件,我将其命名为data1.csv,如下所示:

1

2

3

4

5

姓名,年龄,国家

诺琳,23 岁,英国

阿米尔,9 岁,巴基斯坦

诺曼,4 岁,巴基斯坦

拉希德,12 岁,巴基斯坦

我要做的就是:

data_file = '/Development/PetProjects/LearningSpark/data*.csv'它将读取所有以数据开始的 CSV 类型的文件。

它将读取所有匹配模式的 CSV 文件并转储结果:

如您所见,它将 CSV 中的所有数据转储到一个数据帧中。很酷吧。

但是有一点,只有当所有的 CSV 都遵循特定的模式时,这种转储才会起作用。如果您有一个不同列名的 CSV,那么它将返回以下消息。

19/06/04 18:59:05 WARN CSVDataSource: Number of column in CSV header is not equal to number of fields in the schema:
 Header length: 3, schema size: 17
CSV file: file:///Development/PetProjects/LearningSpark/data.csv

如您所见,Spark 抱怨 CSV 文件不一致,无法处理。

您可以使用 DataFrame 执行许多操作,但是 Spark 为您提供了更简单、更熟悉的界面来使用SQLContext操作数据。它是 SparkSQL 的网关,允许您使用类似 SQL 的查询来获得想要的结果。

在我们进一步讨论之前,让我们先玩一些真实的数据。为此,我们使用我从 Kaggle 获得的超市销售数据。在尝试 SQL 查询之前,让我们尝试按性别对记录进行分组。我们在这里处理 ETL 的提取部分。

data_file = '/Development/PetProjects/LearningSpark/supermarket_sales.csv'
sdfData = scSpark.read.csv(data_file, header=True, sep=",").cache()gender = sdfData.groupBy('Gender').count()
print(gender.show())

当您运行时,它会返回如下内容:

groupBy()按给定的列对数据进行分组。在我们的例子中,它是性别栏。

SparkSQL 允许您使用类似 SQL 的查询来访问数据。

sdfData.registerTempTable("sales")
output =  scSpark.sql('SELECT * from sales')
output.show()

首先,我们从数据帧中创建一个临时表。为此,使用了registerTampTable。在我们的例子中,表名是销售。一旦完成,你就可以对它使用典型的 SQL 查询。在我们的例子中,它是 Select * from sales

或者类似下面的内容:

output = scSpark.sql('SELECT * from sales WHERE `Unit Price` < 15 AND Quantity < 10')
output.show()

或者甚至是聚合值。

output = scSpark.sql('SELECT COUNT(*) as total, City from sales GROUP BY City')
output.show()

很灵活,对吧?

我们刚刚完成了 ETL 的转换部分。

最后加载 ETL 的部分。如果您想保存这些转换后的数据,该怎么办?你有很多选择,RDBMS,XML 或者 JSON。

output.write.format('json').save('filtered.json')

当您运行它时,Sparks 会创建以下文件夹/文件结构。

它用文件名创建了一个文件夹,在我们的例子中是 filtered.json 。然后,一个名为 _SUCCESS 的文件会告知操作是否成功。如果失败,将生成一个名为 _FAILURE 的文件。然后,您会在这里找到多个文件。之所以有多个文件,是因为每个工作都涉及到写入文件的操作。如果你想创建一个单独的文件(不推荐),那么可以使用coalesce,从所有分区收集数据并减少到一个单独的数据帧中。

output.coalesce(1).write.format('json').save('filtered.json')

它将输出以下数据:

{"total":328,"City":"Naypyitaw"}
{"total":332,"City":"Mandalay"}
{"total":340,"City":"Yangon"}

MySQL 和 Apache 火花集成

上面的数据帧包含转换后的数据。我们希望将这些数据加载到 MYSQL 中,以便进一步使用,如可视化或在应用程序上显示。

首先,我们需要 MySQL 连接器库来与 Spark 交互。我们将从 MySQL 网站下载连接器,并放在一个文件夹中。我们将修改SparkSession以包含 JAR 文件。

scSpark = SparkSession \
        .builder \
        .appName("reading csv") \
        .config("spark.driver.extraClassPath", "/usr/local/spark/jars/mysql-connector-java-8.0.16.jar") \
        .getOrCreate()

output现在看起来如下:

output = scSpark.sql('SELECT COUNT(*) as total, City from sales GROUP BY City')
    output.show()
    output.write.format('jdbc').options(
        url='jdbc:mysql://localhost/spark',
        driver='com.mysql.cj.jdbc.Driver',
        dbtable='city_info',
        user='root',
        password='root').mode('append').save()

在运行脚本之前,我在 DB 中创建了所需的 Db 和表。如果一切顺利,您应该会看到如下结果:

如您所见,Spark 使得从一个数据源向另一个数据源传输数据变得更加容易。

结论

Apache Spark 是一个非常苛刻和有用的大数据工具,它有助于非常容易地编写 ETL。您可以加载数 Pb 的数据,并通过建立一个包含多个节点的集群来轻松处理这些数据。本教程只是让您对 Apache Spark 编写 ETL 的方式有一个基本的了解。您应该查看文档和其他资源来深入了解。

本帖原载 此处

创造你自己的强化学习环境

原文:https://towardsdatascience.com/create-your-own-reinforcement-learning-environment-beb12f4151ef?source=collection_archive---------5-----------------------

Image by wallpaperplay

人们一直在使用强化学习来解决许多令人兴奋的任务。无论是简单的雅达利游戏,还是复杂的围棋Dota 游戏。强化学习不仅能够解决任务,而且实现了超人的表现。

在这篇博客中,我们不仅要解决另一个强化学习环境,还要从头开始创建一个。

对于那些不熟悉强化学习并想知道什么是环境的人,让我简单介绍一下。即使你是机器学习的新手,在这篇博客结束时,你也会学到很多东西。

强化学习|简介

强化学习是机器学习的一个分支,我们有一个代理和一个环境。环境只不过是一个任务或模拟,而代理是一个与环境交互并试图解决它的人工智能算法。

在下图中,环境就是****迷宫。代理的目标是通过采取最佳行动来解决这个迷宫。

从图中可以清楚地看出代理和环境是如何相互作用的。代理向环境发送动作,环境在执行从代理接收的每个动作后向代理发送观察和奖励。观察不过是环境的内部状态。奖励意味着这个行为有多好。随着我们继续浏览博客,情况会变得更清楚。

因此,为了应用强化学习,我们需要两样东西。

  • Agent :一种 AI 算法。
  • ****环境:需要代理解决的任务/模拟。

环境通过发送它的状态和奖励与代理交互。因此,下面是创建环境的步骤。

  • 创建一个模拟。
  • 添加一个代表模拟内部状态的状态向量
  • 在模拟中添加一个奖励系统

让我们现在开始构建环境。

创造环境

我要用 python 制作一个非常简单的游戏。一旦我们完成游戏,我们可以在其中添加状态向量和奖励系统。就这样,我们有了第一个强化学习环境。

这场比赛将是一场简单的球拍和球的比赛。我们在地上放了一个桨,桨需要击打移动的球。如果球触地而不是触板,那就是失误。

我将使用 python 中内置的 turtle 模块。Turtle 提供了一个简单易用的界面来构建和移动不同的形状。大部分代码都是不言自明的,所以我将简单介绍一下这些代码。现在没有必要深入研究代码语法。

让我们为我们的游戏创建一个背景窗口。

Creating a background window

我们创建了一个大小为(600, 600)像素的空白窗口。窗口的中点坐标是(0, 0)。意味着我们可以上下左右移动 300 个像素。

Blank Screen

酷,10%环境完成。让我们在底部加一个桨,在中间加一个球。

Adding paddle and ball

Paddle and Ball

太好了,现在 20%的环境已经完成。让我们在按下左右键时添加左右移动。

Adding paddle movement

我们创建了两个函数来左右移动球拍。然后我们用左右键绑定这些函数。表示按下右箭头键,函数 paddle_right 被调用,paddle 向右移动 20 个像素。

Paddle Movement

太棒了,我们已经完成了 30%的环境。现在让我们添加球的运动。

Adding ball movement

对于球,我设置水平速度为 3,垂直速度为-3。意味着球在每一帧后水平移动 3 个像素,垂直移动-3 个像素。所以对于每一帧,我们必须使用球的速度来更新球在主循环中的位置。

Ball Movement

现在完成了 40 %。但是等等,球刚刚穿过屏幕。应该是撞上了侧墙。所以我们必须在代码中加入以下边界检查。

  • 球应该与上面的球和侧面的球碰撞。
  • 球应该和桨碰撞。
  • 如果球碰到了地面,那么游戏应该从头开始。

Adding boundary checks

看起来不错。这个已经做了七成了。让我们在棺材上钉上最后一颗钉子,那就是记分卡。

Adding scorecard

我们维护两个变量,分别叫做hitmiss。如果球击中了球拍,我们增加hit,否则增加miss。然后我们可以创建一个记分卡,在屏幕的顶部中间打印分数。

Scorecard

现在,这看起来像一个适当的游戏。我们现在已经完成了 90%的环境。剩下的就是在这个模拟中添加一个状态向量和奖励系统。

状态向量和奖励系统

我们将状态向量提供给我们的人工智能代理,代理基于该状态选择一个动作。状态向量应该包含有价值的信息。代理采取的行动的好坏取决于状态向量的信息量。

我创建了一个包含以下信息的状态向量。

  • 桨叶棒在 x 轴上的位置
  • 球在 x 和 y 轴上的位置
  • 球在 x 轴和 y 轴的速度

以下是我实施的奖励制度。

  • 如果球碰到了球拍,奖励+3
  • 球没打中桨就给奖励-3
  • 每次划桨移动给予-0.1的奖励,这样划桨就不会不必要的移动。

我们还必须实现一个行动空间。代理将从动作空间中选择一个动作,并将其发送到环境中。以下是我实现的动作空间。

  • 0 -向左移动桨。
  • 1——什么都不做。
  • 2 -向右移动拨片。

代理将把这些数字中的一个发送给环境,环境执行对应于该数字的动作。

Adding reward and state vector

所有这些都包含在这个小小的步骤函数中。这是代理与环境交互的功能。代理调用此函数,并在参数中提供操作值。并且这个函数将状态向量和奖励返回给代理。这个函数还返回一个变量,这个变量是完成的。这将告诉代理剧集是否终止。在我们的例子中,当球触地时一集结束,新的一集开始。当你把这些代码放在一起看的时候,它们会更有意义。

最后,它 100%完成了。看起来不错。现在就来解决吧。

解决环境问题

这个博客的主要焦点是创造环境。因此,我将在这篇博客中简要介绍代理算法。

我已经实现了 DQN 算法来解决这个任务。我们在这个算法的核心使用了一个神经网络,它以状态作为输入,输出动作。DQN 还有更多,你可以在 DQN 的这篇令人敬畏的 论文 中找到。

以下是代理人玩游戏的片段。球拍经常在 49 次失误后开始击球。

Agen playing the game

下面是一个奖励/情节。代理在 30 集后开始实现频繁的高回报。

暂时就这样了。我们从头开始创建了一个非常简单的环境,并使用 DQN 解决了这个问题。以下是包含完整代码的 GitHub 库。我会继续贴出更多很酷的项目,在那之前请保持关注。

** [## shivaverma/轨道

强化学习环境的开源集合。

github.com](https://github.com/shivaverma/Orbit)**

注意

我正在开发一个名为 Orbit 的开源项目,这将是一个强化学习环境的集合。如果你有任何令人兴奋的想法,并通过创建自己的环境为这个包做出贡献,请在shivajbd@gmail.com上 ping 我。如果需要的话,我很乐意为你提供个人指导。

创建您自己的虚拟个人助理

原文:https://towardsdatascience.com/create-your-own-virtual-personal-assistant-94be5df65ced?source=collection_archive---------7-----------------------

Courtesy: Pixabay

你知道 Cortana,Siri,Google Assistant 吧?你有没有想象过你可以制作自己的虚拟个人助理,随心所欲的定制?今天,我们就在这里做。我们将用 python 从头开始构建一个个人助理。哦,在开始之前,让我告诉你,这绝不是一个人工智能,而只是一个人工智能可以做什么的有力例子,以及 python 是多么多才多艺和令人惊叹。此外,为了开始使用 python,您需要有一些使用 python 的经验。那么,让我们开始吧:

首先,我们需要安装一些重要的软件包:

  • SpeechRecognition:用于执行语音识别的库,支持多种引擎和 API,在线和离线。
  • Pyttsx3 : Pyttsx 是 python 中一个很好的文本到语音转换库。
  • Wikipedia : Wikipedia 是一个 Python 库,使得访问和解析来自 Wikipedia 的数据变得容易。
  • Wolframalpha:针对 Wolfram|Alpha v2.0 API 构建的 Python 客户端。
  • py audio:PortAudio 的 Python 绑定。

确保你已经安装了所有这些软件包,否则你可能会遇到一些错误,这是你如何安装它:

pip install PackageName

PyAudio 安装:

你可能会在安装 Pyaudio 时遇到一些错误,我也遇到过同样的问题。您可以利用这些步骤来避免安装错误:

  • 通过python --version找到你的 Python 版本比如我的是3.7.3
  • 这里 找到合适的.whl文件,比如我的是PyAudio‑0.2.11‑cp37‑cp37m‑win_amd64.whl,下载。
  • 转到下载它的文件夹,例如cd C:\Users\foobar\Downloads
  • 以我的例子为例,用pip安装.whl文件:
pip install PyAudio-0.2.11-cp37-cp37m-win_amd64.whl

此外,安装它可以避免不必要的错误:

pip install pypiwin32

如果您完成了这些包的安装,那么我们可以导入它们并返回代码:

import os
import sys
import datetime
import pyttsx3
import speech_recognition as sr
import wikipedia
import wolframalpha
import webbrowser
import smtplib
import random

现在,我们将使用“SAPI5”作为 pyttsx3 的 TTS 引擎,获取 wolframaplha 的密钥,并定义客户端。

engine = pyttsx3.init(‘sapi5’) 
client = wolframalpha.Client(‘Get your own key’)

您可以从 wolframalpha.com->Apps->Key 获得自己的密钥。

现在,我们将初始化一个变量,并获得我们需要的必要的声音参数。女声可以在第二行设置为-1,男声设置为-2。接下来,我们将创建一个函数 talk ,将音频作为输入参数。

voices = engine.getProperty(‘voices’)
engine.setProperty(‘voice’, voices[len(voices) — 2].id)def talk(audio): 
    print(‘KryptoKnite: ‘ + audio) 
    engine.say(audio) 
    engine.runAndWait()

接下来,让我们创建另一个函数 greetMe ,它将用于在用户运行程序时问候用户。 datetime.datetime.now()。小时用于以小时为单位获取当前时间,并根据时间和以下条件给出输出。 Talk fn 将用于给出语音方面的输出。

def greetMe():
    CurrentHour = int(datetime.datetime.now().hour)
    if CurrentHour >= 0 and CurrentHour < 12:
        talk('Good Morning!') elif CurrentHour >= 12 and CurrentHour < 18:
        talk('Good Afternoon!') elif CurrentHour >= 18 and CurrentHour != 0:
        talk('Good Evening!') greetMe()talk('Hey Buddy, It\'s  your assistant KryptoKnite!')
talk('tell me about today?')

接下来,我们将创建另一个函数 GivenCommand ,用于识别用户输入,它将定义麦克风用作输入源,我们将暂停阈值设置为 1。尝试使用 except 块,要识别的语言将被设置为英语-印度,如果语音未被识别或听不到,我们将发送文本输入作为一种错误消息。

def GivenCommand():
    k = sr.Recognizer()
    with sr.Microphone() as source:
        print("Listening...")
        k.pause_threshold = 1
        audio = k.listen(source)
    try:
        Input = k.recognize_google(audio, language='en-in')
        print('Kunal Dhariwal: ' + Input + '\n') except sr.UnknownValueError:
        talk('Sorry! I didn\'t get that! Try typing it here!')
        Input = str(input('Command: ')) return Input

现在,让我们开始主要功能:

在这里,我们将声明一些重要的函数和条件,这些函数和条件将增强我们的个人助理的功能,并帮助他提供输出和接收来自用户的输入。

if __name__ == '__main__': while True: Input = GivenCommand()
        Input = Input.lower() if 'open google' in Input:
            talk('sure')
            webbrowser.open('www.google.co.in') elif 'open youtube' in Input:
            talk('sure')
            webbrowser.open('www.youtube.com') elif "what\'s up" in Input or 'how are you' in Input:
            setReplies = ['Just doing some stuff!', 'I am good!',                                     
                          'Nice!', 'I am amazing and full of power']
            talk(random.choice(setReplies))

同样,你可以添加更多的 elif 和其他功能,比如我添加了一个发送电子邮件的功能。

elif 'email' in Input:
    talk('Who is the recipient? ')
    recipient = GivenCommand() if 'me' in recipient:
        try:
            talk('What should I say? ')
            content = GivenCommand() server = smtplib.SMTP('smtp.gmail.com', 587)
            server.ehlo()
            server.starttls()
            server.login("Your_Username", 'Your_Password')
            server.sendmail('Your_Username', "Recipient_Username", content)
            server.close()
            talk('Email sent!') except:
            talk('Sorry ! I am unable to send your message at this moment!')

或者可能正在播放一些音乐?

elif 'play music' in Input:
    music_folder = 'Path
    music = ['song']
    random_music = music_folder + random.choice(music) + '.mp3'
    os.system(random_music) talk('Okay, here is your music! Enjoy!')

接下来,我们将添加一些功能,使用这些输入在维基百科、谷歌上进行搜索,并使用 wolframalpha。

else:
    Input = Input
    talk('Searching...')
    try:
        try:
            res = client.Input(Input)
            outputs = next(res.outputs).text
            talk('Alpha says')
            talk('Gotcha')
            talk(outputs) except:
            outputs = wikipedia.summary(Input, sentences=3)
            talk('Gotcha')
            talk('Wikipedia says')
            talk(outputs) except:
        talk("searching on google for " + Input)
        say = Input.replace(' ', '+')
        webbrowser.open('https://www.google.co.in/search?q=' + Input)talk('Next Command! Please!')

当这一切完成后,程序退出是非常重要的。让我们在这里为它写一个条件:

elif 'nothing' in Input or 'abort' in Input or 'stop' in Input:
    talk('okay')
    talk('Bye, have a good day.')
    sys.exit()elif 'bye' in Input:
    talk('Bye, have a great day.')
    sys.exit()

就是这样!您已经创建了自己的虚拟个人助理。

你现在可以自定义它,并为它设置任何条件,还可以添加 N 个功能,使它更加神奇。

完整代码:https://bit.ly/2VaBsEU

你可以在我的 LinkedIn 帖子https://bit.ly/2DW8qU0这里获得 视频演示

如果您遇到任何错误或需要任何帮助,您可以随时在 LinkedIn 上发表评论或 ping 我。

领英:https://bit.ly/2u4YPoF

Github:https://bit.ly/2SQV7ss

我希望这有助于增强您的知识库:)

关注我了解更多!

感谢您的阅读和宝贵的时间!

使用 LaTeX 创建您的专业/教育简历

原文:https://towardsdatascience.com/create-your-professional-educational-resume-using-latex-7bc371f201e3?source=collection_archive---------6-----------------------

一份简历可以被认为是你在雇主面前的第一印象。简历是向你未来的雇主宣布你是这个职位的最佳人选的最合适的方式。在本教程中,我将演示如何使用 LaTeX 环境为您未来的工作创建一份组织良好的专业简历。

引人注目的简历背后的主要动机是展示你的基本资产,如你的资历、经验、成就、能力和品质。根据招聘经理(雇主)的典型心态,据观察,雇主只需几秒钟就能决定是否给这个人打电话面试。正如在企业界普遍经历的那样,拥有必要技能和适当经验的人得不到面试电话的情况经常发生。这是因为申请这份工作的人没有在简历中清楚地宣传自己。

因此,要准备一份令人信服的简历,在职业生态系统中应该遵循一定的标准。遵循预先定义的规则并不意味着每份申请/简历都要遵循特定的格式。每份简历都可以根据申请人向雇主展示自己的方式而有所不同。简历是一种有效描述专业/教育背景的方式,可以吸引监考员。

使用通用文本编辑器,如微软 Word 或谷歌文档,可以达到保存简历草稿的初步目的。这些编辑坚持“所见即所得”的方式来编排作品。然而,使用这样的编辑器在整个简历中遵循特定的格式/编辑标准会花费很多不必要的努力。由于这些问题,促使我向读者介绍 LaTeX 环境。LaTeX 是学术和研究团体用于出版其作品的文档准备系统。具体来说,作者使用标记惯例来格式化整个文档中的文本,添加引用和交叉引用,以及定义文档的结构。LaTeX 使用 TeX 发行版,如 TeX Live 或 MikTeX 来生成适合打印或数字发行的输出文件(PDF)。

在 LaTeX 中准备简历可以降低格式化文档所需的整体复杂性;因此,对于每一个专业人士来说,了解基本的 LaTeX 语法来构建简历是非常必要的。在本教程中,我将从几个方面讲述如何创建一份强大而有效的简历,这份简历将涵盖申请的每一个要素。

首先,每个 LaTeX 文件可以包含一个特定的样式类文件,通常称为 。clsT3,它定义了文档的所有样式规则。这个类文件的功能类似于网页设计中的 CSS 文件。网上有多种类型的文件可以用来制作简历,其中我更喜欢由 Trey Hunner 提供的文件。这个文件是一个简单而有效的方式来展示你自己。从下面提供的链接下载类文件:

ridhamdave/resume-latex/blob/master/resume . cls

每个 LaTeX 文件都以“文档”对象开始和结束。为了演示:

\documentclass{resume} % The style class
\begin{document}
.
.
.
\end{document}

让我们开始创建简历,第一项任务是在页面顶部提供个人详细信息,这也称为地址部分。这一部分将出现在包含有关您的姓名、地址、电话号码和电子邮件地址的详细信息的文档的顶部。这里提供的类文件为标题和其他联系信息定义了某些标签(标记)。在文档开始之前添加这一行,以反映引言部分。

\name{John Snow} % Your name
\address{North of the Wall, Outside the reach of every kingdom} 
\address{(+0)9999999999 \\ [johnsnow@realnorth.com](mailto:johnsnow@realnorth.com)}

Introduction Section above the first page

下一部分对每一个大学毕业生来说都是最重要的,也就是教育背景。这一部分必须包括所读的学位、教育机构、其附属大学以及总的 CGPA/分数。这个类文件提供了一个预定义的“rSection”标签,用于区分简历的各个部分。该部分的花括号包含该部分的名称,在\begin 和\end 之间的条目代表实际需要的内容。

这里,\bf 代表粗体,而\em 代表斜体,\hfill 命令用于在页面的右侧和侧面之间提供适当的格式空间。教育部分如下所示,输入到实际文档中:

\begin{rSection}{Education}{\bf Massachusetts Institute of Technology, Cambridge} \hfill {\em July 2016 - May 2020} 
\\ Bachelor of Engineering, Computer.\hfill { Overall CGPA: 9.05 }\end{rSection}

Education section

下一部分可以被认为是职业和个人的主要职业目标。这一部分可以定义为“职业目标”,如下所示:

\begin{rSection}{Career Objective}
 To work for an organization which provides me the opportunity to improve my skills and knowledge to grow along with the organization objective.
\end{rSection}

Career’s long-term goal

从学术角度来看,项目在学习实践技能方面起着至关重要的作用。因此,我考虑将“项目”部分放在文档的这个位置。这是一个可以根据个人喜好修改的方面。对于这一部分,一般惯例是项目的名称以粗体显示,而摘要则从下一行开始以普通文本显示,如下所述。这里双斜杠(\)表示新行。我将同一个项目重复了两次,以演示项目之间的确切间距。

\begin{rSection}{Projects}{\bf GitHub Notifier}
\\This project aims at providing real time information of events from GitHub and notify you accordingly. The project is in ready-to-deployment stage on a demo server as a cron-job. The notification engine  used for real time tracking is completely based on the python implementation assembled in an Android App with firebase cloud support.{\bf GitHub Notifier}
\\This project aims at providing real time information of events from GitHub and notify you accordingly. The project is in ready-to-deployment stage on a demo server as a cron-job. The notification engine  used for real time tracking is completely based on the python implementation assembled in an Android App with firebase cloud support.\end{rSection}

Project section. Note the spacing between each project

简历的下一步是简单明了地展示你拥有的技能和技术优势。因此,无边框的桌子最适合这种视觉美感。表格部分用于创建表格,如下所示。“&”运算符用于各列的多样化,而“\”运算符用于新的行连接。

\begin{rSection}{Technical Strengths}\begin{tabular}{ @{} >{\bfseries}l @{\hspace{6ex}} l }
Languages \ & C, C++, Python, Java, C\#  \\
Technologies & MVC, HTML5, CSS, Latex\\
Tools & MikTex, Kile, Netbeans \\
Databases & MySql, Oracle, Sqlite, NoSql\\
Cloud Technologies & Firebase, AWS, Google Cloud\\
Version Control & Github
\end{tabular}\end{rSection}

Tabular Demonstration of Technical Strengths

下一部分被认为是你简历中最重要的部分之一,即“工作经历”部分。这一部分需要简要描述你对之前工作过的公司的贡献。在实习的情况下,这个人应该提到这一点,并相应地总结在公司中的角色。类文件为此类条目提供了一个“rSubsection”模板,它可能需要多个标记来表示雇员名称、公司名称、工作持续时间等..一个区段将包含一个子区段,用于工作概况的每个条目,如下所示。在这里,每个汇总点都用一个\item 标签声明,以实现相等的间距和设计。

\begin{rSection}{Work Experience}
\begin{rSubsection}{Reversible Alphabet Pvt. Ltd., India}{Jun 2017 - Dec 2018}{Data Scientist}{}
 \item Created classification models for e-commerce websites using neural networks.
 \item Achieved exposure towards classification optimaization techniques for further specialization.
 \item Worked under an experenced Data Scientist and got deep insights related to optimization algorithms.
\end{rSubsection}
\begin{rSubsection}{Irreversible Alphabet Pvt. Ltd., India}{Jun 2016 - Dec 2016}{Data Scientist}{}
 \item Created classification models for e-commerce websites using neural networks.
 \item Achieved exposure towards classification optimaization techniques for further specialization.
 \item Worked under an experenced Data Scientist and got deep insights related to optimization algorithms.
\end{rSubsection}\end{rSection}

Note individual entry for each Job

类似地,学术成就、课外活动和研究概况等部分可以通过以下方式添加。每个部分都可以添加,如下例所示:

\begin{rSection}{Academic Achievements} 
\item Project 'XYZ' won Best Project under Environmental Solver category under AICTE, Government of India
\item Recieved Scholarship For Higher Education(She) Component Under Inspire Scheme worth INR 4,00,000
\item Achived A Grade in Diploma in Computer Science from IBM
\item Won First Prize in Zonal technical quiz Competition Organized by IIT, Mumbai.
\item Project 'XYZ' won Best Project under Environmental Solver category under AICTE, Government of India
\item Recieved Scholarship For Higher Education(She) Component Under Inspire Scheme worth INR 4,00,000
\item Achived A Grade in Diploma in Computer Science from IBM
\item Won First Prize in Zonal technical quiz Competition Organized by IIT, Mumbai.
\end{rSection} 

Point-vise academic achievements

\begin{rSection}{Extra-Cirrucular} 
\item Attended a workshop on Machine Learning and artificial intelligence from faculties of IIT Roorkee in 2019 and won zonal round for the challenge presented.
\item Member of the  Institute of Engineers since 2017.
\item Completed Basic Leadership Training under Project NSS, Gujarat
\item Attended a workshop on Machine Learning and artificial intelligence from faculties of IIT Roorkee in 2019 and won zonal round for the challenge presented.
\item Member of the  Institute of Engineers since 2017.
\item Completed Basic Leadership Training under Project NSS, Gujarat
\item Attended a workshop on Machine Learning and artificial intelligence from faculties of IIT Roorkee in 2019 and won zonal round for the challenge presented.
\item Member of the  Institute of Engineers since 2017.
\item Completed Basic Leadership Training under Project NSS, Gujarat\end{rSection}

Extra Curricular Activities need to be emphasized

同样,研究部分需要与充分记录和引用的论文一起提交,例如(带有期刊/会议名称):

\begin{rSection}{Research Profile}
 \item Student President, Technology and Research, IIT Gandhinagar
 \item Publication : ABC, IOT IEEE Transactions (Impact Factor: 9.3, Status: Published)
 \item Student President, Technology and Research, IIT Gandhinagar
 \item Publication : ABC, IOT IEEE Transactions (Impact Factor: 9.3, Status: Published)
 \item Student President, Technology and Research, IIT Gandhinagar
 \item Publication : ABC, IOT IEEE Transactions (Impact Factor: 9.3, Status: Published)
\end{rSection}

Research Work

最后,在添加了简介的所有方面之后,需要对文档进行最终校对,并需要准备最终草稿。如果有错误或含糊不清的地方,让同事来纠正应该是一种惯例。简历构建是一项反复的任务,需要不断的调整和完善,只有付出足够的努力才能实现。下面的 GitHub 链接提供了简历的所有 LaTeX 代码。

https://github . com/ridhamdave/resume-latex/blob/master/resume . tex

最终的 PDF 如下所示:

Final Resume

总结一下,你现在手里有一份很棒的简历,为了让它更好,需要定期更新。在简历制作过程中,有两个词应该牢记在心,那就是:

精确的简洁的

希望你学到了有效构建简历的新技术,并且更熟悉这种专业任务的 LaTeX 环境。

感谢您的关注。

也可以在 LinkedIn 上关注我。

为非漫画读者创建漫画推荐系统

原文:https://towardsdatascience.com/creating-a-comic-book-recommendation-system-for-non-comic-readers-e56a5c68c798?source=collection_archive---------37-----------------------

我的一个爱好是漫画书。你可能已经注意到,即使你不是读者,你也一定会接触到电视和电影中使用的漫画中的人物和故事。网飞、Hulu、亚马逊、HBO 和许多其他公司都涉足漫画内容制作。夏季影院里挤满了最新的《复仇者联盟》或《蝙蝠侠传奇》。

尽管我很喜欢这种媒介,但漫画书行业通常被认为有利于使用他们的故事或角色的下一部大型电影或电视节目。有很多人看到这些节目和电影,有阅读的灵感,但不知道从哪里开始。我明白,看漫画会让人害怕。我认为许多人在《辛普森一家》中的漫画店主的脑海中形成了这样的愿景,并想以另一种方式逃跑。我认为必须有一种方法来帮助人们涉足漫画,而不是从头开始。

我的主要想法是,我如何让看漫画书的电影和电视节目的人成为漫画书?跟他们在电影电视剧里的喜好怎么样!我从那些已有的偏好里给你推荐漫画怎么样。

总的来说,这个项目依赖于你喜欢的内容有一些内在的味道。下面是一个假设类型的例子。这可能并不总是一个明确的概念,但你的品味中可能有一些潜在的方面,可以通过你消费的媒体看到。

考虑到这些,我们来构建一个推荐系统吧!

数据准备和挖掘漫画

我的目标是寻找那些对电影/电视和漫画书/漫画小说都有评价的人。为了建立我的模型,我使用了之前在加州大学圣地亚哥分校的一个研究项目中收集的大型亚马逊评论库(1996 年至 2014 年约 24GB 的书籍和电影/电视评论,更多信息请点击这里)。

为了提取正确的用户和评级,我不得不花大量时间学习和探索这个数据集。所有的漫画书/漫画小说都被归入所有其他书评中,没有快捷方式将它们取出。我从抓取亚马逊畅销书页面开始,为漫画书准备了少量的亚马逊 id(ASIN)。基于数据探索,我在 ids 中发现了一种模式,可以快捷地获得漫画书的几大块 id。下面是我发现的模式的一个例子:

有了这组 id,我找到了任何对应的评论。然后我找了那组评论者,找到了所有评论过电影/电视的人。在删除少于 5 条评论的条目,并删除任何缺少相关元数据的数据(一些数据缺少标题或链接到不再列出的条目,使它们不可用)后,我正在处理约 84,000 条评论,约 8,500 个不同用户和约 7,400 条条目(约 1,300 部漫画/漫画小说,约 6,100 部电影/电视)。

建模和交替最小二乘法

我的方法是建立一个替代的最小二乘(ALS)模型来拥有一个协同过滤推荐系统。你可能会问自己,这些最小二乘是什么,为什么它们会交替出现?

交替最小二乘法是一种方法,通过这种方法,我们可以将评级矩阵分解为代表用户和项目的矩阵,每个矩阵都通过潜在特征来表示。在一个非常简单的例子中,可以这样认为:

所以我有我的用户评分矩阵和他们对漫画和电影的评论。这个矩阵将是相当稀疏的,因为用户将只对一些事情进行评分,但我们希望填充这些空白的位置,并根据我们对他们的了解猜测他们可能会得分。我们首先选择一些潜在的特征。潜在特征本质上是描述用户和项目的数学推导方式。通过非负矩阵分解(NMF),我们可以从 R 中导出用户(U)和项目(P)的矩阵。我们保持 U 不变(用随机值填充)并求解 P。然后,我们保持 P 不变并求解 U。这个过程如此往复,直到看不到误差减少。完成后,U 和 P 相乘得到新的 R 估计值,填入用户评价矩阵中的值。

估价

为了评估,我基于对均方根误差(RMSE)和平均绝对误差(MAE)的优化来优化我的模型的性能。调整我的模型的参数并没有提供太多的性能,但是我确定了我的最佳模型,使用 50 个潜在特征,正则化参数为 0.1,最大迭代次数为 20。我表现最好的模型的 RMSE 是 1.17。总的来说,我希望这个数字低于 1,但我认为在我目前的范围内这是一个相当好的表现。

起来,起来,走!

你可以在 IntoComics 亲自测试一下。该应用程序为您提供了从 1 到 5 的电影选择(目前是 60 部最常被评级的电影的精选列表,但排除了所有基于漫画或漫画小说的电影,以更清晰地推动这两种媒体的分离)。一旦你对其中一个或多个进行了评级,它会返回一个前 5 名漫画/图形小说推荐列表,并提供亚马逊上每个产品的链接。我将继续努力改进模型,但现在,希望你喜欢!

为文本清理创建自定义分类器

原文:https://towardsdatascience.com/creating-a-custom-classifier-for-text-cleaning-a2a1fc818935?source=collection_archive---------15-----------------------

句子分类的机器学习

最近,我对 NLP 的研究超过了其他数据科学领域,我经常面临的一个挑战是该过程的清理部分。构建 NLP 模型需要许多预处理步骤,如果数据处理不当,可能会导致模型质量差,而这正是我们想要避免的。

在本文中,我们将重点关注 PDF 文档。这里的目标是打开一个 PDF 文件,将其转换为纯文本,了解数据清理的需要,并为此建立一个机器学习模型。

在本帖中,我们将:

  • 打开 PDF 文件并将其转换为文本字符串
  • 将文本分割成句子并建立数据集
  • 通过用户交互手动标记数据
  • 制作一个分类器来删除不需要的句子

我们将要使用的一些库:

  • pdfminer →阅读 PDF 文件
  • 文本斑点 →文本处理
  • 熊猫 →数据分析

PDF 阅读器

和往常一样,我会试着解释文本中使用的代码,所以如果你愿意,可以跳过这些代码片段。让我们从导入一些模块开始:

from collections import Counter
from IPython.display import clear_output
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from textblob import TextBlob
import io
import math
import numpy as np
import pandas as pd
import string

我们将使用 pdfminer 来构建我们的 PDF 阅读器:

def read_pdf(path):
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos=set()
    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password, caching=caching, check_extractable=True): 
        interpreter.process_page(page)
    text = retstr.getvalue()
    text = " ".join(text.replace(u"\xa0", " ").strip().split())  
    fp.close()
    device.close()
    retstr.close()
    return text

虽然这个函数看起来很长,但它只是读取一个 PDF 文件并以字符串形式返回它的文本。我们将把它应用到一篇名为“谷歌数据实用指南”的论文中:

只要看第一页,我们很快就会发现,一篇文章包含的不仅仅是简单的句子,还包括像日期行数页码数字标题和副标题节分隔符等式、等等。让我们来看看当论文被转换成纯文本时,这些属性将如何显示(primer.pdf是文件的名称,存储在我的本地计算机中):

read_pdf('primer.pdf')

很明显,我们丢失了所有的文本结构。行数和页码分散开来,因为它们是句子的一部分,而标题和参考文献无法与正文明确区分。可能有很多方法可以让你在阅读 PDF 时保留文本结构,但是为了便于解释,让我们保持混乱状态(因为这通常就是原始文本数据的样子)。

文本清理

一个完整的清洗管道有许多步骤,为了熟悉它们,我建议遵循一些教程(这个和这个是很好的起点)。一般来说,清洗流程链包括:

  • 标记化
  • 正常化
  • 实体提取
  • 拼写和语法纠正
  • 删除标点符号
  • 删除特殊字符
  • 词干

我们在这里的目标不是取代任何一个阶段,而是建立一个更通用的工具来删除我们不需要的东西。把它作为辅助步骤,在中间帮忙。

假设我们想要删除任何看起来不像人类写的句子。这个想法是将那些句子归类为“不想要的”或“怪异的”,而将其余的句子视为“正常的”。例如:

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 相关。

或者

51 52 53 54 55 #从关联中读取数据,并使其成为动物园时间序列 dat

Those sentences are clearly messed up because of the text transformation and in case we're making, let's say, a PDF summarizer, they shouldn't be included.

To remove them, we could manually analyze the text, figure out some patterns and apply 正则表达式。但是,在某些情况下,为我们建立一个发现这些模式的模型可能会更好。这就是我们在这里做的。我们将创建一个分类器来识别奇怪的句子,这样我们就可以轻松地将它们从正文中删除。

构建数据集

让我们构建一个函数来打开 PDF 文件,将文本拆分成句子并保存到一个数据框中,该数据框包含列标签句子:

def pdf_to_df(path):
    content = read_pdf(path)
    blob = TextBlob(content)
    sentences = blob.sentences
    df = pd.DataFrame({'sentence': sentences, 'label': np.nan})
    df['sentence'] = df.sentence.apply(''.join)
    return dfdf = pdf_to_df('primer.pdf')
df.head()

由于我们没有标记数据(在“怪异”或“正常”中),我们将手动填充我们的标签列。这个数据集将是可更新的,以便我们可以附加新的文件,并标记他们的句子。

让我们首先将未标记的数据集保存到一个中。泡菜文件:

df.to_pickle('weird_sentences.pickle')

现在,我们将创建一个用户交互功能来手动分类数据点。对于数据集中的每个句子,我们将显示一个文本框,供用户键入“1”或不键入任何内容。如果用户键入‘1’,该句子将被分类为‘怪异’。

我使用的是 Jupyter 笔记本,所以我从 IPython.display 调用了 clear_output()函数来改善交互。

def manually_label(pickle_file):
    print('Is this sentence weird? Type 1 if yes. \n')
    df = pd.read_pickle(pickle_file)
    for index, row in df.iterrows():
        if pd.isnull(row.label):
            print(row.sentence)
            label = input()
            if label == '1':
                df.loc[index, 'label'] = 1
            if label == '':
                df.loc[index, 'label'] = 0
            clear_output()
            df.to_pickle('weird_sentences.pickle')

    print('No more labels to classify!')manually_label('weird_sentences.pickle')

每个句子的输出如下所示:

由于这句话看起来挺正常的,我就不打' 1 '了,直接按回车进入下一句。这个过程将一直重复,直到数据集被完全标记或者当您中断时。每一个用户输入都被保存到 pickle 文件中,因此数据集在每一个句子中都被更新。这种简单的交互使得标记数据变得相对较快。我花了 20 分钟标记了大约 500 个数据点。

为了简单起见,还编写了另外两个函数。一个用于将另一个 PDF 文件附加到我们的数据集,另一个用于重置所有标签(将标签列值设置为 np.nan )。

def append_pdf(pdf_path, df_pickle):
    new_data = pdf_to_df(pdf_path)
    df = pd.read_pickle(df_pickle)
    df = df.append(new_data)
    df = df.reset_index(drop=True)
    df.to_pickle(df_pickle)def reset_labels(df_pickle):
    df = pd.read_pickle(df_pickle)
    df['label'] = np.nan
    df.to_pickle(df_pickle)

由于我们最终得到了更多“正常”而非“怪异”的句子,我构建了一个函数来对数据集进行欠采样,否则,一些机器学习算法将无法很好地执行:

def undersample(df, target_col, r=1):
    falses = df[target_col].value_counts()[0]
    trues = df[target_col].value_counts()[1]
    relation = float(trues)/float(falses) if trues >= r*falses:
        df_drop = df[df[target_col] == True]
        drop_size = int(math.fabs(int((relation - r) * (falses))))
    else: 
        df_drop = df[df[target_col] == False]
        drop_size = int(math.fabs(int((r-relation) * (falses)))) df_drop = df_drop.sample(drop_size)
    df = df.drop(labels=df_drop.index, axis=0)
    return dfdf = pd.read_pickle('weird_sentences.pickle').dropna()
df = undersample(df, 'label')
df.label.value_counts()

645 个标记的数据点。不足以制作一个像样的模型,但我们会用它作为一个操场的例子。

文本转换

现在,我们需要以算法可以理解的方式转换句子。一种方法是计算每个字符在句子中的出现次数。这有点像是一种文字袋技术,但是是在角色层面上。

def bag_of_chars(df, text_col):
    chars = []
    df['char_list'] = df[text_col].apply(list)
    df['char_counts'] = df.char_list.apply(Counter)
    for index, row in df.iterrows():
        for c in row.char_counts:
            df.loc[index, c] = row.char_counts[c]
    chars = list(set(chars))
    df = df.fillna(0).drop(['sentence', 'char_list', 'char_counts'], 1)
    return dfdata = bag_of_chars(df, 'sentence')
data.head()

机器学习模型

完美!现在我们只剩下一个常见的机器学习挑战。一个分类问题中的多个特征和一个目标。让我们将数据分成训练集和测试集:

data = data.sample(len(data)).reset_index(drop=True)
train_data = data.iloc[:400]
test_data = data.iloc[400:]x_train = train_data.drop('label', 1)
y_train = train_data['label']
x_test = test_data.drop('label', 1)
y_test = test_data['label']

我们准备选择一个算法并检查它的性能。在这里,我使用逻辑回归来看看我们能实现什么:

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_scorelr = LogisticRegression()
lr.fit(x_train, y_train)accuracy_score(y_test, lr.predict(x_test))

86 %的准确率。对于小型数据集、浅层模型和字符包方法来说,这已经很不错了。唯一的问题是,尽管我们分成了训练和测试,但是我们是用我们训练的同一个文档来评估模型的。更合适的方法是使用新文档作为测试集。

让我们创建一个函数,使我们能够预测任何自定义句子:

def predict_sentence(sentence):
    sample_test = pd.DataFrame({'label': np.nan, 'sentence': sentence}, [0])
    for col in x_train.columns:
        sample_test[str(col)] = 0
    sample_test = bag_of_chars(sample_test, 'sentence')
    sample_test = sample_test.drop('label', 1)
    pred = lr.predict(sample_test)[0]
    if pred == 1:
        return 'WEIRD'
    else:
        return 'NORMAL'weird_sentence = 'jdaij oadao //// fiajoaa32 32 5555' 

正常句子:

我们刚刚建立了一个很酷的机器学习模型

normal_sentence = 'We just built a cool machine learning model'
predict_sentence(normal_sentence)

怪句:

jdaij oadao //// fiajoaa32 32 5555

weird_sentence = 'jdaij oadao //// fiajoaa32 32 5555'
predict_sentence(weird_sentence)

我们的模特得分了!不幸的是,当我尝试更多的句子时,它显示出对其中一些句子进行分类的糟糕表现。单词袋(在这种情况下是字符)方法可能不是最好的选择,算法本身可以大大改进,我们应该标记更多的数据点,使模型变得可靠。这里的要点是,您可以使用相同的方法来执行许多不同的任务,例如识别特定的元素(例如链接、日期、名称、主题、标题、等式、引用等等)。使用正确的方式,文本分类可以是一个强大的工具,以帮助在清理过程中,不应该被视为理所当然。好清洁!

谢谢你一直读到最后。这是一篇关注文本分类以解决清理问题的文章。请关注我的个人资料,了解更多关于数据科学的信息,并随时向我提出任何意见或问题。下一篇帖子再见!

从头开始创建定制的健身房环境—股票市场示例

原文:https://towardsdatascience.com/creating-a-custom-openai-gym-environment-for-stock-trading-be532be3910e?source=collection_archive---------1-----------------------

OpenAI 的gym是一个很棒的包,允许你创建定制的强化学习代理。它配备了相当多的预建环境,如car pole、 MountainCar 和大量免费的 Atari 游戏以供试验。

这些环境非常适合学习,但最终您会希望设置一个代理来解决自定义问题。为此,您需要创建一个定制的环境,特定于您的问题域。稍后,我们将创建一个自定义的股票市场环境来模拟股票交易。本文的所有代码都可以在我的 GitHub 上获得。

首先,让我们了解一下到底什么是环境。环境包含运行代理并允许其学习的所有必要功能。每个环境必须实现以下 gym 接口:

**import** gym
**from** gym **import** spaces

**class** **CustomEnv**(gym.Env):
  *"""Custom Environment that follows gym interface"""*
  metadata = {'render.modes': ['human']}

  **def** __init__(self, arg1, arg2, ...):
    super(CustomEnv, self).__init__() *# Define action and observation space*
    *# They must be gym.spaces objects* *# Example when using discrete actions:*
    self.action_space = spaces.Discrete(N_DISCRETE_ACTIONS) *# Example for using image as input:*
    self.observation_space = spaces.Box(low=0, high=255, shape=
                    (HEIGHT, WIDTH, N_CHANNELS), dtype=np.uint8)

  **def** step(self, action):
    # Execute one time step within the environment
    ... **def** reset(self):
    # Reset the state of the environment to an initial state
    ... **def** render(self, mode='human', close=False):
    # Render the environment to the screen
    ...

在构造函数中,我们首先定义我们的action_space的类型和形状,它将包含代理在环境中可能采取的所有动作。类似地,我们将定义observation_space,它包含代理要观察的所有环境数据。

我们的reset方法将被调用来周期性地将环境重置为初始状态。接下来是通过环境的许多step,其中一个动作将由模型提供,并且必须被执行,下一个观察结果被返回。这也是计算奖励的地方,稍后会详细介绍。

最后,可以定期调用render方法来打印环境的再现。这可能像打印语句一样简单,也可能像使用 openGL 渲染 3D 环境一样复杂。对于这个例子,我们将坚持使用打印语句。

股票交易环境

为了演示这一切是如何工作的,我们将创建一个股票交易环境。然后,我们将培训我们的代理,使其成为该环境中的盈利交易者。我们开始吧!

我们需要考虑的第一件事是人类交易者会如何看待他们的环境。在决定进行交易之前,他们会做哪些观察?

交易者很可能会看一些股票价格走势图,上面可能会覆盖一些技术指标。从那时起,他们将把这些视觉信息与他们对类似价格行为的先验知识结合起来,对股票可能的走势做出明智的决定。

因此,让我们将此转化为我们的代理应该如何感知其环境。

我们的observation_space包含了我们希望经纪人在交易或不交易之前考虑的所有输入变量。在本例中,我们希望代理“看到”过去五天的股票数据点(开盘价、最高价、最低价、收盘价和日交易量),以及其他一些数据点,如帐户余额、当前股票头寸和当前利润。

这里的直觉是,对于每个时间步,我们希望我们的代理考虑导致当前价格的价格行为,以及他们自己的投资组合的状态,以便为下一个行为做出明智的决定。

一旦交易者意识到他们的环境,他们需要采取行动。在我们代理的例子中,它的action_space将由三种可能性组成:买入一只股票,卖出一只股票,或者什么都不做。

但是这还不够。我们需要知道每次买入或卖出的股票数量。使用 gym 的Box空间,我们可以创建一个动作空间,该空间具有离散数量的动作类型(买入、卖出和持有),以及连续的买入/卖出金额范围(分别为账户余额/头寸大小的 0-100%)。

您会注意到,金额对于保留操作不是必需的,但无论如何都会提供。我们的代理最初并不知道这一点,但随着时间的推移,应该会知道该金额与此行为无关。

在实施我们的环境之前,最后要考虑的是回报。我们希望激励长期持续的利润。在每一步,我们将把奖励设置为账户余额乘以到目前为止的时间步数的某个分数。

这样做的目的是在早期阶段延迟对代理人的过快奖励,并允许它在过于深入地优化单个策略之前进行充分的探索。它还将奖励那些在更长时间内保持较高余额的代理商,而不是那些使用不可持续的策略迅速赚钱的代理商。

履行

现在我们已经定义了我们的观察空间、行动空间和奖励,是时候实现我们的环境了。首先,我们需要在环境的构造函数中定义action_spaceobservation_space。环境期望传入一个包含要学习的股票数据的pandas数据帧。 Github repo 中提供了一个例子。

***class*** **StockTradingEnvironment**(*gym*.*Env*):
  """A stock trading environment for OpenAI gym"""
  metadata = {'render.modes': ['human']} **def** __init__(*self, df*):
    *super*(StockTradingEnv, self).__init__()
    self.df = df
    self.reward_range = (0, MAX_ACCOUNT_BALANCE)    # Actions of the format Buy x%, Sell x%, Hold, etc.
    self.action_space = spaces.Box(
      *low*=np.array([0, 0]), *high*=np.array([3, 1]), *dtype*=np.float16) # Prices contains the OHCL values for the last five prices
    self.observation_space = spaces.Box(
      *low*=0, *high*=1, *shape*=(6, 6), *dtype*=np.float16)

接下来,我们将编写reset方法,每当创建新环境或重置现有环境的状态时都会调用该方法。在这里,我们将设置每个代理的初始余额,并将其未平仓头寸初始化为一个空列表。

**def** reset(*self*):
  # Reset the state of the environment to an initial state
  self.balance = INITIAL_ACCOUNT_BALANCE
  self.net_worth = INITIAL_ACCOUNT_BALANCE
  self.max_net_worth = INITIAL_ACCOUNT_BALANCE
  self.shares_held = 0
  self.cost_basis = 0
  self.total_shares_sold = 0
  self.total_sales_value = 0

  # Set the current step to a random point within the data frame
  self.current_step = random.randint(0, len(self.df.loc[:, 'Open'].values) - 6) **return** self._next_observation()

我们将当前步骤设置为数据帧中的随机点,因为它本质上为我们的代理提供了来自同一数据集的更独特的体验。_next_observation方法编译最近五个时间步长的股票数据,附加代理的帐户信息,并将所有值调整到 0 到 1 之间。

***def*** _next_observation(*self*):
  # Get the data points for the last 5 days and scale to between 0-1
  frame = np.array([
    self.df.loc[self.current_step: self.current_step +
                5, 'Open'].values / MAX_SHARE_PRICE,
    self.df.loc[self.current_step: self.current_step +
                5, 'High'].values / MAX_SHARE_PRICE,
    self.df.loc[self.current_step: self.current_step +
                5, 'Low'].values / MAX_SHARE_PRICE,
    self.df.loc[self.current_step: self.current_step +
                5, 'Close'].values / MAX_SHARE_PRICE,
    self.df.loc[self.current_step: self.current_step +
                5, 'Volume'].values / MAX_NUM_SHARES,
   ]) # Append additional data and scale each value to between 0-1
  obs = np.append(frame, [[
    self.balance / MAX_ACCOUNT_BALANCE,
    self.max_net_worth / MAX_ACCOUNT_BALANCE,
    self.shares_held / MAX_NUM_SHARES,
    self.cost_basis / MAX_SHARE_PRICE,
    self.total_shares_sold / MAX_NUM_SHARES,
    self.total_sales_value / (MAX_NUM_SHARES * MAX_SHARE_PRICE),
  ]], *axis*=0) **return** obs

接下来,我们的环境需要能够采取step。在每一步,我们将采取指定的行动(由我们的模型选择),计算奖励,并返回下一个观察结果。

***def*** step(*self*, *action*):
  # Execute one time step within the environment
  self._take_action(action) self.current_step += 1 **if** self.current_step > len(self.df.loc[:, 'Open'].values) - 6:
    self.current_step = 0 delay_modifier = (self.current_step / MAX_STEPS)

  reward = self.balance * delay_modifier
  done = self.net_worth <= 0 obs = self._next_observation() **return** obs, reward, done, {}

现在,我们的_take_action方法需要采取模型提供的动作,或者买入、卖出或者持有股票。

***def*** _take_action(*self*, *action*):
  # Set the current price to a random price within the time step
  current_price = random.uniform(
    self.df.loc[self.current_step, "Open"],
    self.df.loc[self.current_step, "Close"]) action_type = action[0]
  amount = action[1] **if** action_type < 1:
    # Buy amount % of balance in shares
    total_possible = self.balance / current_price
    shares_bought = total_possible * amount
    prev_cost = self.cost_basis * self.shares_held
    additional_cost = shares_bought * current_price self.balance -= additional_cost
    self.cost_basis = (prev_cost + additional_cost) / 
                            (self.shares_held + shares_bought)
    self.shares_held += shares_bought **elif** actionType < 2:
    # Sell amount % of shares held
    shares_sold = self.shares_held * amount . 
    self.balance += shares_sold * current_price
    self.shares_held -= shares_sold
    self.total_shares_sold += shares_sold
    self.total_sales_value += shares_sold * current_price self.netWorth = self.balance + self.shares_held * current_price **if** self.net_worth > self.max_net_worth:
    self.max_net_worth = net_worth **if** self.shares_held == 0:
    self.cost_basis = 0

现在唯一剩下要做的就是render将环境调整到屏幕上。为了简单起见,我们将只呈现到目前为止的利润和一些其他有趣的指标。

***def*** render(*self*, *mode*='human', *close*=False):
  # Render the environment to the screen
  profit = self.net_worth - INITIAL_ACCOUNT_BALANCE print(*f*'Step: {self.current_step}')
  print(*f*'Balance: {self.balance}')
  print(*f*'Shares held: {self.shares_held}
          (Total sold: {self.total_shares_sold})')
  print(*f*'Avg cost for held shares: {self.cost_basis}
          (Total sales value: {self.total_sales_value})')
  print(*f*'Net worth: {self.net_worth}
          (Max net worth: {self.max_net_worth})')
  print(*f*'Profit: {profit}')

我们的环境是完整的。我们现在可以用数据框实例化一个StockTradingEnv环境,并用来自稳定基线的模型测试它。

**import** gym
**import** json
**import** datetime **as** dt**from** stable_baselines.common.policies **import** MlpPolicy
**from** stable_baselines.common.vec_env **import** DummyVecEnv
**from** stable_baselines **import** PPO2**from** env.StockTradingEnv **import** StockTradingEnv**import** pandas **as** pddf = pd.read_csv('./data/AAPL.csv')
df = df.sort_values('Date')# The algorithms require a vectorized environment to run
env = DummyVecEnv([*lambda*: StockTradingEnv(df)])model = PPO2(MlpPolicy, env, *verbose*=1)
model.learn(*total_timesteps*=20000)obs = env.reset()
**for** i **in** range(2000):
  action, _states = model.predict(obs)
  obs, rewards, done, info = env.step(action)
  env.render()

当然,这只是为了好玩,来测试创建一个有趣的、定制的健身房环境,包括一些半复杂的动作、观察和奖励空间。如果我们真的想在股票市场上通过深度学习致富,这将需要更多的时间和努力…

请继续关注下周的文章,在那里我们将学习为我们的环境创建简单而优雅的可视化效果!

[## 创造不赔钱的比特币交易机器人

让我们使用深度强化学习来制造有利可图的加密货币交易代理

towardsdatascience.com](/creating-bitcoin-trading-bots-that-dont-lose-money-2e7165fb0b29)

感谢阅读!一如既往,本教程的所有代码都可以在我的 GitHub 上找到。如果您有任何问题或反馈,请在下面留下评论,我很乐意收到您的来信!我也可以通过@notadamking 上的Twitter联系到。

你也可以通过下面的链接在 Github 赞助商 或者Patreon上赞助我。

[## GitHub 赞助商

嗨,我是亚当。我是一名开发人员、作家和企业家,尤其对深度…

github.com](https://github.com/users/notadamking/sponsorship)

Github 赞助商目前正在 1:1 匹配所有捐款,最高可达 5000 美元!

[## 亚当·金正在创造改变世界的内容

嗨,我是亚当。我是一名开发人员、作家和企业家,尤其对深度…

patreon.com](https://patreon.com/notadamking)

使用 Apache 气流创建动态 DAG

原文:https://towardsdatascience.com/creating-a-dynamic-dag-using-apache-airflow-a7a6f3c434f3?source=collection_archive---------3-----------------------

今天我们想和你分享一个我们用 Apache 气流解决的问题。我们有一个包含 40 多个应用程序的项目。每天,我们都必须将数据从内部数据库加载到云中,特别是 AWS S3 公司。该过程批量执行,每天执行。由于特殊原因,数据必须在没有任何进一步预处理的情况下加载到 S3。要加载到 AWS S3 的表可能会定期变化,因此添加这样的表作为输入源应该更容易——因为我们不想为数据库中的每个表创建 DAG。

我们决定通过自动生成气流 DAG 来解决上述问题。特别是,我们设计的解决方案使 DAG 工作流可以从一个简单的 YAML 生成,,给定一个包含要加载到 AWS S3 的表名的 YAML 文件,Airflow 应该自动生成 DAG 任务来加载这些数据。因此,在本帖中,我们想带您了解我们的解决方案。我们希望你会发现它有用!

YAML 文件

要加载到 S3 的表应该在 YAML 文件中指定。此外,由于这是一个批处理过程,我们需要包含一个日期类型字段,用于根据执行日期过滤这样的表。因此,我们执行增量加载,,即,仅将前一天的数据加载到 S3。

动态任务生成

一旦定义了 YAML 文件结构,我们就可以为我们的动态 DAG 构建逻辑了!因此,首先要做的是使用虚拟操作符、定义两个任务,即开始和结束任务。在这些任务中,我们将通过在它们之间动态创建任务来构建我们的 DAG,此时这可能有点混乱,但一旦您看到图表,一切都将变得清晰。

然后,下一步是定义允许创建 DAG 任务的 Python 函数。特别是,我们通过使用 PythonOperators 来创建这样的任务。该函数应接收任务 id 作为参数;要执行的 python 函数,,python 运算符的Python _ callable;以及在执行过程中使用的一组参数。

我们将任务 id 作为一个参数。因此,我们可以通过 XCOM 在动态生成的任务之间交换数据,例如。**

设置 DAG 工作流程

最后一步是将 DAG 的工作流放在一起,如果您已经做到这一点,这将非常容易。

这是我们的 DAG 在将代码放在一起后的样子

DAG automatically generated by using a YAML file

结论

在这篇文章中,我们介绍了一种在气流 DAG 中创建动态任务的方法。我们在本文中给出了函数 getSQLDataupload_to_s3_task,的定义,因为我们认为它们超出了本文的范围。

您可以在下一个代码片段中找到最终的代码

希望你觉得有用。

感谢阅读到最后!😃

通过 ARKit 使用面部情绪创建动态用户界面

原文:https://towardsdatascience.com/creating-a-dynamic-ui-using-facial-emotions-with-arkit-d2f836010db7?source=collection_archive---------13-----------------------

Photo from Unsplash

如何创建一个美丽的,动画渐变视图,反应面部情绪

ARKit 和原深感摄像头为开发人员实现基于用户面部表情的直观和动态组件开辟了许多新的可能性。本教程的目标是创建一个动画渐变视图,其颜色对应于相关的情绪。

Emotion gradient

设置一个项目来检测面部运动

在 Xcode 中创建一个新项目作为单视图应用程序,然后转到main.storyboard。将 ARKit SceneKit 视图拖放到您的ViewController中,并为视图设置任何约束。该视图将显示前摄像机视图。如果愿意,您可以将其设置为隐藏。

ARKit SceneKit View

Import ARKit,然后将ARSCNView添加到ViewController中。

ARSCNView tracking view

现在添加面部跟踪功能

**override** **func** viewDidLoad() { 
    **super**.viewDidLoad()
    **guard** ARFaceTrackingConfiguration.isSupported **else** {
        fatalError("Face tracking not available on this on this device model!")
    } **let** configuration = ARFaceTrackingConfiguration()
    **self**.trackingView.session.run(configuration)
    **self**.trackingView.delegate = **self** }

情感跟踪

创建一个名为Emotionimport ARKit的新文件。然后添加以下协议,带有后续扩展名。

**import** UIKit
**import** ARKit**protocol** Emotion { *// The range between 0-1 where the emotion is considered active or not* **var** threshold: Double { **get** } *// List of colors associated with the emotion* **var** colors: [UIColor] { **get** } *// Calculated from the the blendshapes to see if that face has the given emotion (for example smile is calculated from '.mouthSmileLeft' or '.mouthSmileRight' being over the threshold amount)* **func** isActive(for face: ARFaceAnchor) -> Bool}**extension** Emotion {
    *// Set default threshold to 0.3, can be overriden by class to change value.* **var** threshold: Double {
        **return** 0.3
    }
}

接下来,我们将创建想要跟踪的情感对象。对于这个教程,我只打算把中性,快乐,悲伤和愤怒。为了确定人脸的情绪,我们将分析人脸对象的混合形状。您可以在此查看所有可用的混合形状。

**struct** NeutralEmotion: Emotion { **var** colors: [UIColor] = [UIColor(hexString: "#9CC0E7"), UIColor(hexString: "#EEEEEE"), UIColor(hexString: "#FCFCFC"), UIColor(hexString: "#F7DBD7")] **func** isActive(for face: ARFaceAnchor) -> Bool {

        **for** blendshape **in** face.blendShapes {
            **if** blendshape.value.doubleValue > **self**.threshold {
                **return** **false** }
        }
        **return** **true** }
}**struct** HappyEmotion: Emotion {
    **var** colors: [UIColor] = [UIColor(hexString: "#01BEFE"), UIColor(hexString: "#FFDD00"), UIColor(hexString: "#ADFF02"), UIColor(hexString: "#E7B2FF")] **func** isActive(for face: ARFaceAnchor) -> Bool {
        **return** face.blendShapes[.mouthSmileLeft]?.doubleValue ?? 0 > **self**.threshold || face.blendShapes[.mouthSmileRight]?.doubleValue ?? 0 > **self**.threshold
    }
}**struct** SadEmotion: Emotion {
    **var** colors: [UIColor] = [UIColor(hexString: "#345467"), UIColor(hexString: "#101442"), UIColor(hexString: "#1F6B65"), UIColor(hexString: "#1D4E7A")] **func** isActive(for face: ARFaceAnchor) -> Bool {
        **return** face.blendShapes[.mouthFrownLeft]?.doubleValue ?? 0 > **self**.threshold || face.blendShapes[.mouthFrownRight]?.doubleValue ?? 0 > **self**.threshold
    }
}**struct** AngryEmotion: Emotion {
    **var** colors: [UIColor] = [UIColor(hexString: "#E72222"), UIColor(hexString: "#C92929"), UIColor(hexString: "#AB3232"), UIColor(hexString: "#963232")] **func** isActive(for face: ARFaceAnchor) -> Bool {
        **return** face.blendShapes[.browDownRight]?.doubleValue ?? 0 > **self**.threshold || face.blendShapes[.browDownLeft]?.doubleValue ?? 0 > **self**.threshold
    }
}

请记住,我还添加了一个 UIColor 扩展,它使用十六进制字符串代替 RGB 值。要将它添加到您的项目中,创建一个名为ColorExtensions的文件,并添加以下代码。

**import** UIKit**extension** UIColor {
    **convenience** **init**(hexString: String) {
        **let** hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
        **var** int = UInt32()
        Scanner(string: hex).scanHexInt32(&int)
        **let** a, r, g, b: UInt32

        **switch** hex.count {
            **case** 3: *// RGB (12-bit)* (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
            **case** 6: *// RGB (24-bit)* (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
            **case** 8: *// ARGB (32-bit)* (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
            **default**:
                (a, r, g, b) = (255, 0, 0, 0)
        }
        **self**.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
    }
}

我们现在想要创建一个名为EmotionManager的新文件。这个类将分析一个 ARFaceAnchor 对象,看看它是否匹配我们的任何情感对象规范,并将它们保存在一个列表中。

**import** UIKit
**import** ARKit**class** EmotionManager { *// List of all of the emotions we want to track* **private** **var** emotions: [Emotion] = [NeutralEmotion(), HappyEmotion(), SadEmotion(), AngryEmotion()] *// Current active emotions. Defaults to neutral.* **var** activeEmotions: [Emotion] = [NeutralEmotion()] *// Gets the current emotions found in the given ARFaceAnchor object. If none are found then return neutral as default.* **func** refreshActiveEmotions(for face: ARFaceAnchor) {
        **var** activeEmotions = [Emotion]() **for** emotion **in** **self**.emotions {
            **if** emotion.isActive(for: face) {
                activeEmotions.append(emotion)
            }
        } *// If no active emotions are found then default to neutral* **self**.activeEmotions = activeEmotions.isEmpty ? [NeutralEmotion()] : activeEmotions
    } *// Return emotion colors from currently active face emotions. Shuffle the order so the gradient constantly changes.* **func** getEmotionColors() -> [CGColor] {
        **return** activeEmotions.flatMap { $0.colors.compactMap { $0.cgColor } }.shuffled()
    }
}

动画渐变视图

回到你的ViewController,为我们刚刚创建的EmotionManager添加一个实例变量和一个 CAGradientLayer (这将是我们的渐变)。

**var** emotionManager = EmotionManager()
**var** gradientView : CAGradientLayer?

现在我们需要两个函数,initialiseGradient()animateGradient(),它们都将在viewDidLoad()方法的末尾被调用。

**override** **func** viewDidLoad() {
    **super**.viewDidLoad() **guard** ARFaceTrackingConfiguration.isSupported **else** {
    fatalError("Face tracking not available on this on this device model!")
    } **let** configuration = ARFaceTrackingConfiguration()
    **self**.trackingView.session.run(configuration)
    **self**.trackingView.delegate = **self** **self**.initialiseGradient()
    **self**.animateGradient()
}**func** initialiseGradient() {
    *// Create gradient view to take up whole of the background view* **self**.gradientView = CAGradientLayer() **self**.gradientView?.startPoint = CGPoint(x: 0, y: 0) *// Starts in top left corner* **self**.gradientView?.endPoint = CGPoint(x: 1, y: 1) *// Ends in bottom right corner* **self**.gradientView?.frame = **self**.view.frame
    **self**.gradientView?.colors = emotionManager.getEmotionColors()
    view.layer.insertSublayer(**self**.gradientView!, at: 0)
}**func** animateGradient() {
    *// Animates gradient from current gradient colors to current emotion colors* **let** colorArray = **self**.emotionManager.getEmotionColors()
    **let** animation = CABasicAnimation(keyPath: "colors")
    animation.duration = 1
    animation.fromValue = **self**.gradientView!.colors
    animation.toValue = colorArray
    animation.delegate = **self
    self**.gradientView?.add(animation, forKey: **nil**)
    DispatchQueue.main.async {
        CATransaction.setDisableActions(**true**)
        **self**.gradientView?.colors = colorArray
    }
}

现在,为了在当前动画完成后开始新的渐变动画,创建无休止的渐变运动效果,我们需要扩展 CAAnimationDelegate 并从animationDidStop方法中调用animateGradient()

**extension** ViewController: CAAnimationDelegate { **func** animationDidStop(**_** anim: CAAnimation, finished flag: Bool) {
        DispatchQueue.main.async {
            *// Run new gradient animation once the previous has finished to create the endless gradient movement effect* **self**.animateGradient()
        }
    }
}

最后,我们想要扩展 ARSCNViewDelegate 并在 renderer 方法内部检查一个包含面部表情数据的 ARFaceAnchor 。如果我们找到一个面部锚,我们可以将它传递给我们的emotionManager来检查任何活跃的情绪,这将相应地改变颜色。

**extension** ViewController: ARSCNViewDelegate { **func** renderer(**_** renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        **guard** **let** faceAnchor = anchor **as**? ARFaceAnchor **else** { **return** }
        DispatchQueue.main.async {
            **self**.emotionManager.refreshActiveEmotions(for: faceAnchor)
        }
    }
}

就是这样!

我希望你喜欢这个教程,如果你把它应用到你自己的任何项目中,或者它启发你创造类似的东西,那么请联系我,因为我很想看看你做了什么。

点击此处查看完整源代码。

用 Python 为人工智能竞赛创建一个平台

原文:https://towardsdatascience.com/creating-a-platform-for-ai-competitions-1184666f32e4?source=collection_archive---------25-----------------------

详细说明在开发 AI 竞赛平台过程中遇到的最重要方面。

去年和今年我写了一篇博客,介绍我和我的同事 Elias 、 Pieter 、奥赞和 Cedric 专门为一年级的工科学生设计的人工智能竞赛解决方案。在这个竞争中,玩家可以编写他们自己的代理,该代理为他们与其他玩家的代理玩游戏。为了促进这一竞争,创建了一个平台,允许学生注册自己,上传他们的代码,并检查他们的代理在排行榜上的排名。排行榜根据定期模拟的游戏结果不断更新。这篇博客文章将详细讨论这个名为 Hexatron 的平台在今年的创建过程,内容安排如下:

  1. 高层综述及采用的技术
  2. 我们模拟器的详细讨论
  3. 讨论我们的数据库技术和数据方案
  4. 撮合及评级代理人技能
  5. 我们的前端概述

请注意,这只是我们平台的第二个版本。绝对有改进的空间!因此,任何形式的反馈都是非常受欢迎和非常赞赏的。

This year we even designed our own logo!

高层架构和使用的技术

以下是我们系统中不同组件及其交互方式的高级概述:

A (very) high-level overview of the architecture, consisting of three main modules: (i) a front-end for user registration, agent submission and display of our data, (ii) a SQL database with our data, and (iii) a runner that periodically samples two players from the database and simulates a game between them. Arrows depict the flow of data.

我们可以区分 4 个大组件。核心组件是我们的后端:一个基于 SQL 的数据存储。关于用户和提交的代理的数据通过前端收集并存储在后端中。而且所有的数据都是通过前端应用显示的。采样器组件定期从数据库中提取一对用户,以便使用模拟器组件在 docker 容器中模拟他们之间的游戏。配对是为了尝试和确保竞争激烈、激动人心的比赛。

代理合规性和基于 docker 的模拟

由于游戏是在服务器端模拟的,而且由于 python 脚本可能会对您的主机造成损害(想象一下shutil.rmtree('/')exec('sudo smth')),所以我们采取了一些措施,以确保不可能(或至少很难)向我们的系统提交代理并有效地对我们的服务器造成损害。这是通过向我们的平台提交代码时的一些初始检查,以及尝试在“沙盒”环境中模拟游戏实现的。

每个参与者需要实现一个函数,该函数接受某个游戏状态作为输入,并输出代理想要进行的移动。每次他或她向我们的平台提交新编写的代码,我们都会进行一些检查。首先,我们检查上传文件的大小是否没有超过一兆字节。这是为了避免用户提交会在我们的硬盘上分配太多空间的解决方案,并避免为每个可能的游戏状态硬编码最佳移动。其次,我们只允许使用 NumPy 和标准库中的某些包。第三,也是最后一点,不允许顶级执行代码(所有代码都必须包装在函数中),并且禁止一些构造,包括evalexecopenfilesubprocessdircache等等。如果所有这些检查都成功,则相应用户的最新提交将被更新为新代码,这将在下一次模拟中使用。

模拟是使用 Docker 容器执行的。每当一个新的代理被提交到我们的平台时,就会为该代理创建一个 docker 容器,其中运行着一个 flask 服务器。这个 flask 服务器有一个 post route,它接受一个游戏状态并把它的移动返回给代理。虽然 Docker 容器不太适合作为沙盒环境,但它确实使得通过提交的代码破坏系统变得更加困难。

后端技术和数据方案

作为后端技术,我们使用了 SQL。例如,虽然它比简单的 MongoDB 需要更多的开发工作,但它通常更高效。我们的数据方案(可能太复杂了)描述如下:

The data scheme used in our SQL store.

我们后端的中心对象是用户提交游戏。对于用户提交到我们平台的每个代理,一个提交对象被创建并添加到 DB 中。此外,这个新添加的提交用于“覆盖”用户的活动提交。我们的运行器定期对成对的用户对象进行采样,并在它们之间运行模拟。该模拟的结果存储在新添加的游戏对象中,从而创建了新的等级对象,该对象代表用户的更新等级。而主动提交提交对象之间并没有真正的区别。我们确实做了区分,这样我们就可以允许在提交的代理之间切换功能。

配对和技能评级

比赛的两个重要方面是如何尽可能准确地确定代理商的排名以及如何尽可能确保竞争性比赛。同样,现有的算法和技术被用来解决这些问题。

为了对代理进行排名,我们首先应用了微软开发的true skill系统。TrueSkill 类似于著名的 ELO 系统(起源于国际象棋),但有一些额外的优势,例如适用于 1 对 1 以外的游戏,并自然地处理玩家的不活跃状态(而在 ELO 系统中,这些玩家只会保持相同的等级)。虽然提到的优势在我们的场景中并不真正相关(在我们的场景中,游戏是 1 对 1 的,并且由于定期采样,不活动的情况不会发生),但 TrueSkill 系统是最近才出现的,因此值得一试。不幸的是,我们注意到真实技能等级变化太慢,使得比其他人晚加入比赛的人很难获得更高的等级。因此,我们在比赛中途重构回 ELO 系统。

为了确保有竞争力的匹配,我们使用了一个已经存在的算法,称为,它在一个图中找到最大匹配。更正式地说:给定一个图 G = (V,E),该算法找到一个匹配的 M (它是边的集合),使得 V 中的每个顶点至多与 M 中的一条边关联,并且| M |(或者在我们的情况下是权重的总和)被最大化。这个问题本身非常类似于二分图匹配问题,可以通过应用 匈牙利算法 来解决(这是我们首先要研究的),但是后者在两组(不同的)顶点(通常代表人和工作)之间创建了一个匹配。举个例子,假设我们的系统中有四个玩家。一个玩家 (A) 拥有非常强的代理,一个玩家【B】拥有非常弱的代理,另外两个玩家【C,D】拥有一般的代理。然后我们可以用加权图来表示我们的排行榜。这个图是全连通的,每个顶点对应一个玩家。来自顶点的每个输出边上的权重对应于这两个玩家之间的比赛质量(玩家之间的竞争越激烈,质量越高)😗*

Representing our leaderboard of four players in a graph. The width of the edges depicts the match quality.

在这种情况下,Blossom 算法将返回 2 条边,使得它们的权重之和最大化,并且使得我们的图中的每个顶点恰好与这些边中的一条边相关联。这正是我们想要的:每个玩家与另一个玩家比赛,比赛质量的总和最大化。当然,这只有在顶点数为偶数时才有可能。在奇数个玩家的情况下,从所有玩家中均匀地抽取 1 个随机玩家,并从图形中移除。

在前端显示所有内容

前端主要使用 Flask 创建。我们平台上的每个可能页面都对应一条路线。当用户浏览这条路线时,从后端检索相关对象并提供给 JINJA 模板,然后呈现该模板。对于我们应用程序的交互部分(比如在特定日期范围内过滤游戏的滑块和不同的可视化),我们使用了 JavaScript 和 D3。下面是该应用程序的一些截图:

Screenshot of the leaderboard page

Screenshot of the game history page

Creating a new account

总结词

这就是了。现在,我已经简要介绍了在平台开发过程中需要大量时间的方面和组件。我希望这能对那些正在尝试创造类似东西的人有所帮助。一如既往:如果有任何不清楚的地方,如果有你想要我进一步阐述的事情,或者如果你有建议或反馈,请不要犹豫与我联系!你可以通过评论这篇文章或者给我发邮件来做到这一点。

也许明年,我可以再发一篇关于我们在年度人工智能竞赛的第三个版本中所做的改变的文章。到时候见,

吉勒斯、伊利亚、皮特、奥赞塞德里克

使用变压器创建流行音乐发生器

原文:https://towardsdatascience.com/creating-a-pop-music-generator-with-the-transformer-5867511b382a?source=collection_archive---------4-----------------------

TLDR;训练一个深度学习模型生成流行音乐。你可以在这里用我们预先训练好的模型—【http://musicautobot.com】作曲。源代码在这里可以找到—https://github.com/bearpelican/musicautobot

在这篇文章中,我将解释如何训练一个深度学习模型来生成流行音乐。这是“构建人工智能音乐生成器”系列的第一部分。

快速提示:有几种方法可以生成音乐。非平凡的方式是生成实际的声波(wave netMelNet)。另一种是为乐器演奏生成乐谱(类似于乐谱)。我将解释如何做到后者。

我来这里只是为了目的地…

好吧!这里有一些很酷的音乐生成的例子给你。

我建了一个网站:MusicAutobot。它由我们将在本文中构建的音乐模型驱动。

歌曲#1(灵感来自里奇·汪妮——拉·邦巴)

Red Notes are generated by the model. Green/White notes are the original

歌曲#2(灵感来自帕切尔贝尔——D 中的佳能)

Feel free to press the red button and generate your own music!

注:MusicAutobot 最好在桌面上观看。对于那些手机用户,你只需要听下面的。

Generated Part starts at 0:03

Generated Part starts at 0:06

背景

Transformer 架构是 NLP 的最新进展,它在生成文本方面产生了惊人的结果。与以前的语言模型相比,变形金刚训练速度更快,长期记忆能力更强。给它几个词,它就能继续生成比这更有意义的整段文字。

自然地,这看起来非常适合创作音乐。为什么不给它一些音符,让它产生一段旋律呢?

这正是我们将要做的。我们将使用一个变压器来预测音符!

这是我们正在尝试做的事情的高层次图表:

用…音乐数据训练变压器

我们正在做的,是为音乐建立一个序列模型。取一个输入序列并预测一个目标序列。无论是时间序列预测、音乐还是文本生成,构建这些模型都可以归结为两个步骤:

第一步。 将数据转换成一系列令牌

第二步 建立并训练模型以预测下一个令牌

在两个 python 库 music21 和 fastai 的帮助下,我们构建了一个简单的库 musicautobot ,使得这两个步骤变得相对容易。

第一步。

将数据(音乐文件)转换成符号序列(音符)

拿一张钢琴单看起来像这样:

Piano Score

然后把符号化成这样:

xxbos xxpad n72 d2 n52 d16 n48 d16 n45 d16 xxsep d2 n71 d2 xxsep d2 n71 d2 xxsep d2 n69 d2 xxsep d2 n69 d2 xxsep d2 n67 d4 xxsep d4 n64 d1 xxsep d1 n62 d1

使用 musicautobot,您可以这样做:

More examples in this Notebook

注:musicautobot 在后台使用 music21 来加载音乐文件和令牌化。这种转换的细节将在下一篇文章中介绍。

第二步。

构建并训练模型以预测下一个令牌。

fastai 有一些惊人简单的训练代码用于训练语言模型。

如果我们修改数据加载来处理音乐文件而不是文本,我们可以重用大部分相同的代码。

训练我们的音乐模型现在就像这样简单:

去试试这个 笔记本 来训练自己吧!

是的,就是这样。

现在让我们看看它是否真的有效。

在下一部分,我将使用我在一个大型 MIDI 数据库上预先训练了几天的模型。你可以在这里直接玩预先训练好的模型。

预测流行音乐

第一步:创建一小段笔记:

Snippet from here

看起来是这样的:

First few notes of La Bamba — sounds like this

第二步:把它喂给我们的模特:

Hyperparameters:[Temperature](https://cs.stackexchange.com/questions/79241/what-is-temperature-in-lstm-and-neural-networks-generally) adjusts how "creative" the predictions will be. You can control the amount of variation in the pitch and/or rhythm.[TopK/TopP](https://twitter.com/Thom_Wolf/status/1124263860104507393) - filters out the lowest probability tokens. It makes sure outliers never get chosen, even if they have the tiniest bit of probability

瞧啊。

听起来是这样的:

这其实是我得到的第一个结果,但副作用可能会有所不同。你可以在这里创造你自己的变化。

真正的考验:流行音乐理论

据 HookTheory 的牛逼人士称,现代音乐中最流行的和弦进行是 I-V-VI-IV 和弦。

你可能以前听过。很多流行歌曲中都有。

喜欢每一个。单身。同POPULATION宋。

All these songs use the I-V-vi-IV chord progression

构建和弦

让我们测试我们的模型,看看它是否能识别这个和弦进行。我们将输入前三个和弦“I — V — vi”,看看它是否能预测“IV”和弦。

以下是你如何用音乐创作前三个和弦 21:

看起来是这样的:[C-E-G]——[G-B-D]——[A-C-E]

Model Input: First 3 chords (I-V-vi)

预测“IV”和弦

现在,我们把这些和弦输入我们的模型来预测下一个:

以下是我们得到的结果(包括 3 个输入和弦):

Model predicted the final chord — IV

万岁。该模型预测了音符[F-A-C]——也就是“IV”和弦。

这正是我们希望它预测的。看起来我们的音乐模型能够遵循基本的音乐理论,制作每一首流行歌曲!至少是和弦。

自己测试一下

不要只相信我的话。在音乐机器人上试试吧:

你所要做的就是按红色按钮。

注:10 次中有 8 次,你会得到一个“IV”和弦或者它的一个 转位 。我不能保证确定的结果。只有概率。

这就是全部了!

现在你知道了训练一个音乐模型的基本步骤。

这篇文章中的所有代码都可以在这里找到:https://github.com/bearpelican/musicautobot

使用我们刚刚建立的模型播放和生成歌曲:
http://musicautobot.com
^这些是实时预测,请耐心等待!

接下来:更深的潜水和更深的模型

我可能忽略了一些细节。还有呢!

第二部分。训练音乐模型的实用技巧——深入研究音乐编码和训练——它将涵盖我刚刚忽略的所有细节。

第三部分。建立一个多任务音乐模型——训练一个超级酷的音乐模型,它可以协调,生成旋律,以及混音歌曲。下一个令牌预测是如此…基本。

第四部分。使用一个音乐机器人来重新混合链烟——我们将使用 musicautobot 在 Ableton 重新混合一个 EDM drop。仅用于纯粹的娱乐目的。

特别感谢耶鲁安·克斯滕和杰瑞米·霍华德的指导,南方公园公地和帕拉帕维克的支持。

用扔量子硬币来分析量子行走

原文:https://towardsdatascience.com/creating-a-quantum-walk-with-a-quantum-coin-692dcfa30d90?source=collection_archive---------18-----------------------

So how does a quantum particle walk?

那么什么是“散步”呢?

一次散步正是我们在公园或其他地方进行漫无目的的漫步时所做的事情。我们站在某个地方(可以认为是公园里有一些坐标的位置),迈一步,最后到了另一个地方(是公园里的某个其他位置)。

漫步,或者更准确地说,关于本文的内容,随机漫步是系统从一个状态到另一个状态的转换序列。需要注意的一个重要事实是,这种转移是随机的,或者形式上有一个概率分布。

它们到底为什么重要?

量子行走在一些量子算法的开发中非常有用。比如复杂性分离和通用计算模型。最后都是值得研究他们的。

伯努利随机漫步

在深入研究量子行走之前,研究一个简单的一般随机行走是有用的。考虑以下场景:

你站在一个名为原点的点上,用整数 0 表示。你可以向右或向左移动,通过掷硬币来决定( 你走路的随机性的原因)。你如何分析这种行走,比如说硬币翻转 100 次?

简单来说,你有 50 %的机会向左或向右移动,相当于硬币有 50 %的机会是正面或反面。所以如果你把到达某个地方的概率列表,你会得到这样的结果:

放弃在时间 t 到达位置 n 的概率

或者前一状态即在时间(t-1)的概率的平均值。这导致了对离散马尔可夫链的整个讨论,马尔可夫链是强大的模型,并且已经被广泛地翻译到量子世界。简而言之,马尔可夫链是这样的:在给定历史的所有信息的情况下,在当前状态下着陆的概率是 与给定 之前的状态下,在当前状态下着陆的概率是

其中 n(a)代表系统在时间 t 的状态。

一般来说,这是一个由下式给出的二项式分布:

Generic probability of landing at state n at time t

随着我们增加 n,二项式分布可以更好地近似为以下形式的正态分布:

The Gaussian or the normal distribution

量子行走是怎样的?

现在让我们把上面的行走转换成量子行走。如果你知道量子力学的基本原理,那会很有帮助。但就算你不说,我也会一路解释。在分析行走之前,我们需要创建一个 孤立的量子系统 ,行走将在那里发生。

量子世界最基本的属性是叠加,或者一个系统同时存在于几个状态的能力。形式上,我们定义了一个无限维希尔伯特空间 ,它将表示我们的行走器的位置(与上面讨论的伯努利行走示例中的线上的点相对比)。我们称这个希尔伯特空间为 a。

我们已经把沃克转移到量子世界了。现在我们需要翻译硬币。离散硬币有两种不同的状态可供选择(正面或反面)。类似地,我们定义另一个希尔伯特空间 B,它是二维的,计算基|0 >和|1 >。通过计算基础,我简单的意思是,通过下面的线性组合方程,可以在这个希尔伯特空间中获得任何叠加形式:

for given values of scalars a and b

如何刻画这样的量子币?

如果我们能找到一个符合我们对 B 的定义的量子系统,我们就可以走了。而且谢天谢地,这样的量子系统是存在的:电子。

考虑一个孤立电子。它可以以它的自旋的任何叠加形式存在,但是正好有两个方向可以通过上述线性组合方程组合起来产生任何可能的自旋。

Consider the left one as |1> and the right one as |0> and we have our computational basis realised in physical terms

原来量子力学中的 测量破坏了系统的叠加态。 这仅仅意味着当你测量处于叠加态的电子时,它的状态会坍缩,变成|1 >或|0 >。

这难道不是非常接近于掷硬币吗?!?!

事实证明,在我们前进之前,我们需要一种机制来将我们的 walker 系统(希尔伯特空间 A)和 coin 系统(希尔伯特空间 B)结合成一个单一的系统。这是通过以下张量运算完成的:

Tensor equation for C

如果你不完全理解张量运算,就简单地把它想象成量子力学中的一种方式,把硬币给行走者,这样他们就可以一起行走。从数学上来说,我们发现了一种方法,可以同时在一个无限维的希尔伯特空间(A)和另一个二维的希尔伯特空间上操作,就好像它们是 c 描述的另一个更大的量子系统的子部分一样。

C 中的任何状态都可以用上面给出的张量方程来描述,例如|n>|0 >,其中|0 >属于 B,表示电子的负半自旋,而|n >属于 a。

一个人可以用几个硬币;我们将使用最著名的一种——哈达玛硬币。

哈达玛是由下式给出的矩阵:

Hadamard matrix

有趣的是,它在 B (the |0 >和 the |1 >)的计算基础上有以下行为:

很容易观察到哈达玛是如何将一个态转换成叠加态的。

除了硬币操作符,让我们定义另一个操作符,类似于移位操作符,它根据量子硬币投掷的结果走一步。

Looks exactly like the decision of the classical coin toss.

现在要靠我们自己走完全程了。假设我们系统的原始状态是|n> |0 >。为了将其提升到叠加状态(,这将为其提供一些随机性,应用以下张量(在 C 中):

其中 I 是属于希尔伯特空间 A 的单位矩阵,H 是属于希尔伯特空间 B 的阿达玛币;两者在希尔伯特空间 c 中形成一个张量,直观上可以认为 I 作用于|n >而 H 作用于|0 >(或者简单地说他们作用于和他们一样属于希尔伯特空间的向量)。

作用于|n >的同一性就这样保持着。相反,哈达玛 T12 将| 0>提升到叠加状态,在希尔伯特空间 C 中产生以下内容:

分布张量,可以得到如下结果:

移位操作符应用于上述操作会产生以下结果:

这里,我们看到了在应用投掷硬币之后,由移位操作符执行的行走器位置的最终叠加状态。

这是我们的量子步行者的概率分布。总之,如果我们知道助行器的初始状态,那么在任何给定时间的状态都可以定义如下:

结论

在这里,我们已经完成了对量子行走器的定义,并得出了一个方程,它告诉我们,在任何给定的时间内,我们的量子系统的演化。

理解最基本的量子行走,因为这使任何人都能够将其扩展到离散马尔可夫链的实现到其量子等价物。这些想法也适用于连续的量子行走,这是我们不久将探讨的。敬请关注!

从头开始创建放射科医生

原文:https://towardsdatascience.com/creating-a-radiologist-from-scratch-d776eb944399?source=collection_archive---------19-----------------------

在我的第一次数据科学竞赛中,我是如何制作 x 射线阅读器来检测肺部缺陷的

A Computer learns to see (albeit at the wrong place)

我不知道该怎么做。

除了我自己的 x 光片,我从来没有看过其他的 x 光片,更不用说那些显示出身体缺陷的 x 光片了。我不知道该看什么来确定缺陷。一个对放射学毫无经验的人怎么能告诉一台机器如何看 x 光图像呢?

六个小时后,我仍然不知道如何确定是否有缺陷。但不知何故,我能够创造出一台在检测缺陷方面几乎和放射科医生一样好的机器。

Which x-ray shows a disorder?

我浏览着我的笔记本电脑屏幕,试图了解我面前的网页。有两个文件夹:都包含 x 光图像。一些图像被标记为阳性,一些图像被标记为阴性。我从两个标签上各拿了一个,老实说我看不出有什么不同。在我旁边的是我的九个队友,其中两个正在解决同一个问题。作为唯一一名本科生(也是唯一一名除了微积分课程之外没有接受过任何大学数学正规教育的学生),我周围要么是研究生,要么是从事数据科学家、数据工程师和公共卫生研究的专业人士。

我们正在开发一种机器,可以对 x 射线扫描是否包含气胸(基本上是肺萎陷)进行分类,然后识别图像中的萎陷区域。除了不能区分,我们必须找到一种方法来显示图像中的哪个区域有差异。虽然图像可能有标签,但它没有标记气胸出现的区域。虽然我们的团队中有两个具有放射学经验的人,但我们肯定不能依靠他们在 3000 多张气胸阳性图像中告诉我们受影响区域的确切位置。作为我第一次 datathon 的最后一个个人障碍,当我使用 Pytorch 时,每个人都在使用 Keras,这两个框架都是深度学习的框架。在很大程度上,我们无法相互理解。

再说一次,除了不能区分,我们必须找到一种方法来显示图像中的哪个区域有差异。你在让一个盲人教一台机器如何“看”和看图像来确定它是否是气胸阳性。最重要的是,你能得到的最接近的帮助是在两个不同的编码框架中工作,这让我们感觉像是在用两种不同的方言交谈。然后,我们不得不奇迹般地克服这种情况,将我们建立的任何东西与一个可能用于拯救人类生命的系统结合起来。这太疯狂了。

你在让一个盲人教一台机器如何“看”和看图像来确定它是否是气胸阳性。

火的洗礼

Our group’s presentation at the National University of Singapore (NUS)-Massachusetts Institute of Technology (MIT) Datathon

该问题分为两部分,分类和分段。分类器任务是根据图像的标签对图像进行分类(例如,x 射线图像是否显示气胸(阳性)或不显示气胸(阴性)),而分割任务是通过将图像分割成“部分”来识别图像的哪一部分具有所讨论的对象(例如,如果是阳性的,则阳性区域将被给予一个边界,该边界将其与图像内的其他对象分开)。我自愿参加分类,因为它似乎更容易。

由于我们在不同的框架中编码,我不得不制作自己的分类器。在我们的三人小组中,我们要比较我们的分类器,并选择一个最准确的。我的一个队友把预处理 x 光图像作为一项工作。作为最后的警告,我两周前才开始学习深度学习,我也从未仅仅使用 Pytorch 制作过真正的模型。在我写这篇文章的时候,我还没有独家使用 Pytorch(但是我快到了!).

相反,我只用过基于 Pytorch 的 fastai。这是一个初学者友好的库,它简化了加载图像数据集,在深度学习模型上训练它,然后用它来预测新图像的标签的整个过程。他们在网上也有完整的课程,我用第一课作为指导,制作了我的第一个图像分类器。但这是我在加入这个数据马拉松之前制作的第一个也是唯一一个分类器。

所以没有人问我如何在 Pytorch,中实现它,我简单地复制了我的第一个项目的步骤。我从医学成像信息学协会(SIIM)获取了提供的图像数据集,并将其远程连接到 NSCC 国家超级计算中心的 GPU。我用 Python 处理 Excel 的知识清理了 labels 文件(仍然花了我两个多小时才找到一个简单的公式,将一列中所有非零值都改为 1)。

我使用这个数据集在 Resnet-50 上训练模型。Resnet-50 是一个模型/神经网络,之前显示了数百万张图像,以产生一系列“权重”。您可以将权重视为代表模型中神经元之间强度的一组数字,这些数字有助于模型“观察”图像。直觉是,使用 Resnet-50 的权重比使用随机选取的权重更好,因为该模型已经更善于“观察”图像。这个过程叫做迁移学习。再打个比方,就像老师(预训练的模型)把知识传授给学生(针对具体问题的新模型)。

同一个图像有 4 种不同的尺寸。我从 1024 x 1024 像素的最高分辨率开始,因为更高质量的图像可以帮助计算机“看”它,因为它更清晰,对吗?这个过程用了一个半小时,几乎把给我的 GPU 都烧光了。

Fit one cycle policy is a learning acceleration technique, but running on 1024 x 1024 still took almost 2 hours 😦

我给电脑输入了总共大约 44,000 张高清图像。但令人惊讶的是,默认设置的准确率为 86%。最后,我不得不放弃这种方法,因为我的 GPU 经常内存不足。

I was 6MB away from remotely crashing a foreign government’s hardware

自学

一开始就达到了 86%的准确率,太神奇了。这比猜测要好,也可能比我看 x 光的能力要好。但是它是怎么到那里的呢?我没有给出任何关于如何查看图像的说明或提示,只是说哪个图像对于训练测试来说是正面的或者不是正面的,但是它能够在没有标签的验证集上进行预测。机器是怎么学会怎么学会的?

从经验和观察中抽象出想法是学习的基本特征,机器在这方面做得越来越好。

看看这个模型是怎么来的。机器“学习”的来源是给它提供例子。从例子中,就像人类回忆经历一样,它能够找到模式。这不是死记硬背,因为它能够归纳并应用于新的未知的数据。我没有写任何明确告诉它如何的代码。它自己发展了一套规则。从经验和观察中抽象出想法是学习的基本特征,机器在这方面做得越来越好。所以,我对放射学毫无经验,怎么能告诉一台机器如何观察它呢?我没有,这也正是它学习的原因。

回到过去,我被迫使用较小的图像,所以我选择了 512 X 512 的图像尺寸。与之前的运行相比,我很惊讶它的速度有多快:

我的模型达到了几乎相同的精度,但速度却快了十倍。哇哦。

我错了。与以前的版本相比,它可以在相同的时期更好地对进行分类,并且分辨率几乎是以前的一半。我的直觉被打破了。也许模型不需要考虑不必要的细节,这些细节使得更高的分辨率得以呈现。如果我再做一次,我会得到更高的初始精度。我花了最后几个小时调整模型来改进它。

The final version of the model. I actually got 89% accuracy but I wasn’t able to save the version.

最终我的分类器表现最好(下一个有~71%的准确率),它和分割模型结合完成了气胸检测器。我已经设法利用我在深度学习方面的稀缺知识制作了一个模型,这个模型的表现优于专业人士制作的其他模型。这个模型既不是建立在复杂的预处理技术上,也不是建立在优雅的算法上。仅仅遵循一些简单的技术就让我惊讶地发现,我能够构建一个具有竞争力且精确的模型。

还是一个 Noob

但一路走来,我欠队友的支持。我曾请 CS 博士生帮助我处理 Python 回调,并试图覆盖 fastai 库中的一些预建函数。我从医学影像分析师那里获得了如何预处理图像的技巧(不幸的是,我无法实现,因为我不知道如何对它们进行编码)。我得到了放射科医生的帮助,他告诉我如何手动确定气胸的位置。我还从一位数据工程师那里得到了关于如何通过热图看到模型“看到”的帮助。这个模型还有很多我可以改进的地方,但是如果没有这些地方,我一开始就不可能造出一个来。

Grad-CAM: Where the model “looks”. (Middle) The hotter the area is, the higher focus of the model on that area. Notice how it ignores the labels and arrows on the side. Our radiologist confirmed that the Pneumothorax was within the hot area. (Right) The image in grayscale.

最重要的是,他们分享了他们如何进入机器学习的故事。虽然大多数人有适当的分析背景,如生物医学工程、计算机科学和纯数学学位,但没有人在课堂上学到这些。无论是自动化他们的任务还是增强他们的研究洞察力,他们都能够通过参加在线课程、获得在线证书和参加 Kaggle 竞赛来自学。

我们正处于这样一个时期,那里有许多有待开发的人工智能系统的未开发领域,我们正处于实现提高我们生活质量的潜力的过程中。

缺乏正规培训和气胸问题的存在反映了人工智能应用的整体状况,因为它目前正在改变我们的工作方式。我们正处于这样一个时期,那里有许多有待开发的人工智能系统的未开发领域,我们正处于实现提高我们生活质量的潜力的过程中。单看气胸问题,有人开发一种解决方案,在这个过程中不需要放射科医生,就像自动驾驶汽车不需要司机一样。同样,这在缺乏放射科医生的地方有巨大的应用。将此扩展到人力稀缺的专业工作。

然而,这再次延伸到危害,如劳动力减少和缺乏对失业工人的再培训,使用人工智能做出不道德的判断,以及使用人工智能系统来针对使社会和资本不平等永久化的被剥夺权利的群体。这些最终将成为普通人必须解决的主要问题的一部分,就像贫困和政治一样,因为这只是一个时间问题,这种系统将主宰我们的生活,就像互联网塑造大多数人与现实的互动一样。

这种情况告诉我的最后一件事是,教室不足以让我了解这个世界。仅有理论是远远不够的,只要存在独特和未知问题的现实世界的变化快于课堂教学的变化,课堂课程就无法跟上。

你可以和我团队中的许多人一样有背景,但这只能让你在某些领域拥有优势。从收集信息,到训练模型,再到可视化,这些都需要专业化,而这通常不是一个人就能完成的。你需要某个领域的专业知识,以及合作和理解其他学科的灵活性。这些人花时间学习机器学习,因为他们意识到这是一种可以帮助他们的工具。

像他们一样,我会继续学习,继续练习。希望这不是我唯一从头开始训练的东西。

我用的代码在我的 资源库 上可以作为 jupyter 笔记本使用。看看吧!

在 Microsoft Azure 中创建用于流式物联网数据的无服务器解决方案—第一部分

原文:https://towardsdatascience.com/creating-a-serverless-solution-for-streaming-iot-data-in-microsoft-azure-part-i-5056f2b23de0?source=collection_archive---------37-----------------------

Photo by Markus Spiske on Unsplash

毫无疑问:物联网设备的使用(以及它们产生的数据)正在疯狂增长。根据 Gartner 的一项研究,到 2020 年,将有 58 亿台物联网设备在线,比 2018 年的 39 亿台增长 46%。到 2025 年,物联网设备产生的数据总量预计将达到惊人的 79.4 吉字节,这几乎是 2018 年数据量的六倍。

奇妙的是,像微软 Azure 这样的平台使得接收、存储和分析这些数据变得非常容易。在本文中,我将向您介绍如何从物联网温度传感设备采集流式遥测数据,并将其存储在数据湖中,同时对其进行一些基本的异常检测。本文的所有代码都可以在这个 GitHub 库中找到。

该解决方案的组件包括:

  • Azure 物联网中心,用于接收物联网设备发送的数据,并将原始数据捕获到数据湖。
  • Azure Stream Analytics ,用于处理发送到物联网中心的数据并检测异常。
  • Azure Event Hub ,用于在检测到异常时从流分析接收消息,以便进行下游处理。
  • Azure Data Lake Storage ,用于存储发送到物联网中心的原始数据,以供以后可能的分析。

先决条件

如果您想跟进,您必须运行位于链接的 GitHub 存储库的terraform文件夹中的 Terraform 部署。在存储库的自述文件中有这样做的说明。这是可选的,因为在整篇文章中我会有大量的屏幕截图,但无论如何都要挖掘并构建自己的实验室!

解决方案的详细组件

Azure 物联网中心

Azure 物联网中心提供了一种简单的 PaaS 产品,允许物联网设备向消息传递端点发送数据。它们很容易扩展,您可以从每月零成本开始(免费层每天提供多达 8,000 条消息,非常适合概念验证)。当部署实时安装时,你应该总是从基本层或标准层开始,而不是免费层,因为根据微软的说法,你不能将免费层集线器升级到其他层。在做出决定之前,请仔细查看提供的功能列表和消息吞吐量数字,当然,您可以在以后扩展解决方案。

为了允许设备连接到物联网集线器,您必须提供设备身份。这可以通过 Azure CLI 界面轻松完成,如下所示:

Commands to create a new IoT Device in IoT Hubs

这将显示在各种可用的客户端库中使用的连接字符串(其中有很多)。

您还必须创建共享访问策略,以允许下游应用程序(如 Azure 流分析或 Azure 函数)访问消费设备消息。在本例中,Terraform 模板已经创建了一个名为“streamanalytics”的模板,它被授予了服务连接权限,允许它从 hub 读取消息。有关可能授予的所有权限的列表,请参见本。

提示:永远不要使用内置的 ***iothubowner*** 策略,因为那样会授予 hub 基本上无限制的权限。此外,为每个消费应用程序创建一个策略,以便您可以轻松地轮换访问键,而不必在大量地方替换它们。

在使用消息时,您希望为每个读取消息的应用程序配置不同的使用者组。这允许每一个独立操作,例如跟踪它们在消息流中的位置。在我们的例子中,部署创建了一个streamanalytics消费者组,因为它将读取消息。

最后,还有路由的概念,它决定消息被路由到哪里!这允许你向多个端点发送消息,比如 Azure Event Hub 兼容的端点、服务总线队列和 Azure 存储。后者对于捕获原始数据并将其存储到数据湖中非常有用,这就是我们在这里配置它的原因。

配置存储端点时,您可以根据文件夹结构配置文件的创建方式。您还可以配置文件写入的频率,以及在将文件写入存储帐户之前必须通过的批处理量。

提示:为了获得数据的全功能以后使用,请确保您配置的存储帐户为Azure Data Lake Storage gen 2启用。此外,确保文件的路径和名称是可排序的;例如,您可以确保路径以年开始,然后是月,然后是日,等等。

Azure 数据湖存储

Azure 数据湖存储提供了一种健壮且经济高效的方式来在现有的 Azure Blob 存储平台上存储大量数据。它与众多分析平台完全兼容,如 Hadoop、Azure Databricks 和 Azure SQL 数据仓库。虽然在此概念验证中未启用,但您可以通过将网络访问限制为仅授权的公共 IP 或 Azure VNET 范围,以及仅 Azure 可信服务(在这种情况下是必需的,因为我们使用了物联网中心)来轻松保护对存储帐户的访问。

Azure 流分析

Azure Stream Analytics 使用简单易学的 SQL 语法,可以轻松处理流式物联网数据。在我们的例子中,我们使用内置的异常检测功能来检测意外的温度变化。

流分析作业基于流单元 (SUs)进行扩展,流单元定义了分配给特定作业的计算资源(CPU 和内存)的数量。

流分析部署有三个主要部分:输入、输出和处理数据的查询。让我们更详细地看一下它们。

投入

输入定义了流分析从哪里获取数据进行处理。在我们的例子中,我们将输入定义为 Azure IoT Hub,它是作为我们部署的一部分创建的。

因为该资源是通过自动化部署创建的,所以已经输入了用于连接到物联网中心的所有信息。如前所述,您应该始终专门为流分析连接创建特定的共享访问策略,而不是使用内置的高权限策略(或任何其他预先存在的策略)。您还希望确保创建一个特定的消费者群体。通过点击“测试”按钮,我们可以确认一切工作正常。

Azure 流分析也支持从 Azure Blob 存储和 Azure 事件中心接受数据。有关不同类型的流输入的更多细节,请参见这份微软文档。

还值得注意的是,流分析接受一种不同的输入,称为参考数据。这用于加载静态数据集,这些数据集可用于连接和丰富流数据。例如,您可以使用一个包含不同传感器设备的详细信息的文件,作为在流的输出中包含有用信息的手段。有关使用参考数据流的更多详细信息,请参见本微软文档。

输出

Azure Stream Analytics 支持其产生的数据的大量输出,包括 blob 存储、Azure SQL 数据库、事件中心和许多其他内容。有关可能输出的完整列表,请参见本文档。

在我们的例子中,我们为 Azure Event Hubs 配置了一个输出,它被用作检测到的异常的目的地。与输入一样,明智的做法是使用特定的授权策略来允许流分析作业连接到事件中心。

请注意,有一个属性我们必须手动设置,因为 Terraform 提供者当前(截至 2019 年 11 月)不支持它,这就是分区键列。正确地设置这一点很重要,这样可以确保相关事件组总是在同一个分区中结束,这样就可以按顺序处理它们。在我们的例子中,一个合理的选择是device列,因为这样我们可以确保来自一个特定设备的所有事件都在同一个分区中结束。

询问

查询是定义流分析所做工作的核心。在这里,我们可以使用简单的 SQL 方言来聚合、转换和丰富通过流分析作业传输的数据。对语言和所有可能性的完整解释将会是一篇独立的文章,所以现在我们将简单地描述当前作业中的查询。

该查询由三部分组成。第一种使用内置的[AnomalyDetection_ChangePoint](https://docs.microsoft.com/en-us/stream-analytics-query/anomalydetection-changepoint-azure-stream-analytics)功能来检测温度数据中的异常,通过识别的设备进行分区,并限于最近 30 分钟的数据。我们还在数据中设置时间戳列,以便流分析知道如何对数据进行排序。第二部分从异常检测函数的输出中检索两个值,这两个值告诉我们数据是否被认为是异常的,如果是,算法对数据的意外程度如何。最后,我们查询一些数据被检测为异常的字段,并将结果输出到异常作业输出(之前定义为事件中心)。

这样一来,我们就可以回顾我们概念验证的最后一个组件,即 Azure Event Hubs。

Azure 活动中心

Azure Event Hubs 是一个可扩展的 PaaS 产品,为应用程序提供发布/订阅消息平台。在我们的例子中,我们使用它作为目的地来接收检测到的异常事件,以便由一个或多个下游应用程序进行处理。

活动中心由以下组件组成。

活动中心

事件中心是一个逻辑存储桶,或者用消息传递体系结构中常用的一个短语来说,是一个主题,相关的事件在其上发布。在事件中心内,您可以定义一些属性,如分区数量(提示,选择比您认为需要的更多的分区,因为如果不重新创建事件中心,它们将无法更改)、消费者组(类似于物联网中心,用于定义处理数据的应用程序,以确保同步应用程序在流中的位置)、捕获(便于将事件发送到存储帐户)和消息保留(消息应在中心保留多长时间;考虑您可能需要重新处理多长时间,最多 7 天)。

在我们的例子中,我们定义了一个名为anomalies的事件中心,它将从我们的流分析作业接收输出。

为什么要使用事件中心而不是更简单的队列产品,比如 Azure Queues?通过使用发布/订阅消息总线,而不是队列,我们考虑到了多个消息消费者的可能性;例如,我们可以使用一个消费者生成松弛警报,但是也可以将结果发布到仪表板的某种数据存储中。正如后面所讨论的,我想在这方面准备一些东西,但是我已经超过了我自己为这篇文章规定的时间限制,所以将推迟到后面的文章。

事件中心名称空间

事件中心名称空间是相关事件中心的逻辑集合,是我们为名称空间内的所有事件中心资源定义分配的处理能力的地方。与存储帐户一样,事件中心命名空间名称必须是全局唯一的。

在我们浏览完各种资源之后,让我们通过系统实际运行一些数据,看看结果!

实时数据流

首先,我们必须模拟一个物联网设备向 Azure 物联网中心发送数据。为此,我构建了一个 Docker 容器,您可以使用下面的命令运行它。您将需要我们在上一节中检索的 IoT Hub 连接字符串。请确保在单独的命令提示符下运行该命令,因为它会一直控制命令行,直到您退出容器。

接下来,我们需要启动流分析作业。这可以通过门户来完成。

您可以选择“现在”作为开始时间,这样作业将从当前日期和时间开始消耗数据。

Query窗格中,您可以单击Test Query Results按钮来查看查询的示例输出。

注意:因为只显示异常情况,您可能实际上看不到任何结果。在我们有意引入异常数据的情况下,您可以在下一个操作后重复该步骤。

现在,为了显示异常到达事件中心,我们将引入一些显著不同的数据,从而触发异常检测算法。

首先,退出容器进程,然后指定一些附加选项重新运行它,如下所示。

为了显示输出正在到达事件中心,我们可以浏览到事件中心名称空间资源的Metrics面板,并查看Incoming Messages度量。确保您选择 30 分钟作为您的时间窗口,以获得最佳视图,您可能需要点击几次刷新按钮。

摘要和待办事项

在本文中,我们介绍了使用 Azure 平台从物联网设备接收和使用消息的参考设置,包括物联网中心、Azure 流分析和 Azure 事件中心。在接下来的一篇文章中,我将介绍如何使用 Azure 函数从这个解决方案中消费和生成 Slack 警报。敬请期待!

使用 TensorFlow 创建智能秤

原文:https://towardsdatascience.com/creating-a-smart-scale-with-tensorflow-cf62a834b670?source=collection_archive---------30-----------------------

想要尝试机器学习,同时构建一些有用的东西吗?这里有一个有趣的周末项目,使用 TensorFlow 从你的体重秤图片中自动读取你的体重,并绘制出一段时间的图表。您将学习到 TensorFlow 对象检测 API 的基础知识,并能够将其应用于这个和其他图像分析项目。

Weight over time as automatically detected using TensorFlow from analyzing pictures (the line is more jagged on the right side because there are more data points)

这篇文章故意写得很短,这样你可以很快得到一个很好的概述,同时提供包含更多细节的其他材料的链接。就这样,让我们开始吧!

获取您的秤的图像

首先,与任何机器学习项目一样,数据是关键。每次你站在你的体重秤上,拍一张清楚显示你体重的照片。为了获得最佳效果,可以在不同的光线条件下拍照,也可以在房子的不同区域拍照。100 张图片应该可以作为一个相当好的训练集。

如果你的照片被备份到 Google 相册,那么你可以使用一个脚本,比如这个来下载它们。

标记您的图像

接下来,用一个工具给你的图片加标签,比如 labelImg 。他们的 docker 映像很容易设置,只需几个简单的命令就可以使用。我在整个刻度周围添加了一个名为“刻度”的标签,在圆形显示屏周围添加了另一个名为“读数”的标签。labelImg 将创建 XML 文件,每个图像一个,看起来像这个。

Image of a scale with bounding boxes drawn around the scale and also around the display

训练一个神经网络来检测你的秤

一旦你有了数据,你就可以训练神经网络来检测你的图像的比例。概括地说,步骤如下:

  1. 安装tensor flow 对象检测 API
  2. 安装用于向谷歌云机器学习(ML)引擎提交作业的gcloud命令行工具。
  3. 创建一个谷歌云平台存储桶。您的训练数据将存储在这里。
  4. 上传预先训练的模型,开始你的训练。TensorFlow 为模型动物园提供了一些常见的模型。ssd_mobilenet_v1_coco是一个流行的选择,它在简单模型的速度和准确性之间取得了良好的平衡。
  5. 准备您的自定义输入数据并上传到您的云存储桶。
  6. 将张量流对象检测源代码捆绑到 ML 引擎上运行。
  7. 更新物体检测配置文件。你可以通过最小的改变来重用矿。
  8. 向 ML 引擎提交培训作业。请注意,ML 引擎需要几分钟时间来启动作业。
  9. 当您的训练作业运行时,它每十分钟将其状态写入您的存储桶。您可以使用 TensorBoard 对其进行监控,并寻找曲线的收敛性。如果在单个 GPU 上运行,这个作业可能需要几个小时才能收敛。
  10. 当你的模型被充分训练后,下载并导出它。
  11. 使用您导出的模型来执行一些推理。您可以使用 TensorFlow 的演示版 Jupyter 笔记本检查您的结果。

这里记录了我为每个步骤运行的确切命令,包括我为帮助完成任务而编写的脚本,所以请在那里查看详细信息。也可以参考官方快速入门指南了解更多。

Screenshots of TensorBoard; left: loss curve converging; right: inferred output shown side-by-side with the hand-annotated bounding boxes

训练一个神经网络来读取显示器

现在你已经训练了一个神经网络来检测你的体重,下一步是训练一个从体重计上读取你的体重。

幸运的是,这个过程几乎和你已经做过的一样。概括地说,步骤如下:

  1. 使用该标度的训练模型来自动裁剪出显示器的图像。你可以试试这个任务的我的脚本。
  2. 标记这些图像中的每个数字,以教会神经网络识别它们。我为每个数字(0–9)和“%”使用了一个标签。我的标签图传递给物体检测代码是这里是。
  3. 使用与上述相同的步骤来训练神经网络识别数字。由于训练数据的差异,使用稍微修改的物体检测配置文件和标签图。

把它放在一起

如果你已经做到了这一步,恭喜你!你已经训练了一个模型来识别你的体重,然后再做一次来读取你的体重。现在,您可以将它放在一起,自动分析您拍摄的所有照片,读取您的体重,并使用简单的 HTML 文件(如 this )绘制其随时间变化的趋势。

精明的读者可能会想,为什么我要运行两次,而不是只训练一个模型来识别比例和数字。原因是我不认为单一模型在我的数据上是有效的。对象检测管道通常用于训练大小为 300x300 或类似大小的图像。它当然可以在更大的图像上训练,但这可能需要更长的时间来收敛。当我的图像大幅缩小时,圆形显示变得不可读。因此,我首先训练一个神经网络来找到圆形显示(我仍然在我的配置中将训练图像的大小增加到 600x600)。利用这一点,我们可以从图像中自动提取出圆形显示,在我的数据中,它恰巧是大约 300x300,现在可以使用这些提取的图像在其原始分辨率下训练另一个神经网络来识别数字。

你可能还想知道为什么我不简单地使用现有的 OCR 工具包来读取刻度上的数字。我试了试 Tesseract ,但是它不能识别任何文本,即使在一些预处理之后。我预计,最终,在这个数据集上训练的神经网络无论如何都会胜过传统的 OCR 软件。

最后,我希望这有助于您了解 TensorFlow 的对象检测,并启发您自己构建一些很酷的项目。请在评论区留下你的想法和反馈。

感谢阅读!

创建可靠的数据科学开发环境

原文:https://towardsdatascience.com/creating-a-solid-data-science-development-environment-60df14ce3a34?source=collection_archive---------11-----------------------

如何使用 Conda、Git、DVC 和 JupyterLab 来组织和复制您的开发环境。

1.介绍

开始一个数据科学项目通常很有趣,至少在开始的时候是这样。你得到一些数据,开始提问并探索它,制作一些图,尝试一些模型,几分钟后,你有一堆有趣而混乱的见解和更多的数据争论要做。然后你意识到你必须整理你的 Jupyter 笔记本,开始注释和版本化你的代码,并且你需要花一些时间在你的分析中“不那么有趣”的部分。如果您需要与他人分享您的发现,或者将模型投入生产,那么前面会有更多的问题,因为您发现您并不确切知道在您的分析过程中使用了哪些库和版本。

一般来说,我们数据科学家倾向于更关注结果(模型、可视化等)而不是过程本身,这意味着我们没有像软件工程师那样足够重视文档和版本控制。

既然如此,就有必要使用当今可用的适当工具,为数据科学项目的开发建立良好的实践。

目标:本文的目标是为数据科学家提供工具和方向,通过使用四个关键工具:Conda、Git、DVC 和 JupyterLab,以可靠和可重复的方式管理他们的项目。本教程结束时,您将能够创建一个存储库,对您的脚本、数据集和模型进行版本化,并在新机器上复制相同的开发环境。

本教程是在运行 Ubuntu 18.04 的 Linux 机器上完成的,但是可以很容易地在 Mac 或 Windows 上使用其他命令行包管理器复制,如家酿 (Mac),或巧克力 (Windows)。

此外,我们将使用 S3 自动气象站来存储我们与 DVC 的数据文件。要遵循教程中的相同步骤,您需要一个安装并配置了 awscli 的 AWS 帐户。

遵循本教程创建的项目资源库可以在我的 GitHub 页面上访问。

2.工具

康达

Conda 是一个环境和包管理器,可以代替 Python 中的 pipenv 和 pip 。它是专注于数据科学的 Python(和 R)发行版 Anaconda 的一部分。您可以选择安装完整版(Anaconda,大约 3GB)或轻型版(Miniconda,大约 400MB)。我推荐使用 Miniconda,因为你将只安装你需要的库。关于更广泛的评论,请查看 Gergely Szerovay 关于 Conda 的文章。

饭桶

Git 是一个管理软件开发的版本控制系统。使用 Git,您可以跟踪对存储在存储库文件夹中的代码所做的所有更改。你通常使用云服务如 GitHub 、 Bitbucket 或 GitLab 连接到你的本地存储库来管理和存储你的存储库。我们将使用 GitHub 来存储我们的项目资源库,因此您需要一个活动帐户来遵循教程的步骤。

DVC

DVC (数据版本控制)是管理数据集和机器学习模型的 Git 等价物。你通过 DVC 将你的 Git 库链接到云(AWS,Azure,Google Cloud Platform 等)或本地存储来存储大文件,因为 Git 不适合大于 100MB 的文件。关于 DVC 的完整教程,请看看 Dmitry Petrov 的文章。

JupyterLab

JupyterLab 是一个用于 Jupyter 笔记本、代码和数据的交互式开发环境。这是 Jupyter 项目的最新版本,它提供了传统 Jupyter 笔记本的所有功能,界面更加坚固。笔记本电脑在数据科学项目中非常受欢迎,因为它提供了一种动态探索数据的好方法。

代码编辑器和 Git 客户端

代码编辑器是程序员必备的工具,如今有很多开源和付费的选项。因此,请随意选择更适合您需求的代码编辑器。

Git 客户端是为你的代码版本化提供图形用户界面的工具,并且可以成为帮助你管理项目的工具集的有趣补充。

3.安装 Git 和 Conda

为了开始组织我们的开发环境,我们首先需要安装工具。我们将从安装 Git (1)开始,并使用我们的终端配置它(2)。

**# 1) Install Git** sudo apt-get install git**# 2) Configure your Git account** git config --global user.name "Your Name" 
git config --global user.email "yourmail@mail.com"

接下来,我们将安装 Miniconda,方法是下载它的最新版本(3),更改安装文件的权限(4)并运行它(5)。将 Miniconda 文件夹添加到您的系统路径(6)也很重要,只需在终端上键入 conda 即可运行它的命令。

**# 3) Download Miniconda latest release for Linux** wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh**# 4) Change the permission to run the Miniconda bash file** chmod +x Miniconda3-latest-Linux-x86_64.sh**# 5) Run Miniconda installation file** ./Miniconda3-latest-Linux-x86_64.sh**# 6) Export the path to Miniconda installation folder** export PATH=/home/YOURNAME/miniconda3/bin:$PATH

4.配置开发环境

现在我们已经安装了工具,是时候开始设置我们的开发环境了。

创建项目 Git 存储库

首先,我们将使用 GitHub 信息定义变量(8),在 GitHub 上创建一个远程存储库(9),并检查创建是否成功(10)。接下来,我们创建一个本地文件夹来存储我们的项目存储库(11)和自述文件(12)。然后,我们启动我们的本地 Git 存储库(13)并将我们的第一个提交推送到 GitHub (14)。

**# 8) Define the your GitHub information as variables** GitHubName=<YourGitHubName>
GitHubPassword=<YourGitHubPassword>**# 9) Create a new git repository on GitHub 
#    named "DataScience_DevEnv"** curl -u $GitHubName:$GitHubPassword [https://api.github.com/user/repos](https://api.github.com/user/repos) -d '{"name":"DataScience_DevEnv"}'**# 10) Check if your new repository is available on GitHub**
curl "https://api.github.com/users/$GitHubName/repos?per_page=100" | grep -w clone_url | grep -o '[^"]\+://.\+.git'**# 11) Create a folder with the name of your repository** mkdir DataScience_DevEnv
cd DataScience_DevEnv**# 12) Create a README file for your repository** echo "# Data Science development environment repository" >> README.md**# 13) Initiate our local Git repository** git init**# 14) Add, commit and push README.md to GitHub** git add README.md
git commit -m "first commit with README file"
git remote add origin https://github.com/GabrielSGoncalves/DataScience_DevEnv.git
git push -u origin master

我们可以在 GitHub 页面上检查一下,是否在第一次提交时正确地创建了包含 README 文件的存储库。

用康达创造环境

现在我们已经设置好了 Git 存储库,我们将创建我们的 conda 环境(15)。我们只需要定义我们的环境的名称(-n)、python 版本和我们想要安装的库(例如 pandas 和 scikit-learn)。创建完成后,我们只需要输入conda activate和环境名(16)。

**# 15) Create o Conda environment** conda create -n datascience_devenv python=3.7 pandas scikit-learn**# 16) Activate your environment** conda activate datascience_devenv

在我们的环境中安装 JupyterLab、DVC 和其他库

现在,我们正在我们的 conda 环境中工作,我们可以安装 JupyterLab (17)和 DVC (18)。使用 conda 的另一个好处是它也可以用来安装包,就像我们使用 pip 一样。

**# 17) Install JupyterLab with
# conda**
conda install -c conda-forge jupyterlab**# or pip** pip install jupyterlab**# 18) Install DVC with
# conda**
conda install -c conda-forge dvc**# or pip** pip install dvc

我们可以使用命令list (19)列出当前环境中可用的库。我们还可以使用 conda 或 pip (20)为您的环境生成需求文件。

**# 19) List your packages installed
# with conda**
conda list**# with pip** pip list**# 20) Create requirements file
# with conda**
conda list --export > requirements.txt**# with pip**
pip freeze > requirements.txt

DVC 和附属国

要使用 DVC 来存储您的大数据文件,您需要配置一个远程存储文件夹。我们将在我们的教程中使用 AWS S3,但你有其他选项(本地文件夹、Azure Blob 存储、谷歌云存储、安全外壳、Hadoop 分布式文件系统、HTTP 和 HTTPS 协议)。在 DVC 安装过程中,您必须定义将要使用的存储类型,并在括号(21)中指定。在为 DVC 安装了 AWS S3 依赖项之后,我们初始化我们的 DVC 存储库(22)。接下来,我们将在存储库中创建一个名为data的文件夹来存储我们的数据文件,并用 DVC (23)进行版本控制。然后,我们创建一个 S3 存储桶来远程存储我们的数据文件(24)。重要的是要记住,我们已经用 IAM 凭证配置了 awscli,以便使用终端运行 AWS 命令。创建 S3 存储桶后,我们将其定义为我们的 DVC 远程文件夹(25),并检查最后一步是否被接受(26)。现在我们可以下载一个 csv 文件到我们的data文件夹(27),并开始用 DVC (28)对它进行版本控制。

**# 21) Install DVC and its dependecies for connection with S3** pip install dvc[s3]**# 22) Initialize DVC repository** dvc init**# 23) Create folder on repository to store data files** mkdir data**# 24) Create S3 bucket** aws s3 mb s3://dvc-datascience-devenv**# 25) Define the new bucket as remote storage for DVC** dvc remote add -d myremote s3://dvc-datascience-devenv**# 26) List your DVC remote folder** dvc remote list **# 27) Download data file** wget -P data/ [https://dvc-repos-gsg.s3.amazonaws.com/models_pytorch_n_params.csv](https://dvc-repos-gsg.s3.amazonaws.com/models_pytorch_n_params.csv)**# 28) Add data file to DVC** dvc add data/models_pytorch_n_params.csv

每当我们向 dvc 添加文件时,它都会创建一个. DVC 文件,该文件跟踪对原始文件所做的更改,并且可以用 Git 进行版本控制。DVC 还在data文件夹中创建了一个. gitignore,并将数据文件添加到其中,这样 Git 就可以忽略它,我们不需要手动设置它(29)。最后,我们使用 DVC (30)将数据文件推送到我们的远程文件夹(我们创建的 S3 桶)。

**# 29) Start tracking DVC file and .gitignore with Git** git add data/.gitignore data/models_pytorch_n_params.csv.dvc
git commit -m "Start versioning csv file stored with DVC on S3 bucket"
git push**# 30) Push data file to DVC remote storage on S3 bucket** dvc push

DVC 还可以帮助我们建立管道和进行实验,使测试和重现特定的 ETL 步骤变得更加容易。有关 DVC 功能的更多信息,请查看 Gleb Ivashkevich 的文章。

JupyterLab 内核

安装 JupyterLab 后,我们可以在终端上输入jupyter lab来运行它。作为默认设置,JupyterLab 使用我们的基本 Python 安装作为内核,所以如果我们尝试导入您安装在我们新创建的 conda 环境(而不是基本 Python 环境)上的库,我们将得到一个ModuleNotFoundError。为了解决这个问题,我们需要从我们的环境(32)中安装 ipython 内核(31)。通过这样做,我们将拥有一个与我们的 conda 环境相对应的内核,因此每个已安装和新安装的库都将在我们的 JupyterLab 环境中可用。我们还可以检查安装在我们机器上的可用 Jupyter 内核(33)。

**# 31) Install ipython using conda** conda install ipykernel**# 32) Install your kernel based on your working environment**ipython kernel install --user --name=datascience_devenv**# 33) List the kernels you have available** jupyter kernelspec list

导出我们的康达环境

正如在简介中提到的,一个可靠的开发环境的一个重要方面是容易复制它的可能性。一种方法是将关于 conda 环境的信息导出到 YAML 文件(34)。记住,为了做到这一点,你需要先激活环境。

**# 34) To export your current conda environment to YAML** conda env export > datascience_devenv.yaml**# 35) Add the yaml file to our GitHub repository** git add datascience_devenv.yaml
git commit -m 'add environment yaml to repo'
git push

我们项目存储库的结构

到目前为止,我们的项目存储库具有以下结构(36)。

**# 36) Project repository structure** tree.
├── data
│   ├── models_pytorch_n_params.csv
│   └── models_pytorch_n_params.csv.dvc
├── datascience_devenv.yaml
├── README.md
└── requirements.txt

如果我们在命令tree中使用参数-a,我们可以更好地理解构成 Git 和 DVC (37)的配置文件。如前所述,DVC 为我们添加的每个数据文件创建了一个. gitignore,这样 Git 就可以避免跟踪它。

**# 37) Detailed repository structure**
tree -a
.
├── data
│   ├── .gitignore
│   ├── models_pytorch_n_params.csv
│   └── models_pytorch_n_params.csv.dvc
├── datascience_devenv.yaml
├── .dvc
│   ├── cache
│   │   └── 6f
│   │       └── 387350081297a29ecde86ebfdf632c
│   ├── config
│   ├── .gitignore
│   ├── state
│   ├── tmp
│   └── updater
├── .git
│   ├── branches
│   ├── COMMIT_EDITMSG
│   ├── config
│   ├── description
│   ├── HEAD
│   ├── hooks
│   │   ├── applypatch-msg.sample
│   │   ├── commit-msg.sample
│   │   ├── fsmonitor-watchman.sample
│   │   ├── post-update.sample
│   │   ├── pre-applypatch.sample
│   │   ├── pre-commit.sample
│   │   ├── prepare-commit-msg.sample
│   │   ├── pre-push.sample
│   │   ├── pre-rebase.sample
│   │   ├── pre-receive.sample
│   │   └── update.sample
│   ├── index
│   ├── info
│   │   └── exclude
│   ├── logs
│   │   ├── HEAD
│   │   └── refs
│   │       ├── heads
│   │       │   └── master
│   │       └── remotes
│   │           └── origin
│   │               └── master
│   ├── objects
│   │   ├── 10
│   │   │   └── c06accd2ad99b6cde7fc6e3f3cd36e766ce88f
│   │   ├── 19
│   │   │   └── 193f4a173c56c8d174ecc19700204d250e9067
│   │   ├── 4e
│   │   │   └── 0790499d1d09db63aaf1436ddbd91bfa043058
│   │   ├── 52
│   │   │   └── 4cb7d319626c1bcf24ca5184d83dc1df60c307
│   │   ├── 5f
│   │   │   └── 694b1bd973389b9c0cdbf6b6893bbad2c0ebc6
│   │   ├── 61
│   │   │   └── d5f990a1bee976a2f99b202f1dc14e33b43702
│   │   ├── 67
│   │   │   └── 3b06660535a92d0fdd72fe51c70c9ada47f22d
│   │   ├── 70
│   │   │   └── 1490f13b01089d7da8fa830bae3b6909d12875
│   │   ├── 72
│   │   │   └── a0ddbcc242d223cd71ee5a058fc99de2fa53cc
│   │   ├── a3
│   │   │   └── b5ebf7e3b752fa0da823aeb258b96e007b97ef
│   │   ├── af
│   │   │   └── 8017769b22fcba5945e836c3c2d454efa16bd1
│   │   ├── c1
│   │   │   └── 694ff5e7fe6493206eebf59ac31bf493eb7e6b
│   │   ├── d7
│   │   │   └── 39682b1f99f9a684cecdf976c24ddf3266b823
│   │   ├── e4
│   │   │   └── 5eca3c70f6f47e0a12f00b489aabc526c86e8b
│   │   ├── e6
│   │   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│   │   ├── ee
│   │   │   └── 75f0e66a68873ac2f767c212c56411cd729eb2
│   │   ├── info
│   │   └── pack
│   └── refs
│       ├── heads
│       │   └── master
│       ├── remotes
│       │   └── origin
│       │       └── master
│       └── tags
├── README.md
└── requirements.txt

接下来,我们在你的存储库的根目录下为我们不想跟踪的其他文件创建一个. gitignore (例如 Python 编译的字节码文件。pyc)与 Git (38)。

**# 38) Add .gitignore for script files on our repository** echo "*.pyc" >> .gitignore
git add .gitignore
git commit -m 'Add .gitignore for regular files'
git push

现在我们已经配置好了开发环境,并且准备好了。我们的 JupyterLab 拥有与我们的 conda 环境相匹配的内核,我们的数据文件由 DVC 进行版本控制,我们的 Git 存储库正在跟踪其余的文件。因此,对我们项目所做的任何更改都将被记录下来,并且可以很容易地被复制和跟踪。

5.复制我们的开发环境

在设置我们的 Git 存储库和配置我们的 DVC 存储文件夹之后,我们可以在任何新机器上复制它。简单地克隆存储库(39),从 YAML 文件创建一个 conda 环境(40),激活它(41),为我们的环境创建一个 JupyterLab 内核(42),最后使用 DVC 从 S3 桶拉数据文件(43)。

**# 39) On a new machine, clone the repository** git clone [https://github.com/$GitHubName/DataScience_DevEnv.git](https://github.com/GabrielSGoncalves/DataScience_DevEnv.git)**# 40) Create conda environment** conda env create --file=datascience_devenv.yaml**# 41) Activate environment** conda activate datascience_devenv**# 42) Install the JupyterLab kernel** ipython kernel install --user --name=datascience_devenv**# 43) Pull the data file from the S3 bucket using DVC** dvc pull

因此,我们可以在一台新机器上拥有完全相同的开发环境(包括数据文件和已安装的库),只需要 5 条命令。

7.结论

在本文中,我们展示了为数据科学家创建可靠且可重复的开发环境的关键工具。我们相信,通过在项目开发中使用最佳实践,数据科学是一个可以变得更加成熟的领域,康达、Git、DVC 和 JupyterLab 是这种新方法的关键组成部分

要了解更多关于实践和方法的数据科学开发环境的观点,请看看威尔·科尔森的文章。

非常感谢你阅读我的文章!

  • 你可以在我的个人资料页面 找到我的其他文章🔬
  • 如果你喜欢并且想成为中级会员,你可以使用我的 推荐链接 来支持我👍

更多资源

[## 为什么需要 Python 环境以及如何使用 Conda-protostar . space 管理它们

我不应该只安装最新的 Python 版本吗?

medium.com](https://medium.com/@gergoszerovay/why-you-need-python-environments-and-how-to-manage-them-with-conda-protostar-space-cf823c510f5d) [## 数据版本控制教程

2019 年 3 月 4 日更新:本教程中的代码示例已经过时。请使用更新的教程…

blog.dataversioncontrol.com](https://blog.dataversioncontrol.com/data-version-control-tutorial-9146715eda46) [## JupyterLab 已经为用户准备好了

我们很自豪地宣布 JupyterLab 的测试版系列,这是 Project…

blog.jupyter.org](https://blog.jupyter.org/jupyterlab-is-ready-for-users-5a6f039b8906) [## 使用 DVC 创建可重复的数据科学工作流

“入门”教程进入 DVC,在你的日常管理工作中建立一个结构和秩序

medium.com](https://medium.com/y-data-stories/creating-reproducible-data-science-workflows-with-dvc-3bf058e9797b) [## 快速添加到。从终端 gitignore

我不久前学了一个技巧来创造我的。gitignore 文件(并添加到它)很快从终端。这里有一个常见的…

raddevon.com](https://raddevon.com/articles/adding-to-gitignore-from-the-terminal/) [## 2019 年排名前 5 的代码编辑器

自从微软的 Visual Studio 代码推出以来,代码编辑器大战真的白热化了。有这么多…

www.software.com](https://www.software.com/review/ranking-the-top-5-code-editors-2019) [## Mac 的 10 个最佳 GUI Git 客户端

Git 是一个版本控制系统,用于跟踪文件变化。通常用于团队环境,尤其是…

www.fossmint.com](https://www.fossmint.com/gui-git-clients-for-mac/) [## 如何避免数据科学编程环境中的常见困难

减少编程环境中的附带问题,这样您就可以专注于重要的数据科学问题。

towardsdatascience.com](/how-to-avoid-common-difficulties-in-your-data-science-programming-environment-1b78af2977df)

用 C++创建 TensorFlow CNN(第 2 部分)

原文:https://towardsdatascience.com/creating-a-tensorflow-cnn-in-c-part-2-eea0de9dcada?source=collection_archive---------6-----------------------

在这篇文章中,我将展示如何使用 TensorFlow C++ API 创建、训练和测试一个卷积神经网络

背景

最近两年,谷歌的 TensorFlow 越来越受欢迎。它是迄今为止最受欢迎的深度学习框架,与 Keras 一起,它是最主要的框架。

现在有了版本 2,TensorFlow 包含了 Keras 构建的内容。

然而,当谈到 C++ API 时,你真的找不到太多关于使用它的信息。大多数代码示例和文档都是用 Python 编写的。正如我在以前的帖子中提到的,我希望允许 C++用户,比如我自己,使用 TensorFlow C++ API,这是一个低级 API,这实际上意味着您必须投入更多的工作来实现它。我的帖子是来帮助你的。

就像我过去写的,我喜欢 C++。我并不反对 Python,但是我希望能够用 C++来构建我的模型,并且拥有工具生态系统来帮助我调试和优化它。

我阅读了文档,并寻找将向我展示如何创建卷积神经网络的代码示例。有几个例子,这里的和这里的启发了我。仅此而已!

我必须对一些 API 进行逆向工程,经历了大量的试验和错误,直到它工作为止。

我希望这篇文章能够帮助那些想开始使用 C++ API 的人。

我在 MacOS 上使用 XCode,但我试图以一种在 Windows 或 Linux 上也能工作的方式构建代码。我没有测试过,所以如果你有任何改变的建议,请告诉我。

设置

我假设您已经安装了 TensorFlow,并且有一个 XCode 项目可以使用它。如果你需要这方面的帮助,请阅读并遵循我的指示这里。

正如我在第 1 部分中所写的,我们的目标是实现 Arden Dertat 著名文章系列第 4 部分中的 AlexNet 缩减版。

我还假设你知道卷积网络的术语,如果没有,我建议你阅读 Arden 的文章。

为了获得训练数据,您需要从 Kaggle 下载图像。

从这里下载小版本。那里有足够的图像供我们使用。

提取文件,并将它们放在项目文件夹下的数据文件夹中。

它应该是有组织的,所以你有三个子文件夹用于训练,验证和测试。

密码

这篇文章的代码可以在这里找到。

有一个驱动执行的 main.cpp 和两个类文件 CatDogCNN.cpp 和 CatDogCNN.h,它们是网络本身的实现。

mainV1.cpp 是前面的文章代码。

通常,在为 TensorFlow 编写代码时,将图形的创建与其实际运行分开是明智的。这是由于一个简单的事实,即您通常创建一次图表,然后用不同的输入运行多次。即使你不改变图的变量(如权重),也没有必要在每次运行图时重新创建图,除非它非常简单,并且分离的努力是无用的。

完成数据准备

CreateGraphForImage 是一个创建类似于我在第一部分中展示的图形的方法。

它接受是否拆分图像的布尔值。当您只想加载一个图像时调用 false,当您想加载一批图像时调用 true。这是因为堆叠批次时会增加一个额外的尺寸。但是,当你想运行 CNN 只有一个图像,你需要有所有 4 个维度。

请注意,当从拆分更改为堆叠时,您必须重新创建图形。

ReadTensorFromImageFile 负责运行由前面的方法创建的图形。你输入一个文件的完整路径名,得到一个 3 或 4 维张量。

这两种方法的代码几乎与 mainV1.cpp(文章第 1 部分)中的代码相同。

处理文件夹和路径

ReadFileTensors 处理文件夹和文件。它接受一个基本文件夹字符串和一个向量对[子文件夹,标签值]。

如果你从 Kaggle 下载了图片,你可能会注意到在 train 下有两个子文件夹 cats 和 dogs。用一个数字标记它们中的每一个,并将这些对作为输入进行传递。

返回的是一对向量,每一对向量都是一个张量(图像的)和一个标签。

这里有一种说法:

base_folder = "/Users/bennyfriedman/Code/TF2example/TF2example/data/cats_and_dogs_small/train";vector<pair<Tensor, float>> all_files_tensors;model.ReadFileTensors(base_folder, {make_pair("cats", 0), make_pair("dogs", 1)}, all_files_tensors);

我们需要打开一个目录,读取其中的文件,然后一个一个地检查。

要连接两个路径字符串,请使用 io::JoinPath(包括 tensorflow/core/lib/io/path.h)

string folder_name = io::JoinPath(base_folder_name, “cats”);

要与文件系统交互,请使用“Env”。这是一个实用程序类(没有真正的文档记录),它为您提供了类似于 C++17 std::filesystem 的便利。

Env* penv = Env::Default();TF_RETURN_IF_ERROR(penv->IsDirectory(folder_name));vector<string> file_names;TF_RETURN_IF_ERROR(penv->GetChildren(folder_name, &file_names));for(string file: file_names){…}

ReadFileTensors 还会打乱矢量中的图像,这样我们就可以在训练时输入不同的图像(你不会想先喂所有的猫,然后再喂所有的狗)。

创建批处理

ReadBatches 封装了所有的逻辑 main 需求。你给它一个基本文件夹,一对子文件夹和标签的向量,以及一个批处理的大小。作为回报,你得到两个张量向量,一个用于图像,一个用于标签。每个张量都是按照你传递的大小一批图像/标签。

首先,它将文件夹及其子文件夹的内容读入一个向量。接下来,它会计算如何拆分批次。然后,它断开张量和标签对以创建两个输入向量,其中张量向量中的每个第 n 个元素匹配标签向量中的第 n 个元素。

为了堆叠这两个向量,我们当场创建一个小图,并在每次迭代中运行它。

结果被添加到输出向量中。

注意堆栈操作是如何需要得到一个要堆栈的图像张量的输入列表的。最简单的方法是创建一个 vector(或另一个容器)并用它实例化 InputList。

vector<Input> one_batch_image;one_batch_image.push_back(Input(tensor));//Add more tensorsInputList one_batch_inputs(one_batch_image);Scope root = Scope::NewRootScope();auto stacked_images = Stack(root, one_batch_inputs);ClientSession session(root);vector<Tensor> out_tensors;TF_CHECK_OK(session.Run({}, {stacked_images}, &out_tensors));//use out_tensors[0]

如上所述,张量以三维张量的形式出现,而创建的批次是四维的。

CNN 图表

现在有趣的部分来了。

我们想创建一个类似于 AlexNet 的模型。

投入

首先,我们想要定义图形的输入:我们已经知道我们需要输入一批图像:

input_batch_var = Placeholder(t_root.WithOpName("input"), DT_FLOAT);

占位符类似于函数参数。您指定了它的名称和元素类型,但此时它的形状未知。

从占位符获取结果的变量是 CatDogCNN 类类型输出的成员。

首先,我们在图中使用它作为第一层的输入,稍后我们将需要在 ClientSession 运行命令中指定它及其值(批处理张量)。

接下来有几个占位符,我稍后会解释。

与通常的 Python Keras 网络不同,C++层是操作的组合(Google 称之为低级 API)。为了知道每个操作属于哪一层,我们为每一层创建一个子范围。

Scope scope_conv1 = t_root.NewSubScope("Conv1_layer");

将使用此范围对象创建操作。

盘旋

第一层是卷积层,所以我们需要定义 4 个参数:过滤器高度和宽度以及进出通道。此外,我们还有激活函数(Relu)和后面的 MaxPool 操作。

我们有 4 个 Conv 层,所以我创建了一个函数来创建一个包含这些操作的通用层:

Input CatDogCNN::AddConvLayer(string idx, Scope scope, int in_channels, int out_channels, int filter_side, Input input){TensorShape sp({filter_side, filter_side, in_channels, out_channels});m_vars["W"+idx] = Variable(scope.WithOpName("W"), sp, DT_FLOAT);m_shapes["W"+idx] = sp;m_assigns["W"+idx+"_assign"] = Assign(scope.WithOpName("W_assign"), m_vars["W"+idx], XavierInit(scope, in_channels, out_channels, filter_side));sp = {out_channels};m_vars["B"+idx] = Variable(scope.WithOpName("B"), sp, DT_FLOAT);m_shapes["B"+idx] = sp;m_assigns["B"+idx+"_assign"] = Assign(scope.WithOpName("B_assign"), m_vars["B"+idx], Input::Initializer(0.f, sp));auto conv = Conv2D(scope.WithOpName("Conv"), input, m_vars["W"+idx], {1, 1, 1, 1}, "SAME");auto bias = BiasAdd(scope.WithOpName("Bias"), conv, m_vars["B"+idx]);auto relu = Relu(scope.WithOpName("Relu"), bias);return MaxPool(scope.WithOpName("Pool"), relu, {1, 2, 2, 1}, {1, 2, 2, 1}, "SAME");}

让我们回顾一下代码:

AddConvLayer 获取一个索引字符串(用于区分层)、子范围、输入和输出通道、过滤器大小(我们假设高度和宽度相同)和输入 Input。

通道中的第一层是图像的颜色数(3 种颜色),输入是图像张量。

Conv2D 操作需要一个张量变量来保存不同的滤波器(第一层中的 32 个)。当网络在训练时,这个变量将在每一步内改变。

出于这个原因,有一个成员映射 m_vars 保存这些变量以及偏差。此外,我们需要存储这些变量的形状(m_shapes map),我们还需要用值初始化这些变量(类似于 Python 变量初始化器)——这些操作存储在 m_assigns 中。Xavier 初始化现在很流行,所以我为 Conv 和 Dense 实现了 XavierInit。

在 Conv2D 之后,调用 BiasAdd 来添加偏置(初始化为 0)。

接下来是对 Relu 的调用,然后是对 MaxPool 的调用。

请注意,对于 Python Keras 版本中的 MaxPool,您只需指定窗口大小及其两个维度(例如 2,2)。这里我们需要提供两个四维的形状(窗口大小和跨度)。要将每层中的图像大小减半,必须在窗口大小和步幅中输入 1,2,2,1。

还要注意,在 CreateGraphForCNN 函数中,我跟踪了进出通道的大小,因为它们必须在层之间匹配。

此外,由于没有办法从运算中得到张量的形状(只有在运行时才知道),我们必须在每一步中计算图像的大小。

平的

扁平化意味着我们将只有两个维度,批处理和平面数据。

为此,我们需要重塑张量。因为我不想硬编码批处理大小(我不知道它是否会被批处理),所以我必须知道平面数据的大小。这就是为什么我在这些层中做这些计算,直到我们得到 flat_len。

auto flat = Reshape(flatten, pool4, {-1, flat_len});

在 Reshape 中,您可以在其中一个维度中传递-1,因此它将被自动计算。整形不会添加数据,只会改变数据的组织方式。

拒绝传统社会的人

这一层负责丢弃随机的神经元,这样网络就不会过度适应。

我们创建一个具有相同形状的新张量,并根据丢弃率随机填充 0 或 1,然后用它乘以我们的数据。

然而,当你想要验证或预测时,你不想放弃神经元。

实现这一点的逻辑方法是在图中放置一个条件。有一些操作以一种非常麻烦的方式支持它(切换和合并),但是在 C++中它们不支持反向传播,所以我们不能使用它们。

相反,我向网络 drop_rate 和 skip_drop 引入了另外两个输入参数,例如,如果您分别传递 0.4 和 0,就会得到 40%的丢弃。如果你通过 1 和 1,就不会有水滴。

Scope dropout = t_root.NewSubScope("Dropout_layer");auto rand = RandomUniform(dropout, Shape(dropout, flat), DT_FLOAT);//binary = floor(rand + (1 - drop_rate) + skip_drop)auto binary = Floor(dropout, Add(dropout, rand, Add(dropout, Sub(dropout, 1.f, drop_rate_var), skip_drop_var)));auto after_drop = Multiply(dropout.WithOpName("dropout"), Div(dropout, flat, drop_rate_var), binary)

丢弃时,我们通过除以丢弃率来增加剩余神经元的值。

注意,当 skip_drop 为 1 时,floor 会将“二进制”变为全 1。

完全连接(密集)

接下来是三个致密层。

密集是基于乘以权重并加上偏差。我们将变量保存在地图中,对形状和赋值也是如此。

我们还用 Xavier init 初始化权重,用 0 初始化偏差。

注意,在最后一个密集层中,我们需要跳过 Relu 激活(为此我们有细菌培养)。

二元分类

最后的致密层将尺寸减小到 1(超过批量尺寸)。这就是所谓的逻辑。

为了使逻辑值为 0(代表猫)或 1(代表狗),我们调用 Sigmoid 并返回这个结果。

这就是打开 TensorBoard 时网络的样子(详见第 1 部分):

The CNN before we add optimization

我打开了其中一个子范围,这样你就可以看到第四个卷积层中的低级操作。

优化图(反向传播)

这封装在 CreateOptimizationGraph 函数中。它不是一个单独的图,而是同一个图中的附加节点(同一个 t_root 主作用域)。

我们从标签的占位符开始。如果图像张量是 x,这是 y。

接下来我们计算损失。这是一个分类问题,所以我们应该使用交叉熵,但是我不知道如何使用 SoftmaxCrossEntropyWithLogits 操作,也找不到任何有意义的信息,所以我必须使用常规的均方 diff 方法。

input_labels_var = Placeholder(t_root.WithOpName("inputL"), DT_FLOAT);Scope scope_loss = t_root.NewSubScope("Loss_scope");out_loss_var = Mean(scope_loss.WithOpName("Loss"), SquaredDifference(scope_loss, out_classification, input_labels_var), {0});TF_CHECK_OK(scope_loss.status());

接下来,我收集所有的权重和偏差,并将它们和损失一起发送给神奇的 API 调用 AddSymbolicGradients。这个神奇的功能不是手术。它获取一个图(通过其相关范围),添加所有相关的反向传播操作,并返回一个梯度向量,其大小与权重和偏差的数量相同。

然后,我们对权重和偏差中的每个变量使用 ApplyAdam 及其各自的梯度。

auto adam = ApplyAdam(t_root, i.second, m_var, v_var, 0.f, 0.f, learning_rate, 0.9f, 0.999f, 0.00000001f, {grad_outputs[index]});v_out_grads.push_back(adam.operation);

出于某种原因,m_var 和 v_var 必须是变量(它们不能是常数)。

传递给 ApplyAdam 的最重要的变量是学习率。我怎么强调这个价值的重要性都不为过。我从 0.001(来自 python 版本)开始,无法停止对为什么损失不收敛的困惑。最终我意识到优化函数在两个峰值之间跳得太长了。仅仅过了几天,当我把它改成 0.0001 时,它就开始工作了。您可以尝试不同的值,看看它在您的情况下是如何工作的。

你也可以改变 ApplyAdam 得到的其他值,尽管我不确定这会有什么影响。

现在,张量板图像看起来“有点”不同:

The CNN with optimization

初始化

我已经提到了用赋值操作初始化所有变量的需要。

我们将所有 m_assigns 元素(也是我们为 ApplyAdam 添加的元素)收集到一个 vector 中,并在创建的会话中运行它们。

vector<Output> ops_to_run;for(pair<string, Output> i: m_assigns)ops_to_run.push_back(i.second);t_session = unique_ptr<ClientSession>(new ClientSession(t_root));TF_CHECK_OK(t_session->Run(ops_to_run, nullptr));

保留摘要文件编写器代码周围的注释,仅当您想要为 TensorBoard 可视化生成新图形时才使用它。

培养

让我们回到 main:我们构造了 CatDogCNN 类的一个实例,创建了图形,加载了图像并运行了初始化。

现在是主历元/步长循环的时间。

一个历元是贯穿所有训练数据的一次运行。一个步骤是一批图像的一次运行。

我们定义历元的数量,遍历它们,然后遍历批。

在每次迭代中,我们调用 TrainCNN,我们调用 ValidateCNN,我们做一些计算来检查网络的性能。

TrainCNN 得到一批图像,一批标签(对应这些图像)并返回结果和损失。

该函数首先运行批处理:

vector<Tensor> out_tensors;//Inputs: batch of images, labels, drop rate and do not skip drop.//Extract: Loss and result. Run also: Apply Adam commandsTF_CHECK_OK(t_session->Run({{input_batch_var, image_batch}, {input_labels_var, label_batch}, {drop_rate_var, 0.5f}, {skip_drop_var, 0.f}}, {out_loss_var, out_classification}, v_out_grads, &out_tensors));

然后它计算精确度。注意使用张量方法来提取数据:out_tensors[0]。标量 ()(0)得到一个标量和 out_tensors[1]。matrix ()得到一个矩阵(几乎就像向量的向量)。

确认

验证是重要的,因为事实上我们运行的网络图像,网络从未见过。如果在每一个时期我们都有更好的表现,我们就不会过度适应。

vector<Tensor> out_tensors;//Inputs: batch of images, drop rate 1 and skip drop.TF_CHECK_OK(t_session->Run({{input_batch_var, image_batch}, {drop_rate_var, 1.f}, {skip_drop_var, 1.f}}, {out_classification}, &out_tensors));

请注意不同之处:我们跳过了漏失(见上面的解释),我们不评估损失,我们不运行梯度。

输出控制台如下所示:

Epoch 1/20:....................................................................................................Validation:..................................................Time: 74 seconds Loss: 0.243231 Results accuracy: 0.561 Validation accuracy: 0.642Epoch 2/20:....................................................................................................Validation:..................................................Time: 72 seconds Loss: 0.203312 Results accuracy: 0.6875 Validation accuracy: 0.692***Epoch 20/20:....................................................................................................Validation:..................................................Time: 73 seconds Loss: 0.041021 Results accuracy: 0.956 Validation accuracy: 0.742

损失在持续下降,结果准确率将达到 95%,验证准确率将达到 75%。

测试

我们来测试一下训练好的网络。

为此,我们需要重新创建负载图像图,这样它就不会散开。

然后我们调用 ReadFileTensors 来加载 test 子文件夹中的图像。最后,我们运行其中几个的循环,以查看网络的性能。

预测类似于验证,尽管它运行单个图像。

输出控制台如下所示:

Test number: 1 predicted: 0 actual is: 0Test number: 2 predicted: 1 actual is: 1***Test number: 20 predicted: 0 actual is: 0total successes: 16 out of 20

80%的准确率。有一些改进的空间,但是我们比 Arden 在他的网络上得到更好的结果。

摘要

我们看到了如何只用 C++和 TensorFlow API 实现、训练和测试 CNN。

我们看到了如何准备数据(用于训练、验证和测试的图像)以及如何对它们进行批处理,以便我们可以将这些批处理提供给 TensorFlow 低级 API。

我们实现了梯度和其他优化方法。

我们取得了良好的结果,但还有更多工作要做。

接下来我打算做一些改进。

正如你在控制台输出中看到的,我正在我的本地 MacBook Pro CPU 上运行,它需要很长时间才能运行…

我打算实现冻结模型功能和 GPU 的使用,以加快速度。

此外,我会看看我是否可以做一些图像增强,为培训创建更多的数据。

用 C++创建 TensorFlow CNN(第 3 部分:冻结模型并扩充它)

原文:https://towardsdatascience.com/creating-a-tensorflow-cnn-in-c-part-3-freezing-the-model-and-augmenting-it-59a07c7c4ec6?source=collection_archive---------17-----------------------

这是关于如何在 TensorFlow C++ API 上创建 CNN 的第三篇也是最后一篇文章。在本文中,我将讨论实现模型冻结、保存和加载,以及数据扩充

背景

前两篇文章(这里和这里)讨论了如何实现 CNN,以及训练、验证和测试它的方法。现在,您需要优化模型以获得更好的结果,并将其部署到“生产”环境中,以便您可以使用优化后的模型进行一些预测。

就像我之前的文章一样,我会详细说明 TensorFlow 在其 C++ API 中不太成熟的地方,以及如何克服这些困难。

这篇文章的代码位于这里。

冻结模型

虽然冷冻模型是最后一步,但我先讨论一下。

你建立你的模型,然后你训练和优化它。一旦你对结果满意,你想要保存模型权重和偏差;把它们从变量变成常量。

这样做时,将模型保存到磁盘将保存常数,稍后当您加载模型时,它就可以运行并可以对新图像进行分类。

新旧 API

TensorFlow C++ API 包括两组 API:

–旧的(基于会话类别);和

–新的(基于 ClientSession 类)

我选择了新的。然而,我注意到存储库中的一些实用程序类还没有迁移到新的 API 中。TensorFlow 存储库附带的冻结/保存实用程序类使用较旧的 API。在/tensor flow/cc/tools/freeze _ saved _ model . cc 文件和头文件中实现。

要使用 API,应该包含/tensor flow/cc/tools/freeze _ saved _ model . h 文件,并调用 FreezeSavedModel API 调用来冻结模型。

问题是,您需要传递会话对象(间接),以便内部实现可以进入活动模型以获取变量的当前值。但是,您没有会话,您有一个 ClientSession,并且该 ClientSession 不公开其具有该会话对象的内部数据。

那你是做什么的?有几个策略:

1.使用旧的 API 重新实现 CNN,这意味着不仅要使用会话,还要使用字符串作为变量名,而不是句柄(模型创建代码中的“auto”声明)。

2.不需要发送会话对象:在调用 API 之前收集变量值,并传递这些值和其他参数。

我选择了第二个选项。我想保持代码的整洁,以便有一天,当有人将这些代码移植到新的 API 时,您可以简单地调用它而无需准备。

如何冷冻

为了冻结模型,我们需要找到所有变量及其各自的值。

变量和偏差的列表已经可用,我们在创建优化图时使用它作为向量(这些是我们计算梯度的变量)。

因此,我们所需要的是一个映射这些变量和当前值的 map 对象:

vector<Tensor> out_tensors;//Extract: current weights and biases current valuesTF_CHECK_OK(t_session->Run(v_weights_biases , &out_tensors));unordered_map<string, Tensor> variable_to_value_map;int idx = 0;for(Output o: v_weights_biases){ variable_to_value_map[o.node()->name()] = out_tensors[idx]; idx++;}

接下来,我们从示波器中获得图形(就像我们使用 TensorBoard 可视化它时所做的那样)。

接下来,我们创建一个包。bundle 是一种特殊的结构,它结合了会话和元图。将不会使用该会话(如前所述),因为我们已经有了所需的地图。

元图是一个非常复杂的类,用于各种用例,但我们只需要它用于 SignatureDef,这类似于函数签名(输入和输出)。

我们用数据填充它,并添加图表本身:

SavedModelBundle saved_model_bundle;SignatureDef signature_def; (*signature_def.mutable_inputs()) [input_batch_var.name()].set_name(input_batch_var.name());(*signature_def.mutable_outputs())[out_classification.name()].set_name(out_classification.name());MetaGraphDef* meta_graph_def = &saved_model_bundle.meta_graph_def;(*meta_graph_def->mutable_signature_def())["signature_def"] = signature_def;*meta_graph_def->mutable_graph_def() = graph_def;SessionOptions session_options;saved_model_bundle.session.reset(NewSession(session_options));//even though we will not use it

接下来,我们准备几个输出参数,并调用修改后的 API:

TF_CHECK_OK(FreezeSavedModel(saved_model_bundle, variable_to_value_map, &frozen_graph_def, &inputs, &outputs));

原始 API 中不存在参数 variable_to_value_map,我添加了它,这样我们就可以跳过会话对象的使用。您还可以查看 freeze_saved_model.cc 文件,查看该文件中与该更改相匹配的其他更改。

最后,我们调用 WriteBinaryProto 将冻结的输出图保存到文件中。

加载冻结的模型

加载模型又涉及到旧的 API(意味着会话,而不是客户端会话):

std::unique_ptr<GraphDef> graph_def;SessionOptions options;f_session.reset(NewSession(options));graph_def.reset(new GraphDef());TF_CHECK_OK(ReadBinaryProto(Env::Default(), file_name, graph_def.get()));return f_session->Create(*graph_def.get());

我们首先创建一个会话,然后创建一个 GraphDef,最后读取 protobuf 文件以在会话中创建图形。

运行“生产”模型预测

由于我们使用旧的 API 来创建会话,我们还需要一个特殊的方法来运行预测模型,使用我们前面创建的相同会话:

Status CatDogCNN::PredictFromFrozen(Tensor& image, int& result){ vector<Tensor> out_tensors; Tensor t(DT_FLOAT, TensorShape({1})); t.scalar<float>()(0) = 1.f; //Inputs: image, drop rate 1 and skip drop. TF_CHECK_OK(f_session->Run({{input_name, image}, {drop_rate_name, t}, {skip_drop_name, t}}, {out_name}, {}, &out_tensors)); auto mat = out_tensors[0].matrix<float>(); result = (mat(0, 0) > 0.5f)? 1 : 0; return Status::OK();}

该方法获取单个张量图像并返回类(0 或 1:猫或狗)。

请注意我们是如何使用变量的名称而不是句柄的。除此之外,代码的其余部分不言自明。

在 main 中使用类方法

在 main 中,我创建了一个 if 分支,它选择我们是要使用一个冻结的模型,还是训练这个模型,然后保存它:

string proto_name = "/Users/bennyfriedman/Code/TF2example/TF2example/frozen/cnn.pb";bool use_frozen = false;if(!use_frozen){ … //this is where the model training code is … …//and at the end s = model.FreezeSave(proto_name); TF_CHECK_OK(s);}else //use the frozen model{ s = model.LoadSavedModel(proto_name); TF_CHECK_OK(s); //testing the model s = model.CreateGraphForImage(false);//rebuild the image loading model without unstacking TF_CHECK_OK(s); string base_folder = "/Users/bennyfriedman/Code/TF2example/TF2example/data/cats_and_dogs_small/test"; vector<pair<Tensor, float>> all_files_tensors; s = model.ReadFileTensors(base_folder, {make_pair("cats", 0), make_pair("dogs", 1)}, all_files_tensors); TF_CHECK_OK(s); //loop through the images and call PredictFromFrozen to get the prediction.}

阅读存储库中的代码,查看统计数据是如何计算的。
不要忘记你需要包含修改后的头文件,并将修改后的 cc 文件添加到你的项目中,这样它将作为产品的一部分进行编译。

衡量模型性能

我们已经了解了如何计算损失、准确性和验证指标。

现在的目标是看到一个图表,显示指标随时间的变化(运行时期的进度)。这将告诉我们是否过度适应或者干脆停止学习。

在 Python 中使用 Keras API 时,内置了指标的可视化。

在 C++ API 中,您有两个选项:

1.使用模型中的日志操作将指标写入磁盘

2.使用我们在上一篇文章中用来可视化图表的实用程序类摘要文件编写器,将度量保存到模型外部的磁盘上

在这两种情况下,你都使用张量板来想象。

你用哪一个?看情况。一方面,由于 API 是对 ScalarSummary 操作的一个简单调用,因此在模型内部更容易一些。另一方面,使用 utility 类为您提供了在模型之外计算指标的灵活性。

我使用了第二个选项:

SummaryWriterInterface *w1;TF_CHECK_OK(CreateSummaryFileWriter(1, 0, "/Users/bennyfriedman/Code/TF2example/TF2example/graphs/loss/", "loss", Env::Default(), &w1));Tensor t(DT_FLOAT, TensorShape({1}));t.scalar<float>()(0) = loss_sum/num_batches;TF_CHECK_OK(w1->WriteScalar(epoch, t, "Original"));

首先创建一个摘要文件编写器对象,然后创建一个标量形状的张量,并使用访问器 scalar <>()填充数据。

然后使用 WriteScalar 将其写入磁盘。

可视化将通过 TensorBoard 完成(见下文)。

组合图表

在大多数情况下,您希望看到指标之间的相互关系如何随着时间的推移而变化。您希望一个接一个地查看图表,以便比较准确性和有效性。

这有点令人困惑,所以你需要注意:

1.对于每个指标,您需要一个单独的文件写入器,将数据保存在单独的文件夹中(文件名后缀参数不太重要)

2.对于图形的每个版本,都需要一个惟一的标记(传递给 WriteScalar 的字符串)。带有此标签的数据将出现在同一个组合图表中。

3.连续运行该程序会在磁盘上添加不同的文件,但 TensorBoard 会将新数据添加到相同的图表中,除非您更改文件夹或删除旧文件。

所以策略应该是:

1.使用 3 个文件写入器(分别用于损失、准确性和验证指标),在“/graphs”文件夹下有 3 个子文件夹。

2.为模型的每个版本使用不同的标签。例如,我将进行一些数据扩充,这将增加通过模型运行的图像数量,因此我将使用“原始”进行正常运行,并使用“扩充”进行具有更多数据的更好模型。例如,这是“原始”图表:

Legend

如您所见,损失几乎为 0 (0.0187),但准确性和验证之间的差距越来越大,验证也没有从大约第 8 纪元开始改善。这意味着我们过度适应。

解决这个问题的唯一方法是获取更多数据来训练模型。运行更多的纪元不能改进模型。

数据扩充

获取更多数据的一种方法是获取更多图像。然而,就像在我们模型的 Python Keras 版本中,我们可以增加图像来“创建”更多的数据来训练模型。

在 Python 中这非常容易,您只需指定想要创建什么样的数据扩充,一切都在幕后为您完成。

对于 C++ API 来说,这有点复杂,但也是可能的。

我们需要创建一个新的图表,将图像批次和扩大他们。

我实现了 4 种增加数据的方法:

1.从右向左翻转(上下没有意义)

2.顺时针和逆时针旋转到一定程度

3.将图像放大或缩小到某个比例

4.水平或垂直向上移动到某个系数

每一种方式都有一个随机因素,所以我们将在不同的时期创造不同的变化。您在 main 中指定的是机会或限制:

float flip_ratio = 0.5f;float rotation_max_angles = 40.f;float scale_shift_factor = 0.2f;TF_CHECK_OK(model.CreateAugmentGraph(batch_size, image_side, flip_ratio, rotation_max_angles, scale_shift_factor));

方法 CreateAugmentGraph 创建图形,该图形随后在每个批次上运行,以创建每个时期中图像的不同变化。

翻转图像

让我们先来看看我们是如何翻转图像的:

auto rand1 = RandomUniform(a_root, {batch_size}, DT_FLOAT);auto flips_vector = Floor(a_root, Add(a_root, rand1, flip_chances));auto flips_tensor = Cast(a_root, Reshape(a_root, flips_vector, {batch_size, 1, 1, 1}), DT_FLOAT);auto reverses = Reverse(a_root, input_images, {2}); // right to leftauto tensors_reversed = Mul(a_root, reverses, flips_tensor);auto tensors_normal = Mul(a_root, input_images, Sub(a_root, 1.f, flips_tensor));fliped_images = Add(a_root, tensors_reversed, tensors_normal);

首先,我们创建一个批量大小的随机向量。然后,我们加上翻转机会因素和地板。这给我们批中的每个图像一个 1 或 0(翻转或不翻转)。

现在,我们对矢量进行整形,使其与图像批次的形状相匹配,并且增加了 3 个维度。

翻转是通过在从右向左的维度 2 上调用反向操作来完成的。

现在我们有两个批次,一个翻转,一个正常。我们在每个图像上调用与随机向量及其 1 的补数相乘,以将我们不需要的图像置零,并将它们相加在一起,以获得增加的批次。

做投影变换

射影变换是将任意维的张量变换成新的张量,同时通过投影改变其“视觉”性质的数学方法。

这正是我们需要移动或缩放图像以及旋转它们。

幸运的是,作为 TensorFlow repository 附带的“Contrib”代码的一部分,已经有人实现了完成这种转换的操作。

代码位于/tensorflow/contrib/image 文件夹中。

不幸的是,贡献者没有完全实现 C++ API,而只是实现了 Python API。我们可以解决。

自定义操作

张量流是可扩展的。有关于如何添加新操作的指南,所以你可以在你的模型中使用它们。有些操作是由贡献者开发的,但没有成为核心张量流的一部分。它们在 Git 存储库中,但是不会作为基本包的一部分进行编译。

为了能够使用它们,我们需要单独编译它们(是的,使用 Bazel),将它们的二进制文件添加到项目中,并包含一个头文件。

控制代码生成和编译的是 Bazel 使用的构建文件。

当查看/tensor flow/contrib/image/BUILD 文件时,您可以看到一个 tf_gen_op_wrapper_py 部分,它负责在操作之上生成 python 包装器,但是没有 tf_gen_op_wrapper_cc 部分,它将为 C++类创建包装器。此外,cc_library 部分缺失,它将创建我们想要链接的库。

使用我的存储库中的构建文件覆盖原始构建文件,然后运行:

bazel build -c opt --verbose_failures //tensorflow/contrib/image:image_cc

构建完成后,您应该有了可以链接的库文件/tensor flow/bazel-bin/tensor flow/contrib/image/libimage _ cc . so。请注意,如果您将它复制到本地工作区(在 lib 子文件夹中的项目文件夹下),您可能需要使用 install_name_tool,以便能够消除 dyld 错误。

此构建还生成了文件/tensor flow/bazel-gen files/tensor flow/contrib/image/image _ ops . cc 和头文件。

这些是从 contrib 源文件生成的包装类。我们将需要包括标题,并添加到我们的项目抄送文件。

将这两个文件与同一文件夹中生成的内部 ops 文件一起复制到项目文件夹下的/include/tensor flow/contrib/image 子文件夹中。

现在我们准备使用自定义操作(ImageProjectiveTransform)

构建转换数据结构

与其他转换操作一样,ImageProjectiveTransform 接受一个名为 transforms 的参数。

这是一个具有 8 个浮点数的张量,称为 a0、a1、a2、b0、b1、b2、c0、c1,如果我们处理一批图像,还有另一个维度的批大小(每个图像有一组 8 个数字)。

为了创建这个张量,在我们的例子中是 20x8,我们需要创建一个 InputList(由一个向量组成)并沿着轴 1 连接它。我们不能使用 Stack,因为这将导致 8x20 的形状被转换操作拒绝。

要水平或垂直移动图像(出于某种原因也称为 translate),我们需要在 a2 和 b2 中放置像素数(正数和负数)。

要缩放图像(放大或缩小),我们需要在 a0 和 b1 中放一个因子(大于或小于 1)。

因为我们还需要加入一个随机因子,所以计算是这样进行的:

auto rand1 = RandomUniform(a_root, {batch_size, 1}, DT_FLOAT);auto rand2 = RandomUniform(a_root, {batch_size, 1}, DT_FLOAT);auto rand3 = RandomUniform(a_root, {batch_size, 1}, DT_FLOAT);auto rand4 = RandomUniform(a_root, {batch_size, 1}, DT_FLOAT);auto rand_shift1 = Sub(a_root, Mul(a_root, rand1, scale_shift_factor*2*image_side), scale_shift_factor*image_side);auto rand_shift2 = Sub(a_root, Mul(a_root, rand2, scale_shift_factor*2*image_side), scale_shift_factor*image_side);auto rand_scale1 = Add(a_root, Mul(a_root, rand3, scale_shift_factor*2), 1-scale_shift_factor);auto rand_scale2 = Add(a_root, Mul(a_root, rand4, scale_shift_factor*2), 1-scale_shift_factor);Input::Initializer zeros(0.f, {batch_size, 1});auto transforms = Concat(a_root, MakeTransforms(batch_size, rand_scale1, zeros, rand_shift1, zeros, rand_scale2, rand_shift2), Input::Initializer(1, {}));shifted_images = ImageProjectiveTransform(a_root, input_images, transforms, "BILINEAR");

首先,我们创建 4 个随机向量(以一批的长度)。因为这些是 0 到 1 之间的数字,我们需要做一些数学运算来得到我们需要的数字。请注意,我们传递到计算中的因子与 Keras API 匹配:当您传递 0.2 时,每个轴上的缩放在 0.8 到 1.2 之间,并且向右或向左以及向上或向下移动高达 20%。

我们将不使用的转换成员置零,并通过连接创建转换。MakeTransform 只是构建 InputList。

最后,我们用图像批处理调用 ImageProjectiveTransform。

旋转图像

旋转稍微复杂一点,但是它使用相同的转换结构和操作:

auto rand6 = RandomUniform(a_root, {batch_size}, DT_FLOAT);auto angles = Mul(a_root, Sub(a_root, rand6, 0.5f), max_angles*2);auto rand_angles = Div(a_root, Mul(a_root, angles, (float)M_PI), 180.f);auto sins = Sin(a_root, rand_angles);auto m_sins = Mul(a_root, sins, -1.f);auto coss = Cos(a_root, rand_angles);float img_side_1 = image_side - 1;auto x_offset = Div(a_root, Sub(a_root, img_side_1, Sub(a_root, Mul(a_root, coss, img_side_1), Mul(a_root, sins, img_side_1))), 2.f);auto y_offset = Div(a_root, Sub(a_root, img_side_1, Add(a_root, Mul(a_root, sins, img_side_1), Mul(a_root, coss, img_side_1))), 2.f);auto transforms = Concat(a_root, MakeTransforms(batch_size, coss, m_sins, x_offset, sins, coss, y_offset), Input::Initializer(1, {}));aug_tensor_output = ImageProjectiveTransform(a_root, fliped_images, transforms, "BILINEAR");

我们首先创建一个随机向量,转换成正负度数,然后转换成弧度。

接下来我们计算正弦,负正弦,余弦等。

我们再次创建一个转换并调用转换操作。我通过查看它的 python 版本(tf.contrib.image.rotate)实现了这个方法。

查看创建包含所有 4 个转换的图形的完整代码。有一些优化,以防你没有做其中的一两个。

对输入图像批次运行模型非常简单。

增强图像的验证

如果图像以这样一种方式被转换,以至于它们不再能被人眼识别为猫或狗,那会怎样?我们怎么检查呢?

我已经编写了一个实用方法 WriteBatchToImageFiles,它可以帮助您将增加的张量转储回您可以查看的图像文件。

在培训的主循环中(我们不会在验证或测试中增加图像),您可以看到以下代码:

if(augment_data){ //TF_CHECK_OK(model.WriteBatchToImageFiles(image_batches[b], "/Users/bennyfriedman/Code/TF2example/TF2example/data/cats_and_dogs_small", "source")); Tensor augmented; TF_CHECK_OK(model.RandomAugmentBatch(image_batches[b], augmented)); //TF_CHECK_OK(model.WriteBatchToImageFiles(augmented, "/Users/bennyfriedman/Code/TF2example/TF2example/data/cats_and_dogs_small", "augmented")); s = model.TrainCNN(augmented, label_batches[b], results, loss);}else s = model.TrainCNN(image_batches[b], label_batches[b], results, loss);

如果我们使用扩充的数据(我们应该这样做),我们首先扩充批处理,然后用扩充的张量调用 TrainCNN 方法。

取消对增强前后的 WriteBatchToImageFiles 调用的注释,以查看图像如何随机变化。

模型性能

让我们看看模型性能是否有所提高:

Legend

您可以清楚地看到,即使经过 100 个时期,损失仍在下降,准确性和验证数字之间的差距也不那么明显了。

它仍然不完美,我们在测试中远远超过 80%,但为了改善这一点,我们可能应该运行更多的时代,并获得新鲜的图像。

摘要

在这一系列文章(概述、第一部分、第二部分)中,我展示了如何使用 XCode 进行 TensorFlow C++开发,如何使用 C++ API 创建 CNN,可视化它,为它准备数据并以几种方式进行优化。我试图遵循 Arden Dertat 在他的第四篇文章中的步骤,实现他在 Keras Python 中实现的 AlexNet。

我希望这将作为其他人的教程,这些人在使用 C++作为主要语言的同时开始了他们在 TensorFlow 中的道路。

让我知道你的想法。欢迎建议!

创建语音识别计算器 Android 应用程序

原文:https://towardsdatascience.com/creating-a-voice-recognition-calculator-android-app-869a515bf6d1?source=collection_archive---------3-----------------------

Photo by Andres Urena on Unsplash

自动语音识别是当今机器学习中最著名的话题之一,每天都有许多新人投入他们的时间和专业知识。在这篇文章中,我们将构建一个简单的端到端语音激活计算器应用程序,它将语音作为输入,并将语音作为输出返回。输入包括整数和基本的数学运算符,而输出是用户说出的运算结果。

这个教程不是什么

  • 关于语音识别如何工作的理论教程。
  • 关于基于云的语音 API 的教程,如 Amazon Polly 或 Google Cloud Speech。
  • Java 语法和原理教程。
  • 关于 Java-XML 通信如何在 Android 上工作的教程。
  • 安卓材质设计教程。

先决条件

  • 基本的 Android 开发知识。
  • Android Studio(您可以使用 Eclipse 等其他 ide,但我将在本教程中介绍 Android Studio)。
  • 期望:基本的 API 知识(不需要认证)。

教程大纲

  • 创建 Android 项目
  • 创建语音转文本功能
  • 处理输入值(整数和运算符)
  • 计算结果
  • 创建文本到语音转换功能

创建 Android 项目

让我们首先打开 Android Studio 并开始一个新项目。如果你已经打开了一个项目,进入文件- >关闭项目,然后按照下图操作:

选择空活动然后点击下一步:

选择您想要的项目细节,或者保持所有设置为默认,然后单击完成:

给 Android Studio 几分钟时间来完成项目的构建和索引。如果您达到以下要求,您就万事俱备了:

创建用户界面

现在让我们创建 activity_main.xml 布局文件。我尽可能保持简约,因为这里的目标不是设计,而是功能:

其中 A、B、+ 只是可点击的占位符,而 C= 是不可点击的占位符。走!按钮触发计算并更新结果 C 。用户将点击它们中的每一个,并以语音形式输入它们自己的值。当然,设计和布局取决于作为开发者的你。这只是为了演示。

将布局链接到 Java 代码

现在让我们导航回 outMainActivity.java,并为我们拥有的每个可点击的文本视图设置一个 OnClickListener 。随后,我们的 MainActivity 类将如下所示:

创建语音识别功能

现在开始本教程有趣的部分。让我们从请求 RECORD_AUDIO 许可开始这一部分。这是通过在 AndroidManifest.xml 中的 <应用> 标签前添加以下行来实现的:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

Android 有一个内置的语音识别 API,其形式为 Intent 。我们处理这个意图就像处理任何其他 Android 意图一样。现在回到我们的。我们拥有的 onClick 方法将负责记录语音并将其转录成文本,以便我们可以将其作为数学运算来处理。因此,我们的意图代码需要驻留在我们所有的 onClick 方法中。

让我们首先为识别器创建一个 Intent 实例:

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);

让我们添加一些额外的数据(用于内务管理和语言选择),并以请求代码开始意向活动:

intent.putExtra(RecognizerIntent.*EXTRA_LANGUAGE_MODEL*, RecognizerIntent.*LANGUAGE_MODEL_FREE_FORM*);intent.putExtra(RecognizerIntent.*EXTRA_LANGUAGE*, Locale.*ENGLISH*);startActivityForResult(intent, 10);

以上两段代码需要复制粘贴到我们所有的三个 onClick 方法中,但是具有不同的请求代码。现在,MainActivity.java类中的那些方法应该是这样的:

到目前为止,我们的代码能够检测可点击文本视图上的点击,并在点击时开始识别语音。然而,它没有返回转录文本的方法。基本上,我们开始了一个意图,但没有收到预期的结果。因此,我们需要定义一个 onActivityResult 方法(在MainActivity.java)来处理那些转录结果:

我们的数据变量是一个意图实例,我们可以通过数组列表从中获取结果。这可以通过简单地调用:

data.getStringArrayListExtra(RecognizerIntent.*EXTRA_RESULTS*)

请记住,这个结果在我们拥有的所有 3 个识别器意图之间是共享的。现在我们需要一种方法来从这个列表中找到并获得实际的整数——在请求代码为 10 或 20 的情况下。为此,我们将创建一个循环遍历由 intent 返回的结果的方法(即 ArrayList )和另一个将说出的数字从字符串转换为 int 的方法:

这里有一个旁注,为了保持代码的整洁,在 switch 语句中不需要任何 break 语句。这是因为一旦其中一种情况评估为真,返回将负责停止开关的执行。

参考上面的代码,当请求代码为 10 或 20 时,我们可以从我们的 onActivityResult() 中调用 getNumberFromResult() 。当用户点击 firstNumberTextViewsecondNumberTextView 时,这将负责将说出的数字转录成相应的整数。

现在让我们为操作符转录创建类似的方法:

最后,让我们将调用 getOperatorFromResult()和 getNumberFromResult()的部分添加到我们的 onActivityResult()中:

其中 FIRST_NUMBERSECOND_NUMBER运算符是类中的全局变量,定义如下:

private int FIRST_NUMBER;
private int SECOND_NUMBER;
private char OPERATOR;

这些将是我们要计算的实际值。让我们定义一个执行这些计算的方法:

这个方法将从 GO 中调用!按钮的 onClick 方法。我们还没有处理过这个按钮。所以让我们添加以下代码:

goButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        RESULT = performCalculations();
        resultTextView.setText(String.*valueOf*(RESULT));
    }
});

其中结果是在类中定义的全局整数变量。

就是这样!现在,应用程序应该可以成功运行了。

创建语音合成功能

语音合成是将文本转换成语音的过程。我们将在应用程序中使用它,以便让 API 大声读出 performCalculations() 方法返回的结果。对于这个相当短的任务,我们将使用 Android 内置的 TextToSpeech 功能。

首先,该类需要实现 TextToSpeech 监听器。简单地说,转到 MainActivity 类签名,将它从:

public class MainActivity extends AppCompatActivity { ...

收件人:

public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener { ...

这表明需要在类中实现以下方法(从类签名中删除红色下划线):

@Override
public void onInit(int i) { }

我们将暂时保留没有实际实现的方法,因为应用程序的当前用例不需要实现。这是必需的,因为我们正在实现一个接口(遵循 OOP 原则)。

现在让我们声明一个对类 TextToSpeech 的全局引用:

TextToSpeech textToSpeech;

然后在我们的 onCreate() 方法中初始化它:

textToSpeech = new TextToSpeech(this, this);

我们现在已经准备好使用这个对象了。导航到 GO!按钮的 onClickListener 并在我们使用 setText() 的部分后添加下面一行:

textToSpeech.speak(
        String.*valueOf*(RESULT), TextToSpeech.*QUEUE_ADD*, null
);

就是这样!只要用户点击开始!按钮,结果将由 API 以语音的形式发出。

最后看一下代码

我已经把 Android 项目推给了 GitHub。可以通过这个链接查看:https://github.com/AnasAlmasri/VoiceRecognitionCalculator

然而,这里有一个 AndroidManifest.xml 文件:

下面是 activity_main.xml 文件:

最后一节,MainActivity.java课:

我们构建了一个 Android 应用程序,它将两个整数(0-9)和一个语音形式的运算符作为输入,识别这些输入,执行数学运算,然后将结果作为语音返回,同时在屏幕上显示出来。这只是初学者掌握语音识别应用程序如何工作的一次尝试。接下来将支持多位数、负数、浮点数,并一次性合并所有三种输入,以便用户可以说出“一加五”,应用程序可以分割感兴趣的单词,并进行必要的中间步骤以获得结果。

为 GameBoy 创建 AI 第 1 部分:编写控制器代码

原文:https://towardsdatascience.com/creating-ai-for-gameboy-part-1-coding-a-controller-5eb782f54ede?source=collection_archive---------17-----------------------

2003 年发布的《火徽,炽剑》是一款非常成功的战略游戏,其角色出现在《超级粉碎兄弟》中,该系列的第 15 部将于 2019 年初上映。游戏的玩法是选择角色(又名单位),决定将他们移动到哪里,然后从一组选项中决定攻击、使用物品等等。因为我在十几岁和十几岁时非常喜欢这个游戏,所以我想为这个 Gameboy Advance classic 制作一个 AI。这篇文章将是我在从头开始构建一个玩游戏的人工智能的过程中,将这一努力分成更多小块的第一篇。这里展示的代码可以在 github.com/aaronfrederick 找到,它的最新版本是为那些想要创建类似项目的人准备的。

在这个项目开始的时候,我把任务分成了 4 大块:

  1. 在 python 中创建控制器
  2. 从游戏中获取数据
  3. 自动化播放过程以连续生成数据
  4. 实现一种算法来优化游戏

为了玩火徽和创造一个 AI,我下载了 VisualBoy Advance 模拟器和一个火徽 ROM 到我的电脑上。该模拟器与 ROM 一起,允许人们在一台计算机上从不同的控制台玩游戏。另一个例子是海豚模拟器,它允许在电脑上玩 Wii 和 Gamecube 游戏。

Pyautogui will not work unless the box is checked!

现在我们已经有了模拟器设置,我们需要能够以编程方式访问它。在准备过程中,我打开了模拟器,并把它放在电脑屏幕的左上角,不受其他应用程序的干扰。有一个一致的位置是至关重要的,在这里我们将点击选择模拟器,但这个一致的位置更重要的是从屏幕上获取信息时,到了屏幕上的数据模拟器。pyautogui 库非常适合用 python 控制你的电脑,但是如果你像我一样在 Mac 上,你需要让终端访问你的电脑,如左图所示。

我们需要做的第一件事是选择模拟器,让它运行,这可以通过将鼠标移动到应用程序上并单击来完成。

import pyautoguipyautogui.moveTo(7,54,0.2)
pyautogui.click()

The code above with a 4 second time to reach destination for clarity

传递给 moveTo 函数的参数是 x 像素位置y 像素位置到达该位置所用的时间。因为左上角是(0,0),所以我们将鼠标移动到靠近左上角,但不是一直移动,这样我们就可以将光标放在应用程序上。

为了在我们选择模拟器后按下按钮,我们需要一个再次使用 pyautogui 的函数。下面的 press_key 函数为将来简化了这一点,这样我们只需键入 press_key(键,次数)就可以轻松控制游戏。

def press_key(key, n_times = 1):
    for _ in range(n_times):
        pyautogui.keyDown(key)
        pyautogui.keyUp(key)

现在我们可以按按钮了,我们需要把它应用到游戏中。我将在这个例子中展示的三个函数是 select_next_unit、move_unit 和 wait。这些函数将为这个人工智能做大部分的工作,所以把它们做好是很重要的。

如下所示,select_next_unit 只需按“q”键,然后按“'”键。这相当于在 Gameboy Advance 上按 L,然后按 A,这是将光标移动到下一个可用单位并按 A 的控件。这将弹出一个界面,允许我们选择将单位移动到哪里。

def select_next_unit():
    press_key('q')
    press_key("'")

在我的 github 上实现的 move_unit 函数比这里显示的稍微复杂一些——它允许随机移动——但是功能基本相同。这个功能背后的基本思想是,我们要输入一组坐标来移动,然后按下按键来实现这些坐标。这些不等式是针对随机移动世代的,因此,例如,如果左的值大于右,我们只按左。

def move_unit(left=0,right=0,up=0,down=0):
    ret_list = [left,right,up,down]
    if left>right:
        press_key('a', left-right)
    elif right>left:
        press_key('d', right-left)
    if up>down:
        press_key('w', up-down)
    elif down>up:
        press_key('s', down-up)
    press_key("'")
    time.sleep(0.2)
    return ret_list

使用 W,A,S,D 分别作为上,左,下,上,我们可以按下按键的次数,对应于我们传入的坐标。一旦我们移动我们的单位,我们会看到一个菜单,允许我们使用一个项目或等待。使用等待功能,我们将保持我们的单位(Lyn)在我们移动她的地方,然后结束我们的回合。

def wait():
    time.sleep(0.2)
    press_key('w')
    time.sleep(0.2)
    press_key("'")

The code to the right playing Fire Emblem!

把这三个功能放在一起,我们就可以在火徽第一关第一个回合了!左边的 GIF 显示了下面的代码在工作。

#Select the Emulator
pyautogui.moveTo(7,54,0.2)
pyautogui.click()
time.sleep(0.3)#Play the Game
select_next_unit()
move_unit(left=2, up=2)
wait()

在第 2 部分,我将讨论如何从这个游戏中获取信息,以便我们可以为机器学习创建数据集和损失函数。这将涉及一些图像处理技术,并创建一个图像分类器来智能地从屏幕上提取数据。

为 GameBoy 创建人工智能第 2 部分:从屏幕上收集数据

原文:https://towardsdatascience.com/creating-ai-for-gameboy-part-2-collecting-data-from-the-screen-ccd7381a1a33?source=collection_archive---------21-----------------------

欢迎来到为 GameBoy 创建人工智能的第 2 部分!如果您错过了第 1 部分:编写控制器代码,单击此处继续学习。在这一期,我将讲述如何通过各种图像处理和分类技术智能地从游戏中获取信息。这对任何游戏人工智能都很重要,但对它在火徽中的应用至关重要,因为游戏是完全通过决策来进行的。从游戏中获取信息如此重要的原因是,我们将训练一个机器学习算法来玩,由于 ML 算法需要数据集来学习,我们需要能够生成数据。考虑到这一点,我们需要知道我们需要哪些信息来建立我们的特征和目标。特征数据应该表示为游戏状态和采取的行动,而目标应该是我们玩游戏的好坏的衡量标准。和以前一样,当前状态的代码可以在我的 github 上找到。

这个任务需要几个库,所以我认为有必要简单回顾一下哪些库对哪些任务有用:

  • Python 图像库(PIL)-用于截屏/提供图像
  • cv2 —用于处理图像和转换颜色
  • pytesserac——用于从图像中获取文本
  • Keras 用于训练模型以从图像中获取数字
  • Scikitlearn —用于训练模型从图像中获取数字

图像处理任务的基本工作流程遵循以下顺序:

  1. 用 PIL 拍一个大截图(在我的旧笔记本电脑上,这个功能非常慢,大约 0.6 秒到 0.75 秒)
  2. 根据需要用下面列出的函数对图像进行子集化(如果 PIL 不那么慢,多张截图就好了
  3. 使用 cv2 填充功能,根据需要转换颜色和填充
  4. 将图像分类模型应用于经处理的图像以获得数据

下面的函数是我用 PIL 拍摄的图像的子集。虽然使用列表中的切片方法可能会更快,但与 PIL ImageGrab 函数拍摄初始图片所需的 0.6 秒以上的时间相比,这种差异可以忽略不计。

def subscreen(x0,y0,x1,y1, screen):
    sub_img = []
    for i in range(y0,y1,1):
        row=[]
        for j in range(x0,x1,1):
            row.append(screen[i][j])
        sub_img.append(np.array(row))
    sub_img = np.array(sub_img)
    return sub_img

We need to know the name of our character: Lyn

对于这两张图片,我们最感兴趣的是文本数据——我们将要使用的角色的名字以及我们可以使用的选项。为此,pytesseract 是一个无价的工具。Google 的 tesseract 是一个开源的光学字符识别(OCR)工具,在 python 中以 pytesseract 的名字发布。这个库的使用非常简单,我们可以从左上角的蓝色窗格中获得文本“Lyn ”,只需一行代码(上图)和第二张图(下图)中显示的选项:

#for black text
text = pytesseract.image_to_string(image)#for white text
text = pytesseract.image_to_string(inverted_grayscale(image))

pytesseract can tell us what options we have

处理函数inverted _ gray可能会因情况而异——在这种情况下,它会将图片变成灰色,并反转所有像素值,将白色像素变成黑色,反之亦然。Cv2 有很好的颜色变化功能,可以替代我使用的处理功能,这是我为这个特定情况编写的,但是真正神奇的是 pytesseract 使我们能够做到的。Pytesseract 允许我们放弃创建带标签的图像数据集、训练分类模型,或者重新发明轮子,这是一个巨大的时间节省,因为我们将看到…

The ‘Status’ screen shows the current game state

下面两张图片分别代表游戏状态和角色状态。充满了数字,从这些屏幕上可以获得很多信息。理想情况下,我们将只使用上面的 pytesseract 代码,但遗憾的是这些字母给软件包带来了一些麻烦。在为一个数据集标记了多个图片并在 Keras 中训练了一些卷积神经网络模型(CNN)之后,我决定返回到基本的 sci-kit 学习包,看看慢速训练的 CNN 是否真的有必要检测哪些图像对应于哪些数字。在没有任何超参数操作的情况下,第一次尝试逻辑回归模型时,我能够达到 99.5%的准确性——大概这 0.5%来自一个错误标记的图像。坦白说,我错标了 500 张图片中的 2 张……显示了这个模型有多好。用于数据提取的代码的实际用法如下,为清楚起见进行了编辑:

#using logistic regression model 'block_reader'
#padder function adds black to outline if image is too smallstats['str'] = block_reader \
                 .predict(padder(str_img).reshape(***to fit model***))[0]

更简单的模型如此成功的原因是由于小的图像大小,不同类别之间的明显差异,以及每个类别之间的一致性。更进一步地说,逻辑回归模型可以处理 30x24 的图像,而不是 400x600 的图像,因为每次观察的特征(像素)数量相对较少。类别的差异允许不同的像素在分类中具有不同的重要性。每个类中的一致性是导致开箱即用模型成功的另一个因素,因为模型的测试数据与之前在训练数据中看到的数据非常相似(如果不完全相似的话)(这就是为什么我们可以使用训练准确性作为评估指标)。

现在,有了谷歌和我们自己训练的模型,我们就可以从火徽中获取信息了。我们所需要做的就是拍摄图片,处理它,并应用我们的模型获得数据,并将其纳入游戏过程!

为 GameBoy 创造人工智能第 3 部分:自动化(糟糕的)游戏

原文:https://towardsdatascience.com/creating-ai-for-gameboy-part-3-automating-awful-gameplay-b60fe7504e4e?source=collection_archive---------23-----------------------

通过随机移动生成数据!

欢迎来到为 GameBoy 创造 AI 的第 3 部分!如果你错过了前两部分中的任何一部分,你可以在这里找到第一部分和第二部分。一如既往,我的 GitHub 是这个项目的最新版本。在这个项目的第三部分,我们将自动随机输入游戏,因此标题。这个游戏必须在玩的时候为我们生成数据,这样我们就可以在未来训练我们的机器学习模型。

我们训练算法所需的数据有三种:状态、动作和度量。状态数据指的是游戏的状态——我们的角色在哪里,谁在我们周围,我们角色的健康水平如何。同样,行动指的是我们在给定的状态下采取的行动。状态和行动是相互关联的数据点,这些数据点将产生一个结果,我们需要对这个结果进行衡量,以了解行动有多好。在这样的尝试中有一些算法可以使用(Q 学习,遗传算法),其中度量数据有不同的名称,如奖励、适合度或 Q(s,a)。我还不想把这个项目放在一个特定的算法上,所以我将把我们对成功的测量称为我们的度量。

为了完全自动化游戏,我们需要两个功能:一个是玩游戏,一个是在出错或运行结束时重启模拟器。游戏功能将更加复杂,因为它将实现我们在第 1 部分中构建的控制器,同时使用我们在第 2 部分中编写的图像处理生成数据。每次我们单位做出一个举动或决定,我们都会捕捉并存储数据。总的来说,每个回合的游戏功能的工作流程是:

  • 收集游戏状态——记录敌人和玩家单位的数量,回合计数(状态)
  • 游戏状态也给了我们想要最小化的值的信息,也就是剩余的敌人单位+回合数(度量)
  • 找到我们的角色—记录名字(动作)
  • 移动我们的角色——记录我们将她移动到的坐标(动作
  • 选择一个选项——记录我们是否攻击、使用物品或等待(动作)

下面我将展示 gen_data 函数的一个截断版本,以展示上面概述的思想的整体感觉和逻辑。在火徽的上下文中,为了清晰易读,我省略了一些按键和睡眠线。

相比之下,重启功能要简单得多。本质上,它按下重启模拟器所需的按键,并通过菜单导航,再次开始游戏。下面我将这两个函数结合起来生成数据,这些数据将在本系列的第 4 部分中使用,以便从这些数据中学习如何玩得更好。通过一个指定要完成的运行次数的 for 循环,我们可以通宵玩游戏来为这个挑战的学习方面生成数据。

#s, a, m are lists containing states, actions and metrics valuesreset_to_prologue()
states, actions, metrics = gen_data_prologue()
s.extend(states)
a.extend(actions)
m.extend(metrics)

对于任何参与类似项目的人来说,火之徽不同于许多其他游戏,因为控制随着每个命令而变化,与其他游戏相比,项目的这一部分变得复杂。在像马里奥,索尼克和许多其他游戏中,“右”总是把角色带到右边,“A”几乎总是跳,“开始”会调出菜单。在火焰徽章中,根据屏幕的不同,“向下”可以有多种含义。它可以将光标下移一格,将一个单位下移一格,将选择从一个选项移动到另一个选项,如果正在检查一个单位,甚至可以改变单位。由于这种复杂性,我编写了一些函数,在很多游戏都不需要这些函数的时候,很明智地解决了这个问题。如果你试图为一个不同的游戏编写一个人工智能,很可能你可以省略这些功能,使用屏幕图像作为状态,使用控制器输入作为动作。

为 GameBoy 创造人工智能第 4 部分:Q-学习和变化

原文:https://towardsdatascience.com/creating-ai-for-gameboy-part-4-q-learning-and-variations-2a0d35dd0b1c?source=collection_archive---------8-----------------------

When the boss dies, he asks us a fitting question

我们期待已久的部分

大家好,欢迎来到为 Gameboy 构建人工智能的第 4 部分!这是真正的奇迹发生的地方——我们已经建立了我们的工具,现在是时候启动它们了。快速回顾一下我们到目前为止的旅程:首先,我们构建了一个控制器,这样我们就可以使用 Python 脚本运行游戏;第二,我们使用了开源和自制的图像处理工具相结合的方式,从游戏中提取信息;第三,我们自动化了这个过程,这样游戏就可以在随机输入的情况下自动运行。现在,我们将实现一个 Q-learning 的变体来击败这个游戏的第一关。如果你想更深入地研究强化学习,我强烈推荐这两篇帖子(链接 1 、链接 2 ),它们在分解算法和实现方面做得非常好。

The final result — playing using the Q-Table’s most rewarded actions

什么是 Q-Learning,我们如何在这里应用它?

为了解决火徽的问题,我们将使用一个 Q 表。该表的行代表游戏的可能状态,列代表动作。在这种特殊的情况下,桌子有 150 种状态(关卡就像一个有 150 个方块的棋盘——10 行 15 列)和 180 种可能的行动。这个数量的动作来自我们的角色 Lyn,她能够走最大曼哈顿距离五个单位(这导致了 60 种不同的移动选项),并且当她到达时有三个选项(攻击、物品和等待)。填充每个状态、动作对的值是在给定状态下与采取该动作相关联的估计回报。这种回报通常被表示为函数 Q(s,a),这就是为什么这个过程被称为 Q-learning。你可能对“深度 Q-Learning”(DQN)这个词很熟悉,并想知道我们为什么不实现它——游戏运行太慢,无法为深度学习生成令人满意的数据量,我们无法在当前的模拟器设置中加快它的速度。下面是一个在任意问题上填写 Q 表的例子。

A small example of a Q-table getting filled in — Source

要填满这个 150x180 的桌子,我们必须多次玩这个游戏。我们从根据我们的状态采取随机行动开始,并随着我们的进步记录奖励。在这种情况下,奖励是我们在上一轮击败的敌人数量。如果我们在一个任意的状态 s,采取一个任意的行动 a,我们的奖励 Q(s,a)要么是 0(如果该回合所有敌人都幸存)要么是 1(每杀死一个敌人)。当我们随机玩游戏时,我们目前正在探索动作/状态空间,并跟踪回报,以便当我们以后想要利用这些知识时,我们可以对什么工作得好有所了解。我们必须首先探索,以便找到行之有效的路线,就像我们最终必须使用我们获得的信息来改进我们的游戏性一样。在实践中,这是由一个称为 exploration_rate(或 epsilon)的变量表示的,它随着我们的进展而衰减。每次我们尝试关卡时,我们会降低我们的探索速度(通过指数衰减)并将其与一个随机数进行比较,看看我们是否会探索或利用这一尝试。在学习过程的最后,我们将基本上在没有任何随机产生的决定的情况下玩游戏,仅仅依靠我们通过玩存储在 Q 表中的游戏而积累的知识。

在实施过程中,我们有 3 个主要部分:

  1. 初始化数据结构
  2. 初始化超参数
  3. 实现算法

设置代码

这里的第一个代码块设置了我们需要的数据结构,即 Q 表和字典,它们将状态和动作映射到所述表中的索引。

第二个代码块初始化我们将在这个实验中使用的超参数。当我们更新 Q 表时,学习率和 gamma 是影响我们奖励得分的乘数。

第三个代码块显示了实际的 Q 学习。我们通过重置游戏和将我们的状态设置到开始位置来开始每一轮,然后开始轮流。对于每个回合,我们使用一个随机数生成器来决定是探索还是剥削,并评估该数字是否高于我们当前的探索率。如果是这样,我们正在利用 Q 表中现有的知识。一旦我们做出了决定,我们要么随机(探索)产生一个行动,要么从 Q 表中选择最高回报的行动(利用)。然后,我们使用我编写的 take_turn*函数轮流执行那个动作,该函数返回信息:谁移动了,他们移动到哪里,他们采取了什么动作,以及奖励。布尔自变量表明我们是在探索还是在利用 Q 表。因为有一些空间是禁区,例如不可通行的地形,敌人的单位,我包括了一个检查,看看移动是否无效。然后,我们使用先前的状态和移动到的位置来设置新的状态,并用结果更新我们的 Q 表。在每次训练结束时,我们降低我们的探索率,以便我们可以更恰当地使用我们的信息。

*关于 take_turn 函数的注意事项:在 OpenAI 的 gym 中,他们有一个非常类似的方法——env . step(action)在游戏中进行一步后返回类似的信息。我想模仿他们的逻辑,使我的实现尽可能适用于其他问题。如果你想了解我的 take_turn 功能,你可以在我的 GitHub 上找到它。

情节变得复杂了——替代方法

如当前描述的,这种方法是非深度 Q 学习的典型方式。对于这个问题,是不行的。这个程序不仅玩游戏太慢,不能为 DQN 生成数据,甚至不能用最优值填充 Q 表。亲爱的读者,不要烦恼,因为到目前为止我还没有浪费你的时间;Q-learning 有不同的变体,我们将讨论如何解决这个问题。

改变奖励

到目前为止,奖励仅仅是为了杀死敌人。这并不能激励我们的英雄走向最终的静态 boss。她随机移动到老板旁边的方格攻击他,然后停留在那里第二回合结束他的概率微乎其微。这并不是说,通过足够多的训练和加速模拟,这是不可能做到的,但坦率地说,我有更好的事情要做,我的时间和电脑。为了解决这个问题,我在奖励中加入了一个基于欧几里德距离的东西,放在老板旁边的一个正方形里。不是每杀死一个敌人增加 1,我们现在增加 1/敌人+%从起点到终点的进度。

明智地初始化 Q 表

改变奖励帮助很大,但我们仍然努力完成平衡杀死我们的第一个敌人和利用我们已知的目标广场治愈我们自己所需的探索。我们没有找到通向老板的最佳路径,而是在第一条随机选择的路径上花费了更多的时间,因为我们知道那是“可行的”。在我看来,这是一个不需要成为问题的问题——在我们开始玩之前,我们已经知道基于距离的奖励条款将是什么。考虑到这一点,我循环了 Q 表中的每一个可能的状态,并奖励了每一个动作在这一关结束时我们离老板有多近。这样,我们就可以以最快的路线到达关卡的终点,并且只需要“学习”如何对付路上的敌人。这也允许我们增加探索率衰减,因为有更多的先验知识和更少的“学习”要做,我们需要执行更少的随机运动。

使用 Q-learning 和合理的奖励函数,我能够在最佳数量的回合中击败第一级火徽。第二层向我们介绍盟友,使我们的问题更加复杂:我们如何改变我们的方法来使用盟友?我将在下一期《为 GameBoy 创造 AI》中回答这个多智能体强化学习问题!

使用 IBM PowerAI Vision 快速创建人工智能驱动的计算机视觉应用程序。

原文:https://towardsdatascience.com/creating-ai-powered-computer-vision-applications-in-no-time-with-ibm-powerai-vision-33ebe49f4f2e?source=collection_archive---------12-----------------------

自从机器学习和人工智能术语浮现在我们周围人的脑海中以来,这已经是一个漫长的旅程,它激励我们许多人探索更新的维度,以应对自动化的需求,在一些可能的特定场景中,甚至可以挑战人类水平的准确性。在机器学习维度中,NLP、计算机视觉、语音识别等等,要解决计算机视觉问题非常非常复杂,如果你在更高的层次上思考它,你会意识到我们正在提供像素矩阵形式的图像,并试图分类、识别或分割对象。正如我们已经看到的,训练机器学习是一个迭代过程,这个过程是调整不同参数、超参数、重塑、添加或删除一个或多个层、连接或跳过连接一个或多个残差块等等的永无止境的迭代。

为了简化和统一为实现不同算法而在数据集上采取的大量操作,有一个简单的解决方案,IBM PowerAI Vision,它通过将复杂的代码任务包装在一个简单易学和易于使用的 web 界面中,使即使是机器学习新手也能够为测试和生产环境创建、训练、调整、维护和部署他们的模型。它在其核心中利用 IBM PowerAI 平台,并使用 IBM Power Systems 支持的加速计算平台,同时尊重 PowerAI GPU/CPU 通信和并行性。可以导入使用 Tensorflow、Keras 或许多其他框架训练的深度学习模型,以将其作为 PowerAI Vision 平台内的自定义模型。这些定制模型可以用作基础模型,它们的功能和性能指标可以通过在 PowerAI 愿景中进行调整来增强。通过使用自动标记功能,我们作为数据科学家可以有效地减少我们的工作量。随着部署模型的跨平台可用性,开发过程的开销变得更少。

聊够了,让我们把手弄脏:

要开始使用 PowerAI Vision,您需要做的只是通过 IBM PowerAI Vision 的官方网站请求试用,https://developer . IBM . com/linuxonpower/deep-learning-power ai/Vision/access-registration-form/并填写您的详细信息以及您的企业或机构电子邮件地址。您将在两个工作日内收到他们的回复,并提供您登录 PowerAI Vision 门户网站的凭据。只需按照电子邮件中提供的链接,输入提供的凭据,您就可以开始了。

PowerAI Vision Login Page

当我们完成登录后,我们将会看到应用程序本身。它分为四个不同的选项卡,数据集、模型、自定义模型和部署模型。“数据集”选项卡允许我们上传不同的图像和视频,作为输入要素提供。“模型”选项卡提供了在指定不同的超参数以帮助算法以更高的准确性更快地收敛之后,在选定的数据集上根据不同的预定义算法训练机器学习模型的选项。自定义模型类型允许您将之前在 PowerAI 视觉平台上训练的预训练视觉模型作为. zip 文件导入,并允许您使用该模型在更大程度上节省工作和时间。这个平台可以被视为迁移学习的真实例子。为了能够对对象进行分类或分割图像,我们需要创建一个非常深的神经网络模型,该模型具有大量的层和数百万个参数、超参数、训练、开发和测试矩阵,以便向前看。更重要的是,我们需要巨大的计算能力和如此多的时间来训练网络。但这就是迁移学习的用武之地,我们不是从零开始,我们从预先训练的模型开始,特别是在计算机视觉模型中训练。这就是像 IBM PowerAI vision 这样的平台发挥作用的地方,它不仅可以简化开销,还可以有效地为用户提供计算能力和数据洞察力。deployed models 选项卡允许您浏览您已经为生产环境部署的模型,可能通过不同的应用程序编程接口向您的客户展示对代表性状态转移范例的尊重。比如你可以从你开发的应用程序内部使用下面的 API 调用来识别或分类或分割结果。在为输入图像提供预测的同时,PowerAI Vision 还提供了嵌入在输入图像顶部的热图,以表示图像矩阵中的位置,这些位置对于算法正确分类或识别图像中的对象起着重要作用。在下面的 API 调用中,我将 true 传递给 containHeatMap 标准,以获取该热图作为响应。

https://{your_deployment_url_or_ip.com}/api/dlapis/{deployed_model_id}?imageUrl={url_of_the_image_object}?containHeatMap="true"?containRle="{true/false}"?containPolygon="{true/false}"?confthre={specify_floating_point_threshold_for_prediction}?cisnum={to_determine_possible_matches}

让我们从创建一个示例计算机视觉模型开始。让我们想象一下,我们将为无人机创建一个计算机视觉算法,以正确识别在洪水、地震或其他自然灾害中受损的房屋。嗯,我在这个主题上通过使用传统的深度神经网络(不使用 PowerAI Vision)实现了一个全尺寸模型,目前它在我的实验室中处于测试阶段。在本次演示中,我将向大家展示,使用 IBM PowerAI 视觉平台开始这样一项复杂的任务是多么容易,我最终在 PowerAI 视觉平台中获得了相当高的分类精度,无需做太多调整,在精度方面一点也不差,同时记住算法训练的迭代过程,调整不同的超参数,将不同的算法集成在一起等等。

所以,让我们来收集一些数据。因此,在这次演示中,我们将从互联网上下载一些被毁房屋的图像,在这次演示中,我只下载了 40 张可能包含受损房屋的航拍图像,还下载了一些其他完好房屋的航拍图像。这是我的数据集,总共只包含 52 张图片。嗯,这绝对不会是我们的任何生产阶段部署。我们将使用 PowerAI 视觉平台提供的工具来增强更多的图像。

Creating or importing Datasets to the PowerAI Vision portal.

选择创建新数据集或使用导入功能导入数据集。zip 文件开始使用。等待图像和视频文件完成上传,在上传过程完成后,您将看到一个类似如下的界面:

Dataset Page: After Creating /Importing a dataset augmentation Process in progress.

有了这么少量的文件,我们的算法不会收敛。所以,我们能做的,就是从我们上传的 52 张图片中增加更多的图片。为此,我们只需单击“增强数据”,它将提供诸如裁剪、旋转、噪声等各种选项来增强原始图像中的新图像,并以您提供的名称创建新数据集。增强过程可能需要很长时间,具体取决于输入图像或视频的大小。通过扩充,我们能够从仅仅 52 个输入图像中生成近 1300 个文件。

After Data Augmentation

Initiation of Training of the dataset

在增强过程完成之后,我们有 312 个图像被分类为完好房屋,其中 3082 个对象被标记为完好房屋,1040 个图像被分类为受损房屋,其中 1850 个对象被标记为受损房屋。直到这个数据集不意味着生产就绪的计算机视觉项目,只是为了演示的目的。因此,我们将进一步从我们生成的图像中训练出一种算法。因此,让我们单击“Train Model ”(训练模型),选择“object recognition model ”(对象识别模型),我们将选择要在更快的 RCNN 算法上训练的模型,以获得更高的准确性。我们单击高级选项来进一步微调超参数,例如迭代或时期的最大数量、梯度下降的动量、训练和测试/验证集的比率、学习率、正则化的权重衰减以减少过度拟合的机会。现在我们开始训练,PowerAI 视觉平台将在提供的 GPU 上开始训练。默认情况下,PowerAI Vision 上的每个试用帐户都可以访问 12 个 GPU,从而大大减少了训练模型的时间。随着培训的进行,您将会看到一个实时的损失与迭代图,在图中您会看到随着迭代的增加,损失会减少。培训结束后,您将会看到一个部署模型和导出模型的选项。只需单击 Deploy Model 或 Deploy and Export Model 即可为生产部署模型。正如您在下面看到的,我的模型在所选的超参数下表现出 100%的准确性。

Model Evaluation Metrics

模型完成训练后,您还可以查看不同的算法指标,以分析模型的实际表现,包括混淆矩阵、迭代与损失图等。导航到 Models 选项卡,单击您刚刚创建的模型,打开 advanced metrics 选项卡,您就可以开始了。

Confusion Matrix and Precision-Recall Curve of the trained model

现在,让我们测试我们的模型如何在两个不同的插图中识别受损的房屋和完好的房屋。要使用您自己的映像进行测试,请导航到 Deployed Models 选项卡,单击您刚刚部署的模型并单击以打开模型详细信息,然后在 Test model 部分下,放置您的映像或提供一个指向对象存储的超链接,或者使用 import 按钮导入映像。为了这个演示,我从网上下载了两张图片,一张是一栋毁坏的房子,另一张是一栋豪华平房。让我们看看算法对它们的表现。我们将 0.5 设置为算法进行预测的置信度阈值。

Algorithm performing object detection over the wrecked houses

Algorithm performing object detection over the intact houses

我们可以看到,这个模型表现得非常准确。由于我们使用了正则项,过拟合的可能性非常小。但由于数据较少,该模型不适合生产环境。现在,使用该模型作为基础模型,您可以训练不同数据集的模型,使用该模型自动标记新数据集中的对象,调整超参数,在一个地方创建集合模型。

自动标记数据集意味着使用您之前部署的模型自动标记数据集中的对象。随着此过程向图像中添加更多数据,模型的性能也会提高。

只需点击下面的链接,您就可以获得这个演示的部署基础模型。您将需要一个 IBM PowerAI Vision 帐户来访问该模型。

https://129 . 33 . 249 . 70/power ai-vision-ny/#/deployed models/2b 998d 64-7a 47-4d 21-92ff-2a 08a 093702 e

那么,你还在等什么?继续构建您自己的支持深度学习的模型,并立即运行!

结束!

宇宙中所有的力量都已经是我们的了。是我们把双手放在眼前,哭喊着天已经黑了”——斯瓦米·维威卡难达。

用神经网络中的正弦激活函数创造替代真理

原文:https://towardsdatascience.com/creating-alternative-truths-with-sine-activation-function-in-neural-networks-d45aac83ee52?source=collection_archive---------10-----------------------

利用正弦激活函数快速训练神经网络

你好!今天我要讲的是在神经网络中使用正弦函数作为激活。我会试着回答“这是什么?”,“它如何改变神经网络的未来?”、“这种方法的缺点是什么?”最后我还会演示一个例子。

什么是 sin 激活功能?

您可能已经从成千上万的出版物中听说过,神经网络使用单调函数,将神经网络的输出映射到 0 和 1 之间。这是正确的方法,因为这些激活函数给出类似概率的输出。但是,这种方法的缺点是输出只有一个真和一个错。但是在现实生活中,完全不同的值可能对一个事件给出相同的输出。因此,我们需要能够触及多个价值领域来获得真理,而不是试图接近一个小的价值领域来获得真理。

Josep M.Sopena、Enrique Romero、Rene Alquezar 撰写的论文“具有周期和单调激活函数的神经网络:分类问题的比较研究”也主张我们使用正弦激活的方法。下图展示了多种可能性。

Figure from paper

具有非单调激活功能的单元可以将空间划分为两个以上的区域。如果函数是周期的,那么区域的数目是无限的,可以解释为一个波前在变量空间中传播。

从图中我们可以看到,sigmoid 函数的输出只能是特定值的 1。但是,正弦函数的输出可以无限次为 1。这实际上意味着,如果神经网络应该为 x 和 x+100 个输入提供输出 1,我们可以通过使用 sin(x)和 sin(x+100)来使 model 的函数接近 y(x)=1 和 y(x+100)=1。如果我们不使用 sin 函数,我们的网络必须调整其权重和偏差,以便它们可以将 x 和 x+100 映射到 0 和 1 之间的范围。

它如何改变神经网络的未来?

证明了具有单调函数的神经网络给出了令人满意的结果。但是他们真正的问题是训练。它们被训练得如此之慢,是因为网络需要调整的参数数量达到了数百万。如果我们将使用 sin 函数作为激活,网络应该进行的调整次数将会更少。因此,网络的训练时间将显著减少。这可以降低神经网络模型的训练成本。

这种方法的缺点是什么?

不确定性和容易过拟合。由于具有正弦激活函数的网络在调整权值时简单而快速,这也造成了过拟合。不要过度拟合网络,我们需要给模型一个小的学习率,这样我们可以防止过度拟合。将网络的输出映射到无限概率空间实际上是增加了不确定性。对一个值的调整可能导致另一个值映射到一个非常不同的概率。

履行

正弦激活函数的正向和反向操作肯定有不同的实现。我只是尝试了我脑海中的那个。

def error_function_for_sin_single(output,y):
    to_search_best = np.sin(np.linspace(output-1,output+1,10000)*np.pi/2)
    index = np.argmin(np.abs(to_search_best-y))
    to_be = np.linspace(output-1,output+1,10000)[index]
    error = to_be-output
    #print("to be:",to_be,"as is",output,"error",error/10)
    return errordef error_function_for_sin_multiple(self,output,y):
    derror_doutput = []
    for cnt in range(y.shape[0]):
        derror_doutput.append(self.error_function_for_sin_single( output[cnt], y[cnt]))
    derror_doutput = np.array(derror_doutput)
    #print("____________")
    return derror_doutput/2

代码的解释:

  • 假设我们有一个输出数组(output)比如[o1,o2,o3,…]仍然没有被正弦函数激活。我们有“未来”数组(y)
  • 首先,我们通过 error _ function _ for _ sin _ multiple 函数中的 for 循环从数组中取出每个元素。
  • 然后,用我们从数组中取的元素调用 error_function_for_sin_single 函数。
  • 在 error_function_for_sin_single 函数中,我们计算输出值(to_search_max)周围的正弦函数。(在正弦函数中,我将输出乘以 pi/2,因为我希望值 1 为 pi/2,它稍后将映射为值 1,作为正弦函数的输出。)
  • 然后我们通过计算 y 和 to_search_best 之间的差来找到最小误差的指标。
  • 给出最小误差的索引实际上是输出应该是的值。因此,我们找到这个值和输出之间的差异,以便我们可以反馈到神经网络进行反向传播。
  • 找到错误后,我们将它们附加到一个列表中,以便将它们全部交给反向传播。

演示如何快速接近目标值

数据集:MNIST 数字数据库

算法:使用正弦基函数的前馈神经网络

层数:输入= 4704(我做基本特征提取,所以不是 784),L1 = 512,L2: 128,输出:10

学习率:0.0000001

我试图过度训练模型,将图像映射到其标签,以测量最少的纪元。

使用正弦激活功能:误差在 13 个周期内降至 0.044。

无正弦激活功能:误差在 19 个周期内降至 0.043。

另外,我上面提到的论文对正弦激活函数做了几个实验。其中一个是“螺旋问题”

来自论文的结果:

具有简单架构的标准 BP 还没有找到这个问题的解决方案(参见[Fahlman and Labiere,1990])。[Lang 和 Witbrock,1988]使用具有复杂架构的标准 BP(2–5–5–5–1,带快捷方式)在 20,000 个时代内解决了该问题。“Supersab”平均需要 3500 个历元,“Quickprop”需要 8000 个,“RPROP”需要 6000 个,而“Cascade Correlation”需要 1700 个。为了解决这个问题,我们构建了一个架构为 2–16–1 的网络,在隐藏层使用正弦作为激活函数,在输出层使用双曲正切。这种架构是迄今为止用来处理这个问题的最简单的架构。结果如表 1 所示。初始权重范围的重要性是显而易见的。对于小范围的非线性参数,学习是不可能的(见表 1 中的前两行

The results of experiment made on spiral problem.

我希望你喜欢阅读这篇文章。虽然每个人都在谈论寻找复杂问题解决方案的极其复杂的神经网络,但我认为我们仍然应该检查神经网络的基本算法。因为基本面的变化带来的影响更大。

用 Tableau 创建一个动画条形图比赛

原文:https://towardsdatascience.com/creating-an-animated-bar-chart-race-with-tableau-6a7839f703af?source=collection_archive---------11-----------------------

使用 Tableau 模拟动画条形图竞赛的分步指南

不久前,我在 Reddit 上的/r/dataisbeautiful 上发布了一个动画条形图,显示了澳大利亚按原籍国分列的国际学生人数的变化。这样的动画条形图非常适合以非常醒目(或者有时很烦人)的方式展示一段时间内不同类别对应的数值数据的演变。

半个月前我没有时间去记录它是如何完成的,但我最近决定,在忘记它们之前,最好在某个地方记录我遵循的步骤和我的思维过程,所以这里有一篇文章详细介绍了当时我脑海中的想法:

在我继续之前,我想说这篇文章很大程度上受到了我从 Ludovic Tavernier 的博客上读到的教程的启发。我对他发现这种用画面模拟条形图动画帧的方法表示最大的尊敬和钦佩,他所做的一切值得称赞!

事实上,我密切遵循他的步骤来创建我发布的条形图,但在浏览完教程后,我认为提炼和阐述某些部分可能会有用,以使教程更全面,更易于初学者理解,并概述所涉及方法的步骤背后的动机和逻辑。本文中的所有代码(除了一些调整)都取自 Ludovic 的,再次感谢他!

在分步指南中,我将向您展示如何使用 Tableau 创建自己的动画条形图,并以我的学生人数数据集为例。希望在本教程结束时,您能看到一些东西在移动!

入门指南

Tableau 不会自动从数据集创建动画条形图。解决这个问题的一个快速方法是让 Tableau 创建单独的帧,当你把它们串在一起时模拟一个动画。这和卡通的制作方式是一样的。

It’s never too late to get moving. Sometimes we fall, but sometimes we succeed too. (Photo: freepik.com / macrovector)

现在,要做到这一点,你最好让 Tableau 自动创建这些帧,这些帧又是从你提供给 Tableau 的数据中创建的。但是除非你真的喜欢手动创建数据集,否则你实际上是如何自动创建这些“伪数据”的呢?

这种方法就是围绕这样做的。

1.创建必要的数据条目

在这个步骤中,您需要创建 3 张数据(最好都在同一个 Excel 文件中)。目标是创建一个包含更多行的更大的数据集,使得每一行代表 1)每个动画帧和 2)动画条的每一点(更多信息见下文)。

不明白吗?这里有一个简单的例子:你从一个包含 20 个条目的表格开始,从 2001 年到 2020 年。现在,您想保留更多关于每年每个月的信息,所以您为“月”创建了一个额外的列。每一年包含 12 个月,您需要确保每一年,比如 2001 年,每个月重复 12 次。因此,您会得到 20 x 12 个条目。这就是我们所说的笛卡儿积。

回到我们应该做的事情,我们想在数据集中复制条目,但是我们想以更优雅的方式来做,而不仅仅是手动为每个条目创建行。因此,我们将通过在单独的表格中为我们想要引入的每个新列创建新的通用条目(或者在前面的例子中,为每个单独的月份创建新的通用条目)来实现这一点。然后,我们让 Tableau 在这些表上自动执行笛卡尔连接。

您的第一张工作表将包含您的原始数据,而另外两张工作表将包含新的通用条目。

表 1:关于数据集的信息

第一张工作表实际上是您想要制作动画的主数据集。应包含等基本信息。除此之外,您需要创建一个额外的列链接,稍后将用于连接其他数据表上的数据。

  • :您观察的时间单位的数值
  • 类别:任何你想观察的事物的名称,比如国家名称
  • :您感兴趣的数值,如 count
  • 链接:作为连接各种数据表的锚的标识符(在所有数据表中使用相同的值;为了简单起见,在这种情况下为 1)

Sheet 1: Information about your dataset

第 2 页:各酒吧信息

该工作表实际上为数据集中的每个类别创建了条形图的 4 个角(将出现在图表中)。点 1 代表矩形左上方的点,随后的每个点都是顺时针方向,以点 4 代表左下方结束。

  • 链接:作为连接各种数据表的锚点的标识符(在整个数据集中使用相同的值;为了简单起见,在这种情况下为 1)
  • :表示条的某个角的点(编号为 1-4)

The four corners of a bar labelled from 1 to 4

您的第二张工作表应如下所示:

Sheet 2: Information about each bar

表 3:每个动画帧的信息

此表创建动画帧,以动画显示数据集中指定的固定间隔之间的时间间隔。例如,如果您的数据集中的最小时间间隔是 1 年,该表将创建 k 个帧数,以动画显示从年【n+1】年的条形图。

  • link :一个标识符,作为连接各种数据表的锚(在整个数据集中使用相同的值;为简单起见,在这种情况下为 1)
  • anim :创建的每一帧的标识符(编号为 1 到 k ,您想要为每个间隔创建的帧数)

您的第三个工作表应该完全如下所示:

Sheet 3: Information about each animation frame

有了这三张工作表后,打开一个新的 Tableau 工作簿,并选择您在上一步中创建的 Excel 文件。对链接列上的所有工作表执行笛卡尔连接。

回头看看 Tableau 创建的新数据条目,您应该会看到,原始数据集中的每个数据条目都已经用条形中每个点的条目以及每个动画帧的条目进行了复制:

Each original entry in your dataset gets replicated for each animation frame and for each point on the bar. Each highlighted box shows the 4 entries needed to define a specific bar at a particular frame.

2.创建必要的变量来定义每个条形

现在,我们的数据集大大扩展,以容纳每个动画帧和每个动画条的更多数据条目,我们现在的目标是计算这些条目的一些值,这些值将定义每个特定帧的条的大小和位置。

切换到一个空的 Tableau 表,然后我们继续使用数据集的列中包含的数据创建几个计算字段:

anim_inter :一个,包含当前帧/每间隔总帧数的比值(例如 2/10 = 0.2)

[Anim]/{MAX([Anim])}

:一个数字,表示某一区间(如 2001.2 年)内的确切动画帧

[Year]+[anim_inter]

value_current :一个数字,表示间隔开始时的棒线实际值(如 2001 年至 2002 年间隔开始时为 190)

{FIXED [Year],[Category]:MIN([Value])}

value_next :一个数字表示间隔结束时棒线的实际值(如 2001 年和 2002 年之间的间隔结束时为 195)

LOOKUP(ATTR([value_current]),1)

value_inter :一个数字,表示在间隔内的一个精确动画帧上的条的内插值(例如在间隔 2001.3 时为 193.2)

ATTR([value_current])+
([value_next]-ATTR([value_current]))*ATTR([anim_inter])

rank_current :一个数字,根据间隔开始时的 value_current 显示该条相对于其他条的等级

RANK_UNIQUE(ATTR([value_current]),”desc”)

rank_next :一个数字,显示间隔结束时棒线的等级

LOOKUP([rank_current],1)

rank_inter :一个数字显示在间隔内的一个精确的动画帧上条形的‘中间’等级

[rank_current]+([rank_next]-[rank_current])*ATTR([anim_inter])

@x_inter :一个数字表示条的指定角的 x 值(即点 1 和点 4 的值应该总是 0,因为条的左侧不移动;而点 2 和 3 的那些应该总是指示条的当前长度)

IF ATTR([Point])=1 THEN 0
ELSEIF ATTR([Point])=2 THEN [value_inter]*1.0
ELSEIF ATTR([Point])=3 THEN [value_inter]*1.0
ELSEIF ATTR([Point])=4 THEN 0
END

@y_inter :一个数字表示条的指定角的 y 值(即点 1 和 2 的值应该总是相同的,并且表示条的上边缘的高度;而 3 和 4 的那些应该总是相同的,并且代表条的底部边缘。y 值之间的任何差异表示该条的高度)

IF ATTR([Point])=1 THEN [rank_inter]*1.0 
ELSEIF ATTR([Point])=2 THEN [rank_inter]*1.0
ELSEIF ATTR([Point])=3 THEN [rank_inter]+0.5
ELSEIF ATTR([Point])=4 THEN [rank_inter]+0.5
END

filter :一个数字,显示该条 value_inter 的等级;我们将使用它来过滤掉不在顶部 x 条数内的所有其他条

RANK_UNIQUE([value_inter],”desc”)

标签:一个字符串表示该条的类别value _ inter类别显示在条形的点 1 上方,而 value_inter 显示在点 3 上方

IF ATTR([Point])=1 THEN ATTR([Category])
ELSEIF ATTR([Point])=3 THEN STR(INT([value_inter]/1000))+”K”
END

3.观想时间!

本质细节都解决了,我们现在终于可以专注于这个过程中令人兴奋的部分:观想!

设置货架和卡片

让我们从在 Tableau 工作表上摆放所有搁板和卡片开始:

  1. @x_inter 拖到架上。修改表格计算
  2. @y_inter 拖至架,然后再次重复完全相同的步骤。将第二个 @y_inter 设置为双轴
  3. 右键单击视图窗格上的任意两个 y 轴,并选择同步轴。将轴的范围设置为从 0 到 11,并反转其刻度。
  4. 拖至架,并确保其为离散尺寸
  5. 过滤器拖到过滤器架上。
  6. 选择 @y_inter 标记卡片下的多边形标记,添加年份类别anim_inter细节,最后路径。确保这些都作为尺寸添加。
  7. 选择 @y_inter(2) 标记卡片下的圆圈标记,添加类别标签标签,以及年份、anim_inter明细。确保这些都作为尺寸添加。

在这一系列步骤的最后,您的 Tableau 工作表应该看起来像这样:

How your Tableau worksheet should look like at the end of this series of steps

指定一些表格计算

设置好所有字段后,就该配置一些表计算了,以确保我们之前创建的计算字段在视图窗格中正常工作:

  1. 右键点击架上的 @x_inter ,配置表格计算。使用计算 @x_inter 。这就使得 Tableau 对每一个 anim_inter类别 *按计算 @x_inter
  2. 右键点击架上的 @y_inter ,配置表格计算。设置为使用类别计算 rank_current ,使用类别年份计算 rank_next ,每选择一个 类别重新启动。对两个 @y_inter 轴重复此操作。
  3. 右键点击过滤器卡下的过滤器,设置表格计算。使用类别计算过滤器,使用计算值 _ 下一个。指定 0–10 作为值的范围。

*对于那些不真正理解表格计算的人来说,请点击这里查看安迪·克里贝尔的精彩解释。

瞧啊。经过这么多步骤后,你终于有了一些条形图的外观!点击播放(界面右上角)查看你的条形图移动!

The moment of truth: a bar chart appears!

在条形图上润色

然而,正如你肯定会注意到的,你的星盘可能仍然是丑陋的一面,仍然有一些事情要做,以润色一些美感:

  1. @y_inter(2) 标记卡片下,选择标签。点击“…”编辑文本。从字段中删除<类别>,并将< AGG(label) >向右对齐。接下来,将标签定位自动改为右上。最后选择复选框允许标签覆盖其他标记
  2. 点击尺寸并在滑块上选择最小尺寸。现在你不再有看起来傻傻的长方形了!
  3. 为了给你的条添加一些冷色调,将 value_inter 添加到 @y_inter 标记卡中作为颜色。使用计算 value_inter (就像前面的一系列步骤一样),最后选择你想要的颜色渐变。

How your screen should look like after some aesthetic tweaks

这些是我认为使你的图表看起来最起码是像样的一些步骤,尽管你也应该自己尝试其他的事情来使你的图表看起来更好——尝试重命名/隐藏你的轴、轴标题和图表标题!

您还可以创建一个 Tableau 仪表板,除了具有条形图的视图窗格之外,还具有多个视图窗格。一个这样的视图窗格可以显示随着图形的移动动画的年份。

如果你发现了有趣的个性化条形图的方法,请告诉我!

结束步骤

最后但同样重要的是,目前还不能使用 Tableau 直接将模拟的动画条形图导出为图像或视频。对于那些想以另一种格式保存动画图表的人,可以考虑使用电脑(或第三方应用程序)上的屏幕录制功能来录制 Tableau 上的动画帧。然后你可以使用互联网上的免费工具将你的视频文件转换成. gif 格式,如果你喜欢的话,就像我一样。这就是你要的,一个漂亮的动画图表!

现在一切都好

所以这应该是本教程!我想我可能已经记下了我的大部分想法和我为了得到一个好看的动画条形图比赛而遵循的步骤,所以如果我有一段时间不接触 Tableau,我可能很容易在未来重新创建一个。

如果你有任何问题或疑问,请告诉我,谢谢你的阅读!希望你在创建图表时玩得开心!

如果你想阅读我创作的动画条形图比赛(澳大利亚的比赛在最上面)的简短反思以及它在 Reddit 上引起的巨大讨论,请查看我的另一篇文章!

预测体育结果的自动化框架

原文:https://towardsdatascience.com/creating-an-automated-framework-for-predicting-sports-results-5fe01623d74b?source=collection_archive---------11-----------------------

我如何建立一个自动化的机器学习框架来预测橄榄球比赛的结果,并在没有任何监督的情况下发布输出

我最近决定开始一个兼职项目,将我对橄榄球的热爱与我对数据科学的热爱结合起来——于是梅尔橄榄球诞生了。Mel 是我用 R 编程语言创建的一个框架,它首先从网上的各种来源收集橄榄球比赛的数据,然后通过一组预先训练的机器学习模型运行这些数据,以产生最终比分的预测,最后将预测的输出和准确性发布到@mel_rugby twitter 帐户。

在这篇文章中,我将讨论一些我必须考虑的要点,我是如何开发这个框架的(作为一个非机器学习专家),最后,我学到了一些经验。

动机

我从 4 岁开始玩橄榄球,所以当我大约一个月前想到一个潜在的项目时,这是我首先想到的话题之一。鉴于橄榄球世界杯(RWC)将于几周后开幕,这似乎是一个完美的时机。所以我着手做了一些关于如何最好地预测体育比赛结果的研究——大部分集中在足球或 NFL 上。根据以前的经验,我知道接下来要做的最好的事情就是开始,看看我能走多远,所以我就这么做了!

工具

在这个项目中,我使用了 R,因为它是我最精通的语言。使用 Python 可以获得相同的结果(也许更有效),但就我个人而言,这会花费我更多的时间。我用的主要包有: rvestXML 2&RSelenium用于抓取数据; dplyrtidyrstringr&lubridate进行数据角力;脱字符号 & 神经网络用于训练模型;以及在推特上公布结果的 T21。在这一点上还值得注意的是,我着手使整个框架尽可能自动化。因此,整个项目本质上是一组嵌套的函数,它们依次相互调用。下面是当前流程的示意图:

Flowchart outlining the current process of the Mel Rugby framework

目前,所需要的是每隔几天运行一次“master()”——这可以被安排或在线托管以实现完全自动化。

获取数据

首先要克服的问题是获得一些我可以用来模拟橄榄球比赛的数据。我很早就决定,调查每一场橄榄球比赛将会大大增加所需的时间和精力,不仅因为它将包括用不同的结构收集数据,而且影响国际比赛和国内/俱乐部比赛的因素也不太可能相同,因此考虑两者可能需要不同的模型。随着世界杯的临近,国际比赛数据是最容易获得的,我决定只考虑国际比赛,如果可能的话,以后再把框架扩展到国内比赛。在网上搜索后,我找到了一个网站,里面包含了从 20 世纪早期开始的所有国际比赛的基本数据。

变量的选择

在考虑变量时,我可以使用两种通用方法——关注团队层面的变量或个人变量。在这里,我受到可用数据的限制:每场比赛的个人球员数据更难获得,也更不可靠(至少我使用的数据源是这样)。澄清一下,我这里指的是诸如身高、体重、近期表现等信息。在玩家层面。我能够获得每个球员之前为国家出场次数的信息,并将其整合到我的模型中。

一旦我决定专注于球队层面的变量,我就争论各种数据来源,以获得一支球队可能影响比赛结果的明显特征,包括:他们的总上限数(我最终分成前锋的总上限和后卫的总上限);他们最近的表现(过去 5 场比赛);他们目前的排名(为此我使用了我自己的——与 IRB 官方排名非常相似,但略有不同——以及他们是在主场、客场还是在中立场地比赛(大多数 RWC 奥运会都是如此),等等。

型号选择

过程的这一部分出乎意料的简单和快速。我目前正在改进现有的模型,并希望有“第二阶段”模型很快实施。我绝不是机器学习方面的专家,所以一旦我粗略地研究了以前是如何处理这个问题的,我就开始尝试不同的模型和模型组合,直到我找到一个相对更好的组合。对于那些感兴趣的人,我开始使用主成分神经网络(PCANNet)和线性支持向量机(LSVM),两者都将两个团队的特征作为输入,然后输出每个团队的预测分数。然后我取了两个分数预测的简单平均值,因为这被证明是最准确的。

在第一阶段的模型被训练并在即将到来的几场比赛中测试后不久,很明显模型失败的一个方面是在一个球队“逃脱”的比赛中。在这些比赛中,一支球队获得了动力,并最终轻松获胜(超过 20 分),这些比赛我称之为“大胜利”。我决定开发一些模型来解决这个问题,这导致了:

  • 一个用于预测比分的套索回归模型,假设其中一个队将以特别大的优势获胜
  • 一种随机森林分类器,试图确定一个团队是否可能在给定的游戏中以特殊的优势获胜。

这意味着对于每场比赛,每支球队都会产生一个预测得分和一个预测的“大胜”得分。如果随机森林暗示比赛中的一个队会彻底消灭他们的对手,我用“大胜”分数作为预测。这产生了积极的影响——例如,在撰写本文时,新西兰最近以 63 比 0 击败了加拿大。最初的模型预测新西兰以 43–5 获胜,但是“大胜”随机森林模型将比赛分类为可能以大胜结束,因此选择了“大胜”得分预测,预测结果为 66–0,这大大提高了模型的性能。

交流输出

从这个项目一开始,我就想确保这个框架所做的预测有一个公开的记录,为了透明,也为了增加对这个项目的参与。我决定使用 Twitter 有几个原因,最重要的是因为 rtweet 软件包让自动化一个 Twitter 账户变得非常容易。因此,我建立了@mel_rugby twitter 账户,并编写了一些功能来获取预测并发布它们,包括根据预测的情况添加表情符号,以便让 mel 看起来更有感觉和更有吸引力。

经验教训

我现在每三天手动打开一次项目并运行主功能。我仍然这样做,以防意外出现错误(这种情况已经好几次没有发生了,所以祈祷继续发生吧!),但实际上我可以设置我的笔记本电脑在预定的时间运行该框架,甚至付费让它在线托管,这样我就可以忘记它,它就可以运行了。我在这个项目中学到的一个关键教训是我从数据科学专家那里一次又一次听到的,但只是刚刚开始意识到:数据来源和清理比实际训练机器学习模型花费更多的时间和精力。

当前性能和未来添加

梅尔目前在预测方面是一个非常混杂的包,许多已经被 bang on 和其他人没有那么多。我对第二阶段模型投入生产感到兴奋,因为我相信这将大大改善预测。有关梅尔如何预测结果/分数的更多信息,请查看梅尔橄榄球推特账户!

就该项目的未来补充而言,我已经开始开发一个 web 应用程序,它将允许人们与 Mel 进行交互,并查看比分预测如何变化,例如:比赛日阵容中挑选的确切球员;从现在到正在讨论的游戏之间将要进行的游戏的结果;当天的天气;和其他变量。如上所述,我还在研究模型的第二阶段,我希望 a)提高用作输入的数据的质量和数量,b)提高对“冷门”的预测,即低排名球队击败高排名球队,以及 c)研究球员水平的表现模型,以及如何使用这种模型来增强得分预测。我还计划增加 Twitter 机器人 Mel 的复杂性,以便它可以与查询进行交互和响应。这可能最终会被托管在某个地方,所以我可以让它无限期地运行下去!

结论

感谢阅读,我希望你觉得这很有趣!如果你想让我再写一篇文章详细阐述以上任何一点,请在下面留下评论。我正在考虑一个更详细的帖子,要么是关于建立一个 Twitter 机器人,要么是关于数据转换过程的更多细节。如果你觉得这有用或有趣,请鼓掌,并与其他可能喜欢它的人分享!

页(page 的缩写)如果你想知道这个项目的名字,我最初把它叫做 rugbyML(机器学习),但是为了让它更有个性,我想给它取一个人类的名字,所以叫“ML”->“Mel ”!

为数据科学创建一个简单的网站抓取器

原文:https://towardsdatascience.com/creating-an-easy-website-scraper-for-data-science-sports-prediction-pt-1-f024abd53861?source=collection_archive---------23-----------------------

收集数据是任何机器学习项目的重要部分,但许多教程倾向于使用已经以方便的格式存在的数据。这对于案例来说是很好的,但是对于学习整个过程来说不是很好。在现实世界中,并不是所有的数据都可以在谷歌上找到…至少现在还不行。这是教程的一部分,我们收集所有必要的统计数据来训练我们的神经网络进行 NHL 预测,但更重要的是,我将向您展示如何应用这些概念并从万维网上收集您想要的任何数据。

突出

  • 构建刮擦环境
  • 使用 selenium 删除 HTML
  • 美颜组处理
  • 写入 CSV 文件

先决条件

  • 必须能够理解 Python

1-概述

对于这个例子,我们将采用整个赛季的 NHL 每日游戏统计数据。输出将由两行数据组成,每行是一个队对比赛的看法。这些数据将以 CSV (逗号分隔值)格式保存到一个文本文件中,这本质上只是一个 excel 工作表,但它没有用线来分隔单元格,而是用逗号和换行符。作为参考,我们将从 NHL.com 每日统计页面的开始,以包含 2.1k 行的输出文件结束:

A single day worth of data, in CSV format

这项工作所需的工具

from bs4 import BeautifulSoup as soup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from numpy import array
import pandas as pdimport csv
from datetime import date

Selenium 本质上是一个库,它可以打开一个 web 浏览器实例并自动与之交互,而 BeautifuSoup 是从页面中提取 HTML 以供我们使用的。 NumpyPandas 都用于数据处理和格式化,如果你只是想制作一个 web scraper,这是不需要的,但是因为我们稍后将在 Tensorflow 中使用这些数据,所以立即使用 Numpy 数组是最容易的,特别是考虑到我对这些数据的计划(更不用说它比常规 Python 逻辑更有效)。

2-网页到 HTML

进入实际的抓取,我们首先需要一个可以访问网页的功能,并把它变成更加用户友好的东西。实现这一点的计划是简单地创建一个简短的方法,该方法将在 selenium 中打开页面,获取 HTML(每个网页都有的基于文本的框架),将其转换成可以使用的,然后将其返回给用户。

这个简短的方法完成了实际“刮擦”的所有步骤。如果你给它一个 URL,页面的 HTML 将会以一种功能性的格式返回,你可以从中找到你所需要的内容。让我们深入了解它的工作原理。

def url_to_soup(url):
    # selenium driver setup
    driver = webdriver.Firefox() # get url
    driver.get(url) # create sauce (raw HTML) using driver
    source = driver.page_source
    driver.close() 

第一步是定义一个 web 驱动程序,它本质上就是 selenium 将要使用的浏览器。我喜欢 Selenium 的一点是,它可以实时自动打开网页,这样你就可以看到程序的每个动作。我决定用火狐。你可以使用任何浏览器,selenium 将完成访问该浏览器的所有工作,这非常简单,只需定义你想使用的浏览器。现在你所要做的就是给驱动一个 URL,它会自动打开页面,但是不要忘记一旦你完成了从页面中拉出,就关闭驱动

变量包含从页面中提取的原始 HTML。我用“原始”这个词是因为它就是这样,原始而杂乱。我们必须首先把这种文本风暴变成我们可以轻松享用的汤。因此,我们简单地通过接受两个输入的“soup”函数来运行它;源页面和解析器

解析器函数不是您可能知道的解析器。您可以查看 B.S .文档来找到不同种类的解析器,但是它们都做相同的事情,即清理 HTML 以便我们可以用自己的代码解析它。有些可能行得通,有些则不行,但在这种情况下,‘lxml’恰好做到了。不过有一个技巧。在指定解析器之前,必须打开命令行并下载解析器。既然我选择了 lxml,我必须首先做:

$ pip install lxml

在这之后,您就可以运行接下来的两行代码了…

# soup(input, parser)
url_soup = soup(sauce, 'lxml')# return the parsed soup
return url_soup

3-收集有效数据

在我们能消化汤之前,我们需要先收集它。到目前为止,我们所做的只是定义了一个从单个网页中删除数据的方法,但是我们需要整个赛季的每日游戏数据,所以我们将多次调用这个方法。因此,首先我们需要找出一种方法来快速收集所有这些信息,并将其保存在一起进行处理。

理解这个 web scraper 的一个重要概念是 URL 的操作。NHL 网站碰巧对表中的每个统计数据实例都使用相同的 URL 结构。下面是一个 NHL.com 每日统计页面的链接。如你所见,这个 URL 中嵌入了一个日期,在两个不同的地方。如果您将这些更改为不同的日期,您会发现该链接仍然有效,您将被重定向到包含该特定日期统计数据的页面。

[http://www.nhl.com/stats/team?reportType=game&dateFrom=2018-10-08&dateTo=2018-10-08&gameType=2&filter=gamesPlayed,gte,1&sort=points,wins](http://www.nhl.com/stats/team?reportType=game&dateFrom=2018-10-08&dateTo=2018-10-08&gameType=2&filter=gamesPlayed,gte,1&sort=points,wins)

我们可以利用这一点,只需自动修改嵌入 URL 的日期。为了让我们将这个概念付诸实施,我们需要一个函数,它将为任何特定日期生成到 NHL.com 页面的链接,这正是下面五行代码所做的。

def nhl_daily_data(year, month, day):
    nhl_daily = f"[http://www.nhl.com/stats/team?reportType=game&dateFrom={year}-{month}-{day}&dateTo={year}-{month}-{day}&gameType=2&filter=gamesPlayed,gte,1&sort=points,wins](http://www.nhl.com/stats/team?reportType=game&dateFrom={year}-{month}-{day}&dateTo={year}-{month}-{day}&gameType=2&filter=gamesPlayed,gte,1&sort=points,wins)"
    nhl_soup = url_to_soup(nhl_daily)

该函数通过使用 f 字符串来实现这一点。您可能不熟悉这个工具,但它是 Python 3.6 的默认版本。实际上,无论您在函数的参数中输入什么日期,f 字符串都会填充 NHL.com URL 中的年、月和日位置。然后,它利用前面的 url_to_soup() 函数来返回该页面的 soup。所以不用分别调用这两个函数,这个函数会替你做。

例如,如果您想要查找 2018 年 10 月 8 日玩的游戏的统计数据,您可以使用这些参数调用函数: nhl_daily_data(2018,10,08) ,然后它会从这个特定的 NHL.com 网页中提取调味汁,通过解析器运行它,并以汤的形式返回它。

您可能会问自己,为什么在您的项目中需要这个函数?事实是,也许你不知道。找到网络数据的第一步是想出一个攻击计划。也许你想要的所有信息都存储在同一个页面上,在这种情况下,你可以跳过这一步,只需一次扫描就可以得到你需要的所有数据。如果你不能使用这个 URL 技巧,selenium 提供了“手动”点击的功能,你可以使用它来浏览网站,你可以在 Selenium 的文档中找到这些功能。

接下来,我将亲自讲解如何阅读 HTML,这样你就可以告诉你的程序要寻找什么。

3.1-阅读 HTML

为了完成下一部分,你需要知道如何阅读 HTML。第一步是导航到你需要数据的页面,我去了一个随机的每日 NHL 统计页面。看看你的数据在页面上的位置。你可以看到游戏的统计数据都被嵌入到某种表格中,所以很可能这个表格是它自己的类。您的数据可能不像我的数据一样在一个独特的 JavaScript 元素中,但是过程仍然是一样的。

接下来,右键单击要使用的文本信息,然后按“检查元素”。这将在您的 web 浏览器中打开检查窗格,您可以在其中找到该页面的所有类和子类。浏览这些,找到你想要的对象、图表或信息所在的类的“路线”。你需要这个来告诉你的铲运机去哪里找。

When selecting the “rt-table” class, the table on the web page is highlighted.

find() 函数是在代码中寻找你所需要的东西。我们不需要让程序遍历 HTML 中的每个文件夹来找到表格,你只需要指定要查找哪个类,然后 BeautifulSoup 就会找到它。

# finding table data
table_body = nhl_soup.find(attrs="rt-table").find(attrs='rt-tbody')

这个一行程序在 python 中定位保存表数据的类,并将其转换为对象“table _ body,然后我们可以解析该对象来记录我们需要的数据。

该表实际上是二维数组的格式;每个游戏有两个数组。每个数组都是一个队对那场比赛的看法的统计数据。

3.2-收集信息

下面的大块代码可能看起来很难,但实际上我们已经到了最后阶段。

# loading the game data
game_data = []# finding the chart and looping through rows
for rows in table_body.find_all(attrs="rt-tr-group"):
    row_data = []

通过阅读 HTML,我们可以简单地使用 find() 函数,并在它前面放置一个 for 循环,它将自动提取类中的所有内容,一次一行。但是我们不能就此止步,因为 table 元素中包含的不仅仅是我们想要的数据,还有一些我们不想要的数据,比如标题和分部。如果我们查看表的数据部分的特定 HTML,可以看到它有一个不同的标签: td (表数据)。这意味着我们需要做一个嵌套的 for 循环,以便将搜索范围缩小到这个表数据。

 # looping through row data
    for td in rows.find_all():
         row_data.append(td.text)
         game_date = f"{year}-{month}-{day}" enemy_team = row_data[4][14:].lstrip()
         win = row_data[8]
         loss = row_data[9]
         over_time = row_data[11]
         points = row_data[12]
         goals_for = row_data[13]
         goals_against = row_data[14]
         shots_for = row_data[17]
         shots_against = row_data[18]
         power_play_goals_for = row_data[19]
         power_play_opportunities = row_data[20]
         power_play_percent = row_data[21]
         power_play_goals_against = row_data[23]
         penalty_kill_percent = row_data[24]
         faceoff_wins = row_data[25]
         faceoff_losses = row_data[26]
         faceoff_win_pct = row_data[27]row_data = [game_date, team_name, enemy_team, home_away, win,   loss, over_time, points, goals_for, goals_against, shots_for, shots_against, power_play_goals_for, power_play_opportunities, power_play_percent, power_play_goals_against, penalty_kill_percent, faceoff_wins, faceoff_losses, faceoff_win_pct]
    game_data.append(row_data)
    return game_data

这为我们找到了行数据的列表,一次一行。然后,我们可以选择我们想要的信息,对其进行分类并保存。

4-唯一剩下要做的事…省省吧

为了把它包装成一个我们可以使用的漂亮的蝴蝶结,我定义了一个批处理收集方法。这个方法调用 nhl_daily_data() 方法,在一个日期范围内一次调用一天。这将为我们收集的所有内容创建一个图表,然后将其作为 CSV 文件写入您的计算机。

def batch_collection(start_date, end_date):
    season_dates = pd.date_range(start=start_date, end=end_date)
    for date in season_dates:
        print(date)
        year = date.year
        month = date.month
        day = date.day
        chart = array(nhl_daily_data(year, month, day)) # .txt to CSV
        with open('2017-2018season.txt', "a") as output:
            writer = csv.writer(output, lineterminator='\n')
            writer.writerows(chart)

从这里开始,这些数据将需要更多的处理,但我们需要的一切现在都以一种易于阅读的格式集中到一个文件中。

创建一个可解释的机器学习算法

原文:https://towardsdatascience.com/creating-an-explainable-machine-learning-algorithm-19ea9af8231c?source=collection_archive---------12-----------------------

用选股结果构建一个可解释的机器学习算法是什么、如何做以及为什么

何必呢?

几年前,我开始学习 Python 和 R,目标是学习如何应用它们的优化、统计、数据科学、机器学习和数据可视化包和库。

我还购买了股票市场数据(赛马数据不可用),抱着测试各种模型的想法,我有几个目标:

  1. 了解模型的工作原理
  2. 学习 Python 和 R
  3. 找出那些可能是好的投资对象的股票

我有运筹学(任何阅读本文的数据科学家都可以使用的规范分析)背景,并在各种行业中用 PL1、Fortran 和 Fortran 统计和优化库、C 和 SAS 进行了大量建模,以解决各种业务问题。所以目标(1)和(2)并不难实现。

对于我尝试过的所有算法来说,确定要投资的股票是非常具有挑战性的。这就是原因 1。

开发自定义 ML 算法的原因包括:

理由 1: 用现有软件为建模难题提供解决方案。

理由 2: 如果我要投资我的钱,参与这个游戏,我想知道为什么这个模型选择某一只股票作为投资候选,而不是另一只。什么样的特征组合在推动决策?

原因 3: 如果算法有效,我想将它应用于另一个问题,能够向最终用户解释它可以加快其接受程度并降低成本。模型开发成本不仅包括处理数据和估计模型权重、优化功能或模拟策略所花费的时间。它们还包括测试、监控和最终用户变更。变更&假设问题可以将宁滨数据包含到当前使用的区间、首选区间或更直观的区间,甚至可以从模型中添加或删除特征或决策变量。

理由 4: 通过创建自己的机器学习算法,组件和功能很容易修改,因为代码是自己写的。

原因 5: 在再次读到“机器学习模型在 X 行业没有用,因为它们缺乏透明度”后,我决定看看是否可以创建一个“透明的机器学习模型”。我喜欢尝试解决问题的挑战。

原因六:我喜欢编码。

建什么?

当我想到这一点时,我决定瞄准最容易理解的有用模型— 记分卡

记分卡

对于那些不熟悉记分卡的人来说,记分卡用于决定是否给申请人贷款。他们对违约风险进行排序——较高的分数比较低的分数风险更小,并且可以根据赔率或概率进行调整。

记分卡构建流程可能包括:

(1)宁滨连续变量(特征)变成一组 0/1 输入。

(2)使用一些度量来评估预测能力——通常是信息值,有时是比率。

(3)选择将用于估计模型的特征。这可以是自动化的,也可以由建模者来完成。

(4)使用线性回归、逻辑回归或数学规划来估计模型权重。

(5)通过将权重放大到整数,将分数缩放或校准到好/坏的赔率或概率。

(6)通过对每次观察的权重(现在是整数点)求和来对数据进行评分。在信用评分中,特征通常被称为特性,特征的 bin 是属性。每个特征只属于一个属性箱,因此评分要么是表查找和求和,要么是矩阵乘法。

一旦模型被估计,它就被呈现给终端用户,终端用户通常希望其他特征被用作预测器或以更直观、更合意或符合商业目标(例如针对特定人群)的不同方式将特征归入模型中。这是一个迭代的过程,如果很容易理解模型是如何工作的,这个过程可能会变得更容易。

何苦呢?

为了提供一个详细的答案,我们去了赛马场,问了这样一个问题:一些赛马赌徒比银行家聪明吗?

赌马的人可能会考虑这些因素:

  • 赛马获胜次数
  • 马匹速度等级
  • 骑师历史表演
  • 比赛类型
  • 赛跑距离
  • 参加比赛的马的数量
  • 支付赔率
  • 等等。

可能的模型特征,如那些可能用于银行信贷风险模型或选股模型的特征。

银行通常不会直接优化回报。回报赔率不进入记分卡,而是在第二步进行估计,通常是对违约损失进行线性回归。尽管事实上有些违约的客户是有利可图的——他们在还清大部分贷款后才违约,而有些没有违约的账户是无利可图的——他们在所有初始化和处理成本被覆盖之前就还清了贷款。

老练的赛马投注者使用凯利标准来确定他们可用资金的最佳部分来投注一场比赛。

要下注的凯利分数= p 减(1-p) *亏损/盈利

其中 p 是获胜的概率,亏损/盈利是收益几率的倒数。

因此,与银行家不同,老练的赛马投注者在下注时有亏损和盈利,并在每次下注时将亏损和盈利比率融入他们的决策中。

何苦呢?

如果我们只是估计记分卡的权重,以获得概率估计值或对观察值进行分类,我们可以很容易地使用一个可解释的模型(逻辑回归或线性规划等)来完成。)或者更难解释的模型(神经网络、随机森林等)。).

所有这些模型都有一个共同点:

它们对整个人口进行预测。他们的目标函数不是针对最终目标的。

在选择候选股票进行投资的情况下,我们所追求的是每周考虑投资的 N 只股票的列表,并根据它们与凯利标准相关的预期回报进行调查。

我们根本不关心大多数的家畜。那么,为什么要在模型的损失函数中考虑它们呢?

我们可以构建一个模型,让它根据案例的利润和损失,而不仅仅是成功的概率,计算出最大化或最小化案例数量的分数。

这在看股票时尤其重要,因为回报率最高的股票可能看起来很像投资导致灾难的股票。

我们希望有一个算法,传递高回报的股票,其预测特征的配置文件也包括高风险的股票,我们希望有一个分数,而不是 2 个模型。

如何?

我一直找不到一种数字绘画(链接处伟大的音乐插曲)类型的算法来解决这个问题,我们希望生成一个分数,只识别观察的一个子集,并希望用更高的分数来优化选择。

设置步骤:

第一步:定义目标函数。在选股的情况下,上面已经做过了。具体来说,我们希望每周产生 10 只具有最高预期回报的股票。

第二步:计算模型开发样本中每只股票的表现。

步骤 3: 从模型开发样本中选择所有可能的预测特征。

第四步:将数据分割成模型、验证、测试和预测(超时)段。创建一个索引数组或列表,将每个观察值映射到它的段。

步骤 5: 使用模型数据,对每个特征进行分类,将任何缺失值放入它们自己的分类中。对于该特征,使用步骤 2 中的性能定义计算其交互信息值。如果需要,可以使用其他测量方法。箱应该有一些最小数量的观察值或最小百分比的观察值。宁滨过程通常不像人们假设的那样重要,因为优化在非常粗糙/宽的宁滨间隔下仍然工作良好。

第 6 步:根据第 5 步的结果,选择将进入模型的一组特征,去掉那些具有低信息值或其他预测能力度量的特征。

步骤 7: 在选择了特征之后,为步骤 5 中的每个箱建立具有 1 列的 X 矩阵。如果观察值不在箱中,则该列包含 0,如果在箱中,则该列包含 1。这将极大地增加 X 矩阵的大小,这也是不为一个特征创建大量条柱的另一个原因。所有线段都应在 X 矩阵中,每次观察一行。

学问

最后,我们到了学习的部分。这是你可以真正获得创意和测试想法的地方。

我采用的方法是实现一种改进的进化算法。有几个选择和定制的任何适应你想测试。

这里的基本思想是重复这些步骤:

(1)生成一个可能的解决方案(在这种情况下是一组整数记分卡权重)。

(2)使用 X 矩阵和权重对数据进行评分

(3)评估解决方案(在这种情况下,根据每周挑选的得分最高的股票数量计算预期回报)

(4)确定是否和/或如何记住好的解决方案并忘记较差的解决方案

(5)基于记忆中的好解集进行探索

(6)时常朝着更好的解决方案前进。当选择前 N 个评分观察值时,优化函数中有一个 if 语句,这使得情况变得复杂。这是通过评估内存中的解决方案,并通过调整搜索区域来确定要探索或收敛的区域来实现的。

可以尝试的可用方法包括:

  • 遗传算法
  • 粒子群优化
  • 贝叶斯优化
  • 随机搜索
  • 禁忌搜索
  • 基于上述内容或其他内容的其他定制方法

可能并入算法的其他模型的组件:

  • 正规化
  • 限制
  • 批量标准化
  • 最终模型的退出或其他特征选择
  • 学习速度和/或动力

超参数

必须设置几个超参数:

  • 每个要素的条柱数量-可以是所有要素的相同数量,也可以是每个要素的不同数量
  • 一个箱中的最小观察数
  • 如果 L1 和 L2 正则化都被使用
  • 要做的最大迭代次数
  • 没有改进的最大迭代次数
  • 保留在学习者记忆中的最大观察次数
  • 实施任何优化所需的其他参数

合奏

如果需要模型解的集合,当算法终止时,可以容易地从存储器中的模型解中产生。

选股结果

部门:技术

细分市场:高波动性

绩效范围:4 周

观察期:52 周

模型中的特征数量:30

X 矩阵的列数:134

唯一股票代码数量:535

限制:

  • 一年中挑选的唯一股票报价机的最小数量= 40
  • 这用于防止算法学习挑选特定的股票

学习模型:简单的概率搜索,每 100 次迭代学习更新一次

最大迭代次数:400 次

合奏:

  • 生成了 10000 个不同的模型
  • 每个模型选择由截止分数确定,截止分数设置为所有库存周模型分数的 90%,即库存周级别的 0/1 分数
  • 库存周级别的得分=模型得分之和/ 10

记分卡的部分样本

下面显示了两个特性的样本特性得分和初始值。这里的下限是仓位的下限,第一个仓位是股票在过去一个季度中低于-31.54%的所有表现值,最后一个仓位高于 48.58%,缺失值为 0 分。

我们可以很容易地理解,该模型喜欢上个季度下跌很多的股票(它们得到 19 点)和上周上涨超过 1.66%的股票。它确实奖励了上周上涨超过 11.61%的账户,给他们 47 个点,而严重惩罚了那些下跌超过 5.93%的账户。

所有 30 个特性都有类似于表中 2 的分数,因为显示的记分卡是所有分数的平均分。

Performance (Quarter) 

        cut    points
     ------    ------
       -inf        19     0.38
     -31.54        -8    -0.13
     -12.02         0     0.01
      48.58         7     0.12
        nan         0     0.00

 Performance (Week) 

        cut    points
     ------    ------
       -inf       -56    -0.71
      -5.93        -6    -0.22
       1.66        27     0.43
      11.61        47     1.11

剧情

该图显示了不同的 50 分区间的综合预期收益和股价上涨的概率。整体方法导致以下分数分布:

42%的观察得分为 0。

24%的人得分在 1 到 25 分之间。

然后,每个分数仓中的观察值数量下降到 450–499 的范围是最后一个范围,至少有 1%的库存周观察值。

最后,950-999 的得分范围只有 0.45%的观察得分那么高。

有趣的是,模型在处理价格上涨的概率价格上涨的百分比减去价格下跌的概率价格下跌的百分比的乘积时,在分数范围内仍然具有几乎单调增加的概率(上涨),同时扩大了损益之间的差距。

通过将一个桶中的平均损耗和增益除以所有桶中的最大增益来计算预期损耗和增益的指数,以便于在同一图表上绘图。

最高评级股票 COUP 的回报与得分的关系图。

点数是在 52 周的模型开发样本中,第 120 周得分最高的 10 只股票的不同得分的观察值。

可以看出,随着得分的上升,回报分布(y 轴)的变化和风险降低。还要注意的是,前 10 名的最高回报在 0 分范围内——没有一个模型选择它,因为它看起来太像风险更高的股票周配置文件。基本上 0 分会有一个期望值< the population expected value since both the probability and gain to loss ratio are going up over the score range.

The vertical black line indicates the score for COUP in the current week when the model was run.

The model results can be used to estimate targets for individual observations by tabulating the outcomes in the ranges. The first number after target is the expectation if COUP goes down in price at the end of 4 weeks, the second if it goes up and the probability that COUP will go up.

结论:

机器学习可以被合并到一个灵活的简单易懂的模型中,即一个整数值记分卡。

这样做允许建模者通过直接计算结果来提供更适用的解决方案。没有必要估计分类概率,对它们进行排序,然后计算第二个模型来获得特定观察的影响大小。

关于使用什么组件、求解过程和正则化,有大量的选项。

对于那些有此倾向的人来说,创造的机会是敞开的。

像这样的模型可以用于:

  • 识别投资机会,股票市场和其他。
  • 在一天内可以调查的交易数量的任何操作限制内,确定一组预期欺诈损失最高的交易。
  • 生成考虑财务回报的申请分数,对申请被接受的百分比或数量进行约束。
  • 确定表现比预期差的 N 个客户的细分市场,同时最大限度地减少未来因拒绝具有此特征的申请而造成的收入损失。

提问&建议

如果您有任何问题、建议或问题,希望看到像这样的 ML 模型的结果,请随时给我发电子邮件:

bill.fite@miner3.com。

如果你感兴趣的话,我还希望在 minor3.com 的一个页面上更新模型选择和监控结果。

使用 Plotly 的 Dash 创建交互式数据应用程序

原文:https://towardsdatascience.com/creating-an-interactive-data-app-using-plotlys-dash-356428b4699c?source=collection_archive---------2-----------------------

我们来做一个 app,自动出图数据文件。这是一个使用 plotly 的破折号在 python 中创建 web 应用程序的演练,其中有一个我们在 Kyso 创建的示例—现场版本可以在这里找到:

[## 破折号

用 Plotly 的 Dash 编辑自动文件绘图应用程序

dash-app-dx9 g 2r 0 la 6-8000 . cloud . kyso . io](https://dash-app-dx9g2r0la6-8000.cloud.kyso.io/)

Uploading Multiple File-Types & Automatically Generate Scalar Plots

这是一个用 xy,xyyy 等上传任何文件的应用程序。坐标,然后自动生成一个图。

Dash 是用于构建 web 应用程序的 Python 框架。它建立在 Flask、Plotly.js、React 和 React Js 之上。,使您能够使用纯 Python 构建仪表板和应用程序。在本教程中,我将向您介绍基础知识,并假设您之前有使用 Plotly 的经验。如果你是 plotly 的新手,请查看这些初学者指南:

https://kyso.io/KyleOS/plotly-intro

https://kyso.io/KyleOS/cufflinks-intro

装置

为了开始使用 Dash,你需要安装几个软件包。

  1. 核心 dash 后端。
  2. 仪表板前端
  3. Dash HTML 组件
  4. 仪表板核心部件
  5. Plotly

请注意,如果您想从 Kyso 启动您的应用程序,所有这些都已预装在 Kyso 的工作区中!

pip install dash==0.21.1  
pip install dash-renderer==0.13.0  
pip install dash-html-components==0.11.0
pip install dash-core-components==0.23.0  
pip install plotly --upgrade

Dash 应用程序布局

Dash 应用程序由两部分组成。第一部分是应用程序的“布局”,它描述了应用程序的外观。Dash 为应用程序的所有可视化组件提供了 Python 类,即使用 Python 生成 HTML 内容。为了使用这些类,让我们导入dash_core_componentsdash_html_components库。用下面的代码创建一个名为app.py的文件:

import dash
import dash_core_components as dcc
import dash_html_components as html

像使用 Flask 一样,我们可以通过调用 dash 的 Dash 类来初始化 Dash。一旦完成,我们就可以为我们的应用程序创建布局,使用来自dash_html_components的 Div 类来创建 HTML Divs。请注意,dash_html_components包含了所有的 HTML 标签,可以让你设计应用程序的布局。

为了在我们的布局中创建一个图表,我们使用了来自dash_core_components的图表类。Graph 使用 plotly.js 呈现交互式数据可视化。Graph 类需要一个包含要绘制的数据和布局细节的图形对象。Dash 还允许你改变背景颜色和文本颜色。您可以通过使用 style 属性并传递具有您的特定颜色的对象来更改背景。

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

colors = {
    "graphBackground": "#F5F5F5",
    "background": "#ffffff",
    "text": "#000000"
}

app.layout = html.Div([
    dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
            'width': '100%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'center',
            'margin': '10px'
        },
        # Allow multiple files to be uploaded
        multiple=True
    ),
    dcc.Graph(id='Mygraph'),
    html.Div(id='output-data-upload')
])

请注意,我们正在为我们正在创建的每个组件设置 id,我们将在一秒钟内完成这些。Dash 上传组件允许应用程序的查看者上传文件。该应用程序可以通过监听 dcc 的内容属性来访问上传文件的内容。上传组件,它是一个 base64 编码的字符串,包含文件的内容,与文件类型无关。

所以我们创建了上面的布局;带有一些样式的上传框,以及当我们放入文件时将创建的图形。

熊猫和袖扣

好了,现在我们需要做一些事情,我们需要为以下内容创建函数:

  1. 读入任何文件,无论是 csv,excel 文件或 tsv,并将其转换成熊猫数据帧。
  2. 放下新文件时创建图形。
  3. 打印数据表。

为此我们需要几个库:

import base64
import datetime
import io
import plotly.graph_objs as go
import cufflinks as cf
import pandas as pd

import dash_table

因此,要解析我们的目标数据文件类型:

def parse_data(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV or TXT file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))
        elif 'txt' or 'tsv' in filename:
            # Assume that the user upl, delimiter = r'\s+'oaded an excel file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')), delimiter = r'\s+')
    except Exception as e:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])

    return df

使用袖扣——一种便于绘制熊猫和 plotly 的包装——来绘制我们的标量图:

def update_graph(contents, filename):
    fig = {
        'layout': go.Layout(
            plot_bgcolor=colors["graphBackground"],
            paper_bgcolor=colors["graphBackground"])
    }

    if contents:
        contents = contents[0]
        filename = filename[0]
        df = parse_data(contents, filename)
        df = df.set_index(df.columns[0])
        fig['data'] = df.iplot(asFigure=True, kind='scatter', mode='lines+markers', size=1)

        table = html.Div([
            html.H5(filename),
            dash_table.DataTable(
                data=df.to_dict('rows'),
                columns=[{'name': i, 'id': i} for i in df.columns]
            ),
            html.Hr(),
            html.Div('Raw Content'),
            html.Pre(contents[0:200] + '...', style={
                'whiteSpace': 'pre-wrap',
                'wordBreak': 'break-all'
            })
        ])

最后,为每次放入文件创建一个表:

def update_table(contents, filename):
    table = html.Div()

    if contents:
        contents = contents[0]
        filename = filename[0]
        df = parse_data(contents, filename)

        table = html.Div([
            html.H5(filename),
            dash_table.DataTable(
                data=df.to_dict('rows'),
                columns=[{'name': i, 'id': i} for i in df.columns]
            ),
            html.Hr(),
            html.Div('Raw Content'),
            html.Pre(contents[0:200] + '...', style={
                'whiteSpace': 'pre-wrap',
                'wordBreak': 'break-all'
            })
        ])

    return table

交互性— Dash 回调

Dash 应用程序的第二部分涉及定义应用程序交互性的回调。为此,我们需要从 dash.dependencies 导入输入和输出:

from dash.dependencies import Input, Output, State

在这个应用程序中,我们有两个回调:

@app.callback(Output('Mygraph', 'figure'),
            [
                Input('upload-data', 'contents'),
                Input('upload-data', 'filename')
            ])

因此,我们的输入是我们在开始时创建的上传组件,并将其绑定到一个回调,这样每当选择一个文件时,它都会实时更新我们的图形组件Mygraph。Dash 提供了一个 decorator @app,它使得将回调函数绑定到我们的组件成为可能。你会注意到在完整的app.py中,我们在声明 update_graph 函数之前使用了装饰器。

下面是我们的第二个回调,具有相同的输入(即,上传到我们的上传组件的文件,这次输出是包含文件数据的打印表格版本的 HTML Div。同样,装饰器在我们声明 update_table 函数之前被调用。

@app.callback(Output('output-data-upload', 'children'),
            [
                Input('upload-data', 'contents'),
                Input('upload-data', 'filename')
            ])

运行您的应用

为了查看我们的可视化,我们需要像在 Flask 中一样运行我们的 web 服务器。记住 Dash 是建立在烧瓶顶部的。Dash 包括“热重装”,当您使用app.run_server(debug=True)运行应用程序时,默认情况下会激活该功能。这意味着当你修改代码时,Dash 会自动刷新你的浏览器。

if __name__ == '__main__':
    app.run_server(debug=True, host='0.0.0.0', port=8000)

接下来,移动到终端,通过键入下面的代码启动服务器:python app.py——这将在[http://localhost:8000/](http://localhost:8000/.) 启动一个新的 web 服务器。

完整的应用程序

现在,把所有东西放在一起:

import base64
import datetime
import io
import plotly.graph_objs as go
import cufflinks as cf

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table

import pandas as pd

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server

colors = {
    "graphBackground": "#F5F5F5",
    "background": "#ffffff",
    "text": "#000000"
}

app.layout = html.Div([
    dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
            'width': '100%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'center',
            'margin': '10px'
        },
        # Allow multiple files to be uploaded
        multiple=True
    ),
    dcc.Graph(id='Mygraph'),
    html.Div(id='output-data-upload')
])

def parse_data(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV or TXT file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))
        elif 'txt' or 'tsv' in filename:
            # Assume that the user upl, delimiter = r'\s+'oaded an excel file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')), delimiter = r'\s+')
    except Exception as e:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])

    return df

@app.callback(Output('Mygraph', 'figure'),
            [
                Input('upload-data', 'contents'),
                Input('upload-data', 'filename')
            ])
def update_graph(contents, filename):
    fig = {
        'layout': go.Layout(
            plot_bgcolor=colors["graphBackground"],
            paper_bgcolor=colors["graphBackground"])
    }

    if contents:
        contents = contents[0]
        filename = filename[0]
        df = parse_data(contents, filename)
        df = df.set_index(df.columns[0])
        fig['data'] = df.iplot(asFigure=True, kind='scatter', mode='lines+markers', size=1)

    return fig

@app.callback(Output('output-data-upload', 'children'),
            [
                Input('upload-data', 'contents'),
                Input('upload-data', 'filename')
            ])
def update_table(contents, filename):
    table = html.Div()

    if contents:
        contents = contents[0]
        filename = filename[0]
        df = parse_data(contents, filename)

        table = html.Div([
            html.H5(filename),
            dash_table.DataTable(
                data=df.to_dict('rows'),
                columns=[{'name': i, 'id': i} for i in df.columns]
            ),
            html.Hr(),
            html.Div('Raw Content'),
            html.Pre(contents[0:200] + '...', style={
                'whiteSpace': 'pre-wrap',
                'wordBreak': 'break-all'
            })
        ])

    return table

if __name__ == '__main__':
    app.run_server(debug=True)

要自己运行这个应用程序,只需将上面的代码复制粘贴到你的app.py文件中,然后从终端运行

python app.py

转到[http://localhost:8000/](http://localhost:8000/)

在 Kyso 上运行 Dash 应用程序

启动一个工作空间(参见此处的指南)并进入 Jupyterlab。您可以从笔记本上运行它(只需执行单元),或者创建一个 app.py 文件并从终端上运行。

要查看正在运行的应用程序,请将工作空间的 URL 复制并粘贴到单独的选项卡中。移除lab?并将-8000(我们在上面启动应用的公共端口)附加到工作区 id 号,在.cloud.kyso.io之前。例如,如果我的工作空间在[https://live-aymycm9bst.cloud.kyso.io/lab?](https://live-aymycm9bst.cloud.kyso.io/lab?)运行

在一个单独的选项卡中,我可以转到https://live-aymycm9bst-8000.cloud.kyso.io/,我的应用将在那里运行。

创建和部署 Python 机器学习服务

原文:https://towardsdatascience.com/creating-and-deploying-a-python-machine-learning-service-a06c341f020f?source=collection_archive---------15-----------------------

用 scikit 构建一个仇恨言论检测系统-通过 Heroku 上的 Docker 学习和部署它。

Photo by Jon Tyson on Unsplash

介绍

假设你是留言板或评论区的版主。你不想阅读你的用户在网上写的所有东西,但你想在讨论变得不愉快或人们开始到处散布种族诽谤时得到提醒。所以,你决定为自己建立一个自动检测仇恨言论的系统。

通过机器学习进行文本分类是一种明显的技术选择。然而,将模型原型转化为工作服务被证明是一个普遍的挑战。为了帮助弥合这一差距,本四步教程展示了仇恨言论检测应用程序的示例性部署工作流程:

  1. scikit-learn 训练并保持一个预测模型
  2. firefly 创建一个 API 端点
  3. 为这个服务创建一个 Docker 容器
  4. Heroku 上部署容器

该项目的代码可在这里获得。

1.创建预测模型

资料组

该方法基于戴维森、瓦姆斯利、梅西和韦伯的论文 自动仇恨言论检测和攻击性语言问题 。他们的结果是基于超过 20 000 条有标签的推文,这些推文可以在相应的 Github 页面上找到。

的。csv 文件作为数据帧加载:

import pandas as pd
import re**df** = pd.read_csv('labeled_data.csv', usecols=['class', 'tweet'])**df**['tweet'] = **df**['tweet'].apply(lambda tweet: re.sub('[^A-Za-z]+', ' ', tweet.lower()))

最后一行通过将所有文本转换为小写并删除非字母字符来清理 tweet 列。

结果:

class 属性可以假设三个类别值:0表示仇恨言论,1表示攻击性语言,2两者都不表示。

模特培训

在训练机器学习分类器之前,我们必须将我们的预测器,即推文文本,转换为数字表示。我们可以使用 scikit-learn 的 TfidfVectorizer 来完成这项任务,它将文本转换为适合机器学习的术语频率乘以逆文档频率(tf-idf)值的矩阵。此外,我们可以从处理中删除停用词(常用词如、…)。

对于文本分类,支持向量机( SVMs )是一个可靠的选择。由于它们是二元分类器,我们将使用一对其余策略,其中对于每个类别,训练一个 SVM 来将该类别与所有其他类别分开。

通过使用 scikit-learn 的管道功能并定义相应的步骤,可以在一个命令中执行文本矢量化和 SVM 训练:

from sklearn.pipeline import make_pipeline
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from stop_words import get_stop_words**clf** = make_pipeline(
    TfidfVectorizer(stop_words=get_stop_words('en')),
    OneVsRestClassifier(SVC(kernel='linear', probability=True))
)**clf** = **clf**.fit(X=**df**['tweet'], y=**df**['class'])

现在,应该评估模型的性能,例如,使用交叉验证方法来计算分类度量。然而,由于本教程关注的是模型部署,我们将跳过这一步(在实际项目中从不这样做)。这同样适用于参数调整或自然语言处理的附加技术,在原始论文中有所描述。

测试模型

我们现在可以尝试一个测试文本,让模型预测概率:

**text** = "I hate you, please die!" **clf**.predict_proba([**text**.lower()])# Output:
array([0.64, 0.14, 0.22])

数组中的数字对应于三个类别的概率(仇恨言论、攻击性语言,都不是)。

模型持久性

使用 joblib 模块,我们可以将模型作为二进制对象保存到磁盘。这将允许我们在应用程序中加载和使用模型。

from sklearn import externals**model_filename** = 'hatespeech.joblib.z'
externals.joblib.dump(**clf**, **model_filename**)

2.创建 REST API

创建 API 端点

python 文件app.py加载模型并定义一个简单的模块级函数,该函数封装了对模型的 predict_proba 函数的调用:

from sklearn import externals**model_filename** = 'hatespeech.joblib.z'
**clf** = externals.joblib.load(model_filename)def predict(**text**):
    probas = **clf**.predict_proba([**text**.lower()])[0]
    return {'hate speech': probas[0],
           'offensive language': probas[1],
           'neither': probas[2]}

现在,我们使用 firefly ,这是一个轻量级 python 模块,用于将功能作为服务。对于高级配置或在生产环境中的使用,Flask 或 Falcon 可能是更好的选择,因为它们已经在大型社区中建立了良好的声誉。对于快速原型,我们对 firefly 很满意。

我们将在命令行中使用 firefly 将 predict 函数绑定到本地主机上的端口 5000:

**$** firefly app.predict --bind 127.0.0.1:5000

本地测试 API

通过curl,我们可以向创建的端点发出 POST 请求,并获得一个预测:

**$** curl -d '{"text": "Please respect each other."}' \ http://127.0.0.1:5000/predict# Output:
{"hate speech": 0.04, "offensive language": 0.31, "neither": 0.65}

当然,在一个成熟的实际应用程序中,会有更多的附加功能(日志记录、输入和输出验证、异常处理等等)和工作步骤(文档、版本控制、测试、监控等等),但是这里我们只是部署一个简单的原型。

3.创建 Docker 容器

为什么是 Docker?Docker 容器在一个隔离的环境中运行应用程序,包括所有的依赖项,并且可以作为映像提供,从而简化服务设置和扩展。

构建图像

我们必须在一个名为Dockerfile的文件中配置容器的内容和开始动作:

FROM python:3.6
RUN pip install scikit-learn==0.20.2  firefly-python==0.1.15
COPY app.py hatespeech.joblib.z ./CMD firefly app.predict --bind 0.0.0.0:5000
EXPOSE 5000

前三行是关于将python:3.6作为基础映像,另外安装 scikit-learn 和 firefly(与开发环境中的版本相同)并复制里面的 app 和模型文件。后两行告诉 Docker 启动容器时执行的命令以及应该暴露的端口 5000。

创建图像hatespeechdetect的构建过程通过以下方式开始:

**$** docker build . -t hatespeechdetect

运行容器

run命令启动一个容器,从一个图像派生。此外,我们通过-p选项将容器的端口 5000 绑定到主机的端口 3000:

**$** docker run -p 3000:5000 -d hatespeechdetect

使用预测服务

现在,我们可以发送一个请求并获得一个预测:

**$** curl -d '{"text": "You are fake news media! Crooked!"}' \ http://127.0.0.1:3000/predict# Output:
{"hate speech": 0.08, "offensive language": 0.76, "neither": 0.16}

在本例中,容器在本地运行。当然,实际的目的是让它在一个永久的位置运行,并且可能通过在一个企业集群中启动多个容器来扩展服务。

4.部署为 Heroku 应用程序

让其他人可以公开使用该应用的一种方式是使用平台即服务,如 Heroku ,它支持 Docker 并提供免费的基本会员资格。要使用它,我们必须注册一个帐户并安装 Heroku CLI。

Heroku 的应用程序容器公开了一个动态端口,这需要在我们的Dockerfile中进行编辑:我们必须将端口 5000 更改为环境变量PORT:

CMD firefly app.predict --bind 0.0.0.0:$PORT

在此变更之后,我们就可以开始部署了。在命令行上,我们登录 heroku(它会在浏览器中提示我们输入凭证)并创建一个名为hate-speech-detector的应用程序:

**$** heroku login**$** heroku create hate-speech-detector

然后我们登录到容器注册中心。heroku container:push将基于当前目录中的 Dockerfile 构建一个映像,并将其发送到 Heroku 容器注册表。之后,我们可以将图像发布到应用程序:

**$** heroku container:login**$** heroku container:push web --app hate-speech-detector**$** heroku container:release web --app hate-speech-detector

和以前一样,API 可以通过 curl 来处理。但是,这一次,服务不是在本地运行,而是面向全球!

**$** curl -d ‘{“text”: “You dumb idiot!”}’ https://hate-speech-detector.herokuapp.com/predict# Output:
{"hate speech": 0.26, "offensive language": 0.68, "neither": 0.06}

现在,只需点击几下鼠标或输入几个命令,就可以扩展应用程序。此外,该服务需要连接到留言板,需要设置触发阈值并实现警报。

希望这篇教程能帮助你部署你自己的机器学习模型和应用。有其他想法吗?请在评论中分享你的观点!

使用 fluore Studio 创建出色的地图数据可视化。

原文:https://towardsdatascience.com/creating-awesome-map-data-visualizations-using-flourish-studio-6410a8e01c74?source=collection_archive---------16-----------------------

一个开源数据故事讲述平台

空间分析和可视化帮助我们从复杂的地理空间数据中获得易于理解的见解。我们以天气数据、谷歌地图、GPS 坐标和带地理标记的社交媒体帖子等形式生成大量地理空间数据,这些数据正在成为我们生活和业务不可或缺的一部分。麦肯锡的一项研究表明,到 2025 年,基于位置的传感器的加速扩散可能会带来每年超过 11 万亿美元的经济影响。可视化地图数据使见解更清晰、更直观,并获得受众的关注。但是许多人发现,与统计分析相比,空间分析和可视化非常难以执行。在这篇博客中,我们将讨论如何使用开源数据可视化和讲故事平台的繁荣来创建交互式地图数据可视化。

为什么用花枝招展?

有许多专用软件可用于地理空间分析和可视化。QGIS 和 CARTO 是一些广泛使用的地理空间分析软件,用于地理空间数据的高端分析。像 R 和 Python 这样的统计软件也有很多专门用于地理空间分析的包。但是,当您想要快速分析地理空间数据并创建交互式可视化时,这些工具就不那么用户友好了。除了您必须编写的代码之外,使在线出版的可视化交互有点棘手。

蓬勃发展来了六个预加载的模板,使交互式地图可视化。您可以在现有的地理地图模板上上传您的数据,或者上传您自己的地理边界文件。六个地图可视化模板如下:

1.投影地图

2.标记地图

3.弧形地图

4.3D 区域地图

5.连接全球

6.测量图

我们将看看如何根据地理空间数据的性质创建三种不同类型的地图可视化。

如何创建针对不同地理区域的动画可视化?

假设您有不同国家/地区的国家级数据,并且想要讲述一个侧重于表现良好的特定地理区域和表现不佳的地理区域的数据故事,那么您可以使用已经存在于 fluore 中的 World 的投影地图模板。当你打开世界模板,点击‘数据’标签,你可以通过查看已经可用的虚拟数据来理解数据应该是什么格式。以所需格式上传数据后,您可以点击【预览】数据选项卡,更改页面右侧的可视化设置。

蓬勃发展带来了这个惊人的选择,创建一个数据故事使用您创建的可视化。在可视化页面的右上角有“创建一个故事”链接,我们可以使用幻灯片模板讲述您的数据故事,就像 PowerPoint 演示一样。一旦你创建了你的故事,你就可以把它发布在 fluorescent server 上,并把它嵌入到任何在线资源中。这是我根据社交媒体关注度制作的可视化图片,展示了各大洲最受欢迎的足球俱乐部。

目前,fluorescent 没有从创建的可视化图像中创建 gif 或视频的选项。您可以使用一种可用的屏幕转 gif 软件来创建视频或 gif。用于 MAC 的 Giphy Capture 和用于 Windows 的 ScreenToGif是常用的软件。gif 或视频可以通过以下步骤创建:

打开您发布的可视化效果

调整屏幕的大小以适合可视化

录制屏幕相关部分的视频或 gif 截图,在幻灯片之间点击并放大地图的相关部分

根据需要将录像保存为 gif 或视频

与 gif 相比,视频是质量更好的输出,但文件大小会更大,上传时可能会有问题。

如何创建 Connections Globe 地图?

我们面临的情况是,我们希望可视化不同地理区域之间的人员和货物流动——无论是可视化国家之间的人员迁移还是可视化鸟类的迁移模式。大多数统计软件没有可视化分析移动数据的功能。蓬勃发展有这个连接全球模板,让您无缝可视化移动。拥有源和目的地的地理坐标就足以创建连接全球地图。这种可视化是高度交互式的,您可以根据需要旋转和缩放地球。您有许多设计和显示选项可用于自定义地图。

在这里,我创建了一个 connections globe 地图,根据居住在这些国家的非居民印度人的数量来可视化印度国民移民到的前 15 个国家。

如何创建一个简单的气泡图可视化?

使用 fluore 的投影地图模板可以非常容易地创建 choropleth 地图和 bubble 地图。对于某些地区,如世界、美国(州)、美国(县)、印度(州)、英国、西班牙、巴西等,fluorescent 有自己的内置模板。这是我创建的气泡图,显示了印度各邦的人均 GDP 值。

当所需的地理边界文件不可用时该怎么办?

蓬勃发展有限的地理文件,你可以上传你的数据到可视化。如果找不到您所在国家的地图,您可以选择上传自己的地理边界文件。有许多在线资源,你可以从那里下载不同国家的地理形状文件。GADM 是为所有国家和地区提供地图和空间数据的流行资源之一。你可以免费下载这些地理形状文件。

结论

蓬勃发展是一个用户友好的数据可视化平台,以创建强大的和交互式的数据故事。这是一个用最少的努力创建不同类型的地图数据可视化的完美媒介。探索 fluore,了解可以实现哪些其他类型的数据可视化。

创造比特币交易机器人不赔钱

原文:https://towardsdatascience.com/creating-bitcoin-trading-bots-that-dont-lose-money-2e7165fb0b29?source=collection_archive---------1-----------------------

让我们使用深度强化学习来制造加密货币交易代理

在本文中,我们将创建深度强化学习代理,学习如何通过比特币交易赚钱。在本教程中,我们将使用 OpenAI 的gym和来自stable-baselines库的 PPO 代理,后者是 OpenAI 的baselines库的一个分支。

这一系列文章的目的是试验最先进的深度强化学习技术,看看我们能否创造出盈利的比特币交易机器人。现状似乎是迅速关闭任何创建强化学习算法的尝试,因为这是“构建交易算法的错误方式”。然而,该领域的最新进展表明,在相同的问题域内,RL 代理通常能够比监督学习代理学习更多的东西。出于这个原因,我写这些文章是为了看看这些交易代理能给我们带来多大的利润,或者说现状的存在是有原因的。

非常感谢 OpenAI 和 DeepMind 在过去几年里为深度学习研究人员提供的开源软件。如果你还没有看到他们用像 AlphaGo、OpenAI Five 和 AlphaStar 这样的技术完成的惊人壮举,你可能在过去的一年里一直生活在岩石下,但你也应该去看看他们。

AlphaStar Training (https://deepmind.com/blog/alphastar-mastering-real-time-strategy-game-starcraft-ii/)

虽然我们不会创造任何令人印象深刻的东西,但每天交易比特币并从中获利仍然不是一件容易的事情。然而,正如泰迪·罗斯福曾经说过的,

任何值得拥有的东西都来之不易。

所以,与其学习交易我们自己,不如让一个机器人来替我们做这件事。

[## 更明智地交易和投资——强化学习方式

深入探讨 TensorTrade——一个用于培训、评估和部署稳健交易的开源 Python 框架…

towardsdatascience.com](/trade-smarter-w-reinforcement-learning-a5e91163f315)

当你读完这篇文章后,看看TensorTrade——这篇文章中产生的代码库的后继框架。

这个计划

  1. 为我们的代理创造一个学习的健身房环境
  2. 呈现简单而优雅环境可视化
  3. 培训我们的代理人学习有利可图的交易策略

如果你还不熟悉如何从头开始创建一个体育馆环境,或者如何呈现这些环境的简单可视化,我刚刚写了关于这两个主题的文章。在继续之前,请随意在此暂停并阅读其中任何一篇。

入门指南

对于本教程,我们将使用由 Zielak 生成的 Kaggle 数据集。如果你想下载代码跟随,我的 GitHub repo 上也有.csv数据文件。好了,我们开始吧。

首先,让我们导入所有必需的库。确保pip install您遗漏了任何库。

**import** gym
**import** pandas **as** pd
**import** numpy **as** np
**from** gym **import** spaces
**from** sklearn **import** preprocessing

接下来,让我们为环境创建我们的类。我们将要求传入一个pandas数据帧,以及一个可选的initial_balance和一个lookback_window_size,它将指示代理在过去的每一步将观察多少时间步。我们将每次交易的commission默认为 0.075%,这是 Bitmex 的当前利率,并将serial参数默认为 false,这意味着默认情况下我们的数据帧将在随机切片中遍历。

我们还调用数据帧上的dropna()reset_index()来首先删除任何带有NaN值的行,然后重置帧的索引,因为我们已经删除了数据。

***class*** BitcoinTradingEnv(*gym*.*Env*):
  *"""A Bitcoin trading environment for OpenAI gym"""*
  metadata = {'render.modes': ['live', 'file', 'none']}
  scaler = preprocessing.MinMaxScaler()
  viewer = None ***def*** __init__(*self*, *df*, *lookback_window_size*=50, 
                         commission=0.00075,  
                         *initial_balance*=10000
                         serial=False):
    *super*(BitcoinTradingEnv, self).__init__() self.df = df.dropna().reset_index()
    self.lookback_window_size = lookback_window_size
    self.initial_balance = initial_balance
    self.commission = commission
    self.serial = serial # Actions of the format Buy 1/10, Sell 3/10, Hold, etc.
    self.action_space = spaces.MultiDiscrete([3, 10]) # Observes the OHCLV values, net worth, and trade history
    self.observation_space = spaces.Box(*low*=0, *high*=1, *shape*=(10, 
                    lookback_window_size + 1), *dtype*=np.float16)

我们的action_space在这里被表示为一个由 3 个选项(买入、卖出或持有)组成的离散集合和另一个由 10 个数量(1/10、2/10、3/10 等)组成的离散集合。当选择买入动作时,我们将买入价值amount * self.balance的 BTC。对于出售行动,我们将出售价值amount * self.btc_held的 BTC。当然,hold 动作会忽略金额,什么都不做。

我们的observation_space定义为 0 和 1 之间的一组连续的浮点数,形状为(10, lookback_window_size + 1)+ 1是为了说明当前的时间步。对于窗口中的每个时间步,我们将观察 OHCLV 值、我们的净值、买入或卖出的 BTC 金额,以及我们在这些 BTC 上花费或收到的美元总额。

接下来,我们需要编写我们的reset方法来初始化环境。

***def*** reset(*self*):
  self.balance = self.initial_balance
  self.net_worth = self.initial_balance
  self.btc_held = 0 self._reset_session() self.account_history = np.repeat([
    [self.net_worth],
    [0],
    [0],
    [0],
    [0]
  ], self.lookback_window_size + 1, *axis*=1) self.trades = [] **return** self._next_observation()

这里我们同时使用了self._reset_sessionself._next_observation,我们还没有定义它们。让我们来定义它们。

交易时段

我们环境的一个重要部分是交易时段的概念。如果我们将这个代理部署到野外,我们可能永远不会一次运行超过几个月。出于这个原因,我们将在self.df中限制我们的代理在一行中看到的连续帧的数量。

在我们的_reset_session方法中,我们将首先将current_step重置为0。接下来,我们将把steps_left设置为1MAX_TRADING_SESSION之间的一个随机数,我们现在将在文件的顶部定义它。

MAX_TRADING_SESSION = 100000  # ~2 months

接下来,如果我们是串行遍历帧,我们将设置要遍历的整个帧,否则我们将把frame_start设置为self.df内的随机点,并创建一个名为active_df的新数据帧,它只是从frame_startframe_start + steps_leftself.df的一部分。

***def*** _reset_session(*self*):
  self.current_step = 0 **if** self.serial:
    self.steps_left = len(self.df) - self.lookback_window_size - 1
    self.frame_start = self.lookback_window_size
  **else**:
    self.steps_left = np.random.randint(1, MAX_TRADING_SESSION)
    self.frame_start = np.random.randint(
         self.lookback_window_size, len(self.df) - self.steps_left) self.active_df = self.df[self.frame_start -   
       self.lookback_window_size:self.frame_start + self.steps_left]

以随机切片遍历数据帧的一个重要副作用是,当我们的代理接受长时间训练时,将有更多的独特的数据要处理。例如,如果我们只是以串行方式(即从0len(df)的顺序)遍历数据帧,那么我们只会拥有与数据帧中一样多的唯一数据点。我们的观察空间甚至只能在每个时间步呈现离散数量的状态。

然而,通过随机遍历数据帧的切片,我们实际上是通过创建帐户余额、进行的交易和我们初始数据集中每个时间步的先前看到的价格行为的更有趣的组合来制造更多独特的数据点。我举个例子解释一下。

在重置串行环境后的时间步骤 10,我们的代理将始终处于数据帧内的同一时间,并且在每个时间步骤将有3 个选择:买入、卖出或持有。对于这三种选择中的每一种,还需要另一种选择:可能金额的 10%、20%、……或 100%。这意味着我们的代理人可以体验(1⁰ ) ⁰所有州中的任何一个,总共可以体验 1⁰ ⁰所有独特的体验。

现在考虑我们的随机切片环境。在时间步长 10,我们的代理可以在数据帧内的任何len(df)时间步长。假设在每个时间步做出相同的选择,这意味着该代理可以在相同的 10 个时间步内经历任何len(df) ⁰可能的唯一状态。

虽然这可能会给大型数据集增加相当多的噪声,但我相信它应该允许代理从我们有限的数据量中了解更多。我们仍将以串行方式遍历我们的测试数据集,以更准确地理解算法对新鲜的、看似“活的”数据的有用性。

代理人眼中的生活

这通常有助于可视化环境的观察空间,以便了解您的代理将使用的功能类型。例如,这是我们使用 OpenCV 渲染的观察空间的可视化。

OpenCV visualization of the environment’s observation space

图像中的每一行代表我们的observation_space中的一行。前 4 行类似频率的红线代表 OHCL 数据,正下方虚假的橙色和黄色点代表容量。下面波动的蓝色条代表代理的净值,下面较亮的点代表代理的交易。

如果你眯着眼睛,你只能看到一个蜡烛图,下面是音量条,下面是一个奇怪的类似莫尔斯电码的界面,显示交易历史。看起来我们的代理应该能够从我们的observation_space中充分了解数据,所以让我们继续。这里我们将定义我们的_next_observation方法,我们将从 0 到 1 缩放 观察数据

重要的是,只缩放代理到目前为止观察到的数据,以防止前瞻偏差。

***def*** _next_observation(*self*):
  end = self.current_step + self.lookback_window_size + 1 obs = np.array([
    self.active_df['Open'].values[self.current_step:end],  
    self.active_df['High'].values[self.current_step:end],
    self.active_df['Low'].values[self.current_step:end],
    self.active_df['Close'].values[self.current_step:end],
    self.active_df['Volume_(BTC)'].values[self.current_step:end],
  ]) scaled_history = self.scaler.fit_transform(self.account_history) obs = np.append(obs, scaled_history[:, -(self.lookback_window_size
                                                     + 1):], *axis*=0) **return** obs

采取行动

现在我们已经建立了我们的观察空间,是时候写我们的step函数了,反过来,采取代理的规定动作。每当self.steps_left == 0我们当前的交易时段,我们将出售我们持有的任何 BTC,并调用_reset_session()。否则,我们将reward设置为我们当前的净值,并且仅在我们没钱的时候将done设置为True

***def*** step(*self*, *action*):
  current_price = self._get_current_price() + 0.01
  self._take_action(action, current_price)
  self.steps_left -= 1
  self.current_step += 1 **if** self.steps_left == 0:
    self.balance += self.btc_held * current_price
    self.btc_held = 0
    self._reset_session() obs = self._next_observation()
  reward = self.net_worth
  done = self.net_worth <= 0 **return** obs, reward, done, {}

采取行动就像得到current_price,确定指定的行动,或者买入或者卖出指定数量的 BTC 一样简单。让我们快速编写_take_action以便测试我们的环境。

***def*** _take_action(*self*, *action, current_price*):
  action_type = action[0]
  amount = action[1] / 10 btc_bought = 0
  btc_sold = 0
  cost = 0
  sales = 0 **if** action_type < 1:
    btc_bought = self.balance / current_price * amount
    cost = btc_bought * current_price * (1 + self.commission)
    self.btc_held += btc_bought
    self.balance -= cost **elif** action_type < 2:
    btc_sold = self.btc_held * amount
    sales = btc_sold * current_price  * (1 - self.commission)
    self.btc_held -= btc_sold
    self.balance += sales

最后,用同样的方法,我们将把交易追加到self.trades,并更新我们的净值和账户历史。

 **if** btc_sold > 0 **or** btc_bought > 0:
    self.trades.append({
      'step': self.frame_start+self.current_step,
      'amount': btc_sold if btc_sold > 0 else btc_bought,
      'total': sales if btc_sold > 0 else cost,
      'type': "sell" if btc_sold > 0 else "buy"
    }) self.net_worth = self.balance + self.btc_held * current_price
  self.account_history = np.append(self.account_history, [
    [self.net_worth],
    [btc_bought],
    [cost],
    [btc_sold],
    [sales]
  ], *axis*=1)

我们的代理现在可以启动一个新环境,遍历该环境,并采取影响该环境的措施。是时候看他们交易了。

看着我们的机器人交易

我们的render方法可以像调用print(self.net_worth)一样简单,但这并不有趣。取而代之的是,我们将绘制一个简单的价格数据的蜡烛图,用量棒和一个单独的净值图来表示。

我们将从我写的最后一篇文章的中提取StockTradingGraph.py中的代码,并重新利用它来渲染我们的比特币环境。你可以从我的 GitHub 中抓取代码。

我们要做的第一个改变是将所有的self.df['Date']更新为self.df['Timestamp'],并删除所有对date2num的调用,因为我们的日期已经以 unix 时间戳格式出现。接下来,在我们的render方法中,我们将更新我们的日期标签以打印人类可读的日期,而不是数字。

**from** datetime **import** datetime

首先,导入datetime库,然后我们将使用utcfromtimestamp方法从每个时间戳获取一个 UTC 字符串,并使用strftime将该字符串格式化为Y-m-d H:M格式。

date_labels = np.array([datetime.utcfromtimestamp(x).strftime(
'%Y-%m-%d %H:%M') **for** x **in** self.df['Timestamp'].values[step_range]])

最后,我们将self.df['Volume']更改为self.df['Volume_(BTC)']以匹配我们的数据集,这样我们就可以开始了。回到我们的BitcoinTradingEnv,我们现在可以编写我们的render方法来显示图形。

***def*** render(*self*, *mode*='human', ***kwargs*):
  **if** mode == 'human':
    **if** self.viewer == None:
      self.viewer = BitcoinTradingGraph(self.df,
                                        kwargs.get('title', None)) self.viewer.render(self.frame_start + self.current_step,
                       self.net_worth,
                       self.trades,
                       *window_size*=self.lookback_window_size)

瞧啊。我们现在可以看到我们的代理商交易比特币。

Matplotlib visualization of our agent trading Bitcoin

绿色虚线标记代表 BTC 的买入,红色虚线标记代表卖出。右上方的白色标签是代理人的当前净值,右下方的标签是比特币的当前价格。简单,却不失优雅。现在,是时候培养我们的代理人了,看看我们能赚多少钱!

训练时间

我的第一篇文章受到的批评之一是缺乏交叉验证,或者将数据分成训练集和测试集。这样做的目的是为了测试您的最终模型在它从未见过的新鲜数据上的准确性。虽然这不是那篇文章关注的问题,但它确实在这里。由于我们使用的是时间序列数据,所以在交叉验证方面我们没有太多选择。

例如,一种常见的交叉验证形式称为 k 重验证,其中您将数据分成 k 个相等的组,并逐一挑出一组作为测试组,并将其余数据用作训练组。然而,时间序列数据高度依赖于时间,这意味着后期数据高度依赖于前期数据。所以 k-fold 是行不通的,因为我们的代理在交易之前会从未来的数据中学习,这是一个不公平的优势。

当应用于时间序列数据时,同样的缺陷也适用于大多数其他交叉验证策略。因此,我们只需简单地从整个数据帧中取出一部分,用作从帧的开头到某个任意索引的训练集,并使用其余的数据作为测试集。

slice_point = *int*(len(df) - 100000)
train_df = df[:slice_point]
test_df = df[slice_point:]

接下来,由于我们的环境仅设置为处理单个数据帧,因此我们将创建两个环境,一个用于训练数据,一个用于测试数据。

train_env = DummyVecEnv([*lambda*: BitcoinTradingEnv(train_df, 
                         *commission*=0, *serial*=False)])
test_env = DummyVecEnv([*lambda*: BitcoinTradingEnv(test_df, 
                        *commission*=0, *serial*=True)])

现在,训练我们的模型就像用我们的环境创建一个代理并调用model.learn一样简单。

model = PPO2(MlpPolicy,
             train_env,
             *verbose*=1, 
             *tensorboard_log*="./tensorboard/")
model.learn(*total_timesteps*=50000)

在这里,我们使用 tensorboard,这样我们可以轻松地可视化我们的 tensorflow 图,并查看有关我们的代理的一些定量指标。例如,下图显示了许多代理在 200,000 个时间步长内的折扣奖励:

哇,看起来我们的代理商非常赚钱!我们最好的代理人甚至能够在 200,000 步的过程中将他的平衡提高 1000 倍,而其他人平均至少提高 30 倍!

就在这一点上,我意识到环境中有一个错误…这是修复该错误后的新奖励图:

如你所见,我们的几个代理做得很好,其余的都破产了。然而,表现良好的代理最多只能达到初始余额的 10 倍甚至 60 倍。我必须承认,所有盈利的代理商都是在没有佣金的环境中接受培训和测试的,所以让我们的代理商真正赚钱仍然是完全不现实的。但是我们正在取得进展!

让我们在测试环境中测试我们的代理人(使用他们从未见过的新鲜数据),看看他们对比特币交易的学习有多好。

Our trained agents race to bankruptcy when trading on fresh, test data

显然,我们还有相当多的工作要做。通过简单地将我们的模型切换到使用 stable-baseline 的 A2C,而不是当前的 PPO2 代理,我们可以大大提高我们在这个数据集上的性能。最后,我们可以根据 Sean O'Gorman 的建议稍微更新一下我们的奖励函数,这样我们就可以奖励净值的增长,而不仅仅是获得高净值并保持高净值。

reward = self.net_worth - prev_net_worth

仅这两个变化就大大提高了测试数据集的性能,正如您在下面看到的,我们最终能够在训练集中没有的新数据上实现盈利。

然而,我们可以做得更好。为了改善这些结果,我们需要优化我们的超参数,并对我们的代理进行更长时间的培训。是时候打开 GPU 开始工作了!

然而,这篇文章已经有点长了,我们还有相当多的细节要看,所以我们要在这里休息一下。在我的下一篇文章中,我们将使用 贝叶斯优化 来确定我们问题空间的最佳超参数,并改进代理的模型以实现高利润的交易策略。

结论

在本文中,我们开始使用深度强化学习从零开始创建一个盈利的比特币交易代理。我们实现了以下目标:

  1. 利用 OpenAI 的健身房从零开始创建了一个比特币交易环境。
  2. 使用 Matplotlib 构建了该环境的可视化。
  3. 使用简单的交叉验证对我们的代理进行培训和测试。
  4. 微调我们的代理以实现盈利。

虽然我们的交易代理不像我们希望的那样有利可图,但它肯定有所进展。下一次,我们将通过先进的功能工程和贝叶斯优化来改进这些算法,以确保我们的代理能够持续击败市场。敬请关注我的下一篇文章,以及比特币万岁!

[## 利用强化学习交易比特币获取巨额利润

让我们教我们的深度 RL 代理通过特征工程和贝叶斯优化赚更多的钱

towardsdatascience.com](/using-reinforcement-learning-to-trade-bitcoin-for-massive-profit-b69d0e8f583b) [## 更明智地交易和投资——强化学习方式

深入探讨 TensorTrade——一个用于培训、评估和部署稳健交易的开源 Python 框架…

towardsdatascience.com](/trade-smarter-w-reinforcement-learning-a5e91163f315)

很重要的一点是要明白,本文中记录的所有研究都是出于教育目的,不应该作为交易建议。你不应该根据本文定义的任何算法或策略进行交易,因为你很可能会失去你的投资。

感谢阅读!一如既往,本教程的所有代码都可以在我的 GitHub 上找到。如果您有任何问题或反馈,请在下面留下评论,我很乐意收到您的来信!我也可以通过@notadamking 的Twitter联系到。

您也可以通过下面的链接在 Github 赞助商 Patreon上赞助我。

[## GitHub 赞助商

嗨,我是亚当。我是一名开发人员、作家和企业家,尤其对深度…

github.com](https://github.com/users/notadamking/sponsorship)

Github 赞助商目前正在 1:1 匹配所有捐款,最高可达 5000 美元!

[## 亚当·金正在创造改变世界的内容

嗨,我是亚当。我是一名开发人员、作家和企业家,尤其对深度…

patreon.com](https://patreon.com/notadamking)

创建引人注目的饼图替代方案

原文:https://towardsdatascience.com/creating-compelling-pie-chart-alternatives-3a1c2c2889b8?source=collection_archive---------17-----------------------

我最近完成了用数据讲故事,这是一个改善我们如何可视化数据的很好的例子。其中比较直白的一点就是没有饼状图。我以前听过这句话,知道这个话题有些争议。反对饼图的理由相当简单:它们不像人们想象的那样容易解释。人们不能轻易地以饼图的形式直观地分辨出数值之间的差异。角度并不特别适合人眼。你花多少时间挂一个没有水平仪的画框?).你也许能从视觉上分辨出 15 度和 90 度之间的区别,但是 20 度和 30 度之间的区别可能很棘手,这种区别可能很重要。尤其是当你开始在饼图上使用 3D 元素时,随着角度的进一步倾斜,这变得更加令人困惑。

让我们举个简单的例子,看看下面的图表,除了最大的比例,你有多大把握确定每个比例代表多少?

说“永远不要饼状图”感觉很容易!,但重要的是你如何替代它。仍然有这样的情况,我们想要传达整体的比例,用数据来讲述一个故事。你可能会被迫回到这种甜点形状的美丽,但让我们看看几个不同的选择。

这里有一个案例:你想创建一个主要电影制片厂当前市场份额的可视化。你从票房魔咒中抓取数据,把它放进一个 Jupyter 笔记本里,然后你开始:

呃。这一切都在那里,但它显然不是超级可解释的或令人信服的,尤其是如果你想说的东西比“布埃纳 Vista 有很大的份额”。

条形图

是的,条形图!这是那种当它和你握手时会看着你的眼睛的图表。它一直是数据可视化的中流砥柱,尽管它可能不是最耀眼的,但它是可靠的,并且更容易理解。为了更清楚,你可以把它放在水平位置,这样便于区分值:

只是在直接比较中,你可以很快看出每个工作室之间的区别,而不仅仅是最大的工作室。那些在饼状图中看起来大小相同的电影公司(如华纳、环球和索尼)的比例要清晰得多。如果你喜欢的话,你也可以试试堆积条形图,但是一个基本的条形图做得好的话会有很大的帮助。

树形图

处理饼图角度读数问题的另一种方法是将数据分成方块,这样可以更清楚地理解。树状图主要用于显示数据的层次结构,最近作为饼状图的替代物受到青睐。你必须注意你的数据有多少段,因为标注可能会很棘手。我们的数据有 11 个值,您可以看出它们就在边缘,我通常会尽量保持在这 11 个值以下,但这里的示例是:

华夫饼图表

华夫饼图表本质上是树形图的一种变体。它不是大块的,而是把它分成美味的华夫饼干形状的均匀部分。基于我们的数据的一个总体示例可能是这样的:

我发现华夫格图在视觉上更有帮助的是对某些值的标注。这里有一个例子,列出三个不同的工作室进行比较:

像这样的小版本可以作为比较的快速展示,在我看来,有时比一大块华夫饼更有帮助。

只显示数字!

有时候,你所拥有的数据并不会显得可笑,即使这是你想要表达的观点。假设您经营一家电影院,拥有如下数据:

------------
Proportion of snack purchase sales at the movie theater
Popcorn: 98%
Fountain drinks: 1%
Candy: .5%
The super combo pack: .25%
Bottled water: .25%
------------

不是你特别想按比例比较的东西,因为它没有讲述一个伟大的故事。退后一步,想想是否有其他方法可以传达这些数据告诉你的信息。对于这个例子,也许只是指出爆米花销售的巨大数量:

你使用什么将最终取决于你的观众和你试图讲述的故事。尝试一些东西,也在其他人身上尝试。通过观察你创造的形象来思考别人可能回答的问题。如果你想找个地方玩玩,就从这里开始吧,这里有一本 Jupyter 笔记本,上面有这篇文章中用到的所有例子。

使用 Doc2Vec 创建产品标签

原文:https://towardsdatascience.com/creating-great-product-tags-f3d2c7607dba?source=collection_archive---------16-----------------------

面向企业的实用方法

Too many tags. Photo Credit: Adi Goldstein.

产品标签给用户一个期望的快照,并帮助他们探索相关产品。如果标签创建的准确度不高,用户会发现很难信任它们,交互也会受到限制。然而,随着产品数量的增加,创建准确的标签变得越来越困难。为了解决这个问题,我们可以利用各种机器学习技术。特别是,我们将讨论如何通过结合人工标记和机器学习技术来创建产品标签。

作为一个例子,我们将使用www.govoyagin.com,其中产品由活动表示。

As we can see, the tags used on these products need some work. Credit: Voyagin.

选择标签

选择正确的标签并不一定是显而易见的。有多种方法:

  • 基于用户的:用户最关心什么标签?对于这种方法,第一步是与用户交谈或进行调查,找出他们对哪些标签感兴趣,以及什么对他们有意义。
  • 机器学习:数据中内置了哪些标签?聚类算法(如 k-means)可用于将产品分组在一起,然后主题建模技术可以得出代表聚类的标签。
  • 市场调查:竞争对手在做什么?无论什么行业,都有可能找到以某种方式使用标签的竞争对手。通常,他们会做各种类型的研究和测试,以提出他们的标签,这些可以是一个很好的起点。它还可以表明用户期望的行业标准是什么。
  • 内功:你觉得什么最好?在你的公司里应该有各种各样的业内专家,他们可能有很好的方法根据他们的经验来设置标签。这是另一个很好的起点,尽管你应该对基于少数人的想法做出产品决策保持警惕。

当然,这些只是其中的一些方法,有必要将它们结合起来以获得最佳效果。例如,你可以运行机器学习算法来计算出一组初始聚类,然后利用你的内部专家来选择精确的标签,最后从用户那里获得反馈,看看它们是否有意义,是否能与市场产生良好的共鸣。

在本例中,我们将使用与主要产品类别相对应的标签列表:

'Culture', 'Nature', 'Relaxation', 'Crazy', 'Celebration', 'Adventure', 'Food', 'Romantic', 'Socializing', 'Instagrammable', 'Family', 'Theme Parks'

一旦确定了标签列表,就必须给产品贴标签。

标记产品

对于拥有数百种产品的公司来说,手动标记产品是可行的,但是随着产品规模的扩大,维护起来就变得非常困难。在这种情况下,最好转向自动化流程。

下面详细介绍的方法是:

  • 手动标记一些产品
  • 将产品描述转换成机器可读的数字
  • 建立对标签含义的理解
  • 使用这种一般理解来给产品分配标签

这是监督学习的一个例子,我们提供输入-输出对的例子,模型学习在给定输入的情况下预测输出。

手动标记

第一步是手动标记一些产品。通过首先手动标记活动,我们引入了一些“专家指导”来提高性能。应该选择一组有代表性的产品来为模型提供最多的信息。对于所讨论的技术,我们将在每个类别中只标记 10 种产品。

手动标记也可以使用单词匹配来实现。例如,如果你的产品标签是衬衫,那么衬衫这个词很可能在产品描述中。这种技术在这种情况下工作得很好,但是对于更一般的标签将会失败。

例如,我们可以手动分配产品,如下所示:

34% OFF Robot Restaurant Shinjuku Tokyo Discount E-Tickets (899)
 => Crazy
Studio Ghibli Museum Tickets — Preorder & Last-Minute Tickets (186)
 => Culture
Tokyo Disneyland Tickets — Maihama Station Pickup (10069)
 => Theme Parks
Reservation for Sushi Jiro Roppongi Michelin 2-star Tokyo (1690)
 => Food

给我们一个最终的 JSON 对象,带有标签和产品 id:

{
  "Crazy": [123, 98, 899, etc.],
  "Culture": [186, 1200, 323, etc.],
  ...
}

虽然这些都是由一个人准备的,但至少有三个人来检查每个产品是有帮助的,这是为了消除任何可能存在的偏见。

标签的含义

一旦我们有了一套描述我们产品的标签,我们就需要弄清楚它们到底是什么意思。我们将用机器学习来做这件事。对于理解产品的机器学习算法来说,它需要一种方法来将这些产品简化为数字。在这种情况下,我们将这些数字称为向量,因为我们经常用一组数字来表示乘积。我们将输入模型的典型内容是产品描述或产品图片。对于产品描述,我们有一些技术可供选择,包括:

  • 一袋单词
  • TF-IDF
  • Doc2Vec

Doc2Vec 是一项伟大的技术,使用 Gensim 在 Python 中实现非常容易。这个模型将把产品描述简化为一个向量,其中有一定数量的数据点代表产品的质量。这些都是未知的,但往往可以看到与特定的质量,如颜色,形状,大小或在我们的情况下,标签或类别,我们正在使用。

from gensim.models.doc2vec import Doc2Vec# Create a model with some pre-defined parameters.
model = Doc2Vec(vector_size=50, min_count=2, epochs=40)# Build the vocabulary from some training data.
model.build_vocab(train_corpus)# Train the model.
model.train(train_corpus, total_examples=model.corpus_count, epochs=model.epochs)

在产品图像的情况下,可以应用图像识别技术。例如,根据每个像素的颜色将图像转换为数据,然后训练神经网络来预测某个图像属于哪个标签(类别)。这些模型可以与下面讨论的产品描述模型相结合。

随着产品描述被简化为向量,我们可以思考某个标签的定义意味着什么。对于独立标签(一个产品属于一个标签,但不属于另一个标签)来说,一种简单的方法是对具有某个标签的产品取向量的平均值。结果是一个向量,它表示该标签的平均乘积。

下面的图表显示了一些产品标签的示例。我们看到类似的标签,如庆典和 Instagrammable(中左)是如此相似,以至于几乎完全重叠。我们可能要重新考虑这些标签,因为它们太相似了。“疯狂”这个标签与其他标签明显不同,这是有道理的,这些产品一定非常独特!

The vertical and horizontal axis represent some underlying meaning, such that the tags closer together are most similar.

分配标签

现在我们有了平均产品,我们可以通过找到任何附近的向量来找到应该被相应标记的产品。如果一个向量在附近,它应该是相似的。我们可以限制距离,以确保我们只捕捉与相关标签足够相似的产品。这个距离可以被称为相似性度量。

在这一点上,绘制产品与标签相似性的直方图有助于了解什么是好的分界点。你要确保你标记了大量的活动,但不是每个产品都有特定的标签!

在下面显示的四个示例中,我们有:

  • 自然:很多产品与这个标签不相关,峰值在 0.1 左右的相似度,然后自然相关产品稳步下降。
  • 松弛:与自然相反,似乎有一个次高峰,许多产品的相似度在 0.4 左右。我们希望有一个比这更高的截止值,以避免捕获所有这些产品,这些产品必须有一些相似的方面,但并不完全相关。
  • 食物:与张弛相似,我们可以看到第二个峰值,但这次相似度要高得多,在 0.6 左右。
  • 主题 公园:在 0.5 之后的最右边有一个清晰的平台,因为我们看到相似性下降得相当快。这可能是因为主题公园的标签很简单,意思是某样东西可以很容易地被说成是主题公园或者不是。对比一下之前的一些标签,比如放松。

我们可以选择 0.6 作为一个分界点,以平衡好的含义,但不要有太多的产品标签。从图表中可以看出,这并不完美,我们应该能够做得更好。

Product similarities for different tags. The height of each column represents the number of products that have a certain range of similarity. Similarity of 0 means the products are completely unrelated, -1 means the products are actively different and 1 means the products are very similar. A solid line is shown at 0.6 representing a potential cutoff point for tagging.

验证标签

一旦准备好标签,下一步就是验证它们是否有意义。最简单的方法是浏览每个标签下的随机产品列表,并检查它们是否有意义。最终,这取决于用户如何回应你的标签。在线测试你的标签并观察用户如何与之互动是很有用的。他们在用标签研究产品吗?在这一点上,他们是否从标签或落客处查看许多产品?

后续步骤

在本文中,我们使用基本的数据处理和机器学习技术创建了一个标签产品列表。有了这些技术,就有可能快速建立并运行一个质量良好的标签系统。

我们有各种方法可以改进我们的方法。我们可以应用机器学习算法,如支持向量机(SVM)或多项式朴素贝叶斯,学习以更复杂的方式预测标签,而不是选择离我们的标签最近的产品。对于这些模型,需要更多的训练数据,但作为回报,我们将拥有更大的预测能力。

如何为放射学人工智能创建高质量的带注释的训练数据?

原文:https://towardsdatascience.com/creating-high-quality-annotated-training-data-for-radiology-ai-d23ca4b85f00?source=collection_archive---------22-----------------------

使用神经网络的深度学习有可能对放射学的医学成像产生非常高的生产力提升影响。虽然人工智能可能永远不会取代放射科医生,但人工智能将有助于以一种非常深刻的方式提高放射科医生的生产力。

四种类型的组织参与在放射学中实现人工智能:

  1. 通用电气、飞利浦、西门子、Nuance technologies、Teracon 等现有公司正在建立市场,以分发来自不止一家供应商的人工智能算法。
  2. 人工智能初创公司正在建立深度学习算法,以将人工智能商业化用于放射学。
  3. 像英伟达这样的 GPU 公司正在通过免费的软件开发工具包加速人工智能的开发,这使得所有其他玩家都可以使用他们的 GPU 硬件和 GPU 云。
  4. 像斯坦福机器学习小组、俄亥俄州立大学医学院和梅奥诊所放射科这样的研究小组正在给放射学人工智能带来最新的研究。

在医学成像领域,人工智能面临着一些重大挑战:

  1. 放射学成像数据通常包含个人健康信息(PHI)。它要求遵守严格的法规和 HIPAA 合规法律。这里有一些指导方针用于指导 HIPAA 合规性下的 PHI 构成,以及保护 PHI 的常见策略。
  2. 由于数据的敏感性,数据需要存放在本地网络或 VPN 控制的网络中。

解决办法

人们普遍需要可扩展的数据管理基础设施。为了帮助这一努力,TrainingData.io 创建了一套工具,以帮助数据科学团队为放射学人工智能创建和管理大量训练数据。

一个好的培训数据管理平台是由什么组成的?

在 TrainingData.io,我们构建了世界上第一个注释工具,能够为 DICOM 格式的放射学图像创建像素精确的注释,如下图所示:

1.标签工具中的本地 Dicom 支持

Dicom 图像格式实际上是来自不同供应商的所有放射设备的标准。Dicom 数据损失少,信息丰富。它允许放射科医生查看捕捉到的图像中的细节。Web 浏览器不像支持 Png 和 Jpeg 那样支持 dicom 解码。标签工具需要支持 dicom 数据格式,具有窗口级预设、多平面视图等功能。

2.像素精确的注释工具

在 TrainingData.io,我们建立了世界上第一个注释工具,能够为 DICOM 格式的放射学图像创建像素精确的注释,如下图所示

3.网络浏览器中 MRI / CT / DICOM / NIFTI 的三维分割

放射学数据集有两种主要的文件格式 a) DICOM 和 b) NIFTI。一些 MRI / CT 研究包括成千上万的图像(切片)。很难单独注释每个切片。3D 可视化对于加速为大型数据集创建注释的过程非常重要。

3D-Segmentation in Web Browser

4.模型辅助注释

英伟达克拉拉:

NVIDIA Clara Model Training Framework

为了生成任何新数据集的自动分割, TrainingData.io 已经建立了一个用户界面,如下面的视频所示:

NVIDIA Clara web server 以虚拟化服务的形式提供了与 TensorRT 的接口,可以接收 DICOM 格式或 nifti 格式的数据,并返回注释的结果。

5.注释者的绩效管理

测量、记录和分析注释者在每个任务、资产和标签上的表现。比较多个注释者在同一任务上的表现。在多个贴标机之间分配贴标工作,并观察他们工作中的共识。黄金数据集的种子注释任务。报告注释器在黄金数据集上的性能。

Quality Management Workflow

6.标签说明管理

为了将标注任务交给自由注释者,数据科学团队需要定义标注任务的规范。这些规范需要转化为用户体验。在 TrainingData.io 应用规范生成器中称为标注指令。标签指令是数据科学家希望人类标签员在图像中找到的对象列表。对象可以有颜色、大小、形状等属性。Data-scientist 希望将这些属性以问答的 HTML 形式呈现给注释者。

Labeling Instruction Builder at TrainingData.io

7.数据安全和隐私:内部隐私保护托管

为了支持严格的安全要求,TrainingData.io 建立了一个混合工作流,其中成像训练数据和注释工具作为 Docker 映像在防火墙网络内运行。带有数据集管理的质量控制工作流托管在云中。这使得数据科学家可以与全球员工一起管理注释工作流,同时保证他们自己网络内的数据安全。

On-Premises Hosting with Docker Containers

这个故事最初发表在 TrainingData.io 博客上。

创建机器学习模型

原文:https://towardsdatascience.com/creating-machine-learning-models-b48bb72a791f?source=collection_archive---------22-----------------------

使用、测试和比较多种机器学习模型

Source: Pixabay

现在,我们已经成功地完成了每个数据科学项目中最困难的部分——数据清理和争论,我们将进入有趣的部分,建模!

虽然本文可以自成体系,但最好先经过 第 1 部分第 2 部分

机器学习中的建模是一个迭代阶段,在这个阶段,数据科学家不断地训练和测试机器学习模型,以发现最适合给定任务的模型。

存在不同的机器学习模型,选择使用哪一个通常取决于手头的问题。没有机器学习模型对所有类型的问题都是最好的。因此,在这个阶段,您的工作是测试多个模型并微调参数,以挤出每一点准确性。

:虽然我们通常追求性能更高的模型,但通常更明智、更好的选择是性能几乎和复杂模型一样好的更简单的模型。

为您的机器学习竞赛节省 .0001 增加的性能,因为在现实世界的大部分时间里,这些微小的差异并不重要,因为我们需要更简单的可解释模型。

有鉴于此,我们开始工作吧。从一个简单的基础模型开始总是好的,这样你就可以得到一个基线来衡量性能。

由于我们的数据集很小,我们将使用交叉验证,对于性能指标,我们将使用平均绝对误差。交叉验证有助于衡量我们模型的真实性能。

我们创建了一个交叉验证函数,如下所示。

对于回归任务,从简单的线性回归开始

我们从简单的线性回归开始建模,交叉验证并打印分数。

我们能调谐什么

线性回归很简单,因此没有太多要调整的参数。所以我们只需使用默认参数。

MAE Sccore:  0.42615411746170206

使用决策树

接下来,我们使用另一种简单但有效的算法,称为决策树

我们能调谐什么

决策树包含许多超参数,但我们可以快速调整的最重要的超参数是:

  1. 最大深度:最大深度参数表示树的深度。树越深,模型就越复杂,它就能获取更多关于数据的信息。如果您的模型太简单,请尝试增加 max_depth,反之亦然。
  2. min_samples_leaf :这是一个叶节点所需的最小样本数。较高的叶片数导致更简单的模型,并可能有助于过拟合,而较小的叶片数可能导致欠拟合。
  3. min_samples_split: 这是分割内部节点所需的最小样本数。该参数增加导致更简单/受约束的模型。
  4. max_features :这是模型在分割一个节点之前考虑的特征数量。
MAE Sccore:  0.4280371717119684

使用 K-最近邻

接下来,我们尝试一种流行的基于距离的算法,称为 k-最近邻算法

我们能调什么

KNN 包含几个超参数。最重要的一项调整是:

  1. n_neighbors :这是投票时使用的邻居数量。数字越大,它就越精确(有时是这样),但代价是速度。
**MAE Sccore:  0.431624658307474**

查看简单模型的 MAE(平均绝对误差)分数,我们看到决策树是迄今为止最好的。这将是我们的基本模型。任何表现更好的模型都将成为下一个要超越的底线。

现在,我们将从简单模型转向高级模型。许多高性能的机器学习模型通常基于集成。集成是一种结合多种机器学习算法的方法,以获得比任何单一算法都更好的预测性能。

下面我们将使用一些流行的合奏方法并比较它们的性能。

打包算法

随机森林

随机森林算法是 bagging 的一种流行而有效的实现,它从一个引导样本构建多棵树。它有很高的预测能力,开箱即用。

我们能调什么

随机森林包含许多超参数,但最重要的优化参数是:

  1. n_estimators :这是要创建的决策树的数量。正如我们可能猜测的那样,更多的树会产生更好的模型,但代价是更长的训练时间。
  2. 最大深度:这是单棵树的最大深度。数字越大,树越简单,因此随机森林集合也越简单。
  3. max_features: 定义了允许分割的最大特征数。
  4. min_samples_split: 这是分割前叶节点所需的最小样本数。
MAE Sccore:  0.41512597643232896

额外的树

额外树算法是 bagging 的另一个流行的实现,它类似于随机森林,但构建其基础树的方式不同,并且通常更快。它还具有很高的预测能力,有时甚至超过随机森林。

我们能调什么

额外的树包含与随机森林相似的超参数。要调整的重要参数有:

  1. n_estimators :这是要创建的决策树的数量。正如我们可能猜测的那样,更多的树会产生更好的模型,但代价是更长的训练时间。
  2. 最大深度:这是单棵树的最大深度。数字越大,树越简单,因此随机森林集合也越简单。
  3. max_features: 定义了允许分割的最大特征数。
  4. min_samples_split: 这是分割前叶节点所需的最小样本数。
MAE Sccore:  0.4131678014407999

BAGGING 元估计量

sklearn 中的 bagging 估计器允许您从任何选择的模型中创建 Bagging 系综。也就是说,你可以从线性回归这样的单一模型中创建 bagging 系综,甚至是像随机森林或额外树这样的系综。

我们能调什么

这里要调整的重要超参数是:

  1. base_estimator: 这是在执行装袋时使用的估计值。bagging 元估计器从指定的基本估计器构建多个模型。
  2. n_estimators :这是要创建的基本估计数。较高数量的估计器将导致更好的模型,但是也以更长的训练时间为代价。
  3. max_samples :指定训练每个基本估计器的最大样本数。
  4. max_features :这是训练每个基本估计器时从数据集中提取的最大特征数
MAE Sccore:  0.4045400489482442

从误差指标来看,我们的下一个最佳模型是 bagging 回归器,它基于额外的树回归器。这成为我们新的基线模型。

接下来,我们来尝试一些 boosting 算法。

助推算法

Boosting 是另一种流行且有效的集合技术。在 Boosting 中,多个模型被顺序训练。目标是训练比他们的前辈做得更好的模型。这意味着我们必须考虑以前的模型表现不佳的领域,并在这些领域进行改进。

adaboost 算法

我们从称为 AdaBoost 的升压的普通实现开始。这是一种古老但广泛使用的 boosting 技术,在回归任务中表现良好,尽管众所周知它会过度拟合。

我们能调什么

这里要调整的重要超参数是:

  1. n_estimators :这是要使用的基本估计数。通常,值越高,性能越好。
  2. learning_rate :该参数控制训练权重的更新。它通常与 n 估计器一起调整。一个流行的经验法则是“当你将 n_estimator 增加 10 倍时,你也将学习速率降低 10 倍。
  3. base_estimator :指定要提升的基本模型。
  4. max_depth :指定基本估计值的深度。
MAE Sccore:  0.4243339946387083

梯度推进

另一种流行的提升算法是梯度提升。

我们能调什么

这里要调整的重要超参数是:

  1. n_estimators :这是要使用的基本估值器的数量。通常,值越高,性能越好。
  2. max_depth :指定基本估算器的深度。
  3. min_samples_split :指定分割一个内部节点所需的最小样本数。
  4. max_features :训练每个基本估计器时从数据集中提取的最大特征数
MAE Sccore:  0.4063934439500354

XGBOOST

“当有疑问时,使用 XGBoost”是近年来 kaggle 平台上最流行的名言之一。

XGBoost 高效、快速,开箱即用。这是梯度增强的高级实现,确实非常有效。

我们能调什么

这里要调整的重要超参数是:

  1. eta :只是学习率的不同叫法。它有助于模型权重更新。
  2. min_child_weight:这个指定一个子节点中所需的所有特性的最小权重和。它主要用于控制过度拟合。
  3. max_depth: 该用于定义每个树节点的最大深度。深度越大,模型越复杂,反之亦然。
  4. max_leaf_nodes: 指定一棵树的最大叶子数。
  5. Gamma:Gamma 值指定进行分割所需的最小损失减少量。只有当产生的分裂给出损失函数的正减少时,节点才被分裂。这些值可能因损失函数而异,应该进行调整。
  6. 子样本:指定为每棵树随机选择的特征部分。较低的值使算法更简单,并防止过度拟合。
MAE Sccore:  0.4099352064907469

LIGHTGBM

LightGBM 是微软的 boosting 算法。这是最快的助推算法之一;高效的开箱即用,目前是大型结构化数据的首选。

我们能调什么

这里要调整的重要超参数是:

  1. num_iterations :指定要执行的增强迭代次数。
  2. 叶子数量:指定一棵树要形成的叶子数量。注意 : 在轻型 GBM 中,由于分裂发生在叶方向而不是深度方向,因此 num_leaves 必须小于 2^(max_depth,否则可能导致过拟合。
  3. min_data_in_leaf :它是处理过拟合最重要的参数之一。
  4. max_depth :指定一棵树可以生长的最大深度。此参数的值非常高会导致过度拟合。
  5. bagging_fraction :用于指定每次迭代使用的数据的分数。该参数通常用于加速训练。
MAE Sccore:  0.4084352064907469

CATBOOST

Catboost 是最近出现的 boosting 算法。它快速、高效且容易处理分类特征(它最好的特征之一)。

CatBoost 可以自动处理分类变量,不需要像其他机器学习算法那样进行大量的数据预处理

我们能调什么

这里要调整的重要超参数是:

  1. loss_function: 指定用于训练的度量。
  2. 迭代次数:可以构建的最大树数。
  3. learning_rate: 指定用于减少梯度步长的学习率。
  4. 深度:指定要创建的树的深度。
MAE Score: 0.4123613834195344

最终想法

在这篇文章中,我们学习了如何获取预处理过的数据集,并尝试不同的机器学习模型。虽然本文基于回归任务,但是同样的步骤也可以应用于分类任务。这篇文章的一些要点是:

  1. 选择一个好的验证策略。(小型数据集的交叉验证,大型数据集的拆分)
  2. 从简单开始,得到一个基线模型。
  3. 通过调整和测量性能来不断改进模型。

手动调整最佳模型后,更高级的技术是使用自动超参数搜索算法,如网格或随机搜索。

记住,尽可能让你的模型简单易懂。

如果你从这一系列的帖子中学到了什么,别忘了鼓掌和分享。

在 GitHub 上链接到带有代码和解释的完整笔记本。

Twitter 上和我联系。

LinkedIn 上与我联系。

用蟒蛇和熊猫创造我自己的“蒙佐年”

原文:https://towardsdatascience.com/creating-my-own-year-in-monzo-using-python-pandas-e866a17c3509?source=collection_archive---------37-----------------------

深入分析

拥有 Monzo 账户的 nyone 只需简单调用一个 API 就能访问他们的全部交易历史。交易历史数据集非常丰富,可以为您的消费习惯提供独特的见解,对于任何学习数据科学和分析的人来说都是一个很好的资源。在本文中,我将探索一些我自己的消费习惯统计数据,并向您展示如何使用一些基本的 Python 编程来做同样的事情。

数据科学工具包

在开始分析之前,先简单介绍一下我将使用的工具:

  • jupyter Notebook——一个在线笔记本,它使运行代码和探索数据比在一个大脚本中编写更容易。
  • python——一种具有许多自定义数据科学库的通用编程语言。
  • Pandas——最强大、应用最广泛的数据科学与分析库。

我已经在我的 GitHub 中嵌入了作为这个分析的一部分而编写的所有代码。

加载并清理数据

首先,你需要将数据放入你的 Jupyter 笔记本,并以一种更友好的方式格式化,这可以通过 7 个步骤实现:

  1. 登录 Monzo for Developers 门户,并遵循 API 文档中的认证指南来访问您的数据。
  2. 通过在本地机器上请求 JSON 形式的“事务列表”来点击 API,并将其保存为 JSON 文件。重要提示:在您必须请求另一个访问令牌之前,您只有 5 分钟的时间来完成此操作,因此请在您访问门户时尽快完成。
  3. 在 Jupyter 笔记本中,导入 pandas 和 matplotlib(用于创建图表的库),然后将 JSON 数据文件加载到 dataframe 中。

4.扁平化数据框架,使数据分析更容易。

5.将列中的事务“created”转换为 datetime 序列,并将其设置为 dataframe 的索引。

6.将交易金额从便士转换为英镑,并强制正金额与购买相对应。这是通过对列应用 lambda 函数来实现的。

7.过滤数据框架,排除内部“现金”转账,因为我们只对实际支出感兴趣。

每个事务都存储为一个 JSON 对象(见下面的例子),并包含许多键值对,我们稍后将使用它们来提取一些有趣的见解。

{
  "id": "tx_00009T3RKKR0B36laVzJh4",
  "created": "2018-01-28T12:33:46.54Z",
  "description": "TfL Travel Charge      TFL.gov.uk/CP GBR",
  "amount": -450,
  "fees": {},
  "currency": "GBP",
  "merchant": {
    "id": "merch_000092jBCaq2cHlL8pLVkP",
    "group_id": "grp_000092JYbUJtEgP9xND1Iv",
    "created": "2015-12-03T01:24:14.372Z",
    "name": "Transport for London",
    "logo": "https://mondo-logo-cache.appspot.com/twitter/@TfL/?size=large",
    "emoji": "🚇",
    "category": "transport",
    "online": true,
    "atm": false,
    "address": {
      "short_formatted": "The United Kingdom",
      "formatted": "United Kingdom",
      "address": "",
      "city": "",
      "region": "",
      "country": "GBR",
      "postcode": "",
      "latitude": 51.49749604049592,
      "longitude": -0.13546890740963136,
      "zoom_level": 17,
      "approximate": false
    },

探索性数据分析(EDA):交易金额

现在,数据作为数据帧加载到笔记本电脑中,我们可以开始进行一些探索性的数据分析(EDA)。EDA 有助于生成一些基本的数据统计摘要,并且是让自己熟悉新数据集的好方法。

我想知道关于我的数据集中 2,464 个正交易的交易金额( )的一些统计数据。(请记住,在第 6 步中,我强制正值表示购买,负值表示付款或退款。)

我过滤金额为正数的交易,并将它们分配到一个新的数据框trans_pos_amount:

trans_pos_amount = trans[trans['amount'] > 0]

然后使用内置的 Pandas 方法.describe()在新数据帧的金额列上获得 2018、2019 和 2018–2019(合并)的交易汇总统计数据:

trans_pos_amount.loc['2018'].amount.describe()
trans_pos_amount.loc['2019'].amount.describe()
trans_pos_amount.amount.describe()

生成的 3 个汇总表返回一些标准统计数据,包括平均值、中值、标准差、四分位距和最大值:

考虑到整个数据集(2018 年至 2019 年),似乎我每笔交易的平均支出金额为 14.50,标准差为 44.50。这表明我的支出有很大程度的可变性,这是有道理的,因为我使用 Monzo 进行日常生活,如旅行和食物,但也支付大额项目,如账单,这通常是更大的交易金额。

有趣的是,我每笔交易的平均消费金额是 2.60 英镑,几乎等同于一杯咖啡的价格(在伦敦)。稍后,我将探索哪些是我最常去的商店,看看咖啡是否真的会影响中值交易额。但是,现在很清楚的是,我用我的 Monzo 账户进行许多小交易。

还可以使用 matplotlib 库来可视化这些统计数据。可视化形式的 EDA 通常比数字形式的 EDA 更容易理解。使用.plot()方法可从trans_pos_amount数据帧中获得直方图和箱线图:

#plot a histogram and boxplot side by side
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(10,5))
trans_pos_amount.plot(kind='hist', bins=600, grid=False, edgecolor = 'black', ax=ax1)
trans_pos_amount.plot(kind='box', ax=ax2)

Histogram (left) and boxplot (right) of my transaction amounts over 2018 & 2019

正如数字数据所暗示的,我们可以看到,我的大多数交易通常金额较小,但少数大额交易会使整体平均交易金额偏高。

探索性数据分析(EDA):消费类别&商户

通过了解我的消费习惯,我知道我可以在哪里改变我的生活方式,这样从长远来看我可以节省更多的钱。使用 Monzo 数据集的一种方法是按类别过滤我的交易,例如账单、外出就餐和交通。虽然我可能无法显著改变我在必要支出(如账单和交通)上的花费,但我可以调整可自由支配的支出,如外出就餐、购物和度假。

Pandas 中非常方便的.groupby()方法可用于按类别对交易进行分组。然后很简单地按该类别的总支出来绘制分组数据:

#plot the amount spent in each category over 2018 & 2019
trans_pos_amount.groupby('category').amount.sum().sort_values().plot(kind='barh')

Total amount spent by category over 2018 & 2019

正如我预料的那样,我花在账单上的钱最多,包括房租、电话费、市政税(你知道,所有无聊的成人用品)。让我感到惊讶和尴尬的是,外出就餐是我的第二大支出类别,在两年时间里高达 6700 英镑。外出就餐肯定是可自由选择的一类,因此,我可以减少下班后外出就餐和喝酒的次数。

通过调查我与哪些商家交易最多,我可以更深入地了解我的消费习惯。在可能的情况下,Monzo 会向我们提供详细的商家信息,包括名称、位置和社交媒体信息。我只对merchant_name字段感兴趣,它可以从 dataframe 中访问。我创建了一个名为merch_freq的新数据框架,并使用.value_counts()方法产生一个按交易数量排序的商家列表(调用.head()返回最后的前 5 个值):

merch_freq = trans['merchant_name'].value_counts()
merch_freq .head()

Top 5 merchants by number of transactions

直观地看这些信息会更容易理解,但我只想包括我的前 10 名商户,所以我在数据帧上使用了.nlargest()方法,然后按照频率顺序绘制出我的前 10 名商户:

merch_freq.nlargest(10).sort_values().plot(kind='barh')

Top 10 merchants by number of transactions

注意:出于保密原因,我编辑了其中一个商家的名字

从这张图表中可以清楚地看出,我的前 10 名商户中有一半可以归为“外出就餐”一类。毫不奇怪,我最受欢迎的商家是伦敦交通局,因为我几乎每天都用我的 Monzo 进出 TfL 网络。

早些时候,我质疑我的平均消费金额 2.60 英镑(相当于伦敦一杯咖啡的价格)能否用我去咖啡店的次数来解释。事实上,从图表上看,有两家咖啡店(Boulangerie Jade & Pret A Manger)创下了令人震惊的 392 笔交易。我的交易中大约有 16%涉及咖啡!我认为假设我的咖啡瘾确实影响了我每笔交易的平均花费是公平的。

虽然我有 10 个最频繁交易的商家,但我想知道当我检查哪些商家我花了最多的钱时,列表是否会有很大变化?为了研究这一点,我创建了一个名为merch_amount的新数据帧,并再次使用.groupby()方法,这次按merchant_name字段分组。我计算了每个商家的总消费金额,然后首先按最大金额对数据框进行排序:

merch_amount = trans.groupby(trans['merchant_name'], sort=True).sum().sort_values('amount', ascending=False)

之后,创建一个情节就很简单了:

merch_amount['amount'].nlargest(10).sort_values().plot(kind='barh')

Top 10 merchants by amount spent

幸运的是,在我的金额排名前 10 名中,我看到了更多与账单和费用相关的商家。然而,令人失望的是,我无法使用这个数据集透露更多关于我的美国运通交易的信息。我使用我 Monzo 帐户来支付我的美国运通,因此关于这些交易的任何信息基本上都落入了黑洞(尽管我可以利用他们的 API 来获取数据)。

我还没探索完我的咖啡假说。当我合计在 Boulangerie Jade 和 Pret A Manger 的消费总额时,我发现两年多来我在咖啡因上浪费了 1037 英镑。分布在总共 392 个事务上,得出的平均值为 2.62,这几乎等于我在整个数据集上的中值事务量。

对比我的 2018 年和 2019 年

最后,我想检查一下我对 Monzo 的使用在 2018 年和 2019 年之间发生了什么变化,并潜在地看看未来是否有我可以预期的特别昂贵的月份。我在这里的目标是创建一个条形图,比较 2018 年和 2019 年之间每月的支出总额。

在开始清理数据时,我确保用日期时间标记索引每个事务。这一步现在将开始得到回报,因为我可以更容易地过滤数据,并使用.resample()方法按月对每笔交易进行分组。

首先,我按年份过滤trans_pos_amount数据帧,然后在新的df_2018数据帧上使用.resample().sum()方法:

df_2018 = trans_pos_amount.loc['2018']
df_2018_monthly_resample = df_2018.resample('M').sum()

本质上,通过重采样然后求和,我得到了一个月内的所有交易(当我将‘M’解析到方法中时指定),并将它们组合成一个数字。

Re-sampling allows me to group transactions by month

df_2018_monthly_resample数据框包含 2018 年每个月花费的总额。但是,这个数据帧的索引不是我想要的。数据帧不是被索引为有序的月份列表,例如“一月”、“二月”、“三月”,而是被索引为日期时间戳,例如“2018–01–31 00:00:00+00:00”。不要担心,只要新索引的长度与数据帧的长度匹配,我可以将数据帧的索引设置为我想要的任何值。我简单地创建了一个月份列表(labels_2018labels_2019),然后将该列表解析为set.index()方法:

df_2018_new_index = df_2018_monthly_resample.set_index([labels_2018])df_2019_new_index = df_2019_monthly_resample.set_index([labels_2019])

现在,我可以将新索引的 2018 年和 2019 年数据帧合并为一个,方法是创建一个新的数据帧,并使用键值对将年份与其各自的数据帧进行匹配:

df_2018_vs_2019 = pd.DataFrame({'2018':df_2018_new_index.amount, '2019':df_2019_new_index.amount}, index=labels_2018)

现在有了一个整洁的数据框架,我可以绘制数据来实现我的目标:

df_2018_vs_2019.plot(kind='bar')

Comparing 2018 and 2019 spending amounts

从图表中可以明确的是,2019 年我对 Monzo 的使用量远远高于 2018 年。这可能有两个原因:1 .我花了一些时间才把 Monzo 作为我的主要银行。2.我在 2019 年赚了更多的钱,这可能会反映在我花费的金额上。

就月度趋势而言,随着夏季(5 月至 9 月)的临近,2019 年的趋势肯定会有所上升,但随着我们进入冬季,这一趋势似乎会有所下降。这是合乎逻辑的,因为夏天有更长的白天,并且提供了更多的机会去做我根据我的数据最常做的事情:出去吃和喝!

最终外卖

在这个小项目开始时,我对如何花钱有一个粗略的想法,但现在我有了一些真正的见解。很明显,我需要减少我在外面吃饭和喝酒的习惯,但我也可能会寻找更具成本效益的方式在伦敦四处游览。伦敦的交通对我来说是一个巨大的支出,所以使用城市地图绘制者通行证或简单地获得月票可能是有益的。

Monzo 提供了一个非常干净和可访问的数据集,可以用来做比简单的 EDA 复杂得多的事情。在一个这样的示例中,商家位置信息用于创建吸引人的交易地图。虽然这些地图很吸引人,但也可以用来帮助用户识别欺诈活动,因为用户更有可能以这种新颖的格式与他们的数据进行交互。

事实上,这个数据集的潜在用例是无限的,这是为什么开放银行的黎明将为初创公司和现有金融服务提供商提供新的有价值的想法的一个例子。

自己试一试

我强烈推荐使用数据营来提升自己在数据科学和分析方面的技能。通过跟随他们的视频,然后用他们的指导教程练习,我在几周的时间里从一个初学者变成了分析真实世界数据的人。

提醒:链接到对您自己的数据进行分析所需的代码。

使用 Google 云平台创建 MySQL 实例

原文:https://towardsdatascience.com/creating-mysql-instance-using-google-cloud-platform-353c36803cee?source=collection_archive---------13-----------------------

在谷歌云中创建和管理 MySQL 数据库。

在本文中,我们将总结如何使用 Google Cloud Platform 创建 MySQL 数据库实例,从 Google 的 cloud shell 连接到创建的实例以测试它,然后在我们的本地机器上使用 MySQL workbench 连接到同一个实例。有很多方法可以在云中的数据库中工作,类似于微软 Azure 或 AWS。在这种情况下,我们将专注于基本的 Google 云平台,不包括高级配置选项。

1-前往https://cloud.google.com/,创建一个免费试用的谷歌云平台账户。这将给予 12 个月或 300 美元的免费积分(以先到者为准)

2-去 https://cloud.google.com/的然后去你的控制台。

3-转到 SQL 仪表板部分,并选择创建实例。

4-选择选择第二代(推荐)

5-创建实例 id 和 root 密码。

6-选择创建。这将需要一些时间,但在谷歌云平台中创建 MYSQL 实例。

8-完成后,实例 ID 旁边会有一个复选标记。

9-单击创建的 MSQL 实例。

10-记下服务器 IP 地址并使用云外壳进行连接。将客户端 IP 地址列入白名单需要一些时间。

11-云壳会提示你输入密码。输入密码后,实例连接将完成。我们可以进一步执行 SQL 语句,并通过云外壳访问 MYSQL 实例。

12-去 google.com 并获得公共 IP 地址。

13-转到实例详细信息/连接,添加一个网络,并在网络名称下添加此 IP 地址,然后单击保存。

14-转到本地机器上的 MYSQL workbench。

15-创建新连接。

16-添加连接名称。

17-使用步骤 10 中记录的服务器 IP 地址更新主机名。

18-创建用户名和最佳实践来创建非 root 密码。

19-保留默认模式。

20-测试连接将提示您输入密码。输入您的实例密码。

21-成功地建立了 MySQL 连接。单击确定。

22-Google 云平台 MYSQL 创建并连接到本地 MySQL workbench。

这个过程非常简单易懂。我们可以进一步创建关系数据库和表,使用 GCP 实例从本地 MySQL 工作台执行查询。我们还可以将数据库中创建的任何表加载到我们的本地 R 或 Python 中,并执行分析。

使用 NLP 创建新的复合生物砖

原文:https://towardsdatascience.com/creating-new-composite-biobricks-using-nlp-812126992a94?source=collection_archive---------29-----------------------

结合合成生物学和人工智能

生物砖是合成生物学中用于创造新的复合结构的基本单元。他们首先提取 DNA 的基本核苷酸:A、T、G 和 C,然后从中形成一种具有特定功能的合成蛋白质。例如,如果我想让我的蛋白质负责让一个细胞发绿光,我会创建一个编码这一特性的序列(或者通过提取让水母发光的蛋白质序列来模仿它)。

An example of a bio brick structure. Source: http://2016.igem.org/wiki/images/6/6f/T--Minnesota--diagram3.png

然后,我会根据细胞成功产生这些蛋白质的需要,通过添加更多的结构来优化它,如 RBS(核糖体结合位点)。当提到生物砖时,经常会用乐高积木来类比,因为用来制造蛋白质的结构是“堆叠”的。

生物砖不仅仅具有制造蛋白质的能力,而且整个系统都依赖于所制造的复合蛋白质的功能。

生物砖之所以备受争议,是因为理论上任何蛋白质都可以由计算机制造出来。这一点的影响是巨大的,因为它们在未来也可以应用于人类细胞,这意味着如果我们继续追求这一知识,改变人类基因组以获得我们想要的特征可以比仅仅使用 CRISPR 技术(简单的基因编辑)更快地成为现实。

然而,目前为了获得结果,通常将生物砖部分注入空的细菌细胞,主要是大肠杆菌细胞中进行观察。但是生物砖也有非常有用的积极意义。例如,使用生物砖,我们可以创造自己的蛋白质,产生人类兼容的胰岛素,这表明没有必要再从其他动物中提取胰岛素并将其转化为可用的蛋白质。

缩短开发人类兼容胰岛素的过程将对糖尿病患者极为有益,因为药物将变得更便宜、更容易获得,更不用说所有其他需要蛋白质来缓解症状的疾病了。

但是我们如何从单一的生物砖部件发展到在细菌中培养胰岛素工厂呢?例如,我们如何有效地利用这些部分来生产更多的复合蛋白质,比如更理想的胰岛素分子?换句话说,在 syn bio 领域有这么多机会,我们从哪里开始呢?

我如何利用人工智能和合成生物

通过 spaCy + NLTK 库使用自然语言处理(NLP ),我能够操纵 BioBrick 部件数据库来产生各种全新的复合蛋白质。

通过提供复合结构各部分的顺序,而不是各部分的具体名称,我的应用程序生成了一个复合砖块,可以用于所需的功能。例如,如果我想制造一个发绿色光的完整蛋白质,并且与细菌细胞相容,我会输入对启动子、RBS、GFP 基因(发绿色荧光)等的要求。

结果是:

起初有许多无意义的核苷酸模式,但当仔细汇编和分析时,你会发现这正是我们所需要的。

它是如何工作的

我的程序通过匹配 DNA 的粘性末端来优化复合蛋白质的最佳结果,这种排列包含在细菌中成功实现的最高机会。使用 NLP 是这个过程不可或缺的一部分,因为它允许您指定在新零件中包含哪些而不是

例如,通过向程序投掷随机单词,它将输出一个随机部分,该随机部分有机会与其他部分匹配,但不是很高。但是,如果您指定了哪些零件可以挑选,哪些不可以挑选的条件,您就大大增加了零件装配在一起并按预期运行的机会。

NLTK 和 spaCy 库非常适合这种情况,因为它们使 NLP 处理变得非常简单。基于这些输入,你现在可以处理与单词相关的否定,某些蛋白质的形容词,等等。

BioBrick 零件数据库包括约 500,000 行测序零件,其中包含每个类别的绝大多数选项。程序创建的每一个新部分都试图根据规范包含启动子、RBS、报告子、终止子等。

该程序还包括使用一个简单的分类器来分类哪些砖块最适合哪些砖块。这个项目中人工智能的另一个相对简单的应用表明,从简单的输入和过程中创造出复杂的输出是多么容易。

未来应用

更多的想法可以从这个中产生。另一个 AI + syn bio 项目的一个例子可能是使用 GANs 生成新的部分,类似于科学家使用相同技术开发新药的方式。

砖块也可以用人工智能来测试。ML 具有从任何数据中学习的潜力,这意味着如果它在成功的复合砖块的要求中找到模式并不断地从它们中学习,那么它就具有测试未来砖块所需的准确性。这将非常有帮助,因为中间的所有处理工作都可以被消除,从而产生一个更高效的系统。

我们试验的部分越多,我们就越能理解人工智能和 syn bio 能走多远。通过将 ML 与任何科学相结合,我们可以有效地加速理解当前未知事物的过程,并开发应用程序来帮助我们作为一个社会成长。

使用 StyleGAN 创建新脚本

原文:https://towardsdatascience.com/creating-new-scripts-with-stylegan-c16473a50fd0?source=collection_archive---------8-----------------------

我将 StyleGAN 应用于 Unicode 字符的图像,看看它是否能发明新的字符。我发现了一些有趣的结果:

New characters generated by StyleGAN from Unicode

世界的剧本

世界上的语言使用大约 400 种不同的书写系统。这包括今天使用最广泛的拉丁文字:

Simple Latin Characters

The Unicode Consortium aims to map every character in the world to an underlying number so that they can be easily used across different computer systems. For example, hash “#” is mapped to the number 35, a-acute “á” is 225, and the Chinese character for fog “雾” is mapped to 38,654. The first ~65,000 characters in Unicode cover most scripts in current use and are divided into ~140 blocks, with Simple Latin being one of those blocks. See the Wikipedia Page on Unicode Blocks for the full list.

我在 Unicode 协会工作过一段时间。我被美国语言学会任命为候补委员,关注那些未被充分代表的语言。我着迷于亲眼目睹脚本如何被形式化和编码的过程,以便世界上的每个人都可以利用信息时代,无论他们选择如何交流。我在 Unicode Consortium 的时候,表情符号第一次被添加到 Unicode 中,这可能是他们最有争议的决定。你可以在这里阅读我关于见证表情符号被添加到 Unicode 的文章:

[## 艾萨克·牛顿 vs 数百万日本青少年

medium.com](https://medium.com/@robert.munro/isaac-newton-vs-millions-of-japanese-teens-6d952801f6f2)

最困难的决定之一是在 Unicode 标准中如何命名给定的脚本。按照 Unicode 的定义,简单拉丁语包括常见的标点符号、字符和数字。显然,使用这种文字的语言比拉丁语多,你可以争论标点符号是否是文字的一部分。你指出除了 0 以外的所有数字都来自阿拉伯语也是对的。因此,Unicode 中的“块”试图映射到脚本中有意义的部分,承认边界可能是模糊的,并且脚本通常会有多个可能具有政治含义的名称。因此,这些名称对于 Unicode 中的块来说是方便的简写,但并不打算成为使用该语言的人的主要或唯一的名称。

带着这个警告,这里有一些有趣的 Unicode 脚本,我用它们作为用 StyleGAN 创建新脚本的基础:

Armenian

Arabic

Devanagari

Bengali

Gujarati

Tamil

Kannada

Malayalam

Thai

Hangul Symbols

CJK Compatibility Ideographs (CJK = Chinese Japanese Korean)

我承认在我上面的例子中,我过分强调了南亚的语言。在早起观看印度和巴基斯坦在板球世界杯中的比赛后,我写了这篇文章,所以我强调了他们国家内部的多样性,可能也包括了他们球队内部的多样性。如果你对语言和体育感兴趣,你也应该在这里看到我对足球世界杯球员名字的分析:

[## 世界杯人物

medium.com](https://medium.com/@robert.munro/world-cup-characters-6c8d003b0274)

数据准备

我用 python Pillow 库和 MAC 自带的“Ariel unicode”字体为每个 Unicode 字符生成了一个 JPG 图像。如果你想重新创建这个,让我知道,我会分享我的代码。

更新:代码在这里:【https://github.com/rmunro/unicode_image_generator】T2

我用不同的颜色对每个区块(与一个脚本相关的每个字符范围)中的图像进行编码,这样我就可以很容易地看到最终字符集中的最大影响。上面图像中的颜色反映出:拉丁语是黑色,泰米尔语是亮绿色,等等。

最初,这产生了大约 40,000 张图像。这是 65,000 个字符中有多少经过 Ariel Unicode 字体的某种渲染。尝试一种覆盖面更大的字体会很有趣,尤其是在不再使用的旧字体和表情符号等其他字符之间。使用多种不同的字体生成字符也是很有趣的。如果你这样做,让我知道!

在这 40,000 个汉字中,大部分是中国和日本汉字。我很快放弃了一个实验,在这个实验中,StyleGAN 只生成看起来像中国和日本汉字的新字符。

对于每个超过 256 个字符的块,我随机选择了 256 个字符的子集。这使得数据从 40,000 个字符增加到大约 7,000 个字符。我用这 7000 来训练这个模型,我在本文中分享了它的结果。

为了查看每个区块的前 20 个字符及其颜色,我在我的个人网站上列出了它们:

  • 【http://robertmunro.com/research/unicode/show.html

StyleGAN

StyleGAN 是一个在 TensorFlow 中实现的图像生成系统,它使用生成式对抗网络(GANs)。它是由 NVidia 开发的,并在此作为开源代码发布:

  • https://github.com/NVlabs/stylegan

有关他们方法的更多信息,请参见本文:

  • 一种基于风格的生成式对抗网络生成器架构。泰罗·卡拉斯、萨穆利·莱恩和蒂莫·艾拉。http://stylegan.xyz/paper

StyleGAN 最著名的用途是为实际不存在的人创建“逼真”的照片:

Examples of fake faces generated by styleGAN, from https://github.com/NVlabs/stylegan

人们一直在用这个来生成其他的假图像,我受到了其中一些的启发,包括迈尔斯·布伦戴奇使用 StyleGAN 来创建新的《太空堡垒卡拉狄加》图像:

Because Cylons look like people, but they are not real people?

实验

我对 7000 张图片进行了分层采样,并根据它们的 Unicode 编码进行了颜色编码,我在 P2 AWS 实例上运行了 styleGAN 整整一周。我使用了深度学习 AMI,我需要安装的唯一附加库是用于从字体生成图像。

同样,如果你感兴趣,让我知道,我会上传代码。这是对 styleGAN 代码的一个小修改。最困难的部分是让图像和字体库在 python 中运行良好,这样我就可以以编程方式为每个 Unicode 字符生成图像并给图像着色。

结果

理想情况下,结果应该看起来像实际的字符,但是而不是看起来像当今 Unicode 中的任何字符。

下面是系统训练过的一些真实的例子:

首先,结果不太令人信服。在 10 个样本图像(styleGAN 系统中的“刻度”)之后,它们变得模糊不清:

Example fakes after 10 ticks

但是在 30 次滴答之后,我们开始看到一些清晰的例子:

Example fakes after 30 ticks

30 个刻度后的示例在缩小时看起来很真实,但在放大时有点奇怪,因为直线和曲线之间没有明显的区别:

Alien-looking character after 30 ticks

这也是本文开头的图片,是在 78 次滴答之后,现在有了一些非常清晰的例子:

Example fakes after 78 ticks

直线和曲线之间的区别现在很明显,重音和音调符号现在与字符本身更加明显。在 StyleGAN 的训练中,分辨率增加了一倍,在 30 到 78 个刻度之间,这也有所帮助。

以下是我最喜欢的《78 滴答》,颜色告诉我们它们的影响来自哪里:

Latin influenced

Arabic influenced

Thai influenced

CJK (Chinese Japanese Korean) influenced

Enclosed CJK influenced

Malayalam influenced

Devanagari influenced

Tamil influenced

我真的对这些角色的逼真印象深刻!除了几个例外,看起来它们都属于某种语言的脚本。

有一些例子表明已经是 Unicode 中的字符。这些例子可能不是随机选择的 256 块中的一部分,或者它们可能以不同的方式偏移或缩放。我还没有研究为什么这些会错误地出现。

到第 78 个滴答时,训练还没有完成。我把这限制在一周的训练中,主要是为了适应我的个人时间表。我敢肯定,如果它能持续更长时间,它会创造出更有趣、更有说服力的角色。

只花了半天时间进行实验,花了几个小时进行分析和记录。或者用板球世界杯的术语来说,它花了一局时间来编写代码和启动流程,然后花了 27 局时间来分析结果和写这篇博文。如果你也是一个喜欢板球的程序员,这是一个在观看世界杯时进行多任务处理的好方法!

只有一个方面的结果没有达到我的预期:我希望一些新角色会是彩虹色的,并同时显示出来自多个剧本的影响。经过思考,我明白了为什么情况不是这样:在训练数据中没有彩色的例子,因此彩色的例子不会是令人信服的对立例子。

为什么要生成新字符?

除了有趣的因素,这里还有一些实际的使用案例:

  • 为新脚本识别新字符。世界上只有一半的语言采用了文字。对于一个语言社区来说,采用前殖民者或入侵者的文字往往是有争议的。这种方法可以提供一个候选字符列表,我们已经知道这些字符并不存在,但是在风格上与世界范围内的文字一致。
  • 理解文字的视觉属性。生成的赝品都告诉我们一些关于文字视觉属性的有趣事情:曲线和线条的选择,字符空间不同部分的信息分布,等等。因此,它们告诉我们一些有趣的事情,关于我们如何在不同的脚本中以相似或不同的方式编码信息。
  • 为创造性用例创建新的脚本。从《指环王》到《星际迷航》,在书籍和电影中有许多有趣的假剧本例子。如果你没有预算雇用大卫·J·彼得森,这种方法可以产生比你有时在低成本科幻电影中看到的随机符号更真实的剧本。

如果你知道 StyleGAN 的任何其他有趣的应用,或者其他生成新字符的方法,请告诉我!

更新:代码在这里:https://github.com/rmunro/unicode_image_generator

在 Tableau 中创建强大的动画可视化

原文:https://towardsdatascience.com/creating-powerful-animated-visualizations-in-tableau-ff30a0d861c2?source=collection_archive---------24-----------------------

Tableau 是一个很好的数据分析和可视化工具。它有一些强大的工具,使可视化的吸引力和互动性。其中一个很棒的功能是动画数据可视化。让我们通过一个有趣的案例研究来探索这是如何实现的(礼貌:Udemy )。

我们将分析世界人口统计数据(礼貌:Udemy )来理解 Tableau 中的动画可视化。这一分析的目的是通过可视化了解 53 年来全球生育率和出生时预期寿命的变化。数据因国家而异,并进一步按地区分类。分析所考虑的时间段在 1960 年至 2013 年之间。

第一步是创建一个基本图表。我制作了一个气泡图,根据不同地区绘制了特定人群的出生时预期寿命与生育率之间的关系。

在此图表中,颜色用于识别不同的区域,分为 7 个类别。气泡大小用来表示人口。这张图表显示了整个 53 年间的总体生育率和出生时的预期寿命。同样的可视化可以转换成令人惊叹的 5 维动画图表,显示给定时间段内的动态数据。

为了实现这一点,需要将所需的维度(Year)从主数据源中拖出来,放在“Pages”网格中。所有年份字段都会自动映射到图表中。年份图例与视频控件一起出现,用于管理动画速度和其他属性。

可以添加许多有趣的功能来增强动画可视化。他们中的一个在图表中留下了痕迹。通过选择“显示历史”复选框,用户可以显示给定时间段内的数据轨迹。将鼠标悬停在每个踪迹点上,用户可以看到特定年份的人口统计信息。这个特性对于只标记选定区域的历史数据非常方便。

可以添加注释来指示动画图表中变化的时间段。动画速度可以控制在 3 个级别之间。也可以循环连续播放。可以修改工具提示数据,使图表对用户一目了然。可以增强气泡颜色和大小等图表元素,使图表在视觉上更具吸引力。动画图表现在可以添加到仪表板中了。它可用于制作强大且令人印象深刻的演示文稿,因为它将所有必需的分析信息打包在一个图表中。

在从一年到下一年的气泡运动过程中,随着气泡尺寸的变化,用户可以容易地看到和理解人口统计的变化。历史线索有助于更清楚地分析数据。

这就是简单的图表如何在 Tableau 中在几分钟内转换成美丽的动画可视化效果。

从 AIS 数据的海洋中创建海上航线。

原文:https://towardsdatascience.com/creating-sea-routes-from-the-sea-of-ais-data-30bc68d8530e?source=collection_archive---------11-----------------------

海上航线是海上运输的重要特征。有时它们被官方指南“交通分隔方案”明确定义,有时它们更多的是建议。国际海事组织负责航道系统,包括分道通航制,并在国际海事组织出版物船舶航道 —目前为 2013 年版中发布。不幸的是,它们没有被数字化。

一些商业和免费增值产品是可用的,它们提供距离,有时在每条路线的基础上提供港口之间的路线。在撰写本文时,我们无法找到一个全面的离线路线库。所以我们决定建造自己的。

自动识别系统 ( AIS ) 使用的是几乎所有船只上安装的应答器。船只的唯一标识、位置、航向和速度通常定期发送。这些信号可以被附近的船只、卫星和地面天线接收到。有几家公司收集、清理和出售这些数据。

从 2016 年初到 2018 年年中,Mariquant 拥有来自 AIS 数据提供商之一的散货船和油轮的每小时数据。该数据包含来自约 19 000 艘有记录的独特船只的信息,作为未压缩的拼花文件大约占用 100 Gb。

我们有一个多边形库,有大约 8 000 个港口和 20 000 个锚地和等候区。大多数时候,锚泊多边形位于端口多边形之外,我们使用图形算法来确定哪个锚泊属于哪个端口。有了这些数据,我们开始构建路线。

抛锚和游荡。

我们将使用轨迹间距离的概念来构建路线的最佳表示,并在同一路线上分离不同的轨迹。大多数距离计算算法使用轨迹上的点之间的距离。我们发现一些噪音阻止我们获得有意义的结果来计算轨迹之间的距离。查看数据,我们发现船只花费大量时间(导致轨迹上的大量点)在港口附近停泊或移动。

Anchoring and ‘loitering’ near Belgium and Netherlands ports.

为了找到轨迹上的至少一些点,我们使用了随机森林分类器的 scikit learn [1]实现。有各种方法来寻找血管轨迹上的不同聚类,参见例如[2]和其中的参考文献。我们更喜欢使用稍微简单的方法,因为它易于实现,并为我们提供足够精确的结果。我们使用到港口的距离、到前一个港口的距离、船的速度、船的径向速度(好像绕着港口转)和在到港口的方向上的速度作为分类器的特征。我们人工构建了训练和测试集,分别标记‘游荡’、锚泊、进港和一般航行点。我们在训练中得了大约 6 400 分,在测试集中得了 1600 分。锚点在集合中较少出现,因为它们在距离计算中产生的问题较少。手动标记的困难导致了集合的小尺寸。

混淆矩阵显示待机、进场和一般航行点被很好地定义。即使进场点和一般航次点被错误识别,错误识别也是在它们之间,而不是兴趣点。

Confusion matrix of the Random Tree Classifier

Precision and recall

精度和召回率,以及 F1 评分表明结果是好的,但分类器还有进一步改进的空间。我们必须重申,锚定点对于计算轨迹之间的距离来说不那么麻烦,我们将继续这些结果。

我们发现到港口的距离、到前一个港口的距离、船的速度是最重要的特征,相应地得分为 0.42、0.21 和 0.28,径向速度和到港口方向的速度得分为 0.04 和 0.05。

可以使用标准的 Scikit-learn 函数来计算上面提到的分数。

**from** sklearn.metrics **import** classification_report, confusion_matrix
**from** sklearn.ensemble **import** RandomForestClassifier
**from** sklearn.model_selection **import** train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)clf = RandomForestClassifier(n_estimators=20, max_depth=6, random_state=0)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))
print(clf.feature_importances_)

我们发现,无论分类器的得分如何,我们的大数据集都需要额外的清理。有时,进港轨迹的一小部分被错误地识别为游荡部分,我们不得不进行保守检查,要求轨迹的锚泊和游荡部分足够长,或者是自相交的,或者在进港方向上行驶的距离应小于行驶的总长度。

在所有这些检查之后,我们对轨迹的游荡和锚泊部分的船只位置进行平均。

路线建设。理论。

我们的方法受到了菲利普·贝斯、布伦丹·吉尤、让-米歇尔·卢贝斯和弗兰克·̧ois·罗耶等人工作的启发[3]。在最初的工作中,作为 Kaggle 竞赛的一部分,作者提出了一种称为“对称段-路径距离”的新方法,用于计算轨迹之间的距离,以聚类滑行航程,预测最终目的地点[4]。文章[3]对轨迹距离计算的各种方法进行了深入描述。

简而言之,我们的方法是

  1. 使用某种度量来计算轨迹之间的距离
  2. 根据轨迹的距离对轨迹进行聚类。
  3. 以选择集群中的“最佳”轨迹。

路线建设。练习。

我们测试了不同的距离计算方法,并决定使用带实际惩罚的编辑距离(ERP) [5]。该方法是一种扭曲距离方法,并且允许在不同长度的轨迹之间进行比较,在计算它们之间的距离期间对准轨迹。它在 O(n)时间内运行。该方法的实现是由[3]的作者创建的 trajectory_distance 包的一部分。我们稍微修改了这个包来加速 python 部分的计算,并添加了对并行计算的 DASK 支持。由于内存和计算时间的限制,我们最多选择 50 个随机轨迹,因为热门路线上的计算可能会处理数百个轨迹。这将我们引向 43847 条不同的路线,这些路线将从近一百万次旅行中重建。

同一条路线上的不同行程可以有完全不同的轨迹。因此,如果需要的话,我们需要对这些轨迹进行聚类。相似性传播聚类算法是该任务的自然选择,因为它既不需要聚类数量的初始知识,也不需要距离的三角形不等式(并非所有距离计算方法都生成满足该不等式的距离)。我们使用scikit learn【1】实现了亲和传播算法。

轨迹的重建

由于 AIS 协议的限制,卫星收集的数据通常会丢失点。我们必须找到解决这个问题的办法。

首先,我们使用考虑轨迹之间的距离(我们使用简单平均)和轨迹中缺失点的数量的成本函数来定义“最佳”轨迹。

第二,我们迭代地更新轨迹:

  1. 我们仅使用可用数据找到“最佳”轨迹
  2. 我们使用“最佳”轨迹点来增强带有缺失点的轨迹。找到离“最佳”轨迹最近的点,并且将“最佳”轨迹段添加到增强轨迹中。
  3. 我们用附加数据迭代 1 -2,直到“最佳”轨迹保持稳定并且成本函数值减小。

在轨迹增强之后,我们将轨迹集合在不同的聚类中进行分割。使用上述迭代方法找到每个聚类内的“最佳”轨迹。我们使用这些轨迹作为港口之间的路线。

结果

结果是亚马逊 s3 桶【http://worldroutes.s3.amazonaws.com。在知识共享署名 4.0 许可下,你可以出于任何目的获得和使用它们。你可以在这里获得关于许可证的信息。

数据由四个文件组成:

  1. 沿路线计算的港到港距离( distances.csv )。
  2. 如上所述的港到港路线( routes.csv )。
  3. 我们不能为您提供端口多边形,但是,我们提供由我们的内部索引、世界端口索引、索引 _ 编号端口 _ 名称组成的参考数据(如果有的话,或者我们拥有的任何可用名称)和端口多边形代表点的一个坐标元组。使用 geopandas representative_point()方法( ports.csv )获得港口多边形的代表点。
  4. 带世界地图的 HTML 文件(WorldRoutes.html)

关于 Mariquant

Mariquant 是一家专注于分析工具开发的公司。我们相信,在海事行业持续广泛地采用数据驱动的分析方法将会产生巨大的价值。然而,较差的数据质量、覆盖范围和庞大的数据量对许多人来说是一个障碍,导致他们经常走上自上而下的分析之路,其中涉及大量的手动工作。

在 Marquant,我们通过采用亚马逊(Amazon)和谷歌(Google)等公司开发的尖端技术来挑战这些障碍,但同时保持对海事行业需求的高度关注。引入全自动、数据驱动的分析允许扩展到海事中发现的单个案例的数量级,从而允许及时、准确和慎重的商业决策。

参考

  1. Pedregosa 等人,sci kit-learn:Python 中的机器学习,JMLR 12,第 2825–2830 页,2011 年。
  2. 盛、潘、尹静波。“基于自动识别系统数据的轨迹聚类模型提取航线模式” 可持续性 10.7 (2018): 2327。
  3. 页(page 的缩写)Besse,B. Guillouet,J.-M. Loubes 和 R. Francois,“基于距离的轨迹聚类的回顾和展望” arXiv 预印本 arXiv:1508.04904,2015 年。
  4. ECML/PKDD 15:滑行轨迹预测(一)
  5. 长度陈和 R. Ng,“论 LP-规范和编辑距离的结合”,第三十届国际超大规模数据库会议论文集-第 30 卷。VLDB 基金会,2004 年,第 792-803 页。

使用高级 NLP 库创建智能知识库系统(KBS)

原文:https://towardsdatascience.com/creating-smart-knowledge-base-systems-kbs-using-advanced-nlp-library-b5c21dfafcd1?source=collection_archive---------11-----------------------

Creating and Sustaining Large Knowledge Base Systems(KBS) can be a daunting exercise even for the largest corporations in the world.

企业、机构或任何大型组织通过将知识记录为书籍、期刊/文章、文档等,在其存在的几年中积累了知识。员工、学生、教学/研究团体持续获取这些知识对于持续运营至关重要。市场上的 KM(知识管理)工具通过创建各种知识库并允许访问它,在一定程度上帮助解决了这种需求。知识管理工具要求对文档进行标记(手动或自动),以便用户可以方便地搜索到它。虽然这些工具有其用途,但组织在数字时代面临着新的挑战-

  1. 获取知识库中的上下文和语义信息
  2. 即时获取信息的能力。
  3. 需要一种自动化和持续的方法来创建这样一个系统

现状场景

A search result like this may not serve the purpose all the time

企业知识管理解决方案可以根据用户的查询帮助用户找到所有相关文档。但是这很难满足用户的需求,因为现在用户已经(比如说)访问了 10 个文档,他必须通读它们才能得到他正在寻找的信息。对于实时项目、研究社区等中的用户来说,这可能仍然是一项乏味且令人沮丧的任务,因为它会导致获取信息的延迟。

未来情景

What information can I get for you today?

从知识库中获取信息的未来场景可能就像向聊天机器人询问所需的确切信息一样简单。例如,“某项技术在多少个项目实施中使用过?”类型的查询会立即返回一个答案。虽然这对大多数人来说可能听起来太好了,不像是真的,但深度学习和自然语言处理框架的技术进步已经使这样的解决方案变得可行。此外,由于人工智能技术的民主化和人工智能开源项目的健康生态系统,这样一个未来的解决方案现在已经在小型和大型企业的掌握之中。

聊天机器人背后的精灵是谁?

很明显这一切背后并没有什么精灵。但我认为,象征性地说,一大群不懈地为 NLP 的 ML & AI 前沿工作做出贡献的研究科学家和研究机构是使这成为可能的天才,我们都应该集体感谢他们的努力。解决方案是这样的。

Knowledge Graph (Illustration)

聊天机器人被集成到一个巨大的图形数据库中,该数据库捕获关于各种实体的信息,例如作为节点的个人、公司、位置、技术名称等,以及作为边的所有实体之间的关系和关联。例如,在句子“公司 X 使用 XYZ技术”中,“使用”是存在于实体 X & XYZ 之间的关系,并且被存储为边缘。此外,关于实体和关系的所有其他相关信息分别存储为节点和边的属性。我们受到谷歌如何使用知识图表来存储和检索信息的启发。从本质上来说,这个解决方案可以被认为是在大量知识上构建一个类似于语义搜索引擎的 google,用于即时检索。

Open source library from Explosion.ai

解决方案的最关键部分或核心是从自然语言中确定哪些是实体以及它们之间的关系。这是由 spacy.io 等 NLP 库提供的,这些库使开发人员能够在任何自然语言文本上训练定制的 NER(命名实体识别)和依赖解析器模型。这些模型的结果是良好识别的实体和它们的关系,捕获文档中实体和关系之间的语义上下文。实体之间的这种语义知识然后被馈送到知识图。

一旦上述流程流被自动化到管道中,知识图就可以在处理后续文档时吸收未来的添加或重叠。当它识别同一个实体时,它会重用它,并且只有当它对知识图来说完全是新的时候才创建新的实体。通过这种方式,知识库可以在未来以可持续的方式为所有后续添加内容进行有机增长,同时保留与现有知识的关系。

挑战和其他考虑

如同任何技术一样,实施智能知识库系统(KBS)有其自身的一系列挑战。

  1. 变革管理 —该解决方案需要企业中文档数字化和处理的新流程,需要组织中知识型中小企业的积极参与,更不用说这可能还需要在组织中创建新的角色
  2. 垃圾进垃圾出——这是一句著名的谚语。因此,确保文档的数字化和信息的准确提取对于该计划的成功至关重要。此外,需要准确标记实体&关系
  3. 并非所有组织都需要这种解决方案,因为信息提取的延迟不是一个巨大的障碍,所以投入时间&资源可能会被证明是违反直觉的
  4. 数据科学团队 —必须有一个经验丰富的数据科学团队来监督实施,即使这意味着从外部聘请专家
  5. 技术基础设施 —该解决方案需要在本地或云技术基础设施上进行合理的重大投资。如果您已经与任何云服务提供商建立了持续的关系,那么针对这一需求的供应将是无缝的
  6. 最后,甚至在设计阶段就让最终用户参与到解决方案中,以鼓励大规模采用,并避免在后期出现任何不匹配的期望

喜欢我的文章吗?请点击拍手按钮帮助其他人也找到它,请查看我的Raj Kumar Kaliyaperumal下面的其他热门帖子

  1. 从商业智能到数据科学&机器学习
  2. ML&DL 学习路径

我在Linkedin上发表了这篇文章。

在 SQL 中创建表

原文:https://towardsdatascience.com/creating-tables-in-sql-96cfb8223827?source=collection_archive---------15-----------------------

理解 SQL 的语法非常简单。它遵循一个简单的结构,允许我们对不同的变量重用语法。以下是创建表格的一些基本语法。

正在创建数据库

CREATE DATABASE database_name;

创建表格

CREATE TABLE movies
(
     movie_name   VARCHAR(200),
     movie_year   INTEGER,
     country      VARCHAR(100), 
     genre        VARCHAR NOT NULL, 
     PRIMARY KEY  (movie_name, movie_year)
);

在括号内注明列名、列类型和长度。您可以声明 NOT NULL 以确保它总是被填充。

插入数据

INSERT INTO movies VALUES
('SE7EN', 1995, 'USA', 'Mystic, Crime'),
('INSTERSTELLAR', 2014, 'USA', 'Science Fiction'),
('The Green Mile', 1999, 'USA', 'Drama'),
('The Godfather', 1972, 'USA', 'CRIME')

如果输入的值类型不正确或者为空,并且不为 NULL,SQL 将抛出错误。

更新数据

如果您忘记添加一个值,您可以使用 update 更新它。

UPDATE movies
SET country = 'USA'
WHERE movie_name = 'The Godfather' AND movie_year = 1972;

更改表格

您可以更新项目并将其设置为默认值。

ALTER TABLE movies
ALTER COLUMN country SET DEFAULT 'USA';

测试默认选项。现在,无论何时你提到违约,你都会得到美国。

INSERT INTO movies VALUES
('test', 2010, DEFAULT, 'test')

添加列

ALTER TABLE movies
ADD COLUMN director VARCHAR(150)

更新表格

如果要为任何列添加新值,可以使用 UPDATE。

UPDATE movies
SET director = 'Christopher Nolan'
WHERE movie_name = 'Interstellar';

删除行

如果要删除一行,可以使用 WHERE 引用它。

DELETE FROM movies
WHERE movie_name = 'test'

删除列

ALTER TABLE movies
DROP director;

还有另一种方法你可以放下一个项目,它被称为下降级联。

DROP CASCADE →删除选定的项目以及依赖于它的所有内容。例如,如果我们在整个电影的数据库中使用 DROP CASCADE,所有内容都将被删除。

用 Python 和朴素贝叶斯分类创建一个 Twitter 情感分析程序

原文:https://towardsdatascience.com/creating-the-twitter-sentiment-analysis-program-in-python-with-naive-bayes-classification-672e5589a7ed?source=collection_archive---------0-----------------------

Photo by Hello I'm Nik on Unsplash

如果你在科技领域呆得够久,你一定听说过情绪分析这个术语。它是预测一条信息(最常见的是文本)是否表明对该主题的积极、消极或中性情绪的过程。在这篇文章中,我们将通过制作一个 Python 程序来分析关于特定主题的推文的情感。用户将能够输入一个关键字,并根据包含输入关键字的最新 100 条推文获得对它的看法。

情感分析简介

也被称为“观点挖掘”,情感分析指的是使用自然语言处理来确定在线提及中的发言者、作者或其他主题的态度、观点和情绪。

本质上,它是决定一篇文章是正面还是负面的过程。这也叫内容的极性。

作为人类,我们能够下意识地将文本分为正面/负面。例如,句子“这个孩子脸上有一个灿烂的笑容”,最有可能给我们一个积极的情绪。用外行人的话来说,我们通过检查单词并平均正面和负面来得出这样的结论。例如,单词“华丽”和“微笑”更可能是积极的,而单词“the”、“kid”和“face”实际上是中性的。因此,句子的整体情绪很可能是积极的。

这项技术的一个常见用途是将其部署在社交媒体领域,以发现人们对某些话题的感受,特别是通过用户在文本帖子中的口碑,或者在 Twitter 的背景下,他们的推文

先决条件

  • 基本编程知识:

虽然 Python 在这个迷你项目中的参与度很高,但并不要求对该语言有很深的了解,只要你有基本的编程知识就可以了。

  • 安装的工具:

对于这个程序,我们需要在计算机上安装 Python。我们将使用库twitternltkrecsvtimejson。您可能必须安装前两个库。其余的已经随 Python 解释器一起提供了。不过,检查它们是否是最新的也无妨。

  • 数据集分割概念:

这对于全面了解流程管道至关重要。你只需要知道训练和测试数据集之间的区别,以及每一个在什么样的上下文中使用。

  • 基本的 RESTful API 知识:

这并不重要,但会有所帮助。我们将在代码中到处使用 Twitter API,对 API 进行正常调用,并处理它返回的 JSON 对象。如果你需要,你可以在这里找到官方的 Twitter API 文档。

生产过程说明

A 区:准备测试集

  • 步骤 A.1:获取身份验证凭据
  • 步骤 A.2:认证我们的 Python 脚本
  • 步骤 A.3:创建构建测试集的函数

B 区:准备训练集

C 部分:预处理数据集中的推文

D 部分:朴素贝叶斯分类器

  • 步骤 D.1:建立词汇
  • 步骤 D.2:根据我们的词汇匹配推文
  • 步骤 D.3:构建我们的特征向量
  • 步骤 D.4:训练分类器

E 部分:测试模型

在我们开始之前:

  • Twitter 有时需要几天时间来批准您的应用程序使用 Twitter API。然而,它通常需要不到 24 小时。
  • 下载训练集可能需要 10 多个小时(这将在后面解释)。
  • 教程摘自 Udemy 课程:从 0 到 1:机器学习、NLP、Python——开门见山。

A 部分:准备测试集

因为我们的情感分析的任务主要集中在文本数据上,所以会有大量的文本处理。这肯定是正确的。事实上,我们的测试和训练数据将仅仅由文本组成。

我选择从测试集开始,是为了让大家为训练集提取部分做好准备,因为它更依赖于 API。下面是我们将要做的事情的一点概述:

1-注册 Twitter 应用程序以获得我们自己的凭证。

2-使用凭证通过 API 验证我们的 Python 脚本。

3-创建基于搜索关键字下载推文的功能。

向 Twitter 注册应用程序至关重要,因为这是获得认证凭证的唯一途径。我们一拿到证书,就开始写代码。步骤 3 是测试集所在的地方。我们将根据我们试图分析情绪的术语下载推文。

步骤 A.1:获取认证凭证

首先,我们需要访问 Twitter 开发者网站,并通过以下链接登录我们的帐户:

[## Twitter 开发者平台

Twitter 是世界上企业和个人联系的最佳场所。自从早期的 Twitter 人…

developer.twitter.com](https://developer.twitter.com/content/developer-twitter/en.html)

在右上角,点击应用程序按钮,创建一个应用程序,应用,然后继续,如下所示:

接下来,我们将选择“我请求访问供我个人使用”选项:

在同一个网页上,向下滚动一点,输入您的帐户名称和国家/地区,然后单击继续,您将被重定向到下一个网页。在这里,您可以选择任何您感兴趣的用例。对于我们的案例,我选择了以下内容:

做出选择后,向下滚动并填写所需的用例兴趣段落。Twitter 现在非常重视这一点(我猜他们从脸书的错误 xD 中吸取了教训),所以确保你强调该应用程序是一个自学/学术相关的项目。政府参与问题选择“否”,按“继续”。

在下一个网页上,阅读条款和条件列表,同意他们,然后提交申请。

接下来,打开您的电子邮件,通过发送给您的电子邮件中包含的链接验证您的 Twitter 开发人员帐户。最后,您将收到类似以下内容的消息:

你现在能做的就是等待几个小时,让申请获得批准(如果你的解释没有违反 Twitter 的条款和条件,几乎肯定会获得批准)。

当您收到批准电子邮件时,单击其中包含的登录链接。您将被重定向到以下网页,在这里您应该选择“创建应用程序”:

在下一个网页上,点击右上角的“创建应用程序”。重定向后,填写所需的应用程序详细信息,包括——如果你愿意——这是为了自学。点击“创建”。

下一个网页将包括您刚才输入的应用程序详细信息、访问令牌和权限。进入“密钥和令牌”选项卡。将 API 密匙和 API 秘密密匙复制到一个安全的地方(如果你愿意的话,可以是一个文本文件),因为我们稍后会用到它们。

完成所有设置后,单击“创建”以生成访问令牌凭证。将访问令牌和访问令牌密码也复制到一个安全的地方。我们已经完成了凭证获取部分!

步骤 A.2:认证我们的 Python 脚本

既然我们现在有了 Twitter 开发人员的登录凭证(即 API 密钥和访问令牌),我们就可以继续认证我们的程序了。首先,我们需要导入 Twitter 库,然后创建一个 Twitter。API 对象和我们讨论过的“安全”位置的凭证,如下所示:

前面代码片段中的最后一行只是为了验证我们的 API 实例是否工作。这将根据我们得到的输出来确定。运行上面的代码,您应该得到类似下面的 JSON 响应:

{"created_at": "Tue Feb 12 17:48:27 +0800 2019" 'default_profile": true ............} 

这没什么疯狂的,只是一些关于通过你的 Twitter 账户访问 API 的数据。如果你到了这里,你就可以走了。

步骤 A.3:创建构建测试集的函数

现在,我们可以开始创建一个函数来下载我们讨论过的测试集。基本上,这将是一个函数,以搜索关键字(即字符串)作为输入,搜索包含该关键字的推文,并将它们作为 twitter 返回。我们可以迭代的状态对象。

不过,这里需要注意的是,出于安全考虑,Twitter 限制了通过 API 发出请求的数量。此限制为每 15 分钟窗口 180 个请求。

这意味着,我们每 15 分钟只能使用我们的搜索功能获得多达 180 条推文,这应该不是问题,因为我们的训练集无论如何都不会那么大。为了简单起见,我们现在将搜索限制在 100 条 tweets,不超过允许的请求数。我们搜索推文(即测试集)的功能是:

正如您所料,这个函数将返回包含我们的搜索关键字的 tweets 列表。

请注意,我们将每条 tweet 的文本都耦合到了一个 JSON 对象中,标签目前为空。这仅仅是因为我们稍后会将每条推文分类为正面或负面,以便根据多数计数来确定对搜索词的情绪是正面还是负面。这就是情感分析的实际工作方式。

在我们继续之前,让我们通过在函数体后面添加以下代码来测试我们的函数:

这应该会在您的 IDE 终端上打印出五条包含我们的搜索关键字的 tweets(如果您正在使用的话)。现在一切都准备好了。我们有了测试集,可以继续构建我们的训练集了。

B 部分:准备训练集

注意,到目前为止,我们还没有写很多代码。这要归功于 Python 简洁的语法之美,以及外部程序就绪库的使用,比如 RESTful APIs(在我们的例子中是 Twitter API)。

在这一节中,我们还将使用上一节中的 Twitter API 实例。然而,我们需要先解决一些事情。我们将使用可下载的训练集。根据内容的不同,这些微博都被标上了正面或负面的标签。这正是训练集的用途。

训练集对模型的成功至关重要。数据需要正确标记,不能有不一致或不完整的地方,因为培训很大程度上依赖于这些数据的准确性和获取方式。

对于这项任务,我们将使用令人惊叹的 Niek Sanders 的超过 5000 条手动分类推文的语料库,这使得它非常可靠。这里还有一个问题。Twitter 不允许在个人设备上存储推文,尽管所有这些数据都是公开的。因此,语料库包括每个 tweet 的关键字(tweet 的主题)、标签(pos/neg)和 tweet ID 号(即我们的 CSV 语料库中的行)。你可以从原始站点获得包含语料库的文件,或者通过个人知识库的这个链接。

让我们往回走一点。还记得我们说过的 Twitter API 限制吗?这也适用于这里,因为我们将使用 API 通过语料库中包含的每个 tweet 的 ID 号来获取实际的 tweet 文本。这意味着,要下载 5000 条推文,我们需要遵循:

max_number_of_requests = 180
time_window = 15 minutes = 900 secondsTherefore, the process should follow:Repeat until end-of-file: {
    180 requests -> (900/180) sec wait
}

现在,让我们编写代码来实现这一点。让我们不要忘记将通过 API 获取的 tweets 保存到一个新的 CSV 文件中,这样我们就不必在每次运行代码时都下载它们。我们的职能如下:

这很难,但是如果我们把它分解成几个部分,就相当简单了。首先,我们定义函数来接受两个输入,这两个输入都是文件路径:

  • corpusFile是我们下载的 Niek Sanders 的 CSV 语料库文件的字符串路径。如前所述,这个文件包括 tweet 的主题、标签和 id。
  • tweetDataFile是我们想要保存完整推文的文件的字符串路径。与corpusFile不同,这个文件将包括每条推文的文本以及主题、标签和 id。

接下来,我们从一个空单corpus开始。然后我们打开文件corpusFile,将文件中的每条推文添加到列表corpus

代码的下一部分处理基于 id 获取 tweets 的文本。我们循环遍历 corpus 中的 tweet,调用每个 Tweet 上的 API 来获取 Tweet。特定推文的状态对象。然后,我们使用同一个对象(status)获取与之相关的文本,并将其推入trainingDataSet,然后休眠(即暂停执行)五分钟(900/180 秒),以遵守我们讨论过的请求限制。

现在让我们花点时间离开我们的脚本,在最后一个函数之后下载推文(这将花费几个小时)。我们可以使用下面的代码片段来做到这一点:

代码一执行完,您的tweetDataFile CSV 文件就会充满 tweets(事实上大约 5000)。如果你走到这一步,恭喜你!—我第一次花了很长时间才顺利到达这里。现在我们完成了相对无聊的部分。让我们为即将到来的部分做好准备。

C 部分:在数据集中预处理推文

在我们进入实际的分类部分之前,有一些清理工作要做。事实上,这一步非常关键,在建立机器学习模型时通常需要很长时间。然而,这在我们的任务中不是问题,因为我们拥有的数据是相对一致的。换句话说,我们确切地知道我们需要从它那里得到什么。我稍后会就此事发表意见。

下面说说情感分析中什么重要,什么不重要。单词是最重要的部分(在某种程度上,我们将在接下来的部分中讨论)。然而,当涉及到标点符号之类的东西时,你无法从标点符号中获得情感。所以标点对情感分析来说无所谓。此外,图片、视频、网址、用户名、表情符号等推文组件。不要助长推文的极性(无论是正面还是负面)。然而,这只适用于这个应用程序。例如,在另一个应用程序中,你可以有一个深度学习图像分类器,它学习并预测推文中包含的图像是代表积极的东西(例如彩虹)还是消极的东西(例如坦克)。说到技术性,情感分析和深度学习都属于机器学习。事实上,你可以通过深度学习进行情感分析,但那是另外一个故事了。

因此,我们知道我们需要在现有的推文中保留什么,需要去掉什么。这适用于训练集和测试集。因此,让我们创建一个预处理器类:

这很难,所以让我们把它分成几部分。我们从导入的库开始。re是 Python 的正则表达式(RegEx)库,它负责解析字符串并以有效的方式修改它们,而不必显式地遍历组成特定字符串的字符。我们还导入了自然处理工具包ntlk,这是最常用的 Python 库之一。它负责我们需要对文本执行的任何处理,以改变其形式或从中提取某些成分。类别建构函式会移除停用字词。这是一个相对较大的主题,您可以稍后阅读,因为它更多地涉及自然语言处理,而与我们的主题关系不大。

processTweets函数只是遍历输入其中的所有 tweet,在列表中的每个 tweet 上调用它的相邻函数processTweet。后者通过首先将所有文本转换成小写字母来进行实际的预处理。这仅仅是因为,在几乎所有的编程语言中,“car”与“cAr”的解释方式不同。因此,最好将所有数据中的所有字符都规范化为小写。其次,URL 和用户名从 tweet 中删除。这是出于我们在文章前面披露的原因。之后,数字符号(即#)从每个标签中移除,以避免标签被不同地处理。最后但并非最不重要的一点是,删除重复字符,以确保没有重要的单词未经处理,即使它以不寻常的方式拼写出来(例如,“caaaaar”变成了“car”)。最后,tweet 的文本被分解成单词(标记化),以便在接下来的阶段中简化处理。

我们举个例子。数据集中可能会出现以下推文:

"@person1 retweeted @person2: Corn has got to be the most delllllicious crop in the world!!!! #corn #thoughts..."

我们的预处理器将使推文看起来像这样:

“AT_USER rt AT_USER corn has got to be the most delicious crop in the world corn thoughts”

最后,标记化将导致:

{“corn”, “most”, “delicious”, “crop”, “world”, “corn”, “thoughts”}

请注意,我们的代码删除了前面提到的单词中的重复字符(即“delllllicious”变成了“delicious”)。但是,它没有从文本中删除重复的单词(即“玉米”),而是保留了它们。这是因为重复词在确定文本的极性中起作用(我们将在下一节中看到)。

我们已经准备好使用我们的预处理器类。首先,我们将创建一个引用它的变量(一个对象),然后像前面讨论的那样在训练集和测试集上调用它:

现在我们可以进入最激动人心的部分——分类。但是首先,让我们重温一下我们的算法:朴素贝叶斯分类器。

D 部分:朴素贝叶斯分类器

毫无疑问,计算机科学和机器学习中最重要的概念之一。直接进入 It 的数学领域可能会令人沮丧。因此,我不会从数学的角度来解释它。

成为计算机科学家不需要懂数学。然而,要成为一个真正优秀的人,你确实需要了解数学。

我想强调的事实是,我在这里只简要地解释朴素贝叶斯分类,因为深入的解释值得自己的长篇大论。

朴素贝叶斯分类器是一种基于贝叶斯定理的分类算法。该定理提供了一种计算称为后验概率的类型或概率的方法,其中事件 A 发生的概率依赖于概率已知背景(例如事件 B 证据)。比如,如果 Person_X 只在外面不下雨的时候打网球,那么,根据贝叶斯统计,Person_X 在不下雨的时候打网球的概率可以给出为:

P(X plays | no rain) = P(no rain | X plays)*P(x plays)/P(no rain)

遵循贝叶斯定理:

P(A|B) = P(B|A)*P(A)/P(B)

对于我们的任务,你只需要知道朴素贝叶斯分类器依赖于著名的贝叶斯定理。在我们继续之前,让我们快速概述一下接下来要采取的步骤:

1-建立驻留在我们的训练数据集中的所有单词的词汇表(单词列表)。

2-将 tweet 内容与我们的词汇表进行逐字匹配。

3-建立我们的单词特征向量。

4-将我们的特征向量插入朴素贝叶斯分类器。

这可能看起来很多,但不要担心。它实际上非常简单,而且尽可能的短。让我们一步一步地把它记下来。

步骤 D.1:构建词汇

自然语言处理中的词汇表是模型可用的所有语音片段的列表。在我们的例子中,这包括我们拥有的训练集中的所有单词,因为模型可以相对平等地使用所有这些单词——在这一点上,至少可以这样说。代码看起来会像这样:

这只是创建一个我们在训练集中拥有的all_words列表,将它分解成单词特征。这些word_features基本上是不同单词的列表,每个单词都有其频率(在集合中出现的次数)作为key

步骤 D.2:根据我们的词汇表匹配推文

这一步至关重要,因为我们将检查我们的训练集(即我们的word_features列表)中的所有单词,将每个单词与手头的推文进行比较,将一个数字与下面的单词相关联:

label 1 (true): if word in vocabulary is resident in tweet
label 0 (false): if word in vocabulary is not resident in tweet

这很容易编码:

给定最后一个代码片段,对于 word_features 中的每个单词,我们将拥有 JSON 键‘contains word X’,其中 X 是单词。根据我们之前所说的标签,其中的每个键都将具有值 True/False——True 表示“存在”, False 表示“不存在”。

步骤 D.3:构建我们的特征向量

现在让我们调用我们编写的最后两个函数。这将建立我们的最终特征向量,我们可以继续进行训练。

NTLK 内置函数apply_features从我们的列表中提取实际的特征。我们最终的特征向量是trainingFeatures

步骤 D.4:训练分类器

我们终于完成了我们任务中最重要的——讽刺的是最短的——部分。多亏了 NLTK,我们只需要一个函数调用就可以将模型训练成朴素贝叶斯分类器,因为后者内置于库中:

我们快完成了!我们剩下的就是运行分类器训练代码(即nltk.NaiveBayesClassifier.train())并测试它。请注意,执行这段代码可能需要几分钟时间。

E 部分:测试模型

关键时刻到了。让我们根据我们的搜索词,通过对我们从 Twitter 下载的 100 条推文运行分类器(即NBayesClassifier)来完成我们的工作,并获得分类器返回的标签的多数投票,然后输出推文的总正面或负面百分比(即分数)。这也很简单:

就是这样!恭喜你。您已经创建了一个 Twitter 情绪分析 Python 程序。请注意,我们没有触及准确性(即评估模型),因为这不是我们今天的主题。稍后我会在一篇文章中解释机器学习中的整个模型/假设评估过程。让我们最后看一下我们为此任务编写的完整代码:

结论

情感分析是一种有趣的方式,可以用来思考自然语言处理在对文本做出自动结论方面的适用性。它被用于社交媒体趋势分析,有时也用于营销目的。由于现代现成的库,用 Python 编写情感分析程序并不是一件困难的事情。这个程序简单地解释了这种应用程序是如何工作的。这只是出于学术目的,因为这里描述的程序绝不是生产级的。