TowardsDataScience-博客中文翻译-2020-二十四-

TowardsDataScience 博客中文翻译 2020(二十四)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

在 R 中构建您的第一个闪亮的 Web 应用程序

原文:https://towardsdatascience.com/build-your-first-shiny-web-app-in-r-72f9538f9868?source=collection_archive---------8-----------------------

作者绘制的图像

数据科学

闪亮教程第 1 集

你想公开你的 R 代码给其他人使用吗?如果您的回答是肯定的,那么这篇文章是为您准备的,因为我将向您展示如何使用 Shiny 包在 R 中构建您的第一个 web 应用程序。

为了补充这篇文章,你也可以观看我在我的 YouTube 频道 Data Professor 上制作的视频用 R 构建你的第一个 Web 应用。

数据科学生命周期

数据科学生命周期从收集数据开始,这些数据将作为数据集和数据科学项目的核心组成部分。接下来,需要清理该数据集,以消除缺失数据和任何异常。顾名思义,探索性数据分析(EDA)将允许我们了解数据集的一般特征,这可以通过执行描述性统计和数据可视化来实现。从 EDA 中获得的见解可以为构建预测模型(例如,分类、回归、聚类、关联分析等)提供起点和思路。).为了完成生命周期,可以将性能最佳的模型部署为应用程序编程接口(API)和 web 应用程序。

数据科学生命周期。(由 Chanin Nantasenamat 绘制)

为什么要构建 Web 应用程序?

所以问题是,你为什么想要构建一个 web 应用程序?这是一个很好的问题!

部署的 web 应用程序提供了一个图形化的前端(用户界面或 UI ),允许用户输入输入参数,后端(服务器)将处理这些参数并将其发送回来,以便在 web 前端上显示。在机器学习的上下文中,将经过训练的机器学习模型部署为 web 应用允许用户通过简单地将输入参数输入到 web 前端上提供的表格中来容易地进行预测,该表格将用作经过训练的机器学习模型的输入特征,其中该模型将进行预测。

所有这些都是通过点击几下鼠标来实现的,因为用户不需要任何编码方面的技术知识来进行这种预测。在本文中,您将学习如何使用 Shiny 包在 R 中制作 web 应用程序。

除了部署机器学习模型,还可以创建 web 应用程序来托管数据驱动的仪表板。这些仪表板可以提供有用的感兴趣的汇总数据,这些数据基本上可以用于实时监控和评估指标和性能。

什么是闪亮的?

在我们进一步讨论之前,也许先简单介绍一下什么是闪亮的。

Shiny 是一个 R 包,可以让你轻松构建交互式 web 应用。使用 Shiny 的好处是,它可以将你的 R 代码扩展到网络上,这将有助于将它的可用性扩展到更广泛的社区中(从单个用户使用到成百上千的用户通过互联网使用)。

除了 Shiny 包提供的功能外,还有几个扩展包补充了 Shiny 的功能,如 shinythemesshinydashboardshinyjs 等。

你能用闪亮建造什么?

这是一个很好的问题!以下是一些开始的想法,我相信你能想出更多的。

  • 机器学习驱动的网络应用
  • 数据驱动的仪表板
  • 数据收集表格

闪亮画廊还有很多其他的例子。

将 Web 应用程序部署到互联网

在你自己的本地计算机上测试了闪亮的网络应用程序后,你确信它可以工作并准备好发布到互联网上,你可以将它部署到你自己的服务器上,或者通过应用程序托管服务,例如 Shinyapps.io 和 Heroku T21。那么这两者有什么区别呢?

拥有自己的服务器的好处是你可以完全控制电脑,因此你可以随心所欲地安装所有软件、模块和软件包。这样做的缺点是,您需要掌握大量的知识来管理服务器。例如,你可能需要精通 BASH 命令,以便通过服务提供商管理云上的 Ubuntu 服务器,如数字海洋(100 美元免费信用)、Linode、亚马逊网络服务或谷歌云平台。

使用 应用托管服务 的好处是,你不用担心管理服务器。没错,不再需要处理服务器更新,不再需要配置路径和复杂的软件和库编译。这些应用程序托管服务提供商允许你将精力集中在构建应用程序上,就是这样!

闪亮网络应用的结构

闪亮的 web 应用程序由 3 个组件组成:

  1. 用户界面(ui。r)—UI 是接受用户输入值的前端。
  2. 服务器功能(Server。R) —服务器是后端,处理这些输入值,最终产生最终显示在网站上的输出结果。
  3. shinyApp 功能 —将 UI 和服务器组件结合在一起的应用本身。

一个闪亮的 web 应用程序如何工作的示意图。(由 Chanin Nantasenamat 绘制)

闪亮网络应用的代码

现在,有趣的部分来了,让我们看看我们今天将要构建的闪亮的 web 应用程序的代码(如下所示)。

闪亮的 Web 应用程序是如何工作的?

下面的 3 个简单步骤总结了我们使用这个闪亮的 web 应用程序时发生的事情。

运行闪亮的网络应用程序

现在,让我们运行 web 应用程序。

第一步。继续启动你的 RStudio。

第二步。点击文件→新建文件→ R 脚本,粘贴上图所示的整块代码,另存为app.R(也可以下载 app。r 档)。

第三步。点击位于文件面板右上方的运行 App 按钮(如下图白色圆圈所示)。

app 截图。r 文件包含 RStudio 中闪亮的 Web 应用程序。

几分钟后,您将看到一个弹出窗口,显示闪亮的 web 应用程序,如下所示。请注意,web 应用程序的输出值为空,因为输入参数仍然为空。

已执行 app 截图。r 文件(点击运行应用程序按钮后)。

让我们在两个输入框(名和姓)中填入值,您将看到输出框(主面板)现在将显示连接在一起的名+姓。例如,我们用“机”作为的名,用“学”作为的姓。在底层,UI 组件接受来自 2 文本框的输入参数,输入名和姓。接下来,我们连接这两个变量以产生一个输出“机器学习”。最后,UI 在主面板(灰色框)上显示这个输出。

输入了输入参数的 web app 截图。

对代码的逐行解释

上面显示的代码已被注释,将代码的主要部分标记如下:

  • # Load R packages(第 1 行),
  • # Define UI(第 5 行),
  • # Define server function(31 行)
  • # Create Shiny object(第三十九行)

现在,我们将在接下来的小节中更深入地讨论上述 4 个部分。

加载 R 包(第 1–3 行)

  • 线 2 —装载shiny包装
  • 线 3 —装载shinythemes

定义用户界面(第 5–29 行)

  • 第 6 行fluidPage()函数创建了流畅的页面布局,元素可以通过这种方式缩放以占据浏览器的可用宽度。所有的 UI 元素都包含在fluidPage()函数中。我们使用的第一个输入参数是theme选项,其中我们定义了来自shinytheme R 包的cerulean主题的使用。
    (注意:右括号在第 29 行)。
  • 第 7 行navbarPage()顾名思义,函数创建一个带有顶级导航栏的页面。
    第 9 行—web app 的名称定义为“My first app”
    第 10 行 —这里我们使用tabPanel()功能定义选项卡面板。这代表三个选项卡面板中的第一个,因此我们将选项卡面板定义为“Navbar 1”
  • 第 11 行 —这里我们使用了sidebarPanel()函数(右括号在第 16 行),以便 web 应用程序可以在 web 应用程序的左侧有一个侧边栏面板,接受用户输入参数。第 12 行 HTML 标签tags$h3用于向侧边栏面板提供“Input:”子标题标题。
    第 13-14 行textInput()函数用于接受用户以文本字段形式输入的值。textInput()函数中包含的输入参数包括(1)变量名(如txt1txt2),(2)显示在文本字段上方的标题(如“Given Name:”“Surname:”)以及(3)
    (注意:右括号在第 28 行)。
  • 第 17 行 —这里我们使用了mainPanel()函数(右括号在第 22 行)。
    第 18 行 —使用h1()标签功能显示“Header 1”的标题。
    第 20 行 —通过使用h4()标签功能显示“Output1”
    子标题(不是错别字,而是表示标题的层次)。
    第 21 行 —显示将输入值(名和姓)组合在一起得到的输出值。
  • 第 25–26 行 —其余两个选项卡面板通过tabPanel()功能显示在这两行上。第一个输入参数是选项卡面板的名称“Navbar 2”“Navbar 3”,而第二个输入参数是“This panel is intentionally left blank”。因此,在点击这两个选项卡面板时,我们将看到消息“This panel is intentionally left blank”,这是这两个选项卡面板的内容。

定义服务器功能(第 31–37 行)

  • 第 32 行——定义服务器,输入和输出变量通过反应性本质上连接在一起(输入值的变化将立即或反应性地导致输出值的更新)。
  • 第 34–36 行 —如上图漫画所示,用户输入的来自input$txt1input$txt2 ( 分别对应Given NameSurname)的输入值被赋给output$txtout变量(处理后的输出值),该变量将被传回 UI,显示在输出文本框中(第 21 行)。特别是,Given NameSurname将通过paste()函数组合在一起,输入参数是来自 UI 文本输入的txt1txt2变量(即第 35 行的input$txt1input$txt2)
    注意第 34–36 行的output$txtout(来自服务器函数)与第 21 行的txtout是同一个变量(来自 UI 函数)。同样,第 13 行和第 14 行上的 txt1 和 txt2(来自 UI 函数)与input$txt1input$txt2(来自服务器函数)是相同的变量。

创建闪亮的对象(第 39-40 行)

  • 第 40 行shinyApp()函数将上面定义的 ui 和服务器变量作为输入参数,并将它们融合在一起,以构建我们最终看到的真正闪亮的 web 应用程序。

恭喜你!您现在已经成功地在 R 中创建了您的第一个闪亮的 Web 应用程序!

订阅我的邮件列表,获取我在数据科学方面的最佳更新(偶尔还有免费赠品)!

关于我

我是泰国一所研究型大学的生物信息学副教授和数据挖掘和生物医学信息学负责人。在我下班后的时间里,我是一名 YouTuber(又名数据教授)制作关于数据科学的在线视频。在我做的所有教程视频中,我也在 GitHub 上分享 Jupyter 笔记本(数据教授 GitHub page )。

* [## 数据教授

数据科学、机器学习、生物信息学、研究和教学是我的激情所在。数据教授 YouTube…

www.youtube.com](https://www.youtube.com/dataprofessor?sub_confirmation=1)

在社交网络上与我联系

YouTube: http://youtube.com/dataprofessor/

LinkedIn:https://www.linkedin.com/company/dataprofessor/

https://www.linkedin.com/company/dataprofessor/

【HTTP://facebook.com/dataprofessor/】
【GitHub:【HTTPS://github.com/dataprofessor/】
Instagram:【HTTPS://www.instagram.com/data*

构建完全可配置的界面,用 Python 在 10 分钟内创建类似 MNIST 的数据集

原文:https://towardsdatascience.com/build-your-fully-configurable-interface-to-create-mnist-like-dataset-with-python-in-10-minutes-43ab414a875e?source=collection_archive---------40-----------------------

一步一步的用户友好的 python 界面,从 JSON 配置文件中编写数据集(带代码)

动机

为了一个个人项目,也许是一篇论文(手指交叉),我需要创建一个类似 MNIST 的数据集。我以为可以对别人有用。因此,我将解释我是如何用 Python 编写这个接口的。( github 库)

本文的目的是能够将自己的界面设计成尽可能的灵活快速。这个界面将允许我们用鼠标绘制我们的角色,其他所有事情都将通过配置文件中指定的大量参数自动完成

完全可配置

我正在从一个 JSON 文件中寻找一个完全可配置的接口。再也不用摸代码,就是灵活便捷可伸缩。我们将在本文中讨论不同的参数,但是所有的参数都包含在我命名为config.json的文件中。你可以随意命名。它允许您更改:

  • 我们在上面绘制的图像的尺寸。
  • 输出图像的尺寸,以完成数据集
  • 每个类别的预期图像数量,首选绘图节奏以及我们输出图像的渲染的存在。
  • 包含数据集的文件夹名称,可以为每个类创建子文件夹。
  • 我们铅笔的尺寸强度褪色..
  • 插补方法。
  • 命名类的

存储和公用设施

重要的事情先来。我们需要知道如何组织我们的数据。在文件config.json中,我们有storage部分:

  • root (str):数据集的 root 文件夹的路径
  • by_class_name (bool):数据集的存储方式

我们所有的图像都将有相同的图案。图像的名称总是以类名开头。然后是下划线,然后是 5 个字符的数字来标识它。所以我们有一个root/(subfolderclass)/name_id.png格式。

您会注意到 id 是递增设置的。换句话说,你可以看到每个类已经生成了多少图像。然而,作为用户,你可能需要也可能不需要将其他文件放入这些文件夹中,或者有时删除图像或重命名它们。我们将在代码的开头放一小部分,让自动重新排列我们的图像名称

utils.py中我们设置了一些功能:

  • get_json :返回 json 文件的**内容,作为 python 字典**
  • check_folder_path :检查文件夹是否存在,否则新建一个**。**
  • order _ filename _ by _ prefix:按照正确的名称格式对文件重新排序。****

设计师

我们想要的是能够用手(鼠标)画出我们的角色。从绘图窗口中,我们想要快速创建数据集。然后我们需要一个class Designer,我们将把它存储在designer.py文件中。为了理解我们为什么需要这个类,让我们仔细看看配置文件中的一些参数:

  • ****输入:包含要绘制图像的尺寸和绘图铅笔的粗细(仅用于可视化)。
  • ****输出:包含输出图像的尺寸,以构成我们的数据集。
  • 插值方法 (str 或 str 列表):我们的绘图图像和我们的输出图像的尺寸不一样。所以我们需要一个插值方法来调整图像的大小。然后我们可以选择由 OpenCV 提供的所有插值方法:INTER_NEARESTINTER_LINEARINTER_AREAINTER_CUBICINTER_LANCZOS4。我们可以精确RANDOM来改变每个图像的插值方法。该参数可以是一个列表:在这种情况下,指定的插值方法有多少个设计器,输入图像就有多少个输出图像。
  • ****线条→粗细(浮动或浮动列表):输出图像上的铅笔粗细与图像对角线成比例。该参数可以是一个列表:在这种情况下,设计者的数量将和笔的粗细一样多。结果是一个设计矩阵结合了插值方法和指定厚度。
  • line → range_value (int 或 int 的列表):像素在绘制时的亮度。在列表的情况下:所画像素的亮度将在指定范围内随机选择。
  • ****线条→渐变(浮点):线条的边缘的渐变值,渐变为线性。对数值fading=1没有影响。

注意绘图将由线条组合完成。因此有了draw(self, pt_1, pt2)的角色。所以我们仍然需要用鼠标来控制这一切。

控制器

首先我们需要创建一个class Controller从配置字典中初始化

在初始化期间,会发生几件事:

  • ****提取的所有配置参数。
  • ****验证文件夹是否存在,如果不存在,创建它们。
  • ****设计器的初始化。
  • 按已经完成的类别计算数量的图像
  • 创建用于绘图的 OpenCV 窗口和用于可视化的 OpenCV 窗口。

为了创建我们所有的设计师,将有一个设计师矩阵,其中垂直用于铅笔粗细,而水平用于插值方法。同时我们可以创建一个函数来捕捉绘图窗口上的鼠标事件。只有按下鼠标左键才能绘图。最后,您可以检索已经绘制的图像数量。****

让我们画画吧

在我们开始绘制之前,让我们来看看process中我们最后的参数建议:

  • volume (int):每个类要到达的图像数量。
  • 选择 (str):选择下一个要绘制的字符的方式。可以是RANDOMCLASSBYCLASS写完一个字再去写其他的,或者ROTATE 轮流换不同的类。
  • display_output (bool):显示或不显示输出窗口。

现在可以创建一个新的图像来绘制,绘制它,以正确的格式保存(root/(subfolderclass)/name_id.png)。

剩下的就是能够从 OpenCV 窗口中查看所有内容,并且只要没有达到每个类的图像量就运行程序。****

主要的

最后,为了更加方便,我们可以让用户选择使用 shell 中的命令来指定他的配置文件:

python3 main.py -c path/to/the/config/file.json
or 
python3 main.py -config path/to/the/config/file.json

知识就是分享。
支持我,一键获得
访问 中我所有文章的****

来源

项目的 Github 库

一切都是自制的,可以免费使用

用 Wolfram Alpha API 和 Python 构建您的下一个项目

原文:https://towardsdatascience.com/build-your-next-project-with-wolfram-alpha-api-and-python-51c2c361d8b9?source=collection_archive---------16-----------------------

实践教程

让我们将 Wolfram Alpha 中的精选数据、自然语言处理、文本到语音转换、绘图渲染等功能应用到您的下一个项目中吧!

任何在某一点上与数学斗争的人都知道 Wolfram Alpha,并且可能因为它解决任何方程、绘制任何函数或可视化逻辑电路的能力而得救。Wolfram Alpha can 然而,做的远不止这些,包括化学、语言学或历史,最重要的是,它可以使用它的公共 API 给你所有的答案。因此,在这篇文章中,我们将探索如何使用它来回答简单的问题,解决数学问题,渲染情节,甚至描述 DNA 序列!

照片由韦恩·范Unsplash 上拍摄

安装

Wolfram Alpha API 是免费的(用于非商业用途),但是我们仍然需要获得 API key (AppID)来对 API 端点执行查询。为了获得 API 密钥,我们将首先在 https://account.wolfram.com/login/create处创建 Wolfram ID。创建帐户后,我们可以导航到developer.wolframalpha.com/portal/myapps,点击注册获得您的第一个 AppID 按钮,填写获得新的 AppID 对话框。之后,我们将看到 API 键,这里称为 AppID ,我们可以使用下面的示例查询来测试它:

上面的代码使用 Wolfram|Alpha 完整结果 API 来找出蚊子的寿命。为此,它向http://api.wolframalpha.com/v2/query发出GET请求,其中包含指定我们的 AppID 进行身份验证的参数、input字段中的问题、格式参数为plaintext(而不是图像)以及最终的输出类型为 JSON(而不是默认的 XML)。

我们以字典的形式遍历结果,寻找感兴趣的字段进行打印。返回的 JSON(或 XML)可能相当复杂,解析它的最简单方法是打印它,并在其中寻找任何有用的字段。上述查询的响应的精简示例如下所示:

做数学

Wolfram Alpha 最有用的部分(在我看来)是解决复杂数学问题的能力。因此,让我们尝试使用 API 来做一些数学计算:

上一节中展示的完整结果 API 不仅仅回答一些奇怪的问题,它还做数学(和几乎所有的事情)。为了让 API 意识到我们想要做数学运算——在本例中——求解方程,我们需要在实际的方程前面加上单词solve。除了输入本身,该查询看起来与上一节中的查询非常相似。添加到这个参数中的一个额外的东西是includepodid参数,它告诉 API 在这种情况下我们只希望在响应中包含Result pod。“但是,pod 是什么?”,你可能会问。

来自 Wolfram Alpha(网站和 API)的每个结果通常包括多个类别的数据。例如,这可以是图表、图像、逐步解决方案或表格。其中的每一个都属于它自己的叫做 pod 的部分,而 pod 又包括子 pod来保存单独的数据。考虑到每个响应有时甚至可能包括 10 个左右的 pod,描述一下我们希望从 API 中得到什么是可取的。为此,可以使用podtitle和更健壮的includepodid参数,如上所示。

因此,上述查询的过滤响应如下所示:

为了进行比较,相同的(但图形)结果,但所有的豆荚看起来像这样:

带有输入、结果、绘图和数字行窗格的结果

Wolfram Alpha 可以成为很好的学习资源,因为它不仅能够显示结果,而且所有的计算步骤和 API 都可以做到这一点。为了获得一个查询的逐步解决方案,我们需要包含另一个名为podstate的参数,它指定 pod 状态变化。这将使用修改后的版本替换原来的 pod,例如,更多位数的十进制数,如圆周率(DecimalApproximation)、扩展的天气数据(更多天/月/年)或在我们的情况下,方程解的步骤:

渲染数学降价

您可以使用 Wolfram Alpha API 的一个巧妙技巧是呈现 MathML。如果你不熟悉 MathML,那么这里有一个快速概述——MathML代表数学标记语言,它是一种基于 XML 的格式,用于在 web 浏览器中呈现类似 LaTeX 的数学表达式。尽管这种格式已经存在很长时间了,但只有 Firefox 才真正支持它,这可能让它看起来像是一个糟糕的选择,但名为 MathJax.js 的 JavaScript 显示引擎使得在任何浏览器中呈现 MathML 成为可能,如果你想在你的 web 应用程序或博客中以 LaTeX 格式显示非常好看的复杂公式,这是一个不错的选择。说完了,我们来查询一下吧!

我们再次使用上一节中的例子,通过逐步求解来查询方程,但是用format=plaintext代替format=mathml,同样用mathml代替所有其他出现的plaintext,例如result = data[0]["mathml"]。上面你可以看到 API 给出的一点 MathML 输出,由于完整的输出非常长,所以它被修剪得很短,但我鼓励你自己尝试运行查询,通过 MathJax.js 传递它,并享受美丽的 LaTeX 数学表达式。

求解布尔代数

Wolfram Alpha 的另一个常见用例是求解布尔代数。与基本方程一样,我们需要做的就是将公式传递给 API,这是我们将得到的结果:

除了我们选择的特定 pod—InputMinimalFormsTruthDensity之外,上面的查询没有显示任何新内容。在解析这 3 个 pod 中的数据后,我们可以看到输出,其中包括提交的输入公式的更好的形式,它的其他计算形式(CNF,DNF...)以及分数和百分比形式的真实密度。

渲染和下载图

我最喜欢用 Wolfram Alpha 做的事情之一就是渲染复杂的情节。实现这一点甚至不需要太多的代码更改,唯一真正的更改是选择 pod 及其字段:

在这种情况下,我们使用includepodid参数来选择3DPlotContourPlot窗格,这些窗格在其img.src字段中保存相应地块图像的 URL。然后可以下载这些图,并以二进制模式写入,生成以下图像:

三维绘图

不仅仅是数学

在这一点上,我认为我们已经看到了足够多的 Wolfram Alpha 和 math 的应用程序。那么,我们还能做什么?举个简单的例子,让我们探索一些 DNA 序列:

我们再次使用相同的 API 端点,但是这次我们提交代表 DNA 序列的字符串。您可能会注意到,我们不需要像前面的solveplot那样在查询前包含关键字。这次我们没有使用关键字,而是添加了scanner参数,它指定了搜索查询的主题区域,在本例中是Genome。要找到哪个扫描仪将为某个查询返回相关数据,最简单的方法是运行不带scanner参数的查询,并查找每个包含预期数据的 pod 的scanner属性。

DNA 序列显然不是你可以搜索的唯一酷的东西。其他一些有趣的话题可以是历史、化学、交通或音乐——仅举几例。

自然语言(口语)答案

如果只是寻找信息,那么前面例子中的例子和 API 就足够了。然而,如果你想要/需要更自然的回答,那么你可以使用口语结果 API :

v1/spoken端点的查询非常简单。我们需要传入的只是一个 AppID 和我们在i参数中的问题。这产生了完整句子形式的反应,而不是简单的事实。这在构建智能聊天机器人时非常有用,或者可以作为文本到语音引擎的输入。

使用对话 API 聊天

作为对口语结果 API 的一种扩展,Wolfram Alpha 还提供了对话 API ,允许你提出后续问题,从而与 API 进行对话。所以,让我们试一试,问 Wolfram Alpha 一些问题:

考虑到我们要问多个问题,我们也必须进行多个查询。第一个是针对v1/conversation端点,并在i参数中包含一个问题。我们还用geolocation参数指定我们的位置——这是可选值之一(其他的是ipunits),可以为问题提供上下文。第一个请求与口语结果 API 做的事情差不多,这意味着它以完整句子的形式返回信息。

当我们提出后续问题时,乐趣就开始了。为此,我们进行另一个查询,但是这一次,我们将它发送到作为对第一个查询(host = r["host"])的响应的一部分提供的主机。第一个响应还包括conversationID,我们也必须为 API 传递它,以了解在它之前说了什么。

然后,第二个查询返回与第一个相同类型的结果,这允许我们使用提供的conversationIDhost继续询问更多问题。

我想在这里强调的最后一点是,问题和答案是如何很好地流动和使用上下文的。在这个例子中,我们使用了“离这里有多远?”作为后续问题,没有具体说明【它】【这里】到底是什么。这些信息是从前面的问题和geolocation参数中自动推断出来的。

结论

就 Wolfram Alpha 提供的信息而言,这篇文章只是冰山一角。这些 API 不仅仅可以用于数学,我认为它是构建酷机器人、智能设备或基于语音的应用程序的良好起点。即使它不是免费的商业用途,你仍然会每月收到 2000 个请求,这足以启动一些很酷的项目。我建议查看https://products.wolframalpha.com/api/获取每个 API 端点的文档,以及 Wolfram Alpha 登录页面,它显示了所有不同的主题,可能会给你一些关于可以用它构建什么的想法。😉

本文最初发布于martinheinz . dev

[## 编写更加地道和 Pythonic 化的代码

使你的 Python 代码可读、有效、简洁和可靠的习惯用法和惯例。

towardsdatascience.com](/writing-more-idiomatic-and-pythonic-code-c22e900eaf83) [## 为您的 GitHub 档案创建一个精彩的自述文件

使用 GitHub 隐藏的新功能— GitHub Profile READMEs,在 GitHub 上展示您的项目和技能!

towardsdatascience.com](/build-a-stunning-readme-for-your-github-profile-9b80434fe5d7) [## 用 Python 从公共 API 抓取新闻和文章

让我们探索纽约时报、卫报、黑客新闻和其他 API,并为您的下一个项目收集一些新闻数据!

towardsdatascience.com](/scraping-news-and-articles-from-public-apis-with-python-be84521d85b9)

用 7 行 Python 代码构建您自己的有声读物

原文:https://towardsdatascience.com/build-your-own-audiobook-in-7-lines-of-python-code-bfd805fca4b1?source=collection_archive---------20-----------------------

不买有声读物,用 Python 实现文本转语音有声读物

图片由来自 PixabayFelix Lichtenfeld 拍摄

有声读物是大声朗读的一本书或其他作品的录音或画外音。可用的流行有声读物列表有:

如果你有一本 pdf 格式的有声读物,你就不需要订阅。在本文中,您将知道如何用 7 行 python 代码开发一个基本的有声读物。

安装:

Python 有大量服务于各种目的的库。在本文中,我们将需要两个库( pyttsx3,PyPDF2 )来开发一本有声读物。

您可以从 PyPl 安装这些库,

**pip install PyPDF2
pip install pyttsx3**

在这里阅读 pyttsx3 库的完整文档。

1)阅读 PDF 文件:

Python 有库 PyPDF2 ,它是作为 PDF 工具包构建的。它允许在内存中操作 pdf。该库能够:

  • 提取文档信息,如标题、作者等
  • 按页面拆分文档
  • 按页面合并文档
  • 裁剪页面
  • 将多页合并成一页
  • 加密和解密 PDF 文件
  • 还有更多!

我们正在使用这个库将 pdf 文件逐页拆分,读取每页上的文本,并将文本发送到下一层/步骤。

import PyPDF2
pdfReader = PyPDF2.PdfFileReader(open('file.pdf', 'rb'))

2)初始化扬声器:

Python 有一个 pyttsx3 库,能够离线转换文本到语音。我们使用 pypdf2 库从 pdf 文件中读取的文本作为文本到语音转换引擎的输入。

import pyttsx3
speaker = pyttsx3.init()

3)播放有声读物:

使用 PyPDF2 实现从 pdf 文件中逐页提取文本。通过阅读文本并将其提供给 pyttsx3 扬声器引擎,循环浏览每一页。它将从 pdf 页面中大声读出文本。

循环处理 pdf 文件中的每一页,最后停止 pyttsx3 扬声器引擎。

for page_num in range(pdfReader.numPages):
    text =  pdfReader.getPage(page_num).extractText()
    speaker.say(text)
    speaker.runAndWait()
speaker.stop()

全面实施:

改变 pyttsx3 扬声器的声音、速率和音量:

你可以调整说话的速度和音量,并根据你的要求将配音从男声改为女声,反之亦然。

速率:

初始化 pyttsx3 库,使用getProperty(‘rate’)获取当前的语速。使用setProperty(‘rate’, x)改变说话速度,其中 x=100 为正常速度(1x)。

# Initialize the speaker
speaker = pyttsx3.init()rate = speaker.getProperty('rate')   
print(rate)speaker.setProperty('rate', 125)

声音:

初始化 pyttsx3 库,使用getProperty(‘voice’)获取当前说话者的性别。使用setProperty(‘voice’, voice[x].id)改变说话者的性别,其中 x=0 表示男性,x=1 表示女性。

voices = speaker.getProperty('voices')
print(voices)#changing index, changes voices, 0 for male
speaker.setProperty('voice', voices[0].id)#changing index, changes voices, 1 for female
speaker.setProperty('voice', voices[1].id)

音量:

初始化 pyttsx3 库,并使用getProperty(‘volume’)获取当前卷。使用setProperty(‘volume’, x)改变扬声器的音量。音量范围从 0 到 1,其中 0 是最小音量,1 是最大音量。

volume = engine.getProperty('volume')
print(volume)engine.setProperty('volume',1.0)

将语音保存到音频文件:

使用以下方法将音频输出(有声读物)保存到 mp3 文件。

engine.save_to_file(text, 'audio.mp3')
engine.runAndWait()

结论:

在本文中,我们介绍了一个基本有声读物的实现,它可以使用几行 python 代码阅读整本 pdf 书籍。为了获得更好的音频效果,您还可以调整扬声器库的声音、速率和音量。

有声读物的最终音频效果不是很好,因为文本在馈送到扬声器引擎之前需要一些预处理。

参考资料:

[1] PyPDF2 文档:https://pypi.org/project/PyPDF2/

[2] pyttsx3 文档:https://pyttsx3.readthedocs.io/en/latest/

感谢您的阅读

使用 PyCaret 2.0 在 Power BI 中构建您自己的 AutoML

原文:https://towardsdatascience.com/build-your-own-automl-in-power-bi-using-pycaret-8291b64181d?source=collection_archive---------4-----------------------

py caret——Python 中的开源低代码机器学习库

PyCaret 2.0

上周我们已经宣布了 PyCaret 2.0 ,这是一个开源的、Python 中的低代码机器学习库,可以自动化机器学习工作流。它是一个端到端的机器学习和模型管理工具,可以加快机器学习实验周期,帮助数据科学家变得更加高效和多产。

在本帖中,我们展示了一个分步教程,介绍如何使用 PyCaret 在 Power BI 中构建自动化机器学习解决方案,从而允许数据科学家和分析师在没有任何额外许可或软件成本的情况下,向他们的仪表板添加一层机器学习。PyCaret 是一个开源的免费使用的 Python 库,它提供了广泛的功能,可以在 Power BI 中工作。

在本文结束时,您将了解如何在 Power BI 中实现以下内容:

  • 设置 Python conda 环境并安装 pycaret==2.0。
  • 用 Power BI 链接新创建的 conda 环境。
  • 在 Power BI 中构建您的第一个 AutoML 解决方案,并在仪表板上展示性能指标。
  • 在 Power BI 中生产/部署您的 AutoML 解决方案。

Microsoft Power BI

Power BI 是一种业务分析解决方案,可让您在整个组织中可视化数据和共享见解,或将它们嵌入到您的应用程序或网站中。在本教程中,我们将通过将 PyCaret 库导入 Power BI 来使用 Power BI Desktop 进行机器学习。

什么是自动机器学习?

自动机器学习(AutoML)是将机器学习的耗时、迭代任务自动化的过程。它允许数据科学家和分析师高效地构建机器学习模型,同时保持模型质量。任何 AutoML 解决方案的最终目标都是基于一些性能标准最终确定最佳模型。

传统的机器学习模型开发过程是资源密集型的,需要大量的领域知识和时间来产生和比较几十个模型。借助自动化机器学习,您可以轻松高效地加快生产就绪型 ML 模型的速度。

【PyCaret 是如何工作的?

PyCaret 是一个用于监督和非监督机器学习的工作流自动化工具。它被组织成六个模块,每个模块都有一组可用于执行某些特定操作的功能。每个函数接受一个输入并返回一个输出,在大多数情况下,这是一个经过训练的机器学习模型。第二版中可用的模块有:

PyCaret 中的所有模块都支持数据准备(超过 25 种基本预处理技术,附带大量未经训练的模型&支持定制模型、自动超参数调整、模型分析和可解释性、自动模型选择、实验日志记录和简单的云部署选项。

https://www.pycaret.org/guide

要了解更多关于 PyCaret 的信息,点击这里阅读我们的官方发布公告。

如果你想开始使用 Python,点击此处查看入门笔记本示例库。

“PyCaret 通过为业务分析师、领域专家、公民数据科学家和经验丰富的数据科学家提供免费、开源和低代码的机器学习解决方案,使机器学习和高级分析的使用民主化”。

开始之前

如果您是第一次使用 Python,安装 Anaconda 发行版是最简单的入门方式。点击这里下载 Python 3.7 或更高版本的 Anaconda 发行版。

https://www.anaconda.com/products/individual

设置环境

在我们开始在 Power BI 中使用 PyCaret 的机器学习功能之前,我们需要创建一个虚拟环境并安装 pycaret。这是一个分为三步的过程:

步骤 1——创建一个 anaconda 环境

从开始菜单打开 Anaconda 提示符并执行以下代码:

conda create --name **myenv** python=3.7

Anaconda 提示符—创建环境

步骤 2 —安装 PyCaret

在 Anaconda 提示符下执行以下代码:

pip install **pycaret==2.0**

安装可能需要 15-20 分钟。如果您在安装时遇到问题,请查看我们的 GitHub 页面,了解已知问题和解决方案。

第三步——在 Power BI 中设置 Python 目录

创建的虚拟环境必须与 Power BI 链接。这可以使用 Power BI Desktop 中的全局设置来完成(文件→选项→全局→ Python 脚本)。默认情况下,Anaconda 环境安装在以下位置:

C:\Users\ 用户名\ AppData \ Local \ Continuum \ anaconda 3 \ envs \ myenv

文件→选项→全局→ Python 脚本

👉让我们开始吧

设置业务环境

一家保险公司希望通过使用住院时的人口统计和基本患者健康风险指标来更好地预测患者费用,从而改善其现金流预测。

( )数据来源 )

目标

根据数据集中的其他变量,如年龄、性别、体重指数、儿童、吸烟者和地区,训练和选择预测患者费用的最佳回归模型。

👉步骤 1-加载数据集

你可以直接从 GitHub 加载数据集,方法是进入 Power BI Desktop → Get Data → Web

链接到数据集:https://raw . githubusercontent . com/py caret/py caret/master/datasets/insurance . CSV

Power BI 桌面→获取数据→ Web

在超级查询中创建重复数据集:

超级查询→创建重复数据集

👉步骤 2-以 Python 脚本形式运行 AutoML

在 Power Query 中运行以下代码(转换→运行 Python 脚本):

**# import regression module**
from pycaret.regression import ***# init setup**
reg1 = setup(data=dataset, target = 'charges', silent = True, html = False)**# compare models**
best_model = compare_models()**# finalize best model** best = finalize_model(best_model)**# save best model**
save_model(best, 'c:/users/moezs/best-model-power')**# return the performance metrics df** dataset = pull()

超级查询中的脚本

前两行代码用于导入相关模块和初始化设置函数。设置功能执行机器学习中所需的几个必要步骤,例如清除缺失值(如果有的话)、将数据分成训练和测试、设置交叉验证策略、定义度量、执行特定于算法的转换等。

训练多个模型,比较和评估性能指标的神奇函数是 compare_models。它根据可以在 compare_models 中定义的' sort' 参数返回最佳模型。默认情况下,它对回归用例使用“R2 ”,对分类用例使用“准确性”。

其余的行用于最终确定通过 compare_models 返回的最佳模型,并将其保存为本地目录中的 pickle 文件。最后一行返回数据帧,其中包含模型训练的详细信息及其性能指标。

输出:

Python 脚本的输出

仅用几条线,我们就训练了 20 多个模型,该表显示了基于 10 倍交叉验证的性能指标。

最高性能模型梯度推进回归器将与整个转换管道一起作为 pickle 文件保存在您的本地目录中。稍后可以使用该文件在新数据集上生成预测(请参见下面的步骤 3)。

转换管道和模型保存为 pickle 文件

PyCaret 致力于模块化自动化的想法。因此,如果您有更多的资源和时间进行培训,您可以扩展脚本来执行超参数调整、集成和其他可用的建模技术。请参见下面的示例:

**# import regression module**
from pycaret.regression import ***# init setup**
reg1 = setup(data=dataset, target = 'charges', silent = True, html = False)**# compare models**
top5 = compare_models(n_select = 5)
results = pull()**# tune top5 models** tuned_top5 = [tune_model(i) for i in top5]**# select best model** best = automl()**# save best model**
save_model(best, 'c:/users/moezs/best-model-power')**# return the performance metrics df** dataset = results

我们现在返回了前 5 名的型号,而不是一个最高性能的型号。然后,我们创建了一个列表理解(循环)来调整顶级候选模型的超参数,最后 automl 函数选择一个性能最佳的模型,然后保存为 pickle 文件(注意,这次我们没有使用 finalize_model ,因为 automl 函数返回最终模型)。

样本仪表板

示例仪表板已创建。PBIX 文件上传到这里

使用 PyCaret AutoML 结果创建的仪表板

👉步骤 3-部署模型以生成预测

一旦我们将最终模型保存为 pickle 文件,我们就可以使用它来预测新数据集的电荷。

加载新数据集

出于演示目的,我们将再次加载相同的数据集,并从数据集中删除“charges”列。在 Power Query 中以 Python 脚本的形式执行以下代码以获得预测结果:

**# load functions from regression module**
from pycaret.regression import load_model, predict_model**# load model in a variable** model = load_model(‘c:/users/moezs/best-model-powerbi’)**# predict charges** dataset = predict_model(model, data=dataset)

输出:

Power 查询中的 predict_model 函数输出

部署电源 BI 服务

当您将包含 Python 脚本的 Power BI 报告发布到服务时,这些脚本也将在您的数据通过本地数据网关刷新时执行。

要实现这一点,您必须确保托管您的个人网关的计算机上也安装了 Python 运行时以及相关的 Python 包。请注意,由多个用户共享的本地数据网关不支持 Python 脚本执行。点击此处阅读更多相关信息。

本教程中使用的 PBIX 文件被上传到这个 GitHub 库:【https://github.com/pycaret/pycaret-powerbi-automl

如果你想了解更多关于 PyCaret 2.0 的信息,请阅读这个公告

如果您以前使用过 PyCaret,您可能会对当前版本的发行说明感兴趣。

使用 Python 中的这个轻量级工作流自动化库,您可以实现的目标是无限的。如果你觉得这有用,请不要忘记给我们 github 回购⭐️。

要了解更多关于 PyCaret 的信息,请关注我们的 LinkedIn 和 Youtube。

你可能也会感兴趣:

使用 PyCaret 在 Power BI 中进行机器学习
使用 PyCaret 在 Power BI 中构建您的第一个异常检测器
如何使用 PyCaret 在 Power BI 中实现聚类
主题使用 PyCaret 在 Power BI 中建模

重要链接

博客
py caret 2.0 发行说明
用户指南/文档 Github
stack overflow
安装 PyCaret
笔记本教程
贡献于 PyCaret

想了解某个特定模块?

单击下面的链接查看文档和工作示例。

分类
回归 聚类
异常检测 自然语言处理
关联规则挖掘

在 Keras 中构建自己的深度学习图像分类模型

原文:https://towardsdatascience.com/build-your-own-deep-learning-classification-model-in-keras-511f647980d6?source=collection_archive---------16-----------------------

从头开始构建自己的深度学习图像分类模型的直观指南

图 1:Pascal-VOC 数据集的分类示例

介绍

图像分类是近年来越来越受欢迎的人工智能领域。它有各种各样的应用:自动驾驶汽车,人脸识别,增强现实,…

在这篇文章中,你将学习如何建立一个深度学习图像分类模型,该模型能够在的 10 个步骤中检测出图像中存在哪些对象。

完整的代码可以在共享的 google collab 中找到,所以你可以在阅读文章的同时轻松地跟着编码。

读完这本指南,你会知道以下事情:

  • 如何建立一个为深度学习模型设计的编码环境?
  • 如何连接流行的影像分类数据集(Pascal VOC)
  • 如何使用 Keras & Tensorflow 的组合创建深度学习卷积神经网络
  • 如何使用数据生成器高效地训练深度学习模型
  • 如何评估数据生成器的性能

步骤 1:设置环境

请查看谷歌协作获取所需的软件包。

从零开始构建深度学习卷积网络需要巨大的计算能力。普通的笔记本电脑不具备处理这些请求的能力。

幸运的是,谷歌来拯救我们了!他们已经开发了一个在线 python 笔记本,给用户免费的计算能力。

您可以通过在笔记本电脑设置中选择 GPU 选项来启用计算能力功能。

步骤 2:导入数据

我们将使用 Pascal VOC 图像数据集用于我们的深度学习模型。

Pascal VOC 数据集是一个图像数据集,在 Kaggle 上的计算机视觉竞赛中非常受欢迎。

使用 Wget 包下载数据集。这个包获取数据并下载到你当前的工作目录。

import tarfile!wget -nc http://host.robots.ox.ac.uk/pascal/VOC/voc2009/VOCtrainval_11-May-2009.tar

最后一步,打开 tarfile 并提取它。

tf = tarfile.open("/content/VOCtrainval_11-May-2009.tar")tf.extractall()

干得好!现在,您已经成功地加载并提取了数据集。

图 1: VOC 数据集结构

步骤 3:加载数据

当前的数据结构对于构建深度学习卷积模型不是最优的。
因此,需要将数据转换成更可行的格式。

您提取的 Pascal VOC 数据集应该包含以下两个文件夹:

  • 注释:该文件夹包含所有关于图像标签的信息。
  • JPEGImages:该文件夹包含所有原始图像

创建两个列表:

  • 文件名:在这个列表中,你保存所有图片的文件名。例如“2208–001068 . JPEG”
  • 分类:在这个列表中,你保存了所有的分类标签。例如“自行车、沙发”
directory_annotations = '/content/VOCdevkit/VOC2009/Annotations'filenames = []
classification = []

遍历注释目录,提取文件名和标签,并将其添加到各自的列表中。

for xml_file in os.listdir(directory_annotations): # Save image for classification and their class label if os.path.isfile(xml_file):
    xml_tree = ET.parse(xml_file)
    root = xml_tree.getroot()
    imgname = root.find('filename').text.strip('.jpg')
    labels = []
    for obj in root.findall('object'):
    label = obj.find('name').text
    labels.append(label) filenames.append(imgname)
    classification.append(labels)

步骤 4:预处理

在这一步中,您必须对数据进行预处理:

  • 在训练和测试集中拆分文件名和它们各自的分类。
label_filenames_temp = os.listdir(directory_annotations)
filenames = []for lbl in label_filenames_temp:
    filenames.append(lbl.split('.')[0])filecount = len(filenames)indexes = []for index in range(filecount):
     indexes.append(index)training_indexes = indexes[:int(filecount*0.7)]
validation_indexes = indexes[int(filecount*0.7):int(filecount*0.9)]
testing_indexes = indexes[int(filecount*0.9):] 
  • 输出标签需要转换成数值,因为当输入和输出变量是数字时,深度学习网络表现得更好。
directory_images = '/content/VOCdevkit/VOC2009/JPEGImages'directory_annotations = '/content/VOCdevkit/VOC2009/Annotations'labelnames = preprocessing.LabelEncoder()labelnames.fit(["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"])
  • 图像大小调整为 224,224,3 格式。在基于 VGG16 模型架构构建深度学习网络时,文献综述对此提出了建议。(西蒙扬&齐瑟曼,2014 年)
def generate_from_xml(filename):label = np.zeros((20), dtype = 'float32')tree = ET.parse(os.path.join(directory_annotations, filename + ".xml"))raw_image = cv2.imread(os.path.join(directory_images, filename + ".jpg"))res_img = cv2.resize(raw_image, (224,224)) for elems in tree.iter():
         if elems.tag == "object":
            name = elems.find("name").text
            labelnr = labelnames.transform([name])[0]
            label[labelnr] = 1return label, res_img

第 5 步:数据生成器

在巨大的数据集上训练模型需要大量的 ram 内存。

如果你像我一样,没有超级计算机,你必须使用数据生成器。

数据生成器将小批量的数据提供给模型。这允许我们在没有大量内存的情况下训练我们的模型。

使用大数据集时,最好使用数据生成器(而不是购买更多的 ram 内存)。数据生成器的细节超出了本文的范围,但是如果您感兴趣的话,可以查看下面的链接

在下一个代码块中,创建一个 datagenerator 类实例,并调用它两次:

  • 一次用于训练集
  • 一次用于验证集

步骤 6:创建我们的模型

在此步骤中,您将构建分类卷积神经网络的架构。

模型架构基于流行的 VGG-16 架构。这是一个总共有 13 个卷积层的 CNN(CFR。图 1)。

下面的代码块表明您将按顺序构建模型。这意味着你会一层又一层。

model = Sequential()

你增加两个卷积层。
在卷积层,对图像应用多个滤波器以提取不同的特征。

给出的参数:

  • Input-shape:给定图像的形状应为(224,224,3)。

  • Filters:卷积层将学习的过滤器数量。

  • Kernel_size:指定 2D 卷积窗口的宽度和高度。

-填充:指定“相同”可确保卷积后空间维度相同。

-激活:这更多的是一个方便的论点。这里,我们指定哪个激活函数将在卷积层之后被应用。我们将应用 ReLU 激活功能。稍后将详细介绍。

model.add(Conv2D(input_shape=(224,224,3),filters=64,kernel_size=(3,3),padding="same", activation="relu"))model.add(Conv2D(filters=64,kernel_size=(3,3),padding="same", activation="relu"))

接下来,添加 1 个 maxpool 层。

池用于通过减少前一卷积层输出中的像素数量来降低图像的维数。

  • Pool_size= 2,2-->这是一个“矩阵”,它将检查输出并从中获取最大值

-跨距= 2,2-->池矩阵沿 x 和 y 轴移动的增量。

model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))

我们继续向我们的深度学习网络添加层。应用如上所述的相同逻辑。

model.add(Conv2D(filters=128, kernel_size=(3,3),padding="same", activation="relu"))model.add(Conv2D(filters=128, kernel_size=(3,3),padding="same", activation="relu"))model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))model.add(Conv2D(filters=256, kernel_size=(3,3),padding="same", activation="relu"))model.add(Conv2D(filters=256, kernel_size=(3,3),padding="same", activation="relu"))model.add(Conv2D(filters=256, kernel_size=(3,3),padding="same", activation="relu"))model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))model.add(Conv2D(filters=512, kernel_size=(3,3),padding="same", activation="relu"))model.add(Conv2D(filters=512, kernel_size=(3,3),padding="same", activation="relu"))model.add(Conv2D(filters=512, kernel_size=(3,3),padding="same", activation="relu"))model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))model.add(Conv2D(filters=512, kernel_size=(3,3),padding="same", activation="relu"))model.add(Conv2D(filters=512, kernel_size=(3,3),padding="same", activation="relu"))model.add(Conv2D(filters=512, kernel_size=(3,3),padding="same", activation="relu"))model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))

现在卷积的基础已经建立了。为了能够产生一个预测,你必须使卷积基的输出变平。

model.add(Flatten())

添加密集层。密集层将卷积基底的输出馈送给它的神经元。

参数:

-单位:神经元的数量

-激活功能:Relu

Relu 激活功能加速了训练,因为梯度计算非常简单(0 或 1)。这也意味着负值不会传递或“激活”到下一层。这使得只有一定数量的神经元被激活,这使得计算变得有趣。

model.add(Dense(units=4096,activation="relu"))model.add(Dense(units=4096,activation="relu"))

您添加了一个 sigmoid 层,以便将前一层的输出转换为概率分布。sigmoid 是多标签分类的理想选择,因此我们使用 sigmoid 代替 softmax 激活。

由 sigmoid 产生的概率是独立的,并且不局限于总和为 1。这在具有多个输出标签的分类中至关重要。

您将单位参数设置为 20,因为我们有 20 个可能的类。

model.add(Dense(units=20, activation="sigmoid"))

步骤 7:损失函数和优化器

在步骤 7 中,您必须编译模型。您使用 RMSprop optimier 来达到全局最小值。你设置学习率为 0.001。

RMSprop ,均方根 prop,是一个未发表的优化算法,但很受机器学习从业者的欢迎。它减少了垂直方向的波动,同时加快了水平方向的学习。这使得我们的模型更快地收敛到全局最小值。与常规梯度下降算法的主要区别在于梯度的计算方式。梯度的计算公式如下图所示。

你设置二元交叉熵损失作为你的损失函数。
建议将此损失函数用于多标签分类,因为属于某个类别的每个元素不应受到另一个类别的决策的影响。

model.compile(optimizer= keras.optimizers.RMSprop(lr=0.001), loss='binary_crossentropy',metrics=['accuracy'])model.summary()

第八步:模型训练

一旦模型性能在保留数据集上停止改善,就可以使用 earlystopping 方法来停止定型。
通过这种方式,您可以在监控过度拟合的同时自动获得完美的时期数。

你给提前停止的人下达指令,寻求验证损失的最小值。

早期停止方法仅在没有检测到进一步改善时停止训练。

但是,最后一个纪元不一定是性能最好的纪元。

因此,您也可以使用模型检查点方法。这将保存在基于验证损失的训练期间观察到的最佳模型。

filepath = "/content/drive/My Drive/MYCNN/CNN1505_v1.h5"earlyStopping = EarlyStopping(monitor='val_loss', verbose=0, mode='min', patience = 4)mcp_save = ModelCheckpoint(filepath, save_best_only=True, monitor='val_loss', mode='min')

现在,你将开始训练我们的深度学习神经网络。我们使用 keras 的 fit 生成器批量加载数据。这是必要的,因为我们的整个训练集不适合我们的内存。

您可以设置以下参数:

  • 使用多重处理:是否使用基于进程的线程
  • Workers:并行生成批处理的线程数。
history = model.fit_generator(generator=training_generator,
validation_data=val_generator,
use_multiprocessing=True,
workers=6,
epochs = 20,
callbacks=[earlyStopping, mcp_save])

当我们的培训结束后,您可以看到我们的培训和验证结果。绘制了两个指标:

  • 模型精度
  • 模型损失

步骤 9:验证我们的模型

你可以看到模型很快从第一个时期的巨大训练损失收敛到更低的数字。
这种快速学习速率是由于所选优化器(RMS prop)的性质,它加快了收敛速度。
当该度量在四个时期内没有改进时,训练过程挑选具有最低验证损失的模型。

df = pd.DataFrame(history.history)
print(history.history.keys())# summarize history for accuracyplt.plot(history.history['accuracy'])plt.plot(history.history['val_accuracy'])plt.title('model accuracy')plt.ylabel('accuracy')plt.xlabel('epoch')plt.legend(['train', 'test'], loc='upper left')plt.show()# summarize history for lossplt.plot(history.history['loss'])plt.plot(history.history['val_loss'])plt.title('model loss')plt.ylabel('loss')plt.xlabel('epoch')plt.legend(['train', 'test'], loc='upper left')plt.show()

步骤 10:测试我们的模型性能

在我们的最后一步,我们在看不见的数据(测试集)上测试我们的模型性能。

打造自己的深度学习机器——你需要知道的

原文:https://towardsdatascience.com/build-your-own-deep-learning-machine-what-you-need-to-know-85c7a0a1604a?source=collection_archive---------5-----------------------

深度学习需要大量的计算,所以为了有效地训练深度学习模型,大多数人使用像 AWS 这样的云,或者在他们自己购买的硬件上进行训练。

我决定建立自己的机器,因为我在云上花了很多钱,并希望节省成本。介绍…战争机器!Warmachine 是一台非常有能力的机器,旨在承担从深度学习到强化学习的高级人工智能任务。Warmachine 是使用货架硬件的消费者构建的。

点击下面的链接,在电脑零件挑选处查看 Warmachine 的零件。

[## 保存的零件列表

编辑描述

pcpartpicker.com](https://pcpartpicker.com/user/learnedvector/saved/#view=f4c8Jx)

在这篇文章中,我将给出如何正确构建人工智能训练机器的技巧。最后,我将讨论构建自己的平台和使用云的优缺点。

如果你想看这个的视频版本,看看这个…

零件

所以 Warmachine 主要是为了解决深度学习和强化学习问题而建立的。我想要一台具有 4 个 GPU 的大量内核的机器,这样我就可以快速迭代训练我的机器学习模型。我的最终目标是最终拥有一台类似于 lambda quad 的机器,但不用支付 Lambda Quad 的价格。

用于 4 GPU RTX 2080 TI 机器的 Lambda Lab Quad

当 Warmachine 完成时,我将花费大约 7000 美元,比 Lambda Labs 便宜 4000 美元!

深度学习装备需要特定的组件,所以比平时更难在网上找到关于如何构建这些东西的可靠资源。让我们来看看你需要知道的所有知识,以构建你自己的深度学习机器。

国家政治保卫局。参见 OGPU

训练深度学习模型的核心是 GPU。GPU 在计算深度学习算法方面速度超快,因为与拥有非常少量复杂计算核心的 CPU 不同,GPU 拥有数百或数千个简单核心,在矩阵乘法方面超高效。GPU 用于深度学习最可靠的品牌是英伟达。大多数深度学习框架完全支持英伟达的 CUDA SDK,这是一个与他们的 GPU 接口的软件库。

当选择一个 GPU 时,为了让你的钱发挥最大的作用,你需要有张量核的东西。张量核是一种执行专门矩阵数学的处理核,使您能够使用半精度或混合精度训练模型。

这允许更有效地使用 GPU 内存,为更大的批量、更快的训练和更大的模型打开了大门。张量核可以在英伟达 RTX GPU 模型中找到。GPU 的内存需求取决于您计划训练的模型类型。

如果你只打算为嵌入式设备训练超小型模型,你可以用内存更少的 GPU。如果你计划训练更大的模型,比如 NLP 领域的 GPT,我会得到尽可能多的内存。

拥有更多的 GPU 内存为..你猜对了…更大的批量,更快的训练,更大的模型。如果你打算做一个多 GPU 设置,你需要使用吹风机式风扇或更昂贵的液冷选项。

你需要吹风机式的风扇,因为它们是为了将热量排出机箱,当你有多个 GPU 运行时,这是必要的。如果您没有鼓风机式风扇,您的系统可能会过热,并可能损坏您的硬件。

对于 Warmachine,我选择了华硕的 Nvidia RTX 2080 TI Turbo。它有 11GB 的 VRam 和鼓风机式风扇,可以在多 GPU 设置上实现更好的加热管理。我计划再买 3 个 GPU 来完成我的设置。

中央处理器

CPU 主要用于深度学习中的数据加载。CPU 上更多的线程意味着您可以并行加载更多的数据,以输入到您的模型中进行训练。如果你在大批量上训练,这是有用的,所以 GPU 不必等待 CPU 太长时间来加载数据。

如果你打算做强化学习问题,CPU 是很重要的,因为大部分计算将在你的学习环境中完成,而这很可能是在 CPU 上完成的。如果你使用强化学习的大型神经网络,那么 GPU 肯定有助于加快训练速度。

如果你只打算只做深度学习,那么确保你的 CPU 兼容你计划拥有的任何数量的 GPU。

选择 CPU 时,问问自己,这些问题…

  1. 你打算进行强化学习吗?如果你想要更快的训练,那么选择一个在基准测试中表现良好的高端 CPU。
  2. 你是不是只想做深度学习?然后,您可以使用更便宜的 CPU,但是更多的线程将有助于数据加载。
  3. 你计划有一个多 GPU 设置吗?然后确保你的 CPU 支持你想要的 GPU 数量。

Warmachine 将用于深度学习和强化学习,因此它配备了一个英特尔 i9–10920 x,它有 12 个内核和 24 个线程。它的时钟速度高达 4.8 GHZ,支持 4 个 GPU。我选择了英特尔,但是阅读了很多使用 AMD 芯片的人的成功故事,这对你的钱来说是一个更大的冲击。英特尔 i9–10920 x 是一款非常强大的 CPU,可以进行深度学习和强化学习,因此非常适合我的需求。

随机存取存储

一个很大的错误是认为你需要具有高时钟频率的最快的 RAM。高 Ram 时钟速度是一个营销噱头,最好的解释是由莱纳斯技术提示。更高的时钟频率在训练期间将显示出微不足道的改善,所以你的钱最好花在别的地方。

真正重要的是 RAM 上的内存量。你应该努力让你的内存至少和你的 GPU 内存一样多。我用的是 corsair 品牌,它的时钟速度为 2666Mhz,内存为 32 GB。当 Warmachine 完成时,我计划将它的内存增加到 128 GB,因为我特别喜欢这样。

母板

选择主板时,确保它有足够的 PCIe 插槽来容纳你想要的 GPU 数量。此外,确保 PCIe 插槽有足够的空间来容纳 GPU。通常,一个 GPU 将占用 2 个 PCIe 插槽的空间。此外,请确保主板与您的 CPU 和 RAM 兼容。

Warmachine 配备了一台华硕 WS X299 SAGE。这款主板支持 4 个 GPU。我唯一希望它有机载 wifi,但我使用以太网电缆连接,所以这不是太大的问题。

储存;储备

如果你想优化你的数据加载速度,你需要更快的存储,如固态硬盘。固态硬盘比标准硬盘更贵,因此为操作系统购买一个较小的固态硬盘,然后购买一个标准硬盘作为长期存储数据和模型的第二个驱动器是非常有用的。

训练的时候可以把感兴趣的数据转移到你的 SSD 上,加快数据加载速度。Warmachine 配备了 NVME 三星 970 Evo,操作系统存储空间为 1 TB。对于第二个驱动器,它有 8TB 存储的希捷 Exos 企业硬盘。

程序存储单元(Program Storage Unit)

对于电源单元,你需要有足够的功率来支持你的整个系统。一个很好的经验法则是将 CPU 和 GPU 所需的功率乘以 110%。

确定您的 PSU 有足够的 PCIe 连接器用于您的系统。Warmachine 配备了一个玫瑰将,1600 瓦 PSU。尽管我现在的设置不需要所有这些,但当它完成时,我会需要这么多,所以我继续购买了它以备将来使用。

冷却

你肯定需要一个 CPU 冷却器。为了降低风扇噪音,可以使用水冷装置。如果你有预算,你也可以看看液体冷却你的 GPU。这将构成一个超级安静的系统。如果你想坚持用空气冷却你的 GPU,确保你有鼓风机式的冷却,如果你计划有一个多 GPU 设置。Warmachine 目前配备了海盗船 H1 15i 专业这是一个 CPU 水冷却器。对于 GPU 来说,这只是股票鼓风机式的。

情况

当你选择一个箱子时,你可以选择任何你想要的东西,只要你的零件合适。我会建议买一个通风良好的箱子,因为我非常谨慎。我去了一个海盗船航空 540 ATX 中塔案件 Warmachine。它有充足的气流,看起来很酷,这和 Lambda 实验室使用的情况一样,为什么不呢?

确保你的零件合适

在装配钻机时,使用 PC 零件拾取器。它有一个功能,它会检查部件兼容性,这样你就不会完全搞砸你的构建。虽然它并不完美,因为它提醒我,我的零件并不适合我的情况,但一切都非常适合,所以在建造时将它用作指南针。

云与您自己的硬件

现在你们很多人可能会好奇,为什么要造我自己的机器?我就不能用云吗?是的,是的,你可以。但是建造你自己的机器也有好处,包括长期的成本节约。

这里有 3 个理由说明为什么建立自己的深度学习平台可能是值得的。

1.节约成本。如果你经常使用你的 GPU 进行训练,那么从长远来看,建造一台机器实际上可以为你省钱!如果你租一辆 v100,那大约是每小时 3 美元或者一个月 2100 美元!你可以用那个价格建造你自己的机器..并且永远保持下去!

2.你自己的硬件其实比云还快。这是因为由于虚拟化,云在实例和 GPU 之间的 IO 很慢。Bizon-Tech 做了一个实验来比较云和你自己的硬件,他们发现你可以买到更便宜的消费硬件。

您可以在这里看到,1080 Ti 接近 V100 的性能

3.拥有自己的钻机就像一台生产力机器,可以做任何你想做的事情。我可以用它在最大设置下玩游戏,为大家制作很酷的视频,并在 chrome 上打开 10 多个标签页!

奖励点:这里有一个奖励点。我喜欢不用担心每轮模特训练要花多少钱。我觉得当我必须为每轮训练付费时,我总是不愿意尝试,因为我知道这会让我花钱。我认为拥有自己的机器鼓励我继续尝试,从而帮助我比使用云更快地完善深度学习的艺术。现在有其他免费的 GPU 支持选项,如 Google Colab 或 Kaggle 内核,但你可以训练的时间有限,这缩小了我对模型和要解决的问题的选择。不过,我强烈推荐大多数刚开始深度学习的人使用它们。

结论

原来如此!这是一个关于如何构建自己的深度学习机器的简短指南。如果你想要一份更详细的指南,我推荐你去看看蒂姆·德特默斯指南。当 Warmachine 完成后,它将花费我大约 7k 美元,这仍然比 Lambda Labs 可比的机器 11K 美元便宜!对我来说,这是一个很大的省钱之道,完全值得你自己造一台机器。

✍🏽想要更多内容?查看我的博客https://www.michaelphi.com

📺喜欢看基于项目的视频?查看我的 Youtube

🥇注册我的 电子邮件简讯 ,了解最新文章和视频!

用变形金刚构建你自己的机器翻译服务

原文:https://towardsdatascience.com/build-your-own-machine-translation-service-with-transformers-d0709df0791b?source=collection_archive---------11-----------------------

使用 Transformers 库中可用的最新赫尔辛基 NLP 模型创建标准化的机器翻译服务

企业环境中需要机器翻译。全球公司能够用各种不同的语言与世界各地的人们共享文档、笔记、电子邮件和其他文本,这一点至关重要。

可以说,更重要的是需要在全球化的同时使信息民主化。不管你说什么语言,你都应该和那些主要语言被广泛使用的人一样,可以访问相同的开源出版物、医疗保健信息、工具和知识,比如英语。

我用 powerpoint 做了这个。太恐怖了。

幸运的是,机器翻译已经存在了一段时间——我们中的许多人已经使用谷歌翻译来确认在线内容,或者只是为了听起来聪明和世故。如果你的翻译需要规模,Azure、AWS 和 GCP 有每百万字符 10 美元的可消费 API,支持个语言对(一个语言对由源语言和目标语言组成)。

在开源领域,已经有大量跨多种语言的机器学习工作,人们早就能够训练自己的机器翻译模型。然而,就建模方法和支持的语言数量而言,大多数方法似乎是不同的(根据我自己天真的评估)。

最近, Huggingface 发布了来自赫尔辛基大学的超过1000 名预先训练好的语言模型。对于任何希望创建自己的 AWS 或 Google translate API 的人来说,这从未如此简单。所以,我想我应该利用别人的辛勤工作。这在功能上相当于“让我们把机器学习包装在一个 flask API 和 docker 映像中”,但是,不管怎样,这很有趣。让我们开始吧。

用变压器进行机器翻译

Huggingface 做了一件令人难以置信的工作,用一个简单的 Python API 为像我这样的复制+粘贴编码者提供了 SOTA(最先进的)模型。要在本地翻译文本,你只需要pip install transformers然后使用下面来自变形金刚文档的片段。

这将下载所需的模型并翻译源文本->目标文本。有了这种格式支持的语言的绝对数量,把它扔进一个 dockerized flask 应用程序并结束它是非常容易的,但是我们确实有一点额外的工作要做…

请随意跟进 git 回购

下载模型

当您初始化上面的模型时,如果您本地没有所需的文件,transformers 会下载它们。这对于本地使用来说是很棒的,但是在使用 docker 容器时就不是这样了。因为容器存储是短暂的,每次我们退出容器时,我们都会丢失所有的模型,并且需要在下一次重新下载它们。

为了避免这种情况,我们可以单独处理模型下载,并将模型作为一个卷挂载。这也给了我们更多的控制语言,我们希望我们的服务从一开始就支持。Huggingface 保存了 S3 所有必要的文件,所以我们可以将它标准化…

然后创建一个简单的命令行实用程序来下载它们:

酷毙了。现在我们可以用一个命令下载我们需要的模型。以下面的日语->英语为例。

python download_models.py --source ja --target en

默认情况下,这会将它们下载到一个名为data的目录中,所以只需检查以确保该目录存在。

Python 中的动态语言翻译

现在我们有了一个更好的方法来管理我们支持的语言,让我们来看看问题的实质,然后是一个类和相关的方法来管理我们的翻译。

这里我们需要几个函数:

  • 翻译给定源语言和目标语言的文本(duh)
  • 将我们没有的模型加载并管理到内存中(我使用一个简单的字典)
  • 获取支持的语言(我们为此应用下载了哪些语言?)

由于 transformers 的用户友好性,几乎不需要任何时间就可以将这种功能封装到一个轻量级的类中供我们使用。

这个类用我们用来保存模型的路径初始化,并自己处理其余的部分。如果我们收到一个翻译请求,但是我们的内存中没有这个模型,那么load_models就会被调用来把它加载到self.models字典中。这将检查我们data目录以查看我们是否有该模型,并返回一条消息让我们知道我们是否有。

使其成为 API

我们现在需要做的就是将它包装在 flask 中,这样我们就可以对它进行 HTTP 调用。

要使用它,只需运行python app.py,然后调用服务。要检查它是否工作,你可以curl localhost:5000或者使用更复杂的东西,比如 Postman。我在这里使用 flask 服务器,但是您会希望一个生产 web 服务器在任何实际的地方使用它。

用 Docker 图像包装它

现在,我们的应用程序可以与基本 Python 一起工作,我们希望它可以与 Docker 或 docker-compose 一起工作,这样我们就可以根据需要扩展它。我们实际使用的Dockerfile非常简单。我们只需要确保在附加了卷的情况下运行服务,这样它就可以访问数据了。

我通常会使用较小的基本映像,但老实说,我不喜欢调试:

构建和运行命令:

docker build -t machine-translation-service .
docker run -p 5000:5000 -v $(pwd)/data:/app/data -it machine-translation-service

同样,我们可以通过调用服务来测试我们的端点。如果我已经下载了一个像 en -> fr 这样的语言路径,那么我应该能够使用curl进行如下 API 调用:

curl --location --request POST '[http://localhost:5000/translate'](http://localhost:5000/translate') \
--header 'Content-Type: application/json' \
--data-raw '{
 "text":"hello",
 "source":"en",
 "target":"fr"
}'

现在是 docker-compose

我将我的服务包装在一个小 flask API 中,甚至“正确地”使它成为一个 Docker 容器,可以以可复制的方式扩展。但是,我想分享一下这种方法的一些问题。

这些翻译模型相当大(每一个都有 300MB)。即使数据/模型是单独下载的,我们仍然需要在内存中加载我们想要支持的每一个语言对——这对于一个容器来说很快就会失去控制。

因此,为什么不创建一个可配置的映像,我们可以使用 docker-compose 为每个服务创建一个容器呢?这样,每个语言对就有一个服务,并且每个语言对都可以随着需求的增加而单独扩展。然后,我们可以编写一个单独的、公开的 API,将请求传递给网络中的所有容器。

免责声明:在这一点上,我只是开始边走边编,我绝不相信这是最佳的方法——但我想看看我能走多远。

首先,我稍微修改了一下目录。为了验证这一点,您可以探索我创建的 git 上的分支:

proxy的目的是将请求重定向到每个运转起来的机器翻译服务。这将是唯一暴露的端点。我为支持 en - > fr 翻译的服务做了一个快速的docker-compose文件。

每个翻译服务都有相同的 env 变量(我可能只需要做一个.env文件),相同的命令,以及包含我们模型的相同的卷。可能有一个更好的方法,用yaml自动化或类似的东西来扩展这个,但是我还没有做到。

之后,我只是对我的代理的/translate端点做了一些难看的工作,以便按需构造所请求的服务端点。当用户向这个公开的服务发出请求时,它将向只能从该网络内部到达的其他容器发出另一个请求。

我们所要做的就是构建基础映像。

cd translation_base
docker build -t translation_base 

然后启动服务。

docker-compose up

还有吧嗒吧嗒吧嗒。下面是使用 postman 的输出截图。

最后是 Kubernetes

这里不打算深入探讨,但合乎逻辑的下一步是将它带到 kubernetes 进行真实的缩放。一个简单的起点是使用kompose CLI 将 docker-compose 转换成 kubernetes YAML。在 macOS 上:

$brew install kompose
$kompose convertINFO Kubernetes file "translation-proxy-service.yaml" created 
INFO Kubernetes file "en-fr-deployment.yaml" created 
INFO Kubernetes file "en-fr-claim0-persistentvolumeclaim.yaml" created 
INFO Kubernetes file "fr-en-deployment.yaml" created 
INFO Kubernetes file "fr-en-claim0-persistentvolumeclaim.yaml" created 
INFO Kubernetes file "translation-proxy-deployment.yaml" created

这应该会创建一些将服务和部署扩展到 K8s 所需的 YAML 文件。

下面是 fr-en 服务的示例部署:

一旦配置好 kubernetes 集群,您就可以kubectl apply -f $FILENAME创建您的服务、部署和持久卷声明。

当然,还有更多的工作要做,还有更多的 kubernetes 对象要创建,但我想在这里为任何真正希望扩展类似内容的人提供一个简单的起点。

结论

我希望 Huggingface 继续构建的工具(以及专门的研究人员训练的模型)继续提供智能机器学习的公平途径。开放机器翻译的努力不仅有助于研究领域,而且使全世界能够访问用单一语言编写的极其重要的资源。

我不知道自己托管这些庞大的模型是否比使用 AWS 或谷歌翻译 API 便宜一半,我也没有探索过质量。但这是一个超级有趣的话题,希望能给你提供一些见解,让你知道如何利用唾手可得的数以千计的 SOTA 机器学习模型。

用 Python 从头开始构建自己的神经网络

原文:https://towardsdatascience.com/build-your-own-neural-network-from-scratch-with-python-dbe0282bd9e3?source=collection_archive---------30-----------------------

了解神经网络的基础知识

娜塔莎·康奈尔在 Unsplash 上的照片

有许多 python 库可以用来构建和训练神经网络,如 Tensorflow 和 Keras。但要真正理解神经网络,我们需要了解它的基本结构,并能够建立和训练我们自己的网络。

与常规的机器学习算法相比,神经网络可以更好地学习数据。事实上,神经网络算法可以解释为一堆线性回归,其中每个节点都是一个线性回归的输出。

神经网络包括:

  • 一个输入层, x
  • 任意数量的隐藏层
  • 一个输出层, y`

在下图中,输入层有 3 个节点,下一层(隐藏)有 4 个节点,输出层有 2 个节点。输入层不包括在层数中,因此它是一个 2 层网络。

两层神经网络结构

两层中的每个节点都是一个线性回归的输出。在每一层,在执行线性回归之后,这些值被馈送到激活函数。

神经网络的基本算法应该是这样的。

for n epochs:
    1\. forward_propagation() #predicting output
    2\. backward_propagation() #updating parameters according to loss

函数名暗示了算法的基本结构。在本文中,我们将建立一个 2 层神经网络。

让我们看看我们将使用的常见命名约定。

Z是线性向前值,即Z = W.XA是节点激活,即A = sigmoid(Z)。我们将在网络中使用 sigmoid 激活函数。

1.初始化参数

首先,我们初始化神经网络的权重和层大小。

我们将变量定义如下:

  • [num_samples, n_x]:输入的形状
  • n_x:输入 X 的特征数
  • n_h:隐藏层节点
  • n_y:每个样本的目标值数量

让我们根据输入和输出值以及我们选择的隐藏层大小来初始化层大小。

然后,我们基于层大小初始化权重。

  • 在上图中,对于第一层,我们需要定义权重,以便能够计算 4 个(n_h)线性回归,下一层中的每个节点一个。
  • 所以第一层中的权重,W1应该是(3,4)(n_x,n_h)(对三个(n_x)输入特征的四个(n_h)线性回归)。

用这个类比,你可以很容易地猜出上面网络中权重W2的形状。

让我们定义初始化权重的函数。

2.正向传播

正向传播由一组线性回归和每层的非线性激活函数组成。

我们将使用 sigmoid 函数作为神经网络的激活函数。

一旦你得到正确的权重,前向传播是非常简单的。

输出= sigmoid((W2 * sigmoid(W1 * X+B1))+B2)

让我们定义我们的前向函数。

正向传播

3.反向传播

这是棘手的部分。反向传播相应地在损失最小化的方向上更新权重参数。我们将使用均方差(MSE) 损失来评估我们的网络。这个计算看起来很复杂,但实际上很简单。

损失函数的加权导数和 sigmoid 导数

这很简单,对吧?现在,让我们定义反向传播的函数。我们将计算梯度,并在向后的步骤中更新权重。

反向传播

4.培养

训练中的一个时期包括一个向前和向后传播步骤。

我们将使用来自sklearn.datasets模块的乳腺癌数据集。该数据集有 30 个特征和 569 个样本,并用隐藏层中的 4 个节点训练我们的网络 1000 个时期。

比较 10 个随机样本的预测值和输出值。

看起来我们的网络工作得非常好!

请注意,预测值与实际值略有不同。这是可取的,因为这意味着模型不会过度拟合,并且会更好地概括。

结论

在我们的神经网络中,我们在激活层使用了 sigmoid 函数。但是,根据问题的类型,还有其他的激活功能可能会有用。事实上,激活函数可以是你选择的任何函数,如果你认为这个函数非常适合我们试图解决的特定问题。但是神经网络中常用的激活函数可以在这里找到

构建您自己的开放式仪表板来跟踪新冠肺炎

原文:https://towardsdatascience.com/build-your-own-open-dashboard-to-keep-track-of-covid-19-f2b09e817320?source=collection_archive---------52-----------------------

跟踪对您自己的 RaspberryPi 有影响的派生指标

我们生活在一个相对前所未有的时代,因为今天活着的人(除了 1918 年左右的少数人)没有一个在他们生活的任何时候经历过疫情。这意味着,与任何其他情况相比,我们更有理由收集尽可能多的数据,以便做出更明智的决策。其中一部分是通过密切监测新病例、死亡和康复的数量,以及许多重要的指标(病毒扩散率、增长率、死亡率、达到 ICU 满负荷前的估计天数等)。)可以从那些数字中推断出来。

自从疫情开始以来,我已经看到世界各地的工程师和数据科学家做出了令人印象深刻的努力,提供可以帮助解决问题的工具。从 3D 打印的面罩,到 RaspberryPi+Arduino 驱动的呼吸机,到构建快速管道来处理大量基因组数据或计算病毒‘蛋白质’的结构,到构建 API 和仪表板来帮助共享数据,在疫情期间,各种类型的工程师都面临着大量挑战。

我将尝试再写几篇关于工程师和数据科学家如何在此时积极帮助世界的文章,从如何构建一个定制的仪表板开始,该仪表板在可用时自动提取关于传染的新数据,计算任何所需的派生指标,并将数据显示在 Grafana 仪表板上。收集尽可能多的关于这种疫情的准确数据对于有效地抗击它至关重要,同样至关重要的是计算并向最广泛的公众显示正确的衍生指标,以便更好地理解(或评估)政府的决策,或者比较世界上不同政策的不同国家如何产生不同的结果,或者甚至某个国家的病例数在实施某些措施前后如何变化。

我们将使用 PostgreSQL 存储数据(但是任何关系数据库都可以),使用 Grafana 显示数据,使用 platypush 填充数据并自动更新数据。不久前,我给写了一篇文章,讲述如何用这些工具构建你的定制仪表板,以存储和显示任何类型的数据(从你浴室中的湿度传感器到你一天中的位置)。可以参考一下,了解一下这些工具是如何配合使用的,以及如何入门。

问题 1:数据可用性和质量

新冠肺炎统计的第一个问题是公布数据的可用性和质量。首先,并不是世界上所有的国家都同样努力让尽可能多的人接受检测。第二,并非所有国家在报告所有数字时都具有相同的透明度或可靠性——包括恢复情况、死亡人数和进行检测的次数。在紧急情况下,可用数据的质量远非完美,这是完全可以预料的。虽然我们作为个人对数据的质量没有太多的控制,但我们仍然可以推断出有趣的信息,并根据手头的不完整数据建立模型。例如,可以查看每个人口单位进行测试次数最多的国家的数据,以更好地了解真实的死亡率和住院率。有可能将病毒扩散的时间线与政府采取措施的时间线重叠,以推断这些措施如何影响了疫情的扩散。考虑到该国现有的重症监护室床位数量,可以推断按照目前的增长速度,卫生系统达到满负荷需要多少天。考虑到这些模型是基于不完整的数据,所有这些信息都应该有所保留,但是根据不完整的数据做出的决策总是比没有数据的决策要好。

问题 2:数据可视化

像疫情这样的现象按照相对简单的指数定律传播。一般来说,时间 t增长率定义为 t 日确诊病例数与前一日 t-1 确诊病例数之比:

如果增长率保持不变(如果没有采取控制措施,情况大致如此),那么只需给出初始病例数和增长率,就可以估计第 t 天的病例数:

如果你关注过这一时期的任何新闻,你可能会经常听说另一个数字——R0,也被称为基本再生数。这是每个感染者携带病原体时感染的平均人数。增长率 γR0 相互关系如下:

其中 w(τ) 为疾病的 世代时间分布 (基本上是描述一个传播链中连续感染之间时间分布的概率密度函数)。如果我们有一个好的分布规律和关于增长率的准确数据,我们可以很好地估计疾病将传播多少,以及在采取一些行动后它的传播如何变化。

虽然数学定律相对简单,但我们很难理解这种现象究竟是如何发生的。在我们的日常经验中,我们非常习惯于涉及线性定律的现象。如果你把某样东西翻倍或减半,那么其他东西可能会翻倍或减半,或者增加/减少 4 倍,等等。对于我们来说,处理指数定律的现象通常更难描绘。这个术语在媒体上经常被滥用,这并没有什么帮助:大多数时候,你听到一个经济体、一个公司或一个行业的“指数增长”,你实际上听到的是一个任意大幅度的线性或多项式增长。

为了描述指数增长的真正含义,假设你的田里长了一些杂草,如果不加限制,它每天都会比前一天扩大一倍(换句话说, γ=2 )。假设这种杂草如果任其自由生长,需要 60 天才能覆盖整个田地。如果你应用上面的公式,你会发现在第 59 天,杂草只覆盖了一半的田地,在第 54 天,杂草只覆盖了大约 1.5%的田地。

指数增长现象的反直觉性意味着,在做决定时,我们不能只依靠我们的本能或共同的经验。这确实需要以正确的方式可视化正确的数据,以了解是否、何时以及如何控制疫情。以正确的方式看待数据也很重要。虽然你正处于指数增长曲线的中间,但仅仅通过观察线性范围内确诊病例的数量,很难判断增长有多“糟糕”。你只会注意到曲线增长了“很多”,但几个小数点的差异意味着在相对较短的时间框架内出现数十万或数百万的新确诊病例。对数标度给出了曲线实际增长多少的更好的图像,但它也能产生一种虚假的保证感。一条持续指数增长的曲线在对数标度上看起来像一条直线,所以你应该记住,一条在对数标度上持续增长甚至一点点的直线通常不是一个好兆头。

许多新的网站和仪表板出现在网络上,以跟踪这种疫情的传播,但尽管它们都在线性和对数标度上显示病例、恢复和死亡的累积数量方面做得相对较好,但它们缺乏一些派生指标的可视化,这些指标将真正有助于更好地掌握问题。例如,随着时间的推移,在某个国家对每单位人口进行了多少次测试,或者在给定的增长率和严重率下 ICU 床位达到满负荷需要多少天,或者死亡率/严重率如何随着被测试人口的比例而变化。这就是为什么我最终决定制作自己的开放式仪表板,以跟踪我希望跟踪的指标,按国家过滤,并且可以根据每个人的需求轻松定制。

问题 3: API 可用性

尽管已经有许多仪表板可以用来跟踪疾病的传播,但大多数仪表板都在后端呈现数据,没有公开任何 API。我个人非常喜欢 Worldometers 提供的数据质量和数量,它提供了许多其他仪表板上没有的数据(如每个国家人口的检测数量,住院病例数量等)。),但是我前面提到的一些派生指标并不容易获得,另外,也没有为数据提供 API。对于 platypush 集成,我最终选择了 covid19api.com提供的数据,即使它没有提供 Worldometers 上可用的许多指标——我仍然用 Worldometers 上发布的每日数据手动填充数据库中缺失的指标。作为下一步,我计划为 Worldometers 数据开发一个刮刀,如果你知道谁已经完成了这项工作,请让我知道:),对于那些开发这些仪表板的人,非常感谢你的工作,但也请确保公开一个 API,以便其他开发人员可以轻松地提取数据或将其集成到其他项目中。

设置环境

我们将使用三种工具来设置仪表板:

  • PostgreSQL(但是任何其他关系数据库都可以)
  • 格拉夫纳
  • 鸭嘴兽

仪表板可以在任何电脑上运行,包括 RaspberryPi。如果你想了解更多关于这些解决方案的信息,请参考我之前关于 PostgreSQL+platypush+Grafana 的文章。

我假设您的系统上安装了 PostgreSQL 或另一个 RDBMS,以及 Grafana。如果您的系统上还没有安装 platypush,您可以通过 pip 轻松安装:

pip install platypush

还要安装并启动 Redis,platypush 将使用它作为后端来传递消息。

设置数据库:

initdb -D covid19

然后创建我们将用来管理统计数据的表和触发器:

基本思想是将新的非规范化行转储到tmp_covid19_data表,然后让触发器管理数据的规范化,而视图vcovid19将用于连接和计算我们想要的派生指标。

然后,您可以使用一个利用 platypush Covid19 插件的简单 Python 脚本来填充您想要跟踪的国家的所有历史数据:

最后,配置 Covid19 后端来自动提取您感兴趣的国家的数据,方法是将以下代码行添加到~/.config/platypush/config.yaml:

backend.covid19:
    country:
        - nl
        - it
        - us
        - es
        - gb
        - cn
        - fr
        - ru

每当有这些国家的新数据时,platypush 就会触发一个[Covid19UpdateEvent](https://platypush.readthedocs.io/en/latest/platypush/events/covid19.html)。您可以用钩子捕获这个事件,并将新行存储在数据库中,但是您还可以做其他任何事情——发送通知、SMS 或设置任何类型的自动化。在~/.config/platypush/scripts下创建一个名为covid19.py的脚本(还要确保这个文件夹中有一个__init__.py文件,这样它就会被识别为一个包):

启动platypush服务。既然您已经获得了数据和更新数据的自动化,那么是时候去 Grafana 并创建一些面板来从vcovid19视图中提取和显示数据了。一些示例报告查询:

SELECT
  report_date AS "time",
  confirmed
FROM vcovid19
WHERE
  country = '<country name>' AND
  $__timeFilter(report_date)
ORDER BY 1

您可以将这些查询组合在一起,构建您喜欢的仪表板:

打造自己的小狗

原文:https://towardsdatascience.com/build-your-own-puppy-dc0a49febe7c?source=collection_archive---------77-----------------------

了解如何对小狗使用 Java Builder 设计模式

照片由乔·凯恩Unsplash 拍摄

设计模式是一个美丽的东西。他们接受普遍面临的软件开发问题,并为我们提供普遍接受的有效解决方案。

你知道还有什么是美丽的吗?小狗!

我们要用一件美好的事物来帮助我们理解另一件美好的事物。

如果没有简单的实现,理解这些设计模式可能会有点困难。

在学习构建器模式的工作原理时,我也遇到了同样的问题。在研究了这种模式的来龙去脉之后,我发现通过正确的解释,这个概念可以很快学会。

所以事不宜迟,让我们开始建立小狗!

目标

了解如何以及何时在 Java 应用程序中使用构建器设计模式。

设置

要跟随自己,我建议使用以下工具:

  • 您最喜欢的 Java IDE
  • JDK 8

如果你正在寻找一种快速的方法来开始使用 VSCode 构建 Java 应用程序,我写了下面的教程

什么时候应该使用构建器模式?

想象你是一个小狗收养中心的主人。您需要存储每只小狗的所有信息,以便在应用程序的其他部分使用。

你需要保存品种、年龄、名字,以及它是否符合健康要求。它可能看起来像这样:

Puppy.java

这很简单,对吧?我们用一个构造器创建一个类,这个构造器具有这四个属性中的每一个,并在每次有小狗进来时实例化一个新的实例。

Puppy pup = new Puppy (“Bichon Frise”, 9, “Andy”, true);

在一个完美的世界里,这将是一个很好的解决方案。但是我们并不是生活在一个完美的世界里,不是吗?

有时当这些小狗进来时,它们没有我们需要的所有信息。我们可能不知道它的年龄或是否接种过疫苗。或者可悲的是,我们可能不知道它的名字。

试图用稀疏信息构造这些对象可能看起来像这样。

Puppy pup2 = new Puppy ("Golden Retriever", false);
Puppy pup3 = new Puppy (true);
Puppy pup4 = new Puppy ("Yorkie", "Johnny", false);
Puppy pup5 = new Puppy ("Doge", 13);
Puppy pup6 = new Puppy ("Shitzu");

在 Java 中,您必须创建不同的构造函数来支持这些实例化。或者你可以使用null值来填充空白点。但那很乱。

此外,如果顺序与原始构造函数中定义的顺序不同,值可能会映射到错误的变量。这可能会在将来给你带来意想不到的运行时错误。

一定有更好、更灵活的方法来创建这些复杂的对象,对吗?

我们使用构建器模式。

小狗建造者

让我们建造一些小狗吧!(说起来有点奇怪。)

照片由卡斯滕·怀恩吉尔特Unsplash 上拍摄

本教程将是实现构建器模式的一个精简的、最基本的例子。

我们将从创建一个名为PuppyMain.java的主类开始。这个类是我们的切入点。

PuppyMain.java

接下来,我们将创建Puppy.java来存放我们的构建器代码并构建我们的小狗对象。

我将把它分成两个部分:T2 部分和 T3 部分。然而,这些都属于同一个Puppy.java级。如果您想查看整个班级,可以向下滚动到底部。

Puppy.java

这里,我们声明这些变量中的每一个都是不可变的。这意味着一旦它们被创建,就不能被改变。私有构造函数和 final 修饰符帮助我们实现了不变性。

创建新小狗的唯一方法是使用 PuppyBuilder。

我们将 PuppyBuilder 作为私有构造函数的一个参数,这样我们就可以将 Builder 变量映射到 Puppy 类变量。

现在让我们深入了解 PuppyBuilder 的核心:

Puppy.java

为了使这个对象尽可能灵活,我们将为每个变量创建一个单独的 setter。

如果我们想要任何必需的变量,我们可以这样定义构造函数内部的变量(其中breed必需的):

public PuppyBuilder(String breed){
  this.breed = breed;
}

但是,这只是在我们希望包含必填字段的情况下。在这个例子中,我们所有的字段都是可选的。

另一个注意:这个类是静态的,所以我们不需要在每次想要构建小狗的时候都创建一个实例。这将允许我们使用我们的建设者作为一个实用的方法;需要时随时可用。

以下是完整的文件:

这是一个使用我们的PuppyMain.java类中的 PuppyBuilder 创建不同小狗对象的例子。我们在这里利用流畅的界面。

根据维基百科的说法,流畅接口是“一种面向对象的 API,其设计广泛依赖于方法链接。”

您可以看到,无论我们向 PuppyBuilder 提供什么信息,当我们打印出每个对象的字符串版本时,它都得到了充分的处理。

回顾

实现 Builder 模式的代码有点冗长,但是我向您保证,它更容易阅读,并且会改进您的代码库。

尤其是对于下一个查看你的代码的开发者,他们将能够毫无问题地阅读你的代码。

巴拉蒂·坎南在 Unsplash 上拍摄的照片

如果您有任何问题、意见或顾虑,请随时留下您的意见。

我希望您喜欢学习如何使用小狗来实现构建器设计模式!

作为一个完全的初学者建立自己的网站:一本正经的指南

原文:https://towardsdatascience.com/build-your-own-website-as-a-complete-beginner-no-nonsense-guide-45f6db28880f?source=collection_archive---------16-----------------------

如何使用 Hugo+Github+Netlify 免费构建一个静态站点并使用自定义域托管它的分步指南

图片由 StartupStockPhotos 来自 Pixabay

我一直想写博客,拥有自己的网站,我终于做到了!感觉真好!

我从未想过自己会成为一名网络开发人员。老实说,web 开发本身及其背后的所有技术对我来说听起来很无聊。真正让我兴奋的是网站的设计部分。你如何做图形,互动,颜色,布局。你说吧。我认为一个网页设计师不仅应该精通技术,还应该是一个有创造性和艺术性的人,能够跳出框框思考:)

显然,我对 web 开发毫无头绪,从头开始学习 CSS、HTML 和 JS 的想法听起来也不太理想。我一直在谷歌上搜索,对所有的语言、平台和学习资源感到不知所措。如果你也有同样的感觉,不用担心。你并不孤单。相信我,你不必成为 HTML 和 CSS 专家就可以开始构建东西。一旦你知道了一些基本原理,你就可以边做边学了。

当你学习的时候,你可能不会从一个单一的来源学习, FreecodecampEdureka 是初学者学习 css、js 和 Html 基础知识的好地方。你也可以在 Udemy 上找到 Edwin Diaz 的这个惊人的 CSS 和 HTML 免费课程。这些是我的最爱。

在本文中,我将向您展示如何使用 Hugo + Github + Netlify 的组合来构建和部署静态网站。

得到💬任何数据科学或编程问题的 GPT 式答案。为成千上万的人生成摘要和学习笔记📚只需一次点击即可获得学习资源。👉

[## 面向数据科学家和开发人员的免费学习资源。精选的博客、教程、书籍和…

机器学习和人工智能工程师的培训课程、黑客马拉松、活动和工作

aigents.co](https://aigents.co/learn)

什么是静态站点生成器?

静态站点生成器是一个应用程序,它将使用 Markdown 语言编写的数据和内容应用到模板中,并以静态 Html 文件的形式生成页面视图,以便交付给访问者。应用程序本身可以用任何语言编写,例如,Ruby (Jekyll)、JavaScript 和 React (Gatsby)。我开始尝试盖茨比,因为它似乎有一个非常繁荣的社区。经过一个星期不断遇到 bug 和调试,我终于成功安装了盖茨比,下载了一个盖茨比网站的模板。然而,我最终决定使用 Hugo,这是一个用 go 编写的静态站点生成器,因为它非常用户友好,而且对我来说理解 go 并不是真正必要的。你可以在这篇文章中找到盖茨比和雨果的详细比较。

好了,说够了。我们开始吧!

第一部分。用 Hugo 建立你的静态网站

A .雨果装置

#1。安装巧克力

要在你的 Windows 操作系统上安装 Hugo,你需要确保你安装了 Chocolately,这是一个用于 Windows 的软件包管理器。参见此处的说明

#2。安装 Hugo 一旦安装了 Chocolately,打开您的终端,从那里,您可以简单地用下面的命令行安装 Hugo:

choco install hugo -confirm

对于 Mac 和 Linux 用户,请参见此处的安装指南。

太好了!现在你应该已经在你的系统上安装了 Hugo。让我们开始建立你的网站吧!

B .建立你的网站

#1。生成 Hugo 网站

接下来你需要做的是用 Hugo CLI 生成你的站点。打开您的终端,键入以下命令:

hugo new site your_project_name

将创建一个与您提供的名称(您的项目名称)相同的文件夹。您现在应该在 C:\ User \ Hugo \ Sites \ your _ project _ name 有一个目录。默认的文件夹结构如下所示:

以下是每个目录的高级概述:

Config.toml

这是 Hugo 站点的主要配置文件。在这里,您可以指定有关您的站点的信息,如站点标题和描述。查看配置文档了解更多细节。

内容

你的网站的内容,例如,你的博客文章和照片将存在于这个目录中。Hugo 中的每个文件夹都被视为一个内容部分。例如,如果您的网站有三个主要部分—博客、时尚和艺术—您将在内容目录中有三个子目录,包括博客、时尚和艺术。

布局

你可以为你的网站定义非常复杂的布局。你可以做很多事情。布局文件夹以。描述如何将内容视图呈现到静态网站中的 html 文件。

静态

这个目录存储所有的静态内容——不变的内容:比如 css 和 JavaScript。

主题

你可以下载一个预建的模板,并把它放在主题文件夹和 boom!你有你的网站。你当然可以按照你想要的方式来调整你的网站的主题。

#2。让网站在本地运行

在终端上的网站目录中,键入以下命令:hugo server

这个命令的作用是启动一个本地开发服务器,在你的机器上托管你的网站。

注意:如果您得到一个错误消息:错误:无法定位配置文件或配置目录。确保您位于包含 config.toml 文件的文件夹中。

现在,如果你打开浏览器: http://localhost:1313/,你应该会看到你的网站。你会得到一个白页,因为服务器正在运行,但还没有主题/内容。

#3。选择一个主题

作为初学者,我发现拥有一个模板并使用结构良好和格式化的代码非常有帮助。你总是可以按照你想要的方式修改你的网站。Hugo 非常用户友好,它允许你使用预先构建的主题。去雨果的主题网站,有数百个主题可供选择。都是开源的。点击演示,你可以看到网站的样子,并选择你的选择之一。

比方说,你想安装 hugo-scroll 主题,从你的终端的 hugo 项目目录中,键入以下命令:

git clone https://github.com/janraasch/hugo-scroll.git .\themes\hugo-scroll

(注意:如果开发服务器仍在运行,您需要按 Ctrl-C 来杀死它,这样您就可以回到 Hugo 目录)

现在,您应该会在网站文件夹的主题目录中看到一个名为“hugo-scroll”的目录。

#4。配置

接下来我们需要告诉 Hugo 我们想使用新安装的主题。将下面一行添加到 config.toml 中:

theme = “hugo-scroll”

如果您现在查看本地主机上的网站,您会看到主题被直接应用。这是因为雨果跟踪所有需要建立您的网站的文件,将重建网站,并迫使网页在您的网页浏览器重新加载每当您编辑一个文件。

我相信你会想改变网站模板中的东西,例如,你的网站的名称!让我们在您的文本编辑器平台中再次进入 config.toml 文件,在我的例子中,我使用 Sublime。也可以使用 VisualStudio 之类的另一个平台。您可以添加网站的标题。

顺便说一句,请务必阅读许可文件。它基本上说的是,如果你在主题中做了任何改动,而你遇到了麻烦,那么创建主题的人不会对此负责。

加入 中等会员 计划继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

[## 通过我的推荐链接加入媒体——蓝初

阅读兰楚的每一个故事(以及媒体上成千上万的其他作家)。你的会员费直接支持兰初…

huonglanchu.medium.com](https://huonglanchu.medium.com/membership)

第二部分。用 GitHub 和 netlify 托管你的网站

#1。找个地方存放你的代码

你需要一个 GitHub 账户。如果您还没有创建,请在这里创建一个。接下来要做的是在 Github 上创建一个资源库。转到存储库并单击“新建”:

接下来,通过转到您网站的目录并键入以下命令来上传您的网站文件夹:

git init

git add .

git commit –m “first commit”

git remote add origin <url_of_your_repository>

git push –u origin master

到目前为止,您应该可以在 git 存储库中看到 website 文件夹中的所有子文件夹。

#2。使用 Netlify 部署您的网站

Netlify 是一个 web 开发平台,为 web 应用程序和静态网站提供托管和无服务器后端服务。Netlify 连接到你的 github 账户,通过你的 git 库,将所有代码复制到 Netlify。之后,它处理并发布网站。请遵循以下步骤:

第一步。创建一个网络账户

第二步。将您的 Netlify 帐户与 Github 帐户连接。

第三步。在 Netlify 上部署您的站点。

你可以在 Netlify 的网站上找到详细的说明。在这个过程之后,Netlify 将为您创建一个有趣的默认 url — random_name.netlify.app。我的名字是:深情-赫尔曼-8298bf。点击链接,看看你的网站现在是活的!祝贺你!

#3。创建自定义域

当然,你会希望有自己的域名,而不是一个有趣的来自 Netlify 的随机名称!在这篇文章中,你可以找到为你的网站创建自定义域名的逐步指南。

更新您的网站

要更新您的网站,您可能需要在本地对您的网站进行更改。在将网站推送到 Git Repo 之前,您还可以在 http://localhost:1313/ 运行以下命令来查看网站的外观:

hugo server

我惊讶地看到,在不到一秒钟的时间内,这些更改就在您的本地计算机上更新了!很酷吧?要将您的更改推送到您的网站,您首先需要使用以下命令添加更改、提交并将其推送到您的 Git 存储库:

git add .

git commit -m "Updates website"

git push origin master

Netlify 将立即检测到您推送到 git repo 的更改,并返回到 Netlify 站点部署新的更改,这将在几秒钟内发生!请看下面的快照,Netlify 在同一分钟内完成构建、处理和发布。

结论

一个 Hugo 模板并不能构建一个完美的网站。然而,作为一个初学者,你可以先建立一个基于模板的网站,然后在此基础上学习更多的 HTML、CSS 和 GO 技巧。一步一步来。熟能生巧。

我希望这有助于学习,并给你一些动力来建立自己的网站。我很乐意看看你的网站,一旦你完成建设。请在评论中告诉我。

用英伟达泰坦 RTX 和 RYZEN ThreadRipper 构建一个价值 5000 美元的机器学习工作站

原文:https://towardsdatascience.com/building-a-5-000-machine-learning-workstation-with-an-nvidia-titan-rtx-and-ryzen-threadripper-46c49383fdac?source=collection_archive---------6-----------------------

3.8 GHz、24 核、64 GB、基于泰坦 RTX 的机器学习工作站

不是每个人都适合制造电脑。在高端,建立一个机器可以节省资金,并允许您准确地指定您希望的硬件。此外,随着更高级的组件变得可用或更经济,自定义计算机版本允许您计划和执行增量升级路径。这篇文章描述了我如何在 5000 美元(USD,2020 年 7 月)的价格范围内构建一个机器学习工作站。我还提供了一些建议来提高或降低这个价格。

我将从描述我的用例开始。我处理的任务可能是 GPU 或 CPU 密集型的。有时,我确实希望有大量的 RAM 用于数据处理和暂存。对于超出这台机器能力的内存需求,我通常使用 Spark 或 Dask。因为这些需求,我在 CPU、RAM 和硬盘访问上花费了相当多的钱。因为我的处理需求最常见的瓶颈是神经网络训练,所以我选择了高端 GPU。

机器规格和零件清单

我构建的计算机是一个 3.8 GHz(4.5 GHz 的加速时钟速率)24 核 AMD ThreadRipper (3960X),64GB 内存和一个英伟达泰坦 RTX 。在我创造计算机的时候,NVIDIA TITAN GPU 是有意义的。在这一点上,我建议看看 NVIDIA 30 系列,如 3080。我将完整的零件清单发布给电脑零件提货人。亮点包括:

硬盘足够快,程序加载非常快。此外,在内存和硬盘之间移动我的数据并不慢。我额外支付了更快的 RAM,希望加快 CPU 和 GPU RAM 之间的加载速度。进一步的基准测试将让我知道这有多好。

选择 GPU

GPU 是机器学习工作站的重要考虑因素。而机器学习工程师可能希望运行使用机器的图形潜力的复杂可视化;大多数现代 GPU 应该能够处理用户的图形需求。GPU 的数字处理能力是机器学习工作站的一个重要特征。对于游戏系统来说,应该在 AMD 和 NVIDIA 之间做出选择。对于机器学习,特别是深度学习,GPU 的选择真的只是英伟达。

CUDAOpenCL 是允许 GPU 充当软件数学引擎的功能。TensorFlow、PyTorch 等常用 CUDA,需要和 NVIDIA。OpenCL 更加开放,支持来自英特尔、AMD 和 NVIDIA 的 GPU。然而,由于各种原因,主要是性能原因,CUDA 得到了最广泛的支持。还有,NVIDIA 主导了 AWS 和 Azure 的云平台。谷歌云平台(GCP)确实提供了一种叫做张量处理单元(TPU)的替代技术;然而,TPU 在本地系统上并不常见。出于这些原因,尤其是云兼容性,我坚持使用 NVIDIA 的 GPU 产品。

NVIDIA 为游戏应用程序提供 GeForce GPUs,为更多以计算为中心的任务提供 Quadro。弥合这一鸿沟的是泰坦卡,它提供的额外内存往往比游戏更有利于深度学习;同时仍然提供与其最高端游戏 GPU 一样多的 CUDA 内核。NVIDIA 非常友好地给我的 YouTube 频道提供了一台泰坦 RTX。我决定,既然我得到了一个 2500 美元(2020 年 7 月)的 GPU,我就投资同样的金额,围绕这个神奇的 GPU 建立一个高级深度学习工作站。

英特尔还是 AMD

我希望我的工作站足够灵活,能够为以 GPU 和 CPU 为中心的任务提供高性能。基于 GPU 的深度学习有多伟大;我确实发现自己在使用 CPU 繁重的任务进行数据预处理和一些可视化。另外,由于我经常用 Python 编写自动化任务的代码;我能够利用多核技术来设计我的软件。除非你正在制造一台计算机,否则你很少能直接选择英特尔或 AMD 就像你有时被允许从硬件制造商那里选择 CPU 类型。

在观看/阅读了相当数量的关于英特尔 vs AMD 现状的报道后;我得出了以下结论。AMD 提供更多核心;然而以稍微降低的时钟速度。所以 AMD 在多线程软件上效率会更高。英特尔将在并行性较低的软件上更加高效,这些软件受益于更大的单核速度优势。因为我的大部分软件是多线程的,我可以选择设计自己定制的多线程软件,所以我选择了 AMD。

我选了一个 24 核的 AMD RYZEN ThreadRipper,适配一个 TRX4 插座,这是目前 AMD 最新的插座类型。这意味着我以后可以轻松地将我的 CPU 升级到更高级的 AMD 产品。传统上,我一直使用英特尔。我在 AMD 遇到的唯一小麻烦是,有时我必须等待最新的“微软内幕”预发布 Windows 版本。

操作系统选择

对于这台电脑,我决定用 Windows 10 Pro。我对微软的 Linux 子系统(LSU)能力印象非常深刻;尤其是现在 Linux 子系统可以访问底层的 GPU。我刚刚开始使用 LSU-2,所以我对这个系统的看法还在发展中。我希望在后面的文章和视频中发布更多关于 LSU 的内容。

与云的成本比较

在构建这台机器之前,我将我的大部分 GPU 工作负载发送到了云。我最常见的任务要么是 Kaggle 竞赛,要么是为我在华府大学深度学习课程重新运行和优化示例。这些工作负载的云成本并不小。为了将这台机器与 AWS 云进行比较,我使用了以下成本(截至 2020 年 7 月):

  • AWS 工作区:16 个 vCPU,122 GiB 内存,1 个 GPU,8 GiB 视频内存,每月 999.00 美元或每月 66.00 美元,每小时 11.62 美元。

上面引用的 AWS workspaces 实例比我的机器弱得多;然而,它是最接近的等效物。我有 24GB 的显存;而 AWS 机器只有 8 个。这可能需要对神经网络训练大小进行一些修改。此外,我有 24 个 CPU,而 AWS 上有 16 个,但 AWS 上的内存更多。在 999 美元/月,这是最有意义的重载,我会提前 5 个月出来。

如果你愿意围绕你的工作流程设计一些管道代码,并使用一些 AWS 专有技术,你可以通过使用 SageMaker 节省大量的 AWS 费用。我在这里不考虑 SageMaker 或 straight up EC2 实例,因为我正在寻找与我刚刚构建的系统最接近的桌面体验。

缩小比例

我敢肯定,阅读这篇文章的人都觉得我在这台机器上花了太多或太少。我曾经使用过基于特斯拉 V100 的先进系统,其造价是这台机器造价的 5 到 10 倍。如果你想少花钱,有很多选择。

其中最简单的就是审美。RGB 在系统构建者使用的组件中非常流行。你可以在下图中看到我的系统上的一些 RGB。不熟悉 RGB?任何发光的都是 RGB。

在计算机内部,发光的 RGB 组件

我是一个 Youtuber 用户,所以电脑是我“生活”中一个有趣的组成部分如果你打算把机器塞到桌子下面,买一个便宜但容易拿的箱子,不要用 RGB 组件。在这个构建的当前阶段,我在 RGB 方面有点失败。我有一个非常漂亮的 RGB RAM,被我真正有效的博格方块形状的“安静”冷却器所掩盖。不久的将来,我可能会把它换成液体 AIO 冷却器。

您可以缩减的零件:

  • 硬盘速度:实际上,硬盘速度只是将数据加载到 RAM,一旦数据进入 RAM,硬盘速度就变得不那么重要了。
  • RAM 速度:较慢的 RAM 也能让你过关。可能反正大部分处理都是在 GPU 上完成的。
  • CPU:对于机器学习来说,内核越多越好。内核越少,性能越差。
  • GPU : CUDA 内核决定你的 GPU 训练速度。GPU 内存决定了您需要对批处理和网络结构进行多大程度的切割才能运行某些东西。你不一定需要一个泰坦 RTX。

已完成构建的 YouTube 视频

我在 YouTube 上制作了这台电脑的视频。我的侄子内森协助建造。你可以在这里看到这个视频。

展望未来,我现在期待着对这个 GPU 进行基准测试,并使用它为我的 GitHub 资源库和 YouTube 频道制作出色的示例。请考虑关注我,查看所有最新内容。

使用 Python 构建条形码/QR 码阅读器

原文:https://towardsdatascience.com/building-a-barcode-qr-code-reader-using-python-360e22dfb6e5?source=collection_archive---------3-----------------------

使用 Pyzbar 库的简单且可实际操作的机器学习项目

马库斯·温克勒在 Unsplash 上的照片

在这篇文章中,我将向你展示如何使用 Python 来构建一个条形码和二维码阅读器。这是一个很好的机器学习项目,可以从计算机视觉开始。在我以前的文章中,我展示了如何使用 python 来识别人脸和文本。这些都是锻炼你技能的好项目。今天,我们将介绍一些稍微不同的东西,那就是条形码和 QR 码阅读器。

我认为条形码/二维码非常酷和有趣,因为它们以不同的格式存储信息。有趣的是,在我们扫描它们之前,我们无法真正知道它们存储了什么。就像玩益智游戏一样。我喜欢它们的另一点是,它们可以成为现实世界的一部分,并且仍然将我们与互联网世界联系在一起。这不是很酷吗?

目录:

  • 入门
  • 解码功能
  • 主要功能
  • 视频演示

[## 用 Python 构建人脸识别器

使用 OpenCv 库进行实时人脸识别的分步指南

towardsdatascience.com](/building-a-face-recognizer-in-python-7fd6630c6340)

入门指南

如果您想知道条形码和二维码阅读器是如何工作的,让我们做一个快速的实际练习。打开手机摄像头,显示这篇文章的特色图片。你会看到一个链接显示出来,这是非常简单的使用。今天,我们将创建我们自己的阅读器,马上开始吧!

我们将从安装这个项目所需的库开始,然后开始编程。对于这个项目,我建议使用常规的代码编辑器,而不是 Jupyter 笔记本。

图书馆

在这一步,我们将安装以下三个库:Pillow、OpenCV 和 Pyzbar。枕头库也被称为 PIL,代表 Python 图像库。OpenCV 是一个众所周知的库,尤其是在处理计算机视觉项目时。最后是 Pyzbar,它是一个 python 库,可以帮助我们读取条形码和二维码。让我们开始安装它们。

枕头

官方文件可以在这里找到。

pip install Pillow

OpenCV

OpenCV(开源计算机视觉库)是一个开源的计算机视觉和机器学习软件库。OpenCV 旨在为计算机视觉应用提供一个公共基础设施,并加速机器感知在商业产品中的应用。

参考:【https://opencv.org

pip install opencv-python

皮兹巴尔

Pyzbar 库的安装因您使用的计算机而异。我将显示 Mac OS 和 Windows 安装行。你也可以从 Pyzbar 的官方文档页面了解更多。

# Mac OS version
brew install zbar# Windows OS version
pip install pyzbar

解码功能

在这一步,我们编写解码函数,大部分酷的事情将在这里发生。解码功能将主要做三件事,可列举如下:

  • 识别和解码我们将展示给摄像机的条形码/QR 码。
  • 将存储的信息作为文本添加到识别的条形码/QR 码上。
  • 最后,将存储的信息导出为文本文档。

让我们在写入函数之前导入我们安装的库:

#import librariesimport cv2
from pyzbar import pyzbar

现在,让我们写函数。我不会一部分一部分地添加,而是将整个功能分享给你。因为在用 python 编写时缩进很重要,所以我不想通过破坏代码的结构来打乱事情。我将在代码下面添加我的注释。

def read_barcodes(frame):
    barcodes = pyzbar.decode(frame)
    for barcode in barcodes:
        x, y , w, h = barcode.rect #1
        barcode_info = barcode.data.decode('utf-8')
        cv2.rectangle(frame, (x, y),(x+w, y+h), (0, 255, 0), 2)

        #2
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, barcode_info, (x + 6, y - 6), font, 2.0, (255, 255, 255), 1) #3
        with open("barcode_result.txt", mode ='w') as file:
            file.write("Recognized Barcode:" + barcode_info) return frame

了解功能:

  • 首先,我们从条形码或 QR 码中解码信息。然后在它周围画一个矩形。这有助于我们了解我们的机器是否检测到条形码/二维码。
  • 其次,我们在创建的矩形上添加文本。文本将显示解码的信息。
  • 第三,我们将信息导出到文本文档中。如果您计划使用多个条形码或 QR 码进行测试,我建议您更改文档名称,否则它会被覆盖。

主要功能

在这一步中,我们将编写主函数,其中应用程序被提示工作。main 函数将打开计算机的摄像机,然后调用解码函数。代码如下:

def main(): #1
    camera = cv2.VideoCapture(0)
    ret, frame = camera.read() #2
    while ret:
        ret, frame = camera.read()
        frame = read_barcodes(frame)
        cv2.imshow('Barcode/QR code reader', frame)
        if cv2.waitKey(1) & 0xFF == 27:
            break #3
    camera.release()
    cv2.destroyAllWindows()#4
if __name__ == '__main__':
    main()

了解功能:

  • 首先,我们使用 OpenCV 打开计算机的摄像头。如果您有一个外部摄像头,您必须根据设备将值 0 更改为 1。
  • 其次,我们运行一个 while 循环来继续运行解码功能,直到按下“Esc”键。否则,循环将不会停止并导致一些问题。
  • 第三,我们正在释放我们在第一步中打开的摄像机。然后我们将关闭应用程序窗口。OpenCV 正在做所有的工作,我们只需要调用方法。
  • 最后,我们调用主函数来触发程序。

完美!我们已经完成了编程部分。让我给你看一个快速演示,看看我们运行程序时它是如何工作的。

视频演示

测试程序

[## 加入我的介绍链接媒体-贝希克居文

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

lifexplorer.medium.com](https://lifexplorer.medium.com/membership)

恭喜你。!您已经创建了一个程序,可以为您读取条形码和 QR 码。现在,你已经知道如何在现实生活中使用计算机视觉和人工智能。从事像这样的动手编程项目是提高编码技能的最好方式。如果你今天学到了新东西,我会很高兴。

如果您在执行代码时有任何问题,请随时联系我

关注我的博客youtube 频道以获得灵感。谢谢你,

使用 GitHub 创建漂亮的静态网页

原文:https://towardsdatascience.com/building-a-beautiful-static-webpage-using-github-f0f92c6e1f02?source=collection_archive---------26-----------------------

查找模板和为静态网页创建表单的位置

使用 GitHub Pages 托管的我的个人网页

你有没有想过建立自己的网页?也许你对 HTML 有一些经验(你好 Myspacers),也许你没有。这篇构建自己网页的教程是对 GitHub 页面教程的延伸。本文将介绍从哪里获得 HTML 模板以及如何创建动态表单,以便其他用户可以在您的 GitHub Pages 站点上连接到您。如果你正在经营一个有大量网络流量的大企业,我不推荐使用 GitHub 页面,因为静态网页的功能有限。对于个人网页或小型企业,GitHub 页面是一个很好的选择。TL;博士在总结的底部。

创建网站的步骤

  1. 查看该域名是否可用:我推荐使用域名搜索工具,比如 Whois.net。此工具允许您查看该域是否可用或谁拥有该位置。有些域名不包括域名所有者信息,而是有域名托管站点的联系信息。
  2. 购买域名:你可以通过任意数量的网站购买可用的域名。我会避免购买域名从另一个人或更糟,域名停车公司。
  3. 设置 GitHub: 对于不熟悉的人来说, GitHub 是一个版本控制的代码库。简单来说就是云端的代码备份。您可以注册一个电子邮件地址,并完成如何创建存储库的教程。存储库是你存储网站资料的地方。一旦您能够创建一个存储库,您将添加您的模板材料。在创建模板之前,我们可以将存储库连接到 GitHub 页面。为此,请单击位于存储库屏幕右上角的设置选项卡。向下滚动到标题为 GitHub 页面的部分。编辑 Source 选项卡,将存储库附加到 Github 页面。再次向下滚动到 GitHub 页面部分。您现在可以选择使用 Jekyll 添加模板。
  4. 编辑模板: Github 和 Jekyll 一起提供了一个简单的 HTML 模板。Jekyll 很棒,可能适合你的网站设计需求,但是我喜欢从 HTML5 到的模板。您可以下载一个模板,将其解压缩,然后通过单击绿色克隆或下载按钮旁边的上传文件按钮,将文件直接添加到您的存储库中。您可以通过简单地拖放文件将模板直接添加到存储库中。编辑模板以个性化您的网页。
  5. 将您的存储库连接到您的域(棘手的部分):再次点击 settings 选项卡,向下滚动到 GitHub 页面。在自定义域部分输入您的域,然后单击保存。此更改将在您的存储库中创建一个 CNAME 文件。转到您购买域名的网站,并导航到您可以管理域名设置的位置。你正在寻找一个像 CNAME,A,或 NS 项目的屏幕。将 CNAME 更改为指向您的 GitHub 页面库。这个名字可以在 GitHub Pages 部分的文本“自定义域允许您从 *your-repository.github.io* 以外的域为您的站点提供服务”下找到。您可以将 A 名称更改为指向 GitHub Pages 服务器。我会把 GitHub A 的四个名字都加上:185.199.108.153 | 185.199.109.153 | 185.199.110.153 | 185.199.111.153。在 GitHub 页面标签下有一个强制 HTTPS 的复选框。出于安全原因,如果可以,请选中此框。
  6. 在静态网页上创建动态联系表单: GitHub 页面非常适合静态网页(也就是说,如果你不做更改,它们就不会更新),但是,如果你想添加一个需要第三方帮助的联系表单。查看 Formspree.io,了解如何向 html 文档添加表单模板的教程。基本上,你用 html 创建一个表单或者使用他们的模板,然后指向你的账户链接。html 将包括类似于<form action="https:formspree.io/yourformlink" method="POST"的东西,后跟你的表单和 html 标签来关闭所有东西。下面是一个 HTML 格式的示例要点。

概述

这就是使用 Github Pages 创建个人网页的要点。探索杰基尔HTML5 UP 上的一些模板。对于那些想要一些动态内容的人来说,比如联系方式,使用第三方如forms spree . io将你的电子邮件链接到静态网页。我用这些方法创建的网站包括我的个人网站codyglickman.com和我的初创公司 Data Dolittle 的网站datadolittle.com。感谢 Formspree.io 的 Cole 让我在静态页面上创建 html 表单变得简单。你可以在 LinkedIn 上找到我。感谢您与本文互动!如果您有任何问题或意见,请留言或通过我的个人网站与我联系。

从头开始构建图书推荐引擎并将其部署到 Web 应用程序中

原文:https://towardsdatascience.com/building-a-book-recommender-engine-from-scratch-and-deploying-it-to-a-web-application-eea029c4c1fb?source=collection_archive---------9-----------------------

概述了在完全部署的 web 应用程序中使用 Spark、Databricks 和 Flask 的分布式计算构建图书推荐系统的过程。

照片由思想目录Unsplash 上拍摄

不管我们喜不喜欢,电子商务系统正在渗透我们生活的方方面面。从你的网飞个人资料上的标题下的一长串节目和电影,到 Spotify 上的为你制作的歌曲列表,我们已经进入了一个内容、媒体和信息都是根据我们独特的兴趣定制的时代。

虽然这可能是常识,但可能不太明显的是在幕后发生了什么来向用户提供这些推荐。我们经常听说“算法”和“机器学习”构成了这些系统的主干,但除此之外,我们通常将其余部分留给想象。

最近在研究生院上了一堂推荐系统课后,我开始钻研这些引擎背后的线性代数和软件。在课程的最后两周,我觉得我已经有足够的知识来构建一个完整的生产 web 应用程序,利用 PySpark 的分布式计算能力PostgreSQLDatabricksFlask 向用户推荐书籍。

如果对改编项目感兴趣,可以在我的 GitHub 上找到代码,并且可以在单独的 repo 中找到我的最终项目的描述,包括探索性分析和 ALS 算法在生产中的示例

我也在这篇文章的末尾添加了网络应用程序链接,但是如果你想创建一个帐户,并开始对书籍进行评级/接收书籍推荐,你可以在这里加入:https://zach-book-recommender.herokuapp.com/

推荐系统如何工作?

现在,在我们看一看我自己的引擎之前,提供一些关于这些系统的总体主题的背景可能是有帮助的。在非常基本的层面上,推荐系统通过机器学习算法来运行。通常,这些算法可以分为两类——基于内容的和协同过滤。

基于内容的方法测量项目属性的相似性,并根据用户以前的行为或明确的反馈(即通过调查或评级)重点推荐与用户喜欢的类似的其他项目。

尽管基于内容的方法在某些情况下非常有效,但它们也有缺点。协同过滤方法操作方式不同,尽最大努力解决基于内容过滤的一些局限性。通过协同过滤,算法同时使用用户和项目之间的相似性来提供推荐。本质上,底层模型被设计为基于相似用户 b 的兴趣向用户 A 推荐一个项目

降维和矩阵分解

协同过滤可以通过多种方式实现,然而,一种常见的方法是使用矩阵分解和维度缩减技术。交替最小二乘法(ALS)、奇异值分解(SVD)和随机梯度下降(SGD)等算法在这方面做得很好,当处理大量数据(即 1M 以上的数据点)时,这些算法与分布式计算和并行处理相结合,是构建具有大量数据的生产就绪型应用的良好解决方案。

如果您有兴趣了解更多关于这些技术的知识,我推荐您阅读这些优秀的 TDS 文章:

有了这些算法如何工作的一些基本知识,我将投入到我自己的项目中,使用 ALS 向用户提供图书推荐。

我的应用程序如何工作

在深入构建应用程序的每个组件之前,我将概述它如何工作的总体流程,以及在 Flask web 应用程序中向用户提供推荐所使用的技术:

将我的 Flask 应用程序与 PostgreSQL 和 Databricks 集成,每小时运行一次我的 ALS 模型,向用户提供图书推荐|作者图片

正如我们所看到的,这是一个非常复杂的系统,它严重依赖 Spark 中的分布式计算来处理大约 100 万本书的评级,并每小时为用户计算更新的推荐。它还依赖于部署的 PostgreSQL 数据库和包含我的 ALS 算法的 Amazon Web Services 集群之间的重要连接。

有了上面建立的总流程,我们现在可以分解构建引擎的每个步骤。

识别用于最大似然计算的高质量用户项目数据集

作为第一步,必须找到一个大的用户手册数据集,它将与我选择的算法很好地配合,并将向用户提供可靠的预测和建议。

所以我做了一些探索性的分析,决定用goodbooks-10k dataset根据 Kaggle 的说法,这个数据集包含了一个流行图书平台 Goodreads 上的 1 万本不同书籍的近 100 万个评分。有了这个数据集,我注意到了一些事情:

  • 该数据集包含总共 53,425 个用户,他们为至少 10 本书提供了评级。
  • 图书的平均评分约为 3.85 分,在李克特量表 1 到 5 分中,4 分是最常见的。因此,大多数评级都相当正面。
  • 正如所料,数据集非常稀疏( ~99.82%的评级文件为空白)。
  • 数据集中一些最受好评的书籍是家喻户晓的,包括部分卡尔文和何拔斯的收藏哈利波特,以及一些带有宗教原则的书籍

要考察一些这种探索性的分析,你可以去 本 jupyter 笔记本

构建和部署网络应用

接下来,在做了一些探索性分析之后,我决定构建一个简单的 python Flask 应用程序 ,以便允许新用户做以下事情:

  • 使用特定用户名注册/登录
  • 加载一个个人资料页面,该页面显示用户已评级书籍的历史记录,并提供导航以对更多书籍进行评级或查看推荐书籍(参见下面的示例):

图书推荐者个人资料页面|作者图片

  • 加入一个搜索功能,它与 Goodreads API 交互,允许用户按书名搜索一本书,然后在 1-5 的范围内给这本书打分(见下面的例子):

在 web 应用程序|作者图片中提交评级

  • 在对几本书进行评级后,用户可以在单独的页面上看到他们的个性化推荐(将在本文后面显示)。

值得注意的是,这些来自应用程序的用户评级随后被合并回稳健的 goodbooks 数据集,并最终合并到 ALS 算法中。通过建立 PostgreSQL 数据库,我能够将新的用户 id、他们的评级和图书 id 与这个原始数据集进行匹配。因此,每当一个新的评级来自一个用户,它就被附加到我后来用于推荐引擎的评级数据集中。

在本地做了大量测试以确保图书 id 和用户 id 在数据库中匹配之后,我用 Heroku 部署了应用程序。

用于 Flask 和 PostgreSQL 部署的资源

关于如何使用 Heroku 部署 Flask 应用程序和相应的 PostgreSQL 数据库的说明,您可以 参考这个非常有用的 YouTube 教程 ,作者是 Brad Traversy 。使用 Heroku 部署的细节也可以在这个 中找到

使用 Databricks 和 PySpark —开发我的 ALS 算法

随着应用程序功能的设置和部署,我使用 Databricks 和 Pyspark 构建了一个交替最小二乘(ALS)算法,该算法从我的 PostgreSQL 数据库中吸收我的评分数据集,根据 Databricks 中建立的矩阵分解技术计算更新的预测,然后根据每个用户的最高预测分数向每个用户推荐图书。

下面的一小段代码概述了这一过程:

首先,在从 PostgreSQL 读取 ratings 表之前,我为 Spark 数据帧设置了一个模式:

**from** **pyspark.sql.types** **import** StructType, StructField
**from** **pyspark.sql.types** **import** DoubleType, IntegerType, StringType

ratings_schema = StructType([
  StructField("col_id", IntegerType()),
  StructField("userid", IntegerType()),
  StructField("rating", DoubleType()),
  StructField("book_id", IntegerType()),
  StructField("username", StringType()),
  StructField("isbn10", StringType())
])

然后,在设置了我们的环境变量和到我的远程 PostgreSQL 数据库的 JDBC 连接之后,我读入表并将其保存为 Spark 数据帧:

remote_table = spark.read.format("jdbc")\
  .option("driver", driver)\
  .option("inferSchema", ratings_schema) \
  .option("url", url)\
  .option("dbtable", table)\
  .option("user", user)\
  .option("password", password)\
  .load()

将 Spark 数据帧加载到 Databricks 后,我开始设置数据来运行我的 ALS 模型。首先,我将数据框架分成训练、验证和测试数据集——60%训练,20%验证和 20%测试。验证数据集用于测试我的模型参数的微调,并允许我有一个保留测试集,用于计算最终优化模型的均方根误差(RMSE)。

(training, validation, test) = remote_table.randomSplit([0.6, 0.2, 0.2]) *# caching data to cut down on cross-validation time later* training.cache() 
validation.cache() 
test.cache()

通过数据分割,我对模型进行了一些微调,以确定最佳参数。然后,我用这些最佳参数运行 ALS 模型,并将其拟合到训练数据集。

als = ALS(maxIter=10, regParam=0.20, userCol="userid", itemCol="book_id", ratingCol="rating", coldStartStrategy="drop", nonnegative = **True**, implicitPrefs = **False**).setRank(50)model = als.fit(training)

您会注意到,我将矩阵的秩设置为 50,这减少了处理时间,并且仍然产生有价值的预测。然后,我能够使用这个模型来计算测试数据集的预测,并确定 RMSE 值。

predictions = model.transform(test)
rmse = evaluator.evaluate(predictions)

最后,我能够得到大约 0.9 的 RMSE 值,这对于我们的目的和 1-5 的李克特量表来说,还不算太差。然后,我能够使用该模型为完整的评级数据集生成预测和建议。为此,我使用 PySpark 中的recommendForAllUsers()函数,为每个用户找到 10 本评分最高的书。

ALS_recommendations = model.recommendForAllUsers(numItems = 10)*# Temporary table* ALS_recommendations.registerTempTable("ALS_recs_temp") clean_recs = spark.sql("""SELECT userid,                             bookIds_and_ratings.book_id AS book_id,                             bookIds_and_ratings.rating AS prediction                         FROM ALS_recs_temp LATERAL VIEW explode(recommendations) exploded_table AS bookIds_and_ratings""")clean_recs.join(remote_table, ["userid", "book_id"], "left").filter(remote_table.rating.isNull()).show()

clean_recs_filtered = clean_recs.select("userid", "book_id", "prediction")

在创建了一个临时表来重定向推荐之后,我希望确保用户在应用程序中评价(并隐式阅读)的书籍不会在应用程序中被推荐给他们。因此,我做了一些额外的清理,只向用户推荐新书:

new_books = (clean_recs_filtered.join(remote_table, ["userid", "book_id"], "left").filter(remote_table.rating.isNull()))

最后一步,我只确定了通过我的应用程序注册的用户 id,以便将推荐附加回 PostgreSQL 数据库。因为最初的 goodbooks 数据集中有如此大量的预测和评级会返回到不存在的用户,所以我过滤了这些数据,只包括对通过 web 应用程序加入的用户的推荐:

new_books_fnl = new_books.select('userid', 'book_id', 'prediction')

new_books_users = new_books_fnl.filter(new_books_fnl['userid'] > 53424)

new_books_use = new_books_users.select('userid', 'book_id', 'prediction')

下面是一个向加入 web 应用程序的用户反馈建议的示例:

将在 web 应用程序|作者图片中推荐给用户的图书快照

我们现在在 web 应用程序中为用户提供了推荐!

正如我们所看到的,一些预测并不是很好——例如,表中的第一个用户将收到一本书,该算法预测他们的评分约为 3.5/4。理想情况下,我们希望找到用户真正喜欢的书(不考虑意外收获、新奇感等因素)。).所以,有了更多的时间和更广泛的用户基础,我希望看到预测评分更高的推荐书籍。

随着模型在 Databricks 中本地工作,我能够上传这个优化的模型并将其部署到 Amazon Web Services 集群,每小时运行一次 cronjob 来处理任何吸收到我的 PostgreSQL 数据库中的新评级。每小时一次的 cronjob 基本上会重新运行模型,重新计算预测和建议,然后用更新后的建议覆盖我的 PostgreSQL 中的建议表。然后,它会连接回我的 Flask 应用程序,为用户提供服务。关于 AWS 和数据块的部署说明,你可以在这里找到一些文档。

我的 PostgreSQL 中的推荐表用我的推荐和它们对应的图书 id 更新后,我就可以利用 Goodreads API 来查找图书信息(例如图片、书名等)。)来构建前端应用程序。

那么,它的效果如何呢?

最后,我做了一些测试,注意到这些推荐并不太糟糕!例如,我创建了一些狂热的数据科学用户,并对许多数据科学书籍进行了评级。我有意让不同用户对书籍的评价有所重叠,但也试图为每个用户评价几本新书。

当我运行我的模型来提供推荐时,我很高兴地看到,没有被一个数据科学狂热者评级的书籍被推荐给了另一个数据科学狂热者的正面评级,这表明我的协作过滤技术正在起作用。请参见下面的示例:

一些数据科学读者的推荐页面示例|作者图片

正如我们从红色方框中的标题可以看到的,用户 2 对这两本书的评价非常高(评分为 5)。因此,当运行我们的机器学习算法时,用户 1 和用户 2 的书籍评级之间存在一些重叠——这意味着没有被用户 1 评级(并且隐含地没有被阅读)但被用户 2 评级很高的书籍被作为推荐给用户 1。

自己试试吧!

要尝试这个应用程序,请点击这里:https://zach-book-recommender.herokuapp.com/

尽管数据科学书籍的推荐看起来确实非常有效,但在其他类型和主题方面存在很大差距。您可能会注意到,您的推荐还会从 goodbooks-10k 数据集中引入其他评价非常高的书籍(例如卡尔文和霍布斯等)。),直到有更多和你口味相似的用户加入 app。因此,我建议与朋友分享,看看随着时间的推移,你的建议是否会越来越好!

连接

如果你喜欢这篇文章,或者觉得它有帮助,请联系我们!我喜欢在项目上与其他人合作,并向对数据科学工作充满热情的同行学习。

你也可以看看我的数据可视化作品集,在那里我主要使用 Javascript 和 D3.js,并谈谈我在研究生院完成的其他项目。

为我蹒跚学步的孩子制作一个播放视频的机器人

原文:https://towardsdatascience.com/building-a-bot-that-plays-videos-for-my-toddler-597330d0005e?source=collection_archive---------17-----------------------

使用一个物体检测人工智能模型、一个游戏引擎、一个亚马逊 Polly 和一个在英伟达(NVIDIA)Jetson Nano 上运行的 Selenium automation 框架来构建 Qrio,这是一个可以说话、识别玩具并在 YouTube 上播放相关视频的机器人。

我和我妻子有一个超级好奇的 21 个月大的男孩,名叫德歇。虽然他还不会说话,但他真的很喜欢指着东西让我们告诉他是什么。它可以是他最喜欢的书里的一张动物图片,他卡片上的一张汽车图片,或者只是一个玩具。我喜欢和他一起做这项活动,最近我一直在给他看描绘老虎、海豚、火车和其他有趣事物的视频。他真的很喜欢看一只真正的老虎如何走路、吼叫和社交,我认为这对他的认知发展有好处。

德协指着一个飞机的机翼,一条鲸鱼和一个拉面!

有一天,我想到给他造一个机器人,可以和他一起玩这个指点游戏。不要误解我的意思,我们的目标不是取代我们,而是补充我们,让他尽早接触技术。

概念

经过一段时间的头脑风暴,我清楚地知道我想要建造什么。这是一个有着狗的外形的聊天机器人,狗是德西最喜欢的动物。她的名字叫 Qrio,是“问题”和“好奇”两个词的混合。在我为他买玩具的一年半时间里,我观察了他一直玩的玩具和不玩的玩具,我发现玩具越能模仿他能与之建立联系的生物(在这种情况下是一只狗),它成功的机会就越高。

为了最大限度地提高凝聚力,Qrio 以我们已故的爱犬百事可乐为模型,德克斯特在第一年就与百事可乐建立了关系。

百事和 Qrio

Qrio 将能够看到 Dexie 走过,并对他说:‘嗨,Dexie!你想过来给我看看你的玩具吗?接下来,当德茜拿起一个飞机玩具给她看时,她会继续说‘嘿,那是一架飞机。‘我给你放一段关于飞机的视频’,然后找一段飞机视频给他播放。

研究

为了实现上述目标,Qrio 需要具备以下模块:

  • 视线。Qrio 必须确认 Dexie 和他携带的玩具。为此,我需要一个连接到人工智能系统的摄像头,以检测德歇和他的玩具的存在和位置。需要建立一个经过训练可以识别人脸和玩具的物体检测人工智能模型,该模型将在连接到摄像头的 GPU 驱动的设备上运行。
  • 视觉存在——以虚拟狗的形式出现,它将与德歇互动。它将由显示在显示器上的虚拟木偶系统驱动。
  • 语音,这样 Qrio 就可以和他打招呼,让他拿起一个玩具,说出玩具的名字等等,这需要一个文本到语音的技术,显然还需要一个扬声器。
  • 视频搜索和播放,这样 Qrio 就可以在 YouTube 上搜索并播放一个相关的视频。这将由自动化工具驱动。
  • 所有组件的协调者

经过一番认真的研究,我列出了运行该系统所需的硬件清单。

  • NVIDIA Jetson Nano(150 澳元)。这是一个微小的 GPU 驱动的嵌入式设备,将运行所有模块(特别是对象检测人工智能模型)。这是一个完美的工作设备,因为它可以通过一个简单的 HDMI 端口支持视频和音频输出,并且它有一个以太网端口,方便互联网接入。你甚至可以插入鼠标和键盘,在设备上进行开发和调试,因为它有一个功能齐全的 Ubuntu 18.04 操作系统。
  • 电视(带 HDMI 输入和内置扬声器)(150 澳元)。这样 Dexie 就可以看到 Qrio,听到她在说什么,还可以播放 YouTube 视频。
  • 相机——索尼 IMX219 ($AUD 35)。这是一个令人敬畏的微型 800 万像素摄像头,使 Qrio 能够识别 Dexie 和他的玩具。画质超赞,价格惊人的便宜。

NVIDIA Jetson Nano 和索尼 IMX219 摄像头

履行

有了一个可靠的计划,我开始完成我的使命。

建筑景观

首先,需要开发和训练一个对象检测组件来识别特定的人脸和玩具。请记住,NVIDIA Jetson Nano 的 GPU 不如 1080Ti 等桌面级 GPU 卡强大,因此选择一种在准确性和性能之间取得良好平衡的对象检测模型架构至关重要。首先,我决定了我能接受的最低每秒帧数(FPS)。然后,我逆向工作,寻找可以在 Jetson Nano 上提供这种 FPS 的模型。我选择了 8 FPS,实际上,当视频处理、文本到语音、虚拟木偶戏渲染等同时运行时,它将下降到大约 5 FPS。每秒少于 5 次检测将显著降低获得高质量捕捉的机会,在高质量捕捉中,Dexie 的脸和他的玩具清晰可见。获胜的模型架构是ssdlitemobilentv 2,它运行在 TensorFlow 1.8 对象检测 API 上。

我只用了四个类来训练这个模型:一张人脸和三个 Dexie 的玩具(飞机、火车和熊猫)。所有训练集图像(每类 150 个图像)都是从使用同一台索尼 IMX219 摄像机记录的视频文件中生成的。为了最大限度地提高检测精度,并确保照明和背景是一致的,它们是在我将运行该系统的同一个客厅中拍摄的。这三个玩具都是从视频中手动、费力地贴上标签的。然而,为了保持理智,我使用了 Amazon Rekognition ,这是一种现成的对象检测云服务,可以自动标记所有人脸。

人脸和玩具检测训练装置

视频录制是使用 GStreamer 完成的,通过执行下面的命令就可以轻松完成。以低 FPS 录制会导致最终视频中出现明显的运动模糊,并产生低质量的训练集。因此,我将录制帧速率设置为 120 FPS,稍后使用视频编辑工具对其进行向下采样。记录尺寸设置为 720x540,这已经足够了,因为我们的对象检测模型只能在 300x300 像素上运行,任何更大的图像在训练和推断期间都会自动调整为 300x300 像素。

*gst-launch-1.0 nvarguscamerasrc num-buffers=120000 ! 'video/x-raw(memory:NVMM),width=720, height=540, framerate=120/1, format=NV12' ! omxh264enc  ! qtmux ! filesink location=out.mp4 -e*

我使用了 EVA ,一个伟大的免费物体检测标签工具,你可以安装在本地,并可以导入一个视频文件作为图像源。

训练在五个小时内完成,使用的是在实现 mAP=0.8 的 P3.2XLarge (Pascal V100)上运行的 AWS EC2 深度学习 AMI 。Mean Average Precision (mAP)是一种用于评估对象检测性能的指标,通过计算在各种 iOU 阈值上平均的精度/召回曲线下的面积来进行。这需要一个完整的博客帖子来解释,所以我会简单地让你看一下物体检测博客的地图。否则,你只需要相信我,0.8 的贴图已经很好了,而且还可以通过聚合几帧的检测来进一步改进。

培训统计

一旦你刷新了设备,在 NVIDIA Jetson Nano 上部署和运行这个模型是非常简单的(按照步骤这里),因为它运行的是全功能的 Ubuntu 18.04。我的意思是你可以安装 Tensorflow,Object Detection API 和所有的 Python 依赖项,就像在你的笔记本电脑或 PC 上一样。我使用 Tensorflow 1.8 是因为在写这篇博客的时候,由于缺少 contrib 依赖项,Tensorflow 2.0 不支持对象检测 API。

GStreamer 和 OpenCV 框架用于连接到摄像机并从摄像机获取视频。从那里,我们只需要将捕获的图像直接传递给我们的对象检测模型。请看这里的代码示例

我设法让物体检测以 10 FPS 的速度运行,这超过了我的最低要求 8 FPS——并且具有相当好的检测精度!

目标检测结果

建立视觉存在

获得正确的视觉呈现组件至关重要。Qrio 必须有吸引力,更重要的是,看起来足够像一只真实的,活着的狗,让 Dexie 想和她一起玩。她的眼睛需要能够直视德谢的脸,无论他在哪里。像一只正常的狗一样,当她不与德西互动时,她需要通过摇尾巴,移动头部和随意看方向来坐立不安。作为一名 3D 动画程序员,我在一家专门从事面部动画和虚拟木偶戏的电影特效公司工作了五年,在这五年的美好时光中,我学到了如此宝贵的技能,对此我感激不尽。我现在需要的只是一个游戏引擎!

几个小时的挖掘让我找到了这个叫做 arcade 的可怕的 Python 框架,它拥有我需要的一切。嗯……差不多,我稍后会讲到这个。它支持游戏动画循环,能够渲染/显示带有旋转和缩放的精灵(PNG 透明图像)。由于该框架基于 OpenGL,NVIDIA Jetson Nano 的速度性能应该非常出色,因为它将进行 GPU 加速。

街机 python 游戏引擎

为了让 Qrio 身体的各个部分(耳朵、眼球、眉毛、头和尾巴)既能独立运动又能作为一个群体运动,需要将单独的精灵组装起来(例如,移动头部也会移动耳朵、眉毛和眼球)。我需要建立一个骨骼动画系统(SAS ),它允许你将几个物体以层次关系连接在一起(例如,头部是身体的孩子,而耳朵、眼睛和眉毛是头部的孩子)。因此,当您对一个对象应用变换(旋转、平移或缩放)时,它也会影响它的所有子对象。

大多数游戏角色,人类,动物,怪物,就像下面动画中的一样,都是用 SAS 制作的。

全身骨骼动画系统

大多数游戏引擎原生支持 SAS 然而,街机没有。由于我找不到替代框架,我决定从头实现 SAS 功能,这实际上并不难。我需要做的第一件事是建立一个存储所有精灵(耳朵、头、眉毛等)的树形数据结构。)并根据它们的关系连接它们的关节。接下来是构建一个 SAS 分层转换函数。这涉及到一点三角学和矩阵。如果你热衷于了解数学细节,你可以在这个博客中阅读。

下图展示了 Qrio 的 SAS。第一幅图像显示了如何使用精灵来定义每个身体部位,这些部位是按层次组合的,如下一幅图像所示。每个身体部位也将有一个定义为旋转中心的关节。最右边的图像显示了围绕其关节应用于右耳的变换(旋转),并且没有其他身体部位受到影响,因为右耳没有任何子体。下图描绘了围绕其关节应用于头部的旋转,它影响了眉毛、眼球和耳朵。注意标记显示右耳也相应地绕着头部关节旋转。

Qrio 的骨骼动画系统

为了完成视觉呈现模块,我需要建立的下一个东西是一个坐立不安的动画系统,它是基于一个简单的关键帧动画。关键帧动画允许您通过提供对象的初始和最终变换(位置、缩放和旋转)以及动画的持续时间来设置对象(如头部)的动画。系统对从初始值到最终值的变换进行插值。接下来,我定义了几个坐立不安的动画,比如耳朵的上下运动,头尾的旋转,眼球和眉毛的运动。每一个小动作都用随机选取的值(旋转/平移)、持续时间和频率使相应的对象从一个变换到下一个变换产生动画,以便看起来更自然。

我花了几个小时调整坐立不安的动画参数,最终得到我想要的结果。

Qrio 的坐立不安动画系统

最后,我添加了一种方法来按需覆盖眼球和眉毛的位置,方法是手动提供它们的位置,这是头部跟踪逻辑在稍后阶段跟随 Dexie 的脸的位置所需要的。

大厦演讲

随着她的视力和视觉呈现模块的完成,她接下来需要的是语言能力。经过几个小时的研究,我能找到的最好的免费离线文本语音转换应用是 pyttsx3 。该引擎支持一些驱动程序,但 Ubuntu 上唯一可用的驱动程序是 espeak,它的语音质量最糟糕。这听起来像已故的斯蒂芬·霍金的轮椅(无意冒犯)。Dexie 目前正处于重复我们说的每一句话的阶段,我最不希望他学会那样说话。查看以下内容,做自己的评判。

ubuntu OS 上的 pyttsx3、espeak 驱动程序产生的音频质量不佳

放弃线下发行后,我开始寻找线上发行。我登陆了亚马逊波利。玩了几分钟后,我完全被迷住了。语音质量提高了 100 倍,没有明显的延迟,尽管它需要通过互联网进行 API 调用,以生成并从云中下载结果音频文件。这最初是我主要关心的问题。生成 7 秒钟的音频文件只需要 200 毫秒。我知道这不是一个免费的解决方案。然而,它可以被大量缓存,因为 Qrio 最多只需要说出 50 个不同的句子,我们只需要支付 50 次亚马逊 Polly 呼叫(0.08 美分)。耶!!!

亚马逊波利

建立视频搜索和播放

正如我们之前讨论的,Qrio 需要能够在 YouTube 上搜索和播放特定的视频。最好的方法是使用自动化测试套件,它可以控制 web 浏览器在 YouTube 中执行搜索,并播放搜索结果中的视频。在这里,Selenium 自动化框架来拯救我们了!

Selenium 自动化框架

这是一个 QA 通常用来测试网站的工具。它允许您编写脚本来自动完成诸如在文本字段中键入内容、按下按钮等操作。你可以猜到,我将使用它来导航到 YouTube 网站,输入像 panda 这样的搜索词,然后自动点击搜索结果中的第一个视频,并按下全屏按钮以全屏播放它。首先,您需要为 Selenium 安装一个 Chromium-chrome 驱动程序,以便能够通过执行下面的 apt-get install 命令来控制 Chromium web 浏览器(Ubuntu 18.04 附带的原生浏览器)。

sudo apt-get install chromium-chromedriver

然后,您可以使用针对 Selenium 的 python 绑定,从您的 Python 代码中以编程方式执行 Selenium 脚本。为了确保播放的视频对孩子是安全的,我用 YouTubeKids.com 而不是普通的 YouTube。这带来了一点复杂,因为每次 Selenium 启动时,您都必须通过一系列步骤来证明您是家长。然而,我设法编写了一个 Selenium 脚本,它可以自动完成这些步骤,并且只需要执行一次。

你可以在这里看到代码。

构建协调器

该模块充当协调器,将所有其他模块粘合在一起。协调器的一个关键部分是跟踪游戏当前状态的状态机。为什么我们需要一个状态机?以便我们在接收到相同的事件时可以根据我们当前所处的状态做出不同的决定。例如,如果之前 Qrio 还没有看到 Dexie,看到一个飞机玩具本身不应该触发播放 YouTube 视频的调用,因为它可能是玩具飞机就在沙发上的情况。在播放完飞机视频后看到一个飞机玩具应该会让 Qrio 说‘嘿,我们以前玩过飞机。“你为什么不给我带点别的东西来,”这样,我们可以避免让 Qrio 一遍又一遍地播放相同的视频,如果 Dexie 在它之前被识别并且视频播放被触发后继续持有飞机的话。

有四种主要状态——空闲占用obec 识别播放视频——如下面的状态图所示。当系统处于除播放视频之外的任何状态时,它会定期调用坐立不安动画系统来制作 Qrio 坐立不安的动画,并与视觉模块核对以获取所有可识别物体的位置。系统从空闲状态启动,如果检测到 Dexie 至少 0.5 秒(以减少错误检测),它将调用语音模块,说类似“嗨 Dexie,你想过来玩吗?”并将游戏状态设置为参与状态。

Qrio 全状态机图

此外,如果在我们处于参与模式时,可以看到一个熊猫玩具,Qrio 会说‘嗨,Dexie。我想那是一只熊猫,将进入物体识别模式。如果熊猫玩具在另外两秒钟内仍然可见,Qrio 将切换到播放视频状态,将说“让我给你播放一段关于熊猫的视频”,并将调用视频搜索和播放模块来搜索熊猫视频并播放它。然而,如果我们最近播放了一段关于熊猫的视频,它会说‘嘿,我们以前和熊猫玩过。为什么不给我带点别的?视频将只全屏播放 45 秒,而视线和坐立不安动画系统暂停,以集中 CPU 资源播放流畅的视频。视频播放完成后,浏览器窗口隐藏,视线和坐立不安动画系统恢复。当 Dexie 在接合模式下 10 秒钟不可见时,协调器将重置状态为空闲

您还可以看到,除了播放视频之外,在任何状态下,当面部可见时,都会调用头部跟踪模块,以使 Qrio 的眼球跟随面部边界框的中心点。

设置和校准

一切准备就绪后,我在客厅安装了系统,进行最后的校准和测试。

Qrio 系统设置

初始化时,系统会顺利通过 YouTubeKids 的母授权。我看到 Qrio 的眼睛快速地跟随我的脸,这表明物体检测和头部跟踪逻辑工作得非常好。我注意到 NVIDIA Jetson Nano 已经被推到了极限,RAM 运行得非常低,设备变得非常热。这是完全可以理解的,因为它正在运行一个重型人工智能模型,仍然需要实时渲染游戏引擎,控制 Selenium 浏览器和解码视频。然而,整个系统似乎运行得很好,游戏引擎显示的基准为 5 FPS。

我现在需要的就是找个合适的时机把 Qrio 给 Dexie 看!

Qrio 系统校准和测试

表演时间

第一次看到 Qrio 的时候,是看着德谢的无价时刻。他好奇地冲向她,而 Qrio 在叫他,他站着不动,只是不相信地盯着她看了几秒钟。突然,他咯咯地笑了起来……我才知道我成功地通过了第一次测试——男孩和机器人的成功结合!

德歇第一次见到 Qrio

为了让他更加熟悉和舒适,我让他做任何他想做的事情,没有任何指导。他走向她,看着她坐立不安,摸着电视(以为他真的在摸她),甚至叫她“小狗”。

接下来是关键时刻——测试实际的游戏玩法。举个例子,我让他看我给 Qrio 展示他的飞机玩具,她完美地认出了它,并说,“嘿,我想这是一架飞机。让我给你放一段关于飞机的录像。德协看到飞机视频开始播放的时候超级兴奋!

视频播放完一次,我把一个熊猫玩具递给了德协。他模仿我,把熊猫玩具给 Qrio 看,她再次搜索并播放了一段合适的视频!你可以在下面的视频中观看整个经历。

德西第一次看到并和 Qrio 一起玩

学习和未来改进

系统还不完善。尽管它在 80%的时间里能够识别玩具并播放正确的视频,但它仍然会时不时地失败——这没什么。最重要的是,我学到了很多关于什么可行,什么不可行,为下次类似的项目做准备。

相机的 FOV

大多数故障发生在 Dexie 站得离电视太近时,这超出了摄像机的可视范围。如下图所示,相机有一个 77 度的 FOV,放置在距离电视中等距离的位置,但不是很近(红色圆圈标记的区域)。同样的问题也发生在垂直覆盖中,当他坐在地板上时,摄像机看不到他举得很低的玩具。降低相机的焦距可以解决这个问题,但会带来相反的问题,即当他站在相机附近时,看不到他的脸。

Qrio 的摄像头的水平盲点

Qrio 的相机的垂直盲点

解决这个问题的办法可能是买一台 FOV 更宽(120 度)的新相机,这样它可以覆盖更多的区域。然而,由于透镜失真,FOV 边缘周围的检测精度可能下降。

可回放性

到目前为止,Qrio sight 模块只对三个玩具进行了训练,并且总是为同一个玩具播放相同的视频。这只够娱乐德歇五分钟,直到他厌烦为止。因此,它具有低的可重复因子。我计划在未来增加对更多玩具的支持——如果我能鼓起勇气手动标记数以千计的额外图片的话。还可以添加一个随机化,从找到的前五个视频中随机选择,而不是总是选择第一个。

更快的 FPS

另一个需要改进的地方是游戏的 FPS。当视频搜索和播放模块执行 Selenium 脚本来控制 chromium 浏览器时,游戏以大约 5 FPS 的速度运行,偶尔会出现短暂的冻结和较长的冻结。你可能已经在上面的演示视频中发现了这一点。一个冻结的游戏引擎意味着 Qrio 停止移动,这不是那么好看。一个想法是将对象检测移到一个单独的线程中,这样它可以并发运行,而不会阻塞游戏引擎。同样的处理也可以应用于视频搜索和播放模块。然而,我们需要测试 OpenCV 和 Selenium 是否乐意在单独的线程上运行。除此之外,我还想测试一款更强大的设备,比如 NVIDIA Jetson NX T1,它可能更适合这种规模的项目。

就这样,伙计们!我希望你喜欢阅读我的令人兴奋的周末计划,就像我喜欢与你分享它一样。

完整的源代码可以在这里找到。

构建脑瘤分类应用程序

原文:https://towardsdatascience.com/building-a-brain-tumor-classification-app-e9a0eb9f068?source=collection_archive---------25-----------------------

一个真正的机器学习应用程序,从零开始,使用 Dash

来源:https://unsplash.com/photos/rmWtVQN5RzU

在下面的文章中,我将展示一个我从零开始创建的机器学习应用程序。

1.目标

我想建立的是一个应用程序,它可以将大脑核磁共振图像作为输入。从那里,应用程序将返回一个预测,说图像上是否有肿瘤。

我发现这个想法很有趣,因为任何人都可以使用这个应用程序来确定是否存在脑瘤。不需要编码技能或关于大脑的知识。

为了实现这一目标,需要完成三个步骤,即创建预测图像类别的模型、创建应用程序以及最后部署应用程序本身。

2.构建卷积神经网络模型

CNN 是一类深度神经网络,通常用于分析视觉内容,这正是我在这里想要做的。

我用来建立 CNN 的数据来自这里的。

它包含 3264 幅脑 MRI 图像(2880 幅训练图像和 384 幅测试图像),分为 4 类:神经胶质瘤肿瘤、脑膜瘤肿瘤、垂体肿瘤和无肿瘤。

我用 Keras 建立模型。对于那些不知道的人,Keras 是一个运行在 Tensorflow 之上的高级 Python 神经网络库。其简单的架构、可读性和整体易用性使其成为使用 Python 进行深度学习时最受欢迎的库之一。

在为 CNN 导入并准备好图像后,我最终构建了以下模型。

model = Sequential()model.add(Conv2D(32, (3, 3), input_shape=(150,150,3), use_bias=False))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3))) 
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Dense(4))
model.add(Activation('softmax'))model.compile(loss = "categorical_crossentropy", optimizer=keras.optimizers.Adam(learning_rate=0.001), metrics=['accuracy'])

我把模型保持得非常简单。它只有两个卷积层,最末端的 softmax 层将返回 MRI 属于 4 类的概率。

然后我根据数据训练这个模型。

history = model.fit(trainData, trainLabel,batch_size = 128, epochs = 30 ,validation_data=(testData, testLabel))

这个只有 30 个历元的简单模型达到了大约 81%的准确率。那意思很明显,不要把这个 app 当做绝对真理,听医生的!

然后,通过保存模型,这意味着它可以很容易地在 Dash 应用程序中用于预测新图像。

model.save('model_final.h5')

现在这一部分已经完成,让我们继续使用 Dash 创建应用程序。

3.创建应用程序

我使用 Dash 来创建应用程序。该平台允许我们开发高质量的企业级分析应用,而不需要开发人员、JavaScript 或除了基本 Python 技能之外的任何东西。

关于如何构建 Dash 应用的完整教程,请点击这里

我做的第一件事是导入运行 dash 应用程序和 keras 模型所需的所有包。之后,就可以构建应用程序了。这是它的完整代码。

那是相当长的,所以让我们检查一些事情。首先,names函数的作用是根据模型的预测,给出一个特定的输出(即肿瘤的名称)。

现在,让我们来复习一下回调。它接受一个图像作为输入,即 html。来自parse_contents函数的 Img 标签。list_of_contents[0]意味着只有上传的第一张图片会被使用(所以上传多张图片是没有意义的)。

然后,以下代码获取 Dash 以 base64 字符串编码的图像,并使其可用于 CNN:

 img_data = list_of_contents[0]
  img_data = re.sub('data:image/jpeg;base64,', '', img_data)
  img_data = base64.b64decode(img_data)  
  stream = io.BytesIO(img_data)
  img_pil = Image.open(stream)

然后,用load_model函数加载之前创建的模型,将图像转换成具有正确形状的 numpy 数组,并用answ = model.predict(x)进行预测。这里的好处是,你可以创建任何你想要的 CNN 模型并加载它,应用程序仍然可以工作!

然后,根据该预测,给出关于图像上没有肿瘤的可能性和关于肿瘤的一些事实的第二个预测。

最后,返回 4 个输出(图像、两个预测和事实),从而结束长时间的回调。

4。Heroku 的部署

随着应用程序的创建,是时候让每个人都可以使用它了。Dash 应用程序可以部署在 Heroku 上,这是一个云应用程序平台,允许您完全免费运行您的应用程序。

要了解如何在 Heroku 上部署 Dash 应用程序,请点击右此处

这款应用就在这里:https://brain-mri-app.herokuapp.com/。只是提醒一下,加载应用程序可能需要一段时间。这是因为它会在一段时间后进入睡眠状态(这是 Heroku 免费版的少数不便之处之一)。

这里有一个简短的 GIF 展示了该应用程序应该如何使用。正如您将看到的,这非常简单:

你可以用任何健康大脑的 MRI 图像,或者有神经胶质瘤、脑膜瘤或垂体瘤的大脑图像来尝试。例如,这是一张脑膜瘤的图像,你可以用它来预测。

感谢阅读,我希望你觉得这篇文章有趣!

所有的代码都可以在这个库中找到:https://github . com/francoistamant/brain-tumor-classifier-app

建立一个基于预算新闻的算法交易者?那么你需要很难找到的数据

原文:https://towardsdatascience.com/building-a-budget-news-based-algorithmic-trader-well-then-you-need-hard-to-find-data-f7b4d6f3bb2?source=collection_archive---------38-----------------------

我的故事——零美元建立一个算法交易者,分析免费 API、数据集和 web 抓取器。第 1 部分:API

M. B. M.Unsplash 上拍摄的照片

利用新闻或股票信号的算法交易近年来越来越受欢迎。一个完整的行业已经从彭博和 Webhose 这样的巨头发展到成千上万的小公司,它们都在争夺最快、最准确、最广泛的新闻报道。然而,大多数这些服务的问题是,它们针对的是大公司,因此通常每个人要花费数百美元,很可能会被大多数人的算法淘汰,至少会侵蚀潜在的回报。出于这个原因,我决定尝试为在家开发人员拼凑最现实的解决方案,在探索了几十个来源后,我将搜索范围缩小到 10 个最可行的选项。这 10 个免费资源都没有为算法交易提供一个本垒打,但是认为这些资源的组合可以让大多数人达到一个伟大的境界是很现实的。在第 1 部分中,我将讨论前 5 个,它们都是 API!关于数据集和 web 抓取器的第 2 部分也可以在这里访问

[## 建立一个基于预算新闻的算法交易者?那么你需要难以找到的数据——第 2 部分

我的故事——零美元建立一个算法交易者,分析免费 API、数据集和 web 抓取器。第 2 部分:数据集和…

towardsdatascience.com](/building-a-budget-news-based-algorithmic-trader-well-then-you-need-hard-to-find-data-part-2-2ddc4a9be1d8)

蜜蜂

API 是大多数平台的最爱,用于以编程方式向用户提供一致的新闻数据。用户将向一个端点发出请求,例如,请求与 Apple 有关的最近 10 篇文章,并从该端点接收响应。

优点:

快速编程访问——大多数 API 将在几百毫秒内返回请求的数据,允许用户快速收集数据

定制——API 倾向于有好的文档,如果构建得好,能够准确地返回用户正在寻找的东西。例如,我可以告诉 API,我想要这些日期的新闻源中的这么多文章。其他方法,如批量下载,可能需要更多的提取才能达到那个粒度级别

实时—用于新闻的 API 大部分时间将实时数据传输到端点。这意味着当您发送请求时,您将获得最新的信息。这对于适应不断变化的市场环境至关重要。

缺点:

使用限制—大多数 API 都是按使用付费的系统。这意味着,如果您使用的是免费层以上的任何东西,您很可能需要定期付费,这可能无法满足复杂系统的需求。许多人还会限制你在一段时间内的访问次数。

缺少历史数据——因为新闻 API 是建立在可以访问最新新闻的概念上的,所以历史数据的积压往往很少。当 ML 算法需要多年的历史数据来开始良好地执行时,这可能是一个问题。

由于 API 的压倒性优势,我发现的 10 个最佳来源中有 5 个都是 API,下面我将详细介绍每一个!

新闻 API

优点:

高使用上限——每天 500 个请求是一个非常好的自由层,普通开发人员永远不需要担心会超过这个上限!

包含大量元数据的准确文章—关于某个主题的请求通常每天会返回数百篇文章,并且包含诸如来源、作者、标题、描述、发布日期和文章内容等信息。这为每个请求提供了大量信息。

缺点:

内置延迟——免费层包括所有退回商品的 15 分钟延迟,这可能是一个交易破坏者,也可能根本不重要,取决于交易的类型。

普通积压—免费层积压可以追溯到 1 个月前(已付费 24 个月),这意味着找到梦寐以求的历史数据可能是不可能的。

超出免费层的高昂成本——如果您愿意每月支付 10 美元来获得更高的使用率和高级支持,那么使用 news API 是不可能的。他们的下一个计划包括 250,000 个请求,没有新闻延迟,价格为 449 美元,远远超出了大多数开发者的承受能力。

总体而言:

当你开始谷歌搜索金融新闻应用编程接口时,第一个结果,也是最好的结果之一,就是新闻应用编程接口。它使用简单,对于普通开发人员来说有很大的自由层!如果您可以通过其他方式填充您的历史数据,并且不介意延迟,那么新闻 API 很难被击败!

必应新闻搜索(通过 Rapid API)

优点:

实时—给定一个搜索,提供关于特定搜索主题或特定类别新闻的快速实时新闻

超出免费等级的优惠价格—对于超过 100 个请求/天限制的每个额外请求,您只需为每个额外请求支付 0.005 美元。如果在某些日子比其他日子需要更多的请求,这就提供了很大的灵活性!

缺点:

不存在的积压-无法为您的搜索结果指定时间范围。这使得查找昨天的数据变得非常困难,所以这个 API 对于检索历史数据是不理想的。

总体而言:

我认为这是一个非常普通的 API。返回的元数据是好的,但不是很好,每天 100 个请求的免费层也是中等水平,但它确实提供了实时的无价优势,但缺点是没有历史结果。它还具有由微软维护的可靠性。如果您所关心的只是可靠的实时结果,那么这个 API 就能满足您的需求!

上下文网络搜索(通过 Rapid API)

优点:

高使用上限—每月 10,000 个请求是一个非常好的免费层。除此之外,一旦达到上限,每个请求只需花费 0.0005 美元,是 bing 新闻搜索请求费用的 1/10!

相当好的积压——新闻搜索 API 带有可选的 to 和 from 日期参数,我能够访问早至 1 年的数据,这对于一个免费增值 API 来说是非常优秀的。对于复杂的交易者来说,这些数据可能不够,但是提供了一个合理的开始!

实时-搜索将自动返回最新的结果,除非另有说明,使实时数据很容易获得!

缺点:

相关性问题——在测试这个 API 时,如果我搜索一个特定的股票代码,大多数结果都是相关的,但是偶尔会出现不相关的结果。例如,在搜索与 AAPL 相关的新闻时,我收到的一篇文章的标题是“玛丽亚·凯莉对她的孩子太放纵了吗?”很明显,这不是任何人都希望输入到他们的 ML 算法中的数据!

高延迟 API 报告的平均延迟约为 4000 毫秒,在我的个人测试中,这个数字似乎很大。这有可能限制大量使用情况下可获得的数据量。

可靠性问题——据报道,API 的可靠性为 95%,对于一个免费服务来说,这已经不错了(尽管仍低于大多数水平)。但是在我的测试中,随机失败的数量是显而易见的,这是我在其他 API 中从未遇到过的。

总体而言:

这个 API 的最大特点是能够有选择地收集一年前的新闻数据,免费层提供了足够的使用量来轻松填充积压的文章(每次调用可以返回多达 50 篇文章)。它还可以提供实时结果,使这个 API 看起来像表面水平的赢家。然而,在表面之外,这个 API 有一些可靠性和相关性的缺陷,这些缺陷让它黯然失色。如果您不介意筛选可能杂乱的数据并实现失败检查,这个 API 可能是最好的万能解决方案!

彭博市场和金融新闻(通过 Rapid API)

优点:

具有丰富深度和元数据的高质量新闻 API 分为两个主要的搜索功能,第一,输入一个 ticker,返回 10 篇最近的文章及其标题和唯一关键字。提供了第二个 API 来输入这个惟一的键,并检索完整的文章和元数据。元数据非常深入,包括标签、相关主题、分成组件的文章等等。

新闻是专门按 ticker 排序的——其他大多数 API 都是新闻的网络搜索。彭博专门给文章贴标签,只给相关的标签。这意味着收到的新闻总是与想要的股票相关!

实时——在文章公开后的几毫秒内提供最新的文章!

超出免费层的良好定价-专业层为每月 10 美元,这对开发人员来说是非常合理的价格,包括每月 10,000 次请求,加上超出上限的合理的 0.002 美元/请求价格。

缺点:

免费层不足—免费层每月仅包括 500 个请求,每天不到 17 个。对于大多数系统来说,这是远远不够的,特别是考虑到使用这个 API 需要两次请求才能获得任何单个文章的深度元数据。

不存在积压——彭博擅长提供快速更新的金融新闻。这是以当前没有检索历史数据的能力为代价的。

总体而言:

彭博多年来一直是财经新闻的领导者,这一点在这个 API 中得到了很好的体现。如果文章的准确性、速度和深度是重要的,那么它显然是赢家。这方面的压倒性优势是以其他方面的代价换来的。没有积压,几乎被迫为一个高级帐户付费,这给本来是一个极好的 API 增加了压力!

雅虎财经 API(通过 Rapid API)

优点:

新闻是专门按股票代码分类的——像彭博一样,雅虎财经 API 的工作原理是输入一个股票代码,然后返回一个最近 10 篇文章的列表,这些文章被专门标记为与该公司相关。雅虎财经还增加了简单返回最新 10 篇一般财经文章的功能!

列表包含大量的元数据——当询问最近的 10 篇文章时,列表中的每一项都包含了大量的细节!这包括文章的标题、摘要、实体和内容!

实时——在文章公开后的几毫秒内提供最新的文章!

超出免费层的良好定价-就像彭博一样,专业层是每月 10 美元,这对开发人员来说是一个非常合理的价格,包括每月 10,000 次请求,加上超出上限的合理的 0.002 美元/请求价格。

缺点:

不存在积压——这个 API 擅长实时更新,所以没有编程。查看积压的工作。

平淡无奇的免费层——像彭博一样,这个 API 每月免费提供 500 次调用。虽然这在彭博几乎不可用,但是每次列表检索返回的元数据量使得 500/月更友好。这实际上每月可以访问 5,000 篇有深度的文章,虽然有点乏味,但对于较小的项目是有用的!

总体而言:

这个 API 的行为和感觉与彭博提供的非常相似,在准确性、速度和文章深度方面都有很大价值。虽然 Yahoo 每篇文章的深度和元数据略低,但它通过更友好的免费层弥补了这一点,并且检索类似数量的信息所需的 API 调用要少得多!总的来说,与列表中的其他 API 相比,它表现得很好!

原料药的总体印象

所有这些 API 都有各自的优缺点。它们都不能提供完美的解决方案,但大多数都以低成本或零成本提供了大量的价值。所有这些 API 都是可用的,我认为这个决定主要取决于个人认为什么是优势!这些解决方案中的任何一个都可能必须与补充数据配对,或者用户必须长时间收集数据才能在交易算法中使用。

评估 API 花费的时间比预期的长得多。为了避免 20 分钟的阅读时间,我将在本系列的第 2 部分讨论数据集和 web 抓取器,可以在这里访问!

[## 建立一个基于预算新闻的算法交易者?那么你需要难以找到的数据——第 2 部分

我的故事——零美元建立一个算法交易者,分析免费 API、数据集和 web 抓取器。第 2 部分:数据集和…

towardsdatascience.com](/building-a-budget-news-based-algorithmic-trader-well-then-you-need-hard-to-find-data-part-2-2ddc4a9be1d8)

目前就这些了!我希望这篇文章能消除在众多网络平台中筛选的痛苦和折磨!

如果你喜欢这篇文章,并且想读更多我写的东西,可以考虑看看下面的其他文章!

[## 我是如何用 eGPU 将我的旧笔记本电脑变成机器学习超级明星的

以新电脑的零头成本改造超极本的惊人简单之旅

towardsdatascience.com](/how-i-turned-my-older-laptop-into-a-machine-learning-superstar-with-an-egpu-66679aa27a7c) [## 深度学习预算:450 美元 eGPU vs 谷歌 Colab

Colab 对于开始深度学习来说是非凡的,但它如何与 eGPU +超极本相抗衡?

towardsdatascience.com](/deep-learning-on-a-budget-450-egpu-vs-google-colab-494f9a2ff0db)

建立一个基于预算新闻的算法交易者?那么你需要难以找到的数据——第 2 部分

原文:https://towardsdatascience.com/building-a-budget-news-based-algorithmic-trader-well-then-you-need-hard-to-find-data-part-2-2ddc4a9be1d8?source=collection_archive---------38-----------------------

我的故事——零美元建立一个算法交易者,分析免费的 API、数据集和网页抓取器。第 2 部分:数据集和 Web 抓取器

斯蒂芬·道森在 Unsplash 上拍摄的照片

为基于新闻的交易者寻找数据是一项非常具有挑战性的任务。获取一年多以前的历史数据要么是一项艰巨的挑战,要么将花费数百到数千美元购买。在第 1 部分中,我分析了访问数据的最佳新闻 API。如果你还没有读过那篇文章,我推荐你先读读这里。总结一下我发现的免费 API 的结果,它们在为交易者提供实时新闻方面非常出色,但在为用户提供积压的数据方面却非常欠缺。事实上,我找不到一年前的数据。它们还限制了用户在任何一个月中可以发出的请求数量。幸运的是,我们可以采取措施减轻 API 的缺点。在这篇文章中,我将分析免费的数据集和网页抓取工具,看看它们如何为创建算法交易者提供必要的数据。

数据集

数据集是快速访问海量数据的首选。如果有正确的数据可用,由于能够快速下载和使用大量数据,数据集在算法开发时间上提供了无价的加速。我从谷歌的数据集服务Kaggle 搜索了几十个数据库档案。令人惊讶的是,能够提供真正有用的数据集的唯一来源是 Kaggle,他们实际上有多个!

优点:

大量信息-可用的信息越多,学习和发现趋势就越容易,这就是经典数据集从未过时的原因!

快速编译—当数据集被下载时,访问、训练和使用数据集的速度非常快,从而缩短了开发时间。

缺点:

难以更新-更新不是由您创建的数据集是一项具有挑战性的任务,即使如此,您也可能会遇到拼接不完全匹配的源的问题。您可能会受数据集创建者的支配,发布新版本,或者可能只能永久访问旧数据,这都是经典数据集的显著缺点。

很难找到-找到新闻 API 比找到新闻数据集容易得多。即使您找到了数据集,也不太可能找到与您试图解决的问题完全匹配的数据集。这可能使使用数据集成为不可能的选择。

Kaggle 美国财经新闻文章

该数据集包含 2018 年 1 月至 5 月彭博、美国消费者新闻与商业频道、路透社、华尔街日报和财富杂志的文章。数据集的总大小超过 1 千兆字节,包含成千上万的文章和元数据。

优点:

充足的数据——1gb 是迄今为止我发现的最大的数据集。这意味着,无论你只想要特定的股票还是一般的新闻,任何用户都可以从这个数据集中提取他们需要的信息。它还有大量的元数据,包括文章是关于什么实体的,以及对该实体的看法。

可靠数据-数据集仅包含可靠的来源,提供可靠的新闻报道作为算法的基础。

缺点:

时间跨度短— 5 个月的数据是一个小样本。这段时间市场稳定,表现良好,这可能会导致不可靠的学习。

杂乱的数据——数据按文章排序,而日期和相关的实体存放在元数据中。这意味着在该数据集可用之前,可能需要大量的数据争论。

总体而言:

这个数据集是数据收集的一个很好的起点。它有一个明显的缺点,即缺乏一个大的时间跨度,但如果你以此为起点,并填写 2018 年 5 月以来的补充数据,这个数据集可能会被证明是有价值的!

消息对股票收盘价的影响

这个数据集非常轻量级,但却是这个列表中最有趣的数据集。它只包括微软和苹果公司从 2006 年到 2016 年的文章。每个日期包含开盘价和收盘价,以及《纽约时报》与该公司相关的所有标题。数据集包含对组合标题串的情感分析,指示是否检测到正面或负面情感。

优点:

长时间跨度——10 年的标题数据足以用来训练、测试和验证算法,并且可以通过在类似的方法中添加额外的数据来进一步改进。

补充信息-内置的股票价格和情绪分析列使这成为一个数据集训练准备!像自然语言处理这样的附加步骤已经为您完成了!

可靠的数据——数据直接来自《纽约时报》,虽然这不是一个多样化的数据来源,但它是一个可靠和一致的来源。

缺点:

只有 2 个报价器——从 2 个报价器中学习并推断出其他股票是危险的。这是一个耻辱,这个数据集不包含来自不同部门的 20+ticker!苹果和微软也是成功的公司,这可能会引入不必要的幸存者偏见。

数据越来越旧——只有 2016 年的数据可能会伤害到现在想要创建一个交易算法的人。这可能需要对丢失的信息进行大量的填充才能使用。

缺少元数据—提供的信息只是标题字符串。这缺乏可以证明有用的深度元数据和文章内容。

总体而言:

这个数据集对于学习如何建立一个算法交易者非常有用。它提供了大量的数据,并提供额外的分析。如果您想获取数据集并开始训练,没有比这更好的选择了!然而,我会谨慎地把它作为你唯一的数据源。尤其是如果你想建立一个全面的算法。旧数据的缺点和没有太多的信息阻碍了原本是一个伟大的数据集。

Kaggle 每日新闻进行股市预测

该数据集包含从 2008 年到 2016 年每天从 Reddit 的世界新闻论坛检索到的前 25 条世界新闻。它还包含道琼斯工业平均指数数据和一个布尔值,如果当天道琼斯指数收盘时较低,则为 0,如果收盘时较高,则为 1。

优点:

时间跨度长— 8 年以上,每天有 25 个标题,这足以用来训练、测试和验证算法,并且可以通过在类似的方法中添加额外的数据来进一步改进。

制作良好-数据集组织良好,可用于算法开发。数据集是由一位教授制作的,用于深度学习课程,因此它自然易于使用。

缺点:

数据有效性——根据用户投票赞成和投票反对的内容提取标题可能会给算法带来偏差。Reddit 也没有审查被投票支持的新闻来源的有效性。

数据越来越旧——只有 2016 年的数据可能会伤害到现在想要创建一个交易算法的人。这可能需要大量的回填信息才可用。

不具体—数据仅来自世界新闻,而非金融新闻或个别符号,因此无法提取具体的金融文章。

总体而言:

这是三个数据集中最全面的。它提供了充足的数据、很大的时间跨度,并为用户提供了轻松添加数据、使用 NLP 等技术扩充数据或使用数据快速开发算法的机会。然而,这种便利和大量免费数据带来了数据可靠性的缺点。

数据集的总体印象

所有这些数据集以令人难以置信的速度提供了大量的免费数据。然而,这些数据集没有一个是完美的。它们都有各自的缺点,可能会限制它们的实用性,并且都是 2018 年或更早的产品。然而,数据集的好处是,它们为向免费 API 或 web scraper 添加一些历史背景提供了一个很好的起点!

Web 刮刀

Web scrapers 涉及创建一个程序,该程序将从源站点系统地提取数据,并保存这些数据以备后用。它们是许多人的最爱,因为它们可以自由创建,并且完全可定制。在这篇文章中,我将介绍 web 抓取工具的两种方法!

优点:

完全可定制—您正在编写提取数据的代码,因此您正在完全按照您想要的方式存储您想要的数据。

无限制的免费访问——只要你允许,你的机器人就会运行,没有付费墙,或者对你接收的数据没有限制。

缺点:

可能会很慢—因为您是以编程方式访问网站,所以收集大量数据比使用 API 慢得多。

受限于网站——你也受限于在你抓取的网站上物理可见和可访问的内容,这可能意味着回到很久以前(比如获取几年前的推文)可能在编程上具有挑战性。

高开发成本——创建 web scraper 比使用 API 或下载数据集更具挑战性,耗时也更长。

Selenium 是一个大多数编程语言都支持的工具包,用于使用脚本编程控制 web 浏览器。它广受欢迎,受到广泛支持,易于使用,目前被数百家公司用于 web 抓取、自动化和系统测试。

优点:

广泛的支持——借助对 Python、Java、Ruby、Javascript 和 C#的开发支持,使用您最喜欢的语言并开始自动化 web 浏览器变得非常容易!

完全可定制—您可以完全控制 web 浏览器。您可以在浏览器中做的任何事情都可以自动化,保存,并用于以编程方式存储数据!

缺点:

高开发成本——创建您的完美刮刀需要时间,此外,网站始终有可能发生变化,需要维护。

耗时——与利用 API 等其他来源相比,等待 scraper 收集足够的数据来创建任何有用的算法可能会令人望而却步。

总体而言:

硒真正是“你想要吗?建吧!”网页抓取选项。这是一个非常扩展和有用的工具,唯一的缺点是你只能通过浏览器来完成。如果您需要特定的数据,并且具有创建自己的解决方案的编程能力,没有比 selenium 更好的平台了。

Getdata.io

getdata.io 提供了一个有趣且可能更快的网络抓取解决方案。该平台允许使用其查询语言创建“食谱”,该语言将在网页变化时系统地从网页中抓取数据。然而,最重要的是,你不需要精通他们的查询语言,因为他们有一个 chrome 扩展,可以作为一个点击式的解决方案来生成食谱!与为执行任何基于 web 的任务而构建的 selenium 不同,它是为收集数据而定制和构建的!

优点:

快速学习-使用 getdata.io 时,开始抓取网页所需的时间不会太长。添加的 chrome 扩展使抓取数据变得简单!

专为提取数据而构建—该平台专为检测数据变化并相应更新而构建。然后,您可以使用 get 请求将任何数据拉入您的算法中!

数据社区——您创建的配方和提取的数据可以公开。这意味着你得到了一个已经在收集数据的巨大的社区!然而,我为金融新闻找到的食谱太弱,不足以报道。

缺点:

缺少历史提要——因为 scraper 只寻找变化,它不擅长向后搜索历史数据,这意味着您需要等待足够的数据!

比硒更有限——配方创建系统虽然简化了过程,但也限制了可以提取的内容的能力。复杂的提取可能更困难,从长远来看,这可能会使硒更容易提取。

总体而言:

对于那些想要简单了解网络抓取和轻松访问定制数据的人来说,这是一个很有吸引力的选择。它在深度上的不足在数据社区和快速启动时间上得到了充分的弥补!

卷筒纸刮刀的总体印象

Web scrapers 为需要创建自己的数据的人提供了最佳选择。虽然他们可能需要更长的时间来收集必要的数据,但可定制性的数量是无与伦比的。Web 抓取可以用来扩充现有的数据集或 API,也可以单独使用来获得巨大的成功。总的来说,你在 web scraper 上投入的工作量将决定它能否成功创建完美的数据集!

你有它!如果你跟着我看了这两部分,我希望我已经提供了一个很好的资源,告诉你从哪里开始寻找算法交易的新闻。我对创建免费数据集的总体建议是

  1. 不要害怕混合来源。只要你试图保持一致性,数据集和 APIs 刮刀就能很好地协同工作。
  2. 使用适合您的用例的资源。这些资源都不完美,但它们都是有原因的。这 10 个项目中的每一个都提供了至少一个其他 9 个项目没有涵盖的独特方面!
  3. 用自己的钱交易要小心!

如果您有我错过的最喜欢的 API、数据集或 web scraper,请告诉我,如果您喜欢这篇文章,请关注我,了解更多数据科学领域的内容!

构建纸板帝国:使用 Python 介绍 TCGplayer API

原文:https://towardsdatascience.com/building-a-cardboard-empire-introduction-to-the-tcgplayer-api-using-python-fbfc2d62ef51?source=collection_archive---------19-----------------------

如何使用 Python 连接到 TCGplayer.com API

韦恩·洛在 Unsplash 上的照片

纸板的生活

我几乎一生都在玩纸牌游戏,并在 90 年代中期大约在二年级的时候开始玩魔法:聚会(MTG) 。虽然这不是一个让我受女孩欢迎的真正爱好,但我断断续续地坚持了下来,并在十几岁的时候花了许多周五晚上在纸牌店打磨构建的锦标赛和增强草案。现在我对编程和数据科学感兴趣,我很高兴了解到在线纸牌游戏市场,TCGplayer.com有一个免费的 API。

本文将带您了解如何使用 Python 和请求库连接和搜索 TCGplayer API。完整代码可在底部找到!

我的魔法中的几张卡片:收集

获取 API 密钥

TCGplayer 是一个收集物品的互联网市场,允许用户建立商店,通过它他们可以在线出售他们的库存。API 代表 应用编程接口

位于 api.tcgplayer.com 的 TCGplayer API 是一个 RESTful API 应用程序,它与 TCGplayer 商店站点进行交互。存在大量的端点,它们返回目录的所有方面,查找定价信息,并管理个人商店。—https://docs.tcgplayer.com/docs/welcome

要访问他们的 API,首先填写他们的申请表:

[## TCGplayer APIs 开发人员社区和文档

此处的所有原创内容均为 2018 TCGplayer,Inc .版权所有。TCGplayer.com 是 TCGplayer,Inc .的商标

developer.tcgplayer.com](https://developer.tcgplayer.com/developer-application-form.html)

使用 Python 通过请求访问 API

一旦你的文书工作被接受,TCGplayer 的代表将通过电子邮件向你发送一个申请 Id公钥私钥。使用这些键,可以使用 Python 中的 请求 库创建到 API 的连接。根据需要使用 Pip 安装请求:

python -m pip install requests

文件 config.py &管理 API 密钥

本项目使用 API 密钥 。如果你是管理钥匙的新手,确保将它们保存到一个 config.py 文件中,而不是在你的应用程序中硬编码它们。 API 密钥非常有价值,必须加以保护将配置文件添加到 gitignore 文件中,防止它也被推送到您的 repo 中

用你的钥匙

创建需要公钥私钥。一个无记名令牌基本上告诉系统给持有令牌的任何东西以访问权。它是由认证服务器自动生成的。

*#import dependencies
import requests#pull in api keys from config file
from config import public_key, private_key#construct api request
response = requests.**post**(
            "[https://api.tcgplayer.com/token](https://api.tcgplayer.com/token)",

            **headers**={
                "Content-Type": "application/json",
                "Accept": "application/json"},

            **data**=(f"grant_type=client_credentials"
                  f"&client_id={**public_key**}&"
                  f"client_secret={**private_key**}")
        )*

注意我使用了一个 POST 请求到 /token URL。我将包含 API 键的数据有效载荷传递到请求中。返回承载令牌和元数据。

使用查看响应中返回的数据。json()或。正文

*response.**json()**#output
# {'access_token': '**YOUR_GENERATED_TOKEN**',
# 'token_type': 'bearer',
# 'expires_in': 1209599,
# 'userName': '**YOUR_GENERATED_USERNAME**',
# '.issued': 'Sat, 12 Sep 2020 15:40:32 GMT',
# '.expires': 'Sat, 26 Sep 2020 15:40:32 GMT'}*

请注意,不记名令牌已过期。TCGplayer 建议缓存元数据,只在密钥即将过期时重新生成密钥。

既然已经生成了不记名令牌,就可以使用它与 API 进行交互了。

将无记名令牌保存到变量:

*access = response.json()['access_token']*

将无记名令牌连同单词“无记名”一起传入请求报头
TCGplayer 还希望您在头文件中包含一个用户代理,这样他们可以更容易地跟踪 API 的使用情况:

*headers = {"accept": "application/json", 
           "Content-Type": "application/json",
           **'User-Agent': 'YOUR_USER_AGENT',
           "Authorization": "bearer " + access**}*

选择要与之交互的 API 端点。我将从目录>开始,列出所有类别 API 端点,并开始探索!

TCGplayer.com API 端点

*url = "[https://api.tcgplayer.com/catalog/categories](https://api.tcgplayer.com/catalog/categories)"response = requests.get(url, headers=headers)response.json()*

注意变量 URL 是我想要命中的 API 端点。
我将 URL传递给 GET 请求并返回 JSON 响应。

如果我想探索某个特定类别的更多信息,我可以在 API 端点的 URL 中使用 categoryID。例如,下面的 URL 将让我搜索类别 1(魔术聚会是类别 1):

*#search the mtg catalog [https://api.tcgplayer.com/catalog/categories/1/search](https://api.tcgplayer.com/catalog/categories/1/search)*

虽然大多数 API 端点可以通过 GET 请求来访问,但有些端点,如目录>搜索类别产品允许您使用 POST 请求向请求传递过滤器。

比如说我要搜魔:聚拢卡什一税。我可以将一个排序选项,以及过滤器聚合传递到 JSON 有效负载中。**

*url = "[https://api.tcgplayer.com/catalog/categories/1/search](https://api.tcgplayer.com/catalog/categories/1/search)"**payload** = {"**sort**":"Relevance",
           "**filters**": [{
              "**values**": ["Tithe"],
              "**name**": "productName"
          }]}search_response = requests.request("POST", url, json=payload, headers=headers)search_response.json()*

该请求返回产品 id 列表。根据项目的排序方式,产品 id 列表与结果在 TCGplayer.com 上的显示方式相匹配

Search_response.text 按相关性排序的 Tithe

按 TCGplayer.com 的相关性排序的什一税搜索结果

要在搜索请求中检索关于卡的信息,只需将逗号分隔的列表传递给 API 端点 URL。

*endpoint = "[https://api.tcgplayer.com/catalog/products/](https://api.tcgplayer.com/catalog/products/)"
productids = str(search_response.json()["results"])url = endpoint + productidsresponse = requests.get( url, headers=headers)response.json()*

注意,我只是将 API 端点与产品 id 列表结合起来。

response.json()

恭喜你!您现在可以导航和探索 TCGplayer API 了!

最终想法和代码

纸牌游戏并没有走向任何地方,它已经成熟成为一个受欢迎的利基市场。魔术:聚会到现在已经有将近 30 年了!使用像 TCGplayer API 这样的工具,有一个独特的机会来进行一些数据分析和数据科学,并开发新的工具和应用程序来帮助玩家建立和管理他们的收藏。通过 TCGplayer API,甚至可以运行您的在线商店!

如果你喜欢这篇文章,可以看看我关于编程和数据科学的其他文章:

* [## 如何使用 Python 和 Dash 创建控制股市的仪表板

自由期权订单流、价格、基本面、聊天集于一身

medium.com](https://medium.com/swlh/how-to-create-a-dashboard-to-dominate-the-stock-market-using-python-and-dash-c35a12108c93) [## 使用 Python 学习自然语言处理的 3 个超级简单的项目

单词云、垃圾邮件检测和情感分析的简单代码示例

towardsdatascience.com](/3-super-simple-projects-to-learn-natural-language-processing-using-python-8ef74c757cd9) [## 自我隔离时探索三种数据科学技术:什么是 Docker、Airflow 和…

探索 Docker、Airflow 和 Elasticsearch,扩展您的数据科学技术堆栈

towardsdatascience.com](/three-data-science-technologies-to-explore-while-you-self-isolate-what-is-docker-airflow-and-78969ba4f5fe)

完全码

下面是完整的代码

#import dependencies
import requests#pull in api keys from config file
from config import public_key, private_key#construct api request
response = requests.**post**(
            "[https://api.tcgplayer.com/token](https://api.tcgplayer.com/token)",

            **headers**={
                "Content-Type": "application/json",
                "Accept": "application/json"},

            **data**=(f"grant_type=client_credentials"
                  f"&client_id={**public_key**}&"
                  f"client_secret={**private_key**}")
        )access = response.json()['access_token']headers = {"accept": "application/json", 
           "Content-Type": "application/json",
           **'User-Agent': 'YOUR_USER_AGENT',
           "Authorization": "bearer " + access**}url = "[https://api.tcgplayer.com/catalog/categories](https://api.tcgplayer.com/catalog/categories)"response = requests.get(url, headers=headers)print(response.json())url = "[https://api.tcgplayer.com/catalog/categories/1/search](https://api.tcgplayer.com/catalog/categories/1/search)"**payload** = {"**sort**":"Relevance",
           "**filters**": [{
              "**values**": ["Tithe"],
              "**name**": "productName"
          }]}search_response = requests.request("POST", url, json=payload, headers=headers)print(search_response.json())endpoint = "[https://api.tcgplayer.com/catalog/products/](https://api.tcgplayer.com/catalog/products/)"
productids = str(search_response.json()["results"])url = endpoint + productidsresponse = requests.get( url, headers=headers)response.json()

谢谢大家!

—埃里克·克莱本*

与 Emily Robinson 一起开创数据科学事业

原文:https://towardsdatascience.com/building-a-career-in-data-science-with-emily-robinson-27cd9bdba4c4?source=collection_archive---------23-----------------------

苹果 | 谷歌 | SPOTIFY | 其他 | 剪辑

艾米丽·罗宾逊在 TDS 播客

编者按:迈向数据科学播客的“攀登数据科学阶梯”系列由 Jeremie Harris 主持。Jeremie 帮助运营一家名为sharpes minds的数据科学导师初创公司。可以听下面的播客:

数据科学存在于许多真正的技术主题的交叉点,从统计学到编程到机器学习。所以很容易被愚弄,以为这是一个纯粹的技术领域。

但是数据科学和分析不仅仅是解决技术问题。正因为如此,数据科学求职不仅仅是编码挑战和竞争。作为一名数据科学家,获得一份工作或晋升需要大量的职业技能和软技能,而许多人没有花足够的时间来磨练这些技能。

在本期播客中,我采访了经验丰富的数据科学家和拥有 Etsy 和 DataCamp 背景的博客作者艾米丽·罗宾逊(Emily Robinson),讨论职业发展策略。关于这个话题,Emily 有很多话要说,特别是因为她刚刚与合著者 Jacqueline Nolis 合著了一本名为《在数据科学领域建立职业生涯》的书。这本书探讨了许多推动数据科学职业发展的伟大而实用的策略,其中许多我们在交谈中讨论过。

以下是我最大的收获:

  • 如果你想引起雇主的注意,个人项目很重要,但仅仅有一个带有 Python 脚本或 Jupyter 笔记本的 GitHub repo 是不够的。阅读代码既无聊又辛苦,雇主也不太可能这么做,所以试着把你的项目写成一篇博文,或者把它做成一个独立的网络应用,你可以和其他人分享。
  • 数据科学在不同的公司可能会有很大的不同,公司规模是一个重要因素:较大的公司往往有更专业的角色,并会费心区分分析师、数据科学家和机器学习工程师,而较小的公司可能需要你发展更全面的技能。
  • 大公司通常能更好地提供在职指导等服务,而小公司在新员工入职方面可能会更加困难。出于这个原因,艾米丽建议,如果你刚开始职业生涯,就去看看大公司,以确保你获得成长为这个角色所需的支持。
  • 人们不常想到的一件事是,一旦到了该继续前进的时候,离开一家公司的过程。让这个过程顺利进行(或者像艾米丽所说的,“优雅地离开”)是非常重要的:你会想和所有和你一起工作过的人保持良好的关系,因为以前的同事往往会成为很好的推荐渠道!
  • 决定什么时候离开一家公司是困难的,但是做这个决定要考虑的一个关键因素是你是否还在学习。工作保障已经今非昔比,数据科学技术发展的快速步伐意味着,如果你涉水太久,你可能会让你的下一次求职变得更具挑战性。Emily 建议抓住每一个机会学习新的技能,并在你目前的职位上有所发展——如果你不能,那是一个好迹象,是时候改变了。

你可以在这里的推特上关注艾米丽,你也可以在这里的推特上关注我

夹子

我们正在寻找能与我们的观众分享有价值的东西的客人。如果你碰巧知道谁是合适的人选,请在这里告诉我们:【publication@towardsdatascience.com】T4。

用 Python 构建猫脸识别器

原文:https://towardsdatascience.com/building-a-cat-face-recognizer-in-python-92e30d77a661?source=collection_archive---------29-----------------------

机器能理解人和猫脸的区别吗?

照片由丛 H派克斯拍摄

在这篇文章中,我将向你展示如何编写一个简单的程序来检测猫的面孔。在我的人脸检测帖子中,我展示了如何使用 Python 来检测人脸。当我用许多图像测试代码时,我意识到其中一些图像中有动物。但是我们创造的人脸检测模型不能识别动物的脸。然后,我想知道是否有一种方法可以检测图像中的动物面孔,在互联网上做了一些研究后,是的,这是可能的。甚至在 Kaggle 上找到了很多免费的数据集,有几百张图片。Kaggle 是一个寻找免费数据集的好地方,他们也在组织数据科学竞赛。这是一个练习数据科学技能和向他人学习的好地方。无论如何,回到我们的项目。我很高兴在一个程序中结合了人类和猫的面部检测模型,这样我们的机器就可以学习区分人类和猫。这将是一个有趣的项目。我们开始吧!!

图书馆

首先,文书工作。当您处理机器学习项目时,安装和导入库是必要的。我们将为这个项目使用两个库,它们被称为 OpenCV 和 Pillow。OpenCV 是一个高度优化的库,专注于实时应用。Pillow 是一个很棒的图像处理库。枕头将作为“枕头”安装,但作为 PIL 进口。它们是一回事,不要混淆。

OpenCV(开源计算机视觉库)是一个开源的计算机视觉和机器学习软件库。OpenCV 旨在为计算机视觉应用提供一个公共基础设施,并加速机器感知在商业产品中的应用。作为一个 BSD 许可的产品,OpenCV 使得企业利用和修改代码变得很容易。

安装过程非常简单和容易。在您的终端窗口中编写以下代码行:

pip install opencv-python pillow

安装完成后,我们可以将其导入到我们的程序中。

import cv2 from PIL import Image

OpenCV 已经包含了许多预先训练好的人脸、眼睛、微笑等分类器。这些 XML 文件存储在 GitHub 文件夹中。我们将使用猫脸检测和人脸检测模型。

以下是链接:

猫脸:https://raw . githubusercontent . com/opencv/opencv/master/data/haarcascades/haarcascade _ frontalcatface _ extended . XML

人脸:https://raw . githubusercontent . com/opencv/opencv/master/data/haarcascades/haarcascade _ frontal Face _ default . XML

如果您有帐户,可以从 Github 下载 XML 文件。如果你没有,请随意从上面的链接中复制代码,粘贴到你的文本编辑器中并保存它们。我将它们保存为“catface_detector.xml”和“humanface_detector.xml”。

将文件保存到您的文件夹后,让我们将它们加载到我们的程序中。

# Load the cascades 
catface_cascade = cv2.CascadeClassifier('catface_detector.xml') humanface_cascade = cv2.CascadeClassifier('humanface_detector.xml')

形象

在这一步中,您将选择一个要测试代码的图像。确保你至少有几张图片来检查你程序的准确性。这些图像可以有人类和猫,也可以只有其中一个。如果你很难找到猫的图片,我在 Kaggle 上找到了一个免费的数据集。请随意下载并用于该项目。

以下是我将在我们的项目中使用的图片:

照片由 mentatdgt像素拍摄

https://www.kaggle.com/c/dogs-vs-cats

选择图像后,让我们给它们重新命名。确保图像文件位于您正在处理的同一文件夹中。在保存它们之后,现在我们将对图像做一些修饰。

图像处理

在这一步,我们将对图像做一些小的修饰,以便更好地处理。我发表了一篇关于常用图像处理技术的文章。做这些修饰确实有助于我们的机器处理并给出更好的结果。在这个练习中,首先,让我们调整图像的大小,使它们大小相同。接下来,我们将它们转换为灰度,我们的模型处理灰度图像更快。

[## Python 中的图像处理

常用图像处理技术逐步指南

towardsdatascience.com](/image-manipulation-in-python-cbb86a61cf0)

为了使用这些图像编辑技术,我们将使用我们在文章开始时导入的图像模块。

调整大小

newsize = (600, 600) #First image retouches
imgr1 = Image.open("test1.jpg") 
imgr1 = imgr.resize(newsize) 
imgr1.save("resized1.jpg")#Second image retouches
imgr2 = Image.open("test2.jpg") 
imgr2 = imgr.resize(newsize) 
imgr2.save("resized2.jpg")

灰度等级

imgr1 = imgr1.convert('L') 
imgr1.save('ready1.jpg') imgr2 = imgr2.convert('L') 
imgr2.save("ready2.jpg")

导入编辑过的图像

最后,让我们将编辑好的图像导入我们的程序,这样我们就可以运行猫脸和人脸检测模型。我们使用 Opencv 库来导入图像。

# Read the input image 
img1 = cv2.imread('ready1.jpg')

img2 = cv2.imread('ready2.jpg')

人脸检测

瀑布状物

是时候检测人脸了。我们将运行两行代码。第一个在图像中发现人脸的人。第二步是检测图像中的猫脸。如前所述,我们正在起诉 opencv 分类器。

human_faces = humanface_cascade.detectMultiScale(img1,     
scaleFactor=1.3, minNeighbors=5, minSize=(75, 75)) cat_faces = catface_cascade.detectMultiScale(img2, scaleFactor=1.3, 
minNeighbors=5, minSize=(75, 75))

画矩形

在这一步,我们将围绕检测到的人脸绘制矩形。这些矩形可以是不同的颜色,其厚度也是可调的。

for (i, (x, y, w, h)) in enumerate(human_faces): cv2.rectangle(img1, (x, y), (x+w, y+h), (220, 90, 230), 3)      
   cv2.putText(img1, "Human Face - #{}".format(i + 1), (x, y - 10), 
   cv2.FONT_HERSHEY_SIMPLEX, 0.55, (220, 90, 230), 2) for (i, (x, y, w, h)) in enumerate(cat_faces): cv2.rectangle(img2, (x, y), (x+w, y+h), (0,255, 0), 3) 
   cv2.putText(img2, "Cat Faces - #{}".format(i + 1), (x, y - 10), 
   cv2.FONT_HERSHEY_SIMPLEX, 0.55, (0, 0, 255), 2)
  • (220,90,230)和(0,255,0)是我们要绘制的矩形的颜色。你可以玩玩它们,看看颜色是怎么变化的。
  • (3)是线条的粗细。您可以更改该值并查看其外观。

保存您的结果

最后,我们将保存检测到人脸的图像。要看到你工作的最终结果,最好的方法就是保存下来,然后检查。确保变量名传递正确。在运行最后一段代码之前,如果一切正常,我建议继续检查整个代码。

#Saving the images using imwrite methodcv2.imwrite("faces_detected1.png", img1)cv2.imwrite("faces_detected2.png", img2)

结果

这是我的工作成果。第一个是人脸检测,第二个是猫脸检测结果。如你所见,我们的机器知道哪个是人,哪个是猫脸。我还通过将两张图片合成一张来测试这个程序。我收到的结果可以在下面找到。

faces _ detected1.png

faces _ detected2.png

额外的

不要逐个测试每个图像,让我们看看当我们将两个图像组合成一个图像并运行代码时会发生什么。我们可以看到,我们的机器现在能够理解和区分猫和人脸。

结果

恭喜你。!你已经创建了一个程序来检测图像中的猫和人脸。现在,你有一个想法,如何教一台机器同时为你做几件事。希望你喜欢这篇教程,并在今天学到一些新东西。计算机视觉是一个伟大的领域,你可以做的事情是无限的。请随意在不同的图像上测试您的代码,看看它是如何工作的。它可能不适用于所有图像,因为预测依赖于训练数据。在未来的帖子中,我计划向您展示如何用您自己的数据集训练机器,以便它可以为您提供更好的预测。

跟随我的 博客 走向数据科学 留下灵感。

谢谢你,

你可能会感兴趣的机器学习项目:

[## 用 Python 构建一个简单的文本识别器

如何使用文本识别器改进笔记记录过程

towardsdatascience.com](/building-a-simple-text-recognizer-in-python-93e453ddb759) [## 用 Python 构建语音识别器

使用谷歌云语音 API 将您的音频文件转换为文本

towardsdatascience.com](/building-a-speech-recognizer-in-python-2dad733949b4)

构建云原生、云无关的数据湖

原文:https://towardsdatascience.com/building-a-cloud-native-cloud-agnostic-data-lake-376aa2f2aacd?source=collection_archive---------28-----------------------

摆脱云供应商的束缚

凯西·霍纳在 Unsplash 上的照片

为什么还要这样做?

最近,我有机会帮助我的一个客户解决一个有趣的问题。

他们在公共云平台上为特定地区构建了完整的数据湖和分析解决方案,并希望将该解决方案部署到另一个地区。负责管理该解决方案的部门希望该解决方案在不同的公共云平台上实施。

该解决方案基于公共云提供商提供的功能丰富的服务,要在不同的云平台上实施该解决方案,需要进行大量的重新工作。我的客户发现自己被绑上了金手铐

这种特殊情况可能是一种独特的情况,可能适用于大公司,但越来越多的组织现在寻求在任何广泛可用的公共/私有云平台上实施其解决方案的灵活性。毕竟,做出的一个重大承诺是实现解决方案的灵活性,那么现在它怎么能把它拿走呢。

有什么解决办法?

近年来,Kubernetes 已经成为实现云原生但与云无关的解决方案的黄金标准。对我来说,一些突出的好处是:

  • 基于 Kubernetes 构建的解决方案可以使用行业标准的模式和工具。这些应用程序是可移植的,随时可以部署在任何平台(公共或私有)上。
  • 它通常也比使用云提供商提供的现成服务便宜。
  • 随着应用程序变得越来越复杂,Kubernetes 将更多的控制权交给了开发团队,使他们能够轻松地进行构建。
  • 有大量的软件发行版可以作为 docker 图像和舵图表,很容易根据您的需要配置它们。

另一方面,基于 Kubernetes 的解决方案需要更多的努力来支持和管理。

好了,现在我们已经奠定了基础,让我们来看看所提议的解决方案的概要设计

作者图片

如您所见,我们使用 Kubernetes 作为我们的数据湖和分析解决方案的基础部分和抽象层,这将分离底层基础架构,并为您提供迁移到任何公共/私有/混合云解决方案的灵活性。

现在,让我们逐一探究该设计中的每个组件:

  • 对象存储(Object Store):基于 S3 的存储是我们解决方案的绝佳选择,S3 与 Spark 合作,并且有一个全面的 API 列表(感谢亚马逊),可以用所有主要的编程语言与 S3 交互。 MinIO 完全符合要求。这是一个高性能,Kubernetes 本机对象存储,并会谈 S3。MinIO 将用于存储与 ETL 和下游处理相关的数据,而对于长期归档,公共云提供商将更加经济实惠。
  • ETL :对于我们的 ETL 需求,我们使用了 Spark(具体来说就是 Pyspark)。它是快速的、分布式的,并且与 S3 配合得很好,所以不需要将所有数据导入 HDFS。Spark 原生支持 Kubernetes 已经有一段时间了,未来的管道看起来更有希望。
  • 数据交付:独立 Hive 元存储和 Presto 的结合让您可以直接从您的 S3 存储中查询数据。Presto 是分布式的、可扩展的,符合我们并行处理的设计模式。它可以通过 JDBC 连接获得,并允许许多应用程序轻松地连接和查询数据。
  • 工作流管理 : Apache airflow 是一个基于 Python 的工作流管理工具,它使您能够调度作业,创建复杂的作业依赖关系,定义重试和通知逻辑,所有这些都在 Python 中基于配置-代码的模式中完成。
  • 治理:我们正在用各种工具和技术构建一个解决方案。使用 DevOps 和适当的日志记录和监控的原则是最重要的。我们将使用 Docker 来管理我们的映像注册表,使用 Git 和 Jenkins 来管理源代码控制和 CI/CD 管道,使用 Prometheus 和 Grafana 来监控我们系统的健康状况。

结论

这个解决方案中有许多组件,从头构建并维护它不是一件简单的任务。对我们来说,这是必要的,在 Kubernetes 上构建定制数据湖和分析解决方案的好处大于坏处。

我将尝试更详细地重新审视这些组件,并提供一些示例代码来帮助开发过程。同时,请随时留下任何反馈/建议/评论。

从头开始构建云架构堆栈

原文:https://towardsdatascience.com/building-a-cloudformation-stack-from-scratch-691ea3a71571?source=collection_archive---------28-----------------------

新冠肺炎推文的数据接收管道

什么是自动气象站云形成

CloudFormation(CF)是一项服务,它允许您通过模板设置和管理 AWS 资源。这使得您可以将更多的时间用于开发应用程序,而不是管理和配置资源。

所以如果要建立以下基础设施;

  • 安全小组
  • EC2 实例
  • 一卷
  • 托管数据库(如 Amazon RDS)

AWS CF 将使用正确的配置按正确的顺序配置所有资源

自动气象站云形成的一些好处:

  • 代码为的基础设施
  • 因为资源不是手动创建的,所以可以通过 git 建立版本控制。对基础设施的改变现在可以通过代码来控制。
  • 一旦创建了一个模板,您可以通过估计成本选项找出每月的成本!
  • 通过创建堆栈或删除它,部署或销毁任何资源也很容易。

我们将从这篇文章中学到什么?

在本帖中,我们将创建一个 CloudFormation 堆栈来提供以下资源:

  • 一个弹性搜索域:用于存储和查询推文
  • 一个 S3 桶:存储未能处理的推文
  • Kinsesis firehose:用于流式传输 covid19 推文
  • Lambda 函数:用于处理推文

AWS 数据管道。使用 draw.io 创建

首先让我们了解我们正在处理的数据,然后我们将了解摄取管道。

新冠肺炎推特流

Twitter 在他们的 Twitter 开发者实验室中发布了一个流媒体端点。流媒体端点将根据其内部 COVID19 注释返回推文。端点配置了一组过滤器,提供了关于该主题的对话的综合视图。

[## 概观

有兴趣探索实验室吗?我们在实验室中发布的端点是可能会更广泛发布的工具的预览…

developer.twitter.com](https://developer.twitter.com/en/docs/labs/covid19-stream/overview)

这些推文是由南加州大学的一个团队从流媒体端点收集的。该数据集根据知识共享署名-非商业性使用-类似共享 4.0 国际公共许可证( CC BY-NC-SA 4.0 )进行许可。通过使用该数据集,您同意遵守许可中的规定,继续遵守 Twitter 的服务条款,并引用以下手稿:

Chen E,Lerman K,Ferrara E 追踪关于新冠肺炎疫情的社交媒体话语:公共冠状病毒推特数据集的开发 JMIR 公共卫生监测 2020;PMID: 32427106

截至 2020 年 9 月 14 日,该数据集拥有超过 5 . 38 亿条推文!

Covid19 数据集中的推文总数

数据摄取管道

由于 Twitter 开发人员 API 的 ToS,只有 tweet IDs 存储在 github repo 中。这被称为将推文脱水。

更新推文是当我们使用推文 ID 并调用 twitter API 来填充其他字段(字典键)时,更新的推文然后被放入一个数据流中,该数据流写入 Kinesis firehose。

Lambda 函数用于处理批量为 5MiB 的推文。

Lambda 函数用于从 Tweet 对象中选择特定的一组键。

处理后的 tweets 随后被存储在 ElasticSearch 域中。如果流程失败,它们将被路由到 S3 存储桶。S3 存储桶也可以用来存储 e S 索引的快照。

给推文 id 补水

我已经在下面的 github repo 中上传了这个项目的 python 代码和其他文件。请随意使用、分享和使用它:

https://github . com/skyprince 999/Data-Engineering-covid 19-ETL

我们现在将创建用于调配资源的堆栈。

S3 铲斗的造云模板

这是我们栈中最简单的模板。事实上,您甚至不需要指定 bucket-name!

弹性搜索领域的云信息模板

我们将使用模板为 ES 域提供配置。我们在集群中有 4 个数据节点(实例计数)每个都是类型 t2.small ( 实例类型)

所有节点都有 35GiB 的 EBS 卷( VolumeSize )

ElasticSearch 版本是最新的(7.7)(elastic search version)

下一个要点是提供 es 域的访问策略。我们允许在域上执行所有操作。对 SourceIP (*)也没有限制,这意味着您可以从任何 IP 地址访问该域。

这不是配置访问策略的最佳实践。您可以将访问策略更改为更具限制性。

kine sis 消防水带云形成模板

cloudformation 模板用于配置 Kinesis 消防软管。该流的类型为 DirectPut。数据的缓冲时间间隔为 300 秒或直到大小为 5mb!

处理后的数据存储在 ElasticSearch 域中,而失败的数据存储在 S3 桶中。因为 ES 域和 S3 桶是通过 CF 栈创建的。我们可以通过使用 Fn::GetAtt 函数来访问他们的域名

查看我的公共 github repo 中完整的 CloudFormation 模板:

[## sky prince 999/数据工程-Covid19-ETL

通过在 GitHub 上创建帐户,为 skyprince 999/Data-Engineering-covid 19-ETL 开发做出贡献。

github.com](https://github.com/skyprince999/Data-Engineering-Covid19-ETL)

模板文件可以通过 CloudFormation 控制台上传。

云形成控制台。上传模板 yaml 文件

在设计器中检查模板,然后将其上传到 S3 存储桶。

为堆栈提供一个名称,然后检查配置。您可以使用 AWS 估算器来计算资源的成本。

我们配置的总成本约为 2300 美元(每年);每月支付约 200 美元

用 Python 构建颜色识别器

原文:https://towardsdatascience.com/building-a-color-recognizer-in-python-4783dfc72456?source=collection_archive---------3-----------------------

使用 OpenCV 的简单实用的机器学习应用程序

Unsplash 上由 Kelli Tungay 拍摄的照片

在这篇文章中,我将向你展示如何使用 Python 来构建你自己的颜色识别器。这个过程也称为“颜色检测”。我们将创建一个基本的应用程序来帮助我们检测图像中的颜色。该程序还将返回颜色的 RGB 值,这非常有用。许多图形设计人员和网页设计人员会理解 RGB 值是如何有用的。构建颜色识别器是开始使用计算机视觉的一个很好的项目。

如果你以前没有听说过计算机视觉,这是了解它的最好时机。大多数机器学习和人工智能领域都与计算机视觉有着紧密的联系。随着我们的成长和探索,看到外面的世界对我们的发展有很大的影响。这对机器来说也是一样的,它们通过图像来观察外部世界,这些图像被转换成计算机可以理解的数据值。

在以前的帖子中,我展示了如何检测人脸以及如何识别图像中的人脸,这些都是在人工智能和计算机视觉中实践 python 的伟大项目。让我们做点工作吧!

目录

  • 入门
  • 定义图像
  • 颜色识别
  • 应用
  • 结果

入门指南

我们将为这个项目使用三个主要模块。他们是 NumPy,熊猫和 OpenCv。OpenCv 是一个高度优化的库,专注于实时应用。

OpenCV(开源计算机视觉库)是一个开源的计算机视觉和机器学习软件库。OpenCV 旨在为计算机视觉应用提供一个公共基础设施,并加速机器感知在商业产品中的应用。

来源:https://opencv.org

[## 每当贝希克居文出版时收到电子邮件。

每当贝希克居文出版时收到电子邮件。注册后,如果您还没有,您将创建一个中型帐户…

lifexplorer.medium.com](https://lifexplorer.medium.com/subscribe)

图书馆

如前所述,本项目将使用三个模块。要使用这些模块,我们必须安装必要的库。使用 pip 安装库是一个非常简单的步骤。Pip 是一个包管理工具。我们将使用命令行界面进行安装。下面是一次安装所有 3 个库的代码行:

pip install numpy pandas opencv-python

安装完成后,我们必须将它们导入我们的程序。在您喜欢的代码编辑器中打开一个新文件。以下是关于如何导入已安装库的代码:

import numpy as np
import pandas as pd
import cv2

OpenCv 作为 cv2 导入。对于其他库,我们将它们“作为”导入,以便在程序中更容易调用它们。

完美!现在,我们可以进入下一步,我们将定义要用来测试颜色识别器应用程序的图像。

定义图像

你可以选择任何你想要的图像。我会将我的图像保存在与我的程序相同的文件夹中,这样更容易查找和导入。

img = cv2.**imread**("color_image.jpg")

为了给你一些想法,这里是我将在这个项目中使用的图像:

照片由斯蒂夫·约翰森派克斯拍摄

太好了!你准备好编程了吗?抓紧时间,让我们进入下一步。

颜色识别

让我问你一个好问题。你知道机器是如此纯洁吗?嗯,我认为他们是因为你教他们什么,他们就学什么。它们就像一块白色的大画布。而你的程序就是你的画笔:)

教授颜色

首先,我们要教他们颜色。为此,我们需要包含颜色名称和一些与这些颜色匹配的值的数据。因为大多数颜色可以用红色、绿色和蓝色来定义。这就是为什么我们将使用 RGB 格式作为我们的数据点。我找到了一个现成的 csv 文件,其中有大约 1000 个颜色名称和 RGB 值。这里是 GitHub 链接。我们将在程序中使用这个 csv 文件。该文件的截图可以让您有所了解:

colors.csv

让我们使用 read_csv 方法将 colors.csv 文件导入到我们的程序中。因为我们下载的 csv 文件没有列名,所以我将在程序中定义它们。这个过程被称为数据操作。

index=["color", "color_name", "hex", "R", "G", "B"]csv = pd.read_csv('colors.csv', names=index, header=None)

全局变量

在下面的步骤中,我们将定义两个函数。为了让应用程序顺利工作,我们需要一些全局变量。你将知道在使用函数时全局变量是如何有用的。

clicked = False
r = g = b = xpos = ypos = 0

颜色识别功能

当我们双击图像的一个区域时,这个函数将被调用。它将返回颜色名称和该颜色的 RGB 值。这就是奇迹发生的地方!

def recognize_color(R,G,B):
    minimum = 10000
    for i in range(len(csv)):
        d = abs(R- int(csv.loc[i,"R"])) + abs(G- int(csv.loc[i,"G"]))+ abs(B- int(csv.loc[i,"B"]))
        if(d<=minimum):
            minimum = d
            cname = csv.loc[i,"color_name"]
    return cname

鼠标点击功能

这个函数用来定义我们的双击过程。在创建我们的应用程序部分时,我们将需要它。

def mouse_click(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDBLCLK:
        global b,g,r,xpos,ypos, clicked
        clicked = True
        xpos = x
        ypos = y
        b,g,r = img[y,x]
        b = int(b)
        g = int(g)
        r = int(r)

希望你还和我在一起!这看起来可能有点复杂,但是当你开始在编辑器中写它们时,大局就会变得清晰起来。我尽最大努力让事情简单易懂。我会在这篇文章的最后加上我的联系方式,如果你需要任何帮助,请联系我。

应用

我很高兴你走到了这一步。在这一步,我们将使用 OpenCV 方法打开图像作为一个新窗口。在该窗口中,我们将使用之前定义的函数。这个应用程序非常简单,当你双击图像上的某个区域时,它会返回颜色名称和颜色值。

应用程序窗口

首先,让我向您展示如何使用 OpenCV 在新窗口中打开图像文件。

cv2.namedWindow('Color Recognition App')

其次,让我们调用我们创建的鼠标点击函数。这为我们的应用程序提供了更多的功能。

cv2.setMouseCallback('Color Recognition App', mouse_click)

应用程序

下面是开始我们的应用程序窗口工作的 while 循环。

while(1):cv2.imshow("Color Recognition App",img)
    if (clicked):

        #cv2.rectangle(image, startpoint, endpoint, color, thickness)-1 fills entire rectangle 
        cv2.rectangle(img,(20,20), (750,60), (b,g,r), -1)#Creating text string to display( Color name and RGB values )
        text = recognize_color(r,g,b) + ' R='+ str(r) +  ' G='+ str(g) +  ' B='+ str(b)

        #cv2.putText(img,text,start,font(0-7),fontScale,color,thickness,lineType )
        cv2.putText(img, text,(50,50),2,0.8,(255,255,255),2,cv2.LINE_AA)#For very light colours we will display text in black colour
        if(r+g+b>=600):
            cv2.putText(img, text,(50,50),2,0.8,(0,0,0),2,cv2.LINE_AA)

        clicked=False

关闭应用程序

如果您使用过 OpenCV 项目,您可能对这个步骤很熟悉。我们必须定义如何结束和关闭应用程序窗口。否则,它将永远运行,因为我们使用了 while(1) 来启动应用程序。添加下面几行对于您将来的项目来说是一个很好的实践。

#Break the loop when user hits 'esc' key    
    if cv2.waitKey(20) & 0xFF ==27:
        breakcv2.destroyAllWindows()

结果

目前,我正在为这个项目制作一个演示视频。我收到了许多关于演示视频的积极反馈,它让我更好地了解了项目和申请流程。视频将发布在我的 youtube 频道 上。

(更新:视频准备好了,下面有。谢谢😊)

视频演示

恭喜你。!您已经创建了一个很酷的计算机视觉应用程序,它可以识别图像中的颜色。现在,您对如何在实际项目中使用计算机视觉有了一些了解。希望你喜欢读我的文章。如果你今天学到了新东西,我会很高兴的。从事像这样的动手编程项目是提高编码技能的最好方式。

如果您在执行代码时有任何问题,请随时联系我

关注我的博客走向数据科学以获得灵感。谢谢你,

更多计算机视觉项目:

[## 使用 Python 渲染视频文本

使用 moviePy 库的动手机器学习项目

towardsdatascience.com](/rendering-text-on-video-using-python-1c006519c0aa) [## 用 Python 构建人脸识别器

使用 OpenCv 库进行实时人脸识别的分步指南

towardsdatascience.com](/building-a-face-recognizer-in-python-7fd6630c6340)

构建命令行应用程序来检查开源漏洞

原文:https://towardsdatascience.com/building-a-command-line-application-to-check-for-open-source-vulnerabilities-360a3024528f?source=collection_archive---------35-----------------------

弗朗茨·哈文·阿西图纳在 Unsplash 上拍摄的照片

开源软件、编程语言或项目中的漏洞是一件大事,因为一次利用可能会导致许多混乱,并导致大组织数千美元的损失。

许多公司一直在关注软件中的漏洞、依赖性和他们在驱动系统时使用的语言,因为如果其中一个漏洞被利用,它们可能会受到攻击。

幸运的是,我们有一个公共数据库,所有新发现的漏洞和常见弱点都在其中公布,并在发现后立即提供修复。这些公开发布的漏洞数据库可以在类似 CVENVD白源漏洞数据库等网站上找到。

通过这些网站,您可以轻松地查找带有 ID 的漏洞,并获得相关信息。您可以了解严重性级别、受影响的组件、有时是什么导致了错误、如何临时或永久地修复它。

我们还可以通过构建一个简单的命令行应用程序来查找漏洞细节和信息,从而自动化并加速这一过程。

因此,在本文中,我们将探讨如何使用 Python 构建一个命令行实用程序来查找漏洞细节。

设置 Python 环境

构建命令行实用程序的第一步是设置 Python 开发环境。当从事 Python 项目时,我总是建议建立一个虚拟环境,因为它使事情变得更容易,并有助于避免模块版本中的冲突。

如果您使用 Python 3,您可以轻松运行 python3 -m venv 来创建虚拟环境,或者安装 virtualenvwrapper 或 virtualenv 来帮助设置虚拟环境。你可以在这里阅读更多关于如何设置你的环境的

一旦您的环境启动,下一件事就是安装构建我们的应用程序所需的模块:

$ pip install requests beautifulsoup4 click lxml

对于这个项目,我们安装了:

  1. 请求:Python HTTP 请求客户端库
  2. BeautifulSoup:用于从 HTML 和 XML 解析和提取数据的 Python 库
  3. 点击:一个丰富的 python 命令行框架
  4. LXML:用于处理 HTML 和 XML 的 BeautifulSoup deps。

接下来,我们可以使用以下内容创建文件夹结构:

$ mkdir vulr && cd vulr
$ touch scraper.py main.py __init__.py

以下是适用于您的环境的完整设置命令:

$ python3 -m venv vulr-env && source vulr-env/bin/activate$ pip install requests beautifulsoup4 click lxml$ mkdir vulr && cd vulr$ touch scraper.py main.py __init__.py$ pip freeze > requirements.txt$ touch readme.md .gitignore # optional

您应该会得到如下所示的内容:

编写我们的网页抓取器

要使用我们的命令行从 WhiteSource 漏洞数据库中获取详细信息,我们需要构建一个简单的 web scraper,用于从数据库中提取所需的数据和关于漏洞的信息。

之前我们安装了 Requests 和 Beautifulsoup,我们将一起使用它们来构建一个简单的刮刀,并提取关于漏洞的所有可用细节。

基本上,当给定一个特定漏洞的 CVE ID 时,我们的网络抓取器将提取该漏洞的可用信息。为了便于识别,CVE ID 是给每个已发布漏洞的唯一 ID。

现在让我们为我们的 scraper 编写一个基本的代码设置:

import requests
from bs4 from BeautifulSoupBASE_URL = "[https://www.whitesourcesoftware.com/vulnerability-database/](https://www.whitesourcesoftware.com/vulnerability-database/)"def get_html(url):
   request = requests.get(url)
   if request.status_code == 200:
     return request.content
   else:
    raise Exception("Bad request")def lookup_cve(name):
   pass

上面我们已经为我们的网页抓取器创建了一个基本结构。我们添加了 WhiteSource 漏洞查找 URL,添加了获取请求的 HTML 内容的函数,还添加了一个空的 lookup_cve 函数。

现在让我们前往这个 WhiteSource Vuln Lab ,打开开发者控制台,研究页面的 DOM 结构。

接下来的事情是提取请求网页时发送的标题和 cookies。为了向网页发送一个成功的请求,我们需要像浏览器一样工作,这样我们就不会得到一个禁止的错误。

您可以在“Network”选项卡上执行此操作,因此单击“on ”,然后单击“All”。然后点击发送的请求以获取网页。它通常是浏览器发出的第一个请求。

右键单击它,鼠标悬停在复制上,然后单击复制为卷曲。这将以 cURL 格式复制请求,包括其标题和 cookies:

现在提取 cURL 命令,包括 Python 请求的头和 cookies,我们可以很容易地使用这个工具。这将有助于将 cURL 命令转换成任何语言和流行的 HTTP 请求库。

你所需要做的就是粘贴你的 cURL 命令,选择 Python,你就会得到一个格式良好的 Python 请求实现:

现在,从第二个文本框开始,我们将复制出 headers 和 cookies 字典,并更新我们的代码,如下所示:

import requests
from bs4 from BeautifulSoupBASE_URL = "[https://www.whitesourcesoftware.com/vulnerability-database/](https://www.whitesourcesoftware.com/vulnerability-database/)"cookies = {
'_ga': 'GA1.2.1677532255.1591419793179',
...
}headers = {
'authority': '[www.whitesourcesoftware.com'](http://www.whitesourcesoftware.com'),
'cache-control': 'max-age=0',
...
}def get_html(url):
   request = requests.get(url, headers=headers, cookies=cookies)
   print(request.content)
   if request.status_code == 200:
     return request.content
   else:
     raise Exception("Bad request")

接下来要做的是使用 dom 结构有序地提取页面上显示的所有信息。

根据上面的代码,我们:

  1. 提取了描述、日期、语言、引用、严重性分数、top_fix、弱点和报告。
  2. 我们添加了另一个函数 extract_cvs_table,从页面右侧的 cvs 表中提取数据。
  3. 然后我们将结果组织成一个简单的字典

要测试这一点,只需调用函数并传递 CVE id:

cve_details = lookup_cve("CVE-2020-6803")print(cve_details)

然后运行:

$ python scraper.py

瞧啊。我们已经成功地创建了我们的网络刮刀。

构建我们的命令行应用程序

现在要做的下一件事是使用我们之前安装的 click 库构建我们的命令行应用程序。

正如我之前简要解释的,Click 是一个命令行框架,由于其简单性和结构性,它是你能找到的最好的框架之一。

首先,让我们看看 main.py 中的 CLI 代码设置:

import sys
import click[@click](http://twitter.com/click).group()
[@click](http://twitter.com/click).version_option("1.0.0")
def main():
    """Vulnerability Lookup CLI"""
    print("Hey")[@main](http://twitter.com/main).command()
[@click](http://twitter.com/click).argument('name', required=False)
def look_up(**kwargs):
    """Get vulnerability details using its CVE-ID on WhiteSource Vuln Database"""
    click.echo(kwargs)if __name__ == '__main__':
    args = sys.argv
    if "--help" in args or len(args) == 1:
        print("Vulnerability Checker - Vulr")
    main()

通过上面的设置,我们创建了一个名为 look_up 的命令,并向该命令传递了一个参数——name。这将是用于获取漏洞信息的命令。

要在这个命令上实现 web scraper,您需要从 scraper.py 导入 lookup_cve,并将参数传递给函数。一旦我们这样做了,我们就可以通过打印来显示结果数据。

下面是如何做到这一点:

要运行此程序:

$ python main.py look-up CVE-2014-8338

哒哒!我们的命令行应用程序正在工作。

最后的想法

到目前为止,我们已经探索了如何构建一个 web scraper 来从 WhiteSource 漏洞数据库中提取数据,以获得漏洞信息,并在命令行应用程序中实现它,以便它可以用于直接从命令行显示漏洞细节。

接下来你可以在 PyPI 上发布它,这样其他用户就可以使用 PIP 包管理器来安装和使用它。

用 Elasticsearch、Kubeflow 和 Katib 构建一个完整的基于人工智能的搜索引擎

原文:https://towardsdatascience.com/building-a-complete-ai-based-search-engine-with-elasticsearch-kubeflow-and-katib-590c7b27eb8f?source=collection_archive---------12-----------------------

让我们看看如何在 Kubernetes 的基础上建立一个完整的搜索引擎,提供人工智能个性化的结果

建立搜索系统很难。让他们准备好机器学习真的很难。开发一个完整的集成 AI 的搜索引擎框架真的真的很难。

所以我们做一个吧。✌️

在这篇文章中,我们将从头构建一个搜索引擎,并讨论如何通过使用 Kubeflow 和 Katib 添加机器学习层来进一步优化结果。考虑到用户的上下文,这个新层将能够检索结果,这也是本文的主要焦点。

正如我们将看到的,多亏了 Kubeflow 和 Katib,最终的结果相当简单、高效且易于维护。

由 Kubeflow 执行的完整管道,负责协调整个系统。图片作者。

为了在实践中理解这些概念,我们将通过实践经验来实现这个系统。因为它是建立在 Kubernetes 之上的,所以您可以使用任何您喜欢的基础设施(只要经过适当的修改)。在这篇文章中,我们将使用谷歌云平台( GCP )。

我们首先简要介绍概念,然后讨论系统实现。

所以,没有进一步的麻烦,

1.你知道,为了搜索

如果你接受为你的公司建立一个搜索系统的挑战,或者想为你自己建立一个,你很快就会意识到最初的步骤有些简单。

首先,搜索引擎必须包含用于检索的文档。由于我们将与 Elasticsearch 合作,让我们将其作为参考(关于介绍,请参考他们的官方文件

文档应该按照 JSON 格式上传到 Elasticsearch。例如,如果我们正在为一个时尚电子商务商店构建一个搜索引擎,这里有一个文档示例:

上传到 Elasticsearch 的文档示例。图片作者。

接下来是检索步骤,本质上是将搜索查询与文档字段进行匹配:

搜索词与文档字段匹配的示例。图片作者。

排序阶段应用一些数学规则,如 TF-IDFBM25F 来找出如何正确排序,从最佳到最差匹配对文档进行排序。大概是这样的:

Elasticsearch 在数据库中存储的文档中运行 BM25 评分检索到的正确排名的结果示例。图片作者。

进一步的优化可以利用包含性能指标的文档的特定字段。例如,在前面的例子中,我们知道 t 恤的点击率(CTR,即点击和总印象之间的原因)是 CTR=0.36 。可以使用该信息添加另一个检索层,并且将具有更好 CTR 的文档显示在顶部(也称为“提升”):

在检索规则中添加性能指标层的示例。先前的第二好的文档上升到结果的顶部。图片作者。

到目前为止一切顺利。但是让我们看看如何进一步优化更多。

考虑每个用户都有一个特定的上下文。再以我们的时尚网店为例。一些交通可能来自南方地区,那里可能比北方地区更热。他们可能更愿意穿轻薄的衣服,而不是冬季专用的产品。

等式中还可以加入更多的上下文:我们可以根据顾客喜欢的品牌、类别、颜色、尺寸、使用的设备、平均消费金额、职业、年龄来区分他们,这样的例子不胜枚举…

这样做也需要一些额外的工具。让我们深入一点。

2.机器学习层

Learn-to-rank ( LTR )是机器学习的一个领域,它研究的算法的主要目标是对一系列文档进行适当的排序。

它本质上像任何其他学习算法一样工作:它需要一个训练数据集,遭受诸如偏差之类的问题,每个模型都比某些场景有优势,等等。

基本上改变的是,训练过程的成本函数被设计成让算法学习排序,并且模型的输出是给定文档对于给定查询的匹配程度的值。

从数学上讲,它简单地由下式给出:

在我们的例子中, X 包含了我们想要用来为搜索添加上下文的所有特性。它们可以是诸如用户的地区、他们的年龄、喜爱的品牌、查询和文档字段之间的相关性等值。

f 是应该被训练和评估的排序模型。

最后, J判断进行了扩展,对于我们来说,它是一个范围从 0(意味着对于给定的查询特性,文档不是很好的匹配)到 4(文档是非常好的匹配)的整数值。我们通过使用判断从最好到最差排列文档

我们的主要目标是获得 f ,因为它表示将机器学习层添加到搜索结果中的排序算法。为了获得 f ,我们需要一个已经包含判断值的数据集,否则我们无法训练模型。

事实证明,找到这些价值是相当具有挑战性的。虽然如何做到这一点的细节不会在这里讨论,这篇的帖子对这个话题有一个彻底的讨论;简而言之,我们使用用户与搜索引擎交互的点击流数据(他们的点击和购买)来拟合模型,这些模型的变量产生了判断值的代理。

pyClickModels 上实现的图形模型示例,用于查找与搜索引擎结果相关联的文档的相关性。图片作者。

在计算判断之后,我们剩下的是训练排名模型。Elasticsearch 已经提供了一个学习排名插件,我们将在这个实现中使用。该插件提供了从决策树到神经网络的各种排序算法。

这是所需培训文件的一个示例:

Elasticsearch Learn2Rank 插件要求的训练步骤的输入文件示例。图片作者。

这个想法是为每个查询(“women t-shirt”)注册结果页面中打印的所有文档。对于每个人,我们计算他们的预期判断并构建特征矩阵X

在实践中,我们将首先准备所有这些数据,并将其输入到 Elasticsearch 的 Learn-To-Rank 插件中,这将产生一个经过训练的排名模型。然后,它可以用来添加我们正在寻找的个性化层。

关于建造 X 的更多细节将很快被讨论。

我们现在准备训练模型。到目前为止一切顺利。但是,我们仍然有一个棘手的问题:如何知道它是否有效?

2.1 估价框架

我们可以从几种方法中选择来检查排名模型的性能。我们将在这里讨论的是基于用户点击或购买的平均排名指标( pySearchML 只关注购买事件,但点击可以互换使用)。

数学上,它由下式给出:

该公式参考完整的文档列表,对与每个购买(或点击)的项目相关联的每个排名进行求和。分母只是流程中汇总的商品数量的基数(用户点击或购买的商品总数)。

实际上,在训练一个排名模型后,我们将遍历验证数据集(包含用户搜索的内容和购买的内容),并使用每个搜索词向 Elasticsearch 发送一个查询。然后,我们将结果与用户购买的东西进行比较,以计算适当的平均排名。

实践中的验证框架示例。对于数据集中的每个用户,我们使用他们的搜索词从 ES 结果中检索已经实现的排名模型。然后,我们获取用户购买商品的平均排名以及它们在 ES 结果中的位置。图片作者。

上图说明了这个概念。对于每个用户,我们将他们的搜索词发送到 Elasticsearch,其中已经包含了最近训练的模型。然后,我们将搜索结果与用户购买的内容进行比较,并计算排名。在前面的示例中,红色 t 恤出现在 3 个检索到的项目中的位置 2。因为只购买了一件商品,所以排名=66%。**

我们对数据库中的所有用户运行相同的计算,然后对它们进行平均,得到最终的排名表达式。

请注意,最终的等级度量必须低于 50% ,否则该算法只是作为文档的随机选择器来执行。

这个值很重要,因为它用于选择最佳排名模型。这就是我们使用 Kubeflow 的 Katib 的地方。

现在让我们看看如何将所有这些概念放在一起并构建搜索引擎:

3.库伯流程编排

如前所述,Kubeflow 是管道处理的指挥者。它的职责多种多样,从为 Elasticsearch 和培训准备数据到运行整个培训流程。

它通过定义组件及其各自的任务来工作。对于 pySearchML,下面是实现的完整的管道:

管道是通过接收各种输入参数来定义的,比如bucketmodel_name,我们将能够在执行时更改这些值(我们很快就会看到)。

让我们看看管道实施中的每个组件及其用途:

在 pySearchML 中逐步实现。图片作者。

1.准备 _ 环境

下面是如何定义 prepare_env 组件的:

  • **图像是在该步骤中运行的组件的 docker 引用。
  • **参数是发送给在 Docker 的映像ENTRYPOINT中执行的脚本的输入参数。
  • pvolumes 将卷声明装入\data

这里是prepare _ env 中的所有文件:

  • run.py负责针对 BigQuer y 运行查询,并准备 Elasticsearch。它的输入参数之一是model_name,它设置使用哪个文件夹作为处理数据的参考。lambdamart0是一种已经实现的算法,可用于 Google Analytics(GA) 公共样本数据集。

  • [Dockerfile](https://github.com/WillianFuks/pySearchML/blob/master/kubeflow/components/prepare_env/Dockerfile)将整个代码捆绑在一起,并作为ENTRYPOINT执行run.py脚本:

  • lambdamart0是一个文件夹,专用于以此命名的算法的实现。它是为处理 GA 公共数据而构建的,是该系统的一个示例。以下是它包含的文件:

  • [ga_data.sql](https://github.com/WillianFuks/pySearchML/blob/master/kubeflow/components/prepare_env/lambdamart0/ga_data.sql)是一个查询,负责从 GA 公共数据集中检索文档,并将其导出到 Elasticsearch
  • [es_mapping.json](https://github.com/WillianFuks/pySearchML/blob/master/kubeflow/components/prepare_env/lambdamart0/es_mapping.json)是文档中每个字段的索引定义
  • 如前所述,[features](https://github.com/WillianFuks/pySearchML/tree/master/kubeflow/components/prepare_env/lambdamart0/features)携带 X 的值。在lambdamart0示例中,它使用 GA 公共数据作为构建特性的参考。

请注意名为[name.json](https://github.com/WillianFuks/pySearchML/blob/master/kubeflow/components/prepare_env/lambdamart0/features/name.json)的特性:

学习排名插件要求将每个特征定义为有效的弹性搜索查询,并且分数结果与 X. 相关联

在前面的例子中,它接收一个参数search_term,并继续对返回 BM25 匹配的每个文档的字段name进行匹配,这实际上变成了我们的“ X0 ”。

在查询和名称字段之间使用 BM25 不足以增加结果的个性化。定制层的另一个进步是定义如下的[channel_group.json](https://github.com/WillianFuks/pySearchML/blob/master/kubeflow/components/prepare_env/lambdamart0/features/channel_group.json):

它接收参数channel_group(将用户带到我们的网络商店的渠道)作为输入,并返回相应渠道的 CTR。

这有效地准备了模型来区分用户的来源以及如何对每个组进行排序。具体来说,例如,来自付费渠道的用户可能与来自有机渠道的用户行为不同。如果训练足够好,排序算法应该准备好处理这些情况。

尽管如此,这并没有告诉如何通过使用每个用户的内在特征来个性化结果。因此,这里有一个解决这个问题的可能性。特征[avg_customer_price.json](https://github.com/WillianFuks/pySearchML/blob/master/kubeflow/components/prepare_env/lambdamart0/features/avg_customer_price.json)定义为:

它接收参数customer_avg_ticket作为输入,并为每个文档返回平均用户票和文档价格之间的距离的日志。

现在,排名模型可以在训练阶段学习如何根据每个项目的价格与用户在网站上的平均支出的距离来管理每个项目的排名。

有了这三种类型的功能,我们可以在 Elasticsearch 的基础上为搜索系统添加一个完整的个性化层。特性可以是任何东西,只要它可以被抽象成一个有效的搜索查询,并且它们必须返回一些最终被翻译成我们的值 X 的评分标准。

对于 prepare_env 组件中的内容:

  • 要素被导出到 Elasticsearch。
  • Elasticsearch 上创建了一个定义文档字段的索引。
  • BigQuery 查询文档并上传到 Elasticsearch。
  • 创建 RankLib 需求(特性集存储等等)。

为了用新的数据和特性实现新的模型,只需在 prepare_env(类似于modelname2)中创建另一个文件夹,并设置它将如何查询数据并将它们上传到 Elasticsearch。

2.验证数据集

这是一个简单的步骤。它包括从 BigQuery 检索数据,其中包含用户搜索的内容、搜索的上下文和购买的产品列表。

下面是用于检索数据的 BigQuery 查询。它基本上选择所有用户,他们的搜索和购买,然后结合他们的背景。结果的一个例子:

search_keys可以包含设置客户上下文的任何可用信息。在前面的例子中,我们在网站上使用他们的渠道组和平均消费票。

这些数据是我们在计算之前讨论的平均排名时输入到验证框架中的。

请注意,系统构建了三个不同的验证数据集:一个用于训练期,另一个用于常规验证,最后第三个用于最终测试步骤。这里的想法是分析训练模型的偏差和方差。

3.训练数据集

如前所述,这是负责构建 RankLib 训练文件的组件。完整的脚本其实相当简单。首先,它从 BigQuery 下载包含用户在搜索页面上的交互的输入点击流数据。这里有一个例子:

请注意,与搜索相关的关键字在search_keys中聚集在一起。这些值是我们发送给 Elasticsearch 并适当替换每个特性 X 的值,如 prepare_env 中所述。在前面的 JSON 示例中,我们知道用户搜索上下文是:

  • 已搜索酒具
  • 直接来到店里。
  • 在网站上平均花费 20 美元。

judgment_keys将用户在搜索页面上看到的文档组成的会话和他们在给定文档上的交互结合起来。

这些信息随后被发送到 pyClickModels ,后者处理数据并评估每个查询-文档对的判断。结果是换行符分隔的 JSON 文档,如下所示:

注意,键的值是search_term:bags|channel_group:organic|customer_avg_ticket:30

如前所述,我们希望我们的搜索引擎知道上下文,并在此基础上进一步优化。因此,判断是基于整个选定的上下文提取的,而不仅仅是 search_term。

通过这样做,我们可以区分每个上下文的文档,例如,我们会有这样的场景,对于来自北方地区的客户,产品接收到的判断为 4,否则为 0。

请注意,pyClickModels 给出的判断值的范围是 0 到 1。由于 Learn-To-Rank Elasticsearch 插件是建立在 RankLib 之上的,这个值的范围应该在整数 0 和 4 之间,包括 0 和 4。我们接下来要做的是,用变量的百分位数作为参考来转换变量。下面是构建最终判决文件的完整代码:

以下是此步骤的输出示例:

这些数据需要转换成 RankLib 所需的训练文件。在这里,我们将判断、文档、查询上下文的信息与特性 X 结合起来(这里是从 Elasticsearch 检索 X代码示例)。

上一步中包含搜索上下文和判断键的每一个 JSON 行都被循环并作为一个查询发送给 Elasticsearch,输入参数为search_keys。结果将是从先前的准备 _ 环境步骤中已经定义的 X 的每个值。

最终结果是一个类似如下的培训文件:

对于每个查询和每个文档,我们都有由 pyClickModels 计算出的估计判断、查询的 id 以及一个特性列表 X 及其各自的值。

有了这个文件,我们现在可以训练排名算法。

4.Katib 优化

Katib 是一款来自 Kubeflow 的工具,它提供了一个自动超参数优化的接口。它有几种可用的方法;pySearchML 中选择的是贝叶斯优化。

贝叶斯优化算法的例子。随着它从允许的域中采样更多的数据点,它可能越接近给定函数的最佳值。在 pySearchML 中,域是一组变量,设置排名器应该如何拟合数据,它优化的成本函数是平均排名。图片来自维基媒体基金会

Katib 所做的是根据勘探-开采之间的权衡为每个超参数选择一个新值。然后,它测试新模型并观察用于未来步骤的结果。

对于 pySearchML,每个参数都是一个 RankLib 的输入,RankLib 设置模型将如何拟合(例如使用多少棵树、总叶节点、网络中有多少神经元等等)。

Katib 是通过 Kubernetes 的自定义资源定义的。我们可以通过定义一个 YAML 文件并将其部署到集群来运行它,如下所示:

kubectl create -f katib_def.yaml

Katib 要做的是通读 YAML 文件并开始试验,每个试验一个特定的超参数值。它可以实例化并行运行的多个 pod,执行实验定义中指定的代码。

以下是此步骤中的文件:

[launch_katib.py](https://github.com/WillianFuks/pySearchML/blob/master/kubeflow/components/model/launch_katib.py)负责从 Python 脚本启动 Katib。它接收输入参数,构建 YAML 定义,并使用 Kubernetes APIs 从脚本本身启动 Katib。

[experiment.json](https://github.com/WillianFuks/pySearchML/blob/master/kubeflow/components/model/experiment.json)作为实验定义的模板。下面是它的定义:

它本质上定义了并行运行多少个 pods,以及为每个试验运行哪个 Docker 图像及其输入命令。请注意,并行运行的 pods 总数以及最大试验次数在 pySearchML 中是硬编码的。最好的方法是从管道执行中接收这些参数,并相应地替换它们。

launch_katib.py 将读取该模板,构建最终的 YAML 定义并将其发送给 Kubernetes,后者将启动 katib 流程。

其中一个输入参数是 ranker 它是从 RankLib(如 lambdaMart、listNet 等)中选择的排序算法。每个排名器都有自己的一组参数,下面是 launch_katib.py 中实现的 LambdaMart 算法的示例:

Katib 将从上面定义的域中选择参数,并运行 train.py ,其中 RankLib 被有效地用于训练排名模型。Python 中实现的命令示例:

这个字符串被发送给一个subprocess调用(注意它需要 Java,因为 RankLib ),这个调用启动了训练过程。结果是一个新训练的排名模型,可以导出到 Elasticsearch。

当模型合适时,调用 validate.py 来计算期望的等级。发生的步骤是:

  • 该脚本遍历验证数据集中的每个 JSON。

  • 每一行都包含搜索上下文,然后用于构建 Elasticsearch 查询。下面是模型lambdamart0使用的查询,我们稍后会用到它:

  • 给定最近构建的查询,向 Elasticsearch 发送一个请求。

  • 在搜索结果和购买的文档之间进行比较。

下面是负责构建 Elasticsearch 查询的代码:

注意,参数rescore_query触发了 Elasticsearch learn-to-rank 插件上的机器学习层。

最后,函数compute_rank将所有这些放在一起,如下所示:

Katib 实例化sidecars pod,它通过训练 pod 的 stdout 保持读取。当它识别字符串Validation-rank=(...)时,它使用该值作为优化过程的结果。

在该过程中使用了一个持久卷来保存由 Katib 训练的最佳模型的定义,该模型将被我们的下一个组件使用。

5.后等级模型

最困难的部分已经完成了。现在所发生的是脚本简单地跟踪保存在文本文件中的最佳模型的定义,并将其上传到 Elasticsearch。

请注意,这种设计的主要优势之一是,该组件可以将模型导出到生产弹性搜索,而整个优化可以在分段复制引擎上进行。

6.最终测试

最后,当最佳模型被导出到 Elasticsearch 时,该系统就拥有了最佳优化排序模型。在该步骤中,执行最终验证,以便不仅验证一切工作正常,而且提供关于系统是否遭受偏差变化的进一步信息。

差不多就是这样!现在让我们运行一些代码来看看整个框架的运行情况。

4.动手操作部分

是时候在实践中实现整个架构了!完整的代码可从 pySearchML 资源库获得:

* [## WillianFuks/pySearchML

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/WillianFuks/pySearchML)

在这一节中,我们将使用 GCP 来用真实数据运行代码。此外,请记住,运行这个实验会有相关的成本(几美分)。

对于那些刚到 GCP 的人,有一个持续一年的 300 美元的免费信用礼品;只需登录并为本教程创建一个项目(例如 pysearchml )。您最终应该可以访问如下所示的仪表板:

GCP 仪表板项目示例。图片作者。

通过命令行与 GCP 交互需要 gcloud 。安装它非常简单。初始设置完成后,确保您可以通过运行以下命令登录:

gcloud auth login

现在剩下的就很简单了。将 pySearchML 克隆到您的本地:

git clone pysearchml && cd pySearchML

在您的平台中启用 Kubernetes 引擎。之后,只需触发执行 cloudbuild ,它将负责创建整个所需的基础设施(这一步应该需要 5~10 分钟)。

下面是构建如何触发运行:

您可以在变量SUBSTITUTIONS中选择合适的值。注意_VERSION设置了要导出到 Kubeflow 的管道版本。设置好一切后,只需运行脚本:

./kubeflow/build/build.sh

在 cloudbuild 上执行的步骤。图片作者。

  1. 准备密钥以允许访问和授权进入 GCP 工具。
  2. 在构建机器中准备已知主机。
  3. 本地克隆 pySearchML。
  4. 在步骤 4 中运行的文件 create_k8.sh 负责在 Google Kubernetes 引擎( GKE )之上创建 Kubernetes 集群,以及部署 Elasticsearch、Kubeflow 和 Katib。与此同时,系统所需的所有 Docker 映像都被构建并部署到 Google Container Registry(GCR)中,供以后在 Kubeflow 中使用。
  5. 运行几个单元测试。这些对于确认系统是否按预期运行非常重要。此外,它并行编译 Kubeflow 管道。
  6. 最后,将管道部署到集群。

完成后,如果你浏览到你的控制台并选择“Kubernetes 引擎”,你会看到它已经启动并运行:

Kubernetes 集群部署到 GKE 准备运行。图片作者。

这是一个小集群,因为我们不会使用太多数据,这有助于进一步节省成本。

已经安装了 Kubeflow 和 Katib。要访问它,首先运行以下命令将您的 gcloud 连接到集群:

gcloud container clusters get-credentials pysearchml

之后,通过运行以下命令将处理 Kubeflow 的服务移植到本地:

kubectl port-forward -n kubeflow svc/ml-pipeline-ui 8080:80 1>/dev/null &

现在,如果您在端口 8080 上访问本地主机,您应该会看到以下内容:

Kubeflow 仪表盘。图片作者。

并且流水线准备好执行。

这个实验使用公开的谷歌分析样本数据集,它由在谷歌商店浏览的一小部分客户样本组成。它从2016080120170801不等,包含每个用户搜索的内容以及他们如何与搜索结果交互。

选择pysearchml_0.0.0,然后选择“+创建运行”。您应该看到一个屏幕,其中显示了 Python 管道脚本中定义的所有可能的输入参数。选择合适的参数后,运行代码即可。

执行后,预期的结果如下:

完全执行 pySearchML 中定义的整个管道。图片作者。

Katib 组件的输出:

Katib 组件打印的输出示例。图片作者。

我们可以看到一个排名 36.05% 。然后,我们可以比较测试组件的结果:

测试组件打印的输出示例。图片作者。

这里的排名是 40.16 % 比验证数据集差一点。这可能表明模型有点过度拟合;更多的数据或进一步的参数探索可能有助于缓解这个问题。

而且,差不多,你有它!Elasticsearch 现在有一个经过全面训练的新的机器学习层,可以根据客户的背景来改善结果。

如果您想浏览为每个步骤创建的文件,有一个可用的部署。在 pySearchML 文件夹中,只需运行:

kubectl apply -f kubeflow/disk-busybox.yaml

如果您运行kubectl -n kubeflow get pods,您会看到其中一个 pod 的名称类似于“nfs-busybox-(…)”。如果你进入它,你就可以访问这些文件:

kubectl -n kubeflow exec -it nfs-busybox-(...) sh

它们应该位于/mnt/pysearchml

还有一个快速和肮脏的可视化的整个过程。只需运行:

kubectl port-forward service/front -n front 8088:8088 1>/dev/null &

localhost:8088访问你的浏览器。您应该会看到这个(又快又难看)的界面:

用于在新培训的 Elasticsearch 上运行查询的前端界面。图片作者。

结果示例:

它不仅允许我们摆弄结果,还能让我们更好地了解优化管道是否在工作。

这几乎就是让一个完整的搜索引擎运行人工智能优化来处理任何商店的收入流量所需要的全部。

5.结论

现在,这是一个挑战!

构建 pySearchML 相当困难,我可以有把握地说这是我所面临的最残酷的挑战之一😅。无数的设计、架构、基础设施被考虑,但大多数都失败了。

在 Kubeflow 和 Katib 之上集成整个流程的实现只是在几个备选方案已经测试过之后才实现的。

这种设计的优点是最终代码变得非常简单和直接。它是完全模块化的,每个组件负责一个简单的任务,Kubeflow 协调整个执行过程。最重要的是,我们可以把主要精力放在代码开发上,让 Katib 去做寻找最佳参数的艰苦工作。

开发过程并不简单。必须吸取几个教训,包括来自 Kubernetes 的概念及其可用资源。尽管如此,这一切都是值得的。结果,一个完整的搜索引擎可以用几行代码从零开始构建,准备好处理真正的流量。

作为下一步,人们可能会考虑用某种深度学习算法来取代 RankLib,这种算法将进一步从数据中提取上下文。这样做的主要挑战之一是系统的响应时间可能会增加,成本也会增加(必须评估利弊)。

不管使用什么排序算法,体系结构在很大程度上保持不变。

希望这对于在这个领域工作的人来说是一个有用的帖子。现在是时候让我们休息一下,思考一下学到的教训,为下一次冒险做准备了:)。

至于这个帖子,它当然值得以任务完成配乐结束。

和往常一样,

下次任务再见;)!*

用 Python 为量化交易构建一套全面的技术指标

原文:https://towardsdatascience.com/building-a-comprehensive-set-of-technical-indicators-in-python-for-quantitative-trading-8d98751b5fb?source=collection_archive---------4-----------------------

机器学习和统计算法的可定制综合指标

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

概述

预测资产价格变动一直是一个广泛研究的领域,旨在开发能够“准确”捕捉这些资产价格变动的阿尔法生成交易策略。鉴于大多数资产价格的随机性质,我有保留地准确地说,根据定义,资产价格本质上是随机的。因此,这个想法集中于执行某种分析,以某种程度的信心捕捉这个随机元素的运动。在用于预测这种运动的众多方法中,技术指标已经存在了相当一段时间(据说从 19 世纪开始使用),作为形成对潜在运动的看法的方法之一。

在算法交易普及之前,技术指标主要由交易者使用,他们会在交易屏幕上查看这些指标来做出买卖决定。尽管这仍然非常普遍,但鉴于机器学习和其他统计工具在短时间内分析这些数据的能力,以及计算机用几十年的数据进行回溯测试的计算能力,技术分析已经进入了自动化交易。

尽管本文并不支持或反对使用技术分析,但下面的技术指标可以用来进行各种回溯测试,并得出对其预测能力的看法。

技术指标

本文将重点介绍专业人士和学者广泛使用的技术指标,以及我认为对自动交易最有益的技术指标。指标列表包括:

1.简单移动平均线(快速和慢速)

2.平均真实范围

3.平均方向指数(快速和慢速)

4.随机振荡器(快速和慢速)

5.相对强度指数(快和慢)

6.移动平均收敛发散

7.布林线

8.变动率

数据

使用 pandas datareader for Yahoo finance 数据库,我提取了从 1990 年 1 月到今天的每日苹果和网飞股票数据。在本文中,大多数指标都是使用收盘而不是调整收盘创建的。这是留给读者选择价格。

由于技术指标在短期内效果最好,我将分别用 5 天和 15 天作为我的快速和慢速信号。然而,这可能会根据投资期限而改变。以下指示器可定制为任何持续时间,只需更改一个参数。

作者图片

简单移动平均线

简单移动平均线是最常见的技术指标之一。SMA 计算给定时间间隔内的平均价格,并用于确定股票的趋势。如上所述,我将创建一个慢速 SMA (SMA_15)和一个快速 SMA (SMA_5)。为了给机器学习算法提供已经设计的因子,还可以使用(SMA_15/SMA_5)或(SMA_15 - SMA_5)作为因子来捕捉这两个移动平均线之间的关系。

作者图片

简单移动平均线成交量

与价格的简单移动平均线相似,成交量的简单移动平均线提供了对股票显示的信号强度的洞察。

怀尔德的平滑

在讨论下一个指标之前,我想提一下其他指标常用的另一种平滑或移动平均线。虽然 SMA 相当常见,但它包含了过去对每个值给予同等权重的偏见。为了解决这个问题,Wells Wilder 引入了一个新版本的 smoothening,将更多的权重放在最近的事件上。我们将对以下大部分指标使用怀尔德平滑法,以下是通常可用于获得该平滑法的函数。

平均真实范围(ATR)

平均真实范围是一种常用的技术指标,用于衡量市场的波动性,以真实范围的移动平均值来衡量。公司的 ATR 越高,意味着股票的波动性越高。然而,ATR 主要用于确定何时退出或进入交易,而不是交易股票的方向。

如上所述,慢速 ATR 代表 5 天移动平均线,快速 ATR 代表 15 天移动平均线。

真实范围定义为以下最大值:

a.高低

b.abs(高-前收盘)

c.abs(低-先前收盘)

作者图片

平均方向性指数(ADX)

平均方向指数是由怀尔德开发的,用于评估股票价格趋势的强度。它的两个主要组成部分,+DI 和-DI 有助于确定趋势的方向。一般来说,ADX 为 25 或以上表明趋势强劲,ADX 小于 20 表明趋势疲软。ADX 的计算相当复杂,需要一定的步骤。

我也会计算 5 天和 15 天的 ADX。

作者图片

随机振荡器

随机振荡器是一种动量指标,旨在识别超买和超卖的证券,常用于技术分析。

作者图片

相对强弱指数

RSI 是最常见的动量指标之一,旨在量化价格变化和这种变化的速度。

作者图片

移动平均线收敛发散(MACD)

MACD 使用两条指数移动平均线,并根据它们的趋同或趋异进行趋势分析。尽管大多数常用的 MACD 慢速和快速信号分别基于 26 天和 12 天,我还是用了 15 天和 5 天来和其他指标保持一致。

作者图片

布林线

布林线捕捉股票的波动性,用于识别超买和超卖的股票。布林线由三个主要元素组成:简单的移动平均线,高于移动平均线 2 个标准差的上限和低于移动平均线 2 个标准差的下限。

作者图片

变化率

变化率是一个动量指标,它解释了相对于之前价格固定时期的价格动量。

作者图片

结论

这些技术指标在捕获的时间范围方面是高度可定制的,并且允许有助于创建更好模型的各种特征工程。这些值可以直接适合机器学习模型,也可以形成更大模型的因素子集。

还有许多其他指标可以考虑,即使不太重要。本文中列出的指标绝不是一个详尽的指标列表,而是我在模型中使用的指标列表。

在我的下一篇文章中,我将解释这些指标在机器学习模型中的实现,并更深入地创建和仔细回测该策略。

请在下面留下你的评论和建议。

为 Horovod 营造康达环境

原文:https://towardsdatascience.com/building-a-conda-environment-for-horovod-773bd036bf64?source=collection_archive---------35-----------------------

如何使用 Horovod 开始 DNNs 的分布式训练?

来源:https://eng.uber.com/nvidia-horovod-deep-learning/

什么是 Horovod?

Horovod 是针对 TensorFlowKerasPyTorchApache MXNet 的开源分布式培训框架。Horovod 最初由优步开发,供内部使用,几年前开源,现在是官方的 Linux 基金会人工智能项目。

在这篇文章中,我描述了我如何为我的深度学习项目构建 Conda 环境,当时我正在使用 Horovod 来实现跨多个 GPU 的分布式训练(在同一节点上或分布在多个节点上)。如果你喜欢我的方法,那么你可以利用 GitHub 上的模板库来开始你的下一个 Horovod 数据科学项目!

安装 NVIDIA CUDA 工具包

你需要做的第一件事是在你的工作站上安装 NVIDIA CUDA Toolkit 的合适版本。我使用的是NVIDIA CUDA Toolkit 10.1(文档),它可以与 Horovod 目前支持的所有三个深度学习框架一起工作。

为什么不用cudatoolkit包呢?

通常,当使用 Conda 安装 PyTorch、TensorFlow 或支持 GPU 的 Apache MXNet 时,您只需将适当版本的[cudatoolkit](https://anaconda.org/anaconda/cudatoolkit)包添加到您的environment.yml文件中。

不幸的是,至少在目前,[conda-forge](https://conda-forge.org/)提供的cudatoolkit包不包括 NVCC ,如果你需要编译扩展,它是将 Horovod 与 PyTorch、TensorFlow 或 MXNet 一起使用所必需的。

cudatoolkit-dev套餐怎么样?

虽然有来自conda-forge的包含 NVCC 的[cudatoolkit-dev](https://anaconda.org/conda-forge/cudatoolkit-dev)软件包,但我很难让这些软件包持续正确地安装。一些可用的构建需要手动干预来接受许可协议,这使得这些构建不适合安装在远程系统上(这是关键的功能)。其他版本似乎可以在 Ubuntu 上运行,但不能在其他版本的 Linux 上运行。

我鼓励你尝试将cudatoolkit-dev添加到你的environment.yml文件中,看看会发生什么!这个包维护得很好,所以也许将来它会变得更加稳定。

使用nvcc_linux-64元包!

获得 NVCC 并仍然使用 Conda 管理所有其他依赖项的最可靠方法是在您的系统上安装 NVIDIA CUDA Toolkit,然后安装来自conda-forge的元包[nvcc_linux-64](https://anaconda.org/nvidia/nvcc_linux-64),该元包配置您的 Conda 环境,以使用安装在系统上的 NVCC 以及安装在 Conda 环境中的其他 CUDA Toolkit 组件。关于这个包的更多细节,我建议通读 GitHub 上的问题主题。

environment.yml文件

我更喜欢在 Conda environment.yml文件中指定尽可能多的依赖项,并且只在requirements.txt中指定通过 Conda 通道不可用的依赖项。查看官方 Horovod 安装指南了解所需依赖项的详细信息。

通道优先级

我使用推荐的通道优先级。注意conda-forgedefaults有优先权。

name: nullchannels:
  - pytorch
  - conda-forge
  - defaults

属国

关于依赖关系,有一些事情值得注意。

  1. 尽管我已经手动安装了 NVIDIA CUDA 工具包,但我仍然使用 Conda 来管理其他所需的 CUDA 组件,如cudnnnccl(以及可选的cupti)。
  2. 我使用了两个元包cxx-compilernvcc_linux-64,以确保安装了合适的 C 和 C++编译器,并且最终的 Conda 环境能够识别手动安装的 CUDA 工具包。
  3. Horovod 需要一些控制器库来协调各种 Horovod 进程之间的工作。通常这将是一些 MPI 实现,如 OpenMPI 。然而,我没有直接指定openmpi包,而是选择了[mpi4py](https://mpi4py.readthedocs.io/en/stable/) Conda 包,它提供了一个支持 cuda 的 OpenMPI 构建(假设您的硬件支持它)。
  4. Horovod 还支持 Gloo 集体通信库,可以用来代替 MPI。我加入cmake是为了确保 Gloo 的 Horovod 扩展已经完成。

以下是核心必需依赖项。完整的environment.yml文件可以在 GitHub 上获得。

dependencies:
  - bokeh=1.4
  - cmake=3.16 # insures that Gloo library extensions will be built
  - cudnn=7.6
  - cupti=10.1
  - cxx-compiler=1.0 # insures C and C++ compilers are available
  - jupyterlab=1.2
  - mpi4py=3.0 # installs cuda-aware openmpi
  - nccl=2.5
  - nodejs=13
  - nvcc_linux-64=10.1 # configures environment to be "cuda-aware"
  - pip=20.0
  - pip:
    - mxnet-cu101mkl==1.6.* # MXNET is installed prior to horovod
    - -r file:requirements.txt
  - python=3.7
  - pytorch=1.4
  - tensorboard=2.1
  - tensorflow-gpu=2.1
  - torchvision=0.5

requirements.txt文件

requirements.txt文件中列出了所有的pip依赖项,包括 Horovod 本身,以便安装。除了 Horovod,我通常还会使用pip来安装 JupyterLab 扩展,以通过[jupyterlab-nvdashboard](https://github.com/rapidsai/jupyterlab-nvdashboard)实现 GPU 和 CPU 资源监控,并通过[jupyter-tensorboard](https://github.com/lspvic/jupyter_tensorboard)实现 Tensorboard 支持。

horovod==0.19.*
jupyterlab-nvdashboard==0.2.*
jupyter-tensorboard==0.2.*# make sure horovod is re-compiled if environment is re-built
--no-binary=horovod

注意文件末尾的--no-binary选项的使用。包含此选项可确保每当重建 Conda 环境时,Horovod 都会重建。

完整的requirements.txt文件可在 GitHub 上获得。

建筑康达环境

在添加了应该通过conda下载到environment.yml文件的任何必要的依赖项和应该通过pip下载到requirements.txt文件的任何依赖项之后,您可以通过运行以下命令在项目目录的子目录env中创建 Conda 环境。

export ENV_PREFIX=$PWD/env
export HOROVOD_CUDA_HOME=$CUDA_HOME
export HOROVOD_NCCL_HOME=$ENV_PREFIX
export HOROVOD_GPU_OPERATIONS=NCCL
conda env create --prefix $ENV_PREFIX --file environment.yml --force

默认情况下,Horovod 会尝试为所有检测到的框架构建扩展。有关在构建 Horovod 之前可以设置的其他环境变量的详细信息,请参见 Horovod 文档中关于环境变量的内容。

创建新环境后,您可以使用以下命令激活该环境。

conda activate $ENV_PREFIX

postBuild文件

如果您希望使用包含在environment.ymlrequirements.txt文件中的任何 JupyterLab 扩展,那么您可能需要重新构建 JupyterLab 应用程序。

为了简单起见,我通常在一个postBuild脚本中包含重新构建 JupyterLab 的指令。下面是这个脚本在我的 Horovod 环境中的样子。

jupyter labextension install --no-build @pyviz/jupyterlab_pyviz
jupyter labextension install --no-build jupyterlab-nvdashboard 
jupyter labextension install --no-build jupyterlab_tensorboard
jupyter serverextension enable jupyterlab_sql --py --sys-prefix
jupyter lab build

使用以下命令生成postBuild脚本。

conda activate $ENV_PREFIX # optional if environment already active
. postBuild

用 Bash 脚本将这一切包装起来

我通常将这些命令打包成一个 shell 脚本create-conda-env.sh。运行 shell 脚本将设置 Horovod 构建变量,创建 Conda 环境,激活 Conda 环境,并构建带有任何附加扩展的 JupyterLab。

#!/bin/bash --loginset -eexport ENV_PREFIX=$PWD/env
export HOROVOD_CUDA_HOME=$CUDA_HOME
export HOROVOD_NCCL_HOME=$ENV_PREFIX
export HOROVOD_GPU_OPERATIONS=NCCLconda env create --prefix $ENV_PREFIX --file environment.yml --force
conda activate $ENV_PREFIX
. postBuild

我通常将脚本放在我的项目根目录下的一个bin目录中。该脚本应该从项目根目录运行,如下所示。

./bin/create-conda-env.sh # assumes that $CUDA_HOME is set properly

验证 Conda 环境

构建 Conda 环境后,您可以使用以下命令检查 Horovod 是否已构建为支持深度学习框架 TensorFlow、PyTorch、Apache MXNet 以及控制器 MPI 和 Gloo。

conda activate $ENV_PREFIX # optional if environment already active
horovodrun --check-build

您应该会看到类似下面的输出。

Horovod v0.19.4:Available Frameworks:
    [X] TensorFlow
    [X] PyTorch
    [X] MXNetAvailable Controllers:
    [X] MPI
    [X] GlooAvailable Tensor Operations:
    [X] NCCL
    [ ] DDL
    [ ] CCL
    [X] MPI
    [X] Gloo

列出 Conda 环境的内容

要查看安装到环境中的软件包的完整列表,请运行以下命令。

conda activate $ENV_PREFIX # optional if environment already active
conda list

更新 Conda 环境

如果您在创建环境之后向environment.yml文件或requirements.txt文件添加(从其中移除)依赖项,那么您可以使用以下命令重新创建环境。

conda env create --prefix $ENV_PREFIX --file environment.yml --force

然而,每当我添加新的依赖项时,我更喜欢重新运行 Bash 脚本,这将重新构建 Conda 环境和 JupyterLab。

./bin/create-conda-env.sh

摘要

为我的深度学习项目找到一个可重复的构建 Horovod 扩展的过程是很棘手的。我的解决方案的关键是使用来自conda-forge的元包,以确保安装了适当的编译器,并且最终的 Conda 环境知道系统安装了 NVIDIA CUDA Toolkit。第二个关键是使用requirements.txt文件中的--no-binary标志来确保每当 Conda 环境被重新构建时 Horovod 也被重新构建。

如果你喜欢我的方法,那么你可以利用 GitHub 上的模板库来开始你的下一个 Horovod 数据科学项目!

构建基于内容的图书推荐引擎

原文:https://towardsdatascience.com/building-a-content-based-book-recommendation-engine-9fd4d57a4da?source=collection_archive---------14-----------------------

来源:图片由 PixabayTuendeBede 提供

根据书籍描述和名称推荐相似的书籍

如果我们计划购买任何新产品,我们通常会询问我们的朋友,研究产品的特点,将该产品与类似产品进行比较,阅读互联网上的产品评论,然后我们做出决定。如果所有这些过程都被自动处理并高效地推荐产品,会有多方便?推荐引擎或推荐系统是这个问题的答案。

基于内容的过滤和基于协作的过滤是两种流行的推荐系统。在这篇博客中,我们将看到如何使用 Goodreads.com 数据构建一个简单的基于内容的推荐系统。

基于内容的推荐系统

基于内容的推荐系统通过获取项目的相似性来向用户推荐项目。该推荐系统基于描述或特征来推荐产品或项目。它根据产品的描述来识别产品之间的相似性。它还会考虑用户以前的历史,以便推荐类似的产品。

例如:如果用户喜欢西德尼·谢尔顿的小说“告诉我你的梦”,那么推荐系统推荐用户阅读西德尼·谢尔顿的其他小说,或者推荐体裁为“非小说”的小说。(西德尼·谢尔顿小说属于非小说体裁)。

正如我上面提到的,我们使用 goodreads.com 的数据,没有用户阅读历史。因此,我们使用了一个简单的基于内容的推荐系统。我们要用一个书名和图书描述来搭建两个推荐系统。

我们需要找到与给定书籍相似的书籍,然后向用户推荐这些相似的书籍。如何发现给定的书是相似还是不相似?使用相似性度量来找到相同的结果。

来源: dataaspirant

有不同的相似性度量可用。余弦相似度被用于我们的推荐系统来推荐书籍。有关相似性度量的更多详细信息,请参考此文章

数据

我从 goodreads.com 那里搜集了有关商业、非小说和烹饪类型的书籍细节。

# Importing necessary libraries
import pandas as pd
import numpy as np
import pandas as pd
import numpy as np
from nltk.corpus import stopwords
from sklearn.metrics.pairwise import linear_kernel
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.tokenize import RegexpTokenizer
import re
import string
import random
from PIL import Image
import requests
from io import BytesIO
import matplotlib.pyplot as plt
%matplotlib inline# Reading the file
df = pd.read_csv("goodread.csv")#Reading the first five records
df.head()#Checking the shape of the file
df.shape()

我们的数据集中总共有 3592 本书的详细信息。它有六列

书名->书名

评分->用户给出的图书评分

体裁->类别(书的类型)。对于这个问题,我只选择了三种类型,如商业、非小说和烹饪

作者->图书作者

Desc ->图书描述

URL ->图书封面图片链接

探索性数据分析

流派分布

# Genre distribution
df['genre'].value_counts().plot(x = 'genre', y ='count', kind = 'bar', figsize = (10,5)  )

随机打印书名和描述

# Printing the book title and description randomly
df['title'] [2464]
df['Desc'][2464]

# Printing the book title and description randomly
df['title'] [367]
df['Desc'][367]

图书描述—字数分布

# Calculating the word count for book description
df['word_count'] = df2['Desc'].apply(lambda x: len(str(x).split()))# Plotting the word count
df['word_count'].plot(
    kind='hist',
    bins = 50,
    figsize = (12,8),title='Word Count Distribution for book descriptions')

我们没有更长的书籍描述。很明显,好的读物只是提供了一个简短的描述。

图书说明中词类标签的分布

from textblob import TextBlob
blob = TextBlob(str(df['Desc']))
pos_df = pd.DataFrame(blob.tags, columns = ['word' , 'pos'])
pos_df = pos_df.pos.value_counts()[:20]
pos_df.plot(kind = 'bar', figsize=(10, 8), title = "Top 20 Part-of-speech tagging for comments")

图书描述的二元模型分布

#Converting text descriptions into vectors using TF-IDF using Bigram
tf = TfidfVectorizer(ngram_range=(2, 2), stop_words='english', lowercase = False)
tfidf_matrix = tf.fit_transform(df['Desc'])
total_words = tfidf_matrix.sum(axis=0) 
#Finding the word frequency
freq = [(word, total_words[0, idx]) for word, idx in tf.vocabulary_.items()]
freq =sorted(freq, key = lambda x: x[1], reverse=True)
#converting into dataframe 
bigram = pd.DataFrame(freq)
bigram.rename(columns = {0:'bigram', 1: 'count'}, inplace = True) 
#Taking first 20 records
bigram = bigram.head(20)#Plotting the bigram distribution
bigram.plot(x ='bigram', y='count', kind = 'bar', title = "Bigram disribution for the top 20 words in the book description", figsize = (15,7), )

图书描述的三元模型分布

#Converting text descriptions into vectors using TF-IDF using Trigram
tf = TfidfVectorizer(ngram_range=(3, 3), stop_words='english', lowercase = False)
tfidf_matrix = tf.fit_transform(df['Desc'])
total_words = tfidf_matrix.sum(axis=0) 
#Finding the word frequency
freq = [(word, total_words[0, idx]) for word, idx in tf.vocabulary_.items()]
freq =sorted(freq, key = lambda x: x[1], reverse=True)#converting into dataframe 
trigram = pd.DataFrame(freq)
trigram.rename(columns = {0:'trigram', 1: 'count'}, inplace = True) 
#Taking first 20 records
trigram = trigram.head(20)#Plotting the trigramn distribution
trigram.plot(x ='trigram', y='count', kind = 'bar', title = "Bigram disribution for the top 20 words in the book description", figsize = (15,7), )

文本预处理

清理图书描述。

# Function for removing NonAscii characters
def _removeNonAscii(s):
    return "".join(i for i in s if  ord(i)<128)# Function for converting into lower case
def make_lower_case(text):
    return text.lower()# Function for removing stop words
def remove_stop_words(text):
    text = text.split()
    stops = set(stopwords.words("english"))
    text = [w for w in text if not w in stops]
    text = " ".join(text)
    return text# Function for removing punctuation
def remove_punctuation(text):
    tokenizer = RegexpTokenizer(r'\w+')
    text = tokenizer.tokenize(text)
    text = " ".join(text)
    return text
#Function for removing the html tags
def remove_html(text):
    html_pattern = re.compile('<.*?>')
    return html_pattern.sub(r'', text)# Applying all the functions in description and storing as a cleaned_desc
df['cleaned_desc'] = df['Desc'].apply(_removeNonAscii)
df['cleaned_desc'] = df.cleaned_desc.apply(func = make_lower_case)
df['cleaned_desc'] = df.cleaned_desc.apply(func = remove_stop_words)
df['cleaned_desc'] = df.cleaned_desc.apply(func=remove_punctuation)
df['cleaned_desc'] = df.cleaned_desc.apply(func=remove_html)

推荐引擎

我们将使用书名和描述来构建两个推荐引擎。

  1. 使用 TF-IDF 和 bigram 将每本书的标题和描述转换成向量。关于 TF-IDF 的更多详情
  2. 我们正在构建两个推荐引擎,一个带有书名,另一个带有图书描述。该模型基于标题和描述推荐类似的书。
  3. 使用余弦相似度计算所有书籍之间的相似度。
  4. 定义一个函数,将书名和流派作为输入,并根据书名和描述返回前五本相似的推荐书籍。

基于书名的推荐

# Function for recommending books based on Book title. It takes book title and genre as an input.def recommend(title, genre):

    # Matching the genre with the dataset and reset the index
    data = df2.loc[df2['genre'] == genre]  
    data.reset_index(level = 0, inplace = True) 

    # Convert the index into series
    indices = pd.Series(data.index, index = data['title'])

   ** #Converting the book title into vectors and used bigram**
    tf = TfidfVectorizer(analyzer='word', ngram_range=(2, 2), min_df = 1, stop_words='english')
    tfidf_matrix = tf.fit_transform(data['title'])

    # Calculating the similarity measures based on Cosine Similarity
    sg = cosine_similarity(tfidf_matrix, tfidf_matrix)

    # Get the index corresponding to original_title

    idx = indices[title]# Get the pairwsie similarity scores 
    sig = list(enumerate(sg[idx]))# Sort the books
    sig = sorted(sig, key=lambda x: x[1], reverse=True)# Scores of the 5 most similar books 
    sig = sig[1:6]# Book indicies
    movie_indices = [i[0] for i in sig]

    # Top 5 book recommendation
    rec = data[['title', 'url']].iloc[movie_indices]

    # It reads the top 5 recommend book url and print the images

    for i in rec['url']:
        response = requests.get(i)
        img = Image.open(BytesIO(response.content))
        plt.figure()
        print(plt.imshow(img))

让我们推荐《史蒂夫·乔布斯》这本书和体裁《商业》

recommend("Steve Jobs", "Business")

输出

我们已经给了史蒂夫·乔布斯的书作为输入,并且该模型基于书名中存在的相似性来推荐其他史蒂夫·乔布斯的书。

基于图书描述的推荐

我们通过将书籍描述转换成向量来使用上述相同的函数。

# Function for recommending books based on Book title. It takes book title and genre as an input.def recommend(title, genre):

    global rec
    # Matching the genre with the dataset and reset the index
    data = df2.loc[df2['genre'] == genre]  
    data.reset_index(level = 0, inplace = True) 

    # Convert the index into series
    indices = pd.Series(data.index, index = data['title'])

    **#Converting the book description into vectors and used bigram**
    tf = TfidfVectorizer(analyzer='word', ngram_range=(2, 2), min_df = 1, stop_words='english')
    tfidf_matrix = tf.fit_transform(data['cleaned_desc'])

    # Calculating the similarity measures based on Cosine Similarity
    sg = cosine_similarity(tfidf_matrix, tfidf_matrix)

    # Get the index corresponding to original_title

    idx = indices[title]# Get the pairwsie similarity scores 
    sig = list(enumerate(sg[idx]))# Sort the books
    sig = sorted(sig, key=lambda x: x[1], reverse=True)# Scores of the 5 most similar books 
    sig = sig[1:6]# Book indicies
    movie_indices = [i[0] for i in sig]

    # Top 5 book recommendation
    rec = data[['title', 'url']].iloc[movie_indices]

    # It reads the top 5 recommend book url and print the images

    for i in rec['url']:
        response = requests.get(i)
        img = Image.open(BytesIO(response.content))
        plt.figure()
        print(plt.imshow(img))

来推荐一下《哈利波特与阿兹卡班的囚徒》这本书和体裁《非小说》

recommend("Harry Potter and the Prisoner of Azkaban", "Non-Fiction")

输出

我们提供了“哈利·波特与阿兹卡班的囚徒”和“非小说”作为输入。该模型推荐了与我们的输入相似的其他五本哈利波特书籍。

再推荐一个吧

recommend("Norwegian Wood", "Non-Fiction")

以上模型根据描述推荐五本类似《挪威的森林》的书。

这只是一个简单的基层推荐系统。真实世界的推荐系统更加强大和先进。我们可以通过添加其他元数据(如作者和流派)来进一步改进上述内容。

此外,我们可以使用 word2Vec 实现基于文本的语义推荐。我用过 Word2Vec,建过推荐引擎。请在这里查看。

你可以在我的 GitHub repo 里找到数据。

感谢阅读。如果你有什么要补充的,欢迎随时留言评论!

故事时代:建立一个面向父母的基于内容的儿童书籍推荐系统

原文:https://towardsdatascience.com/building-a-content-based-childrens-book-recommender-for-parents-680e20013e90?source=collection_archive---------32-----------------------

针对睡前故事崩溃的 NLP 解决方案

自然语言处理和无监督学习项目。你可以在我的 GitHub 上看看这个项目的文件。

妈妈和孩子在床上一起阅读,图片来自 shutterstock.com菲茨克斯

动机

我一天中最喜欢的部分是在睡觉前给我的儿子 Storm 读图画书。我也很清楚这对他在智力上的巨大益处,无数像这样的研究证实了这一点。然而,由于这项活动消耗了我大量的空闲时间——阅读了 100 万遍同样的书——除了我孩子的书之外,我还想找到优先考虑我的兴趣的书。

目标

为儿童绘本建立一个推荐系统,既考虑家长的兴趣,也考虑孩子的兴趣。

方法学

数据:Goodreads 数据集(一个电子书平台)

  1. 查看数据—插图与故事— 2 个特征
  2. 图书数据-图书描述+元数据-21 个要素

型号:

  1. 查看数据—计数矢量器和标准化
  2. 图书数据— 带非负矩阵分解的 TFIDF 矢量器

推荐引擎:余弦相似度

度量:测试用例

我的个人经历框定了我在 NLP 过程中的目标特性:

阿努帕玛·加拉的概念主题映射

使用自然语言处理,我将 NMF 分别应用在书籍描述的形容词和名词上。这些名词提供了很多具体的话题,比如“农场动物”和“黑白”,这些信息会让我儿子更感兴趣。形容词提供了更抽象的术语,如“有趣”或限定术语,如“独特的”,我会更感兴趣。使用 NMF 和一些更简单的统计方法,我能够梳理出几个可以为推荐系统提供信息的主题:

用于选择感兴趣主题的用户界面模型

利用这些特性,我创建了 3 个测试案例,看看我的推荐引擎是否有效。我的测试案例是:我儿子的偏好(孩子的)、我的偏好(妈妈的)和我丈夫的偏好(爸爸的)。我们每个人都有自己的个人兴趣,在我看来,引擎工作得非常好:

测试案例 1:孩子

斯托姆的主要兴趣是动物,他喜欢故事情节,是一个真正的爱开玩笑的人,所以我的系统推荐的这三本书,根据它们的封面,似乎很好地涵盖了这些主题——动物、幽默、冒险。

Storm 的主题选择和推荐引擎输出,图片由 Anupama Garla 提供,封面来自[goodreads.com](https://www.goodreads.com/)

测试用例 2:妈妈

在我的脑海中,我倾向于生活在一个更抽象的空间,所以我的主题是关于更大的主题,比如家庭和杰出的艺术品。我也更喜欢长一点的书,这样我就可以确定停止点,而不是我的儿子坚持要我们读完较短的书。乍看之下,这些推荐有着奇特的插图和古怪的标题。然而,它们都不是长书。这与我将我的数据集限制在 500 本最受欢迎的书籍中进行概念验证的事实有关,不幸的是,更长的书没有通过筛选。

妈妈的选题和推荐输出,图片由 Anupama Garla 拍摄,封面来自 goodreads.com

测试案例 3:爸爸

我丈夫很担心我儿子的社交技巧以及驾驭学校和生活的能力。他还对短小、独特、充满冒险精神的书籍感兴趣。这些建议当然集中在教育主题上,排名第一的比赛《林肯先生的方式》是一本关于如何应对校园欺凌的书,实际上是许多公共核心课程的一部分。艺术品还可以,但不是第一个建议的重点。第二个标题是关于一个男孩从养老院绑架了他的爷爷,带他去冒险。最后一个是关于一个只想被餐具家族接受的斯博克人,尽管他有点与众不同。

爸爸的选题和推荐输出,图片由 Anupama Garla 拍摄,封面来自 goodreads.com

总之,推荐者抓住了这样一个事实:爸爸想让故事时间有教育意义,而妈妈想看很酷的图画,斯托姆想知道更多关于奶牛的事情。

结论

这个推荐系统非常有效。我希望看到它被折叠成一个 flask 应用程序,并在整个 Goodreads 插图书籍数据集上进行训练。这将是我训练营后的任务,因为我相信这个引擎对各地的妈妈和爸爸都有用。

基于内容的推荐系统的一个挑战是,如果你选择相同的主题,你可能会得到相同的响应,所以最终,将这与从用户交互中学习的协作推荐系统结合起来可能是有意义的。或者,拥有大量的主题,每个查询最多选择三个主题,可以产生足够多样的搜索结果。

引文

这个项目使用了 UCSD 为这些论文制作的 Goodreads 数据集。非常感谢这些作者:

孟婷·万,朱利安·麦考利,“关于单调行为链的项目建议”,RecSys’18。[ bibtex ]

孟婷·万,里沙布·米斯拉,恩达帕·纳卡肖勒,朱利安·麦考利,“大规模评论语料库中的[细粒度剧透检测”,载于 ACL'19 bibtex ]

用 AWS Lambda 函数和亚马逊 EFS 构建对话式 AI 聊天机器人

原文:https://towardsdatascience.com/building-a-conversational-ai-chatbot-with-aws-lambda-function-and-amazon-efs-615fddb4d55?source=collection_archive---------30-----------------------

亚马逊 EFS 在 AWS Lambda 上的无服务器机器学习

@exxtebanunsplash 上的照片

亚马逊宣布对亚马逊弹性文件系统的 AWS Lambda 支持全面可用。亚马逊 EFS 是一个完全托管的、弹性的、共享的文件系统,旨在供其他 AWS 服务使用。

随着 Amazon EFS for Lambda 的发布,我们现在可以轻松地跨函数调用共享数据。它还开放了新的功能,例如将大型库和机器学习模型直接构建/导入到 Lambda 函数中。让我们来看看如何使用 Lambda 函数和 EFS 构建一个无服务器的对话式人工智能聊天机器人。

在本帖中,我们将:

  • 创建一个 Amazon 弹性文件系统
  • 部署并运行一个 SageMaker 笔记本实例,并将 EFS 装载到该实例。
  • 将 PyTorch 库和 ConvAI 预训练模型下载到 EFS。
  • 添加对话历史 DynamoDB 表和网关端点以保存和检索对话历史。
  • 部署聊天机器人引擎 Lambda 功能,并为其启用 EFS。

这是架构图:

创建 EFS 文件系统

在这个例子中我们将使用 CloudFormation 来创建 EFS 和 EFS 接入点,配置定义如下:

请注意,我们将使用 EFS 通用性能模式,因为它的延迟低于最大 I/O

与亚马逊 SageMaker 合作

我们将在亚马逊 SageMaker 笔记本上安装 EFS,在 EFS 上安装 PyTorch 和 ConvAI 模型。

笔记本实例必须能够访问同一个安全组,并且与 EFS 文件系统位于同一个 VPC 中。

让我们来看看 EFS 山路径/py-libs/home/ec2-user/SageMaker/libs 目录:

然后将 PyTorch 和 simpletransformers 安装到lib/py-libs目录:

!sudo pip --no-cache-dir install torch -t libs/py-libs
!sudo pip --no-cache-dir install torchvision -t libs/py-libs
!sudo pip --no-cache-dir install simpletransformers -t libs/py-libs

一旦我们安装好所有的包,下载拥抱脸提供的预训练模型,然后解压文件到 EFS 的convai-model目录。

!sudo wget [https://s3.amazonaws.com/models.huggingface.co/transfer-learning-chatbot/gpt_personachat_cache.tar.gz](https://s3.amazonaws.com/models.huggingface.co/transfer-learning-chatbot/gpt_personachat_cache.tar.gz)
!sudo tar -xvf gpt_personachat_cache.tar.gz -C libs/convai-model
!sudo chmod -R g+rw libs/convai-model

我们现在准备与预训练的模型对话,只需调用model.interact()

拥抱脸提供的预训练模型开箱即用性能良好,在创建聊天机器人时可能需要较少的微调。

我们可以看到 python 包和模型正确地从 EFS 消费,我们能够与预先训练好模型开始对话。

创建 AWS DynamoDB 表

创建一个 DialogHistory 表来存储至少带有用户最后一次发言的对话历史。我们可以使用样例 CloudFormation 模板 来配置 DynamoDB 表。

请注意,我们必须为 DynamoDB 创建一个VPC 端点,即使 Lambda 函数在 VPC 的公共子网内运行。

配置 AWS Lambda 以使用 EFS

我们将使用 AWS SAM 来创建 Lambda 函数并挂载 Lambda 函数的 EFS 访问点。

首先,创建一个 Lambda 函数资源,然后为 Lambda 设置 EFS 文件系统。确保 EFS 和 Lambda 在同一个 VPC 中:

添加对话引擎:AWS Lambda

在本节中,我们将创建一个 Lambda 函数,用于用户和对话 AI 模型之间的通信。

我们将在src/api.py中包含以下源代码:

注意 simpletransformers 库允许我们使用input()在本地与模型交互。为了构建我们的聊天引擎,我们需要覆盖默认方法interactconv_ai中的sample_sequenc:

部署聊天机器人服务

我们快到了!现在我们必须部署我们的机器人。运行以下命令进行部署:

**$**sam deploy --capabilities CAPABILITY_NAMED_IAM --guided

从上面的输出中,我们可以看到聊天机器人现在已经部署好了。

现在是时候测试我们的机器人了。转到 AWS 管理控制台中的 CloudFormation 资源列表,找到 lambda 函数名称,并使用以下命令调用 Lambda 函数:

**$**aws lambda invoke --function-name "[chat-efs-api-HelloFunction-KQSNKF5K0IY8](https://ap-southeast-2.console.aws.amazon.com/lambda/home?region=ap-southeast-2#/functions/chat-efs-api-HelloFunction-KQSNKF5K0IY8)" out --log-type Tail  \--query 'LogResult' --output text |  base64 -d

输出如下所示:

下面是一个对话框示例:

>>hi there
how are you?
>>good, thank you
what do you like to do for fun?
>>I like reading, yourself?
i like to listen to classical music
......

有用!从上面的截图我们可以看到,聊天机器人根据用户的输入返回响应。

但是,我知道冷启动对响应时间的影响。第一个请求花费了大约 30 秒的时间让冷启动完成。为了防止 Lambda 函数冷启动,我们可以使用 提供并发 来保持函数预热:

因此,预热功能的等待时间缩短至约 3 秒:

就是这样!希望你觉得这篇文章有用,这篇文章的源代码可以在我的 GitHub repo 中找到。

仅用 40 行代码构建一个卷积神经网络

原文:https://towardsdatascience.com/building-a-convolutional-neural-network-in-only-40-lines-of-code-bef8ce38bf6d?source=collection_archive---------39-----------------------

最简单的 CNN 可能使用 Keras 和 Tensorflow

来源

对于任何进入深度学习的人来说,卷积神经网络都可能令人困惑和恐惧。在本文中,我将展示构建一个简单的 CNN 实际上是相当容易的。

首先,我们需要导入模块。

import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
from keras.preprocessing.image import ImageDataGenerator

Keras 是一个运行在 Tensorflow 之上的高级 Python 神经网络库。其简单的架构、可读性和整体易用性使其成为使用 Python 进行深度学习时最受欢迎的库之一。

在这篇文章中,我使用了“10 种猴子”的数据集,可以在 Kaggle 上找到:https://www.kaggle.com/slothkong/10-monkey-species。它包含 1098 个训练图像和 272 个验证图像,分在 10 类猴子中。

在我们开始之前,请确保图像存储正确。下面看到的结构是 flow_from_directory 函数(我们很快就会讲到)工作所必需的。

Directory
   - Training_images
      - Class_1
         - image_1
         - image_2
      - Class_2
         - image_1 - Validation_images
      - Class_1
         - image_1
...

现在我们开始。首先,我们必须指定图像的路径,以及它们的目标大小。

*#****Path*** 
train_dir = Path('../input/10-monkey-species/training/training/')
test_dir = Path('../input/10-monkey-species/validation/validation/')

***#Images target size*** target_size = (100,100)
channels = 3 *#RGB*

然后,我们创建我们的生成器,这将使我们能够对图像进行数据扩充和缩放。请注意,只增加训练图像,但重新缩放一切。重新缩放是必要的,因为让每个图像都在相同的[0,1]范围内将意味着它们在训练期间的贡献更均匀。

作为澄清,请注意 ImageDataGenerator 函数不会创建新图像。相反,它修改了我们当前的一些训练图像,以便在更大范围的样本上训练该模型。这有助于避免过度拟合,并使模型更易于预测新猴子的类别。

***#Data augmentation*** train_generator = ImageDataGenerator(rescale=1/255,
                                    rotation_range=40,
                                    shear_range=0.2,
                                    zoom_range=0.2,
                                    horizontal_flip=True,
                                    fill_mode='nearest')

valid_generator = ImageDataGenerator(rescale = 1/255)

然后我们可以导入图像。flow_from_directory 函数在指定的路径中查找图像,并将它们调整到目标大小。

epochs = 20
batch_size = 64 

***#Finds images, transforms them***train_data = train_generator.flow_from_directory(train_dir,                                                                                target_size=target_size, batch_size=batch_size,                                           class_mode='categorical')

test_data = valid_generator.flow_from_directory(test_dir,       target_size=target_size, batch_size=batch_size,                                                 class_mode='categorical', shuffle=False)

时期和批量是两个非常重要的超参数。当整个数据集通过网络时,一个历元完成。批量大小是模型更新前处理的图像数量。调整这些参数会极大地改变训练的速度和长度。

然后我们可以建立模型本身。在这里,我创建了一个非常简单的模型,除了输入/输出层之外,只有一个卷积层和一个池层。显然,一个更复杂的模型将有助于提高性能,添加层是非常简单的,但对于本教程,我将把它留在那里。

**#Number of images we have** train_samples = train_data.samples
valid_samples = test_data.samples**#Building the model** model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape (100, 100, channels)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Dense(10, activation='softmax'))

***#Compile model*** model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

第一卷积层需要输入形状,即图像的形状。这个 CNN 的最后一层使用 softmax 激活函数,这在我们有多个类(这里有 10 个)时是合适的,因为它允许模型计算图像属于每个类的概率。最后, model.compile 函数允许我们指定模型在训练期间将如何学习。

然后,我们可以拟合模型并评估验证集的性能。

***#Fit the model*** model.fit_generator(generator=train_data,
                    steps_per_epoch=train_samples/batch_size,
                    validation_data=test_data,
                    validation_steps=valid_samples/batch_size,
                    epochs=epochs)

这个超级简单的模型仅经过 20 个时期就在验证集上达到了几乎 63%的准确率!

Epoch 20/20
17/17 [===============================] - 81s 5s/step - loss: 0.6802 - accuracy: 0.7395 - val_loss: 1.4856 - val_accuracy: 0.6287

在实践中,有更多的纪元是有意义的,只要模型改进,就让它训练。

这就是一个卷积神经网络,从头到尾只有 40 行代码。不再那么可怕了,是吗?非常感谢你的阅读!

建立一个卷积神经网络来识别刮胡子和未刮胡子的人脸

原文:https://towardsdatascience.com/building-a-convolutional-neural-network-to-recognize-shaved-vs-unshaved-faces-cb96ea5bc0f0?source=collection_archive---------40-----------------------

使用计算机视觉和 Keras 深度学习 API 构建 CNN 模型的代码指南。

乔希·里纳拍摄的图片

在本教程中,我们将使用由报废免费库存照片网站创建的图像数据集。该图像集包含大约 2000 张被标记为“刮胡子”或“未刮胡子”的个人图像。我们将结合计算机视觉和机器学习,使用卷积神经网络(CNN)对图像进行分类。

本教程结束时,您将能够:

  1. 从头开始构建 CNN 模型并使用迁移学习
  2. 可视化模型结构、隐藏层和评估指标
  3. 保存您的 CNN 模型,以便重复使用和/或部署

导入库和加载图像数据帧

要继续编码,请从 Google Drive 下载我的图像数据集。所有图像数据都存储在 Pandas dataframe 中,包括原始图像数组,以及大小调整为 700x700、300x300、150x150 和 50x50 的图像数组。

我们将使用 pickle 来“解钩”和加载熊猫数据帧。我们使用 Keras 从头开始构建 CNN,并利用 VGG16 预训练模型。我们将使用 Pyplot 来可视化图像数据,并可视化 CNN 隐藏层中的中间激活。

import pickle
import pandas as pd
import numpy as np   
from numpy import asarray
from matplotlib import image
from matplotlib import pyplot
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense, Conv2D, MaxPooling2D, Flatten, Dropout
from keras.callbacks import EarlyStopping# loading the data frame using pickle
data = pickle.load( open( "data_pickle_final.p", "rb" ) )# creating a list of image arrays to preview
size_list = data.iloc(0)[0][-5:]# iterating through list to view images
for i in size_list:
    pyplot.imshow(i)
    pyplot.show();

预览数据帧

在这里,我们可以看到保存在图像集中的图像数据。为了确保图像不是堆叠的,我们将在执行训练、测试、评估分割之前打乱图像的顺序。这可以使用内置的 pandas 方法来实现。样本()

# preview dataframe information
display(data.info())# preview first 5 rows in dataframe
display(data.head())# shuffle order of images and preview first 5 images
resampled_data = data.sample(frac=1)
resampled_data.head()

此时,我们将选择我们将要使用的图像形状。在你自己的项目中,你可能需要根据自己的需要来抓取照片,所以请查看我的文章使用 Google Selenium 和 Python 来抓取股票图片。好的,我们将选择尺寸为 300 x 300 的图像,然后继续前进。

创建张量和定义变量

最常见的像素格式是字节图像,其中该数字存储为 8 位整数,给出了从 0 到 255 的可能值范围。通常,0 表示黑色,255 表示白色。介于两者之间的值构成了不同的灰度。在我们的例子中,我们将使用共享红色、绿色和蓝色比例的彩色照片,即:“rbg”;其中 0 表示没有光线,255 表示最大光线。我们将通过将每个值除以该范围中的最大数来归一化这些值,并且因为我们将每个图像存储为数组,所以我们将特征变量重新格式化为神经网络的张量。

# Normalizing the image arrays
X = resampled_data.img_data_300
X = X/255# Creating an empty tensor to store image arrays
tensor = np.zeros((X.shape[0],300,300,3))# Iterating through image arrays to update tensor
for idx, i in enumerate(X):
    tensor[idx] = i# Checking the tensor shape
tensor.shape

这里我们将定义我们的目标变量。我们将首先把我们的标签转换成神经网络的二进制目标,也称为一键编码。

# creating list to store target codes
target = []# iterating through labels to change strings to numbersfor i in resampled_data['Labels']:
  if i == 'shaved':
    target.append(0)
  elif i == 'unshaved':
    target.append(1)

我们将把新的二进制目标添加到我们的数据帧中,并将目标变量定义为“y”。根据您下载数据帧的时间,这可能已经包含在标记为“目标”的数据帧中。如果没有,不用担心。就照着这个剧本。

# updating dataframe to include target
resampled_data['target'] = target# defining target variable
y = resampled_data.target# checking the shape
y.shape

现在我们已经改组了我们的图像数据集,定义了我们的目标和特征变量;现在是我们进行训练-测试-评估分离的时候了。我们将使用 Sklearn 的 train_test_split 模块来执行此操作。但是执行训练-测试-分割,我们将使用最后 100 个图像创建一个保留集,用于模型评估。

# importing train-test-split module from sklearn
from sklearn.model_selection import train_test_split # Performing train-test split for model training
X_train, X_test, y_train, y_test = train_test_split(tensor[:-100], 
                                                    y[:-100], 
                                                    test_size=0.20, 
                                                    random_state=42)# check the size of the train/test split
for i in [X_train, X_test, y_train, y_test]:
    print(len(i))# Defining hold out data for evaluation 
evals_tensors = tensor[-100:]
evals_targets = y[-100:]

从头开始构建 CNN 模型

卷积神经网络(CNN)是一种专门用于图像的深度学习算法,其中该算法识别图像内的模式,为图像中的不同模式/对象分配重要性,使用权重和偏差来识别输入图像之间的差异和相似性。这些 CNN 基于标记的图像进行训练。CNN 的工作是将图像缩减成一种更容易处理的结构,而不损失权重/偏差,这是获得最佳结果的必要条件。

在这里,我们将建立我们的卷积神经网络层。我们将从添加一个连续层开始;其次是我们的 2D 卷积层,最大池层,密集层,和辍学层。

代码如下:

model = Sequential()
model.add(Conv2D(32,(4,4),activation='relu',input_shape=(300,300,3)))
model.add(Conv2D(32,(4,4),activation='relu', padding='same'))
model.add(Conv2D(128,(4,4),activation='relu', padding='same'))
model.add(Conv2D(128,(4,4),activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2)))
model.add(Dropout(.3))
model.add(Conv2D(256, (4,4), activation='relu', padding='same'))
model.add(Conv2D(256, (4,4), activation='relu', padding='same'))
model.add(Conv2D(128, (4,4), activation='relu', padding='same'))
model.add(Conv2D(128, (4,4), activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2)))
model.add(Dropout(.3))
model.add(MaxPooling2D((2, 2)))
model.add(Dense(1024, activation='relu'))
model.add(Dense(512, activation='relu'))
model.add(Dropout(.3))
model.add(Flatten())
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.summary()

2D 卷积层使得 CNN 在图像预测方面如此强大。该层使用内核/过滤器(4x4)来检查每个通道的所有像素;从左到右、从上到下、从前到后开始;卷积所有像素(灰度、RGB 等)。该滤波器将使用特征内的像素数据执行点积乘法,以便从输入图像中提取特征,例如边缘。

第一个 Conv2D 层捕捉基本特征,如边缘、颜色、大小等。随着更多的图层添加到网络中,该算法会从输入图像中识别复杂的要素。我们使用 ReLu 或修正线性激活函数来训练我们的深度网络,因为 ReLU 往往比用其他激活函数训练收敛得更快更可靠。

最大池层减小了卷积特征的大小,降低了降维所需的计算能力,提取了主要特征,还抑制了噪声。

我们将对输出图层使用 sigmoid 激活函数,因为它存在于(0 到 1)之间,并且我们希望预测输出为剃齿或未剃齿的概率。

编译、拟合和评估模型

现在我们已经建立了 CNN 模型,我们需要编译、拟合和评估这个模型。我们将使用早期停止来帮助我们确定二元交叉熵损失函数的全局最小值。我们将存储每个时期的准确性和损失度量,以便可视化模型随时间的性能。

# timing the training
import time
start_time = time.time()# compiling the model
model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])# setting upearly stopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=5)# fitting the model to train/test data
history = model.fit(X_train, y_train,
                      batch_size=128, epochs=1000, 
                      validation_data=(X_test, y_test),
                      callbacks=[es], verbose=1)# printing training time
print("--- %s seconds ---" % (time.time() - start_time))# evaluating the model
train_loss, train_acc = model.evaluate(X_train, y_train)
test_loss, test_acc = model.evaluate(X_test, y_test)# checking model performance by accuracy metrics
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))

评估培训结果

在这里,我们将使用 PyPlot 来可视化我们的模型在训练和测试期间的性能。

# plotting the loss during training
plt.plot(history.history['loss'], label='train')
ply.plot(history.history['val_loss'], label='test')
plt.title('Training vs Test Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()# plotting the accuracy during training
plt.plot(history.history['accuracy'], label='train')
plt.plot(history.history['val_accuracy'], label='test')
plt.title('Training vs Test Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

现在我们已经有了相当精确的模型,我们将使用它来对我们坚持的评估集进行预测。

评估模型预测

模型没有看到这个数据,应该可以做出准确的预测。让我们看看评估目标 vs 预测,也看看评估图像集中的图像。

# making predictions using evaluation features
res = model.predict(evals_tensors)# iterating through prediction results, and evaluation features
for i, j, k in zip(res, evals_tensors, evals_targets):
    if i >= .5:
      _ = 'Unshaved'
      print('Prediction:', round(i[0],2), '-', _) # printing test
    else:
      _ = 'Shaved'
      print('Prediction:', round(i[0],2), '-',_) # printing test
    print('Actual:', k)
    pyplot.imshow(j)
    pyplot.show();

我们还可以利用 Sklearn 的指标来查看分类报告,并查看将预测与实际结果进行比较的混淆矩阵。我们将在下面创建测试集和评估集。

代码如下:

from sklearn.metrics import classification_report, confusion_matrix# making predictions
Y_pred = model.predict(X_test)
Y_pred_train = model.predict(evals_tensors)# creating lists to store predictions
y_preds = []
y_preds_train = []# iterating through results to update Test prediction lists
for i in [round(i[0],0) for i in Y_pred]:
    if i > 0.5:
        y_preds.append(1)
    else:
        y_preds.append(0)

# iterating through results to update Evaluation prediction lists
for i in [round(i[0],0) for i in Y_pred_train]:
    if i > 0.5:
        y_preds_train.append(1)
    else:
        y_preds_train.append(0)

下面是打印混淆矩阵和分类报告的代码。

# printing the confusion matrix
print('Confusion Matrix - Test Set')
print(confusion_matrix(y_test.values.tolist(), y_preds))
print('Confusion Matrix - Evaluation Set')
print(confusion_matrix(evals_targets.values.tolist(), y_preds_train))# printing the classification report
print('Classification Report - Test Set')
print(classification_report(y_test.values.tolist(), y_preds, target_names=['Shaved','Unshaved']))
print('Classification Report - Evaluation Set')
print(classification_report(evals_targets.values.tolist(), y_preds_train, target_names=['Shaved','Unshaved']))

绘制模型结构并可视化中间激活

有这么多隐藏层,很难理解模型在引擎盖下做什么。虽然不是模型执行所必需的,但这是可视化模型结构和查看中间激活的好方法。

此代码将把您的模型结构保存为 PDF 文件:

# Saving the model structure
import pydot
pydot.find_graphviz = lambda: True
from keras.utils import plot_model
plot_model(model, show_shapes=True, to_file='model_pdf/{}.pdf'.format('Model_Structure'))

这段代码将为中间激活层保存一个图像:

# Saving intermediate activations
from keras import models
import math# Creating list of layer outputs
layer_outputs = [layer.output for layer in model.layers[:9]]
activation_model = models.Model(inputs=model.input, outputs=layer_outputs)
activations = activation_model.predict(img_tensor)# Extract Layer Names for Labelling
layer_names = []
for layer in activation_model.layers[:9]:
    layer_names.append(layer.name)# Defining number of images per row
images_per_row = 16# iterating through layer names and activations
for layer_name, layer_activation in zip(layer_names, activations): 
    n_features = layer_activation.shape[-1] 
    size = layer_activation.shape[1] 
    n_cols = n_features // images_per_row 
    display_grid = np.zeros((size * n_cols, images_per_row * size))
    for col in range(n_cols): # Tiles each filter into a big horizontal grid
        for row in range(images_per_row):
            channel_image = layer_activation[0,
                                             :, :,
                                             col * images_per_row + row]
            channel_image -= channel_image.mean() # Post-processes the feature to make it visually palatable
            channel_image /= channel_image.std()
            channel_image *= 64
            channel_image += 128
            channel_image = np.clip(channel_image, 0, 255).astype('uint8')
            display_grid[col * size : (col + 1) * size, # Displays the grid
                         row * size : (row + 1) * size] = channel_image
    scale = 1\. / size
    plt.figure(figsize=(scale * display_grid.shape[1],
                        scale * display_grid.shape[0]))
    plt.title(layer_name)
    plt.grid(False)
    plt.imshow(display_grid, aspect='auto', cmap='viridis')
plt.savefig(f'intermediate_activation_visualizations/unshaved/{layer_name}')

使用迁移学习构建 CNN

这里,我们将利用来自 Kera 预训练模型之一的 imagenet 权重, VGG16

from keras.applications import vgg16
from keras.models import Model
import kerasinput_shape = (300, 300, 3)
vgg = vgg16.VGG16(include_top=False, weights='imagenet', 
                                     input_shape=input_shape)output = vgg.layers[-1].output
output = keras.layers.Flatten()(output)
vgg_model = Model(vgg.input, output)vgg_model.trainable = False
for layer in vgg_model.layers:
    layer.trainable = False

import pandas as pd
pd.set_option('max_colwidth', -1)
layers = [(layer, layer.name, layer.trainable) for layer in vgg_model.layers]
pd.DataFrame(layers, columns=['Layer Type', 'Layer Name', 'Layer Trainable'])vgg.summary()

接下来,我们将使用预训练的模型层重新构建我们的模型,并添加类似于上面所做的其他层。

from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, InputLayer
from keras.models import Sequential
from keras import optimizersmodel = Sequential()
model.add(vgg_model)
model.add(Dense(512, activation='relu', input_dim=input_shape))
model.add(Dropout(0.3))
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))model.summary()

现在,我们将编译、拟合和评估我们的新模型。

from keras.callbacks import EarlyStoppingmodel.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])# simple early stopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=10) ## patience=200history = model.fit(X_train, y_train,
                      batch_size=128, epochs=1000, 
                      validation_data=(X_test, y_test),
                      callbacks=[es], verbose=1)train_loss, train_acc = model.evaluate(X_train, y_train)
test_loss, test_acc = model.evaluate(X_test, y_test)print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))

现在,我们可以评估来自培训的指标。

import matplotlib.pyplot as pltplt.plot(history.history['loss'], label='train')
plt.plot(history.history['val_loss'], label='test')
plt.title('Loss')
plt.legend()
plt.show()plt.plot(history.history['accuracy'], label='train')
plt.plot(history.history['val_accuracy'], label='test')
plt.title('Accuracy')
plt.legend()
plt.show()

我们还可以评估混淆矩阵和分类报告的结果,看看我们的模型是否比我们从头构建的模型表现得更好。

from sklearn.metrics import classification_report, confusion_matrix#Confution Matrix and Classification Report
Y_pred = model.predict(X_test)
Y_pred_train = model.predict(evals_tensors)y_preds = []
y_preds_train = []
for i in [round(i[0],0) for i in Y_pred]:
    if i > 0.5:
        y_preds.append(1)
    else:
        y_preds.append(0)

for i in [round(i[0],0) for i in Y_pred_train]:
    if i > 0.5:
        y_preds_train.append(1)
    else:
        y_preds_train.append(0)print('Confusion Matrix - Test Set')
print(confusion_matrix(y_test.values.tolist(), y_preds))
print('Confusion Matrix - Evaluation Set')
print(confusion_matrix(evals_targets.values.tolist(), y_preds_train))print('Classification Report - Test Set')
print(classification_report(y_test.values.tolist(), y_preds, target_names=['Shaved','Unshaved']))
print('Classification Report - Evaluation Set')
print(classification_report(evals_targets.values.tolist(), y_preds_train, target_names=['Shaved','Unshaved']))

我们现在可以看到,这个模型表现得更加准确。

保存最终模型

现在我们有了一个在看不见的图像上表现良好的实体模型,我们可以保存这个模型和权重。这将允许我们部署这个模型,或者甚至与对类似项目感兴趣的其他人共享这个文件。

# Saving whole model
model.save('/content/drive/My Drive/Model_Files/Final_Model.h5')# Loading the whole model
from keras.models import load_model
loaded_model = load_model('/content/drive/My Drive/Final_Model.h5')
loaded_model.compile(loss='binary_crossentropy', 
                     optimizer='adam', metrics=['accuracy'])# Testing predictions using loaded model
res2 = loaded_model.predict(evals_tensors)
results2= []
for i in res2:
    results2.append(round(i[0],2))
compare = zip(results2, evals_targets)# View the comparison
for i in compare:
  print(i)

由于我们从 pickle 文件开始,如果不将我们的模型保存为 pickle 文件,本教程将是不完整的。要将您的模型保存为 pickle 文件,只需运行以下代码:

filename = 'finalized_model.p'
pickle.dump(loaded_model, open(filename, 'wb'))

# some time later...

# load the model from disk
loaded_model = pickle.load(open(filename, 'rb'))
result = loaded_model.score(X_test, Y_test)

结论

现在我们来复习一下。首先,我们导入我们的库和映像集。然后,我们对数据进行重新采样,定义和缩放我们的特征,并将图像存储在张量中。我们一次性编码了我们的目标变量;然后将我们的数据分成训练/测试/评估子集。我们从零开始建立了一个 CNN 模型,还使用预训练的 VGG16 和迁移学习建立了一个模型;将每个模型拟合到我们的图像集,并使用 adam 优化器编译每个模型,使用 binary_crossentropy 损失函数来提高我们在向前和向后传播期间的准确性度量。

培训完成后,我们能够评估指标,并可视化培训结果、模型结构和中间激活。最后,我们能够将整个模型保存为一个. h5 文件,也可以保存为一个 pickle 文件。我们流程的下一步是部署我们的模型供公众使用。我将使用 flask 构建一个 python 应用程序,并将其托管在 PythonAnywhere 上,请继续关注本系列的下一篇文章。

这里是最终产品:【http://jtadesse.pythonanywhere.com/】T4

你可以在这里找到我的 GitHub 库。谢谢大家!

构建冠状病毒爆发短信预警系统!

原文:https://towardsdatascience.com/building-a-coronavirus-outbreak-sms-alert-system-d80f4d648eea?source=collection_archive---------22-----------------------

照片由 @thedotter 拍摄

使用 Python 来控制疫情

由于最近冠状病毒在中国以及亚洲其他国家爆发,世界其他地区的人们越来越担心病毒会继续传播并最终到达他们的国家。截至撰写本文时,mainland China 约有 98%(超过 70,000)的确诊病例,当局正在尽一切努力控制疫情。但是,这并不意味着我们不应该做好准备。

考虑到这一点,我决定写一个 Python 脚本来帮助人们在他们的国家达到一定数量的确诊病例时设置警报触发器。例如,美国目前约有 15 例确诊病例,但例如,如果该数字达到 30 例(或任何其他数字),则会触发警报,您会收到一条发送到手机的短信。

下面,我将描述如何建立这个由网页抓取器和文本消息 API 组成的系统。

收集冠状病毒数据

首先,我们需要一个数据源来检查是否应该触发警报。幸运的是,有很多网站提供实时更新。我选择从网上抓取这个由约翰霍普金斯系统科学与工程中心提供的实时仪表板,因为它看起来是最可靠的。

冠状病毒全球数据仪表板

从浏览网站开始

为了找出我需要针对的元素,我从检查网站的源代码开始。这可以通过右击感兴趣的元素并选择 inspect 来轻松完成。这将显示 HTML 代码,从中我们可以看到包含每个字段的元素。例如,获取与确诊病例相关的所有数据将有助于为每个国家设置触发器

通过检查代码,我们可以很快意识到这个网站使用动态内容,而不是将其作为 HTML 源代码的一部分。因此最好的网络抓取工具是Selenium

开始刮!

Selenium提供了多种在网站中查找和提取元素的方法,其中之一就是使用函数find_elements_by_xpath()。此功能要求您通过网站中包含您感兴趣的信息的部分的XPath,它将继续查找其所有元素。例如,我们可以按国家/地区复制名为确诊病例部分的XPath,以提取每个国家的确诊病例数

下面是提取数据所需的带有XPathclass名称的代码:

请记住,这只是我们可以提取的一组数据,我们可以应用相同的过程来提取网站中的任何其他部分,如总恢复数总死亡数。

触发短信提醒!

为此,我们将使用设置非常简单的 Twilio API 。虽然 Twilio 不是免费服务,但它为新用户提供 15 美元的免费信用,一条文本大约 1 美分,应该足够我们的脚本运行一段时间了!首先去他们的网站创建一个账户。

如果你去控制台,你会看到你的Account SID和你的Auth Token,留着以后用。也点击红色的大按钮“获取我的试用号”,按照步骤,并保存这个稍后。

Twilio 控制台

现在,您需要做的就是使用pip install Twilio在您的计算机上安装软件包,并使用以下代码发送文本消息:

把所有东西放在一起

既然我们已经知道了如何使用Selenium 收集数据,使用Twilio发送短信提醒,我们可以将所有代码放在一起构建一个提醒系统:

请记住,最佳实践是将 Twilio Account SID等敏感信息保存为环境变量,而不是将其存储为代码的一部分,这就是上面的代码引用TWILIO_SID等变量的原因。此外,为了避免运行脚本时出现问题,需要进行大量的错误处理,但是上面的代码应该足够好,可以开始使用了。

运行脚本

从这里开始,有多种方法可以在一天中多次运行该脚本,以检查是否触发了任何警报。一种选择是将它本地托管在您的计算机或 Raspberry Pi 之类的设备上,并使用像cron (Mac 或 Linux)或Task Scheduler (Windows)这样的服务来安排脚本在一天内运行多次。在本文中,我将解释如何做到这一点:

[## 使用 Python 和 Raspberry Pi 的网络抓取山区天气预报

从没有 API 的网站提取数据

towardsdatascience.com](/web-scraping-mountain-weather-forecasts-using-python-and-a-raspberry-pi-f215fdf82c6b)

另一种选择是通过使用 Heroku 之类的服务将其托管在云上,但这超出了本教程的范围。

这个项目的所有代码都可以在这个 Github 资源库中找到,您可以下载并立即开始运行!

未来的改进

这个项目原来很简单,但这主要是因为它没有太多的功能。以下是一些改进它的想法:

  • 通过短信定义警报触发器
  • 支持其他类型数据的触发器,如“总死亡人数”
  • 支持多个短信收件人

我希望这篇文章对你有用。如果你有任何问题或反馈,我很乐意在下面的评论中阅读:)

建立新冠肺炎项目推荐系统

原文:https://towardsdatascience.com/building-a-covid-19-project-recommendation-system-4607806923b9?source=collection_archive---------16-----------------------

如何用 MLflow、Sagemaker、 Booklet.ai 创建 GitHub 开源回购推荐系统 web app?

TL;DR: 我们建立了一个新冠肺炎项目推荐系统来帮助人们发现社区中的开源项目。请继续阅读,看看我们是如何建造它的。

在新冠肺炎疫情期间,开源社区做出了巨大贡献,这让我深受鼓舞。GitHub 最近公布了一个超过 36K(!!)开源回购,人们为社区贡献他们的时间和代码。

当我浏览可用项目列表时,我被开发人员、数据科学家和其他技术社区倾注到世界各地项目中的热情所淹没。从跟踪症状的应用程序到对现有数据集的广泛分析,长长的项目列表确实令人振奋。

我发现自己(实际上)正在和朋友们讨论我们如何为这些努力做出贡献。当我们讨论构建一个分析或跟踪应用程序时,我们意识到为已经在进行的新冠肺炎开源项目做贡献会更有影响力。这让我产生了帮助人们尽可能容易地找到这些与他们的技能相关的伟大项目的想法。

考虑到巨大的工作量,找到一个可以参与的项目可能会很有挑战性。有如此广泛的项目,涵盖许多不同的语言和主题。为了使这更容易,我们建立了一个推荐系统。给定一组您感兴趣的语言和关键字,您可以找到一些可能与您的输入相关的项目。你可以尝试一下新冠肺炎项目推荐系统,或者一起来看看它是如何构建的!你也可以在 GitHub 上访问这个项目的完整笔记本。

新冠肺炎项目推荐系统Booklet.ai

您可能会发现这个演示与我发布的端到端销售线索评分示例有一些相似之处。如果你也看了那篇博文,谢谢你!请随意跳过您已经讲述过的部分。

免责声明:我是booklet . ai的联合创始人之一,这是一个免费工具,作为本演示的一部分使用。

先决条件

这将是一个技术教程,需要一点编码和数据科学的理解才能通过。为了从中获得最大收益,您至少应该接触一些:

  • Python(我们将一直呆在 Jupyter 笔记本中)
  • 自然语言处理(我们将使用一个简单的CountVectorizer
  • 命令行(是的,它可能很吓人,但我们只是使用一些简单的命令)
  • AWS(我们将帮助您解决这个问题!)

此外,您应该安装一些东西,以确保您可以快速浏览教程:

通过awscli访问的 AWS 用户名(我们将在下面介绍!)

带有几个包的某种 Python 3:

  • 熊猫pip install pandas
  • MLflow pip install mlflow
  • SKlearn pip install scikit-learn
  • NLTK pip install nltk
  • Docker(快速简单安装此处)

在我们开始之前…

我们将接触到各种工具和想法。在我们开始之前,重要的是后退一步了解这里发生了什么。我们将使用一些工具:

  • Jupyter Notebook :数据科学家用 Python 编程的常用方法。允许您以笔记本的形式运行 python 脚本,并在线获得结果。
  • MLflow :开源模型管理系统。
  • Sagemaker :来自 AWS 的全栈机器学习平台。
  • Booklet.ai :模型 web app 构建器。

下图概述了这些不同工具的使用方法:

作者的作品

我们将在 Jupyter 笔记本中使用 Python 来清理 Github 数据并训练一个模型。接下来,我们将把模型发送到 MLflow 来跟踪模型版本。然后,我们将把 docker 容器和模型发送到 AWS Sagemaker 来部署模型。最后,我们将使用 Booklet 展示该模型的演示。

让我们开始吧!

Python:训练模型

关于数据

我们正在利用来自 Github 上新冠肺炎回购数据回购的数据集。它包含 36,000 多个与新冠肺炎相关的开源项目,以及与每个项目相关的元数据。要了解关于数据集的更多信息,请查看数据字典

导入和清理数据

首先,您需要克隆 GitHub repo 以将数据提取到您的机器上:

git clone https://github.com/github/covid-19-repo-data.git

将最新的数据文件放入工作目录后,您需要使用 pandas 导入 tsv(制表符分隔值):

GitHub 数据集中列出了各种各样的项目,但是我们希望找到那些最有可能受益于额外贡献者的项目。为此,我们将设置几个过滤器:

  • 它必须至少有一个合并的 PR
  • 它必须有自述文件和描述
  • 它必须列出主要语言名称(主要是文本的回复,如文章列表,可能没有列出编程语言)
  • 它必须至少有两个不同的贡献者

以下是我们如何将这些过滤器应用于熊猫:

我们计划使用基于文本的方法来推荐项目,利用回购描述、主题和主要语言的组合作为我们的核心词汇袋。为了简化我们的文本处理,我们将删除标点符号,并仅限于英语回购描述(以后可能会添加更多语言!).为此,我们需要:

  • 首先,使用langdetect包来检测语言,并且只限于检测到英语的描述。
  • 接下来,我们将检查只包含拉丁字符的描述。在此之前,我们需要使用emoji包将表情符号转换成字符串(表情符号不是拉丁文吗?).我们将使用这个方法来排除不只有拉丁字符的描述,作为上面的langdetect方法的备份。
  • 最后,我们将删除回购描述、主题和主要语言中的标点符号,然后将所有这些内容组合成空格分隔的字符串。

为了完成上述任务,我们将设置几个助手函数,这些函数将应用于数据集中的文本:

接下来,我们将使用这些函数来完成清理和过滤:

运行完以上所有这些过滤器后,我们现在有大约 1400 个项目可以推荐。比我们最初的集合小得多,但希望仍然足以帮助用户发现可以贡献的有趣项目。

构建和运行矢量器

正如我们所讨论的,我们将基于由描述、主题和主要语言组成的词汇袋来推荐项目。我们需要获取这一大串单词,并将其转换成可用于推荐算法的形式。为此,我们将创建一个矢量器(也称为记号化器),它将我们的字符串转换成一个稀疏向量,指示字符串中存在哪些单词。

为了简单起见,我们将使用 sklearn 的CountVectorizer。在运行矢量器之前,有一些重要的输入需要讨论:

词条释义是将一个单词的多种形式转化为该单词的一个“词条”的过程。例如,“case”和“cases”都将转换为“case”。这对于减少噪音和创建向量时考虑的绝对字数是很重要的。这里我们使用nltk包中的WordNetLemmatizer()创建一个LemmaTokenizer类:

停用词是在创建向量之前我们将删除的词的列表。这些词不会直接给我们的推荐增加价值,比如“我们”、“the”等。Sklearn 有一个我们可以使用的很好的预置停用词列表。此外,我们将删除在我们的用例中非常常见并且不会区分项目的单词,例如“covid19”或“疫情”。在这里,我们将预先构建的列表与我们专门针对该数据集的手动筛选列表相结合:

现在我们可以构建矢量器,并在我们的项目列表中运行它。这创建了一个大的稀疏矩阵,该矩阵对我们数据集中的每个词袋进行矢量化:

构建推荐器

为了推荐项目,我们将接受一组语言和关键字,将其转化为单词包,并使用单词包找到最相似的存储库。首先,让我们检查代码,然后我们可以分解它:

  • 首先,我们将输入的文本字段转换成一个单词包。
  • 接下来,我们使用与前面相同的矢量器将单词包转换成表示文本的矢量。对我们来说,重要的是与之前相同的转换器,这样向量将表示与其他存储库相同的文本集。
  • 然后,我们使用cosine_similarity将向量从我们输入的字符串映射到整个存储库列表。这使我们能够理解每个单独回购协议的词袋与我们输入的词袋有多么“相似”。如果你想阅读更多关于余弦相似性的文章,这里有一篇很棒的文章
  • 最后,我们选取前 10 个最相似的存储库,并将其作为数据帧返回。

为了将这个推荐函数转换成可以部署的形式(我们将在一分钟内对此进行更多介绍),我们将利用 MLflow 的pyfunc类。我们需要创建一个类,该类包含预测所需的所有输入,然后运行预测并以正确的格式返回结果:

我们现在可以测试我们的新类了。我们可以基于类创建一个对象,使用我们的所有输入,并确保输出按预期填充:

您应该会看到一个字典格式的数据帧——很好!

MLflow:管理模型

什么是 MLflow?

在我们开始设置之前,让我们快速地聊一下 MLflow。官方说法是,MLflow 是“机器学习生命周期的开源平台。”Databricks 开发了这个开源项目,以帮助机器学习构建者更轻松地管理和部署机器学习模型。让我们来分解一下:

管理模型:在构建一个 ML 模型时,您可能会经历多次迭代并测试各种模型类型。跟踪关于那些测试的元数据以及模型对象本身是很重要的。如果你在 100 次尝试中的第二次发现了一个很棒的模型,并想回去使用它,该怎么办?MLflow 已经覆盖了你!

部署模型:为了使模型可访问,您需要部署模型。这意味着将您的模型作为 API 端点来托管,这样就可以很容易地以标准的方式引用您的模型并对其进行评分。为您部署模型的工具有一长串。MLflow 实际上不是这些工具之一。相反,MLflow 允许将您的托管模型轻松部署到各种不同的工具。它可以在你的本地机器上,微软 Azure,或者 AWS Sagemaker。我们将在本教程中使用 Sagemaker。

设置 MLflow

MLflow 跟踪服务器是一个很好的 UI 和 API,它包含了重要的特性。在我们可以使用 MLflow 开始管理和部署模型之前,我们将需要设置它。

确保您安装了 MLflow 软件包(如果没有,请查看先决条件!).从那里,在您的终端中运行以下命令:

mlflow ui

在这之后,您应该会看到闪亮的新 UI 在 http://localhost:5000/ 上运行

如果您在进行此设置时遇到问题,请查看 MLflow tracking server 文档此处。此外,如果你不想在自己的机器上安装跟踪服务器,Databricks 还提供了一个免费的托管版本

将模型记录到 MLflow

因为我们已经为我们的模型创建了pyfunc类,我们可以继续将这个模型对象推送到 MLflow。为此,我们需要首先将 Python 指向我们的跟踪服务器,然后设置一个实验。实验是 MLflow 跟踪服务器内部的模型集合。

在我们将模型对象发送到 MLflow 之前,我们需要设置 Anaconda 环境,当模型在 Sagemaker 上运行时将使用该环境。在这种情况下,我们需要利用默认的 Anaconda 和conda-forge。使用conda-forge的原因是,我们也可以下载nltk_datanltk软件包。通常,您可以在脚本中下载数据,但是在这种情况下,我们需要确保数据存储在包的旁边,以便在部署模型时使用。更多关于nltk_data的细节可以在这里找到。另外,关于 Anaconda 的更多信息,这里有一个详细的概述

现在,我们可以继续将模型记录到 MLflow。我们使用这个命令发送我们创建的类,以及该类的所有输入。这确保了运行模型所需的一切都打包在一起。

测试本地部署

在我们继续部署之前,我们将想要测试在本地部署模型。这允许我们在必须经历实际创建端点的过程(这可能需要一段时间)之前,理解任何可能出现的错误。幸运的是,MLflow 有一个很好的 Sagemaker 本地仿真器:mlflow sagemaker run-local命令。我们设置了一个小助手函数,这样您就可以将run-local脚本直接复制并粘贴到您的终端中:

一旦您在终端中运行了它(可能需要一分钟),您就可以测试本地端点以确保它按照预期运行。首先,我们设置一个函数来轻松调用端点,然后我们在 JSON 方向传入我们的数据帧:

您应该会看到与之前测试该类时相同的结果!如果您遇到错误,请到您的终端,您应该看到堆栈跟踪,以便您可以调试。

Sagemaker:部署模型

什么是 Sagemaker?

Sagemaker 是亚马逊网络服务(AWS)创建的一套工具,用于支持机器学习的开发和部署。Sagemaker 中有大量可用的工具(太多了,无法在此列出),我们将专门使用他们的模型部署工具。在他们的 GitHub repo 这里有一些伟大的 Sagemaker 例子。

设置 Sagemaker

首先,你需要得到许可。AWS 权限从来都不简单,但是我们会尽量保持简单!您需要设置两个不同的设置:您自己的用户和 Sagemaker 的角色。

第一个是用户帐户,这样您就可以在将模型发送到 Sagemaker 时访问 AWS。为此,您需要转到身份和访问管理(IAM)控制台,并设置一个具有管理员权限的用户帐户。如果您的安全团队进行反击,“Sagemaker 完全访问”应该也可以工作!在设置流程的最后,您将获得一个 AWS 访问密钥 ID 和一个 AWS 秘密访问密钥。一定要保存好这些!第一次之后就无法访问了。现在,到你的终端键入aws configure。这将提示您输入刚刚收集的 AWS 密钥。完成设置后,您就可以从终端和 Python 访问 AWS 了!这里是来自 AWS 的更多细节。

第二个是 Sagemaker 的角色(本质上是 AWS 内服务的用户帐户)。要设置这一点,请访问 IAM 的角色部分。您需要将这个角色分配给 Sagemaker,然后选择名为“SagemakerFullAccess”的策略。在这个过程的最后,你会得到这个角色的 ARN 奖!部署时我们需要这个,所以把它放在手边。更多细节来自 AWS 这里

最后,我们需要将一个 MLflow docker 容器推入 AWS。假设您正确设置了上面的权限并安装了 docker(参见 docker 设置的先决条件一节),您将希望在您的终端中运行以下命令:

mlflow sagemaker build-and-push-container

这将把一个 docker 容器推入 AWS,该容器将在部署期间使用。

部署到 Sagemaker

现在我们已经设置好了一切,是时候将我们的模型推送给 Sagemaker 了!

部署功能通常需要 5 到 10 分钟才能完成,并且在完成之前会经常使用此功能检查状态。一旦部署完成,您将能够在 Sagemaker UI 中找到一个列出的模型。

Booklet.ai:把模型变成网络应用

Woot woot,你的模型展开了!我们的下一步是确保任何人都可以方便地访问这些推荐。我们希望任何人都能够选择首选语言和关键字,然后看到一些推荐的回购。关于如何从这里向前推进,有几个选项:

  • 您可以共享代码来直接调用您的模型。这要求用户启动 python 环境,并利用正确配置的凭证在 Sagemaker 中直接调用模型。下面是教程
  • 您还可以创建一个定制的 web 应用程序,使用 Flask 之类的东西创建一个与您的模型交互的界面。这是那个方法的教程

在这一点上,我们急于尽快将模型送到用户手中。我们创建了booklet . ai来使构建 web 应用程序的最后一步变得简单快捷。

什么是 Booklet.ai

Booklet 为您的 ML 模型创建一个 web 应用程序,无需更改任何代码或安装额外的库。以下是 Booklet 工作原理的概述:

  1. 授予 Booklet.ai 只读访问有限数量的 AWS Sagemaker 操作的权限。
  2. 在我们的 UI 中选择您希望与 Booklet 集成的 Sagemaker 端点。
  3. Booklet 托管一个响应式 web 应用程序,它接受 HTML 表单输入,格式化数据,调用 Sagemaker 端点,并在 web 应用程序中显示结果。您可以原样返回输出,或者使用 Nunjucks 以您喜欢的任何方式格式化您的输出。

注册并授权访问 Sagemaker

Booklet 可免费用于您的第一个 ML Web 应用程序。前往注册页面创建一个账户。

您还需要通过与我们的 AWS 帐户关联的 IAM 角色授予对有限数量的 Sagemaker 操作的只读访问权限。以下是步骤:

  1. 在 AWS IAM 控制台中创建新角色。
  2. 为角色类型选择“另一个 AWS 帐户”。
  3. 在帐户 id 字段中输入“256039543343”(这是 Booklet.ai AWS 帐户 ID)。
  4. 单击“下一步:权限”按钮。
  5. 单击“创建策略”按钮(打开一个新窗口)。
  6. 选择 JSON 选项卡。将这个 JSON 复制并粘贴到文本区域。
  7. 点击“审查政策”。
  8. 将策略命名为“BookletAWSIntegrationPolicy”。
  9. 单击“创建策略”并关闭窗口。
  10. 返回“创建角色”窗口,刷新策略列表并选择您刚刚创建的策略。
  11. 点击“下一步:回顾”。
  12. 为角色命名,如“BookletAWSIntegrationRole”。点击“创建角色”。
  13. 复制角色 ARN。看起来有点像“arn:AWS:iam::123456789012:role/BookletIntegrationRole”。

随着 AWS 角色的创建和 ARN 的出现,我们就快成功了。在 Booklet.ai 设置中,粘贴 AWS 角色 ARN,点击“保存”按钮:

在 Booklet.ai 中输入 IAM 角色

为模型创建 Web 应用程序

点击 Booklet.ai 中的“新建模型”按钮,并选择您想要包装在响应式 web 应用中的 Sagemaker 端点。在此屏幕上,您还可以配置友好的显示型号名称和描述。我们需要设置两个快速配置来准备演示:

特性模式:这配置了用户将发送到您的 ML 模型的输入。在这种情况下,我们希望设置两个不同的字段:一个用于编程语言的多选文本字段,一个用于关键字的多选文本字段。您可以在下面看到我们是如何构建的:

后处理:配置输出如何显示给用户。Booklet 在这一部分使用了 Nunjucks,一种简单的 Javascript 模板语言。在编辑面板中,您可以参考模型结果的结构(根据特征模式中的默认值填充),还可以实时查看编辑后的输出更新。

Booklet.ai 中编辑后处理

对于这个模型,我们希望结果看起来像一个 Github repos 列表,所以我们以这种方式配置了 Nunjucks 模板:

填写完这两项配置后,请点击“更新型号”

为模型创建 Web 应用程序

您的 web 应用程序已经可以使用了!

完成小册子中的模型 Web App . ai

目前,您的模型只对小册子中您组织内的人员开放。您还可以通过返回到“设置”并将您的模型设置为“公共”(旁边有一个易于使用的 URL ),使您的模型易于共享,这样任何人都可以访问您的模型。

结束语

在本教程中,您已经学习了如何从 Github 中的原始数据集,一直到一个正常工作的 web 应用程序。感谢您的关注!如果你有任何想法,问题,或遇到问题,请在下面留言。提醒一下,这个项目的所有代码都可以在 GitHub 上找到。

编者注: 走向数据科学 是一份以研究数据科学和机器学习为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

Booklet.ai

构建加密 ML Web 应用程序

原文:https://towardsdatascience.com/building-a-crypto-ml-web-app-5f7dd1442568?source=collection_archive---------34-----------------------

用 AWS SageMaker 预测以太坊投资者概况

来源: Unsplash

TL;博士

该项目旨在将以太坊数据集、机器学习和云技术连接到一个项目中。结果是一个无人监管的 ML 数据产品,可通过网络用户界面访问。它基于使用提供的以太坊地址及其公开可用的数据动态构建的特征来预测投资者概况(聚类)。

项目代码可在 Github 上获得。

将模型预测作为 web 应用程序中的 API 端点

定义

项目概述

该项目将区块链数据、机器学习和云管理服务结合到一个最终产品中,即一个 web 应用程序。以太坊数据作为 GCP 公共数据集提供。

该网络应用程序预测在用户界面中输入的以太坊地址的投资者概况(聚类)。这基于从数据源中提取的三个特征:当前余额、唯一转账和持有的唯一代币

在金融术语中,投资者档案定义了个人在投资决策中的偏好。这方面的例子有风险厌恶/风险容忍、资产类别和单个资产的多样性、成长股或价值股的投资等。在这个项目中,它是指任何一种可以量化并用于区分不同以太坊地址的投资行为。

数据在 BigQuery 上可用,随时可以使用。挑战在于对数据进行建模,并将其用于 ML 模型。数据没有被标记,这就是为什么问题被公式化为无监督的机器学习任务。由于定价数据更容易获得和货币化,大多数加密机器学习项目都专注于预测这一点。

另一方面,该项目侧重于个人地址(投资者)的行为足迹,并根据可用的交易数据对其进行聚类。

AWS 的云服务用于在 web 用户界面中提供模型。AWS SageMaker 用于所有机器学习步骤,并将模型用作预测端点。然后,这作为 Lambda 函数通过部署的 API 端点和 API 网关被触发。此端点用于预测网络用户界面中的以太坊投资者概况。

问题陈述

虽然公共区块链上的数据是开放的,但还没有多少机器学习应用程序(除了价格预测)利用它们。原因之一是底层数据结构基于难以分析的 OLTP 系统(与 OLAP 相反)。

对于在公共区块链上执行的每一笔交易,都有我们可以分析的痕迹。与其他资产类别不同,我们有个人投资者行为的可用数据。该项目的目的是回答以下问题:

能否利用 BYOD(自带资料)的原理,仅用提供的地址聚类一个以太坊投资人?

考虑到问题的复杂性,我没想到会得到必然有见地的结果。目前有近 1 亿个独特的以太坊地址,这些地址高度多样化。目标是建立一个可行的解决方案。为此,需要做一些假设。

一个核心(过度)简化的假设是,一个地址等于一个投资者。这很难争辩,因为以太坊生态系统中有许多子群,如矿工、交易所和 ICO 钱包。同时,区分这两者超出了本项目的范围,本项目的重点是构建一个概念验证管道。

韵律学

对于给定数量的簇,每个模型将所有采样的以太坊地址聚类到单独的簇中。该项目中使用的指标是剪影得分。使用每个样本的平均聚类内距离和平均最近聚类距离来计算系数。这对于用例来说是理想的,因为我们没有可用的基础真值。

分析

数据探索

抽取 10000 个以太坊地址的样本。由于其中一些不满足指定查询中的进一步条件,数据框中大约有 8000 个可用。如下表所示,乙醚平衡的最小阈值为 1 乙醚。这是一个任意设置的边界,因为许多以太坊地址余额为零。

平均值为 138 以太(截至 2020 年 5 月 15 日,目前约为 25,000 欧元),这表明当我们查看第 75 百分位值时,分布的偏斜度。虽然第 75 百分位小于 13,但平均值是 138。样品中明显存在一些强异常值,例如最大值为 300000 乙醚平衡值。

unique_tokens 功能在以太天平上并不分散。通常值从 2 个唯一令牌到持有的 8 个令牌不等。

Unique _ transfers功能变化很大。平均转账次数为 26 次,最大金额为 28560 次。我们可以看到,前 25%的地址产生了大部分传输,因为 75%的地址没有一个传输超过 1 次。

探索性可视化

下面是所有构建要素的散点图。正如可视化中清楚显示的那样,在 eth_balanceunique_transfers 功能中都存在幂律分布。两者累积价值的绝大部分是由少数地址产生的。

同时,在不同的特征之间没有太多可见的相关性。

提取特征的散布矩阵

下面是所有可用功能的关联热图。如上所述,不同特征之间几乎没有相关性。这是一个积极的信号,因为我们想要探索具有不同特性的特性空间的不同区域。如果有很强的相关性,我们可以用不同的特征来解释相同的现象。

算法和技术

用于预测聚类的技术都是无监督的机器学习算法。选择的是 K-means,高斯混合模型和层次聚类。

与 K-means 一样,聚类之间的边界总是线性的,其他两种算法用于处理更复杂的边界。此外,通过测量聚类分配的概率或不确定性来进一步扩展分析的可能性。分析中没有这样做,但这是一个可能的扩展。

基准

该项目的基准模型是 K-means 算法的轮廓得分。之后,使用更复杂的算法来比较性能。根据经验,0.5 的轮廓分数被定义为具有合理性能的解决方案的阈值。

方法学

数据预处理

提取了三个特征:

  • 当前以太币余额
  • 历史上持有的独特代币
  • 以太坊地址的唯一传输

实现

项目中使用了相当多的 Python 模块。同时,这些是实现的核心。 Pandas_gbq 库用于查询 BigQuery 以太坊数据源。 Google-cloud-bigquery 用于认证 GCP 服务账户。 Scikit-learn 被用作所有型号的工具。

项目中使用的 AWS 服务:

  • S3,用于存储训练数据,用 transformer 对象进行预处理,以及 GCP 凭证
  • SageMaker 利用笔记本实例,将项目端到端地连接起来
  • Lambda 函数来触发预测脚本
  • API 网关,用于创建在用户与之交互的 web UI 中使用的 API
  • CloudWatch 记录和调试在构建解决方案的过程中可能遇到的问题

使用了来自以太坊公共数据源的两个表:

  • ` big query-public-data . crypto _ ether eum . balances '
  • ` big query-public-data . ether eum _ block chain . token _ transfers '

令人惊叹的 Bigquery 视图 Github 页面用于构建 SQL 查询并更好地理解以太坊数据模型。

下面我们可以看到一些不同以太坊地址的构造特征的例子。

以太坊地址特征示例

之后,使用 Sklearn 的管道功能对特征进行预处理。我们对它们进行规范化,以确保这些特征有助于输入到模型中。这通过使用功率变换、标准缩放和 PCA 变换来完成。PCA 变换在这里可能是多余的,因为只有三个特征被映射到三个分量,但是如果考虑到样本大小,特征集被扩展并且维数需要被减少,则 PCA 变换可能是有用的。

使用最终的特征集,所有三种聚类算法备选方案都被训练:K-均值模型、GMM 模型和分层聚类模型。

下图显示了 4 个集群中每个集群的实例数量。

聚类分布

所选择的集群数量是 4。它是基于不同值的反复试验而选择的。由于替代算法的性能没有显著提高轮廓系数,因此在部署的模型中使用的解决方案中使用了 K-means。

在使用训练脚本进行训练之后,被训练的模型的元数据与预测脚本相结合,以预测各个以太坊地址的聚类值。

预测脚本对所提供的以太坊地址的特征值进行实时计算。它查询以太坊数据源并返回规范化的特征值。这些然后被用作训练模型的输入,该模型返回预测的聚类值。

资料来源: Udacity MLND

最终的解决方案是通过 API 网关作为 Lambda 函数触发的预测端点。Lambda 函数是基于无服务器架构的云函数。它通过 API 网关部署为一个 API,可以在 web 应用程序的用户界面中使用。

每当用户输入以太坊地址并按下提交按钮时,预测的聚类值就会显示在用户界面上。

结果

模型评估和验证

最终结果是一个 web 应用程序,它根据用户提供的以太坊地址返回投资者资料。用户不需要提供任何个人数据,因为所有需要的数据都可以从公开的以太坊数据源中提取。

基于轮廓分数来评估模型。由于目前存在超过 1 亿个以太坊地址,如果不制定一些明确的规则,例如过滤掉非平凡余额,就很难对地址进行可靠的采样。

使用选择的度量标准对模型进行经验评估。K-means 的剪影评分是 0.38。因为没有可用的基本事实值,所以没有办法以可扩展的方式客观地测试这一点。另一方面,所选择的度量很好地量化了不同的聚类在特征空间中是如何被区分的。

最终的解决方案在一个 web 应用程序中进行测试,在该应用程序中为一个样本以太坊地址提取预测的聚类值。

考虑到性能,显然提取的数据没有足够的差异来创建可解释的聚类。当查看不同的集群时,也不可能找到有意义的集群命名。

正当理由;辩解

剪影系数的 0.5 阈值没有达到,这意味着考虑到这一指标,我们无法描述模型以充分掌握基础数据。同时,该项目的主要目标是构建一个最小的可行的解决方案,然后可以对其进行改进。

性能的最大瓶颈是输入到模型中的特性。有了对底层数据模型的更好理解,我们就可以构建更好的特性集。

此外,预处理也可以改进。除此之外,聚类的数量是通过反复试验选择的,在所有算法中具有相同的值。这可以通过使用一些更复杂的分析(轮廓分析)来加速。

结论

这个项目展示了如何相对快速地建立一个机器学习管道,并在 web UI 中以数据产品的形式提供它。

考虑到数据科学和加密行业的成熟,我们将慢慢看到一种转变,以一种以前不可能的方式将这些技术结合在一起将变得更加普遍。

借助云托管服务,大量复杂性被抽象出来,这有助于通常未接受过软件工程和开发运维/管理运维培训的数据科学家。除此之外,高级 API 可以帮助工程师构建以前只有专业数据专家才能使用的数据产品。随着这些领域的进步,我们可以看到大量的相互学习,这将使一个新的软件产品范例成为可能。

进一步研究

其他一些致力于加密数据解决方案的项目:

在 Scikit-Learn 中构建定制模型

原文:https://towardsdatascience.com/building-a-custom-model-in-scikit-learn-b0da965a1299?source=collection_archive---------11-----------------------

Scikit-Learn 令人难以置信。它允许其用户适应你能想到的几乎任何机器学习模型,加上许多你可能从未听说过的模型!所有这一切只需要两行代码!

然而,它没有一切。例如,有序回归无处可寻。而且它的深度学习能力……欠缺。但是谁在乎呢?你可以在其他地方找到这些东西,对吗?

没错。但是!Scikit-Learn 不仅仅是建模。还有一些非常棒的工具可以帮助你简化建模过程,比如GridSearchCVPipeline。这些工具是非常宝贵的,但它们只适用于 Scikit-Learn 模型。事实证明,如果 Scikit-Learn 和我们的 Google 霸主不直接给我们,我们可以制作我们自己的定制 Scikit-Learn 兼容模型!而且比你想象的要简单!

在这篇文章中,我将构建 Scikit-Learn 中明显缺失的东西:使用 k 的能力——意味着在Pipeline中进行迁移学习。也就是说,将聚类的结果输入到监督学习模型中,以便找到最佳值 k

警告:前方 OOP!

这篇文章会有点技术性。具体来说,我将假设您具有面向对象编程(OOP)的工作知识。也就是说,你知道如何以及为什么使用class Python 关键字。

你必须有这么多class才能继续。

Scikit-Learn 模板

Scikit-Learn 最棒的一点是它令人难以置信的一致性。拟合一种类型的模型名义上与拟合任何其他类型的模型是一样的。也就是说,在 Scikit-Learn 中建模非常简单:

model = MyModel(parameters)
model.fit(X, y)

就是这样!您现在可以分析您的模型了,可能是在模型的.predict().score()方法的帮助下。事实上,每个 Scikit-Learn 估计器都保证有 5 种方法:

  • .fit()
  • .predict()
  • .score()
  • .set_params()
  • .get_params()

构建您自己的

为了构建我们自己的模型,我们只需要构造一个具有上述 5 种方法的类,并以“通常的方式”实现它们。听起来工作量很大。幸运的是,Scikit-Learn 为我们做了艰苦的工作。为了构建我们自己的模型,我们可以从 Scikit-Learn 内置的基类中继承。

旁白:继承

在 OOP 中,如果我们指定一个类从另一个继承,那么“子类”将获得“超类”的所有方法

继承的语法如下所示:

class Car(Vehicle):
    # stuff...

汽车是一种交通工具。Car类将包括Vehicle类的每一个方法,加上更多我们可以在Car类定义中定义的方法。

Scikit-Learn 给了我们什么?

为了符合 Scikit-Learn,我们的模型需要从一些 mixin 继承。mixin 只是一个从未打算独立工作的类,相反,它只是包含了许多可以通过继承添加到当前类中的方法。Scikit-Learn 为每一种通用类型的模型提供了一个模型:RegressorMixinClassifierMixinClusterMixinTransformerMixin,以及其他几个我们不需要担心的模型。

我们想要自己创造的一切,都是通过简单地超越我们所继承的来实现的!

这是一个口无遮拦的例子。首先,一个简单的例子。之后,使用聚类的动机示例。

示例 1:空模型

零模型,有时称为“基线”模型,是除了随机猜测之外没有任何信息的模型。例如,回归问题的零模型将只是取训练数据的平均值 y 并将其用作每个预测。对于分类,它只是对每个预测取多数类。例如,如果你不得不预测某人是否会赢得彩票,零模型将指示你总是输,因为这是最有可能的结果。

事实:这和现实并没有太大的差别。

空模型有助于判断当前模型的表现。毕竟,如果你的模型很好,它应该会超过基线。Scikit-Learn 中没有内置 null 模型,但是我们很容易实现它!

import numpy as np
from sklearn.base import RegressorMixinclass NullRegressor(*RegressorMixin*):
    def fit(*self*, *X*=None, *y*=None):
        # The prediction will always just be the mean of y
 *self*.y_bar_ = np.mean(y) def predict(*self*, *X*=None):
        # Give back the mean of y, in the same
        # length as the number of X observations
        return np.ones(X.shape[0]) * *self*.y_bar_

很简单!我们现在可以自由地做平常的事情了…

model = NullRegressor()
model.fit(X, y)
model.predict(X)

重要的是,我们的新NullRegressor现在兼容 Scikit-Learn 的所有内置工具,如cross_val_scoreGridSearchCV

示例 2:使用网格搜索“调优”集群器

这个例子是出于好奇,当一位同事问我是否可以使用GridSearchCVPipeline来“调整”一个k-意味着模型。我最初说,因为您需要使用 clusterer 作为转换器来传递到您的监督模型中,这是 Scikit-Learn 不允许的。但为什么要让这阻止我们呢?我们刚刚学会了如何黑掉 sci kit——学会做我们想做的任何事情!说白了,本质上我想要的是创建以下管道:

Pipeline([
    ("sc", StandardScaler()),
    ("km", KMeansSomehow()),
    ("lr", LogisticRegression()
])

其中KMeansSomehow()是用作 Scikit-Learn 转换器的群集器。也就是说,它将 onehot 编码的聚类标签附加到数据矩阵X中,然后传递到我们的模型中。为了让它工作,我们将从定义一个继承自TransformerMixin的类开始。然后我们会给它适当的.fit().transform().fit_transform()方法。

但首先,初始化:

from sklearn.base import TransformerMixin
from sklearn.cluster import KMeansclass KMeansTransformer(TransformerMixin):
    def __init__(self, *args, **args):
        self.model = KMeans(*args, **args)

self.model的目的是包含底层集群模型。但是你问什么是*args**kwargs?它们是懒惰的程序员的捷径。它们本质上捕获了您传递给__init__()的所有其他参数,并将它们传递给KMeans()。这实质上是我在说“我传递给KMeansTransformer的任何东西也将传递给KMeans,我懒得去想那些参数将来会是什么。”

接下来,我们需要给它适当的拟合方法:

from self.preprocessing import OneHotEncoderclass KMeansTransformer(TransformerMixin):
    def __init__(self, *args, **args):
        self.model = KMeans(*args, **args) def fit(self, X):
        self.X = X
        self.model.fit(X) def transform(self, X):
        # Need to reshape into a column vector in order to use
        # the onehot encoder.
        cl = self.model.predict(X).reshape(-1, 1)

        self.oh = OneHotEncoder(
            categories="auto", 
            sparse=False,
            drop="first"
        ) cl_matrix = self.oh.fit_transform(cl)      

        return np.hstack([self.X, cl_matrix]) def fit_transform(self, X, y=None):
        self.fit(X)
        return self.transform(X)

应该就是这样了!我们现在可以像使用内置的 Scikit-Learn 转换器一样使用这个KmeansTransformer。最后,试试这个例子:

from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_blobsX, y = make_blobs(
    n_samples=100,
    n_features=2,
    centers=3
)pipe = Pipeline([
    ("sc", StandardScaler()),
    ("km", KMeansTransformer()),
    ("lr", LogisticRegression(penalty="none", solver="lbfgs"))
])pipe.fit(X, y)
pipe.score(X, y)
# ==> 1.0

在不太人工的例子中,您可能还想使用GridSearchCV来找到传递到您的逻辑回归(或您拥有的任何模型)中的最佳聚类数。

结论

现在,您应该明白如何在 Scikit-Learn 的框架内构建自己的定制机器学习模型,Scikit-Learn 是目前最受欢迎的(在许多情况下)强大的 ML 库。

这篇博文学究气吗?当然可以。你会需要这个吗?不,你可能永远不会需要这个,但这不是重点。这种技术被用于建造某种东西。需要一个建造者来认识到需要建造一个更有创造性的解决方案。另外,正如一位智者曾经说过的:

你永远不会因为知道得多而少。

我希望您喜欢将这个工具添加到您的工具带中。掌握了它,你可能才刚刚实现真正的机器学习提升

图为:我们机器学习者每天实际做的事情。

使用 Streamlit 快速构建数据应用程序

原文:https://towardsdatascience.com/building-a-data-app-with-streamlit-in-no-time-c5942c48abd?source=collection_archive---------36-----------------------

创建股票价格应用程序的实用指南

Streamlit 数据应用程序(作者 GIF)

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

当我开始我的数据科学之旅时,我对部署模型或创建 web 应用程序一无所知。我的数据科学世界被 jupyter 笔记本所束缚。

过了一段时间,我清楚地意识到我需要超越笔记本。无论我对数据做了什么,它都需要以某种方式转化为产品,以便其他人可以测试或使用它。从那时起,我开始学习部署模型和创建数据应用程序。

即使你创造了一个最先进的模型,当你坐在 jupyter 笔记本上时,它也不会创造任何价值。你可以创建一个出色的数据应用程序,但只有当其他人使用它时,它才有价值。

因此,创建产品并维护它们是数据科学领域中非常关键的步骤。

Streamlit 使将数据脚本转换成 web 应用程序变得相当容易。你不必有前端经验。你需要的只是 Python。

在这篇文章中,我们将创建一个简单的股票价格数据应用程序。它将提取并展示基于一些用户输入的股票价格。

我们将使用文本编辑器来编写脚本(我使用 sublime)。确保您的计算机上安装了 Python 3.6 或更高版本。

我们需要的依赖项可以通过 pip 从终端安装:

pip install streamlit
pip install pandas
pip install pandas-datareader
pip install datetime

让我们开始构建我们的应用程序。

第一步是导入依赖关系:

import pandas as pd
import streamlit as st
from pandas_datareader import data
from datetime import datetime, timedelta

我们可以为我们的应用程序显示一个标题:

st.title("Streamlit Stock Prices App")

下一步是检索数据。我们将使用 pandas-datareader 模块来获取股票价格数据。它需要三个输入,即股票名称、开始日期和结束日期。

我们将要求用户输入这些参数。Streamlit 提供了许多不同的方法来收集用户输入。

我们将使用 text_input 小部件向用户询问股票名称:

stock_name = st.text_input("Enter the stock name: \n")

对于开始和结束日期,我们将询问用户他们希望使用 slider 小部件查看多少天的数据。

option = st.slider("How many days of data would you like to see?",
      1,60,1)

数字参数是开始、结束和步长。

这些部件将出现在应用程序中,如下所示:

(图片由作者提供)

我们将使用 datetime 模块根据用户输入创建开始日期和结束日期。

end = datetime.today().strftime('%Y-%m-%d')
start = (datetime.today() - timedelta(option)).strftime('%Y-%m-%d')

我们把今天作为结束日期。通过回溯用户给定的天数来计算开始日期。例如,如果期权是 20 天,数据将显示过去 20 天的股票价格。

下一步是定义一个基于这些输入收集数据的函数。

def load_data(stock, start_date, end_date):
    df = data.DataReader(name=stock,
                         start=start_date,
                         end=end_date,
                         data_source='yahoo')
    return df

load_data 函数将创建一个 pandas 数据框架,其中包含基于给定输入的股票价格。

在我们调用这个函数之前,我们将显示一个描述操作状态的文本。

data_load_state = st.text("Loading data...")

当应用程序处理数据时,用户会看到“正在加载数据…”。

下一步是调用函数并创建一个熊猫数据帧。

df = load_data(stock=stock_name, start_date=start, end_date=end)
df.sort_index(axis=0, inplace=True, ascending=False)

我们现在将数据存储在数据帧中。我们有许多向用户显示数据的选项。Streamlit 提供了大量图表。例如,显示价格随时间变化的折线图会很有用。

我们不局限于 Streamlit 提供的图表。我们甚至可以运行机器学习模型来预测接下来的日子。

为简单起见,我将显示数据帧和折线图:

st.subheader(f'{stock_name} stock prices for the past {option} days')
st.dataframe(df) chart_data = df[['Close']]
st.subheader("Close Prices")
st.line_chart(chart_data)

名字让它看起来很明显。我们使用 st.dataframe()来显示数据帧,使用 st.line_chart()来创建折线图。st.subheader()允许为显示的对象添加标题。

最后一步是在应用程序处理数据时更改显示文本的状态。您可能还记得,正文是“加载数据…”。下面的代码会将其更改为“数据已加载!”。

data_load_state.text("Data loaded!")

下面是整个脚本的截图。

(图片由作者提供)

您可能已经注意到,我们在函数定义之前使用了“@st.cache”。它所做的是运行函数并将结果存储在本地缓存中。因此,如果使用完全相同的参数再次调用该函数,streamlit 将从本地缓存中读取输出,而不是再次运行该函数。

我们的剧本现在完成了。我们将把它作为 python 文件保存在当前工作目录中,然后使用命令行来运行脚本。命令是:

streamlit run "file_name"

(图片由作者提供)

当 streamlit 执行脚本时,浏览器中将会打开一个新的选项卡。

(图片由作者提供)

我们的数据应用程序现在已经完成。请注意,它目前正在您的本地计算机上运行。因此,只有你可以试验这个应用程序。

在下一篇文章的中,我将讲述如何在 AWS EC2 实例上运行应用程序。之后,你就可以和你的朋友分享你的应用了。

结论

我们已经创建了一个简单的应用程序,做一个简单的任务。然而,创建复杂应用程序的过程非常相似。

使用 streamlit 最大的好处就是一切都是用 Python 完成的。大多数(如果不是全部)数据科学家都熟悉 Python,因此他们适应 Streamlit 并不困难。

如同任何其他科目一样,熟能生巧。我建议先做简单的应用程序。然后,您可以稳步增加项目的复杂性。

感谢您的阅读。如果您有任何反馈,请告诉我。

构建数据仓库:基本架构原则

原文:https://towardsdatascience.com/building-a-data-warehouse-basic-architectural-principles-66bd7059ffd0?source=collection_archive---------6-----------------------

什么是数据仓库:基本架构

一种简化数据仓库的方法

谢尔盖·佐尔金Unsplash 上拍摄的照片

数据仓库理论有很多有用的资源。然而,如此大量的资源有时会让人不知所措——或者至少在我们开始构建数据仓库时是这样。

最初,当我们开始塑造我们的数据仓库架构时,我们问的第一个问题是:什么是数据仓库的正确架构?然后,经过一番研究,我们意识到没有对或错的架构。这总是取决于你的需求。

尽管如此,在开始构建数据仓库时,您应该记住一些业内公认的有用的架构原则。特别是,在构建我们的数据仓库架构时,三个基本原则对我们帮助很大:

  • 构建解耦系统,当涉及到数据仓库时,不要试图将所有流程放在一起。一种尺寸不适合所有人。因此,理解过程的本质,并为正确的工作使用正确的工具。
  • 实施功能性数据管道来自管道的数据应易于重现——例如,如果您想要重新运行一个流程,您应确保它将始终产生相同的结果。这可以通过实施功能数据工程范例来实现。
  • 实现一个不可变的暂存区,数据应该存储在一个不可变的暂存区。从那里,数据应该被转换并加载到您的数据仓库中。

在我们开始遵循这些原则之后,数据仓库过程变得简单了一些。因此,在这篇文章中,我们想与你分享一些关于这种架构原则的事情,以及它们如何帮助我们建立数据仓库的架构。此外,我们希望与您分享我们在 AWS 中构建数据仓库的首次尝试。

[## 什么是数据仓库:基本架构

数据仓库主要概念介绍

towardsdatascience.com](/what-is-a-data-warehouse-basic-architecture-ea2cd12c9bb0)

第一个原则:构建解耦系统

该原则遵循关注点分离原则。它基于这样一个假设,即每个系统都应该以这样一种方式处理一个问题,即这个问题应该被系统本身封装起来。

具体来说,数据仓库可以分为四个关注点,可以认为是数据管道的一部分:收集、存储、处理/分析和消费— 查看 Siva Raghupathy 的演讲了解更多信息 因此,作为我们数据管道一部分的每个系统都应该封装这四个关注点之一的职责

Siva Raghupathy 在幻灯片上的插图

第二个原则:实现功能性数据管道

这个原则基于函数式数据工程范例,这是一个将函数式编程范例引入数据工程学科的尝试。

实现功能数据管道的基础是在 纯任务之上定义数据流程。根据 Maxime Beauchemin :

“一个纯任务应该是确定性的幂等的,这意味着它每次运行或重新运行都会产生相同的结果”

因此,任何提取、转换或加载过程都应该遵循纯任务的标准——查看这篇帖子了解更多信息。

第三个原则:实现不可变的临时区域

这一原则基于在数据管道上实现一个临时区域,理想情况下,数据应该以其原始形式存储,或者接近其原始形式。

我们希望使我们的资源不变,这样就可以确保数据的再现性。根据 Maxime Beauchemin 的说法,不可变暂存区原则是再现性的关键,因为从理论上来说,它确保了从零开始重新计算整个数据仓库的状态是可能的。

个案研究

数据管道架构是基于 Siva Raghupathy 提出的关注点划分而设计的:收集存储处理/分析,以及消费。构建解耦数据管道的问题在于,编排可能会很复杂,因此,通过这种方式,我们添加了这一流程,作为设置数据管道架构时需要牢记的额外关注点。

在下一张图中,我们展示了这五个问题如何塑造我们的数据管道架构。

AWS 中的数据仓库体系结构——作者的实现

数据管道架构以这种方式解决了上述问题:

  • 收集:使用 Apache Spark 从本地数据库中提取数据。然后,它被加载到 AWS S3
  • 存储:数据以原始形式存储在 S3。它作为数据仓库的一个不可变的暂存区。
  • 处理/分析:使用 DBT 转换数据并插入 AWS 红移。请记住,DBT 只是作为在数据仓库内部执行转换的工具。一种解决方法是通过红移光谱外部表访问 AWS S3 数据,这样就可以使用 DBT 在红移中转换和具体化这些数据。
  • 消费:用户通过不同的 BI 工具消费数据,如元数据库表格
  • 编排:数据流程由气流编排。它允许解决人们在编制解耦系统时可能遇到的大多数问题。

最后,在整个数据管道中实施功能数据工程范例。我们确保所有数据流程(如、数据加载和数据转换)都是在纯任务的基础上定义的。因此,通过这种方式,我们确保了它们的确定性和幂等性——查看这篇帖子了解更多信息。

结论

我们的目标是这篇文章中的信息可以让你简化数据仓库的过程。

特别是,我们相信这些基本架构原则可以帮助人们开始他们的过程。然而,请记住这篇文章中的信息是对整个数据仓库理论的一部分的简化。

如果你想深入了解数据仓库的理论,别忘了查看 Ralph Kimball 的数据仓库工具包。这本书是最受认可的关于数据仓库的书籍之一。

此外,您可以在这里找到一些参考资料,帮助理解一些超出本文范围的内容:

我们希望这些信息对你有用。

感谢阅读到最后。

下期帖子再见!

如果你想随时更新我的作品, 请加入我的 简讯 !偶尔,我会和我的读者分享一些东西。如果你加入我会很感激:)

[## 对数据仓库感兴趣?

我已经写了几篇关于它的文章。这就是如何阅读它们!

ajhenaor.medium.com](https://ajhenaor.medium.com/interested-in-data-warehousing-424b49ec97e4)

数据仓库管道:基本概念和路线图

原文:https://towardsdatascience.com/building-a-data-warehouse-pipeline-basic-concepts-roadmap-d14032890ab6?source=collection_archive---------9-----------------------

什么是数据仓库:基本架构

提高数据管道可操作性和性能的五个过程

马克-奥利维尔·乔多因Unsplash 上拍摄的照片

构建数据仓库管道有时会很复杂。如果你是从这个世界开始,你很快就会意识到做这件事没有对错之分。这总是取决于你的需求。

然而,在构建数据管道以提高其可操作性和性能时,有几个基本的过程应该到位。

在本帖中,我们打算与分享一个路线图,它可以在构建数据仓库管道时作为指南

该路线图旨在帮助人们在通过一系列流程构建数据仓库管道时实现数据运营理念。

TL;DR — 在路线图部分,我们将讨论为提高数据管道的可操作性和性能而应实施的五个流程——流程编排、监控、版本控制、CI/CD 和配置管理。

如果您已经熟悉一些数据仓库术语,例如数据湖、数据仓库、批处理、流、ETL、ELT 等等,请直接跳到路线图部分。

基本概念

数据仓库世界的一个很好的起点是数据学校的书。

在本书中,他们介绍了数据复杂化的四个阶段。这些阶段是数据行业多年来一直遵循的数据管道架构模式。

基础建筑

数据仓库管道的基本架构可以分为四个部分:数据源、数据湖、数据仓库、数据集市**

数据仓库管道架构——作者基于数据完善的 4 个阶段的说明

根据数据学校,这些部分可以定义如下:

  • 数据来源:来自业务运营的数据。这些数据来自生产数据库、CRM、API 等等。
  • 数据湖:数据湖是在一个位置存储多个原始数据源的存储库数据有多种格式。通常,在数据管道的这个阶段,数据可能通常是非结构化的,并且有点混乱。
  • 数据仓库: " 数据仓库(通常也称为单一真实来源)是您的数据的干净、有组织的单一表示。有时它是完全不同的数据源,但越来越多的是虚拟结构化的,就像现有湖面上的视图模式。
  • 数据集市: “数据集市是数据仓库中经过过滤(有时是聚合)的子部分,使特定的组更容易查询数据。它提供了一个较小的模式,只包含该组的相关表。

这四个部分共同代表了数据管道的基本架构。数据从数据源向下移动到数据仓库。这可以通过批处理处理来完成。

批处理与流

批处理基于批量加载数据。这意味着,您的数据每天、每小时等加载一次。

流处理基于在数据到达时加载数据。这通常使用发布/订阅系统来完成。因此,通过这种方式,您可以几乎实时地将数据加载到数据仓库中。**

这两种类型的处理并不相互排斥。它们可能共存于一个数据管道中——更多信息请参见 Lambda 和 Kappa 架构。特别是,我们将在本文中重点讨论批处理方法

ETL 与 ELT 流程

批处理意味着将数据从 A 点移动到 b 点。允许执行此类任务的流程被称为 ETL 流程——提取、加载和转换。

这些过程基于从源中提取数据、转换数据并将其加载到数据湖或数据仓库中。

虽然,近年来,另一种方法已经被引入:ELT 方法。

数据学派认为这两种方法的区别在于:

ETL 是遗留方式,数据的转换发生在去湖边的路上。

ELT 是现代的方法,其中转换步骤保存到数据放入湖中之后。当从数据湖转移到数据仓库时,转换真的发生了。

ETL 是在没有数据湖的时候开发的;正在转换的数据的暂存区充当了一个虚拟数据湖。现在存储和计算相对便宜,我们可以有一个实际的数据湖和一个建立在其上的虚拟数据仓库。

ELT 方法优于 ETL 方法,因为它促进了最佳实践,使数据仓库过程变得更加简单— 例如,高度可重复的过程,数据管道架构的简化,等等。

数据管道路线图

我们建议您实施五个流程来提高数据管道的可操作性和性能。

这些流程是编排监控版本控制CI/CD配置管理。**

此类流程是基于数据运营理念定义的,该理念“是技术实践、工作流、文化规范和架构模式的集合”,能够减少数据管道中的技术债务——以及其他事项。

数据管道路线图——作者基于数据完善的 4 个阶段的说明

管弦乐编曲

在生活中的某个时刻,我们都编写过用于编排数据流程的 CRON 作业。

当数据处于正确的位置并且在预期的时间到达时,一切都会顺利进行。但是,有一个问题。事情总会在某个时候出错。当它发生时,一切都是混乱的。

采用更好的实践来处理数据编排是必要的——例如,重试策略、数据编排流程一般化、流程自动化、任务依赖性管理等等。

随着管道的增长,流程的复杂性也在增加。CRON jobs 无法协调整个数据管道。这就是工作流程管理系统 (WMS)介入的地方。它们是面向系统的,以支持稳健的操作,允许编排您的数据管道。

数据行业用的 WMS 有阿帕奇气流阿帕奇路易吉阿兹卡班

监视

您是否遇到过这样的情况:所有仪表板都坏了,业务用户来找您修复它们?或者你不知道你的 DW 坏了?这就是为什么您应该始终监控您的数据管道!

监控应该是一个主动的过程,而不仅仅是被动的过程。因此,如果您的仪表板或数据仓库出现故障,您应该在业务用户关注您之前就知道。

为此,您应该建立监控系统。它们持续运行,让您实时了解数据管道的健康状况。

用于监控的工具有 GrafanaDatadogPrometheus

CI/CD

更新数据管道中的变更是否涉及大量手动且容易出错的过程,以将它们部署到生产环境中?如果是这样,CI/CD 是您的解决方案。

CI/CD 代表持续集成持续部署。CI 的目标是"建立一种一致的、自动化的方法来构建、打包和测试应用程序"。另一方面,CD " 从连续积分结束的地方开始。CD 自动向选定的基础架构环境交付应用程序。”—更多信息此处

CI/CD 允许您以自动化的方式将更改推送到您的数据管道。此外,它将减少手动和容易出错的工作。

用于 CI/CD 的一些工具有詹金斯GitlabCICodeship特拉维斯

结构管理

所以…想象一下你的数据管道基础设施因为任何原因而崩溃。例如,您需要再次部署整个编排管道基础设施。你是怎么做到的?

这就是配置管理发挥作用的地方。配置管理 " 处理任何给定基础设施或软件系统在任何给定时间的状态。“它将类似基础设施的实践作为代码。此外,它还处理基础设施的整体配置—更多信息请点击此处

用于配置管理的工具有 AnsiblePuppetTerraform

版本控制

最后,软件行业中最著名的过程之一:版本控制。当版本控制实践不到位时,我们都会遇到问题。

版本控制管理工件中的变更。这是一个跟踪代码变更、迭代开发和团队协作的基本过程

一些用于版本控制的工具有 GithubGitLabDocker HubDVC

结论

在本帖中,我们推荐了五个流程,您应该实施这些流程来提高数据管道的可操作性和性能。

在实现数据管道时,这些过程通常会被忽略。我们希望这些信息能让您了解它们。

更重要的是,我们希望这份路线图能让您将数据管道提升到另一个可操作性水平!

我们希望你觉得有用。

直到下一次我的朋友们,

感谢阅读。

如果您想随时更新我的作品, 请加入我的 简讯 !偶尔,我会和我的读者分享一些东西。如果你加入我会很感激的:)

* [## 对数据仓库感兴趣?

我已经写了几篇关于它的文章。这就是如何阅读它们!

ajhenaor.medium.com](https://ajhenaor.medium.com/interested-in-data-warehousing-424b49ec97e4)*

构建数据库—没有数据库

原文:https://towardsdatascience.com/building-a-database-without-a-database-41fcbf586dd6?source=collection_archive---------28-----------------------

构建 pythonic 数据库类来获取、清理、转换、合并和标记数据——所有这些都不需要数据库

机器学习实践者和数据工程师都很清楚数据来源、收集、清理、转换、合并和标记的可重复性。这些活动的目的是为简化、探索性分析或建模准备数据。例如, scikit-learn 通过它们的 Pipeline 类在抽象数据管道方面做得非常出色。尽管如此,从多个来源提取数据的问题仍然存在,因为没有多少简单的抽象使数据争论者的生活更容易。

Python 数据库类|📸由

问题陈述:不同的数据是不同的,合并起来很麻烦。

解决方案:开发一个 pythonic 数据库抽象,以一种易于使用、健壮且生产就绪的方式合并您的数据。

目录

  1. 抽象
  2. 数据库—没有数据库—抽象
  3. 介绍 Python 数据库抽象
  4. 如何

关键概念

抽象使得编程生活更容易管理。一个数据库——没有数据库——抽象将使您的数据争论生活更加舒适,并且将是您的生产管道的一个健壮的补充。

1.抽象

为了不重复网上的文章,我将不解释抽象,但这里有两个参考:

抽象被定义为位于更复杂的事物之上,并使其对用户更简单的事物。—马特·伯吉斯在《批判的概念:抽象》中

2.数据库—没有数据库—抽象

没有数据库的数据库抽象(我称之为数据库抽象;不要与 SQL 数据库混淆)至少有四个用途:

  • 您只需要编写一次数据争论代码
  • 生产一个 ML 模型是非常容易的
  • 您不需要数据存储
  • 争论操作的顺序被保留并且是灵活的。

Python 数据库抽象图|📸由

你只需要写一次数据角力代码。

如果有足够的远见,数据库抽象将抽象出重复进行所有争论操作的需要。挑战是使抽象足够好,以允许用户以健壮和易于使用的方式灵活地应用他们喜欢的任何操作。

下面是众所周知的数据争论操作的一个不全面的列表:查询、排序、转换、填充空值和合并。为每一个实验和/或每一个生产模型编写代码来完成这些操作(甚至更多)是很难的。

生产一个 ML 模型是非常容易的。

ML 管道的最终目标是做出预测(例如,对于大多数 ML 任务)。数据科学家面临的一个问题是可重复性。当数据科学家处于试验阶段时,他们会应用各种各样的争论操作来测试哪个是最佳的。将最佳操作转移到生产场景并不总是容易的。

数据库抽象将允许科学家以可重复的方式轻松地从实验阶段过渡到生产阶段,然后再返回。

你不需要数据存储。

数据库抽象不需要本地或基于云的数据存储,但是您可能希望授予用户这种能力。在我的例子中,我不想管理数据库。我只是构建与 web APIs、网页等交互的功能。

他们的数据库是我的数据库,但他们的数据库问题不是我的问题。

注意:这种抽象的一个限制是查询速度。如果您管理自己的数据库,您可能会提高查询的性能。

角力作战的秩序被保留了下来,而且很灵活。

这个目的很重要,也是一个考虑不周的问题。把操作的顺序留给用户自己去理解和记忆是一个过分的要求。解决方案是构建一次——将操作的逻辑和顺序记录下来并构建一次——然后就不必再构建一次了。

操作顺序失败示例:下面的折线图显示,如果您对已经向前填充的价格序列计算移动平均,那么您的结果将会滞后。滞后的信息是不理想的。对于这些争论不休的任务,正确的操作顺序是在跨日期展开系列之前计算移动平均值,合并到主数据集,然后向前填充。

📸由

3.介绍 Python 数据库抽象

下面的数据库抽象是以生产就绪的方式合并、转换和合并数据的强大而健壮的方法。它是生产管道的第一步(见上图)。事实上,您可能会以某种方式创新和合并 scikit-learn 管道功能。一种可能是创建一个名为 MyPipeline 的新类,确保继承您的数据库类。然后,您的服务、lambda 或脚本可以使用您需要的所有功能来调用 MyPipeline。

你会注意到我没有为你做所有的工作。这种抽象 25%集中在金融领域。唯一的数据源是羊驼(我只展示我的类如何与羊驼交互,因为他们的 API 很简单,我的目的是教你如何钓鱼,而不是给你一个装满鱼的数据库)。你可能想要/需要更多的数据来源。此外,我的代码假设被争论的数据是时间序列数据。其余 75%的代码通常已经准备好供您复制、粘贴和开箱即用。我建议您根据自己的需要修改这段代码。

4.如何

在我们进入所有代码之前,我想向您展示一个用户或系统如何与这个数据库类交互。

dct = # shown later

database = Database(dct).build()

简单吧?

请注意,我将带您回顾数据库课程。例如,在我解释构建方法之前,我解释一下特性目标方法,当构建方法使用特性目标方法时。

初始化

首先 ,我们创建自己的类对象,并为用户提供一种与我们的抽象轻松交互的方式:通过 init 方法。

class Database:
    final_dataset = None
    data_cache_ = {
        'alpaca': {},
    }

    def __init__(self, dct: dict, jobs: int=1):
        *"""
        Initialize

        :param dct: user parameters
        :param jobs: number of processes
        """* self.dct = dct
        self.jobs = jobs
        self.config = dct

        self.date_dataset = pd.DataFrame(
            index=pd.date_range(
                start=self.config.get(
                    'globals', {}).setdefault(
                    'start_date', '2010-01-01'),
                end=self.config.get(
                    'globals').setdefault(
                    'end_date', str(datetime.now().date() \
                                    - timedelta(days=252 / 4))),
                name='Date'))

    def cache_data(self, source: str, key: str, json_data: dict):
        *"""
        Cache unique raw data

        :param source: data source (e.g., alpaca)
        :param key: unique identifier of raw data
        :param json_data: response from data request
        """* _ = self.data_cache_.get(source).setdefault(key, json_data)

这里,我们希望用户传入一个字典(如果需要,您可以构建自己的类,允许用户以字符串形式指定存储 json 文件的文件路径),指定所需数据的位置、如何获取数据、应用什么转换、用什么命名数据等。这是用户需要的一切。

在我们了解用户词典的外观之前,这里有一些后续要点:

  1. 数据缓存:由于我们不依赖于数据存储,如果我们要查询数据并对相同的数据应用不同的操作,那么我们希望缓存原始数据,这样我们就不会多次查询相同的数据。缓存原始数据将加快你的工作。
  2. 多处理引擎:用户可以指定运行作业的作业或进程的数量。你所需要的是一个多重处理引擎。(如果你想了解更多关于如何设置你的引擎的知识,我将很快写一篇关于马科斯·洛佩兹·德·普拉多在他的一本书中谈到的引擎的文章,这里。)
  3. 样本外(OOS)数据:我写这个类的方式有一些细微差别。例如,我用金融机器学习的视角写了这个类。在金融机器学习中,我们的数据一般是时间/价格序列数据。所以,我把最后的 252/4=63 天留作纸上交易。该论文数据集被认为是样本外的。(最后,我得到了训练、验证、测试和 OOS 数据集。)

用户交互

第二个 ,这个类提供了足够有用的结构,而且也很灵活。在我的例子中,用户交互非常冗长。我希望用户交互清晰无误。我还希望用户能够轻松地抬起和移动。为此,数据库类需要一个包含不同级别的键:值对的字典,如下所示。

第一级键是全局目标特征。Globals 用于指定整个数据集级别的参数。Target 用于指定应该为目标使用什么数据,以及应该应用什么标记技术(即转换)。特征用于指定哪些数据应该用作建模的特征。

第二层的键:值对需要关于数据源、参数(kwargs)、从源返回的数据的名称、要删除的特性(不需要,取决于源输出)以及数据类型的信息。

第三层的 key: value 对允许对底层数据进行转换。这些变换以一种易于理解的方式逐一应用于每个单独的特征。

dct = {
    "globals": {
        "start_date": "2010-01-01"
    },
    "target": {
        "source": "alpaca",
        "kwargs": {
            "timeframe": "day",
            "symbols": "AAPL",
            "limit": "0",
            "start": "2000-01-01"},
        "clean": {
            "names": [
                "open",
                "high",
                "low",
                "target",
                "volume"
            ],
            "drop": [
                "open",
                "high",
                "low",
                "volume"
            ],
            "types": [
                "float"
            ]
        },
        "transformations": [
            {
                "function": "trend_scanning_label",
                "kwargs": {
                    "name": "target"
                }
            }
        ]
    },
    "features": [
        {
            "source": "alpaca",
            "kwargs": {
                "timeframe": "day",
                "symbols": "AAPL",
                "limit": "0",
                "start": "2000-01-01"
            },
            "clean": {
                "names": [
                    "open",
                    "high",
                    "low",
                    "close",
                    "volume"
                ],
                "drop": [
                    "open",
                    "high",
                    "low",
                    "volume"
                ],
                "types": [
                    "float"
                ],
            },
            "transformations": [
                {
                    "function": "rsi",
                    "kwargs": {
                        "days": 14
                    }
                }
            ]
        }
    ]
}

要求

第三个 ,below 方法请求数据,不考虑 API。这个方法将 url、headers 和 kwargs 作为参数。数据以字典的形式返回,稍后进行处理。

@staticmethod
def request_data(base_url: str, headers: dict=None, **kwargs):
    *"""
    Request data through web api

    :param base_url: data source base url
    :param headers: headers to pass through requests
    :param kwargs: params to pass through requests
    """* if headers is None:
        response = requests.get(base_url, params=kwargs)
    else:
        response = requests.get(
            base_url, params=kwargs, headers=headers)
    return response.json()

净化

第四个 ,下面的方法根据上面用户字典中的 clean 键清洗数据集。传递给该方法的数据将是来自 request_data 方法(如上)的结果,作为 pandas 数据帧。之所以有参数 date_int_s,是因为有些日期时间数据有秒,有时没有(默认值设置为 False)。

特征被命名。列被删除。数据类型已设置。索引已排序。

@staticmethod
def _clean_dataset(
        dataset: pd.DataFrame, dct: dict, date_int_s: bool=False):
    *"""
    Clean dataset

    :param dataset: dataframe needing cleaned
    :param dct: clean dict with names, drop, and types keys
    :param date_int_s: make True if date is an integer with seconds
    """* dataset.columns = ['DateTime'] + dct.get('clean').get('names')
    dataset.drop(
        dct.get('clean').get('drop', []), axis=1, inplace=True)
    if date_int_s:
        dataset = dataset.assign(
            DateTime=pd.to_datetime(
                dataset.DateTime, unit='s').dt.date)
    else:
        dataset = dataset.assign(
            DateTime=pd.to_datetime(dataset.DateTime).dt.date)
    dataset.set_index('DateTime', inplace=True)
    names = [name for name in dct.get('clean').get(
        'names') if name not in dct.get('clean').get('drop', [])]
    dataset = dataset.astype({
        name: dtype for name, dtype in zip(names, dct.get(
            'clean').get('types'))})
    return dataset.sort_index(ascending=True)

数据源

第五个 ,我们需要数据来源。在这个例子中,我使用了一个源,Alpaca,但是,正如我前面提到的,你的源方法可以是任何种类的:Web APIs,网页,S3,SQL Server,CSV,你能想到的。

让我们不要触及这些方法的所有细节,但这里有一些要点:

  1. 多重处理:我们创建一个函数来与多重处理引擎交互。
  2. 第三方软件包:我不喜欢依赖第三方软件包,除非它们非常有用。numpy 、熊猫scikit-learn 是非常有用的第三方软件包的例子。有针对羊驼的 API 的包,但是他们的 web API 足够简单。
  3. 步骤:使成为查询和缓存的唯一标识符,设置头和 kwargs,从数据请求中查询并获取字典,缓存以备将来使用,使用多重处理在数据帧中快速创建数据行,然后清理数据帧。
@staticmethod
def _mp_alpaca(molecule):
    out = []
    for tickerset in molecule:
        for bar in tickerset[list(tickerset.keys())[0]]:
            out.append([bar.get('t'), bar.get('o'), bar.get('h'),
                        bar.get('l'), bar.get('c'), bar.get('v')])
    return out

def alpaca(self, dct: dict):
    *"""
    Get data using Alpaca's web api

    :param dct: dict of config source info
    """* key = str(sorted([(key, value) for key, value in dct.get(
        'kwargs').items()]))
    headers = {
        'APCA-API-KEY-ID': os.environ['APCA_API_KEY_ID'],
        'APCA-API-SECRET-KEY': os.environ['APCA_API_SECRET_KEY']
    }
    timeframe = dct.get('kwargs').get('timeframe')
    kwargs = {key: value for key, value in dct.get(
        'kwargs').items() if key != 'timeframe'}

    if self.data_cache_.get('alpaca').get(key, False):
        json_data = self.data_cache_.get('alpaca').get(key)
    else:
        base_url = 'https://data.alpaca.markets'
        json_data = self.request_data(
            base_url=F'{base_url}/v1/bars/{timeframe}',
            headers=headers, **kwargs)
        self.cache_data(
            source='alpaca', key=key, json_data=json_data)

    tickersets = [{ticker: barsets}
                  for ticker, barsets in json_data.items()]
    out = mp_pandas_obj(
        func=self._mp_alpaca, pd_obj=('molecule', tickersets),
        num_threads=1)
    dataset = pd.DataFrame.from_records(sum(out, []))
    dataset = self._clean_dataset(
        dataset=dataset, dct=dct, date_int_s=True)
    return dataset

注意:确保您的环境变量中有 APCA API 密钥 ID 和 APCA API 密钥。您可以从您的帐户中获取它们。

转换

第六个 ,我们需要一个方法来转换我们来源的数据;我们希望以某种方式构建它,以便从用户那里抽象出代码和争论任务的序列,使它灵活,并使它健壮。

下面的转换方法采用一个数据帧和一个要应用的转换列表。输出是一个转换后的要素,该要素被合并并正向填充到日期日期集中。如上所述,这个顺序是关键。稍后,您将看到这个新转换的特性是如何合并到我们的目标系列中的。

def transform(
        self, dataset: pd.DataFrame, transformation_lst: list):
    *"""
    Apply transformations to dataset

    :param dataset: dataframe needing transformed
    :param transformation_lst: list of dicts of transformations
    """* for transformation_dct in transformation_lst:
        if '.' in transformation_dct.get('function'):
            function = globals()[transformation_dct.get(
                'function').split('.')[0]]
            for notation_part in transformation_dct.get(
                    'function').split('.')[1:]:
                function = getattr(function, notation_part)
        else:
            function = globals()[
                transformation_dct.get('function')]
        if transformation_dct.get('kwargs', False):
            if transformation_dct.get('kwargs').get(
                    'other', False) and \
                    isinstance(transformation_dct.get('kwargs').get(
                        'other', 1), dict):
                sub_query_dct = transformation_dct.get(
                    'kwargs').get('other')
                dataset0 = self._get_data(dct=sub_query_dct)
                if sub_query_dct.get('transformations', False):
                    dataset0 = self.transform(
                        dataset=dataset0,
                        transformation_lst=sub_query_dct.get(
                            'transformations'))
                    dataset0 = self.date_dataset.copy().merge(
                        dataset0, how='left', left_index=True,
                        right_index=True).ffill()
                else:
                    dataset0 = self.date_dataset.copy().merge(
                        dataset0, how='left', left_index=True,
                        right_index=True).ffill()
                dataset = self.date_dataset.copy().merge(
                    dataset, how='left', left_index=True,
                    right_index=True).ffill()
                dataset = function(dataset, dataset0)
                continue
            else:
                dataset = function(
                    dataset, **transformation_dct.get('kwargs'))
        else:
            dataset = function(dataset)
        dataset = self.date_dataset.copy().merge(
            dataset, how='left', left_index=True, right_index=True)
    return dataset

目标

第七个,下面的函数采用第一级的键:值对,称为目标,请求数据并转换它,或者简单地将数据合并到一个日期数据集。

def target(self, transform: bool=True):
    *"""
    Make target dataset* *:param transform: False if using self.target standalone
    """* target_dct = self.config.get('target')
    dataset = getattr(self, target_dct.get('source'))(target_dct)
    if transform and target_dct.get('transformations', False):
        dataset = self.transform(
            dataset=dataset, 
            transformation_lst=target_dct.get('transformations'))
    else:
        dataset = self.date_dataset.copy().merge(
            dataset, how='left', left_index=True, right_index=True)
    return dataset

检索数据

第八个,我们需要一个检索数据的函数。

def _get_data(self, dct: dict):
    function = getattr(self, dct.get('source'))
    dataset = function(dct)
    return dataset

特征

第九个,我们需要一种快速获取特性并转换它们的方法:下面的方法。

类似于我们如何创建一个与我们的多处理引擎交互的方法,我们创建一个用于多处理特征的检索和转换的方法。一旦完成,最终的结果是一个数据集,将所有正确的争论和转换技术应用-在他们适当的顺序。

def _mp_features(self, molecule):
    out = []
    for feature_dct in molecule:
        dataset = self._get_data(dct=feature_dct)
        if feature_dct.get('transformations', False):
            dataset = self.transform(
                dataset=dataset,
                transformation_lst=feature_dct.get(
                    'transformations'))
        else:
            dataset = self.date_dataset.copy().merge(
                dataset, how='left', left_index=True, 
                right_index=True)
        out.append(dataset)
    return out@property
def features(self):
    *"""
    Makes features dataset
    """* if self.config.get('features', False):
        features_lst = self.config.get('features')
        try:
            out = mp_pandas_obj(
                func=self._mp_features,
                pd_obj=('molecule', features_lst),
                num_threads=self.jobs)
        except AssertionError:
            out = mp_pandas_obj(
                func=self._mp_features,
                pd_obj=('molecule', features_lst), num_threads=1)
        dataset = pd.concat(sum(out, []), axis=1)
        dataset = self.date_dataset.copy().merge(
            dataset, how='left', left_index=True, right_index=True)
    else:
        raise Exception('you need features in your dct file')
    return dataset

建设

第十个,最后我们来看最重要的方法:让它们都活起来的方法。这是用户调用来启动构建过程的方法。

该方法简单地创建了 final_dataset,该数据集包括转换后的目标和转换后的特征。如果用户在其字典中没有指定目标,则只有变换后的要素将构成 final_dataset。

def build(self):
    *"""
    Build dataset
    """* if self.config.get('target', False) and self.config.get(
            'target', False):
        self.final_dataset = self.target.copy(), how='left',
            left_index=True, right_index=True).merge(
            self.features.copy(), how='left', left_index=True,
            right_index=True)
        self.final_dataset = self.final_dataset.ffill().loc[
            self.investment.dropna().index]
    # only make features dataset
    else:
        self.final_dataset = self.features.ffill()
    return self

结论

在本文中,我们讨论并证明了争论任务有一个适当的操作顺序。我们构建了一个类来抽象用户自己应用这些操作的需求;我们以一种新颖的方式做到了这一点。

我希望你喜欢,我会喜欢你的反馈/挑战。

后续步骤

  1. 错误处理:如果你想加强用户通过你的抽象所传递的字典的结构,那么你将想增加好的错误处理和可解释的错误消息来帮助你的用户。有许多错误处理将使用户的生活更容易。
  2. 你应该有一个抽象类来执行某些方法。我认为这个数据库类是一个“基类”,因为其他抽象可以很容易地继承这个类。例如,在本文中,我简要解释了一种将数据库类的功能扩展到 MyPipeline 类的方法。

把所有的放在一起

参考

[1] M. Lopez de Prado,金融机器学习的进展(2018),威利

建立一个深度学习模型来判断你是否有风险。

原文:https://towardsdatascience.com/building-a-deep-learning-model-to-judge-if-you-are-at-risk-1c96f90d666c?source=collection_archive---------38-----------------------

使用 CNN + LSTMs 和 Carla 预测车辆碰撞前的瞬间!

关于

作者照片

该项目将 CNN 和 LSTMs 结合起来,在碰撞发生前利用一系列图像预测车辆是否处于碰撞过程中。CNN 有利于图像理解,但是如果图像之间没有序列关系,我们就会错过很多时间信息来预测一系列事件如何导致事件。

注意:

这篇文章假设你对 CNN 和 LSTMs 有基本的了解。你不必读完整本书,这个故事更多的是解释在构建项目中所面临的挑战、各种实验和优化。所以,你可以选择你想读的东西。把它当作解决你面临的问题的起点或指南。并非所有的知识都有用。

给我看看代码帮这里

环境

需要一个坚实的模拟环境来收集数据。 Carla 是一款可以提供环境等级控制的驾驶模拟软件。由于我们需要重放事故点的记忆,卡拉可以选择在违规或事故发生时发出危险信号。它也让我们使用不同种类的代理,从新手到专家。这使得卡拉成为收集数据的好选择。此外,我们还可以获得关于车辆、气候、街道物体、交通水平、速度等信息,这些信息在复杂系统中至关重要。

该项目完全建立在 Python 和 TensorFlow Keras 之上。

该项目可分为三个阶段:收集数据,创建适当的网络和培训。

1 数据收集

1.1 卡拉挑战

Carla 是一个图形密集型软件,令人惊讶的是,Carla 没有无头模式(在 windows 中),因此运行系统在某个时间点后变得非常慢,并且经常崩溃。

  • 通过更改配置文件,Carla 的图形设置被更改为可能的最低分辨率。
  • 帧数减少到 12 帧/秒,减少了机器的负载,这有助于程序收集完整的数据而不会崩溃。

1.2 自定义脚本

Carla 有 Python APIs,可以帮助你创建自定义代理供你四处驾驶。他们也有专业的代理人可以在地图上完美地行驶。

  • 首先,我们有一个天真的代理人,他开着车在城市里转,每 4 帧拍一次照片。我们使用一个天真的代理,以便我们可以捕捉更多的事故和违规行为。
  • 一旦发生事故或导致违规,CARLA 会发出危险信号,从事故发生的时间点开始,我们可以拍摄该事件过去的 15 个图像。所以,如果我们看这一系列的照片,随着时间的推移,每一张照片都让我们离事故更近了。
  • 收集统一驾驶的数据很容易,我们只需使用 Carla 提供的自动驾驶 API 来驾驶,并使用相同的捕捉率来拍摄照片,以保持一致性。
  • 当发生碰撞时,程序只执行最后 15 步,并自动删除该集之前的所有图像,以避免数据溢出。

1.3 数据处理:

收集的数据具有独特的结构,很难处理。收集的数据总量约为 40GB,很难移动数据或将数据加载到内存中,这不仅是因为数据的大小,还因为文件的数量(210,000)。此外,每个样本在事件发生前都有 15 个时间步长的图像,每个样本的图像分辨率都是 420×280 像素。

作者照片

  • Numpy 二进制格式与作为有效存储的数据类型的 int 一起使用。
  • 将所需的时间步数从 15 减少到 8 ,将分辨率减少到 210 X 140。
  • 这些图像被分批存储,每个文件 8 集,以减少文件数量和加快阅读时间。
  • 这些措施的结合将总体数据大小降至 8 GB,并加快了物流速度。

总共收集了 7000(集)×2(类)= 14000 个样本,每个样本包含大约 8 个用于训练网络的图像。由于环境的性质,没有应用数据扩充。这些样本是在卡拉的不同城镇和不同环境条件下收集的,以使其在不同条件下都具有鲁棒性。

2 模型架构

作者照片

众所周知,在处理序列或时间序列形式的问题时,随机神经网络效果最好,而 RNN 单位由于显而易见的原因被线性时间序列模型所取代。现在以时间序列的格式对给定的信息进行编码,但这仅适用于简单的数据,如数字序列。我们需要一种复杂的嵌入方法来理解复杂的数据形式。

  • 对于图像,我们可以使用卷积神经网络。细胞神经网络被证明是提取空间信息的最佳方法。我们将使用一些标准的 CNN 架构来从图像中提取特征。因此,对于系列中的每个图像,我们将获得一个固定大小的特征向量,该向量可以传递到它们各自的 LSTM 时间步长单元中。
  • 但是我们不需要这么多 CNN 来学习图像。三维细胞神经网络适合这类数据,它比时间相关性更适合探索和学习空间相关性。
  • 因此,我们可以使用时间分布式包装器,包装我们的 CNN 层,以跨时间步长传播它。与 3D CNNs 相比,这在提取时间相关性方面要好得多,因为它仅使用单个 CNN 来学习跨时间步长的图像特征。
  • 一旦这些特征以嵌入向量的形式被提取,所有这些特征在它们的时间步中被传递到它们各自的 LSTM 单元中。
  • 现在,这些嵌入被带入编码器,然后传递给完全连接的层,这些层又学习分类任务。
  • 图中显示了最初提出的网络,对于卷积模块,使用全 VGG 网络来获得图像嵌入。CNN 网络在时间上是分布式的,以执行每个时间步长的卷积。尽管这个网络最初看起来在逻辑上是正确的,但它经历了许多修正才达到了所示的结果。

2.1 培训问题

  • 即使网络相对不小,训练也导致了存储器耗尽错误,因为网络在时间上是分布式的,这导致了运行时间耗尽的问题。
  • 有时,训练将运行一定量的时间,并在达到上限后停止,这是由于 CNN 每层中发生的数据大小和时间分布操作。
  • 因此,批量大小被减小,并且在大量实验之后,一些网络参数如滤波器大小和嵌入大小被小心地调整。

2.2 过度拟合

  • 过度拟合一直是深度学习的致命弱点。最初,我对数据拟合过度并不感到惊讶。网络立即对给定的数据进行了超拟合,即使在 epoch1 中,准确率也是 100%。显然,测试数据中的结果非常糟糕
  • 因此,我继续进行标准的过度拟合程序,如检查数据、偏差、添加批次标准化等。
  • 但事实证明,这个问题对于这种网络架构来说是非常独特的。网络过载,因为对于每个全局网络步长更新,网络的 CNN 部分更新 8 次(时间步长数)。
  • 这意味着网络的 CNN 部分正在学习太多关于图像的信息,而它下面的 LSTM 层却跟不上。
  • 这个问题的解决方案是缩小 VGG 网络的规模。CNN 网络几乎减少到原始网络的一半,并且在对各种滤波器数量和组合进行重复实验之后,仔细选择滤波器。
  • 此外,通过添加两个完全连接的层和漏接层而不是提议的一个层,显著提高了性能,准确率为 65–71%。

2.3 学习复杂时间函数

  • 增加 LSTM 层中 LSTM 单元的数量会稍微提高性能,之后增加单元的数量不会产生任何影响。
  • 但是在网络中添加 LSTM 层有助于提高网络的性能,这实际上使网络能够学习更复杂的时间函数,网络的准确率提高到了 86%。

2.4 一个更好的 CNN

  • 到目前为止,VGG 层在网络中运行良好,但是可以通过添加更智能的层而不是简单的 VGG 层来提高网络的性能。

作者照片

  • 为了实现这个想法,两个具有精心选择的过滤器数量的初始模块被用来代替 VGG 层。
  • 值得注意的是,没有选择 ResNet 模块,因为问题不是健忘的网络,而是我们需要一个更好的特征提取器。
  • 此外,需要对完全连接的层进行修改,以防止过度拟合,这令人惊讶地工作得很好,使网络的最终训练精度达到 93%。

3 培训

训练过程类似于分类任务,我们可以使用 softmax 交叉熵来查找损失,并使用 Adam optimizer 将其最小化。

  • 与传统的(批量、通道、宽度、高度)相比,输入的维度是(批量、时间、通道、宽度、高度)。总的来说,LSTMs 比 CNN 花费更多的时间来训练,因为我们训练两者,我们可以预期训练对于分类任务来说是相当耗时的。
  • 这是一个相当大的网络,大约有 1400 万个参数,它需要一个好的 GPU 进行训练,否则就会出现内存耗尽错误。幸运的是,我使用了 GTX 1080 Ti 机器,在 3 小时内完成了训练。培训和测试指标如图所示:

作者照片

  • 该图显示了准确性随时间的提高,并且还可以注意到,具有初始模块的网络比基于 VGG 的 CNN 表现好很多。
  • 基于 VGG 的网络已经在其损失中振荡,甚至准确度也相当低。另一方面,如图所示,具有初始模块的网络表现更好,并且具有相对稳定的收敛。
  • 对于 VGG,批量大小是 16,而对于基于 inception 的批量大小是 8(由于内存耗尽)。如果我们对初始模型也使用更高的批量,那么度量会更加平滑。

作者照片

结果

作者照片

向该系统提供视频馈送,并且获得给定图像系列的安全级别。因此,每时每刻都会升起一面安全旗帜。

一辆汽车在各种卡拉环境中行驶的多个视频剪辑被提供给网络,它表现得非常好。

推论 1

  • 预测依赖于车辆的速度,当实际的人驾驶汽车时,速度动态变化,而火车样本是通过恒速驾驶收集的。
  • 当车辆快速行驶时,通过减少事故发生前的时间,这对于预测未来有影响,并且如果车辆缓慢行驶,这可以提前很好地预测。

推论 2

  • 这里要注意的一件重要事情是,网络实际上学会了知道一个环境何时是安全的或有风险的。这可以清楚地看到,当车辆从碰撞、未遂事故中后退时,网络的状态从危险变为安全。
  • 这种特殊情况从未出现在训练样本中,这确实意味着网络以一种有意义的方式学习了安全和危险的环境,而不仅仅是记忆碰撞模式。

使用

作者照片

  • 该项目的核心是提取时空信息,并利用它来更好地理解我们的环境,用于风险预测、上下文和场景理解、行为识别和预测等。
  • 该项目不仅可以用于自动驾驶汽车的决策系统,还可以用于手动汽车的应急协议系统,以防止极端事件。
  • 该网络可以集成为汽车的一部分,汽车可以调用安全协议,例如应用刹车、打开安全气囊、部署安全预防措施,甚至可以调用位置紧急服务。在碰撞发生前几秒钟预测碰撞对于人类来说可能没有足够长的时间来做出反应,但对于机器来说,这确实是一段很长的时间。
  • 这也可以用作强化学习任务的奖励生成系统。
  • 这个项目虽然非常具体,但只能应用于特定的领域,在我看来,这个项目的目标是让神经网络像我们人类一样理解带有时间元素的场景。

课程

  • 总是看你是否真的需要数据的全部复杂性,我们降低分辨率和时间步骤的数量来简化问题。
  • 如果你正在使用模拟软件,检查你是否减少了所需的计算能力,自动化,加快了速度。
  • 从你的想法开始,进行实验,失败,然后通过标准的社区实践来修改你的网络。随着时间的推移,这有助于你建立直觉,你可以看到自己转动网络的正确旋钮,离开随机实验。
  • 每个问题都是不同的和独特的。所以,即使问题看起来很熟悉并且已经解决了,也要坚持做上面的步骤。
  • 过度拟合可能有不同的原因。检查您的问题、模型和数据的性质,以开发洞察力。对于我们的问题,这是与网络的性质。
  • 摆弄超参数,但是记住,这种调整不能超越对问题本质的错误假设。有时这只是我们一方的错误假设。
  • 稍微了解一下每一层对整个网络的贡献,这有助于调试,例如添加一个 LSTM 层,而不是添加更多的单元。
  • 如果可能的话,尝试一种不同的方法,看看是否能让你的模型变得更好。我们尝试用初始模块做实验,给了我们惊人的结果。
  • 进行推理并检查网络是否实际学习了预期的目标函数是非常重要的。如果它没有很好地学习任务,数字没有任何意义。
  • 看到更大的图片。您可能无法在某个地方直接或立即使用该项目。但是你从尝试一个未知的项目中获得的知识在你未来的支出中是非常有价值的。
  • 我们都在一起,注意安全。

YouTube 链接:https://www.youtube.com/watch?v=5E20U7b_4zQ

代码、外部链接和引用都在这个 GitHub repo 里。

如果你觉得有用,请启动 GitHub repo。

我的其他作品,

[## 我如何从零开始使用 Tensorflow 构建卷积图像分类器。

(不使用狗 Vs 猫,从从谷歌获取图像到保存我们训练好的模型以便重用。)

medium.com](https://medium.com/@ipaar3/how-i-built-a-convolutional-image-classifier-using-tensorflow-from-scratch-f852c34e1c95) [## 通俗地说就是强化学习。

(包含令人敬畏的图形图像)。

medium.com](https://medium.com/@ipaar3/saturnmind-94586f0d0158)

构建深度学习的人物分类器

原文:https://towardsdatascience.com/building-a-deep-learning-person-classifier-ecc55bd01048?source=collection_archive---------8-----------------------

准确识别人脸和非人脸的图像

照片由岩田良治Unsplash 上拍摄

介绍

机器学习统计分类是识别一个新的观察值属于一组类别(子群体)中的哪一个的问题,其基于包含其类别成员已知的观察值(或实例)的数据的训练集[1]。

“浅层”学习技术,如支持向量机 (SVM)可以从中等大小的数据集产生有效的分类器,最近深度学习分类器已经在识别任务中与人类相匹敌,但需要更大的数据集和大量计算资源来实现这一点。特别是,深度学习技术已经产生了卷积神经网络 (CNN),这是最先进的图像分类器。

本文将向您展示如何使用 TensorFlow 开发一个基于 CNN 的个人分类器,它在某些情况下可以胜过标准的人脸识别技术。标准方法通常包括使用像 SVM 这样的浅层学习器来对面部嵌入生成的模式进行分类(例如,参见高超的面部识别程序)。)标准技术是 极度 擅长在大部分人脸可见的情况下识别。然而,我的应用程序需要一种方法来准确地对只有部分面部视图的人进行分类,最好是从后面进行分类。这为使用深度学习开发一个人分类器提供了动力,我的目标是在看他们认识的人的图像时,无论有没有脸,都能达到和人类一样的识别精度。

需要以下步骤来构建准确的基于 CNN 的人分类器,该分类器识别新观察结果属于一组已知和未知人中的哪一个。这些步骤也适用于训练其他类型的基于 CNN 的分类器。

  1. 收集你想要分类的每个人以及陌生人的图像,以创建你的训练集并对其进行预处理。您应该使用数据扩充方法,从收集的数据中自动生成相关的新图像,以增加数据集的大小。你的数据集很可能是不平衡的,也就是说,每一类的观察值并不相同。您将需要对此进行补偿,否则您的模型将过分强调具有更多观察值的类,其准确性将受到影响。最后,您的数据集需要转换成适合训练过程的数据格式。你应该为每堂课计划一个至少有 1000 个观察值的训练集。请注意,观察和样本这两个术语在本文中可以互换使用。
  2. 选择已经在标准数据集上训练过的 CNN,并将其用作将成为您的分类器的新模型中的一个层。标准数据集应包含类似于您想要分类的类别。在这种情况下, ImageNet 是一个很好的选择,因为“人”(在一般意义上)已经是它被训练识别的一个类。TensorFlow 提供了许多 CNN 模型,具有不同的复杂性和精确度。您应该选择能够满足您的应用程序的推理准确性要求的最简单的模型。当然,您可以对任何类似于 ImageNet 类的类进行微调,而不仅仅是人。
  3. 使用您的图像数据在您的 CNN 上应用 转移学习 。深度神经网络容易过度拟合,你将学习几种缓解技术来对抗它。请注意,迁移学习也称为微调,训练模型也称为将模型拟合到数据集。这些术语在本文中可以互换使用。
  4. 评估微调后的型号。您应该检查微调模型的准确性,看看它是否符合您的应用要求,如果不符合,则使用更多数据或更优的训练参数(“超参数”)重新调整它。
  5. 保存您的模型并为推理做准备SavedModel 是保存和提供 TensorFlow 程序的标准方式,但是您可能还希望生成一个 TensorFlow Lite 表示,以便部署在移动或边缘设备上。两者都包括在下面。

请注意,我使用了一台 64GB 主内存的英特尔 i5 + Nvidia 1080Ti 机器来训练我的模型。你至少需要一台类似的机器来可行地训练一个深度学习模型。

另外,请注意,这些工作大部分是为smart-zone minder项目完成的,您可以利用这些工作。如果您只想快速微调 TensorFlow CNN 而不深入细节,在合适的机器上安装机器学习平台,按如下所述准备您的数据集,并运行 Python 程序 train.py ,其中包含适合您配置的选项。本文的其余部分将一节一节地对 train.py 进行分解,以帮助您理解它是如何工作的,从而更好地使用它,并可能根据您自己的需要对它进行修改。

数据集准备

在一个名为“数据集”的目录中,为你想要识别的每个人的图像创建一个子目录,并以该人的名字命名(我用我的 Google photos 作为这个目录的种子)。另外,创建一个名为“未知”的子目录,保存随机陌生人的面孔。在每个子目录中,您可以选择放置另一个子目录,该子目录可以保存没有完整或部分面部视图的人的图像。您可以决定将此类图像作为其类的成员或未知类。数据集目录将如下所示。

dataset
    |-name_of_person_1
        |-sample_image_1
        |-sample_image_2
        |-sample_image_n
        |-images_with_no_face
            |-sample_image_1
            |-sample_image_2
            |-sample_image_n
    |-name_of_person_2
    |-name_of_person_n
    |-Unknown

下面的函数根据数据集的内容创建 Python 数据帧。

从数据集创建数据帧

dataframe 是 TF . keras . preprocessing . image . image data generator 类的 flow_from_dataframe 方法的输入。ImageDataGenerator 通过实时数据扩充生成批量张量图像数据,并创建训练集和验证集。flow_from_dataframe 方法为每个集合创建一个 Python 生成器。该代码如下所示。

创建培训和验证生成器

虽然可以直接使用 train_generator 和 validation_generator 来拟合 CNN 模型,但是使用来自 tf.data.Dataset 的数据集对象将会给更好的拟合性能。在 train.py 中,这是按如下方式完成的。

创建一个 tf 数据集

由于某些类别中的样本图像可能比其他类别中的多,因此您需要将类别权重传递给模型拟合过程。下面显示了实现这一点的代码,以及拟合过程用于训练和验证的步骤数。

确定类别权重和拟合步骤

这些数据现在可以用来拟合模型了。

模型准备

下面的函数从一个 ImageNet 预训练的 tf.keras.applications 模型创建一个 CNN 模型。虽然该函数将基于 VGG16、InceptionResNetV2、MobileNetV2 和 ResNet50 创建模型,但只显示了 InceptionResNetV2。从基本模型中移除最后的 softmax 层,添加新的密集分类器和 softmax 层,然后编译它。请特别注意超参数常数,因为它们可能需要调整以适应您的数据集,但默认值给我很好的结果。该函数包括各种过拟合缓解技术,包括 L2 正则化标签平滑和 D ropout 。它还会选择一个适当的 tf.keras 预处理器来正确格式化数据样本。

Python 函数来创建 CNN 模型

该模型现在可以进行微调了。

模型微调

微调分两步完成。第一遍使用高学习率,并且只训练新添加的密集层和软最大层,因为它们是用随机数据初始化的。第二遍使用小得多的学习速率,并训练最后几层以及基本模型的大部分。两遍方案以及正则化被设计成尽可能多地保留来自基础模型的原始权重,同时仍然从新的数据集中学习模式。两次通过都使用提前停止基于验证损失,这是减轻过度拟合的另一种方法。

第一遍微调代码如下所示。请再次注意,只有新的层是适合的。

微调的第一步

微调的第二步如下所示。请注意,底部基础模型的一些层是冻结的,不会在此步骤中进行训练,但所有其他层都将进行训练。冻结的层数是一个超参数,它在保留根据 ImageNet 的高级功能训练的层与允许顶层学习数据集中的新功能之间保持平衡。尽管采取了所有缓解措施,解冻的图层越多,防止过度拟合所需的数据就越多。

微调的第二步

该模型现在已经过微调,将评估其准确性,并保存以供下一步进行推断。

最终模型评估

应该对您的模型进行评估,以确定其精度是否满足您的应用要求。从它的预测中生成一个 sklearn 分类报告就是这样做的一种方式,如下面的代码所示。

生成分类报告

下面显示了我的一次运行的分类报告示例。虽然我很高兴这个模型偏向于它的创造者;),需要更多的工作来通过数据集中的额外观察和超参数优化来提高其他类的准确性。

分类报告示例

目前,我最好的结果是使用 InceptionResNetV2 基本模型,它实现了大约 92%的整体准确性。我的目标是大于 95%,这是我对正常人在有脸和无脸图像上所能实现的主观估计。作为比较,使用上述标准方法对于具有完整或大部分完整人脸视图的那些图像产生大约 90%的准确度,而对于具有完整、部分人脸和没有人脸的相同数据集,准确度小于 70%。

保存用于推理的模型

train.py 包括以各种方式保存模型的选项-冻结的 TensorFlow 程序(从 TensorFlow 2 开始不推荐使用),针对物联网设备上的推理进行优化的八位量化 TensorFlow Lite 程序,针对谷歌的 Edge TPU 和 TensorFlow SavedModel 格式(从 TensorFlow 2 开始的规范方法)编译的 TensorFlow Lite 程序。下面的代码显示了 train.py 如何保存为 SavedModel 格式。

将最终模型保存为 SavedModel 格式

最终的模型现在已经准备好通过它的 SavedModel 或其他表示进行推理了。有关保存和使用边缘模型的更多细节,请参见在谷歌边缘 TPU 上使用 Keras。

结论

与用于训练基本模型的原始数据集相比,您可以利用 TensorFlow 通过中等大小的数据集快速微调 CNN 分类器,如上面的 person 分类器示例所示。来自smart-zone minder项目的 Python 程序 train.py 可以用来构建自己的分类器,或者作为开发自己程序的参考。

将深度学习模型拟合到有限的数据可能会很棘手,因为它们可以快速记住数据集,但不会很好地推广到新的观察结果,这就是所谓的过度拟合。为了减轻这种情况,您可以使用以下技术。

  • 收集更多的观察数据。
  • 数据增强。
  • 选择满足应用精度要求的最简单模型。
  • L2 正规化。
  • 辍学。
  • 标签平滑。
  • 阻止许多基础模型层被定型(“冻结”)。
  • 根据验证损失提前停止培训过程。

您还很可能不得不处理数据集中每个类的不同数量的样本(例如,不平衡的集合),这将影响模型的准确性。为了进行补偿,您需要在模型拟合过程中使用类别权重。

构建 CNN 分类器的步骤如下。

  1. 收集和预处理您的数据集。
  2. 选择一个合适的 CNN 基本模型。
  3. 微调模型。
  4. 评估您的微调模型的准确性。
  5. 准备您的最终模型进行推理,并保存它。

参考

[1] 统计分类,来自维基百科,免费百科。

构建深度学习驱动的(婴儿)名称生成器

原文:https://towardsdatascience.com/building-a-deep-learning-powered-baby-name-generator-5d91a14ddc3b?source=collection_archive---------21-----------------------

维基百科传记和深度神经网络能告诉我们名字里有什么吗?

当我年轻的时候,我总是讨厌被叫做戴尔。这主要是因为我对戴尔的最初印象是由《T2》中的《山丘之王》和《T3》中的戴尔·格里布以及纳斯卡车手小戴尔·恩哈特塑造的。

戴尔·格里布图像信用,戴尔·恩哈特 Jr 图像信用

这两个山谷都不符合我渴望的自我形象。相反,我想被命名为美少女战士。

我不喜欢我的名字是“雌雄同体”——每出生一只雌斑羚,就会有 14 只雄斑羚出生。当我问我父母这件事时,他们的理由是:

A.名字雌雄同体的女性可能更成功。

B.他们的时髦朋友刚刚给他们的女儿取名为戴尔,真是太可爱了!

值得称赞的是,作为一个成年人,我确实觉得在我的简历上,在 Github 上,在我的电子邮件签名中,甚至在 Medium 上假装是一个男人(或者不直接否认)让我受益匪浅。

但是撇开性别歧视不谈,如果真的有提名决定论(即人们倾向于选择符合自己名字的工作或生活方式)呢?如果你的名字对你的生活有影响,那么为一个完整的人选择一个名字是多么大的责任。我不想把这个责任留给品味、机遇或趋势。当然不是——我会转向深度学习。)。

在这篇文章中,我将向您展示我如何使用机器学习来构建一个婴儿名字生成器(或者更准确地说是预测器),它获取(未来)人类的描述并返回一个名字,例如:

我的孩子将在新泽西出生。她将成为谷歌的一名软件开发人员,喜欢骑自行车和喝咖啡。

给定一份简历,该模型将返回一组姓名,按概率排序:

Name: linda Score: 0.04895663261413574
Name: kathleen Score: 0.0423438735306263
Name: suzanne Score: 0.03537878766655922
Name: catherine Score: 0.030525485053658485
...

所以理论上我应该是琳达,但在这一点上,我真的很喜欢戴尔。

如果你想亲自试用这款产品,请看这里。现在你绝对不应该把太多的重量放在这些预测上,因为 a .它们是有偏见的,b .它们就像星座一样科学。但是,让第一个婴儿由人工智能命名不是很酷吗?

数据集

虽然我想创建一个名称生成器,但我最终构建的是一个名称预测器。我想我会找到一堆人的描述(传记),屏蔽掉他们的名字,并建立一个模型来预测这些(屏蔽掉的)名字应该是什么。

幸运的是,我在 Github 的一个名为的维基百科传记数据集中找到了这样的数据集。该数据集包含来自维基百科的 728,321 个传记的第一段,以及各种元数据。

自然,当谈到谁在维基百科上获得传记时,会有一种选择偏见(根据百合,维基百科上只有 15%的传记是女性,我假设非白人也可以这么说)。此外,维基百科上有传记的人的名字会倾向于偏老,因为过去 500 年出生的名人比过去 30 年多得多。

考虑到这一点,并且因为我想让我的名字生成器产生当今流行的名字,我下载了人口普查中最受欢迎的婴儿名字,并减少了我的维基百科数据集,只包括人口普查中流行名字的人。我也只考虑那些我至少有 50 本传记的名字。这给我留下了 764 个名字,大多数是男性。

在我的数据集中,最流行的名字是“约翰”,相当于 10092 个维基百科简历(令人震惊!),接下来是威廉,大卫,詹姆斯,乔治,以及其他圣经中的男性名字。最不受欢迎的名字(我仍然有 50 个例子)是克拉克、洛根、塞德里克和其他一些名字,每个都有 50 个。为了解释这种巨大的偏差,我再次缩减了数据集的采样,为每个名字随机选择了 100 个传记。

训练模型

一旦我有了数据样本,我决定训练一个模型,给定维基百科传记第一段的文本,该模型将预测该传记所涉及的人的名字。

如果你已经有一段时间没有读过维基百科的传记了,他们通常会这样开头:

戴尔·阿尔文·格里布是福克斯动画系列山中之王【2】中的一个虚构人物,由约翰尼·哈德威克斯蒂芬·鲁特比尔配音,演员丹尼尔·斯特恩最初都曾试演过这个角色。他是革命性的【口袋沙】防御机制的创造者,一个灭虫者赏金猎人,Daletech 的拥有者烟鬼枪械狂热者偏执者,几乎所有阴谋论都市传说的信徒。

因为我不希望我的模型能够“欺骗”,所以我用一个空行替换了这个人的名字和姓氏的所有实例:“___”。所以上面的简历变成了:

___ Alvin ___ 是福克斯动画系列中的一个虚构角色……

这是我的模型的输入数据,它对应的输出标签是“Dale”

一旦我准备好我的数据集,我就开始建立一个深度学习语言模型。我有很多不同的方法可以做到这一点(这里有一个例子在 Tensorflow 中),但我选择使用 AutoML 自然语言,这是一种无代码的方式来建立分析文本的深度神经网络。

我将我的数据集上传到 AutoML 中,它自动将其分成 36,497 个训练示例、4,570 个验证示例和 4,570 个测试示例:

尽管我试图删除名和姓,但还是有几个中间名溜了进来!

为了训练一个模型,我导航到“训练”选项卡并点击“开始训练”大约四个小时后,训练结束了。

评估名称生成器

那么名称生成器模型表现如何呢?

如果你以前建立过模型,你会知道评估质量的常用指标通常是精度和召回率(如果你不熟悉这些术语或者需要复习,请查看我的同事 Zack Akil 为了解释它们而制作的这个漂亮的交互式演示演示!).在这种情况下,我的模型的准确率为 65.7%,召回率为 2%。

但是在我们的名称生成器模型的情况下,这些指标并不能真正说明问题。因为数据非常嘈杂——根据一个人的生活故事,他或她的名字应该是什么,并没有“正确的答案”。名字在很大程度上是任意的,这意味着没有模型能够做出真正优秀的预测。

我的目标不是建立一个能 100%准确预测一个人名字的模型。我只是想建立一个模型来理解关于名字和它们如何工作的一些事情。

深入了解模型所学内容的一种方法是查看一个名为混淆矩阵的表格,该表格显示了模型所犯的错误类型。这是调试或进行快速健全检查的有用方法。

在“评估”选项卡中,AutoML 提供了一个混淆矩阵。这是它的一个小角落(因为我在数据集中有太多的名字而被删掉了):

在该表中,行标题为真标签,列标题为预测标签。行表示一个人的名字应该是的名字,列表示模型预测的这个人的名字。

举个例子,看一下标有“ahmad”的第你会看到一个标有“13%”的浅蓝色方框。这意味着,在我们的数据集中,所有名字为 ahmad 的人的简历中,有 13%被模型标记为“Ahmad”。同时,向右看一个框,25%的名字为“ahmad”的人的个人简介被错误地标注为“ahmed”另有 13%名叫艾哈迈德的人被错误地标注为“亚历克”

虽然这些从技术上来说是不正确的标签,但它们告诉我,这位模特可能已经学会了关于命名的一些东西,因为“艾哈迈德”和“艾哈迈德”非常接近叫亚历克的人也一样。该模型有 25%的时间将 alecs 标记为“alexander ”,但在我看来,“Alec”和“alexander”是非常接近的名字。

运行健全性检查

接下来,我决定看看我的模型是否理解关于命名的基本统计规则。例如,如果我将某人描述为“她”,模型会预测女性名字,而不是男性名字“他”吗?

对于“她喜欢吃”这个句子,预测最多的名字是“弗朗西斯”、“多萝西和“尼娜”,接下来是一些其他女性的名字。似乎是个好兆头。

对于“他喜欢吃”这个句子,最热门的名字是“吉尔伯特”、“尤金”和“埃尔默”。所以看起来这个模型理解一些性别的概念。

接下来,我想测试它是否能够理解地理如何影响名字。以下是我测试的一些句子和模型的预测:

“他出生在新泽西”——吉尔伯特

“她出生在新泽西”——弗朗西斯

"他出生在墨西哥。"—阿曼多

“她出生在墨西哥”——艾琳

"他出生在法国。"—吉尔伯特

"她出生在法国。"—伊迪丝

“他出生在日本”——吉尔伯特

“她出生在日本”——弗朗西斯

我对这位模特理解当地流行名字的能力没有什么印象。该模型似乎特别不善于理解亚洲国家流行的名字,在这些情况下往往只返回相同的一小组名字(如 Gilbert、Frances)。这告诉我,我的训练数据集中没有足够的全球多样性。

模型偏差

最后,我想我要测试最后一件事。如果你读过关于模特公平的书,你可能听说过很容易意外地建立一个有偏见的、种族主义的、性别歧视的、年龄歧视的等等。模型,尤其是当您的训练数据集不能反映您要为其构建模型的人群时。我之前提到过谁在维基百科上有传记是有偏差的,所以我已经预料到我的数据集中男性多于女性。

我还预计,这个模型反映了它被训练的数据,会学习性别偏见——计算机程序员是男性,护士是女性。让我们看看我是不是对的:

"他们将成为一名电脑程序员。"—约瑟夫

“他们将成为一名护士。”—弗朗西斯

“他们将成为一名医生。”—艾伯特

"他们将成为宇航员。"—雷蒙德

“他们会成为小说家。”—罗伯特

“他们将为人父母。”—何塞

“他们会成为一个典范。”—贝蒂

嗯,似乎模特在职业方面确实学习了传统的性别角色,唯一的惊喜(至少对我来说)是“父母”被预测有一个男性名字(“何塞”)而不是女性。

所以很明显,这个模型已经了解了一些关于人们命名方式的东西,但并不完全是我所希望的。在为我未来的后代选择名字时,我想我又回到起点了……小戴尔?

  1. 可能没有,这和占星术一样科学。但想想还是很有趣!

使用 Amazon Sagemaker 构建一个可部署的吉拉 Bug 分类引擎

原文:https://towardsdatascience.com/building-a-deployable-jira-bug-classification-engine-using-amazon-sagemaker-827fda8d0460?source=collection_archive---------39-----------------------

循序渐进的方法

菲洛利花园的大门(鸣谢:作者自己的收藏)

作者注:我选择这张图片是因为本文中记录的练习最终会在 AWS 上创建一个 API 网关,用于对构建在 Amazon Sagemaker 工具链之上的吉拉门票进行分类的预测模型。

介绍

在之前的文章中,我记录了我使用 Tensorflow(特别是使用 1D CNN 和嵌入式层)构建吉拉 bug 分类引擎并将其部署为 Docker 容器的步骤。在这篇文章中,我记录了我使用 Amazon Sagemaker 工具链,特别是 BlazingText 内置文本分类算法来做同样事情的步骤。

和上一篇文章一样,这个小项目是作为一门 AICamp 课程的一部分完成的,这次是 AWS 课程中的全栈深度学习。

由于我已经完成了从[1]中找到的开源存储库中提取数据集的初始工作,所以我能够将处理过的 CSV 用于这个项目。

我从事这个项目的个人目标是:

  1. 体验一下在 AWS 的 GPU 实例上运行培训。
  2. 比较之前 1D CNN 方法的结果
  3. 了解如何使用 AWS 工具链部署预测模型。
  4. 体验一下 Sagemaker 的 Baysian 超参数调优工具。

和上一篇文章一样,您可以在 Gitlab 中找到笔记本和数据文件:

https://gitlab.com/foohm71/octopus2

我为这个项目创建了一个名为BlazingText/supervised的独立文件夹(如果你想知道BlazingText文件夹中的word2vec文件夹是什么,这是以后一篇文章的主题)。

什么是 BlazingText?

在我之前的文章中,我提到了使用 DNNs 进行文本分类的几种选择,而word2vec是其中之一。使用带有单词嵌入层的 1D CNN 是那篇文章中探讨的另一种方法。

word2vec

我不打算过多地谈论word2vec,因为我无法对这个话题做出公正的评价,但可以说,word2vec是 DNN 创造单词嵌入的一种方法。

如果你想了解更多关于word2vec的内容,我强烈推荐你看《Word2Vec 解说!YouTube 上的 Python 程序员。本质上,word2vec是一个 DNN,它给定一串文本,将单词映射到一个 N 维向量空间。这背后的想法是,彼此“更接近”的单词“属于”彼此。通常这是基于它们在它被训练的文本串的句子中彼此之间的距离。然后,我们可以使用这种“接近度”来训练分类算法。

BlazingText

BlazingText 是亚马逊对 DNN 的word2vec的实现,它用于创建一个单词嵌入,然后使用另一个带有嵌入的 DNN 在其基础上构建一个文本分类器。为了更好地理解这一点,我强烈推荐观看亚马逊关于这一主题的视频

亚马逊 AWS 和 Sagemaker

我们使用几个 AWS 工具来构建和部署模型,它们是:

  1. S3——见https://AWS . Amazon . com/getting-started/hands-on/backup-files-to-Amazon-S3/
  2. sage maker—https://AWS . Amazon . com/getting-started/hands-on/build-train-deploy-machine-learning-model-sage maker/
  3. lambda—https://AWS . Amazon . com/getting-started/hands-on/run-server less-code/
  4. API 网关—https://docs . AWS . Amazon . com/cloud 9/latest/user-guide/tutorial-lambda . html

作者注:如果你有兴趣学习如何使用 AWS Sagemaker 栈来构建一个可部署的 ML 或 DNN 引擎,我强烈推荐参加简介中提到的 AICamp 课程。特别是如果(a)你有 ML 的经验,但是没有 AWS 的经验,或者(b)你有 AWS 的经验,但是没有那么多 ML 或 DNNs 的经验。这门课程试图在两者之间架起一座桥梁,开始时有很多手把手的练习。对我个人来说,我属于(a)组,我能够接触到 BlazingText,即使它不在课程中。

注意:我在 Google Colab 上运行我的一些笔记本,因为在 Sagemaker notebook instance 上运行它们需要花钱。这是使用 AWS 要注意的一件事——你必须经常检查你的花费,因为你可能会让一些未使用的服务运行,这可能会增加账单。

数据准备

第一步是以 BlazingText 使用的形式准备培训和验证数据。在 BlazingText 文档中,它描述了两种格式:(a)行分隔和(b) JSON。为此,我们将使用(a)。

在这个练习中,我也使用了JIRA_OPEN_DATA_LARGESET_PROCESSED.csv,因为我想用这个结果与前一篇文章中描述的 1D CNN 进行比较。

为了将 csv 转换成 BlazingText 的格式,我使用了在blazingtextdatapretraineval . ipynb中找到的代码(在 gitlab repo 中,在BlazingText/supervised子文件夹中)。这是一个谷歌 Colab 笔记本)

# mapping dictionary to map the priorities to labels
labels = {“Optional”: “__label__1”,
          “Trivial”: “__label__2”,
          “Minor”: “__label__3”,
          “Major”: “__label__4”,
          “Critical”: “__label__5”,
          “Blocker”: “__label__6”}# write lst file function
def write_lst_data_to_file(path, Xdata, Ydata):
   with open(path, ‘wb’) as fp:
   num_rows = Xdata.shape[0]
   for i in range(1,num_rows):
   output = labels[Ydata.iloc[i]] + “ “ + Xdata.iloc[i]
   fp.write(output.encode(“utf-8”))
   fp.write(“\n”.encode(‘utf-8’))

由于数据可以读入熊猫数据帧,我只是使用 scikit-learn 的标准 train-test-split 函数来分割它们(30%测试),然后使用这个函数将它们写入两个文件:jira_largeset_train.lstjira_largeset_test.lst。两个文件都在 gitlab 报告里。

注意:在笔记本blazingtextdatapretraineval . ipynb中,我还包含了一个标签图来显示数据是如何不平衡的。

结果文件如下所示:

__label__3 Form Item’s asterix is not getting placed vertically ... 
__label__4 New beans.xml wizard should warn if the file already ... 
__label__6 focusAlpha not working This bug was imported from ...

接下来,你必须上传这两个文件到一个 S3 桶。

创建基本模型

下一步是建立一个基本模型。有两种方法可以做到这一点:

  1. 使用 Sagemaker 用户界面
  2. 在 Sagemaker Jupyter 实例上使用 Jupyter 笔记本

我们将首先在这里讨论(1),并将在“评估模型”一节中介绍(2)。

第一步是点击 Sagemaker 页面上的“培训工作”

接下来点击“创建培训工作”

给你的工作起个名字。至于 IAM 角色,您必须使用一个现有的角色或者创建一个新的角色来执行 Sagemaker 任务。它应该能接触到你的 S3 水桶。此外,S3 和你的 Sagemaker 实例应该居住在同一个地区,如us-east-1

选择“BlazingText”和“File”输入模式。

选择资源配置。我选择了一个ml.c5.4xlarge和 100Gb 的存储(这可能是大材小用)。

对于超参数,我使用了以下非默认参数:

mode: supervised
epochs: 15
early_stopping: true

对于“输入数据配置”,您需要添加培训和验证渠道的 S3 位置。

您将需要创建另一个名为“validation”的通道,并用测试数据集的 S3 位置填充它。

接下来,您需要配置输出的位置。为输出路径添加有效的 S3 位置。

最后点击“创建培训工作”。这将带您进入“培训工作”主页面。你的工作需要一些时间来运行。

您现在一定想知道如何检查训练和验证的准确性。这需要使用 Cloudwatch。转到培训作业,单击它并导航到“监控”。点击“查看日志”链接,您将能够查看训练运行的日志。

培训完成后,您还可以单击“查看算法指标”链接来检查培训和验证的准确性。

对于我的运行,我得到了 0.69 的训练精度和 0.572 的验证精度,这比 1D CNN 略好。

超参数调谐

Amazon Sagemaker 提供了一个非常直观的 UI 工具,用于为其内置算法执行超参数调优。我在过去使用过 scikit-learn 来构建一个简单的 randomgrid-search 调优,用于基于【2】的随机森林分类器(参见 Octopus2 gitlab repo 中的 ModelAnalysis.ipynb )。这是新的,因为 Sagemaker 工具提供了内置的贝叶斯调整算法,所以我很高兴尝试一下。

第一步是点击 Sagemaker 页面中的“超参数调整作业”

接下来单击“创建超参数调整作业”按钮

接下来给你的工作起个名字,并开启提前停止

为调整策略选择“贝叶斯”

点击“下一步”。然后点击“添加培训工作定义”

给你的培训作业定义一个名称,并填写“算法选项”,就像你在“创建培训作业”ie 中所做的那样。选择 BlazingText 等。接下来在“客观指标”框中选择validation:accuracy(参见下面的截图):

对于“超参数配置”,我遵循了https://docs . AWS . Amazon . com/sagemaker/latest/DG/blazingtext-tuning . html中的指导。需要注意的一点是,如果没有变体,需要将类型设置为“Static”。然后点击“下一步”。

下一页要求您填写培训和验证渠道、检查点和输出 S3 位置。这与“创建基本模型”中的相同。

接下来,在“资源配置”中,我使用了一个 100Gb 的ml.c5.4xlarge,我将每次运行的停止条件设置为最长 30 分钟(应该会少得多)。

对于资源限制,这取决于您配置的支出限制。对我来说,我必须将最大并行培训作业数设置为 8,将最大培训作业数设置为 100。

最后点击“创建超参数调整作业”。

这将启动运行超参数调整过程的整个过程,需要一些时间。完成后,您将看到如下内容:

单击作业,您将看到您的结果:

您还可以通过点击“培训工作”选项卡来检查所有培训工作。

评估模型

正如我在开始时提到的,还有另一种方法来构建模型,那就是使用 Sagemaker notebook 实例。首先,您需要创建一个实例。要做到这一点,请遵循这里的指示。

注意:运行 Sagemaker 笔记本实例需要付费。为了省钱,一定要把它们关掉(不是删除!)不用的时候。您可以随时重新启动它们,所有存储的文件保持不变。

在本节中,我将介绍主 gitlab repo 的BlazingText/supervised文件夹中的blazingtext _ text _ classification _ jira . ipynb笔记本的内容。

这款笔记本由 AWS 提供的示例笔记本改装而成。

第一步是连接数据源和输出位置:

然后为培训作业设置容器

设置培训参数

然后训练!(这当然需要一段时间)

接下来,创建 Sagemaker 端点

注意:如果不使用,请确保删除端点,否则您将为保持其运行而付费。您可以随时通过稍后在笔记本上运行该命令来重新启动它,Sagemaker 知道选择最后一个经过训练的模型。要删除端点,命令在笔记本底部:

下一部分将向您展示如何对模型端点执行预测:

响应是一个带有概率和预测标签的 JSON

模型评估

我喜欢使用 AWS Sagemaker 和 AWS 工具链创建、训练和部署(您将在下一节中看到)模型的便利性,但是我对缺少评估模型的工具感到非常恼火。因此,我不得不从头开始构建这一部分。

我想做的是使用验证数据集,并通过预测算法运行它,创建一个混淆矩阵,并计算标准指标,如精度召回准确度。为此,我必须创建一个零矩阵并填充它

我能够从 https://www.python-course.eu/confusion_matrix.php找到一些计算精度/召回指标的代码,并且能够生成这些指标:

然后我用混淆矩阵用matplotlib创建了一个热图。

接下来,我想看看这个模型在一个完全不同的数据集下是如何支撑的。在 Octopus2 中,我已经创建了JIRA_OPEN_DATA_ZOOKEEPER.csv数据集,所以我使用相同的代码对其进行预测,并计算了指标和混淆矩阵。

注意:看起来像是被零除了,因为数据集没有包括一些标签,所以我选择忽略它们,因为它给了我我正在寻找的信息。该算法在全新数据集上的表现如何。

虽然整体精度不好(低于 50%),但精度还不错。接下来我想检查混淆矩阵:

您将会注意到,它看起来与使用验证数据集的那个非常相似。

肯定还有更多工作可以做,以改善这一模式。好消息是现在有了一个评估任何新模型的机制。

部署模型

本节简要介绍了以下步骤:

  1. 使用在“创建基本模型”或“超参数调整作业”中创建的培训作业,创建一个模型
  2. 使用该模型创建 Sagemaker 端点
  3. 创建 Amazon Lambda 来处理传入的预测请求
  4. 创建 API 网关以公开 HTTP POST API

创建模型和 Sagemaker 端点

首先选择一个训练作业:这可以是第一个训练作业,也可以是超参数调整作业中的一个训练作业。然后在那里,点击“创建模型”按钮。

给模型起个名字,选择合适的 IAM 角色。我使用默认的“容器定义”和“网络”。然后我点击了“创建模型”按钮。

接下来,您将是您创建的模型列表。选择您的新模型,然后单击“创建端点”。

加上一个名字和通常的东西。选择“创建新的端点配置”。单击“创建端点配置”。

然后点击“创建端点”。

注意:即使没有流量,Sagemaker 终端也要花钱。请确保在用完之后删除它们。

创建 Lambda

导航到亚马逊 Lambda。点击“创建功能”。

选择“从头开始创作”。给函数起个名字,选择一个运行时(我用的是 Python 3.6)。点击“创建功能”。

下一页是你构建和测试 Lambda 的地方。在“功能代码”部分,我使用了以下代码:

import json
import os
import boto3ENDPOINT_NAME = os.environ['ENDPOINT_NAME']sgm_runtime = boto3.client('runtime.sagemaker')reverse_label_map = {"__label__1": "Optional",
                     "__label__2": "Trivial",
                     "__label__3": "Minor",
                     "__label__4": "Major",
                     "__label__5": "Critical",
                     "__label__6": "Blocker"}def format_payload(data):
   list = []
   list.append(data)
   payload = {"instances": list}
   return json.dumps(payload)def lambda_handler(event, context):
   data = event['body']
   payload = format_payload(data)
   response = 
      sgm_runtime.invoke_endpoint(EndpointName=ENDPOINT_NAME,  
                                  ContentType='application/json',
                                  Body=payload) prediction = json.loads(response['Body'].read().decode())
   prediction_label = prediction[0]['label'][0]
   mapped_prediction = reverse_label_map[prediction_label] return {
      'statusCode': 200,
      'body': mapped_prediction}

本质上,它得到的有效载荷是这样的

{ "body": "some text to classify"}

并在表单中创建一个有效负载

{ "instances": ["some text to classify"]}

并将其发送到预测引擎。我们已经在前一节“评估模型”中看到了这个表单。一旦获得响应,它就提取响应有效载荷的label部分,并执行从__label__X到实际 bug 优先级的转换。

接下来您需要做的是通过填写“功能代码”部分下面的表单来设置环境变量ENDPOINT_NAME。输入您在上一节中创建的端点名称。

有一个测试工具,您可以在其中传递测试负载来测试 Lambda。我建议你用它来检查它的工作情况。这是不言自明的,网上有相关文档。

创建 API 网关

导航到亚马逊 API 网关。选择以构建 REST API。

填写相同的和通常的东西,然后点击“创建 API”。完成后,按照https://docs . AWS . Amazon . com/API gateway/latest/developer guide/API-gateway-Create-API-as-simple-proxy-for-lambda . html的“创建 Hello World API”一节中的步骤操作。当然,请确保使用您的 Lambda 函数,而不是那里提供的函数。

一旦完成,您将获得您的方法的 API 网关 URL,并且您将能够将您的 API 与有效负载结合起来。

参考

[1]吉拉社会知识库,马可·奥图等著https://github.com/marcoortu/jira-social-repository

[2]Hyperparameter Tuning the Random Forest in Python,Will Koehrsen,2018 年 1 月https://towardsdatascience . com/Hyperparameter-Tuning-the-Random-Forest-in-Python-using-scikit-learn-28 D2 aa 77 DD 74

[3]“word 2 vec 解释!”,Python 程序员(YouTube)https://youtu.be/yFFp9RYpOb0

[4]“亚马逊 SageMaker 内置算法网络研讨会系列:炽热的文字”,亚马逊,https://youtu.be/G2tX0YpNHfc

使用 Google AutoML 构建可部署的吉拉 Bug 分类引擎

原文:https://towardsdatascience.com/building-a-deployable-jira-bug-classification-engine-using-google-automl-a0497ad8c475?source=collection_archive---------53-----------------------

循序渐进的方法

从吉萨看到的金字塔(鸣谢:作者自己的收藏)

作者注:我选择这张图片是因为这个练习的一个要点是 AutoML 在引擎盖下是多么复杂,但谷歌在让事情变得简单方面做得非常好。各种 AutoML 工具与其他 GCP 工具(如云存储、应用引擎等)共存,就像金字塔与吉萨市的其他部分共存一样。

介绍

在本系列的第一篇文章中,我详细介绍了如何使用 Tensorflow 构建一个吉拉 bug 分类引擎。在后续的文章中,我描述了使用 Amazon 的 BlazingText 构建和部署类似引擎的一步一步的方法。在本文中,我详细介绍了使用 Google 的 AutoML 完成同样工作的步骤。

和上一篇文章一样,我将使用[1]中的数据集。

我这样做的个人目标如下:

  1. 感受一下使用 Google 的 AutoML 引擎,尤其是“自然语言”工具集
  2. 对 AutoML 和 BlazingText 之间的分类结果进行比较
  3. 对部署分类引擎的步骤进行比较

和上一篇文章一样,您可以在 Gitlab 中找到笔记本和数据文件:

https://gitlab.com/foohm71/octopus2

我已经创建了一个文件夹AutoML/textClassification来存储这个项目中的文件。

由于构建这个分类引擎的大多数步骤都是通过 UI 完成的,所以我把所有步骤都放在了 Gitlab repo 中的 Google Colab 笔记本GCPAutoMLDataPrepTrainEval.ipynb中。

什么是 AutoML?

我可能不会在这里详细解释什么是 AutoML,所以我会让你看一个视频(见[2])。

一言以蔽之:还记得你用 Scikit-learn 或者 Tensorflow 做机器学习的时候吗?你要做的是尝试几种不同的模型和超参数集。这整个过程可以自动化,这是 AutoML 所做的。

因此,在这种情况下,您需要做的是(类似于 BlazingText),您需要将训练数据集格式化为特定算法类(在这种情况下为文本分类)将接受的格式,然后让 AutoML 完成其余工作。

谷歌云和云自然语言

这个项目使用了几个 GCP(谷歌云平台)工具:

  1. 谷歌云存储
  2. 云自然语言
  3. 谷歌应用引擎

作者注:如果你有兴趣在 GCP 上学习机器学习,我强烈推荐 Coursera 的数据工程,大数据,以及 GCP 专业化在线课程上的机器学习。它是自定进度的,并且有许多免费的实验室。还有一个关于 GCP 基础知识的 YouTube 系列,你可以在这里找到【3】。

GCP 最棒的一点是,当你刚起步时,他们会给你 300 美元的免费服务。因此,如果你只是想尝试一下,这是一个很大的激励。要了解更多信息,请参见 https://cloud.google.com/free 的。

走向云自然语言

对于那些熟悉 GCP 的人来说,这是显而易见的:只需导航到 GCP 控制台,在侧边菜单的“人工智能”下查找“自然语言”。

对于刚到 GCP 的人,您需要:

  1. 在浏览器上访问“http://console . cloud . Google . com”。
  2. 使用服务帐户创建一个新项目(稍后您需要服务帐户来进行预测)参见此处的说明。
  3. 如果你点击侧边菜单,你将能够导航到“人工智能”部分下的“自然语言”。

当你到达“自然语言”时,你会看到:

单击“自动文本和文档分类”部分的“开始”链接。您将看到的页面是“数据集”页面。

数据准备

在我点击“新数据集”链接,选择“多标签分类”后,我花了一段时间才弄清楚格式化训练数据的方式是什么。并尝试导入 CSV 文件。原来系统需要另一种格式的数据。

这是我通过点击工具提示(即那个“?”)选择“从电脑上传 zip 文件”后。这是这样说的:

我决定使用第一种方法。以下是我用来将我的 CSV 转换成这种格式的代码(您也可以在笔记本中找到):

导入数据

下一步是下载 documents.zip 并上传到 AutoML 进行处理。这可能需要一些时间,但好事情是,一旦完成,他们会给你发一封电子邮件。

处理完成后,当您单击“项目”选项卡时,您会看到如下内容:

最棒的是,你可以点击“查看标签统计”来查看标签的分布等,你也可以查看数据。我个人非常喜欢这个工具。

培养

要开始培训,只需点击“培训”选项卡,然后点击“开始培训”。这将需要几个小时来运行,因为它正在搜索最佳算法和超参数。任务完成后,您会收到一封电子邮件。

评估模型培训

培训完成后,您会看到类似这样的内容:

点击“查看完整评估”,您会看到如下内容:

您可以选择左侧的每个标签来查看精度和召回指标。我非常喜欢的一点是,它们实际上会列出真阳性、假阴性和假阳性,供您进行某种分析。

部署模型

这再直接不过了。单击“测试和使用”选项卡,然后单击“部署模型”。

作者注:完成后一定要删除模型,因为如果你继续运行它,你会被收费。

测试模型

一旦模型展开,你可以带着你的模型兜一圈(双关语)。有很多方法可以做到这一点,云自然语言提供了一些方法。

第一种方法是输入一些文本,让模型预测:

下面提供了下一个锅炉板代码(sh 和 python)。你可以在你自己的机器上做或者打开一个谷歌云外壳。

将模型公开为 API

为此我使用了谷歌应用引擎。这是相当直接的。

创建 AppEngine 应用程序

首先导航到谷歌控制台上的应用引擎。然后寻找快速入门指南。在“标准环境演练”中选择 Python,并按照步骤在 Cloud Shell 中克隆样本代码。

在“appengine”文件夹下,您会看到以下 4 个文件:

  1. app.yaml
  2. main.py
  3. requirements.txt
  4. 测试. sh

接下来,我使用测试 Python 代码将其与示例 AppEngine 代码合并:

需要注意一些事情:

  • 型号名称将因您而异
  • 服务帐户信用也将不同

您可以通过运行以下命令在本地(或在 google cloud shell 上)对此进行测试:

  • python3 main.py
  • sh test.sh

您应该会看到这样的内容:

{
  "prediction": "Major",
  "score": 0.7177224159240723,
  "statusCode": 200
}

部署应用程序

首先你需要创建应用程序(我在谷歌云壳上做了这个):

gcloud app create

接下来部署应用程序:

gcloud app deploy app.yaml \
    --project <project id>

测试部署

部署应用程序后,您将在屏幕上看到应用程序引擎应用程序 URL。然后你可以使用curl来测试它:

curl -X POST -H "Content-Type: application/json" 
  -d '{"title": "TestSizeBasedThrottler fails occasionally",       
       "description": "Every now and then TestSizeBasedThrottler fails reaching the test internal timeouts.I think the timeouts (200ms) are too short for the Jenkins machines.On my (reasonably fast) machine I get timeout reliably when I set the timeout to 50ms, and occasionally at 100ms."}' 
   "https://octopus-282815.uc.r.appspot.com/predict"

评估模型

本练习的目标之一是评估 AutoML 生成的模型与前一篇文章中的 BlazingText 相比如何。因为我已经为 BlazingText 创建了测试数据集,所以我只需要再次使用它。

使用测试数据集

以下是我使用的代码

输出:

这接近 BlazingText 的结果。

使用另一个数据集

正如在 BlazingText 文章中一样,我也使用了Zookeeper数据集来评估模型。

这是我得到的:

(nan 是由于被零除,因为一些标签不存在于该数据集中)

这也类似于使用 BlazingText 获得的结果。

结论

总的来说,这是我使用 GCP 的 AutoML 自然语言分类器后的印象。

  1. 该算法的性能与 BlazingText 相似。
  2. 起初,关于如何格式化训练数据的文档有点难以找到。
  3. 我真的很喜欢摄取后数据的呈现方式,因为它给了我一些分析数据的方法,而无需编写任何代码。
  4. 我真的很喜欢训练后评估模型的工具,尤其是显示真阳性、假阳性等的表格
  5. 使用 App Engine 构建一个无服务器的 API 接口相当容易。对于 BlazingText,我使用的是 AICamp 课程提供的基本模板。
  6. 我真的很喜欢这个事实,有云壳做 CLI 的东西。对于 BlazingText,我不得不使用 Sagemaker 的 Jupyter 笔记本中的一个 shell 来完成一些工作。

参考

[1]吉拉社会知识库,马可·奥图等著https://github.com/marcoortu/jira-social-repository

[2]针对 Keras 和 TensorFlow (14.1)、杰夫·希顿、https://youtu.be/TFUysIR5AB0的自动机器学习(AutoML)

[3]欢迎来到谷歌云平台:https://youtu.be/4D3X6Xl5c_Y、谷歌云平台、GCP 精要

使用 Python 构建数字时钟

原文:https://towardsdatascience.com/building-a-digital-clock-using-python-349b691c5cd7?source=collection_archive---------9-----------------------

如何使用 Tkinter 包创建简单的 python 应用程序

照片由像素皮克斯拜拍摄

在这篇文章中,我将向你展示如何使用 python 来构建和设计你的数字时钟窗口。这是一个简单的 Tkinter 入门项目,Tkinter 是 Python 自带的一个内置包。Tkinter 基本上是一个图形用户界面包。它有很好的特性,可以用来创建简单的应用程序。今天我们将用它来创造我们的数字时钟。

建造你自己的数字钟的最大好处是你可以随心所欲地定制它。从文本字体到背景颜色,所有的功能都可以定制。如果你准备好了,让我们开始吧!

目录

  • 巨蟒
  • 导入库
  • 设计应用程序窗口
  • 数字钟功能
  • 运行应用

计算机编程语言

Python 是一种通用编程语言,在分析数据方面越来越受欢迎。Python 还能让您快速工作,更有效地集成系统。世界各地的公司都在利用 Python 从他们的数据中收集知识。官方 Python 页面如果你想了解更多

导入库

在这个项目中,我们将使用两个库。而且这两个都是 Python 自带的,也就是说我们不用安装。这种类型的库被称为 Python 内置包。

我们将使用的主要软件包是 Tkinter。你可以从官方文档页面这里了解更多关于 Tkinter 的信息。

因此对于这一步,我们需要做的就是将它们导入到我们的程序中:

from tkinter import Label, Tk 
import time

设计应用程序窗口

在这一步,我们将首先使用 Tkinter 包定义窗口面板。之后,我们将定义我们想要用于数字时钟的文本设计。

定义窗口

如前所述,我们将使用 Tkinter 包。Tkinter 可以定义为 Tk。并且定义好之后,我们会对其进行定制。

app_window = Tk() 
app_window.title("My Digital Time") 
app_window.geometry("350x150") 
app_window.resizable(0,0)

理解代码:

  • 定义 Tkinter 函数。
  • 给我们的应用程序窗口添加一个标题。
  • 定义我们的视频的大小,例如在我的例子中,它是 350 像素宽到 150 像素高。
  • 该窗口不可调整大小,因为文本值不是响应式设计。我们不希望我们的设计在窗口大小改变时看起来很奇怪。

完美,我们的申请窗口准备好了!现在,让我们开始设计时钟。

标签设计

程序中最酷的一步是这个。因为你可以把自己的喜好放进设计里。这一步会让你的作品与众不同。如果你热爱设计,是时候展示你的技能了。

我们将定制四个元素:

  • 数字的字体。
  • 我们的数字时钟的背景颜色。
  • 数字的颜色,确保它不是你背景的颜色。😉
  • 文本的边框宽度。

以下是我在设计中使用的价值观:

text_font= ("Boulder", 68, 'bold')
background = "#f2e750"
foreground= "#363529"
border_width = 25

对于颜色,可以随意使用 RGB 值或十六进制值。在我的例子中,我使用了颜色的十六进制值。我使用谷歌浏览器上的颜色选择器。在谷歌搜索上搜索“拾色器”就可以了。你会看到的。

现在,让我们结合元素并定义我们的标签。标签函数是将显示我们的时间的文本。

label = Label(app_window, font=text_font, bg=background, fg=foreground, bd=border_width) label.grid(row=0, column=1)

如果你想了解更多关于标签函数的属性,这里的是我找到的一个不错的页面。

数字时钟功能

如果我们正在做一个应用程序项目,函数是让事情运转的最好方法。函数也很棒,因为它们使程序更加结构化,更容易理解。好吧,让我们定义我们的数字钟功能:

def digital_clock(): 
   time_live = time.strftime("%H:%M:%S")
   label.config(text=time_live) 
   label.after(200, digital_clock)

理解代码:

  • 在第一行中,我们使用时间包获得了实时性。我们也在定义我们想要的格式。由于我们正在设计一个数字时钟,“小时,分钟,秒”将是一个很好的格式。
  • 在第二行中,我们只是将实时分配给标签方法。这样,数字时间将被更新。
  • 最后,我们再次调用该函数,以便数字时钟显示实时时间。这样每隔 200 毫秒时间就会更新一次。在编程中,这被称为递归循环。在函数内部调用同一个函数。感觉像是创意,是不是很酷?

运行应用程序

太好了!你做到了这一步,这是我们申请项目的最后一步。如你所知,除非你调用它们,否则函数不会运行。为了触发应用程序,我们将调用函数。让我们运行应用程序:

digital_clock()
app_window.mainloop()

结果

python digital_clock.py

作者照片

干得好!您已经只用 python 创建了一个简单的数字时钟应用程序。Python 是一种非常强大的语言,我们可以用 python 创造无限的东西。这是关于思考一个想法,并使其工作。希望你喜欢读我的文章。从事像这样的动手编程项目是提高编码技能的最好方式。

我很高兴你今天学到了新东西。如果您在执行代码时有任何问题,请随时联系我。😊

关注我的博客youtube 频道,保持灵感。谢谢你,

更多 Python 文章:

[## 用 Python 构建人脸识别器

使用 OpenCv 库进行实时人脸识别的分步指南

towardsdatascience.com](/building-a-face-recognizer-in-python-7fd6630c6340) [## 使用 Python 构建电影推荐器

使用 scikit-learn 的简单实用的机器学习项目

towardsdatascience.com](/building-a-movie-recommender-using-python-277959b07dae)

构建灾难响应网络应用程序

原文:https://towardsdatascience.com/building-a-disaster-response-web-application-4066e6f90072?source=collection_archive---------50-----------------------

在现实生活中使用机器学习模型来对抗灾难

当前问题

2019 年全球共发生 409 起自然灾害。具有讽刺意味的是,由于 Covid19,我们现在正处于全球疫情的中心。在灾难期间或灾难发生后,数百万人直接或通过社交媒体进行交流,以获得政府或救灾和恢复服务的帮助。如果受影响的人在推特上发布消息,甚至向帮助热线服务发送消息,那么该消息很可能会在收到的数千条消息中丢失。有时,这是因为很多人只是在发微博,很少有人需要帮助,组织没有足够的时间来手动过滤掉这么多信息。

因此,在这个项目中,我们将构建一个灾难响应 web 应用程序,该应用程序将消息分类为不同的类别,如医疗用品、食物或阻塞道路,并将它们发送到正确的组织以提供快速恢复!

图片来源

数据概述

我们将分析灾难事件中发送的真实信息。数据由数字 8收集,由 Udacity 提供,非常感谢他们。我们来看数据描述:

  1. messages.csv: 包含 id、发送的消息和类型,即方法(直接,推文..)消息已发送。
  2. categories.csv: 包含 id 和类别(相关、报价、医疗援助..)该消息属于。

ETL 管道

因此,在这一部分中,我们将在公共 id 列上合并两个数据集, messages.csv 和 categories.csv 。id categories.csv 中的类别列是字符串格式,因此我们需要为每个类别创建列。然后,我们将删除重复项,并将转换后的数据加载到使用 SQLAlchemy 库托管的数据库中。

类别的形式如下:

类别. csv

转型后:

最后,我们将转换后的数据加载到数据库: disaster.db

签出整个 ETL 管道这里

engine = create_engine('sqlite:///disaster.db')
df.to_sql('disaster_response', engine, index=**False**)

ML 管道

这里,我们将从 disaster.db 数据库加载数据集。我们的主要任务是将消息转换成令牌,以便它们可以被解释。因此,我们创建了一个函数,它将删除标点符号,标记单词,删除停用单词,并执行词汇化

url_regex = 'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'**def** tokenize(text):
    *# Detect URLs*
    detected_urls = re.findall(url_regex, text)
    **for** url **in** detected_urls:
        text = text.replace(url, 'urlplaceholder')

    *# Normalize and tokenize and remove punctuation*
    tokens = nltk.word_tokenize(re.sub(r"[^a-zA-Z0-9]", " ", text.lower()))

    *# Remove stopwords*
    tokens = [t **for** t **in** tokens **if** t **not** **in** stopwords.words('english')] *# Lemmatize*
    lemmatizer=WordNetLemmatizer()
    tokens = [lemmatizer.lemmatize(t) **for** t **in** tokens]

    **return** tokens

这就是我们的函数要做的:

输出

这些词是有意义的,但是它们不能被 ML 模型理解。因此,我们将使用计数矢量器tfidf 转换器将令牌转换为特征(整数),并使用简单的随机森林分类器来拟合训练数据。

pipeline = Pipeline([
    ('vect', CountVectorizer(tokenizer = tokenize))
    , ('tfidf', TfidfTransformer())
    , ('clf', MultiOutputClassifier(RandomForestClassifier()))])pipeline.fit(X_train, Y_train)

为了评估我们的模型,我们将使用 F-1 评分,因为假阴性和假阳性对我们来说都很重要,也就是说,如果我们无法预测正确的邮件类别,那么我们就无法提供正确的帮助,如果我们错误地预测了邮件的类别,那么我们就是在浪费时间。

随机森林分类器给我们的 F-1 分数为 0.44。得分低的主要原因是类别高度不平衡。这些类别的分布如下:

分配

让我们使用一些不同的 ML 模型和超参数调整来改进模型。因此,在进行 GridSearchCV 以找到随机森林模型的最佳参数后,我们能够将 F-1 分数增加到 0.51。接下来,我们训练 AdaBoost 分类器,我们能够将 F-1 分数提高到 0.59

*#https://medium.com/swlh/the-hyperparameter-cheat-sheet-770f1fed32ff*
pipeline_ada = Pipeline([
    ('vect', CountVectorizer(tokenizer=tokenize)),
    ('tfidf', TfidfTransformer()),
    ('clf', MultiOutputClassifier(
        AdaBoostClassifier(base_estimator=DecisionTreeClassifier(max_depth=1, class_weight='balanced'))
    ))
])parameters_ada = {
    'clf__estimator__learning_rate': [0.1, 0.3],
    'clf__estimator__n_estimators': [100, 200]
}cv_ada = GridSearchCV(estimator=pipeline_ada, param_grid=parameters_ada, cv=3, scoring='f1_weighted', verbose=3)

我们将这个模型保存为 pickle 文件,这样我们就不需要再次训练它。代码可用此处

pickle.dump(cv_ada, open('disaster_ada_model.sav', 'wb'))

烧瓶应用

我们将创建一个train _ classifier . py来创建转换、加载、构建和保存模型的函数。基本上,我们将使用 ETL 管道和 ML 管道。我们将创建一个名为 app 的文件夹,其中包含一个 master.html 文件,该文件将作为前端,run.py 将在后端运行以执行计算。代码可以在这里这里找到。以下是演示:https://Twitter . com/harshdarji _ 23/status/1256761506949222407?s=20

结论

构建一个全栈多输出的 ML web 应用,将灾害发生时发送的消息进行不同的分类,提供不同救灾组织的快速援助。您可以按照此处的说明在自己的电脑上运行该应用程序。

感谢您的阅读!

为后锁定时代构建距离违例检测器(D.V.D)

原文:https://towardsdatascience.com/building-a-distance-violation-detector-d-v-d-for-a-post-lockdown-era-5b9894f5a6b1?source=collection_archive---------29-----------------------

人工智能驱动的解决物理距离“问题”的方法

随着各国开始有放松封锁规范的想法,最终外出的人之间保持 5 英尺或以上的物理距离可能在阻止新冠肺炎传播方面发挥关键作用。

我第一次接触到这个想法是在加利福尼亚州旧金山的一家计算机软件公司。该程序通过闭路电视监控录像实时监控和跟踪人群,寻找相互之间距离小于 5-6 英尺的人群。在这些团体上画一个红框,以告知监督当局。

一个人不断监控安全摄像头以识别红色块的违规行为听起来可能像是浪费宝贵的人力资源。因此,我在程序中集成了一个邮件功能,一旦发现违规行为,它会立即通知当局。违规的定义可根据地方当局设定的标准来设定,这些标准可能从两人一起步行到超过 20 人的聚会不等。下面是代码和解释。已经在 Google Collab 上用 GPU 运行时编译过了。

import time
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from google.colab.patches import cv2_imshow
from google.colab import drive
import pandas as pd
import cv2
import math
import numpy as np
drive.mount(“/GD”)

我决定使用一个非常简单的分类器,即哈尔级联分类器,用于全身检测,这是由(Paul Viola,2001)开发的预训练分类器。如果你想了解更多关于这个分类器上的检测模块的信息,你可以在这里阅读。这可以在 OpenCV 库中找到。最近的发展已经产生了更好和更快的分类器,比如更快的 R-CNN 和 YOLO,我将尝试在未来的版本中使用它们来改进这个模型。

person_clf = cv2.CascadeClassifier(‘/GD/MyDrive/dataset/haarcascade_fullbody.xml')
# Initiate video capture for video file
cap = cv2.VideoCapture(‘/GD/My Drive/dataset/mall_walking.avi’)
writer = None
OUTPUT=’/GD/My Drive/dataset/output_’+str(YOUROUTPUTFILENAMEHERE)

这里,分类器的一个实例已经加载到 person_clf 中,并且已经设置了带有违规标记的已分析视频的输出目录。 cv2。VideoCapture 用于加载我们的测试视频,是 cv2 对象的一个预构建的可调用函数。

def center(c):
  x_start=d[‘box’+str(c)+’x’]
  y_start=d[‘box’+str(c)+’y’]
  x_end=d[‘box’+str(c)+’x+w’]
  y_end=d[‘box’+str(c)+’y+h’]
  Point=int((x_start+x_end)/2), int((y_start+y_end)/2)
  return Point
def mailer(pic,mail):
  path=”/GD/My Drive/dataset/”+pic
  from = “[YOURMAILHERE]”
  to = "[TARGETMAILHERE]"
  message = MIMEMultipart()
  message[‘From’] = from
  message[‘To’] = to
  message[‘Subject’] = “Violation notification”
  body = “Dear user, pfa for instances of violation of social    distancing”
  msg.attach(MIMEText(body, ‘plain’))
  filename = pic
  attachment = open(path, “rb”)
  p = MIMEBase(‘application’, ‘octet-stream’)
  p.set_payload((attachment).read())
  # encode into base64
  encoders.encode_base64(p)
  p.add_header(‘Content-Disposition’, “attachment; filename= %s” %  filename)
  msg.attach(p)
  s = smtplib.SMTP(‘smtp.gmail.com’, 587)
  s.starttls()
  s.login(from, “YOURPASSWORDHERE”)
  text = msg.as_string()
  s.sendmail(from, to, text)
  s.quit()

在做类似的工作时,为你的项目构建函数是帮助迁移学习的好方法。因此,我在这里创建了两个基本函数,一个用于查找两点之间的中心,另一个用于向目标发送带有附件的邮件。我将在下面详细解释中心函数。mailer 函数获取 pic 的名称,该名称存储在我的 Google drive 中,具有违例时刻,并将它附加到带有消息正文的邮件中,并发送给目标。我发现这篇文章这里真的信息量很大,我用它来结合这一点。

现在转到主函数。为了理解主代码,我们必须首先理解不同类型的循环运行的层次结构以及它们所做的工作。

代码解释

i=1
contn_frame_with_detection=0
skipped_frames=0
while cap.isOpened(): 

我们调用存储输入视频的 cap 实例并打开它,这样我们就可以一次处理一帧。这是我们的第一个 while 循环,因此所有的代码都在里面。我们还启动了 3 个计数器。“I”保持正在处理的帧的计数,“contn_frame_with_detection”保持已经检测到违规的连续帧的数量,“skipped_frames”保持没有发现违规的检测帧之间的帧的计数。跳过帧的概念将在后面讨论。

frame_violator=0
l=[]
d={}
person_id=0
ret,frame = cap.read()
if not ret:
  break

这里,另一个计数器‘frame _ violator’被启动,以计数在每个帧中检测到违规的次数。如果他们只需要检测大型集会而忽略 2、3 个人一起行走,一些管理机构可能喜欢将它保持为高。预期在第一帧中检测到第一个人,person_id 被设置为 1。‘cap . read()’帮助我们读取帧并存储以供进一步处理。它还被指示在帧结束时中断。

frame = cv2.resize(frame, None,fx=0.95, fy=0.95, interpolation = cv2.INTER_LANCZOS4)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
persons = person_clf.detectMultiScale(gray, 1.02, 5)

我们首先需要用 cv2.resize()将帧的大小调整到 60%左右,这样计算就可以实时进行,而不会影响速度。如果你有比谷歌 Collab Gpu 更快的处理器,你可以让它更高。cv2。INTER_LANCZOS4 通常被认为是最好的插值方法,但是根据图像的上采样或下采样,也可以使用其他方法,如 INTER_LINEAR、INTER_AREA。COLOR_BGR2GRAY 方法用于将具有 3 个通道的 BGR 图像(OpenCV 就是这样读取图像的)转换为只有 1 个通道的灰度图像。可以看出,在使卷积层均匀的同时,灰度级的计算要低得多,并且不会丢失太多信息,因此更易于机器处理。因此,我们使用 cv2 的 detectMutiScale 方法从灰度图像中检测给定帧中的人。需要注意的是,这返回了一个矩形对角线的起点和终点坐标,在这个矩形中可以找到被检测的人。我们将这些坐标存储在 persons 变量中,以便以后逐个循环。

for (x,y,w,h) in persons:
  d[‘box’+str(person_id)+’x’]=x
  d[‘box’+str(person_id)+’y’]=y
  d[‘box’+str(person_id)+’x+w’]=x+w
  d[‘box’+str(person_id)+’y+h’]=y+h
  l.append(center(int(person_id)))
  if person_id>0:
    s=0
    feed_detected=0
    for mid in l[:-1]:
      dist = math.sqrt((mid[0] — center(int(person_id))    [0])**2 + (mid[1] — center(int(person_id))[1])**2)
      if dist<=40:
        cv2.rectangle(frame, (d[‘box’+str(s)+’x’], d[‘box’+str(s)+’y’]), (d[‘box’+str(s)+’x+w’], d[‘box’+str(s)+’y+h’]), (0, 0,255), 2)
        cv2.line(frame,(int(mid[0]),int(mid[1])),(center(int(person_id))[0],center(int(person_id))[1]),(0,0,255),(2))
        feed_detected+=1
        frame_violator+=1
        s+=1
     if feed_detected>0:
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
   person_id+=1

上面的代码构成了这个算法的逻辑核心。我们首先开始逐个循环每个人(对于循环 A) ,并将矩形的坐标存储在 python 字典中,以格式['box-person_id-x']: value 命名。然后我们调用我们的中心函数找到这个人的质心,并存储在一个列表中。函数 center 接收要计算质心的 person_id,从起点和终点的字典中检索他的数据,并计算中心坐标。现在,根据我们的层级,第二个循环被初始化(对于循环 B) 当帧中的 person_id 大于 0 时,(实际上意味着多于两个人),其与每个先前检测到的人的质心的距离通过简单的欧几里德距离公式来计算。如果检测到违规,feed_detector 加 1,表示输入的 feed 有违规,在检测到的违规周围画一个红框,用 cv2.rectangle 保持颜色尺寸为(0,0,255 ),表示红色用于 cv2 使用的 BGR 格式。

if frame_violator>0 and skipped_frames<4:
  contn_frame_with_detection+=1
  skipped_frames=0
else:
  skipped_frames+=1
if skipped_frames>=4:
  contn_frame_with_detection=0
  skipped_frames=0i+=1

引入了一个跳过帧计数器来解决我们模型的假阴性。在两个检测到的违规帧之间将有许多帧,其中 HAAR 分类器可能甚至不能检测到所有人。这将导致错误地将帧识别为无违规。因此,当我们看到检测到违规的连续帧的数量时,我们还必须看到跳过的帧是否保持在某个数量以下。如果 skipped_frame 大于 5,这可能意味着先前发生违规的帧实际上可能只是误报,因此我们应该再次将 continuous_frame_counter 设置为 0,并将 skipped_frames 设置为 0,重新开始计数。

if contn_frame_with_detection>25:
  contn_frame_with_detection=0
  skipped_frames=0
  name=”pic”+str(i)+”.jpg”
  cv2.imwrite(‘/GD/My Drive/dataset/’+name,frame)
  mailer(name)

为了加强检测为真阳性,我们仅考虑当 continuous_frame_counter 超过 25 (或更高,取决于用户的需要)时的重大距离违规。

收到的自动邮件的屏幕截图

此时,我们通过调用 cv2.imwrite 函数拍摄一张图片,并调用我们预定义的邮件函数来提供 jpg 图片的名称。因此,该邮件功能立即向目标用户发送邮件,向他更新情况。

if writer is None:
   vid_write= cv2.VideoWriter_fourcc(*”XVID”)
   writer = cv2.VideoWriter(OUTPUT, vid_write, 35,(frame.shape[1],    frame.shape[0]), True)
writer.write(frame)

最后,我们让成为 cv2 的一个实例。用 XviD 格式保存我们的视频文件,一次一帧

#this will outside main while loop
writer.release()
cap.release()
cv2.destroyAllWindows()

到达帧的末尾后,我们释放 writer,cap,并通过 cv2.destroyAllWindows()销毁的所有窗口,这样计算机就不会崩溃。下面是该程序的输出示例

样本输出

好的,一天之内要理解的循环相当多。我试图从零开始构建每一个功能,并通过逻辑实现整个事情,因此这些复杂的循环。我将会在网上发布如何使用 Azure ml 的 EC2 实例来部署它。我希望你喜欢程序背后的直觉,并且能够欣赏用于构建它的各种计数器和循环。任何人有任何想法,也许添加一些功能到这个程序或使它运行得更快,肯定可以联系我。在那之前,万岁和数据科学。

来源

科尔德威,D. (2020 年 4 月)。https://TechCrunch . com/activity-monitoring-startup-Zen sors-re purposes-its-tech-to-help-coronavirus-response。 检索自 Techcrunch:https://Techcrunch . com/2020/04/02/activity-monitoring-startup-Zen sors-re purposes-its-tech-to-help-coronavirus-response/

琼斯,P. V. (2001 年)。 opencv 。从 Github 检索:https://Github . com/opencv/opencv/tree/master/data/Haar cascades

保罗·维奥拉,法学博士(2001 年)。使用简单特征的增强级联的快速对象检测。www.cs.cmu.edu。

用 Databricks 和 Azure 数据工厂构建动态数据管道

原文:https://towardsdatascience.com/building-a-dynamic-data-pipeline-with-databricks-and-azure-data-factory-5460ce423df5?source=collection_archive---------10-----------------------

利用 Databricks 和 Azure Data Factory 使您的数据管道更加动态

TL;DR 一些简单有用的技术,可以应用在数据工厂和数据块中,使您的数据管道在可重用性方面更加动态。传递参数、嵌入笔记本、在单个作业集群上运行笔记本。

坦纳·博瑞克在 Unsplash 上拍摄的照片

-简单骨架数据管道

-执行时传递管道参数

-嵌入笔记本

-将数据工厂参数传递给 Databricks 笔记本

-在一个作业集群上运行多个临时作业

第一步:简单骨架数据管道

该段将在基础管线的高层次分解

图 1 — ETL 外壳文件检查器(外部管道)

主要思想是构建一个 shell 管道,在其中我们可以将变量的任何实例参数化。在本例中,我们将使用 get 元数据返回文件夹列表,然后使用 foreach 遍历文件夹并检查任何 csv 文件(。csv),然后将变量设置为真。然后if*在具有 Databricks 组件的 true activities 内部条件为真以执行笔记本。

执行时传递管道参数

不用说,完成一个管道来确保尽可能多的值是参数化的。这是为了在运行时或被触发时将值传递给管道。减少尽可能多的硬编码值将减少在将 shell 管道用于相关的其他工作时所需的更改数量。

传递管道参数容器 ClusterID

嵌入笔记本

出于可维护性的原因,将可重复使用的功能保存在单独的笔记本中,并在需要的地方嵌入运行它们。一个简单的例子:具有修剪任何额外空白的所有列的功能。

儿童笔记本(包含功能)

def trim_all_columns(x):
    """
    Trim white space from ends of each value across all series in   dataframe
    """
    trim_strings = lambda x: x.strip() if type(x) is str else x
    return x.applymap(trim_strings)

父笔记本(调用功能)

%run /[Users/..U](mailto:Users/a2270226-msp01@ey.net)sername../ParentFunctionsdf = trim_all_columns(data)

将数据工厂参数传递给 Databricks 笔记本

可以在数据块中选择高并发集群,或者只使用作业集群分配来选择临时作业。创建连接后,下一步是工作流中的组件。下面我们来看看如何利用高并发集群。

图 1 —数据块 ADF 管道组件设置

如图 1 所示,在这里调整基本参数设置将允许 Databricks 笔记本能够检索这些值。这是通过使用 getArgument("BlobStore ")函数实现的。这些参数可以从父管道传递。这使得它特别有用,因为可以使用触发器来调度它们的传递。

创建到 Blob 存储的连接的一个关键部分是 azure-storage 库。这将允许我们创建到 blob 的连接,因此必须将该库添加到集群中。

下一部分将假设您已经在 databricks CLI 中为 blob 存储创建了一个秘密范围。在这里,您可以为 blob 存储存储 SAS URIs。如果您需要进行数据隔离,并隔离对帐户中各个容器的访问,这可能特别有用。

from azure.storage.blob import (BlockBlobService,ContainerPermissions)
import pandas as pdfrom importlib import reload
import sys, re, iotrigger = getArgument("DepartmentName")
scope = "" # Insert Secret scope name heredbutils.secrets.list(scope=scope)
keyC = trigger+"-home"Secrets = dbutils.secrets.get(scope = scope ,key = keyC)
storage_account_name = getArgument("BlobStore")
container_name = trigger+"-home-exp"blobService = BlockBlobService(account_name=storage_account_name, account_key=None, sas_token=Secrets[1:])generator = blobService.list_blobs(container_name)
for blob in generator:
  print(blob.name)
blobs = [b for b in generator]

上面是一个使用 Databricks 笔记本连接到 blob 存储的示例。半信半疑地说,有其他有记载的方法可以连接 Scala 或 pyspark 并将数据加载到 spark 数据帧而不是 pandas 数据帧。

在创建用于连接的代码块并将数据加载到数据帧中之后。现在,您可以在将数据输出到容器之前执行任何数据操作或清理。

最后一步是清理活动的处理容器,并将新文件发送到它自己的 blob 容器中,或者与其他整理过的数据一起发送。

在一个作业集群上运行所有临时作业

在处理较小的工作(不是很大的数据任务)时,为了提高效率,在单个工作集群上动态运行笔记本电脑。如果出于任何特殊原因,您选择不使用作业池或高并发集群,则使用此选项。

这里的想法是,您可以将变量或管道参数传递给这些值。为了演示这个例子的简单性,我将它们硬编码。其中 name***data structure _ * n ****定义了数据块中 4 个不同笔记本的名称。

ADF 中的数据块组件

如果发现从名为 exists 的数据工厂传递的参数,下面来自 Databricks 笔记本的代码将运行列表 nbl 中的笔记本。这方面的一个用例可能是,您有 4 种不同的数据转换要应用于不同的数据集,并且更喜欢将它们隔离起来。

嵌入式笔记本

nbl = ['dataStructure_1', 'dataStructure_2', 
       'dataStructure_3', 'dataStructure_4']arg1 = "exists"
exitParam =[]def argCheck(list: nbl):
    return [getArgument(i) for i in nbl]
var_s = argCheck(nbl)def notebookExe(list: nbl):
  for x,y in zip(nbl,var_s):
    try:
      if y == arg1:
        output = dbutils.notebook.run("/..NotebookLocation/JobA/"+ x, 60,
                             {"key": x})
        print(x,y)
        print(output)
        exitParam.append(output)
      else:
        pass
    except:
      pass
notebookExe(nbl)
dbutils.notebook.exit(exitParam)

希望你能从中获得一些有用的信息,或者给我一些建议。请不要客气。

构建动态天气下载应用程序

原文:https://towardsdatascience.com/building-a-dynamic-weather-download-app-1ce64a6c3e61?source=collection_archive---------54-----------------------

使用 Python、Dash 和 AWS 简化加拿大历史天气数据

照片由维达尔·诺德里-马西森Unsplash 拍摄

本文描述了我用来构建动态仪表板 web 应用程序的框架,该应用程序用于下载和可视化历史加拿大天气数据…快!!!

【WeatherHistoryCanda.com】查看 App:

获取代码: GitHub Repo

动机

加拿大有 8000 多个活跃和不活跃的政府气象站,它们都有开源数据。然而,下载数据并不容易。

目前,通过由加拿大环境和气候变化部(ECCC)维护的一个政府运营的门户网站可以访问和下载加拿大的历史天气数据。虽然 ECCC 提供了优秀的开源数据服务,但下载门户还有待改进。该门户没有地图来直观地搜索和显示气象站的位置,下载仅限于一小部分数据,并且下载后无法绘制数据图表。

目标

构建仪表板 web 应用程序,动态搜索、过滤和下载加拿大历史天气数据。

几个要求:

  • 基于过滤标准显示气象站的交互式地图
  • 任何时间范围内气象站数据的单个文件下载(即不再有多文件下载)
  • 快速下载气象站数据(即分钟级)
  • 气象站数据的交互式图形
  • 便宜的💰

步骤 1:应用程序框架

最初,我制定了一个松散的概念,即我希望如何构建应用程序,例如使用哪个微服务框架,经过一些尝试和错误后,我确定了如下所示的架构。这是一个由前端进程、后台进程和数据库存储组成的标准结构。

web 应用程序框架概述

Dash 应用

对于小型仪表板应用,微服务是必由之路。它加速了开发,并且易于部署。我选择使用 Python 微服务框架 Plotly Dash 来构建我的应用程序。Dash 是一个非常棒的工具,尤其是对于不熟悉 JavaScript 的人来说,因为它允许您用纯 Python 构建复杂的交互式仪表板!

*##  BASIC MULTI-PAGE DASH APP FRAMEWORK- app.py    # Flask server
- index.py  # browser caching and page routing
- tasks.py  # background job in Celery
- Procfile  # Heroku commands on start-up
- /pages
    | -- __init__.py    
    | -- homepage.py
    | -- graphpage.py
    | -- about.py
- /assets
    | -- CSS and JS*

后台作业

我的应用程序的要点是允许用户下载历史天气数据。由于下载任务需要几秒到几分钟的时间来执行,因此无法在前端高效运行(即,这会引入延迟,并阻止应用程序快速响应传入的请求)。更好的解决方案是将长时间运行的任务作为后台作业执行,并将结果反馈给前端。

为此,我使用了 Celery,一个异步任务队列,以及 CloudAMQPs RabbitMQ 消息代理和 Heroku Redis 结果存储。关于如何建立一个异步任务队列有很多很棒很详细的教程(也就是 Miguel Grinberg 的博客),所以我在这里就不赘述了。相反,我提供了芹菜后台作业架构的概要。

  • 消息代理:客户端发送一个请求来执行一个长时间运行的任务。消息代理(即 RabbitMQ)接收请求,并将其放入消息队列,Celery worker 在该队列中卸载并运行任务。
  • 这些是运行后台作业的进程,比如下载历史天气数据。在 Celery 中,您可以同时运行多个工作线程来处理多个请求。
  • 结果存储:用于存储任务结果的数据库(即 Heroku Redis)。在我的例子中,我用它来存储气象站元数据,比如位置、海拔和站 ID。

我强烈建议不要同时使用 Heroku Redis 作为结果存储和消息队列。我一开始尝试了这种方法,并不断达到允许的最大并发连接数。通过将消息队列分配给 RabbitMQ,将结果存储分配给 Heroku Redis,可以获得更多的并发连接。

数据库存储

最初,我的应用程序的结构是直接从 ECCC 服务器(第三方)下载数据。这被证明是缓慢的并且不是非常健壮的。相反,我把所有的 ECCC 数据(大约 37 Gb)下载到一个 AWS S3 桶中。我通过使用 AWS Lambda 和 SQS 消息队列运行多个批量下载作业来实现这一点。一旦我有了 S3 桶中的数据,我就使用 AWS Lambda 和 CloudWatch 事件来更新每天午夜的活动气象站数据。结果是一个灵活的数据库,不依赖于 ECCC 服务器。

将数据存放在 S3 存储桶中的最大好处是,可以在应用中使用 S3 选择(即简单的 SQL 表达式)直接从 S3 的 CSV 文件中查询数据。我曾考虑过使用传统的 SQL 数据库,如 MySQL,但在我的用例中,S3 更便宜,而且非常适合持久存储。💪

赫罗库

我选择使用 Heroku 云服务来部署我的应用程序。除了非常容易部署之外,我没有什么理由在 DigitalOcean、Linode 或 EC2 上使用 Heroku 这样的云服务。Heroku 应用程序运行在 dyno(虚拟 Linux 容器)上,有两种类型,一种是处理 web 进程(即 HTTP 流量)的 web dyno,另一种是处理后台作业(即芹菜任务)的 worker dyno。我最终在 Heroku 免费层用一个免费网站和 worker dyno 部署了这个应用程序。

对于我的用例,Heroku 有一些缺点:

  • Heroku dynos 有一个短暂的文件系统。这意味着应用程序保存到磁盘的文件(即下载)最终会丢失,web 和 worker dynos 可能看不到相同的文件。如果一个文件被工人保存到磁盘,web dyno 可能找不到它。
  • Heroku 可能很贵。例如,Heroku Redis 插件在免费层有 25mb 的内存,不足以让我的应用程序存储完整的芹菜任务结果,下一层是 15 美元/月。

最后,通过使用 AWS S3 进行数据库存储,很容易就可以解决这两个问题。

步骤 3:构建仪表板过滤器功能

我想要一个简单的界面,在交互式地图上显示气象站,这样用户就可以根据气象站的位置和数据可用性等直观地过滤气象站。Dash 库包括易于实现的高级组件,如图表、下拉框和输入框。Dash 应用程序的结构是应用程序布局,由 HTML 和 Dash 核心组件组成,后面是创建链式交互的应用程序回调。

交互式地图过滤

背景地图来自 Mapbox API,气象站元数据(如气象站位置)在应用程序启动时从 S3 自动气象站加载。Dash 中的回调很容易实现,包括输入组件(即省或站名)和输出组件(即地图图形)。

Dash 应用回调示例

步骤 4:构建仪表板下载功能

单击地图上的气象站后,用户可以查看表格中的气象站元数据,并选择所需的气象站来下载数据。然后,用户可以设置下载间隔(即在站点记录数据的频率)和下载日期。完成后,会显示一条消息,让用户知道他们将要下载的内容。该消息还会激活“生成数据”按钮。

交互式气象站选择和下载

当点击“生成数据”按钮时,一个任务被发送到 RabbitMQ 消息队列,芹菜工人在那里接收它。芹菜任务使用选定的表格数据(即,站名、省等。)、下载日期和数据间隔,以查询 S3 相关 CSV 的子集。在 Celery 执行任务的同时,前端使用 task.id 查询 task.state(即待定、进度、成功或失败)。这每 250 毫秒发生一次,并更新进度微调器的可见性。

如果我没有使用 Heroku,我可以将查询的数据保存到磁盘,或者如果我的数据较小,我可以在浏览器中缓存。相反,我将查询到的 S3 数据推回到 S3 的一个临时文件夹中。在前端,创建一个指向临时数据的 S3 预签名 URL,并使用 Flask routing 链接到“下载数据”按钮。当用户点击“下载数据”按钮时,它重定向到临时数据并在浏览器中下载文件。

即使我的下载结构稍慢且效率较低(例如,多个 S3 GET 和 PUSH 命令),预签名 URL 的出色之处在于,客户端直接从 S3 下载,避免了将数据保存到服务器或缓存在浏览器中。

S3 预签名 URL 的 Flask 路由示例

步骤 5:构建仪表板图形功能

在我看来,能够近实时地可视化下载的数据对用户来说是最重要的功能,因为它允许他们在现场进行探索性的数据分析。

我选择使用 Dash graph 组件呈现三个基本图形来传达不同的数据统计(即季节性趋势的箱线图和数据分布的直方图),以呈现数字。即使是大型数据集(> 500000 个数据点),折线图和直方图的渲染速度也相对较快,但箱形图可能会比较慢。为了保持几秒钟的渲染时间,我使用了箱线图的数据子样本。这是通过 Pandas DataFrame.sample 函数完成的,并保持分布与原始分布相同。

下载数据的交互式绘图

如上所述,因为我使用 Heroku,保存到磁盘不是一个选项,而且由于数据集可能超过 50mb,使用 Heroku Redis 来存储 Celery 任务结果是不切实际的(例如,在空闲层上只有 25mb 的内存)。此外,在 Dash 回调和 Dash 页面之间共享数据可能很棘手。标准解决方案是使用 dcc。存储组件(即在浏览器存储中),但这只适用于小于几兆字节的数据。

经过一些测试,我发现最大化成本和速度的解决方案是使用 S3 选择在 S3 和图形中查询数据。这样做的最大缺点是图形的加载时间较长(即从云数据库查询数据,而不是在本地检索),并且需要在每次图形渲染时查询 S3。

步骤 6:部署应用程序

Dash(即 Flask)应用程序本身一次只能处理一个 HTTP 请求,因此要处理多个请求,应该使用 Gunicorn WSGI web 服务器将 Dash 部署到 Heroku。Gunicorn web 服务器允许您同时运行应用程序。Heroku 对 Gunicorn 工作进程的配置有几个建议,比如在一个空闲层上将 Gunicorn 工作进程的数量限制在 2-3 个。

正确设置 Procfile、RabbitMQ、Heroku Redis 和 Celery 配置是相当具有挑战性的。CloudAMQP 推荐使用 Celery 时 RabbitMQ 消息队列的配置。使用 CloudAMQP 自由层时最重要的方面是降低“后台”消息速率(即配置 Celery worker 在没有流言蜚语、混杂和心跳的情况下运行)。

Heroku Procfile 示例

芹菜配置示例

第七步:监控成本

如果你的业余爱好应用花费你一大笔钱,你将无法支撑很久!我的应用程序目前每月花费约 1-2 美元,但这将随着规模的扩大而改变。

  • Heroku Dyno :自由层!
  • CloudAMQP RabbitMQ: 自由层!
  • Heroku Redis: 自由层!
  • AWS S3:~ $ 1–2/月(取决于获取/推送命令的数量)

后续步骤

在未来版本的应用程序中,我想添加和更改一些内容。

  • 迁移到 DigitalOcean 或其他 IaaS 云服务。这将允许我将数据保存到磁盘,或者在 Redis 缓存方面有更大的灵活性,并防止我的应用程序每次下载都需要 GET 和 PUSH 请求。
  • 加速绘图。这可以通过仅缓存数据以生成初始图表或在浏览器中存储数据子集来实现。

总的来说,这是一个非常有趣的项目,我学到了很多关于全栈开发的知识!

用 Python 构建人脸识别器

原文:https://towardsdatascience.com/building-a-face-recognizer-in-python-7fd6630c6340?source=collection_archive---------1-----------------------

使用 OpenCv 库进行实时人脸识别的分步指南

克里斯托弗·坎贝尔Unsplash 上拍照

在这篇文章中,我将向你展示如何使用 Python 来构建你自己的人脸识别器。构建一个检测和识别人脸的程序是一个非常有趣和好玩的计算机视觉入门项目。在以前的帖子中,我展示了如何识别文本以及如何检测图像中的人脸,这些都是在计算机视觉中练习 python 的伟大项目。今天,我们将做一些更高级的事情,那就是人脸识别。

从名字就可以理解,我们将编写一个程序,它将识别图像中的人脸。我说的“程序”,你可以理解为教一台机器做什么,怎么做。我喜欢用教学来代替编程,因为那实际上是我们将要做的。最好的学习方式是教学,所以在教机器如何识别人脸的同时,我们也在学习。在我们开始这个项目之前,我想分享一下人脸检测和人脸识别之间的区别。这是值得知道的事情。

目录:

  • 人脸检测 vs 人脸识别
  • 入门
  • 图书馆
  • 训练图像
  • 人脸识别
  • 测试识别器

人脸检测与人脸识别

这两件事听起来可能非常相似,但实际上,它们并不相同。让我们明白其中的区别,这样才不会漏掉重点。

人脸检测就是从无关紧要的图像或视频中检测人脸的过程。这个程序除了寻找人脸之外什么也不做。但是另一方面,人脸识别,这个程序可以找到人脸,还可以分辨出哪张脸属于谁。所以它比仅仅检测它们更能提供信息。

要编写一个识别人脸的代码需要一些训练数据,我们应该训练我们的机器,让它知道这些人脸以及他们是谁。在这个项目中,我们是教授我们程序的人。在机器学习中,有两种类型的学习;有人监督和无人监督。我将不会进入细节,在这个项目中,我们将使用监督学习。这里有一个关于机器学习方法的不错的帖子

比较示例

克里斯托弗·坎贝尔Unsplash 上拍照

入门指南

我们将为这个项目使用两个主要模块,他们被称为人脸识别和 OpenCV。OpenCV 是一个高度优化的库,专注于实时应用。

OpenCV(开源计算机视觉库)是一个开源的计算机视觉和机器学习软件库。OpenCV 旨在为计算机视觉应用提供一个公共基础设施,并加速机器感知在商业产品中的应用。作为一个 BSD 许可的产品,OpenCV 使得企业利用和修改代码变得很容易。

来源:https://opencv.org

[## 分步指南-用 Python 构建预测模型

使用长短期记忆预测模型的动手练习

towardsdatascience.com](/step-by-step-guide-building-a-prediction-model-in-python-ac441e8b9e8b)

图书馆

我们必须安装一些库,这样我们的程序才能运行。下面是我们将要安装的库的列表:cmake,face_recognition,numpy,opencv-python。Cmake 是一个必备的库,所以面部识别库安装不会给我们一个错误。

我们可以使用 PIP 库管理器在一行中安装它们:

pip install cmake face_recognition numpy opencv-python

安装完成后,让我们将它们导入到代码编辑器中。其中一些库包含在 Python 中,这就是为什么我们可以在不安装它们的情况下导入它们。

import face_recognition
import cv2
import numpy as np
import os
import glob

太好了!现在我们进入下一步,我们将导入图像并使用它们来训练我们的程序。

训练图像

首先,让我们找到我们的图像。

导入图像

我下载了一些名人的照片,并把它们添加到一个名为“面孔”的新文件夹中。同样为了获得当前目录,换句话说,你的程序的位置,我们可以使用一个叫做“getcwd()”的操作系统方法。

faces_encodings = []
faces_names = []cur_direc = os.getcwd()path = os.path.join(cur_direc, 'data/faces/')list_of_files = [f for f in glob.glob(path+'*.jpg')]number_files = len(list_of_files)names = list_of_files.copy()

理解上面的行:

  • 所有的照片都在一个名为“面孔”的文件夹里。
  • 图像文件名必须是图像中人物的名字。(如:bill-gates.jpg)。
  • 文件名被列出并分配给“names”变量。
  • 文件类型必须相同。在这个练习中,我使用了“jpg”格式。

这是我的文件夹截图

让我们进入下一步。

训练面部表情

for i in range(number_files):
    globals()['image_{}'.format(i)] = face_recognition.load_image_file(list_of_files[i])
    globals()['image_encoding_{}'.format(i)] = face_recognition.face_encodings(globals()['image_{}'.format(i)])[0]
    faces_encodings.append(globals()['image_encoding_{}'.format(i)])# Create array of known names
    names[i] = names[i].replace(cur_direc, "")  
    faces_names.append(names[i])

为了让你有所了解,这里是我的“名字”列表的样子。

姓名列表

太好了!这些图像是经过训练的。在接下来的步骤中,我们将使用设备的网络摄像头来查看我们的代码如何执行。

人脸识别

在这一步中,我们有很长的代码行。如果你仔细阅读,你会很容易理解每一行发生了什么。让我们定义需要的变量。

face_locations = []
face_encodings = []
face_names = []
process_this_frame = True

人脸识别代码来了。(如果您复制下面的代码,您可能需要重新格式化间距,我建议您通过查看代码来从头开始编写,并尝试理解)

video_capture = cv2.VideoCapture(0)while True:
    ret, frame = video_capture.read() small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25) rgb_small_frame = small_frame[:, :, ::-1] if process_this_frame:
        face_locations = face_recognition.face_locations( rgb_small_frame)
        face_encodings = face_recognition.face_encodings( rgb_small_frame, face_locations) face_names = []
        for face_encoding in face_encodings:
            matches = face_recognition.compare_faces (faces_encodings, face_encoding)
            name = "Unknown" face_distances = face_recognition.face_distance( faces_encodings, face_encoding)
            best_match_index = np.argmin(face_distances)
            if matches[best_match_index]:
                name = faces_names[best_match_index] face_names.append(name)process_this_frame = not process_this_frame# Display the results
    for (top, right, bottom, left), name in zip(face_locations, face_names):
        top *= 4
        right *= 4
        bottom *= 4
        left *= 4# Draw a rectangle around the face
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)# Input text label with a name below the face
        cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)# Display the resulting image
    cv2.imshow('Video', frame)# Hit 'q' on the keyboard to quit!
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

测试识别器

在第一张图中,我使用的图像与训练数据中使用的图像完全相同。

人脸识别测试 1

现在,我将尝试使用泰勒·斯威夫特的不同图像。效果非常好!

面部识别测试 2

恭喜你。!您已经创建了一个程序,可以检测并识别图像中的人脸。现在,你已经知道如何在实际项目中使用计算机视觉了。希望你喜欢阅读这个循序渐进的指南。如果你今天学到了新东西,我会很高兴。从事像这样的动手编程项目是提高编码技能的最好方式。

如果您在执行代码时有任何问题,请随时联系我

我是 贝希克居文 ,喜欢分享编程、教育、生活方面的故事。 订阅 我的内容待启发 走向数据科学 待启发。谢谢你,

更多机器学习项目

[## 使用 Python 渲染视频文本

使用 moviePy 库的动手机器学习项目

towardsdatascience.com](/rendering-text-on-video-using-python-1c006519c0aa) [## 使用 Python 从视频中提取语音

使用 Google 语音识别 API 的简单实用项目

towardsdatascience.com](/extracting-speech-from-video-using-python-f0ec7e312d38)

建立食物推荐系统

原文:https://towardsdatascience.com/building-a-food-recommendation-system-90788f78691a?source=collection_archive---------0-----------------------

机器学习通过营养预防和治疗癌症

任何影响个人健康的因素,如体育锻炼、睡眠、营养、遗传和污染。营养是我们生活中最大的可变因素之一,微小的变化也会产生巨大的影响。随着可供选择的食物数量呈指数增长,不可能再把它们都考虑进去了。考虑用户偏好、最大化食品中健康化合物的数量并最小化不健康化合物的唯一方法是使用(3D)推荐系统。

这个项目的目标是使用最大的公开可用食谱数据集合(Recipe1M+)来构建一个食材和食谱推荐系统。训练、评估和测试一个模型,该模型能够从多种配料中预测菜肴。根据预测的菜肴,估计负面配方-药物相互作用的概率。最后,构建一个 web 应用程序,作为构建 3D 推荐系统的一个步骤。

从 GitHub 下载 web 应用并在本地执行。

介绍

已知有许多因素会影响一个人的健康。体育锻炼、睡眠、营养、遗传、污染以及其他外部因素[1]。营养是我们生活中最大的可改变因素之一,所以小的改变会导致重大的结果也就不足为奇了。

由于我们的饮食与文化有着紧密的联系,我们有可能在世界范围内找到大量的美食。每一种中最常见的成分都与该地区的特征密切相关,例如气候。这对当地食谱中每种成分的可用性有很大的影响[3]。

众所周知,一些分子对健康有积极的影响,即抗癌。能够确定哪些成分含有较高的浓度,可能有助于我们治疗和预防疾病[4]。此外,通过在美味和负担得起的膳食中加入这些成分,它可以促进人们营养习惯的转变。在一个快餐消费不断增长的世界里,很明显,除了前面两点,准备的速度也是一个重要因素。

随着越来越多的数据在网上公布,无论是来自研究还是网络应用,这是一个分析这些数据并创建新的食物推荐系统的机会,这些系统不仅考虑了抗癌特性等因素,还考虑了味道、营养成分以及与药物的负面相互作用。这将使用户在购买或准备下一餐时做出更好的决定[5]。

癌症

二十一世纪疾病(图 1)。癌症属于更广泛的肿瘤,是细胞分裂不受控制的一种亚型,有可能扩散到不同的组织。相反,良性肿瘤局限于某个器官。随着寿命的增加,衰老和一些调节途径的功能丧失之间存在密切的相关性,疾病的发病率也呈同样的趋势[6]。

众所周知,营养可以在预防和治疗这种疾病中发挥重要作用[4]。这样,它将有利于最大限度地增加食物中抗癌化合物的数量,并减少已知的与抗癌药物发生负面作用的化合物。

图 12016 年全球主要死亡原因。癌症排在第二位。改编自[7]。

自然语言处理

尽管在线数据集和 API(应用程序编程接口)包含易于检索的结构化信息,但大多数在线资源并不具有这种有组织的结构。因此,需要不仅能够提取数据,而且能够获得其上下文的算法[8]。这一部分集中在单词嵌入和主题建模。

有几种方法可以实现单词的矢量表示。一种可能是将它们全部对齐,并将每一个表示为 0 的向量,数字 1 位于对齐的相应位置。那么,向量空间的维数将等于词汇表的大小。虽然这种方法对于小词汇表是可行的,但是计算效率不高。或者,有一种不同的单词嵌入机制,该机制通过考虑单词在句子中的上下文,允许使用低维向量来表示大型词汇表。

Word2Vec 由谷歌的 Tomas Mikolov 领导的研究团队开发,是一个浅层的两层神经网络特定类别的模型,可以产生单词嵌入[9]。它将文本语料库作为输入,并跨越一个向量空间,其中每个单词都被映射到一个向量。更经常出现在相似上下文中的单词被映射到由更短的欧几里德距离分隔的向量中。

Word2Vec 并不是主题建模的唯一工具。 Doc2VecFastText 分别能够对整个文档进行编码或者专门查看每个单词的形态结构【10】。

Word2Vec 被选择来编码这个项目中使用的数据集中的成分,作为向量。这使得从食谱的上下文中捕捉它们的相似性成为可能。

逆向烹饪算法

这种食谱检索算法是由脸书人工智能研究所开发的,它能够直接从图像中预测配料、烹饪说明和食谱标题[11]。

过去,算法一直使用简单的配方检索系统,该系统基于某些嵌入空间中的图像相似性。这种方法高度依赖于学习嵌入的质量、数据集大小和可变性。因此,当输入图像和静态数据集不匹配时,这些方法就会失败[11]。

反向烹饪算法不是直接从图像中检索食谱,而是提出了一个流水线,其中有一个中间步骤,首先获得配料集。这使得指令的生成不仅考虑了图像,还考虑了成分(图 2) [11]。

图 2 使用多个编码器和解码器的反向烹饪食谱生成模型,生成烹饪指令[11]。

这种方法的主要成就之一是在试图从图像中预测成分时,呈现出比基线配方检索系统[12]和普通人[11]更高的准确性。

本项目开发的美食推荐系统中包含了反向烹饪算法。基于 web 应用程序中的预测成分,向用户提供若干建议,例如:不同的成分组合。

降维

一般来说,降维的目的是从高维向量中保留尽可能多的信息。主成分分析(PCA) [13]和 T-分布随机相邻实体(T-SNE) [14]是两种最常用的方法。第一种通常被定义为用数学方法解决问题,第二种是用统计方法。

PCA 的主要目的在于保留数据中具有较高可变性的矢量分量,同时丢弃增加较少信息的分量。这种分解可以通过两种不同的方式实现。一种是通过分解数据协方差矩阵的特征值。第二种方法是在通常将初始数据标准化后,对数据矩阵进行单值分解[13]。

另一方面,T-SNE 将点之间的相似性转换成联合概率。并且最小化低维嵌入和高维数据上的这些概率之间的 Kullback-Leibler 散度。这种方法具有非凸的成本函数,因此,不同的初始化可能产生不同的降维向量[14]。

能够可视化高维数据是至关重要的,尤其是在对执行聚类感兴趣的情况下。根据应用,社区发现算法可以输入不同的阈值参数,这些阈值参数影响集群的大小和连通性。能够可视化数据如何分布允许在选择这些值时使用人类推理。

其快速的执行和可靠的结果,使 PCA 成为首选。

社区发现

有许多优化不同成本函数的聚类算法。

Louvain 算法反复分割网络,优化模块化[15]。它的值与同一集群内节点间的连接数成比例,当集群间的连接数开始增加时,该值会减少。数学上,模块化被定义为:

Aij 是表示连接节点 ij 的边的权重的邻接矩阵条目, ki = ∑j Aij 是节点 ici 是其所属的社区, 𝛿(u,v) 如果 u = v 则为 1,否则为 0。 m = 1/2∑ij Aij* 是图中所有边的权重之和【15】。

在迭代步骤之间,要优化的值是它的变化,这使得计算更有效[15]:

虽然需要为每个试验社区计算 ki,in∑tot ,但是 ki/2m 是特定于正在被分析的节点的。这样,后一个表达式只有在优化模块性时考虑不同节点时才重新计算[15]。

Infomap 算法试图通过减少在网络内部确定的集群之间随机传播的假想流来减少网络的描述长度[16]。数学上可以表示为:

q = ∑(m)(j=1) qj 每个社区的退出概率之和, H(Q) 社区间移动的平均码长, p(i)(o)= qi + ∑(m)(β∈i) pβ 在一个社区中随机行走的停留概率 cH(Pm)a 的平均码长

第三种方法也被广泛使用,称为谱聚类[17]。与前两者相比,它有几个优点。最重要的是,在检测高度非凸的聚类时,或者当聚类的中心和扩散的度量不是预测社区的合适描述时,它显示出更高的准确性。此外,与其他两种方法相反,它的 Python 实现允许用户输入数据中出现的所需集群的数量。这是沿着项目执行集群的第一选择。

数据可视化

Python 中有几个工具可用于数据可视化。即 Matplotlib [18]、Plotly [19]、Seaborn [20]和 Pandas [21]。有些被认为在表示大量数据时更有效,而其他的则以非常通用和允许用户以多种方式轻松可视化数据而闻名。其他的则与现有的数据容器集成在一起,最终促进了它的可视化。与最新的数据分析和可视化平台(如 Jupyter Notebook 或 JupyterLab)兼容也是一个重要的标准。

Matplotlib 允许生成各种类别,例如:散点图、误差图、条形图、功率谱、直方图等。尽管它们是静态的,当散点图中的节点数量超过数万时,就不再能够代表它们[18]。

Plotly 不同于 Matplotlib,它允许数据点及其标签的动态表示。当点的数量超过数万个时,它也能更好地伸缩[19]。

Seaborn 是一个构建在 Matplotlib 之上的 Python 库。在表示大量数据点方面,它与后者一样强大,并允许用户以更简单的方式探索新的可视化选项[20]。

由于之前强调的要点和与 JupyterLab 完全兼容的事实(在 Plotly 的情况下,在安装相应的扩展之后),这 3 个模块在项目中一起使用。

食物推荐系统

虽然吃是一种基本需求,但有时人们不知道选择什么。事实上,当购买食品或在线订购时,选项的数量太大,无法将它们全部考虑在内。

人类有不同的营养需求,并以不同的方式感受味道。出于这个原因,满足他们需求的唯一选择是通过了解这个人。无论推荐对象是单纯的饥饿用户、烹饪爱好者、关心健康的人、节食者还是希望改善自己健康状况的人,这都会影响最终的选择[5]。

此外,被推荐的产品也有重要的影响:简单的配料替代、食谱、饭菜、餐馆甚至是一道菜。推荐的时机:实时或简讯。并且它可以考虑用户的位置并建议最近的地方。提出建议的平台。根据推荐的生成方式(协作过滤、基于内容、图形聚类或嵌入),它们可能需要设备提供不同的功能。这样,它们可以在网站、应用程序或纯文本(SMS)中共享。过敏或不耐受化合物(如坚果和牛奶)的存在,品牌,烹饪所需的时间,课程,烹饪,动物衍生物的存在,菜肴类型,配料,成本,配料数量,准备时间,味道或烹饪所需的技术[5]。

构建这些系统时的一个重要因素是数据的来源。它可以来自过去的订单,用户对某个帖子的反应(喜欢或不喜欢),社区的评级,观看的图像或视频,或其他社交网络相关的行为,包括帖子,分享,搜索,评论或追随者[5]。

食品推荐系统的成功(图 3)与其考虑用户偏好、最大化食品中健康化合物的数量和最小化不健康化合物的能力相关。

在这个项目中,探索了基于公开可用数据生成食物推荐的不同方法。大型食谱数据集(Recipe1M+和 Kaggle 和 Nature (K&N))包含关于现有配料、标题、源统一资源定位器(URL)和烹饪的信息,经过解析后可提供最精确的建议。

图 3 一个食物推荐系统的例子[5]。

目标

这个项目的目的是建立一个食材和食谱推荐系统。这包括预处理 Recipe1M+数据集以进行成分检索。优化配料的词汇,使之与食谱中的相匹配。训练 Word2Vec 模型,使其能够将配料和配方转换为数字向量。将 2D 空间中的配料可视化,并将其用作配料推荐系统。训练、评估和测试支持向量分类器(SVC)模型,该模型能够通过考虑菜谱的配料集来预测菜谱所属的菜系。基于预测的烹饪,预测负面配方-药物相互作用的概率。为了鉴别菜肴,每份食谱中抗癌分子的平均数量较高。最后,创建一个 web 应用程序,该应用程序能够从图像中预测成分,建议新的组合,并检索食谱所属的菜肴,以及与抗肿瘤药物的预期负面相互作用次数的分数。

文章大纲

在介绍中,讨论了癌症、自然语言处理、逆向烹饪算法、降维、社区发现、数据可视化和在线食物推荐系统背后的基本概念。方法详述了项目的目标,并介绍了用于解决这些目标的工具。在结果中,介绍并讨论了项目的成果。最后,在结论中,回顾了项目的目标,讨论了目标是否实现,提出了主要的困难和对未来工作的建议。

方法

简介涵盖了广泛的理论概念,尤其是项目中使用的工具。在方法上,将描述如何根据要实现的目标调整和应用这些方法。在项目的每一步中使用的最重要的 Python 和 JavaScript 包也包括在内。

首先,Recipe1M+和 K&N 数据集,以及成分的词汇表,根据它们的结构和对项目的价值进行描述。它还包括他们提交的优化过程。

将成分嵌入向量空间、减少其维数和聚类的过程根据所采用的工具和考虑到先前数据集的特征而执行的参数调整来详细描述。

接下来,考虑到参数和函数的选择,并考虑到训练集的维度,解释了预测每个食谱配料集的烹饪的分类器。

然后,描述了根据抗癌分子的数量和预测的负面配方-药物相互作用的数量对配方和烹饪进行分类的方法。

指定了每个地块使用的数据可视化工具。

最后,介绍了一个 web 应用程序,该应用程序从菜谱图像中检索配料,并使用了本项目开发的许多食物推荐系统,并详细介绍了它的实现。

Recipe1M+数据集

Recipe1M+数据集是最大的公开配方数据集[22]。每个配方包含的信息被分成两个 JavaScript 对象符号(JSON)文件。

第一个用 ID 标识每个配方,并定义成分、说明、标题、URL 和它所属的集合:训练、验证或测试集合。这三组用于训练、验证和测试反向烹饪算法。第二个文件包括第一个文件的配方 id 和一组指向配方被废弃的网站的图片的 URL。一些网址不再活跃。虽然使用 Wayback 机器(【archive.org/web】)也可以访问和可视化菜谱。

除了这个数据集之外,还有两个 pickle 文件,其中包含配料词汇表和食谱说明。

构建食物推荐系统的一个必要步骤是从 Recipe1M+数据集中的食谱文本中提取配料。为了实现这一点,它优化了现有成分的词汇,其中所有的停用词和标点符号都被删除,其余的词被词条化。

一旦 Recipe1M+数据集从公开网站上抓取,包含来自访问者的食谱,预计会出现错误信息、错别字、非拉丁字符等。例如,有人证实,有些食谱中的配料或说明是空的,或者完全是由数字或标点符号组成的。所有这些情况都得到了纠正。在开始从数据集中的词汇中搜索成分之前,所有的停用词都被删除,剩下的被词条化。

Kaggle 和自然数据集

这个数据集包含几个标有它们所属菜系的菜谱(github . com/altos AAR/food 2 vec/blob/master/dat/ka ggle _ and _ nature . CSV)。它被用来训练监督学习模型,该模型能够从一系列配料中预测菜肴。使用上一节中描述的词汇确定的相同成分。

它的结构是一个逗号分隔的文件,每行包含一个不同的配方。第一个值是菜谱的菜系。剩下的都是令牌化的成分。因此,不需要使用任何词汇来检索它们。

为了尽可能地使该数据集中的配料名称与 Recipe1M+中的一致,所有配料名称都进行了词条化,并删除了停用词。

食品包埋

为了构建一个配料和食谱推荐系统,最基本的是将它们表示为向量。这将允许用数学方法计算它们的上下文相似性。

使用 Recipe1M+和 K&N 数据集训练 Word2Vec 模型。在 Recipe1M+和 K&N 数据集的情况下,按照 Recipe1M+数据集和 K&N 数据集的说明分别检索每个配方中的成分。Word2Vec 工具可以在 python 库 Gensim 中免费获得。

训练 Word2Vec 模型的关键点之一是捕捉单词的周围环境。考虑到这一点,确保每个食谱中的配料顺序遵循一定的标准是非常重要的。否则,模型会将排序不同的相同成分解释为具有不同的上下文。为此,配料按字母顺序排列。作为模型输入而引入的语料库是来自 2 个数据集的食谱中存在的一组配料。

需要适当调整的超参数是尺寸工人窗口sg最小计数尺寸指的是代表配料的每个向量所考虑的维数(100)。该值的选择是基于所获得的配料嵌入(配料推荐)的质量以及从烹饪方法到烹饪一节中介绍的配料集中检索烹饪的模型的准确性。工作人员的数量被设置为等于模型被训练的核心的数量(8)——MacBook Pro 15’2016 年末。这大大加快了培训过程。窗口指的是与被编码的单词的最大距离,该单词被认为是周围环境的一部分。为了计算该值,确定了 Recipe1M+和 K & N 中配料数量最高的配方。在 K & N 数据集中找到 66 个元素的配方后,窗口被设置为 65。最后,由于模型的目标是从相邻单词中预测目标向量,因此选择连续单词包。这意味着, sg 被作为 1 引入。考虑的最后一个参数是最小计数。为了获得每种配料的矢量表示,即使较少表示, min_count 被设置为 1。

在获得成分的向量之后,它们在 2D 图中被可视化。使用下一节介绍的工具降低维度后,这是可能的。

降维

为了将 Word2Vec 创建的成分嵌入的维数从 100 减少到 2,使用了 PCA。在 scikit-learn 中,在分解包中,有几个模块可以减少向量维数。其中一个是 PCA ,用于允许 Recipe1M+数据集中所有成分的可视化。

聚类成分

为了根据相似性对 Recipe1M+数据集中的成分进行聚类,将谱聚类应用于用 Word2Vec 创建的成分嵌入和用 PCA 降维。同样,它使用了 scikit-learn ,但是是一个不同的包。 cluster 包含了很多能够在数据中发现社区的函数,但是使用的是 SpectralClustering

该功能为用户提供了输入所需聚类数的可能性。选择的数量与[3] — 9 中确定的成分类别的数量相同。它们是主菜、小吃、饮料、汤/炖菜、面包、沙拉、开胃菜、配菜和甜点。

烹饪食谱

一个 SVC 模型被训练来根据它们的配料预测食谱的烹饪。

选择 K&N 数据集来训练模型是因为它的大小,包含每个食谱和各自菜肴的成分列表。然而,不可能向 SVC 提供一组字符串来执行训练。在对所有成分的矢量表示进行平均后,每个配方都被转换成一个矢量。之前介绍的 Word2Vec 模型是用来自 Recipe1M+和 K&N 数据集的数据训练的,因此,第二个数据集中每种成分的矢量表示已经可用。

为了训练支持向量机(SVM)模型,使用了来自 scikit-learn 的 SVM 软件包。它需要选择一个函数,还需要根据训练数据集调整几个参数。

由于大量的功能(100 个)、配方和模型训练的计算限制(MacBook Pro 15 ' 2016 年末),它使用了线性内核来减少训练时间。使用的函数是 LinearSVC

需要调整函数的几个参数。发现 K&N 是一个不平衡的数据集。数据集中某些类别(菜系)的规模有时相差两个数量级。由于这个原因, class_weight 被设置为平衡。这意味着每个类的权重与它们的元素数量成反比。接下来,为了保证训练收敛,将最大迭代次数( max_iter )从标准值 1000 增加到 5000。此外,每当数据集包含的元素数量比每个特征配方的元素数量多时,建议设置算法来解决对偶优化问题。这是通过将参数设置为假来实现的。有一些参数(例如:正则化)不能从数据集的特征中直接推断出来。因此,使用 model_selection 包(也属于 scikit-learn )中的 GridSearchCV 函数是很重要的,这样就可以对它们进行详尽的搜索,并优化模型的精度。对于正则化参数,测试范围从 0.00001 到 10000 的 10 的倍数的值。发现 0.0001 是最佳的,然后将其用于训练模型。该参数说明了数据点错误分类的重要性。

菜肴分类

这个项目的目标之一是根据抗癌分子的数量对菜肴进行排序。首先,使用表 1 中的全套成分(包括未列出的成分),确定 Recipe1M+数据集中每种配方中抗癌分子的数量[4]。为了将它们的名称与数据集中的成分相匹配,它们被简化了。比如普通葡萄转化为葡萄。在使用《烹饪方法》中介绍的 SVC 检索数据集中每种烹饪方法后,计算出每种烹饪方法中抗癌分子的平均存在量。

表 1 每种成分在第一栏和第二栏分别用其(修改后的)通用名称和学名表示。抗癌分子的数量及其名称出现在最后两位。只有五种抗癌分子数量最多的成分被显示出来。改编自[4]。

烹饪也可以根据它们的食谱与药物的预期负面相互作用的数量来分类。对于抗肿瘤药和免疫调节剂,引入了预期有害相互作用的百分比(表 2) [3]。在使用 HyperFoods 应用程序从食谱图像中检索菜肴后,这些信息将用于预测负面食谱-药物相互作用的可能性。

表 2 抗癌药与全球美食之间预期的负面相互作用的千分之一[3]。缩写:NA(北美)、WE(西欧)、NE(北欧)、EE(东欧)、SE(南欧)、ME(中东)、SA(南亚)、SEA(东南亚)、EA(东亚)、LA(拉美)和 A(非洲)。

可视化工具

Matplotlib、Plotly 和 Seaborn 是三个 python 可视化框架,用于可视化项目的一些数据。

Matplotlib 用于绘制报告中所有 2D 成分的矢量嵌入。在项目存储库中可用的 Jupyter 笔记本中,可以使用 Plotly 来动态可视化相同的数据。使得逐个成分的检查变得更容易,一旦它们的标签最初被隐藏,仅当鼠标悬停在相应的节点上时才出现。也可以分别放大和缩小以获得更多或更少的细节。

Seaborn 绘制了困惑矩阵,这是评估《烹饪法到烹饪法》中详述的烹饪检索算法的结果。

HyperFoods 应用程序

作为建立新的食材和食谱推荐平台的一个步骤,它开发了一个 web 应用程序。这能够从图像(由 URL 提供)中预测成分。基于它们在嵌入向量空间中与由反向烹饪算法识别的成分的接近度来建议替代成分。从检索到的一组配料中预测菜系。并且基于预测的烹饪来估计负配方-抗肿瘤药物相互作用的概率。

下面描述 web 应用程序的后端和前端的实现。

后端是使用 Node.js 开发的。在服务器端,导入了包含词汇表中前 3 个最相似成分的文件。这个文件是在计算嵌入空间中所有向量之间的欧几里德距离并将结果字典导出为 JSON 文件之后获得的。通过设置监听端口,在前端 HTML 页面和服务器之间建立连接。python 外壳用于:执行用 Python 实现的反向烹饪算法;加载 Word2Vec 模型;将图像的成分转换成矢量;计算每个食谱的矢量表示,并加载 SVC 模型,以便能够根据食谱矢量预测菜肴。在服务器端实现并执行了一个将二进制代码转换回字符串的函数。由于一般 URL 的格式,不可能从前端获取到服务器的链接。所以,这在前端被转换成二进制,在后端被转换回字符串。

在前端,使用 HTML 构建界面的主要结构。CSS 被用来使界面简单直观。JavaScript 支持响应性网页和与服务器的通信。用于使网站用户友好的一个基础 JavaScript 库是 D3.js 的缩小版,版本 4。它处理所有的鼠标事件。

在实现后端和前端之后,目标是使 web 应用程序在线可用。由于 Heroku 应用程序(托管平台)的大小限制和一些 PyTorch 文件的大小,这没有实现。在执行反向烹饪算法时,它使用了 PyTorch 模块的一个版本,该版本包括 GPU 和 CPU 支持。模块占用的内存超过 1GB。由于托管平台的存储限制(500 MB ),它使用了仅在 CPU 上执行的 PyTorch 的较轻版本。一旦 Heroku 不提供图形处理能力,这不会影响应用程序的执行。这一修改将应用程序的大小减少了一半。但仍然有来自反向烹饪算法的训练 PyTorch 模型导致应用程序超出服务器的内存限制。克服这一点的一种方法是使用较小的训练数据集来重新训练模型,但这将显著降低检测的准确性。由于时间限制,没有遵循这条路线。模型的大小(436 MB)不足以超过阈值,但与执行应用程序所需的 Node.js 和 Python 包并行,不可能使其在线可用。虽然,从 GitHub 下载后,web 应用仍然可以在本地运行。

结果

在方法上,项目的目标和实现它们所使用的工具被详细描述。在结果中,呈现了来自数据分析和可视化的结果。同时讨论结果的可预测性及其影响。

首先,提供了用于数据分析(Recipe1M+数据集)和模型训练(K&N 数据集)的数据集的详细概述。然后,指定成分嵌入和在二维空间中可视化它们的标准(成分推荐)。接下来,使用混淆矩阵评估 SVC 的性能,并在之后进行测试(食谱到烹饪)。每份食谱中抗癌分子数量较多的菜系会被排名(菜系分类)。最后,介绍了开发的食物推荐 web 应用程序(HyperFoods App)。

Recipe1M+数据集

该数据集包含 1029715 种配方,由 1480 种不同的成分混合而成。

为了更好地了解菜谱的来源,对数据集进行了解析,并返回了一个抓取的网站列表(表 3)。大多数数据库是欧洲或美国的。通过这种方式,烹饪检索算法可以将大量的食谱分类到这些类别中。

表 3 左侧废弃的用于创建 Recipe1M+数据集的网站。中间是各自的网址。右边是每个来源的食谱数量。

为了从 Recipe1M+中检索配料,开发了一个词汇表的优化版本,它是由发布数据集的同一个团队创建的。

表 4 显示了 Recipe1M+数据集中最常从食谱中检索到的前 5 种配料及其各自的出现次数。在 2D 嵌入向量空间中绘制成分时使用了该数据,并讨论了其在成分推荐方面的相关性(成分推荐)。

表 4 左侧 Recipe1M+数据集中出现频率最高的 5 种配料。右边是各自出现的次数。

Kaggle 和自然数据集

K&N 数据集包含 96250 种食谱和 3904 种不同的配料,涵盖 11 种菜系:北美、西欧、北欧、东欧、南欧、中东、南亚、东南亚、东亚、拉丁美洲和非洲。尽管这个数据集包含 Recipe1M+中大约 10%的食谱,但它包含的不同配料的数量是前者的两倍多。这是因为在该数据集中,糖等简单成分根据其颜色或来源(例如:有机砂糖、超细白糖、烘焙糖等)被分成不同的成分。

表 5 列出了前 5 种最常见的成分。Recipe1M+和 K&N 数据集中最常见的成分明显重叠。在前 5 名中,洋葱和胡椒同时出现在两个数据集中。

表 5 在左边,K & N 数据集中出现频率更高的成分。右边是各自的存在数量。

在表 6 中,根据食谱的数量,表示了数据集中的烹饪的分布。在 K&N 数据集中检测到的每种菜肴的食谱数量不平衡。北美烹饪包含的食谱比东欧多 2 个数量级。这将影响 SVC 模型的准确性(混淆矩阵)。

表 6K&N 数据集中属于不同菜系的菜谱数量。缩写:NA(北美)、WE(西欧)、NE(北欧)、EE(东欧)、SE(南欧)、ME(中东)、SA(南亚)、SEA(东南亚)、EA(东亚)、LA(拉美)和 A(非洲)

成分推荐

在 100 个特征嵌入中表示 Recipe1M+数据集中存在的每种成分,并将维度减少到二维空间后,获得了图 4 中的图。为了清楚起见,在数据集中出现少于 4500 次的所有成分都没有表示出来。不同的颜色对应于使用光谱聚类识别的不同聚类。

光谱聚类确定了沙拉亚洲菜肴水果&坚果甜点类别(图 4)。

图 4recipe 1m+中几种成分的上下文相似性。仅表示在数据集中至少出现 4500 次的那些。配料根据它们所属的种类而着色。

这种食物表征允许我们提取关于哪些成分最常同时出现的信息。因此,它为根据它们在图中的接近程度尝试新的组合提供了基线。重叠成分的半径越大,它们组合成功的信心就越大。

一些成功的组合是大蒜、鸡肉和洋葱;番茄,罗勒和芹菜或蜂蜜和橘子。

相同的图像被重印,但是具有不同的着色标准。这一次,含有至少一种抗癌分子的成分被涂成绿色,其余成分被涂成黑色(图 5)。

图 5recipe 1m+中成分的上下文相似度。仅表示在数据集中至少出现 4500 次的那些。绿色节点(成分)包含至少 1 个抗癌分子。

通过识别与含有抗癌分子(绿色节点)的成分更接近的成分,人们可以假设,鉴于它们在食谱中存在的相似背景,可能更有可能在食谱中找到这些相同的分子。

此外,图 5 不仅为我们提供了通常同时出现的成分的信息,还为用户提供了它们在抗癌分子中的含量信息。这样,用户可以考虑他们的抗癌特性,同时考虑上下文相似性。检索了一些潜在的组合,如图 6 所示。

图 6 肉桂、核桃、蔓越莓;观察图 5,花生和芒果是两种最成功的配料组合。

烹饪食谱

在 Recipe to Cuisine 中讨论过,SVC 的实现能够在给定 Recipe1M+和 K&N 数据集包含的一组食材的情况下预测菜系。在这一节中,在构建混淆矩阵后评估其准确性,在 Recipe1M+数据集中测试该模型,并确定在菜系分类中起重要作用的一些食材。

混淆矩阵

为了理解分类器如何检测不同的菜肴,从训练集计算出多维混淆矩阵(图 7)。它包括对 K&N 食谱数据集中 11 种烹饪法中每一种的预测。

图 7 使用 K & N 数据集训练的 SVM 模型的混淆矩阵。每一行,以及各自的值,代表正确分配给真正的菜肴的配料比例。每一列都是由算法预测的菜系。

属于北欧、东欧、西欧和中东地区的食谱经常被误归类为北美食谱。就北欧、东欧和中东而言,这可能是因为它们在数据集中代表性不足:分别为 739、381 和 645 种食谱。以及过多的北美美食。

另一个重要因素是常见的成分。事实上,所有的欧洲美食经常被错误地归入其中。例如,11.5%的北欧食谱被错误地归类为西欧食谱。欧洲是拥有最多美食的大陆(4)。这可能会降低它们之间的特异性。

该模型在预测东亚、南亚和北美食谱时更加准确。事实上,分别有 84.8%、83.4%和 73.0%的人回答正确。

测试分类器

在训练分类器之后,它被用来预测 Recipe1M+数据集中每个食谱的烹饪。各自的比例如表 7 所示。

为了测试分类器,使用了以下方法:首先,检索标题中出现单词 tea 的所有食谱。然后,计算出最终的菜肴分布(表 7)。

表 7recipe 1m+内菜系分布。另外,过滤标题中包含关键字沙拉的。

正如所料,标题中包含单词 tea 的大多数食谱被归类为,第一,属于东亚(27%的食谱),第二,属于北欧(25%的食谱)(图 8)。

这两个领域在 tea 精选食谱中比在整个 Recipe1M+数据集中表现得更多。在东亚,中国是世界上最大的茶叶绝对消费国,每年消费 16 亿英镑[23]。从北欧国家来看,爱尔兰、英国和俄罗斯是人均消费率较高的前 4 个国家[23]。另一方面,排名最高的南欧国家(西班牙)在人均茶叶消费量上仅排在第 40 位[23]。事实上,数据集的最大下降(从 21%到 5%)是在这个地区得到验证的。

图 8 全球每人每年的茶叶消费率。[23]

菜肴分类

为了分析不同菜肴中抗癌分子的存在,人们使用了每种菜肴中抗癌分子数量的信息。在对一个烹饪类别中的所有食谱进行平均后,确定每个食谱的得分(表 8)。

表 811 种代表性菜系中每一种的平均抗癌分子数量。缩写:NA(北美)、WE(西欧)、NE(北欧)、EE(东欧)、SE(南欧)、ME(中东)、SA(南亚)、SEA(东南亚)、EA(东亚)、LA(拉美)和 A(非洲)。

地中海地区的三个地区获得了最高的抗癌得分:南欧、中东和非洲(图 9)。另一方面,北美菜肴被认为是抗癌分子数量最少的。

这些结果与对北美烹饪的预测一致,北美烹饪通常被归类为不健康,并与肿瘤疾病的发病率呈正相关[24]。地中海饮食富含水果和蔬菜,通常被认为可以预防癌症[25]。

图 9 包含抗癌分子数量较高的食谱的菜肴。使用[26]生成的世界地图。

为了了解哪些配料可能是导致南欧、中东和非洲菜肴排名靠前的原因,通过只考虑标题中包含关键字沙拉的配料来计算它们的分布(表 7)。

表 7 显示沙拉食谱大多被归类为南欧菜肴的一部分。它们可能是增加这种菜肴抗癌得分的主要原因之一,因为表 1 完整版本中的大多数成分通常在沙拉中都能找到。此外,值得强调的是,南欧饮食的主要组成部分之一是沙拉[27]。

HyperFoods 应用程序

在网页的顶部,FoodReco 接收在线可用图像的 URL,并在执行反向烹饪算法后返回预测的配料列表。它们将显示在已处理图像的下方。将鼠标悬停在每种成分上,会显示 Recipe1M+和 K&N 中最常同时出现的前 3 种成分的有序列表。底部显示的是根据一系列配料预测的菜肴。每当与药物的负面相互作用数量低于平均值时,该文本字段的背景颜色为绿色,如果高于平均值,则为红色(图 10)。该值是对表 2 中的所有许可值求平均值后计算得出的。

点击可下载网络应用。

图 10FoodReco web 应用界面。它能够从图像中预测配料,建议每种配料的 3 种替代物,并检索出这道菜最可能属于的菜肴。

结论

这个项目的目标是使用最大的公开可用食谱数据集合(Recipe1M+)来构建一个食材和食谱推荐系统。训练、评估和测试一个模型,该模型能够从多种配料中预测菜肴。基于预测的烹饪,预测负面配方-药物相互作用的概率。最后,建立一个 web 应用程序,作为建立一个考虑用户口味偏好的推荐系统的一个步骤,使食物中健康化合物的数量最大化,不健康化合物的数量最小化。

使用 Word2Vec 生成每种成分的矢量表示。通过对矢量化配料的所有成分进行平均,获得了食谱的类似表示。SVC 模型被训练来从它们的配料集合中返回食谱的烹饪。南亚、东亚和北美菜肴的预测准确率超过 73%。非洲、南欧和中东的菜肴含有最多的抗癌分子。最后,它开发了一个 web 应用程序,能够从图像中预测成分,建议新的组合,并检索食谱所属的菜肴,以及与抗肿瘤药物的预期负面相互作用次数的分数。它不可能在网上发布,但是可以在本地执行(github.com/warcraft12321/HyperFoods)。

这个项目中使用的方法的未来增强是为成分创建更详尽和准确的词汇表。在使用 Word2Vec 嵌入成分之前,Recipe1M+和 K&N 数据集中存在的成分之间的一致化可以增强嵌入和 SVC 的准确性。为考虑到不同成分的比例的配方生成向量。这个项目朝着这个方向迈出了一步,开发了一个词汇表,其中包括 Recipe1M+数据集中的所有单位(习惯单位和常用公制单位)。以及所有确定的单位与克之间的转换系统。除了线性核之外的不同的核可以用于训练烹饪检索 SVC 模型。或者,深度学习被用来优化相同的问题。最后,虽然 web 应用程序可以在本地计算机上顺利运行,但下一步将是使其在线可用并具有更多功能,例如:添加额外的食物推荐,以选择富含抗癌分子的成分(超食物),同时减少除抗肿瘤药之外的其他类型药物的药物-菜肴负面相互作用的数量。

报告 | 海报 | GitHub 资源库

参考

[1] H. Arem 和 E. Loftfield,“癌症流行病学:预防和生存的可变风险因素调查”,美国生活方式医学杂志,第 12 卷,第 3 期,第 200–210 页,2018 年。

[2] M. S. Donaldson,“营养与癌症”,《营养杂志》,第 3 卷,第 19-25 页,2004 年。

[3] M. Jovanovik,A. Bogojeska 和 D. e. a. Trajanov,“使用关联数据方法推断烹饪-药物相互作用”,科学报告,第 5 卷,第 9346 号,2015 年。

[4] K. Veselkov,G. Gonzalez,S. Aljifri,D. Galea,R. Mirnezami,J. Youssef,M. Bronstein 和 I. Laponogov,“HyperFoods:食品中抗癌分子的机器智能绘图”,科学报告,第 3 卷,第 9237 号,2019 年。

[5] C. Anderson,《食品推荐者调查》, ArXiv,第一卷 abs/1809.02862,2018。

[6] J. R. Aunan,W. C. Cho 和 K. Sø reide,“衰老和癌症的生物学:共享和分歧分子特征的简要概述”,衰老和疾病,第 8 卷,第 5 期,第 628-642 页,2017 年。

[7]“IHME,全球疾病负担,数据中的世界”,2016 年。【在线】。可用:http://www.healthdata.org/gbd.【2020 年 3 月 8 日获取】。

[8] M. Chary,S. Parikh,A. F. Manini,E. W. Boyer 和 M. Radeos,“医学教育中的自然语言处理综述”,《西方急诊医学杂志》,2019 年第 20 卷第 1 期。

[9] T. Mikolov,K. Chen,G. Corrado 和 J. Dean,“向量空间中词表征的有效估计”,学习表征国际会议论文集, 2013。

[10]r . řehůřek,“gensim:人类的主题建模”,[在线]。可用:https://radimrehurek.com/gensim/.【2020 年 3 月 8 日获取】。

[11] A. Salvador,M. Drozdzal,X. Giro-i-Nieto 和 A. Romero,“逆向烹饪:从食物图像生成食谱”,计算机视觉与模式识别, 2018。

[12] A. Salvador,N. Hynes,Y. Aytar,J. Marin,F. Ofli,I. Weber 和 A. Torralba,“学习烹饪食谱和食物图像的跨模态嵌入”,计算机视觉和模式识别, 2017。

[13] I. T. Jolliffe 和 J. Cadima,《主成分分析:回顾与近期发展》,英国皇家学会哲学汇刊 A 数学物理与工程科学,2016 年第 374 卷第 2065 期。

[14] L. v. d. Maaten 和 G. Hinton,“使用 t-SNE 可视化数据”,《机器学习研究杂志》,,第 9 卷,第 2579-2605 页,2008 年。

[15] V. D. Blondel,J.-L. Guillaume,R. Lambiotte 和 E. Lefebvre,“大型网络中社区的快速展开”, J. Stat 机甲战士。, 2008 年。

[16] M. Rosvall、D. Axelsson 和 C. T .博格斯特伦,“地图方程”,《欧洲物理杂志专题》,第 178 卷,第 1 期,第 13-23 页,2009 年。

[17] A. Y. Ng,M. I. Jordan 和 Y. Weiss,“关于谱聚类:分析和算法”,第 14 届国际神经信息处理系统会议记录:自然和合成,第 849-856 页,2001 年。

[18]《Matplotlib:Python 绘图》,Matplotlib,[在线]。可用:https://matplotlib.org/.【2020 年 3 月 8 日获取】。

[19]“Plotly:面向企业的现代分析应用”,Plotly,[在线]。可用:https://plot.ly/.【2020 年 3 月 8 日获取】。

[20]“seaborn:统计数据可视化”,Seaborn,[在线]。可用:https://seaborn.pydata.org/.【2020 年 3 月 8 日获取】。

[21]《熊猫》,[在线]。可用:https://pandas.pydata.org/.【2020 年 3 月 8 日获取】。

[22] J. Marin,A. Biswas,F. Ofli,N. Hynes,A. Salvador,Y. Aytar,I. Weber 和 A. Torralba,“Recipe1M+:用于学习烹饪食谱和食物图像的跨模态嵌入的数据集”, IEEE 模式分析和机器智能汇刊, 2019。

[23] R. A. Ferdman,“地图:喝茶最多的国家”,《大西洋月刊》,2014 年 1 月 21 日。【在线】。可用:https://www . theatlantic . com/international/archive/2014/01/map-the-countries-the-drink-the-most-tea/283231/。【2020 年 3 月 7 日访问】。

[24] M. S. Donaldson,“营养与癌症:抗癌饮食证据综述”,《营养杂志》,第 3 卷,第 19 期,2004 年。

[25] A. Maruca,R. Catalano,D. Bagetta,F. Mesiti,F. A. Ambrosio,I. Romeo,F. Moraca,R. Rocca,F. Ortuso,A. Artese,G. Costa,S. Alcaro 和 A. Lupia,“地中海饮食作为具有多靶向抗癌概况的生物活性化合物的来源”,《欧洲药物化学杂志》,第 181 卷,2019 年。

[26]《地图图》,[在线]。可用:【https://mapchart.net/world.html. 【2020 年 3 月 7 日接入】。

[27] C. M. Lăcătușu,E. D .格里戈里斯库,m .弗洛里亚,a .奥诺弗雷斯库和 B. M .米海,《地中海饮食:从环境驱动的饮食文化到新兴医学处方》,《国际环境研究与公共卫生杂志》,第 6 卷,第 16 期,2019 年。

[28]“朱庇特项目”,朱庇特,[在线]。可用:https://jupyter.org/.【2020 年 3 月 8 日获取】。

构建游戏推荐引擎

原文:https://towardsdatascience.com/building-a-game-recommendation-engine-870a1ccd11c4?source=collection_archive---------35-----------------------

使用来自 Steam 和 LightFM 库的数据生成预测

对于我的 Flatiron 数据科学训练营顶点项目,我知道我想建立一个推荐引擎。推荐系统已经成为我们日常生活的一部分,从网飞推荐电影到亚马逊展示我们感兴趣的商品。虽然 MovieLens 数据集似乎是学习和构建推荐系统的首选数据集,但我希望使用不同的数据源来确保项目更加独特。

在 COVID 疫情期间,随着人们更多地呆在家里,视频游戏出现了激增。事实上,Steam 在 2020 年 3 月报告了创纪录的在线并发用户数。因此,我决定调查游戏推荐,看看我的预测是否与 Steam 的一致。

亚历克斯·哈尼Unsplash 拍摄的照片

第一步:获取数据

这些数据是从朱利安·麦考利的推荐系统数据集页面获得的。我使用了两个文件:版本 1:用户和物品数据,其中包含了协作过滤模型所必需的用户-物品交互数据;以及版本 2:物品元数据,其中包含了与游戏相关的信息,比如发布日期、标签、价格等等。

第二步:加载并预处理数据

虽然数据据说是 JSON 格式的,但我无法用 Pandas 直接加载它。当通过 JSON linter 运行它时,我注意到它不是正确的 JSON,因为使用了单引号而不是双引号。一个可行的解决方案是使用ast.literal_eval().读取数据,数据预处理相对简单,从字典列表中提取游戏 id 是一个小小的挑战。

第三步:建模

为了创建用户推荐模型,我使用了 LightFM 库。文档非常简单。在实例化模型之前,我将数据框架修改为稀疏交互矩阵。有许多可能的损失函数可以使用,我发现 WARP 提供了最好的模型。这种方法通过重复采样负样本直到找到一个违反规则的样本来最大化正样本的等级。当只有积极的互动,人们希望优化推荐列表的顶部时,这也是最常用的,这两种情况都适用于我的情况。

步骤 4:生成用户推荐

随着我们的最终模型在完整的交互矩阵上得到训练,我现在可以为用户生成推荐了。我创建了一个函数,它将训练好的模型、交互矩阵、用户 id 和所需推荐的数量k作为输入,并为该用户返回排名前k的游戏。

第五步:单品推荐

我还使用余弦相似性作为距离度量,使用该模型来生成项目到项目的推荐。我创建了一个函数,它接受一个游戏 id 并返回k最相似的游戏。

示例输出:五个类似于美国卡车模拟器的游戏

更多细节和底层代码,请看我的 GitHub 库

参考

https://www . games industry . biz/articles/2020-03-16-record-number-of-steam-users-online-during-coronavirus-outbreak

构建 GAN(通用对抗网络)

原文:https://towardsdatascience.com/building-a-gan-general-adversarial-network-6d0f69747945?source=collection_archive---------27-----------------------

用 Pytorch 生成人脸

致谢: Pexels 的 jimmy teoh

在过去的一个月里,我一直在开发一个人脸识别系统。我从一开始就对 gan 感兴趣,因为它们能够创造新的照片和不存在的数据集。在本文中,我将介绍什么是 GAN,然后简单介绍一下我使用的代码。

【甘简介:】

GAN 或通用对抗网络是利用两个神经网络的网络,一个生成器和一个鉴别器。生成器的工作是创造新的数据,鉴别器的工作是决定生成器吐出的数据是不是假的。在我的例子中,生成器创建图像,鉴别器决定图像是否真实。在训练过程中,生成器的目标是生成越来越好的图像来欺骗鉴别器,而鉴别器的作用是越来越好地决定图像是不是假的。目标是鉴别器不能区分图像是否来自训练数据。如您所见,这为两种算法创建了一个正反馈循环,从而改善了生成器生成的最终图像。

GAN 的基本图。署名:维克拉姆·梅农

我专门构建了一个 DCGAN,一个深度卷积的一般对抗网络,它的工作方式有点不同。它利用卷积网络,而不是在发生器和鉴别器中使用多层感知器。

DCGAN 图。署名:维克拉姆·梅农

这有利于我们,因为需要更少的训练数据和时间。ConvNets 基于数据相关的思想。在我的例子中,它允许算法将图像一侧的像素关联到另一侧。这使得它能够为图像中的不同结构赋予重要性,并区分它们。这对于图像非常有帮助,因为常规的多层神经网络单独观察和训练每个像素,而 ConvNet 可以训练一个区域,并将其应用于其他像素。此外,DCGAN 不使用池,而是使用 Stride。这是因为池只关心图像中的对象是否存在,而 Stride 也关心位置。总的来说,DCGANs 能够实现更平滑和更高效的过程,这就是为什么它是最常见的 GAN。

这一切是如何运作的

我将回顾所使用的代码,以及这些代码对于 DCGAN 如何工作的意义。

发电机

如上所述,生成器的工作是生成一个图像来欺骗鉴别器。那么,它到底是怎么做到的呢?

发电机的输入是一个潜向量。潜在向量是映射到潜在空间中的一组隐藏点,这些点应用于向量算法。矢量算法建立点之间的关系,例如距离和地形数据。

图像尺寸开始很小,最后变大。署名:维克拉姆·梅农

然后,潜在向量被送入一系列步长二维卷积转置层。这基本上包括一个跨越(或跳过)输入矩阵的内核。为了增加图像的大小,需要上采样。上采样是指程序将维度加倍,以获得特定维度的更大、更密集的图像。

接下来,我们通过批量标准化来运行它,以使训练更容易。通过规范化图层,它减少了潜在值的变化量。这稳定了层的激活,允许最佳权重并降低损失函数。

信用:笑库存,通过维基 (CC BY-SA 4.0)

接下来我们通过一个 ReLU 激活来运行它。Relu 的特别之处在于,虽然它在照片的右半部分看起来像一条直线,但在左半部分可以看到,它并不是。这是一个基本的激活功能,它允许程序超越线性回归,学习更复杂的数据,如视频、音频或对我来说是图像。

最后,我将我的数据输出到一个双曲正切函数中,该函数依次输出-1 和 1 之间的数据。这将使数据正常化,并将其返回到原始范围。

鉴别器

图像发生器的尺寸减小了。署名:维克拉姆·梅农

如前所述,鉴别器将生成的图像作为输入,并输出图像来自训练数据的概率。鉴别器只是做与生成器相反的事情。首先,它将数据输入到一个 2dConv 网络中,这次没有放大(因为我们在缩小)。然后,它通过批处理规范化和 Relu 来馈送它。最后,它使用 sigmoid 激活函数输出概率,而不是生成器中的双曲正切函数。这样做的好处是它输出 0 到 1 之间的概率。

结果

既然我们已经有了生成器和鉴别器,我们必须实际训练网络并得到结果。我们首先根据训练数据训练鉴别器,然后从生成器生成图像,并对生成的图像运行鉴别器。

快速旁注:

那就是 Goodfellow 的论文中提到的 GAN 损失函数。D(G(z))是生成器(G)的输出是真实图像的概率。鉴别器 D 试图最大化它对生成的图像进行正确分类的机会(log(D(x))。另一方面,G 试图最小化鉴别器将图像分类为假图像的概率(log(1D(G(x)))。这迫使生成器和鉴别器在工作中做得更好。

经过一个时期的训练后,结果如下:

经过 10 个时期的训练,结果看起来像这样:

正如你所看到的,随着时间的推移,生成的图像在识别和再现人脸的面部结构方面变得越来越好

疯狂的是生成的人都是百分百假的。这太疯狂了。这方面的应用有很多。从图像编辑到安全和银行业务,GANs 拥有巨大的潜力。能够生成新的数据集是理解和创造新事物的关键因素

创作这个 GAN 对我来说是一次非常享受的经历,因为我必须真正弄清楚所有复杂的部分是如何组合在一起的。请继续关注我的下一个版本!

教程:https://py torch . org/tutorials/初学者/dcgan_faces_tutorial.html

联系我:

领英:https://www.linkedin.com/in/vikram-menon-986a67193

电子邮件:vikrammenon03@gmail.com

基于自然语言处理和机器学习的工作推荐系统

原文:https://towardsdatascience.com/building-a-job-recommender-for-non-technical-business-roles-via-nlp-and-machine-learning-626c4039931e?source=collection_archive---------12-----------------------

为非技术背景的人建了一个工作推荐器。这篇文章是关于这个应用的特性和我构建它的步骤。

剧组Unsplash 上拍照

这里是 app 的链接。

由于我以前的公司最近裁员,我受到启发创建了一个工作推荐器。我的许多被解雇的前同事进入职业生涯不到 3 年,他们想知道,根据他们的经验,他们适合什么样的角色,他们应该从哪里开始找工作。我记得大学毕业时也有过类似的挣扎,当时我也不知道应该把目光放在哪里。我相信这个问题对于非技术背景的人来说是相当普遍的。

因此,我决定为我们这种职位的人——那些非技术背景的人,如心理学专业的人——建立一个工作推荐器,它将使用基于我们过去经历的信息来帮助我们走上正确的道路。

该应用程序结合了自然语言处理技术,如主题建模和分类风格的机器学习,以确定最适合你的。你复制并粘贴你的简历/ LinkedIn 到文本框中,应用程序解析文本并为你提供 ML 驱动的分析,分析你适合哪些工作以及为什么适合。

该应用程序有 3 个特点:

功能 1: 按作业类型返回匹配百分比。

功能 2: 根据主题匹配,返回一张你的简历与其他职位的匹配度图。这个图表有望对你从特性 1 中得到的结果提供某种解释。

特点 3: 选择不同工作原型的下拉列表,看看你的简历中哪些关键词匹配,哪些不匹配。

在本文的剩余部分,我将回顾我构建工作推荐器的步骤。我的代码的链接在这里。

步骤 1:确定项目范围

数据科学项目最重要的部分是范围界定,也就是说,规划您的项目,使其符合您的时间和精力限制,但仍然能够回答有价值的问题。某个领域可以拥有如此多的数据和探索途径,其数量之大令人难以招架。因此,你需要清楚你要解决什么问题,你要寻找什么具体数据,成功的最低门槛是什么。

我研究的关键问题是找出需要分析的工作类型。在非技术性的商业领域,有如此多不同的工作。我觉得如果我包括太多的工作申请,这个项目就不会达到预期的效果。建模可能不太准确,应用程序最终可能过于混乱和不集中,对最终用户没有帮助。因此,我回想了一下自己的初衷,并为乔布斯的分析确定了两个标准:

  1. 这些工作必须是不需要技术技能的商业角色。这不包括软件工程师、医学或表演。
  2. 这份工作的薪水必须在 40-120,000 英镑之间。这反映了具有 0-3 年工作经验的人的典型收入范围。

之后,我想到了一些有意义的宽泛的工作原型,但也发出了一份调查,看看别人对我的想法有什么看法。然后,我让我的同事对他们感兴趣的工作类型进行排名,这样我就可以限制我必须分析的工作类型的数量。理想情况下,我希望分析不到 10 种工作类型。

有了这些信息,我选择了 5 个最受欢迎的工作作为我分析的基础,但后来当我确信我的模型可以正确区分工作类型时,我又添加了更多。我最终在非技术业务领域选择了 8 种不同的工作类型,还出于个人兴趣添加了“数据科学家”。

步骤 2:收集数据

我计划使用的数据是符合上述标准的各个工作类型的职位发布。我第一次看 LinkedIn 和确实,但他们的网站证明太难刮,因为动态加载。

我决定从 Glassdoor 上抓取招聘信息,它也使用动态加载。但这一次,我借用了一位数据科学家同事的代码,并根据我的需要进行了修改。我很感激这段代码,因为构建我自己的 scraper 将花费我更多的时间!

在修改了 scraper 以适应我的需求后,我为每个工作类型刮了 40 个帖子并加入了文件。许多工作显然不符合正确的工作原型——例如,当我担任“项目经理”时,我得到了许多建筑方面的工作。我还得到了许多头衔为“高级(工作类型)分析师”或“主管(工作类型)”的工作,这些职位对于有 0-3 年工作经验的人来说显然是高不可攀的。因此,我设置了文本过滤器来筛选这些工作类型,并仔细检查以确保其余的数据符合我的要求。最终,我得到了来自 9 个不同工作类型的 149 个工作列表的文本描述作为我的数据集。

第三步:数据清理和主题建模

下一步是清理文本描述。我使用了标准的清理技术,比如删除标点符号和大写,然后对单词进行标记化和词干化,以实现语义标准化。最后,我使用矢量器将数据放入数组格式。

一旦数据是可分析的格式,我就执行主题建模,尝试了几种技术,但最终还是采用了 TruncatedSVD。优化因素是我在步骤 4 中建立的分类模型预测工作类型的准确度。我总共想出了 20 个不同的主题。

步骤 4:构建分类算法

在主题建模之后,我使用了主题-文档矩阵,并将其输入到分类算法中。为了提高准确性,我最终选择了随机森林分类器。该模型在验证集上返回了约 90%的准确度,显示了在预测每个职位描述的正确职位类型方面的强大能力。

接下来,是时候赋予模型一个功能性的目的了。我用了上面的主题模型来改造一个人的简历,然后用上面的分类模型来预测简历最适合哪些工作。然后,我根据工作类型提取了匹配百分比,给出了一个人最佳工作匹配的更细致的视图——例如,60%的项目经理,40%的产品经理——并为最终用户提供了多种职业发展途径进行调查。

步骤 5:构建 PCA 图表构建函数

当我向人们展示他们各自工作匹配百分比的结果时,他们问为什么他们适合这些群体。我很难向非技术人群解释模型的基本机制,因此我决定向他们展示一个简化的图表来解释这些工作匹配结果。

首先,我使用主成分分析将主题-文档矩阵简化为二维。然后,我根据缩减后的维度划分出每种工作类型。我还对一个人的简历进行了降维处理,并在图表上画出了一个人的简历与其他工作的对比。在解释新的 PCA 特性时,我发现它们主要面向两种主题类型:市场营销相关的关键词和项目管理相关的关键词。

步骤 6:构建关键字匹配功能

用户感兴趣的是如何改善他们的简历,以便在他们瞄准的任何工作中获得更好的机会。为了让应用程序更有用,我决定做一个匹配关键词的功能。

在这个功能中,用户从下拉列表中选择他们感兴趣的工作,应用程序会返回他们简历中匹配和缺失的关键词。人们可以看到他们的简历目前所处的位置,以及他们可以在更有针对性的申请中加入哪些词语和经历。

这个特性可能是最容易制作的。我使用了上面相同的主题模型来找出每种工作类型中最重要的单词——比如前 20 个——并使用列表理解来查看哪些单词匹配或错过了。

步骤 6:编写和部署应用程序

既然我已经创建了函数和模型,我需要在线部署一个应用程序,以便人们可以使用它。

对于 app 编写,我用的是 Streamlit。这是最简单和最有效的软件包之一。然后我用 Heroku 和 git 把它上传到网上,尽管回想起来,使用 streamlit 新发布的应用程序部署功能要容易得多。

我们做到了!工作推荐人。我为这个项目感到非常自豪,我希望人们会发现它很有用。如果你认为这个应用可以帮助某人,就发给他们吧!如果你有任何批评,欢迎在下面评论或者给我发信息。感谢阅读。

使用 Amazon Elasticsearch 和 SageMaker 构建 k-NN 相似性搜索引擎

原文:https://towardsdatascience.com/building-a-k-nn-similarity-search-engine-using-amazon-elasticsearch-and-sagemaker-98df18d883bd?source=collection_archive---------12-----------------------

构建高效且可扩展的文档相似性搜索引擎的分步指南

NeONBRANDUnsplash 拍摄的照片

亚马逊 Elasticsearch 服务最近增加了对 k 近邻搜索的支持。它使您能够像运行任何常规的 Elasticsearch 查询一样轻松地在数千个维度上运行高规模和低延迟的 k-NN 搜索。

k-NN 相似性搜索由 Elasticsearch 开放发行版提供支持,这是一个 Apache 2.0 许可的 Elasticsearch 发行版。

在这篇文章中,我将展示如何使用 Amazon Sagemaker、Amazon Elasticsearch、Amazon Elastic File System (EFS)和 Amazon ECS 构建一个可扩展的相似性问题搜索 api。

我们将在本例中介绍的内容:

  • 在 VPC 部署并运行一个 Sagemaker 笔记本实例。
  • 将 EFS 装载到笔记本实例。
  • 下载 Quora 问题对数据集,然后使用 DistilBERT 模型将数据集中的变长问题映射到定长向量。
  • 创建下游任务以减少嵌入维数,并将句子嵌入器保存到 EFS。
  • 将问题文本转换为向量,并将所有向量索引到 Elasticsearch。
  • 将容器化的 Flask rest api 部署到 ECS。

下图显示了上述步骤的架构:

在 VPC 部署和运行 Sagemaker 笔记本实例

首先,让我们创建一个连接到 Elasticsearch 的 Sagemaker 笔记本实例,并确保它们在同一个 VPC 中。

要在 Sagemaker 控制台中配置 VPC 选项,请在创建笔记本实例页面的网络部分的中,设置 VPC 网络配置详细信息,如 VPC 子网 id 和安全组 id:

将 EFS 安装到笔记本实例

我们将在 SageMaker 笔记本中完成所有必要的句子转换步骤(代码在 处找到 )。

现在,将 EFS 安装到型号目录,关于 EFS 的更多详情,请查看 AWS 官方文件

:

  • fs-xxxxx.efs.ap-southeast-2.amazonaws.com是 EFS 的 DNS 名称。
  • EFS 山目标和萨格马克在同一个 VPC。

使用 DistilBERT 模型将变长问题映射到定长向量

要运行最近邻搜索,我们必须获得句子和标记嵌入。我们可以使用句子变形器,这是一个用 PyTorch 使用 BERT/RoBERTa/distil BERT/ALBERT/XLNet 的句子嵌入。它让我们只用几行代码就能把句子映射成固定长度的表示。

我们将使用轻量级 DistilBERT 模型到生成句子嵌入在这个例子中,请注意 DistilBERT 的隐藏单元数量是 768。这个维度对于 Elasticsearch index 来说似乎太大了,我们可以通过在合并后添加一个密集层来将维度减少到 256:

接下来,将句子嵌入器保存到 EFS 安装的目录中:

transformer.save("model/transformer-v1/")

我们需要确保数据集已经下载,本例中的数据集是[quora question paris datas](https://www.kaggle.com/quora/question-pairs-dataset)

接下来,将每个问题的全文提取到 dataframe 中:

将问题文本转换为向量,并将所有向量编入索引以进行弹性搜索

首先,创建一个 kNN 索引,

然后将问题向量转换并索引到 Elasticsearch。

弹性搜索中的问题具有以下结构:

{'question_vector': [-0.06435434520244598, ... ,0.0726890116930008],
'question': 'How hard is it to learn to play piano as an adult?'}

我们将问题嵌入到固定长度的向量中,并将所有向量编入索引以进行弹性搜索。让我们创建一个连接到 Elasticsearch 的 rest api 并进行测试!

部署容器化的 Flask rest api

我们将使用示例云形成模板在 VPC 创建 ECS 集群和服务(模板和 bash 脚本在 这里 )。

我们将使用带有 ECS 的 EFS 卷,搜索流程为 1) Flask 应用程序将保存的句子嵌入器加载到 EFS 卷中, 2) 将输入参数句子转换为向量, 3) 然后在 Elasticsearch 中查询 K-最近邻居。

我们现在已经在 ECS 容器中运行了 flask api,让我们使用基本的搜索功能来查找类似的问题,以进行查询:“ 在线赚钱的最佳方式是什么 ?”:

$**curl** --data '**question=What is best way to make money online?**' --data '**size=5**' --data '**min_score=0.3**'  -X POST http://knn-s-publi-xxxx-207238135.ap-southeast-2.elb.amazonaws.com/search

查看结果:

正如你所看到的,结果是相当惊人的,你也可以微调你自己的句子嵌入方法,这样你就可以为 k-NN 搜索得到特定任务的句子嵌入。

太好了!我们有我们需要的!我希望这篇文章对你有用。

完整的脚本可以在我的 GitHub repo 中找到。

用 Python 一步步构建语言翻译聊天机器人

原文:https://towardsdatascience.com/building-a-language-translation-chatbot-in-python-step-by-step-40709393a98?source=collection_archive---------14-----------------------

Python 中的语言翻译模型

沃洛德梅尔·赫里先科Unsplash 上的照片

这里,在本文中,我们将制作一个语言翻译模型,并通过提供一种语言的输入并获得您想要的语言的翻译输出来进行测试。对于使用 Python 的语言翻译模型,我们将使用序列到序列模型架构。

一个序列到序列模型有两个部分。第一部分是编码器,第二部分是解码器。这两个特征是两个不同的神经网络模型组合成一个巨大的神经网络。编码器模型的任务是在应用其他文本清理机制后理解输入序列并创建给定输入文本的较小矢量表示。然后,编码器模型将创建的向量转发到解码器网络,解码器网络生成序列,该序列是表示模型输出的输出向量。

作者照片

数据

我们将使用英语到印地语的翻译数据集,其中包含我们日常生活中使用的大约 3000 个对话。我们可以从任何开源资源中获取数据。你可以在卡格尔买到。

这里,我使用一个简单的文本文件,它是空格分隔的对话。它基于英语到印地语的对话,但是你也可以使用你自己的语言。但是,数据格式应该与文本文件相同,这将有助于您更好地遵循我的代码,不做任何更改。否则你可能需要根据你的数据格式做一些小的改变。

作者照片

大量数据

我们需要将我们的数据分成一些部分,并使用这些部分来训练出深度学习模型,以便我们的机器不会耗尽内存。

设置向量大小

我们需要设置向量的大小。向量大小是我们需要定义的输出数组的大小,这样所有的输出数组都可以有相同的大小。

embed_size=100 #define the vector size based on word your embedding
max_features=6000 #to restrict your number of unique words
maxlen=100

文本处理

如前所述,需要对编码器和解码器的数据进行处理,以获得更好的结果。这里,在我们的语言翻译中,我们将使用一些文本清理方法,如:

  1. 移除所有停用字词
  2. 单词大小写的变化
  3. 删除所有数字数据
  4. 删除重复的单词

单词嵌入

我们将使用 word2vec 模型将文本数据转换成定义大小的向量。

Word2Vec 是一种把单词变成数字的技术。我们的机器学习或深度学习模型接受数字形式的输入。

鸣谢:维基百科

我们有两种著名的单词嵌入技术:

  1. CBOW:
  2. 跳跃图

作者照片

我们可以使用任何预先训练好的 word2vec 模型。这里,我们将利用手套模型。 GloVe 模型在单词类比任务中结合了 word2vec skip-gram 模型的优点。这个手套模型可以在谷歌上找到。它有一个. txt 格式,我们可以使用下面的代码导入。

手套嵌入以小尺寸嵌入而闻名,足以满足我们的日常聊天。

数据标记化

初始化单词嵌入后,我们需要使用嵌入来标记数据。嵌入将每个单词转换成定义大小的数字向量。我们的机器学习或深度学习模型对数字数据起作用,因为有必要通过将每个单词定义为特定的向量来将任何文本数据转换为数字数据,以便我们稍后可以识别它们。

数据准备

最后,我们需要使用我们定义的数据处理步骤来清理我们的数据,并使用 tokenized_data.py 将它们转换为令牌。这里,我们将把一个问答集作为输入。我们将应用文本清理步骤,最后,我们将通过我们预先训练的 word2vec 模型,为每个单词分配一个向量。然后,取单词向量的平均值来构成句子向量。

斯科特·格雷厄姆Unsplash 上拍照

这里,我们还需要定义聊天句子的开始和结束,以便模型可以理解特定句子的结束位置和句子的开始位置,这有助于我们的模型进行推理。

火车

最后,是时候训练我们的模型了。这里,我们将使用清理后的矢量格式数据将其传递给序列对序列模型。我们的模型将在所有对话中使用我们在开始时定义的批量数据进行训练。

Liam Charmer 在 Unsplash 上的照片

使用我们的语言翻译聊天机器人

现在,是时候使用我们训练好的模型了。但是,在使用它之前,我们需要定义一些函数来帮助我们清理输入数据,将其转换为向量,并将其传递给经过训练的语言翻译模型,并获得输出向量,我们将解码该向量以获得输出的翻译句子。

enc_model , dec_model = make_inference_models()

运行聊天机器人

因此,我们已经在我们创建的大量数据上训练了我们的模型。我们在不同的时代接受训练。现在,为了检查模型性能,我们可以开始给出输入,并观察我们从模型接收到的输出类型。这里,我使用一个循环向我们的模型提出 10 个语言翻译问题。我们的模型接受输入。清理输入,创建一个词向量,最后取词向量的平均值,生成一个句子向量。句子向量进入模型,模型作为输出提供另一个句子向量,我们解码并输出。

运行语言翻译

所以,现在我们有了语言翻译模型,可以将任何英语句子转换成印地语。我们也可以使用任何其他语言,代码也是一样的。

如何提高准确性

micha Parzuchowski 在 Unsplash 上的照片

模型的准确性取决于数据源和适合您的数据的模型使用类型。您拥有的数据越多,您就越能训练和验证您的模型。

所以,在这里。我们已经用 Python 建立了我们的语言翻译。用自己的数据,自己的语言去尝试。如有任何疑问,欢迎在评论区提问。快乐学习!

构建预测二手车价格的线性回归模型-现在使用日志!

原文:https://towardsdatascience.com/building-a-linear-regression-model-for-predicting-the-price-of-a-used-car-now-with-logs-54a478438d1?source=collection_archive---------10-----------------------

约翰·皮门塔尔在 Unsplash 上拍摄的照片

你的车值多少钱?

欢迎大家回到另一个激动人心的环节,建立一个线性回归模型来给你的二手车定价!我知道你看到这个结局有多激动。对于那些希望跳到实际工作模型的人,我已经把它上传到 Heroku 这里

我们叙叙旧吧。在我们这次旅程的第一篇文章中,我们从 Cars.com 收集了数据,稍微清理了一下,并对新清理的数据运行了一些 EDA。我们了解到一些汽车具有绝对可怕的零售价值,我们推测了零售市场中某些品牌的代表性。与此同时,我了解到一些有趣的事实:奔驰在转售市场上非常突出,因为奔驰车主倾向于租赁,因为他们希望每 3 年买一辆新车。日产代表了转售市场的很大一部分,因为日产将其年产量的 30%送给租车公司,而大多数其他汽车公司最多只给 10%。这意味着,如果这个有趣的事实是正确的,如果你要买一辆二手尼桑,那么你很有可能会买一辆在以前的历史中作为租赁的汽车。你可以在这里通读第一部分

我们的第二个博客致力于做一些探索性的关联,我们设法发现了一些有趣的关联。高城 _mpg 和高速公路 _mpg 与价格负相关,导致我推测 2019 年的人不太在乎节省油钱。这可能是由于与 2018 年相比,当年的平均燃料价格较低。我们还使用线性回归查看了一些初始运行,发现了一些有希望的 R 数,并取消了奢侈品作为一个新特征,以帮助平滑我们的模型。你可以在这里阅读所有这些。

我认为在这一点上,我们可以开始进入标准的线性回归工具箱。第一个也是最明显的工具是获取一个或多个变量的自然日志。自然对数的目的是减少偏斜数据的可变性。也就是说,如果您的数据到处都是,希望对其应用一个数学函数(如自然对数)将减少其可变性,从而使人们更容易确定模式。然而,你必须记住,一旦你创建了你的模型,你的自然日志,实际上所有的数据转换,必须被逆转,这样你才能产生真实的结果。

所以我们要做的第一件事是取目标变量价格的自然对数。让我们看看我们的模型现在是什么样子!

现在好了!那是一个好看的 R,不是吗?记录我们的价格,我们已经达到了最高的 R 值 0.752。让我们看看我们的剩余部分,好吗?

哦,伙计,我喜欢这个,现在它变得很有意义了。我几乎可以通过它画一条线,并考虑能够预测我可怜的二手车的价格!

为了让事情变得更有趣一点,我和我的伙伴决定尝试通过玩这些特性来微调我们的模型。我们为低里程的汽车创建了一个新功能,并将其设置为小于 7500 英里,以查看它是否会影响我们的模型。我们还喜欢我们创造的豪华功能,因为豪华在二手车定价中发挥了如此巨大的作用,所以为了简单起见,我们将它用于所有品牌,并重新运行我们的模型:

我们仍然有很大的 R 值,但低里程的 P 值是 0.844!这是一个可怕的 P 值。基本上,它告诉我们的是,增加低里程数在统计学上是无关紧要的!这意味着我们可以扔掉它,让我们看看没有它我们会得到什么,或者在功能创建方面进行实验,相同的价格日志,不低的里程数:

相同的 R 和我们的 P 值已经平静了很多。所以我们要用那个。我们的残值怎么办?

看起来相当不错!最终测试,让我们运行一些预测,看看它是如何摇出来的!

左:价格预测,右:残差

好吧,该死,我喜欢它的样子。它并不完美,没有一个模型会完全完美,但我认为我们已经创建了一个逻辑回归模型,它可以很好地估计我们假设的二手车的价格。

容易理解的数学部分

所以我运行了一个模型,它符合。我们已经经历了许多线性回归,我已经向你们展示了对统计学家、计算机科学家和数据科学家有意义的统计数据。如果你是数学新手,或者你只是对汽车感兴趣,我该如何让你更容易理解呢?所有这些只是为了推导系数,你可以在下面的 OLS 图表中看到。

看到这些系数告诉我们多少调整我们的预测价格的轨迹。所以比如我们看 city_mpg,系数是. 0134。也就是说,每 0134 city _ mpg 上涨,我们的价格就增加 1 美元。整个模型试图根据所有这些竞争因素重新定价。事实上,所有的线性回归都是为了创建一个数学公式,通过一组代表汽车价格的点来画一条线。这条线试图足够完美地拟合,使得它覆盖或位于路径上合理距离内的所有这些点。

那看起来像什么?因为所有的线性回归只是试图建立一个公式,我们有从建立模型中得到的系数,我们所要做的就是考虑每个系数,然后建立公式。看起来像这样:

使用这个公式,我们只需将我们知道的汽车价值乘以我们通过线性回归得出的系数,一旦我们完成公式,我们就有了预测的二手车价格!这太简单了,你可以用纸和笔来做!

在 Streamlit 前端应用程序这里上尽情体验吧!

结论

我们已经实现了我们设定的目标。我们有一个相当准确的线性回归模型,它将考虑汽车的特征,并以相当的准确度预测价格。在我看来,更有趣的是我们从 EDA 中获得的有趣见解。我的意思是,我很高兴我的合作伙伴和我能够创造一个模型,帮助人们正确地为他们的汽车定价,帮助人们对我来说是世界上最重要的事情之一。但是,举例来说,发现开奔驰的人大多是租车,这让我了解了很多开奔驰的人是什么样的。正是这些小事影响了我们看待周围世界的方式,这让我很高兴,我决定从事数据科学方面的职业。

在 PyTorch 上手工制作 LSTM

原文:https://towardsdatascience.com/building-a-lstm-by-hand-on-pytorch-59c02a4ec091?source=collection_archive---------3-----------------------

能够从零开始建立一个 LSTM 细胞使你能够在架构上做出自己的改变,并把你的研究带到一个新的水平。

LSTM 细胞图解—来源:https://upload . wikimedia . org/Wikipedia/commons/thumb/3/3b/The _ LSTM _ cell . png/300 px-The _ LSTM _ cell . png—2020 年 5 月 24 日获取

所有提到的代码都在下面的列表中或者在我们的回购中。

LSTM 细胞是深度学习的递归神经网络研究领域中最有趣的架构之一:它不仅使模型能够从长序列中学习,而且还为长期和短期记忆创建了一个数字抽象,能够在需要时用一个代替另一个。

在这篇文章中,我们不仅要浏览 LSTM 单元的架构,还要在 PyTorch 上手工实现它。

最后但同样重要的是,我们将展示如何对我们的实现做一些小的调整,以实现一些确实出现在 LSTM 研究领域的新想法,如窥视孔连接。

LSTM 建筑

LSTM 有翼被称为门控结构:一些数学运算的组合,使信息从计算图上的那个点流动或被保留。正因为如此,它能够在长期记忆和短期记忆之间“做出决定”,并对序列数据输出可靠的预测:

LSTM 单元格中的预测序列。注意,它不仅流过预测 h_t,还流过 c_t,它是长期记忆的代表。来源:https://medium . com/turing-talks/turing-talks-27-modelos-de-predi % C3 % A7 % C3 % A3o-lstm-df 85d 87 ad 210。访问时间:2020 年 5 月 24 日

我们将一部分一部分地讲述:

遗忘之门

遗忘门是输入信息和候选信息一起操作的门,作为长期记忆。请注意,在输入、隐藏状态和偏置的第一个线性组合上,应用了一个 sigmoid 函数:

忘记 LSTM 牢房的门。来源:https://medium . com/turing-talks/turing-talks-27-modelos-de-predi % C3 % A7 % C3 % A3o-lstm-df 85d 87 ad 210。访问时间:2020 年 5 月 24 日

这个 sigmoid 将遗忘门的输出从 0“缩放”到 1——通过将其乘以候选值,我们可以将其设置为零,这表示长时间记忆中的“遗忘”,或者设置为一个更大的数字,这表示我们从长时间记忆中记住了“多少”。

新长时记忆的输入门及其解决方案

输入门是包含在输入和隐藏状态上的信息被组合,然后与候选和部分候选 c'_t 一起操作的地方:

LSTM 池的输入门。来源:https://medium . com/turing-talks/turing-talks-27-modelos-de-predi % C3 % A7 % C3 % A3o-lstm-df 85d 87 ad 210。访问时间:2020 年 5 月 24 日

在这些操作中,决定了有多少新信息将被引入内存以及它将如何改变——这就是为什么我们使用一个双曲正切函数(“从-1 到 1 的标度”)。我们结合来自短时和长时记忆的部分候选项,并将其设置为候选项。

现在我们可以进入输出门了。

单元的输出门和隐藏状态(输出)

之后,我们可以收集 o_t 作为 LSTM 细胞的输出门,然后将其乘以已经通过适当操作更新的候选(长期记忆)的 tanh。网络的输出将是 h_t。

LSTM 电池的输出门。来源:https://medium . com/turing-talks/turing-talks-27-modelos-de-predi % C3 % A7 % C3 % A3o-lstm-df 85d 87 ad 210。访问时间:2020 年 5 月 24 日

最后,我们有:

LSTM 电池的方程式:

在 PyTorch 上实现它

为了在 PyTorch 上实现它,我们将首先进行适当的导入。

我们现在将通过从nn.Module继承来创建它的类,然后实例化它的参数和权重初始化,您将在下面看到(注意它的形状由网络的输入大小和输出大小决定):

设置参数

为了了解每个砝码的形状,让我们看看:

矩阵的输入形状为(batch_size,sequence_length,feature_length)-因此将乘以序列中每个元素的权重矩阵必须具有形状(feature _ length,output_length)。

序列中每个元素的隐藏状态(也称为输出)的形状为(batch_size,output_size),这在序列处理结束时会产生(batch_size,sequence_length,output_size)的输出形状。—因此,与其相乘的 weight_matrix 必须具有与单元格的参数 hidden_sz 相对应的形状(output_size,output_size)。

这里是权重初始化,我们使用的和 PyTorch 默认的一样:

前馈操作

前馈操作接收init_states参数,该参数是具有上述等式的(h_t,c_t)参数的元组,如果不引入,该参数被设置为零。然后,我们对保持(h_t,c_t)的每个序列元素执行 LSTM 方程的前馈,并引入它作为序列的下一个元素的状态。

最后,我们返回预测和最后的状态元组。让我们看看它是如何发生的:

现在和优化版本

这种 LSTM 在运算方面是正确的,但在计算时间方面不是很优化:我们分别执行 8 次矩阵乘法,这比以向量化的方式执行要慢得多。我们现在将展示如何通过将它减少到 2 个矩阵乘法来实现,这将使它更快。

为了进行这种操作,我们设置两个矩阵 U 和 V,它们的权重包含在 4 次矩阵乘法中。然后,我们对已经通过线性组合+偏置运算的矩阵执行门控运算。

通过矢量化运算,LSTM 单元的方程将为:

所以它的nn.Module类应该是:

优化的 LSTM 细胞等级

最后但同样重要的是,我们可以展示使用 LSTM 窥视孔连接来调整您的实现有多容易。

LSTM 窥视孔

LSTM 窥视孔对其前馈操作进行了细微调整,优化后的情况是:

有了 LSTM 的良好实现和优化实现,我们就可以添加窥视孔连接的选项,并做一些小的调整:

这样我们的 LSTM 就完成了。你可能想在我们的回购上看到它,并用我们的 LSTM 文本情感分析笔记本进行测试,我们准备用火炬 LSTM 内置层进行测试和比较。

结论

我们可以得出一个结论,尽管这是一种深度学习的禁忌,但是如果一步一步地完成,并且有干净和良好的编码,实际上很容易将它的操作执行成一个干净、易于使用的nn.Module。我们也看到了改变和调整它的连接来完成像窥视孔连接这样的操作是多么容易。

参考

[## piEsposito/py torch-lstm-手工

一个关于如何制作 LSTM 神经网络的小而简单的教程。PyTorch 上的手工模块。记得执行 bash…

github.com](https://github.com/piEsposito/pytorch-lstm-by-hand) [## 了解 LSTM 网络

2015 年 8 月 27 日发布人类不是每秒钟都从零开始思考。当你读这篇文章时,你…

colah.github.io](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) [## LSTM 神经网

机器学习

medium.com](https://medium.com/turing-talks/turing-talks-27-modelos-de-predição-lstm-df85d87ad210)

用 Scikit-Learn 构建机器学习管道

原文:https://towardsdatascience.com/building-a-machine-learning-pipeline-3bba20c2352b?source=collection_archive---------14-----------------------

数据科学

使用 scikit-learn 构建简单管道的分步指南

马库斯·斯皮斯克在 Unsplash 上的照片

数据科学项目需要迭代进展。例如,我们清理和准备用于建模的数据,将其转换为适当的格式,运行模型,获得结果,改进模型/更改模型,进行特征工程,获得新的结果,将它们与其他结果进行比较,等等。把每一步都做一遍又一遍,不容易,也不聪明。为了解决这个问题,我们可以使用管道来集成机器学习工作流的步骤。

管道对于快速转换和训练数据非常有用。此外,我们可以通过在管道中集成网格搜索来比较不同的模型和调整超参数。在本文中,我将讲述如何在 scikit 中创建管道——学习展示管道的神奇世界。

制作管道的方法有很多,但我将在这篇博客中展示其中一种最简单、最聪明的方法。

要使用 scikit-learn 的管道功能,我们必须导入管道模块。

from sklearn.pipeline import Pipeline

通过使用(键,值)对的列表,可以构建管道。这里,键是一个字符串,其中包含您要给出的名称,值是 estimator 对象。非常简单的示例代码,显示如何使用;

estimators = [('reduce_dim', PCA()), ('clf',SVC())]pipe = Pipeline(estimators)

更多细节,你可以查看 scikit-learn 文档

构造管道的简写:make_pipeline 函数

“make_pipeline”是一个实用函数,是构造管道的简写。它接受可变数量的估计,并通过自动填充名称来返回管道。

我想在示例中解释管道的用法,因为我认为,当我们看到代码中模块的应用时,更容易理解。在现实生活中,数据集通常由数字列和分类列组成。我们必须用不同的技术改造这些柱子。当我们使用缩放器缩放数字列时,我们应该用编码器对分类列进行编码。第一次进行这种转换很容易,但通常,在数据科学项目中,我们会尝试不同的缩放器和编码器。为了快速简便地实现这一点,我们使用了管道。

在我的一个项目中,我用分类技术预测了坦桑尼亚水井的状况。我对管道使用了不同的缩放器、编码器和分类模型。如果你想看完整的带数据的木星笔记本,以及如何在建模过程中使用管道,可以在我的 Github 上找到这里。项目中的管道示例;

步骤 1:导入库和模块

我在这里只展示如何导入管道模块。但是当然,我们需要导入我们计划使用的所有库和模块,比如 pandas、NumPy、RobustScaler、category_encoders、train_test_split 等。

**from** **sklearn.pipeline** **import** make_pipeline

第二步:读取数据

df = pd.read_csv('clean_data.csv')

第三步:准备数据

如果您的数据包含一些无意义的要素、空值/错误值,或者需要任何类型的清理过程,您可以在此阶段进行清理。因为数据的质量影响模型的质量。在这篇博客中,我的目的是展示管道过程,所以我跳过这一部分,使用我的数据的清理版本。

步骤 4:定义分类和数字列

cat_col = ['basin','region','extraction_type_group','management','payment','water_quality','quantity','source','waterpoint_type','decade','installer_cat','funder_cat']

num_col = ['gps_height','longitude','latitude','district_code','population','public_meeting','permit']

步骤 5:分割特征/目标和训练/测试数据

target='status_group'used_cols = [c **for** c **in** df.columns.tolist() **if** c **not** **in** [target]]
X=df[used_cols]
y=df[target]X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

步骤 6:制作管道和建模

*# making pipeline*scaler = RobustScaler()
encoder = ce.TargetEncoder(cols=cat_col)*# putting numeric columns to scaler and categorical to encoder*
num_transformer = make_pipeline(scaler)
cat_transformer = make_pipeline(encoder)

*# getting together our scaler and encoder with preprocessor*
preprocessor = ColumnTransformer(
      transformers=[('num', num_transformer, num_col),
                    ('cat', cat_transformer, cat_col)])

*# choosing model*
model_name = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42)

*# giving all values to pipeline*
pipe = make_pipeline(preprocessor,model_name)
pipe.fit(X_train, y_train)

*# make predictions on training set*
y_pred = pipe.predict(X_train)

*# make predictions on test set*
y_pred_test = pipe.predict(X_test)

*# to print the results in good way*
print("Accuracy:"); print("="*len("Accuracy:"))
print(f"TRAIN: {accuracy_score(y_train, y_pred)}")
print(f"TEST: {accuracy_score(y_test, y_pred_test)}")

print("**\n**Balanced Accuracy:"); print("="*len("Balanced Accuracy:"))
print(f"TRAIN: {balanced_accuracy_score(y_train, y_pred)}")
print(f"TEST: {balanced_accuracy_score(y_test, y_pred_test)}")

在这个例子中,我们可以看到,我们可以添加功能到我们的管道,如预处理器,其中包含缩放器和编码器。针对不同的问题,我们还可以在流水线中增加更多的函数。这有助于以快速简单的方式转换我们的数据。在这个例子中,make_pipeline 函数自动将 scaler、encoder 和我们的模型应用到管道中,我们可以非常轻松地对其进行拟合。

当我们写一个函数,把我们的管道放在这个函数中并返回结果时,改变模型也是非常容易的。对于这个例子,当我们只改变 model_name 来尝试另一个分类模型并运行调用相应函数的单元时,它很容易在管道内得到结果。简而言之,我们不需要为了转换数据而改变数据集。我们可以在管道中进行每一次转换,并保持我们的数据集不变。

我们也可以使用 make_pipeline 来集合数值列的估算器和缩放器;

# Imputing nulls and scaling for numeric columns
num_imputer = SimpleImputer(strategy='median')
scaler = RobustScaler()# Imputing nulls through the encoding for categorical columns
encoder = ce.TargetEncoder(cols=cat_cols, handle_missing="value")# Defining different transformers for numeric and categorical columns
num_transformer = make_pipeline(num_imputer, scaler)
cat_transformer = make_pipeline(encoder)*# getting together our scaler and encoder with preprocessor*
preprocessor = ColumnTransformer(
      transformers=[('num', num_transformer, num_col),
                    ('cat', cat_transformer, cat_col)])

*# choosing model*
model_name = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42)

*# giving all values to pipeline*
pipe = make_pipeline(preprocessor,model_name)

在这个例子中,我还在我的管道中添加了 imputer。如您所见,当我们构建一个好的管道而不需要手动转换数据时,添加和更改模块是非常容易的。

结论:

管道的目的是在设置不同参数时,将几个可以交叉验证的步骤组合在一起。通过收集这些步骤,可以帮助我们轻松地添加新参数或对模型进行更改。此外,它使我们的代码更具可读性和可理解性。通过建立一个可理解的工作流程,它有助于项目的可重复性。通过使用管道,我们不需要在流程开始时转换数据。Pipeline 为我们完成所需的转换,并保留原始数据。

其他资源:

如果您想深入了解 scikit-learn 库文档,这里有一些有用的链接。

[## 6.1.管道和复合估计器-sci kit-了解 0.23.2 文档

转换器通常与分类器、回归器或其他估计器结合,以构建复合估计器。的…

scikit-learn.org](https://scikit-learn.org/stable/modules/compose.html) [## sk learn . pipeline . pipeline-sci kit-learn 0 . 23 . 2 文档

具有最终估计器的变换流水线。依次应用一系列转换和一个最终估计器…

scikit-learn.org](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html)

如果您对本文有任何反馈或建议,请随时通过 LinkedIn 与我联系。

构建机器学习管道—第 1 部分

原文:https://towardsdatascience.com/building-a-machine-learning-pipeline-part-1-b19f8c8317ae?source=collection_archive---------48-----------------------

使用软件包 fast_ml

照片由 JJ 英Unsplash

以下是构建 ML 管道的常用步骤:

  1. 输入数据
  2. 探索性数据分析
  3. 缺失值插补
  4. 异常值处理
  5. 特征工程
  6. 模型结构
  7. 特征选择
  8. 模型解释
  9. 保存模型
  10. 模型部署*

问题陈述和获取数据

我用一个相对更大更复杂的数据集来演示这个过程。参考 Kaggle 竞赛— IEEE-CIS 欺诈检测

导航到数据浏览器,您会看到类似这样的内容:

选择 train_transaction.csv ,它将向您展示数据的大概情况。单击红色箭头突出显示的下载图标获取数据。

除了通常的库导入语句,您还需要检查另外两个库——

安装 pyarrow

pip 安装快速 _ml

主要亮点

这是构建机器学习管道系列的第一篇文章。在本文中,我们将重点关注关于在 Jupyter notebook 中导入数据和更快执行的优化。

这篇文章中有 3 个关键点需要注意—

  1. Python zipfile
  2. 减少数据集的内存使用量
  3. 保存/加载工作数据集的更快捷方式

1:导入数据

下载压缩文件后。使用 python 来解压文件要好得多。

提示 1:****se 函数从 python 的 zipfile 库中解压文件。

***import zipfile**with zipfile.ZipFile('train_transaction.csv.zip', mode='r') as zip_ref:
    zip_ref.extractall('data/')*

这将创建一个文件夹data并在该文件夹中解压缩 CSV 文件train_transaction.csv

我们将使用 pandas read_csv方法将数据集加载到 Jupyter 笔记本中。

*%time trans = pd.read_csv('train_transaction.csv')df_size = trans.memory_usage().sum() / 1024**2
print(f'Memory usage of dataframe is {df_size} MB')print (f'Shape of dataframe is {trans.shape}')---- Output ----
CPU times: user 23.2 s, sys: 7.87 s, total: 31 s
Wall time: 32.5 sMemory usage of dataframe is 1775.1524047851562 MB
Shape of dataframe is (590540, 394)*

该数据约为 1.5 GB,包含 50 多万行。

技巧二:我们将使用 fast_ml 中的一个函数来减少这种内存占用。**

***from fast_ml.utilities import reduce_memory_usage**%time trans = reduce_memory_usage(trans, convert_to_category=False)---- Output ----
Memory usage of dataframe is 1775.15 MB
Memory usage after optimization is: 542.35 MB
Decreased by 69.4%CPU times: user 2min 25s, sys: 2min 57s, total: 5min 23s
Wall time: 5min 56s*

这一步花了将近 5 分钟,但是它将内存大小减少了将近 70%,这是一个相当显著的减少

为了进一步分析,我们将创建一个包含 20 万条记录的样本数据集,这样我们的数据处理步骤就不会花费很长时间。

**# Take a sample of 200k records*
%time trans = trans.sample(n=200000)#reset the index because now index would have shuffled
trans.reset_index(inplace = True, drop = True)df_size = trans.memory_usage().sum() / 1024**2
print(f'Memory usage of sample dataframe is **{**df_size**}** MB')---- Output ----
CPU times: user 1.39 s, sys: 776 ms, total: 2.16 s
Wall time: 2.43 s
Memory usage of sample dataframe is 185.20355224609375 MB*

现在,我们将把它保存在本地驱动器中— CSV 格式

***import** **os**os.makedirs('data', exist_ok=True) trans.to_feather('data/train_transaction_sample')*

技巧三:使用羽化格式代替 csv**

***import** **os**os.makedirs('data', exist_ok=True)
trans.to_feather('data/train_transaction_sample')*

一旦从这两个来源加载数据,您将会看到显著的性能改进。

加载保存的样本数据— CSV 格式

*%time trans = pd.read_csv('data/train_transaction_sample.csv')df_size = tras.memory_usage().sum() / 1024**2
print(f'Memory usage of dataframe is **{**df_size**}** MB')
print (f'Shape of dataframe is **{**trans**.**shape**}**')---- Output ----
CPU times: user 7.37 s, sys: 1.06 s, total: 8.42 s
Wall time: 8.5 sMemory usage of dataframe is 601.1964111328125 MB
Shape of dataframe is (200000, 394)*

加载保存的样本数据—羽毛格式

*%time trans = pd.read_feather('tmp/train_transaction_sample')df_size = trans.memory_usage().sum() / 1024**2
print(f'Memory usage of dataframe is **{**df_size**}** MB')
print (f'Shape of dataframe is **{**trans**.**shape**}**')---- Output ----
CPU times: user 1.32 s, sys: 930 ms, total: 2.25 s
Wall time: 892 msMemory usage of dataframe is 183.67779541015625 MB
Shape of dataframe is (200000, 394)*

注意这里的两件事:

I .加载 CSV 文件所花费的时间几乎是加载羽毛格式数据所花费时间的 10 倍。

二。加载的数据集的大小以羽化格式保留,而在 CSV 格式中,数据集再次消耗大量内存,我们将不得不再次运行 reduce_memory_usage 函数。

感谢阅读!

  • 如果你喜欢这个,在 medium 上跟随我了解更多。
  • 你们的掌声对写更多、写得更好是一个巨大的鼓励和帮助。
  • 有兴趣合作吗?我们在 Linkedin 上连线吧。
  • 请随意写下您的想法/建议/反馈。
  • 我们将使用我们创建的新样本数据集进行进一步分析。
  • 我们将在下一篇文章中讨论探索性数据分析。
  • Github 链接

建立反向传播的心智模型

原文:https://towardsdatascience.com/building-a-mental-model-for-backpropagation-987ac74d1821?source=collection_archive---------27-----------------------

通过用 Python 实现自己的深度学习框架

安德烈·韦莱在 Unsplash 上拍摄的照片

作为深度学习的跳动的心脏,任何深度学习实践者都需要对反向传播有坚实的理解。虽然互联网上已经有很多解释反向传播的好资源,但大多数都是从非常不同的角度来解释的,并且每个都适合特定类型的受众。在这篇文章中,我将把直觉、动画图和代码结合在一起,供深度学习的初学者和中级水平的学生更容易使用。对任何算法的理解的一个好的评估是你是否能从头开始自己编码。看完这篇文章后,你应该知道如何用 Python 实现你自己版本的反向传播。

实值电路和校正力

从数学上讲,反向传播是通过应用链式法则来计算函数分量梯度的过程。在神经网络的情况下,感兴趣的函数是损失函数。我喜欢 Andrej Karpathy 在 CS231n 中的解释:把计算图看成是带有逻辑门的实值电路。门是函数中的运算,例如加、乘、取幂、矩阵乘法等。

来源:https://cs231n.github.io/optimization-2/

这是一个很好的心理模型,因为它意味着反向传播是一个局部过程。电路中的每个门都可以计算其输出和局部梯度,而无需了解全局。

在反向传递(反向传播)期间,门应用链规则,即,在电路的最终输出上取其输出的梯度,并将其乘以关于其所有输入的局部梯度。可以使用递归方法从电路的输出返回到所有输入来实现反向传递。

直观上,反向传播及其相关权重更新的最终效果是,电路“想要】输出一个更接近我们所拥有的任何目标值的值。以上图中加法门(-4)的梯度为例,意思是将 q 改变+1ε会导致 f 中-4ε的变化。如果我们想要更高的 f 值,我们可以把 q 值降低。这就是梯度的本质。人们有时称之为“敏感”。另一个很好的类比是修正力。梯度的符号表示校正的方向,大小表示强度

从函数到计算图

可视化反向投影的最好方法之一是绘制函数的计算图。让我们看看下面这个奇怪的函数,演示如何绘制它的计算图,然后手动反向投影。( σ()是 sigmoid 函数)

为了计算其梯度,我们可以将其分解为加法、s 形、正方形门,如下面的动画步骤所示:

具体来说,该流程包括 3 个高级步骤

  1. 从操作(门)构建计算图
  2. 在每个操作中运行正向传递
  3. 基于(1)正向过程中计算的值和(2)每个门的反向函数运行反向过程,以计算其局部梯度

您可以跟随并手动计算这些值。我将在最后一节展示如何实现它,但是现在让我们来看一个技巧,它将帮助我们简化这个过程。

分阶段计算

任何一种可微函数都可以充当一个门,我们可以在方便的时候将多个门组合成一个门

因为我们不应该明确地解析求解梯度,所以这些函数分量的选择就成了一个需要考虑的问题。以 sigmoid 函数为例:

我们可以将其分解为加法、乘法、求反、取幂和倒数门,如下图所示:

资料来源:https://cs231n.github.io/optimization-2/

一个简单的乙状结肠已经有这么多的运算和梯度,这似乎是不必要的复杂。我们可以做的另一件事就是将一个 sigmoid gate 与计算其梯度的函数一起应用于红框的输出。乙状结肠的坡度非常简单:

这样我们避免了许多不必要的计算。它节省了我们的时间、空间和能量,使代码更加模块化和易于阅读,并避免了数值问题。

乙状结肠门的代码可能类似于:

它既有向前传递的输出,又有计算向后传递的局部梯度的功能,只需几行代码。在下一节中,我将把它放到更大的图片中,并展示如何用这样的组件编写一个迷你的亲笔签名的库。

亲笔签名:递归方法

要让计算机使用链规则计算任何用有向无环图(DAG)表示的函数的梯度,我们需要为前面提到的 3 个高级步骤编写代码。这样的程序通常被称为自动分化或自动签名。正如您接下来将看到的,我们可以将代码组织成一个定义数据和操作的Tensor类,这样它不仅可以支持动态构建动态计算图,还可以递归地反向传播。

向前传递:构建图表

卡帕西显微图中的代码

一个张量对象有datagrad、一个_backward()方法、一组_prev张量节点和一个_op操作。当我们执行一个表达式时,它会动态构建计算图,因为我们已经用定制的 dunder 方法覆盖了 Python 操作符,如+***。当前张量的_backward()_prev_op由其父张量定义,即产生它的张量。例如c = a + b中的c__add__中定义的_backward(),还有_prev = {a, b}_op = '+'。这样我们就可以定义任何我们想要的操作,并让 Python 来构造图形。

这里说的是神经网络,所以我们关心的表达式是损失函数。以 MSE 损失为例(为简单起见,使用 1 个标量数据点),MSELoss = (w*x - y)**2其中wxy为张量对象,分别初始化为 3、-4 和 2。然后,图形会自动构建为:

注意减法其实就是否定和加法。我命名中间节点只是为了便于说明。有了图形,我们就可以实现反向投影了!

向后传递:拓扑排序

卡帕西显微图中的代码

backward应该从当前张量节点开始逐个计算梯度,并移动到其祖先。遍历的顺序需要进行拓扑排序,以确保每一步都计算了依赖关系。实现这种拓扑排序的一个简单方法是深度优先搜索。这里有一个动画来展示如何在 MSELoss 示例中执行它。

这是图遍历 101:一个普通的老 DFS。如果你有一个大型复杂的神经网络,你只需用你的大图替换左上角的wx,并且假设所有的操作和它们的_backward都在Tensor类中定义,那么 DFS 将会去那里计算梯度。这里我们需要的一些显而易见的操作包括maxsum、矩阵乘法、转置等。要使用渐变来更新权重,请执行以下操作:

for p in <your_parameters>:
    p.data -= learning_rate * p.grad

就这样,几行代码中的亲笔签名算法。它是任何深度学习框架的支柱。现在,困难的部分已经过去了,要完成您的 mini 深度学习框架的实现,您只需要实现一个模型接口,其中包含层类型、损失函数和一些优化器的集合。

推荐读物

这篇文章的灵感很大程度上来源于 Andrej Karpathy 令人敬畏的 CS231n 讲座和漂亮的文字微图:最小的亲笔签名引擎。如果你想看看一个 DIY 深度学习框架的不同和更扩展的版本,它非常类似于 PyTorch,请查看 Andrew Trask 在 Grokking Deep Learning 中实现的那个。如果你更喜欢直接阅读 PyTorch 的亲笔签名,埃利奥特·韦特在 Youtube 上有一个很棒的视频,它将为你节省大量钻研源代码的时间。坚持学习!

参考

看我在 上的其他帖子 ,或者关注我在 上的推特

构建现代分析堆栈

原文:https://towardsdatascience.com/building-a-modern-analytics-stack-966b0525dbc5?source=collection_archive---------23-----------------------

美国宇航局在 Unsplash 拍摄的照片

各行各业各种规模的公司都很快认识到,为了保持竞争力,他们必须接受一种文化,在所有业务中,决策都以数据为依据,并快速做出。这可以是在管理层,BI 仪表板用于监控公司的整体健康和绩效,分析师通过查询多个来源的数据来寻找见解,或者工程师在公司数据的基础上构建机器学习工具和智能自动化应用程序。

随着数据量和使用案例的增加,组织、集成和管理数据访问变得更加困难,在较小规模下有效的工具和流程不再有效。试图处理数据并将其嵌入整个组织的公司需要一个强大的基础架构,能够快速、轻松地提供数据。随着数据规模的增长,他们需要考虑指导数据管理的框架。这项工作的一个重要部分是建立分析堆栈。

什么是分析堆栈?

分析堆栈是作为集成系统的一部分执行特定流程的一组工具。通过组合执行简单过程的工具,如存储来自多个来源的数据、合并和转换数据以及可视化数据,我们能够组装更复杂的行为。通过使用具有特定功能的工具,您可以获得可定制性和可互换性的好处。这意味着,例如,当您的数据存储需求急剧增加,而您当前的存储解决方案变得太贵或太慢时,您可以轻松替换堆栈中的该层,或者添加满足您需求的新层,而不必替换整个堆栈。

如今的数据分析堆栈有什么问题?

如今,大多数公司都在一系列应用程序上运营,如用于 CRM 的 Salesforce、用于在线销售的 Shopify、用于 ERP 的 Workday、用于收集、组织和可视化数据的 Microsoft Excel 以及用于存储和共享数据的 Sharepoint。这些工具对于业务任务来说非常棒,但是对于分析来说却变得非常有限。您很快意识到 Excel 电子表格对于存储或操作大量数据来说效率不高,或者对 Sharepoint 的不同访问级别会导致孤立的数据,而其他团队无法利用这些数据来构建他们的用例。至少,你会发现有些人使用来自 Salesforce 和 Hubspot 等工具的自动化报告和仪表盘。这样做的最大问题是,您无法跨应用程序合并数据来构建自动化工具或进行高级分析。此外,这些服务提供了汇总和聚合级别的数据,如果您想深入了解细节或比较不同时间的数据,这是没有帮助的。

那些对构建可靠的分析基础设施不够重视的公司意识到,数据分析师和科学家在 ETL 等基本数据处理和管理任务上分配的时间不均衡。软件公司 Jetbrains 的一项调查显示,分析团队中高达 75%的成员最终从事这些任务,而不是商业智能、数据科学或机器学习,这些才是分析的真正附加值。

那些已经采取下一步措施,通过内部部署数据仓库、数据集成工具和 BI 来构建分析基础架构的公司面临着自己的挑战。硬件服务器需要大量的 IT 参与,难以维护,并且需要很长时间来证明其价值。此外,高昂的设置成本使得随着需求的变化很难互换解决方案,并且随着时间的推移,对于许多公司来说,这是一个负担不起和难以扩展的障碍。

AWS 和 Azure 等云计算平台的兴起及其基于使用的数据仓库、集成和高级分析产品的成本,减轻了设置的重大负担,并大大缩短了分析的价值实现时间。下一阶段的 SaaS 和云分析公司(如 Snowflake、Stitch 和 Looker)进一步推动了这一趋势,这些公司提供自助服务技术,这些技术非常容易设置和运行,并且彼此无缝集成。

现代分析堆栈

为了建立一个功能性的数据操作,一个组织通常需要将几个服务组合成一个数据栈。从根本上说,有效的数据堆栈将使执行三种基本操作成为可能,包括从许多来源收集数据并将其吸收到存储系统中,为各种用例清理和转换数据,以及最终将转换后的数据用于可视化或机器学习等分析的增值部分。这三个过程都是数据管道的一部分。您在每个流程中使用的工具构成了分析堆栈。根据公司的需求,数据管道的架构可能会有所不同,但它们在上述主要流程中都有共同点,如下图所示。

分析数据管道

我们将详细介绍每个流程的功能,并列出一些可用的流行云平台。

数据接收和转换

任何分析项目的最初挑战都是使来自多个孤立数据源的数据可用。这些可能是您的 SaaS 工具、企业应用程序、应用程序数据库、来自您的 IOT 系统的遥测数据,也可能是许多其他来源。有许多云优先工具越来越受欢迎,用于将数据从源移动到目标,如 StitchFivetran 。这些工具可以从 100 多个来源移动数据,包括公司使用的最流行的应用程序和数据库。但是一些公司可能需要自己的方法或途径来收集数据,也有很多编程工具来帮助这一点。例如, Singer 是一个开源工具,可用于编程连接器,在任何自定义源和目标(如 web APIs 和文件)之间发送数据。

实时流

分析中的一些主要用例,如检测信用卡欺诈,依赖于实时数据流。不断生成新数据的应用程序可以使用流式 API 将数据推送到接收方,也可以由接收方应用程序从队列中或通过对 API 的轮询请求来提取数据。像 Stitch 这样的工具可以用来在很短的时间间隔内轮询数据,以模拟实时流,但像 Apache Kafka 和 Amazon Kinesis 这样的流处理服务是专门为处理实时数据馈送而设计的。你可以在这里阅读一篇关于如何使用亚马逊 Kinesis 的文章。

ETL

一旦建立了数据接收流程,您将需要决定是以原始形式存储数据,还是将数据转换为更有利于分析的形式。这将取决于原始数据的有用程度。在将数据加载到数据存储器之前,您可能希望清理并统一不完整、混乱或不相关的数据。此外,数据的格式可能与您的存储解决方案不兼容;例如,您可能希望从 API 中展平嵌套的 JSON 对象,以便可以将它们存储在数据库中。

提取、转换、加载

在存储数据之前对其进行转换的过程称为 ETL(提取、转换、加载)。有很多云 ETL 工具,其中 Talend 和 Matillion 是著名的例子。

ELT

另一方面,您可以选择在将原始数据加载到存储提供程序后立即对其进行转换。这就是所谓的 ELT(提取、加载、转换)。这种方法允许来自许多来源的原始数据的历史可用于更广泛的分析用例。 DBT 是一款开源工具,因为它将工程最佳实践与分析相结合,所以在英语教学中非常流行。

提取、加载、转换

许多现代分析架构更喜欢 ELT 方法,因为它增加了管道中的灵活性。有了像雪花数据仓库这样允许存储和查询半结构化数据的存储解决方案,这变得更加容易。但是,这不是选择 ETL 还是 ELT 的问题,因为根据公司的需要,两种方法的组合可能是正确的。

数据库

数据分析堆栈的下一部分是数据存储平台。最流行的策略是将来自所有数据源的数据放入一个公共存储库中,在那里可以针对各种用例对数据进行转换和组合。最流行的数据存储解决方案是数据仓库——它们将原始数据和转换后的数据存储在数据库中,便于公司内的不同团队访问。传统上,数据集市一直是将特定领域(如人力资源和财务)的数据管理到他们自己的数据库和服务器中的流行解决方案,但代价是被孤立。云数据仓库的革命和像雪花AWS 红移谷歌 BigQuery 这样的平台正在彻底打破这种模式。例如,雪花越来越受欢迎,因为它的架构将存储和计算资源分开。随着存储成本的大幅降低,雪花的分离架构使公司能够廉价地存储来自所有来源的大量原始数据,并将计算资源仅用于转换分析用例的数据。阅读这篇关于如何建立雪花架构的文章。

另一种方法是将目前没有任何特定目的的原始数据存储到数据湖中。数据湖不像数据仓库那样是基于关系 SQL 的平台,在概念上与数据集市完全相反。数据湖是一般数据的广泛存储,它允许任何类型的数据,无论是结构化的还是非结构化的,都可以在没有任何组织的情况下存储。虽然它们很难导航,但它们有利于轻松启动新的分析用例和数据科学探索。AWS S3 和 Azure Blobs 就是数据湖的一些例子。然而,像雪花这样的平台也结合了数据湖的优势,使用 S3 这样的云存储作为他们的存储解决方案,使雪花的存储成本一样低。此外,凭借其存储半结构化数据和自动优化数据以进行存储和查询的能力以及其他功能,像雪花这样的解决方案可以替代许多分析堆栈中的数据湖。

数据分析和机器学习

在分析堆栈中,分析位于层次结构的顶部。对于每一个分析用例,团队都希望制定出相关的目标指标和 KPI。然后,他们可以选择在数据仓库中建模和存储数据以服务于用例,或者在数据进入他们选择的分析工具后建模数据。选择使用哪种分析工具取决于正在执行哪种活动以及用户是谁。这些用户可能是业务团队、产品和工程团队或数据团队。

商业智能是大多数公司最常见的分析用例。从根本上说,BI 为用户提供了一种分析业务运营的历史、当前和预测视图的简单方法。要选择 BI 工具,我们必须首先缩小用例范围。公司现在认识到,为业务线用户和高管提供 BI 仪表板有很大的好处。控制面板让终端用户能够自助获取能够影响利润的见解。它们还提供具有数据过滤器等功能的即席分析,以及分组或隔离数据以发现有趣趋势的能力。像 Chartio 和 Microsoft PowerBI 这样 BI 平台的例子也非常容易为业务团队部署,而不需要持续的 IT 参与。建立后,业务用户可以轻松地将 BI 平台连接到数据仓库中满足其需求的模型数据。此外,许多公司也在寻找将分析工具集成到现有应用程序和整体业务流程中的方法。嵌入式分析工具通过允许开发人员将可视化嵌入到应用程序中来提供这些功能。Sisense 是一个平台的例子,它帮助开发者使用 API 将定制分析构建到任何类型的应用中。

高级分析的部署频率仍然较低,但它们可能是一些让公司脱颖而出的最高价值活动。数据科学是将更复杂的统计技术和建模应用于大量结构化和非结构化数据以生成预测性或规范性见解的活动之一。数据科学涉及大量探索性工作,因此数据科学家通常使用查询工具进行初始数据探索,然后构建连接到数据仓库的自定义程序来提取数据,或者与 RapidMiner 等平台集成,为挖掘和预测分析工作提供集成环境。机器学习是数据科学工作的延伸,其中建模数据被输入到 AWS SageMaker 或数据机器人等服务中,以训练、评估和部署模型。然后,这些模型被集成到公司的现有产品中,以实现面向客户的功能,如推荐引擎,与现有的分析工具一起用于增强分析,如流失预测,或者作为智能自动化应用的一部分,如服务器负载的预测性维护。由于高级分析和机器学习下的用例范围巨大,很难缩小几个工具的范围。与 BI 不同,高级分析可以有自己非常复杂的架构,但分析堆栈的数据处理和数据仓库组件保持不变。

最后的想法

从依赖孤岛式应用程序进行基本分析转变为构建自己的堆栈可能是一项重大任务。我们已经为您应该如何考虑堆栈中的组件提供了指南。如果您的公司刚刚开始这一旅程,那么知道没有放之四海而皆准的工具是很重要的。此外,随着数据的增长,适用于您当前使用情形的工具可能需要改变。因此,您的分析堆栈将不断发展。无论您处于哪个阶段,都要仔细考虑一下哪些工具能很好地满足您目前的需求,但在未来是可扩展的或可互换的。

您的分析堆栈需要帮助吗?通过 LinkedIn 联系。

构建无需更新的现代批量数据仓库

原文:https://towardsdatascience.com/building-a-modern-batch-data-warehouse-without-updates-7819bfa3c1ee?source=collection_archive---------4-----------------------

Unsplash 上由 Helloquence 拍摄的照片

功能数据工程|星形模式

创建没有更新、锁定或 ACID 合规性的星型模式

在这篇文章中,我将描述如何设计维度事实以及在不执行可变变更的情况下为其提供信息的流程。

出于本文的目的,我将假设数据在一个便宜的云存储上,由一个直接操作文件的计算引擎处理,并写入不可变的块中。

了解大数据堆栈中的事务性、更新和锁定选项。Databricks 和 Snowflake 围绕提供这些服务(以及更多服务)建立了非常成功的企业。Databricks 甚至开源了“ Delta Lake ”,为 Apache Spark 带来了其中的一些功能。

然而,更新是大数据堆栈中复杂的操作。我相信保持我们的大部分数据处理不变是更容易维护和推理的。

更新可能会给数据管道带来不必要的灵活性。我见过一个团队只通过(非常低效的)更新来扩展另一个团队拥有的表,而不是协作和扩展公共脚本。不变性迫使数据管道具有某种结构

我将从高层次描述星型模式概念开始,并解释为什么它们今天仍然相关。如果你熟悉这些概念,我邀请你跳到“管理维度”

星形模式

星型模式是一种关系建模技术,它将与业务流程相关的度量或事件(事实)从其上下文(维度)中分离出来。

与关系数据库模式(应用程序数据库)相比,它更加非规范化,并且被设计为对分析查询( OLAP 工作负载)高效。

举例:

在电子商务网站中,业务流程的一个例子是网站上的交易。

在这种情况下,一些示例度量是:交易期间支付的金额和购买的产品数量。

上下文包括:进行交易的用户、交易日期和购买的产品。

简化星形模式提取

实际上,每个交易可能包含不同的产品:这是一个简化的模型

星型模式的名字来源于物理模型与星型的相似性,星型的中心有一个事实表,周围的维度表代表星型的点

https://en.wikipedia.org/wiki/Star_schema

雪花模式

维度可以进一步规范化:例如,产品的“品牌”可以保存在一个单独的表中,该表具有与“产品”的外键关系,从而创建一个从维度到维度的关系。

星型模式维度的进一步规范化导致了“雪花模式”,从历史上看,其主要目标是减少冗余数据量(节省存储)。

缺点是雪花模式通过更多的连接引入了更多的复杂性。随着存储变得不那么受关注,对于大多数情况来说,“雪花模式”方法是不合适的。

大数据中的星型模式相关性

星型模式是在存储和计算昂贵的时代创建的。因为存储昂贵且有限,减少数据冗余是数据仓库团队的主要关注点。

这也是支持数据仓库查询的有效方式,因为通过维度表的连接和过滤器,可以跳过事实表上的大量数据。可预测的访问模式允许简单的优化,比如在事实表的外键上创建索引。

简洁明了—所有外键列都应该有一个非聚集的非唯一索引。

https://www . data vail . com/blog/how-to-index-a-fact-table-a-best-practice/

如今,存储很便宜,并且根据需要配置计算能力(相对而言)很容易。我们可以衡量设计和实现这些模型的工程成本与节省的硬件成本,并问自己— 这样做还值得吗?

照片由阿齐兹·阿查基Unsplash 上拍摄

为什么星型模式仍然相关?

多样的来源

公司从越来越多的来源收集越来越多的数据,需要对产生的数据集进行协调以进行分析。

例如,有线电视网络可能有非常不同的系统来托管有关其电视订户和其新推出的流媒体服务的订户的信息。同样,他们的“客户支持”分析必须整合来自 Twitter、第三方呼叫中心和支持电子邮件的数据。

标准化工作的目标是汇集“订户”、“客户反馈”和其他逻辑实体的不同定义,消除否则将由异构源系统引入的分析复杂性。

标准

Ralph Kimball 编写的数据仓库工具包(1996)和 Kimball 集团网站定义了业内广泛理解的概念(如星型模式)。

新员工可以快速掌握数据仓库结构,而不需要熟悉组织的具体情况。

数据工程师、数据科学家和分析师有共同的术语(事实、维度、粒度),有助于协作。

展开性

新添加的事实可以重用现有的维度。

通过向事实表添加更多的外键,可以向事实添加新的维度。

因此,可以集成新的数据集,而无需对模式进行重大更改。

表演

星型模式可以完全通过在 Map-Reduce 框架中容易并行化的插入和计算来填充(我们将在下一节中看到“如何进行”)。

查询性能调优:

虽然外键索引通常不是一个选项,因为它们在许多现代数据仓库框架中不受支持,但是我们有其他选项来提高性能。

维度通常很小,有时可以放在内存中,支持地图端连接优化(参见 Spark 的 BroadcastJoin )。

我们可以在维度表上使用

Spark 支持星型模式检测、对连接进行重新排序并有效地跳过数据。

适应大数据

1996 年的许多实践今天仍然适用,但是一些方法需要重新定义。

Lyft等公司已经成功地更新了这些数据仓库实践,以适应新的技术环境。 Maxime Beauchemin 就这个主题做了一个很棒的演讲这篇文章的“管理维度”部分很大程度上受到了它的启发。

来自同一个演讲:

先学习规则,再打破规则

照片由 乔治·贝克尔 发自 派克斯

外键

自然键

数据仓库书籍警告不要重复使用“自然键”(来自生产系统的唯一 id)作为事实表中的外键。

如果表被部分清空(出于性能原因),生产系统中的自然键可能会重用 id。因为数据仓库保存历史数据,IDs 的重用会产生难以解决的冲突。

顺序生成的 id

创建“代理键”的最佳实践是使用由数据处理系统顺序生成的整数 id,并与生产系统的自然键分离。

整数可以节省存储空间,创建更小更高效的 T4 索引。

现代数据仓库中不使用索引。Hive 3.0 移除了索引,它们被替换为在文件(ORC、Parquet)、物理分区和存储桶中编译的统计信息/元数据,这同样能够跳过大部分数据。

性能命中

生成代理键是一个复杂的并行操作。

这篇 BigQuery (Google)博客文章描述了使用通用方法(对新行使用ROW_NUMBER函数)添加生成序列的限制:

不幸的是,这种方法是有限的。为了实现ROW_NUMBER(),BigQuery 需要在执行树的根节点对值进行排序,这受限于一个执行节点的内存量。

解决方案

UUIDs 和散列更容易并行化,这使得它成为为“大”数据集生成 id 的更具可伸缩性的方法。

对于“维度快照”,我们更喜欢使用散列而不是 UUIDs,我们将在下面的小节中讨论动机:“管理维度”/“代理键”

照片来自 创业股票照片 来自 Pexels

管理维度

静态尺寸

一些特殊维度如“日期”维度(静态维度),是生成,而不是数据处理的结果。这些表可以预先生成,并且不会保留它们的更改历史。

当一个维度是静态的时,我们可以在每次需要对它进行修改时简单地用覆盖整个数据。

缓慢和快速变化的尺寸

对于要求随时间变化的维度,我们需要一种策略来改变数据。

用户可以更改其家庭地址,产品可以更改名称,品牌可以更换所有者。

多年来,许多“类型”的缓慢和快速变化的维度管理策略被形式化了。其中一些保留历史记录,大多数使用“更新”就地添加或修改信息。

这里的具有快速改变属性的维度和具有缓慢改变属性的维度之间的分离。

在保存历史记录的维度中,当记录中的任何属性发生更改时,需要复制整行数据,如果属性经常更改,则会使用更多的存储空间。

这些技术很复杂,因为它们是在严格的存储限制下设计的。

维度快照使用更多的存储,但是它们更容易创建和查询

维度快照

尺寸应该比事实小得多。一个电子商务的交易、订单和客户评论(事实)可能有数百万,但是独立客户的数量(维度)会小得多。

维度也因其携带的“状态”而不同于事实。维度中的记录将有一个“身份”,当其他属性改变时,需要保留该身份。

维度快照易于管理

每天,我们都会在版本化快照中重写整个维度表

s3://my_data_warehouse/dim_users/ds=2020-01-01
s3://my_data_warehouse/dim_users/ds=2020-01-02
...

因为不管发生多少变化,整个表都会被重写,所以对于快速和缓慢变化的维度采用不同的策略没有什么好处。

历史

有了这个模型,我们可以通过在特定的日子加入一个过滤器来轻松回答历史问题。

历史记录也不会减慢查询速度,因为传递特定日期实际上会跳过其他日期的文件。

该表的结构使得尺寸表上的时序变得容易。例如,我们可以计算一段时间内每个居住国家的用户数量。

代理键

UUIDs 引入了随机性。为了保持新的代理键与前一个快照的代理键一致,我们需要查询那个快照。

相反,散列是基于构成记录“身份”的键的连接(不包括自然键),因此我们只能从当前数据重新计算它。这就是为什么我们更喜欢在维度快照中使用 UUIDs 散列的原因。

请注意,每日快照消除了对第二个密钥的需要。某些类型的渐变维度实现了两个代理键:一个指向维度记录的“最新”状态,另一个指向特定事实被摄取时记录的历史快照。因为每个快照都包含该时间点的所有数据,所以我们可以使用快照的日期来获得“最新”状态,或者给定时间点的状态。

那不会产生大量数据吗?

数据重复是维度快照的主要缺点。

另一个缺点是维度只需要从的一个进程中创建,因为一天多个快照会加重重复。

以比每天更频繁的频率刷新维度的要求也会放大重复。

收益是简单性易于访问历史维度上的时间序列在写入和查询方面的性能

然而,在数据复制不可行的情况下,我们可以求助于另一种缓慢变化的维度管理。使用像三角洲湖这样的项目来支持更新。

照片由Unsplash上的气候现实项目拍摄

管理事实

事实表是数据仓库的基础。它们包含企业的基本度量,并且是大多数数据仓库查询的最终目标

https://www.kimballgroup.com/2008/11/fact-tables/

有多种类型的事实模型来涵盖事实表旨在捕捉的不同度量和事件。

谷物

在设计事实时,我们需要决定表中每一行的详细程度。

预先汇总事实可以节省存储空间,但这是一个高风险的赌注,因为来自业务的分析需求可能在未来需要更多的细节。对于今天的大多数情况,在最低细节层次捕捉事实信息是可取的。

仅插入

绝大多数事实不需要更新。即使在累积快照的特定情况下,我们也可以通过一种消除可变性需求的方式来设计模型。

例如,对于电子商务订单,如果我们有状态:ORDER_BEING_PREPARED, ORDER_SHIPPED, ORDER_IN_TRANSIT。我们可以创建新的状态来象征先前状态的结束,而不是每次动作结束时都去事实表并用一个end_date来更新行:ORDER_BEING_PREPARED_END, ORDER_SHIPPED_END, ORDER_IN_TRANSIT_END。现在每个状态的改变都是一个可以插入的独立事件。

物理分区

为了创建在上游错误或业务需求变化的情况下可以被覆盖的不可变分区,我们需要按照“提取日期”——从源系统提取数据的日期——对我们的数据进行分区。

第一个分区键通常对查询性能没什么用,但是对于实现等幂批处理作业来说很重要。

此外,建议按“事件日期进行分区,因为查询经常使用它作为过滤器(WHERE 子句)。

可以添加其他分区键来额外提高查询速度,但是我们需要确保它们在过滤器中使用,并且生成的文件不会太小

表格结构示例:

under s3://my_data_warehouse/fact_transactions:/event_date=2020-02-05/extraction_date=2020-02-05/event_date=2020-02-05/extraction_date=2020-02-06
/event_date=2020-02-06/extraction_date=2020-02-06
...

我们的数据处理作业在 5 号创建了 1 个分区:即/event_date=2020–02–05/extraction_date=2020–02–05分区。

然而在 6 号:在前一天发生的一些事务被延迟捕获,因此创建了两个分区:/event_date=2020–02–05/extraction_date=2020–02–06/event_date=2020–02–06/extraction_date=2020–02–06,这通常被称为,并且由该表结构支持。

最后

通过采用“星型架构”方法来利用廉价的云存储,我们可以避免数据仓库中的更新、锁定和 ACID 合规性需求。

  • 外键是散列而不是整数序列
  • 维度使用每日快照
  • 事实按照“提取日期进行分区,以支持等幂处理和分区的潜在覆盖

使用 Pantsbuild 为数据科学构建 monorepo

原文:https://towardsdatascience.com/building-a-monorepo-for-data-science-with-pantsbuild-2f77b9ee14bd?source=collection_archive---------18-----------------------

并了解它的好处

塞尔吉奥·索萨在 Unsplash 上的照片

HousingAnywhere ,我们在扩展数据团队时必须面对的第一个主要障碍是建立一个包含我们不断增长的机器学习应用程序的集中式存储库。在这些项目之间,许多项目相互依赖,这意味着代码重构可能会成为一种痛苦,并消耗大量时间。此外,由于我们非常反对数据科学家复制/粘贴代码的倾向,我们需要一个统一的位置来存储可以轻松访问的可重用函数。

我们用例的完美解决方案是构建一个 monorepo。在本文中,我将介绍如何使用构建自动化系统 Pantsbuild 构建一个简单的 monorepo。

什么是单向回购?

monorepo 是一个存储库,其中存储了许多项目的代码。为您的团队建立一个集中的存储库有很多好处:

  • 复用性:允许项目共享功能,在数据科学的情况下,预处理数据、计算度量甚至绘制图形的代码可以跨项目共享。
  • 原子变更:只需要一个操作就可以跨多个项目进行变更。
  • 大规模的重构 : 可以简单快速地完成,确保项目在之后仍然有效。

然而,Monorepo 并不是一个适合所有人的解决方案,因为它有许多缺点:

  • 安全问题:没有办法只暴露存储库的一部分。
  • 大代码库:随着回购规模的增长,它会带来问题,因为开发人员必须检查整个存储库。

在 HousingAnywhere,我们的数据科学家团队发现 monorepo 是我们数据团队用例的完美解决方案。我们的许多机器学习应用程序都有从中派生出来的较小的项目。monorepo 使我们能够快速地将这些新项目整合到 CI/CD 管道中,减少了为每个新项目单独设置管道的时间。

我们尝试了许多构建自动化系统,我们坚持使用的是。Pants 是为数不多的原生支持 Python 的系统,是 Twitter、Toolchain、Foursquare、square、Medium 广泛使用的开源项目。

最近 Pants 已经更新到了 v2,目前只支持 Python,但是对于数据科学项目来说并没有太大的限制。

一些基本概念

有几个关于裤子的概念你应该事先了解:

  • ****目标帮助用户告诉裤子采取什么行动,例如test
  • ****任务是运行动作的裤子模块
  • ****目标描述对哪些文件采取这些操作。这些目标是在构建文件中定义的
  • ****目标类型定义可在目标上执行的操作类型,例如,您可以在测试目标上执行测试
  • ****地址描述回购中目标的位置

要了解更多信息,我强烈推荐阅读这篇文档,裤子的开发者在详细解释这些概念方面做得非常好。

示例存储库

在本节中,我将介绍如何使用 Pants 轻松设置 monorepo。首先,确保满足以下安装裤子的要求:

  • Linux 或者 macOS。
  • Python 3.6+可在您的PATH上发现。
  • 互联网接入(这样裤子就可以完全自举了)。

现在,让我们建立一个新的存储库:

mkdir monorepo-example
cd monorepo-example
git init

或者,您可以通过以下方式克隆示例回购:

git clone [https://github.com/uiucanh/monorepo-example.git](https://github.com/uiucanh/monorepo-example.git)

接下来,运行以下命令下载安装文件:

printf '[GLOBAL]\npants_version = "1.30.0"\nbackend_packages = []\n' > pants.toml
curl -L -o ./pants https://pantsbuild.github.io/setup/pants && \ chmod +x ./pants

然后,通过奔跑./pants --version拉起裤子。您应该收到1.30.0作为输出。

让我们向回购中添加几个简单的应用程序。首先,我们将创建一个utils/data_gen.py和一个utils/metrics.py,它们包含几个实用函数:

现在,我们将添加一个应用程序first_app/app.py来导入这些代码。应用程序使用来自generate_linear_data的数据,将它们传递给线性回归模型,并输出平均绝对百分比误差。

另一个应用程序second_app/app.py使用第一个应用程序代码:

然后,我们为这些应用程序添加了几个简单的测试,例如:

在每个目录中,我们都需要一个构建文件。这些文件包含关于目标及其依赖项的信息。在这些文件中,我们将声明这些项目需要什么需求,以及声明测试目标。

让我们从存储库的根开始:

这个构建文件包含一个宏python_requirements(),它创建了多个目标来从同一个目录下的requirements.txt中提取第三方依赖项。它节省了我们为每个需求手工操作的时间:

python_requirement_library(
    name="numpy",
    requirements=[
        python_requirement("numpy==1.19.1"),
    ],
)

utils中的构建文件如下所示:

这里我们有两个目标:第一个是 Python 库,包含在source中定义的 Python 代码,即我们的两个实用程序文件。它还指定了运行这些代码所需的需求,这是numpy,我们在根构建文件中定义的第三方依赖项之一。

第二个目标是我们之前定义的测试集合,它们依赖于之前的 Python 库。要运行这些测试,只需从 root 运行./pants test utils:utils_test./pants test utils::即可。第二个:告诉 Pants 运行构建文件中的所有测试目标。输出应该如下所示:

============== test session starts ===============
platform darwin -- Python 3.7.5, pytest-5.3.5, py-1.9.0, pluggy-0.13.1
cachedir: .pants.d/test/pytest/.pytest_cache
rootdir: /Users/ducbui/Desktop/Projects/monorepo-example, inifile: /dev/null
plugins: cov-2.8.1, timeout-1.3.4
collected 3 items

utils/data_gen_test.py .                   [ 33%]
utils/metrics_test.py ..                   [100%]

类似地,我们将为first_appsecond_app创建两个构建文件

second_app构建文件中,我们将上面first_app中的库声明为这个库的依赖项。这意味着来自该库的所有依赖项,连同它的源,将成为first_app的依赖项。

类似地,我们也向这些构建文件添加一些测试目标,它们可以用./pants test first_app::./pants test second_app::运行。

最终的目录树应该如下所示:

.
├── BUILD
├── first_app
│   ├── BUILD
│   ├── app.py
│   └── app_test.py
├── pants
├── pants.toml
├── requirements.txt
├── second_app
│   ├── BUILD
│   ├── app.py
│   └── app_test.py
└── utils
    ├── BUILD
    ├── data_gen.py
    ├── data_gen_test.py
    ├── metrics.py
    └── metrics_test.py

Pants 的强大之处在于它能够跟踪受变更影响的项目和测试目标之间的可传递依赖关系。Pants 的开发人员为我们提供了这个漂亮的 bash 脚本,可以用来追踪受影响的测试目标:

为了展示它的威力,让我们运行一个例子。我们将创建一个新分支,对data_gen.py进行修改(例如,更改generate_linear_data的默认参数)并提交:

git checkout -b "example_1"
git add utils/data_gen.py
git commit -m "support/change-params"

现在,运行 bash 脚本,我们将看到一个minimized.txt,它包含所有受影响的项目和将要执行的测试目标:

first_app:app_test
second_app:app_test
utils:utils_test

传递依赖性

查看上图,我们可以清楚地看到,更改utils会影响它上面的所有节点,包括first_appsecond_app

让我们再做一个例子,这次我们只修改second_app/app.py。切换分支,提交并再次运行脚本。在minimized.txt内部,我们只会得到second_app:app_test,因为它是最顶层的节点。

就这样,希望我已经成功地向你们展示了 Pantsbuild 对于数据科学 monorepos 是多么有用。加上正确实现的 CI/CD 管道,开发的速度和可靠性可以大大提高。

使用 Python 构建电影推荐器

原文:https://towardsdatascience.com/building-a-movie-recommender-using-python-277959b07dae?source=collection_archive---------8-----------------------

使用 sci-kit learn 的简单实用的机器学习项目

照片由晨酿Unsplash 拍摄

在这篇文章中,我将向你展示如何使用 Python 来构建一个电影推荐程序。这将是一个简单的项目,我们将能够看到机器学习如何在我们的日常生活中使用。如果你查看我的其他文章,你会发现我喜欢演示动手项目。我觉得这是练习我们编码技能,提升自己的最好方式。建立一个电影推荐程序是开始使用机器推荐器的好方法。在分享了目录之后,我想给你介绍一下推荐系统。

内容

  • 简介
  • 电影数据
  • 数据准备
  • 基于内容的推荐器
  • 显示时间
  • 视频演示

介绍

推荐系统已经伴随我们有一段时间了,它们是如此的强大。这些天来,他们确实对我们的决定有很大的影响。从电影流媒体服务到在线购物商店,它们几乎无处不在。如果你想知道在你的购物车中添加一个“x”项目后,他们如何知道你可能会购买什么,答案很简单: 数据的力量

我们可能看起来非常不同,但我们的习惯可能非常相似。这些公司喜欢寻找他们客户的相似习惯。由于他们知道许多购买了“x”商品的人也购买了“y”商品,他们建议您将“y”商品添加到购物车中。你猜怎么着,你买得越多,你就在训练你自己的推荐者,这意味着机器会更了解你。

推荐系统是机器学习的一个非常有趣的领域,它的酷之处在于它就在我们身边。关于这个话题有很多东西要学,为了简单起见,我就讲到这里。让我们开始建立自己的电影推荐系统吧!

电影数据

我在 Kaggle 上找到了很棒的电影数据。如果你没有听说过 Kaggle,Kaggle 是世界上最大的数据科学社区,拥有强大的工具和资源来帮助你实现数据科学目标。

这里是下载数据集的链接。

语境

  • 数据文件夹包含完整的 MovieLens 数据集中列出的所有 45,000 部电影的元数据。
  • 该数据集由 2017 年 7 月或之前上映的电影组成。数据点包括演员、工作人员、情节关键词、预算、收入、海报、上映日期、语言、制作公司、国家、TMDB 票数和平均票数。
  • 该数据文件夹还包含评级文件,该文件具有来自 270,000 个用户对所有 45,000 部电影的 2,600 万个评级。

数据准备

首先,让我们从导入和探索我们的数据开始。下载数据文件夹后,您将多个数据集文件。对于这个项目,我们将使用 movies_metadata.csv 数据集。这个数据集包含了我们创建电影推荐器所需的所有内容。

import pandas as pd#load the data
movie_data = pd.read_csv('data/movie_data/movies_metadata.csv', low_memory=False)movie_data.head()

电影数据头

绘图概述

movie_data['overview'].head(10)

完美!我们的数据都准备好了。准备接受我们模特的训练。是时候进入下一步了,我们将开始构建基于内容的推荐器。

基于内容的推荐器

基于内容的推荐器是一种推荐模型,它根据特定的项目返回项目列表。推荐者的一个很好的例子是网飞、YouTube、Disney+等等。例如,网飞推荐你以前看过的更喜欢的类似节目。通过这个项目,你将更好地理解这些在线流媒体服务的算法是如何工作的。

回到这个项目,作为训练我们模型的输入,我们将使用我们之前检查过的电影的概述。然后我们将使用一些 sci-kit learn ready 函数来构建我们的模型。我们的推荐程序将在四个简单的步骤中准备就绪。我们开始吧!

1.定义矢量器

from sklearn.feature_extraction.text import TfidfVectorizertfidf_vector = TfidfVectorizer(stop_words='english')movie_data['overview'] = movie_data['overview'].fillna('')tfidf_matrix = tfidf_vector.fit_transform(movie_data['overview'])

理解上面的代码

  • 从 sci-kit 学习模块导入矢量器。在这里了解更多。
  • Tf-idf 矢量器对象删除所有英文停用词,如' the ',' a '等。
  • 我们用空字符串替换空值,这样在训练它们时就不会返回错误消息。
  • 最后,我们通过拟合和转换数据来构建所需的 Tf-idf 矩阵

2.线性核

我们将从 sci-kit 学习模块中导入线性内核函数开始。线性核将帮助我们创建一个相似性矩阵。这些行执行起来要花一点时间,不要担心这是正常的。计算两个巨大矩阵的点积并不容易,即使对机器来说也是如此:)

from sklearn.metrics.pairwise import linear_kernelsim_matrix = linear_kernel(tfidf_matrix, tfidf_matrix)

3.指数

现在,我们必须构建索引和电影标题的反向映射。在系列函数的第二部分,我们用一个简单的函数 drop_duplicates 清除重复的电影标题。

indices = pd.Series(movie_data.index, index=movie_data['title']).drop_duplicates()indices[:10]

前十个指数

4.最后—推荐功能

def content_based_recommender(title, sim_scores=sim_matrix):
    idx = indices[title] sim_scores = list(enumerate(sim_matrix[idx])) sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True) sim_scores = sim_scores[1:11] movie_indices = [i[0] for i in sim_scores] return movie_data['title'].iloc[movie_indices]

秀场

干得好!是时候测试我们的推荐者了。让我们看看实际情况,看看它到底有多强大。我们将通过添加电影名称作为一个字符串参数来运行该函数。

类似《玩具总动员》的电影

content_based_recommender('Toy Story')

视频演示

项目视频演示

恭喜你。!您创建了一个向您推荐电影的程序。现在,当你想选择下一场网飞秀时,你有一个程序可以运行。希望你喜欢阅读这个动手项目。如果你今天学到了新东西,我会很高兴。从事像这样的动手编程项目是提高编码技能的最好方式。

如果您在执行代码时有任何问题,请随时联系我

关注我的博客youtube 频道,保持灵感。谢谢你,

更多机器学习项目

[## 用 Python 构建人脸识别器

使用 OpenCv 库进行实时人脸识别的分步指南

towardsdatascience.com](/building-a-face-recognizer-in-python-7fd6630c6340) [## 使用 Python 从视频中提取语音

使用 Google 语音识别 API 的简单实用项目

towardsdatascience.com](/extracting-speech-from-video-using-python-f0ec7e312d38)

10 分钟打造多功能语音助手

原文:https://towardsdatascience.com/building-a-multi-functionality-voice-assistant-in-10-minutes-3e5d87e164f0?source=collection_archive---------33-----------------------

一步一步的初学者指南,建立您的第一个语音助手,执行 8 个基本和引人注目的功能

图像取自— 图像 1图像 2图像 3图像 4

如今,人们没有时间手动在互联网上搜索信息或问题的答案,而是希望有人为他们做这件事,就像个人助理一样,听取提供的命令并据此采取行动。由于人工智能,这种个人助理现在可以以语音助理的形式提供给每个人,比人类快得多,也可靠得多。一个甚至能够完成困难任务的助手,比如在线下单、播放音乐、开灯等。仅仅通过听用户的命令

在本文中,我将向您展示如何构建一个语音助手来响应基本的用户查询。读完这篇文章后,你会对什么是网络抓取以及如何用它来构建一个语音助手有一个基本的概念。

注意:要阅读本文,您需要对 Python 语言有一个基本的了解。

目录

  1. 语音助手

2.网页抓取

3.履行

语音助手

语音助手是一个软件代理,可以根据命令或问题为个人执行任务或服务。一般来说,语音助手对语音命令做出反应,并向用户提供关于他/她的查询的相关信息。

该助手可以理解用户发出的特定命令并做出反应,如在 YouTube 上播放歌曲或了解天气。它将搜索和/或抓取网页以找到对命令的响应,从而满足用户。

目前,语音助手已经能够处理产品订单,回答问题,执行播放音乐或与朋友打电话等操作。

实现的语音助手可以执行以下任务:

  1. 提供天气详情
  2. 提供电晕更新
  3. 提供最新消息
  4. 搜索一个词的意思
  5. 做笔记
  6. 播放 YouTube 视频
  7. 在谷歌地图上显示位置
  8. 在谷歌浏览器上打开网站

在构建语音助手时,有两个重要的库是你应该考虑的。Python 的 SpeechRecognition 包帮助语音助手理解用户。它可以按如下方式实现:

import speech_recognition as sr#initalises the recognizer
r1 = sr.Recognizer()#uses microphone to take the input
with sr.Microphone() as source:
    print('Listening..') #listens to the user
    audio = r1.listen(source) #recognises the audio and converts it to text
    audio = r1.recognize_google(audio)

Python 的 pyttsx3 包通过将文本转换成音频来帮助语音助手响应用户。它可以按如下方式实现:

import pyttsx3#initialises pyttsx3
engine = pyttsx3.init('sapi5')#converts the text to audio
engine.say('Hello World')
engine.runAndWait()

网页抓取

网页抓取是指从网站中提取数据。网站上的数据是非结构化的。Web 抓取有助于收集这些非结构化数据,并以结构化形式存储。

网页抓取的一些应用包括:

搜集社交媒体如 Twitter,以收集推文和评论来进行情感分析。

抓取亚马逊等电子商务网站提取产品信息进行数据分析,预测市场趋势。

收集电子邮件地址以收集电子邮件 id,然后发送大量电子邮件用于营销和广告目的。

抓取谷歌图片以创建数据集,用于训练机器学习或深度学习模型。

虽然可以手动完成,但是 Python 的库美汤让抓取数据变得更加简单快捷。

要通过 python 使用 web 抓取来提取数据,您需要遵循以下基本步骤:

  1. 找到您想要抓取的网站的 URL
  2. 提取网站的全部代码
  3. 检查网站并找到您想要提取的数据
  4. 使用 html 标签过滤代码以获得所需的数据
  5. 以要求的格式存储数据

履行

让我们首先在您的 python 笔记本中导入以下库,如下所示:

import requests 
from bs4 import BeautifulSoup 
import re
import speech_recognition as sr 
from datetime import date
import webbrowser
import pyttsx3

现在让我们创建我们的主函数,它由一系列 if-else 语句组成,告诉助手在特定条件下如何响应。

engine = pyttsx3.init('sapi5')r1 = sr.Recognizer()
with sr.Microphone() as source:
    print('Listening..')
    engine.say('Listening')
    engine.runAndWait()
    audio = r1.listen(source)
    audio = r1.recognize_google(audio) if 'weather' in audio:
        print('..')
        words = audio.split(' ')
        print(words[-1])
        scrape_weather(words[-1]) elif 'covid' in audio:
        print('..')
        words = audio.split(' ')
        corona_updates(words[-1]) elif 'meaning' in audio:
        print('..')
        words = audio.split(' ')
        print(words[-1])
        scrape_meaning(words[-1])

    elif 'take notes' in audio:
        print('..')
        take_notes()
        print('Noted!!')

    elif 'show notes' in audio:
        print('..')
        show_notes()
        print('Done')

    elif 'news' in audio:
        print('..')
        scrape_news()

    elif 'play' in audio:
        print('..')
        words = audio.split(' ')
        print(words[-1])
        play_youtube(audio)

    elif 'open' in audio:
        print('..')
        words = audio.split('open')
        print(words[-1])
        link = str(words[-1])
        link = re.sub(' ', '', link)
        engine.say('Opening')
        engine.say(link)
        engine.runAndWait()
        link = f'[https://{link}.com'](/{link}.com')
        print(link)
        webbrowser.open(link)

    elif 'where is' in audio:
        print('..')
        words = audio.split('where is')
        print(words[-1])
        link = str(words[-1])
        link = re.sub(' ', '', link)
        engine.say('Locating')
        engine.say(link)
        engine.runAndWait()
        link = f'[https://www.google.co.in/maps/place/{link}'](https://www.google.co.in/maps/place/{link}')
        print(link)
        webbrowser.open(link)

    else:
        print(audio)
        print('Sorry, I do not understand that!')
        engine.say('Sorry, I do not understand that!')
        engine.runAndWait()

案例一:如果用户想了解天气,他/她可以问助手“嘿!孟买今天的天气怎么样?”

由于音频中出现了单词 "weather" ,函数scrape _ weather(words[-1])将被调用,参数为 "Mumbai "。

让我们来看看这个函数。

def scrape_weather(city):
    url = '[https://www.google.com/search?q=accuweather+'](https://www.google.com/search?q=accuweather+') + city
    page = requests.get(url)soup = BeautifulSoup(page.text, 'lxml')links = [a['href']for a in soup.findAll('a')]
    link = str(links[16])
    link = link.split('=')
    link = str(link[1]).split('&')
    link = link[0]

    page = requests.get(link, headers={'User-Agent': 'Mozilla/5.0'})soup = BeautifulSoup(page.content, 'lxml') 

    time = soup.find('p', attrs = {'class': 'cur-con-weather-card__subtitle'})
    time = re.sub('\n', '', time.text)
    time = re.sub('\t', '', time)
    time = 'Time: ' + timetemperature = soup.find('div', attrs = {'class':'temp'})
    temperature = 'Temperature: ' + temperature.text

    realfeel = soup.find('div', attrs = {'class': 'real-feel'})
    realfeel = re.sub('\n', '',realfeel.text)
    realfeel = re.sub('\t', '',realfeel)
    realfeel = 'RealFeel: ' + realfeel[-3:] + 'C'climate = soup.find('span', attrs = {'class':'phrase'})
    climate = "Climate: " + climate.text

    info = 'For more information visit: ' + link 

    print('The weather for today is: ')
    print(time)
    print(temperature)
    print(realfeel)
    print(climate)
    print(info)
    engine.say('The weather for today is: ')
    engine.say(time)
    engine.say(temperature)
    engine.say(realfeel)
    engine.say(climate)
    engine.say('For more information visit accuweather.com' )
    engine.runAndWait()

我们将使用“accuweather.com”网站搜集所有与天气相关的信息。函数 request.get(url) 向使用 BeautifulSoup(page.text,' lxml') 提取完整 HTML 代码的 url 发送 get 请求

一旦提取了代码,我们将检查代码以找到感兴趣的数据。例如,温度的数值以下列格式表示

<div class = "temp">26°</div>

可以使用提取

soup.find('div', attrs = {'class':'temp'})

类似地,我们提取时间、真实感觉和气候,并使用 engine.say()让助手对用户做出响应。

案例二:如果用户想要当前新冠肺炎的更新,他/她可以问助手嘿!你能给我印度的 COVID 更新吗?”“嘿!你能给我世界的 COVID 更新吗?”

由于单词“covid”出现在音频中,函数corona _ updates(words[-1])将被调用,参数为“印度”或“世界”

让我们来看看这个函数。

def corona_updates(audio):

    audio = audiourl = '[https://www.worldometers.info/coronavirus/'](https://www.worldometers.info/coronavirus/')
    page = requests.get(url)soup = BeautifulSoup(page.content, 'lxml')totalcases = soup.findAll('div', attrs =  {'class': 'maincounter-number'})
    total_cases = []
    for total in totalcases:
        total_cases.append(total.find('span').text)world_total = 'Total Coronavirus Cases: ' + total_cases[0]
    world_deaths = 'Total Deaths: ' + total_cases[1]
    world_recovered = 'Total Recovered: ' + total_cases[2]

    info = 'For more information visit: ' + '[https://www.worldometers.info/coronavirus/#countries'](https://www.worldometers.info/coronavirus/#countries')if 'world' in audio:
        print('World Updates: ')
        print(world_total)
        print(world_deaths)
        print(world_recovered)
        print(info)else:
        country = audiourl = '[https://www.worldometers.info/coronavirus/country/'](https://www.worldometers.info/coronavirus/country/') + country.lower() + '/'
        page = requests.get(url)soup = BeautifulSoup(page.content, 'lxml')totalcases = soup.findAll('div', attrs =  {'class': 'maincounter-number'})
        total_cases = []
        for total in totalcases:
            total_cases.append(total.find('span').text)total = 'Total Coronavirus Cases: ' + total_cases[0]
        deaths = 'Total Deaths: ' + total_cases[1]
        recovered = 'Total Recovered: ' + total_cases[2]info = 'For more information visit: ' + urlupdates = country + ' Updates: 'print(updates)
        print(total)
        print(deaths)
        print(recovered)
        print(info)

        engine.say(updates)
        engine.say(total)
        engine.say(deaths)
        engine.say(recovered)
        engine.say('For more information visit: worldometers.info')
        engine.runAndWait()

我们将使用网站“world ometers . info搜集所有与日冕相关的信息。函数 request.get(url) 向使用 BeautifulSoup(page.text,' lxml') 提取完整 HTML 代码的 url 发送 get 请求

一旦提取了代码,我们将检查代码以找到总电晕情况、总恢复和总死亡的数值。

这些值存在于具有类“maincounter-number”的 div 范围内,如下所示。

<div id="maincounter-wrap" style="margin-top:15px">
<h1>Coronavirus Cases:</h1>
<div class="maincounter-number">
<span style="color:#aaa">25,091,068 </span>
</div>
</div>

这些可以提取如下。

totalcases = soup.findAll('div', attrs =  {'class': 'maincounter-number'})
    total_cases = []
    for total in totalcases:
        total_cases.append(total.find('span').text)

我们首先找到所有具有类“maincounter-number”的 div 元素。然后我们遍历每个 div 以获得包含数值的跨度。

案例三:如果用户想了解新闻,可以问助理“嘿!你能告诉我最新的消息吗?”

由于音频中出现了单词“news”,因此将调用函数 scrape_news()

def scrape_news():
    url = '[https://news.google.com/topstories?hl=en-IN&gl=IN&ceid=IN:en](https://news.google.com/topstories?hl=en-IN&gl=IN&ceid=IN:en) '
    page = requests.get(url)
    soup = BeautifulSoup(page.content, 'html.parser')
    news = soup.findAll('h3', attrs = {'class':'ipQwMb ekueJc RD0gLb'})
    for n in news:
        print(n.text)
        print('\n')
        engine.say(n.text)
    print('For more information visit: ', url)
    engine.say('For more information visit google news')
    engine.runAndWait()

我们将使用“谷歌新闻”来抓取新闻标题。函数 request.get(url) 向使用 BeautifulSoup(page.text,' lxml') 提取完整 HTML 代码的 url 发送 get 请求

一旦提取了代码,我们将检查代码以找到最新新闻的标题。

这些标题出现在 h3 标记的 href 属性中,具有如下所示的类“ipQwMb ekueJc RD0gLb”。

<h3 class="ipQwMb ekueJc RD0gLb"><a href="./articles/CAIiEA0DEuHOMc9oauy44TAAZmAqFggEKg4IACoGCAoww7k_MMevCDDW4AE?hl=en-IN&amp;gl=IN&amp;ceid=IN%3Aen" class="DY5T1d">Rhea Chakraborty arrest: Kubbra Sait reminds ‘still not a murderer’, Rhea Kapoor says ‘we settled on...</a></h3>

我们首先找到所有具有类“ipQwMb ekueJc RD0gLb”的 h3 元素。然后,我们遍历每个元素以获取 href 属性中的文本(新闻标题)。

案例四:如果用户想知道任意单词的含义,可以问助手“嘿!刮是什么意思?”

由于音频中出现了单词,意思是,函数 scrape_meaning(单词[-1])将被调用,参数为“scraping”

让我们来看看这个函数。

def scrape_meaning(audio):
    word = audio
    url = '[https://www.dictionary.com/browse/'](https://www.dictionary.com/browse/') + word
    page = requests.get(url)
    soup = BeautifulSoup(page.content, 'html.parser')
    soup
    meanings = soup.findAll('div', attrs =  {'class': 'css-1o58fj8 e1hk9ate4'})
    meaning = [x.text for x in meanings]
    first_meaning = meaning[0]
    for x in meaning:
        print(x)
        print('\n')
    engine.say(first_meaning)
    engine.runAndWait()

我们将使用网站“来刮取意思。函数 request.get(url) 向使用 BeautifulSoup(page.text,' lxml') 提取完整 HTML 代码的 url 发送 get 请求

一旦提取了代码,我们将检查代码,找到所有包含作为参数传递的单词含义的 html 标签。

这些值存在于具有类“css-1o58fj8 e1hk9ate4”的 div 中,如下所示。

<div value="1" class="css-kg6o37 e1q3nk1v3"><span class="one-click-content css-1p89gle e1q3nk1v4" data-term="that" data-linkid="nn1ov4">the act of a person or thing that <a href="/browse/scrape" class="luna-xref" data-linkid="nn1ov4">scrapes</a>. </span></div>

我们首先找到所有具有类“css-1o58fj8 e1hk9ate4”的 div 元素。然后,我们遍历每个元素以获取 div 中的文本(单词的含义)。

情况 5:如果用户想让助手做笔记,他/她可以问助手“嘿!你能帮我记笔记吗?”

由于单词“做笔记”出现在音频中,将调用函数 take_notes() 。

让我们来看看这个函数。

def take_notes():r5 = sr.Recognizer()  
    with sr.Microphone() as source:
        print('What is your "TO DO LIST" for today')
        engine.say('What is your "TO DO LIST" for today')
        engine.runAndWait()
        audio = r5.listen(source)
        audio = r5.recognize_google(audio)
        print(audio)
        today = date.today()
        today = str(today)
        with open('MyNotes.txt','a') as f:
            f.write('\n')
            f.write(today)
            f.write('\n')
            f.write(audio)
            f.write('\n')
            f.write('......')
            f.write('\n')
            f.close() 
        engine.say('Notes Taken')
        engine.runAndWait()

我们首先初始化识别器,向用户询问他们的“任务清单”。然后我们听用户说话,并使用 recognize_google 来识别音频。现在我们将打开一个名为“MyNotes.txt”的记事本,记下用户给出的笔记和日期。

然后,我们将创建另一个名为 show_notes()的函数,它将从名为“MyNotes.txt”的记事本中读出今天的笔记/待办事项列表。

def show_notes():
    with open('MyNotes.txt', 'r') as f:
        task = f.read()
        task = task.split('......')
    engine.say(task[-2])
    engine.runAndWait() 

案例六:如果用户想播放 YouTube 视频,他/她可以问助手“嘿!能不能玩催眠?”

由于音频中出现了单词“play”,因此将调用函数 play _ YouTube(words[-1]),并传递“催眠”作为参数。

让我们来看看这个函数。

*def play_youtube(audio):url = '[https://www.google.com/search?q=youtube+'](https://www.google.com/search?q=youtube+') + audio
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    }
    engine.say('Playing')
    engine.say(audio)
    engine.runAndWait()
    page = requests.get(url, headers=headers)
    soup = BeautifulSoup(page.content, 'html.parser')
    link = soup.findAll('div', attrs = {'class':'r'})
    link = link[0]
    link = link.find('a')
    link = str(link)
    link = link.split('"')
    link = link[1]webbrowser.open(link)*

我们将使用 G oogle Videos 来搜索视频标题,并打开第一个链接来播放 YouTube 视频,该视频出现在具有类“r”的 div 元素中。

情况 7:如果用户想要搜索位置,他/她可以问助手“嘿!IIT 孟买在哪里?”**

由于单词“where is”出现在音频中,下面的代码将被执行。

(这段代码出现在主函数的 if-else 循环中)

*elif 'where is' in audio:
        print('..')
        words = audio.split('where is')
        print(words[-1])
        link = str(words[-1])
        link = re.sub(' ', '', link)
        engine.say('Locating')
        engine.say(link)
        engine.runAndWait()
        link = f'[https://www.google.co.in/maps/place/{link}'](https://www.google.co.in/maps/place/{link}')
        print(link)
        webbrowser.open(link)*

我们将加入谷歌地图链接用户提供的位置,并使用 webbrowser.open(链接)打开链接定位' IIT 孟买'。

案例 8:如果用户想打开一个网站,他/她可以问助手嘿!能不能向数据科学开放?”**

由于单词“打开”出现在音频中,下面的代码将被执行。

(这段代码出现在主函数的 if-else 循环中)

*elif 'open' in audio:
        print('..')
        words = audio.split('open')
        print(words[-1])
        link = str(words[-1])
        link = re.sub(' ', '', link)
        engine.say('Opening')
        engine.say(link)
        engine.runAndWait()
        link = f'[https://{link}.com'](/{link}.com')
        print(link)
        webbrowser.open(link)*

我们将把用户提供的网站名称与任何 URL 的标准格式连接起来,即https://{网站名称}。com 打开网站。

这就是我们如何创建一个简单的语音助手。您可以修改代码以添加更多功能,如执行基本的数学计算、讲笑话、创建提醒、更改桌面壁纸等。

你可以在下面链接的我的 GitHub 资源库中找到完整的代码。

* [## sakshibutala/语音助手

在这个笔记本中,我建立了一个语音助手,可以回答基本的询问。“VoiceAssistant.ipynb”包含…

github.com](https://github.com/sakshibutala/VoiceAssistant)

参考文献

[## 什么是网页抓取,它是用来做什么的?ParseHub

一些网站可能包含大量宝贵的数据。股票价格,产品详情,体育统计,公司…

www.parsehub.com](https://www.parsehub.com/blog/what-is-web-scraping/) [## 使用 Python 进行 Web 抓取-初学者指南| Edureka

使用 Python 进行 Web 抓取想象一下,您必须从网站中提取大量数据,并且您希望尽可能快地完成这些工作…

www.edureka.co](https://www.edureka.co/blog/web-scraping-with-python/) [## 什么是语音助手,它们是如何工作的?Onlim

科幻电影中的场景,我们回到家,开始对着我们的个人家用电脑说话…

onlim.com](https://onlim.com/en/what-are-voice-assistants-and-how-do-they-work/)*

用 Keras 构建多输出卷积神经网络

原文:https://towardsdatascience.com/building-a-multi-output-convolutional-neural-network-with-keras-ed24c7bc1178?source=collection_archive---------2-----------------------

在这篇文章中,我们将探索 Keras functional API,以建立一个多输出深度学习模型。我们将展示如何训练能够预测三种不同输出的单一模型。通过使用 UTK 人脸数据集,该数据集由超过 2 万张不受控制的环境中的人的照片组成,我们将预测数据集中呈现的每条记录的年龄、性别和性别,性别的准确率达到 91%,种族的准确率达到 78%。

数据集

UTKFace 数据集是一个大型数据集,由超过 2 万张人脸图像组成,并分别标注了年龄、性别和种族。图像被适当地裁剪到面部区域,但是在姿势、照明、分辨率等方面显示一些变化。

为了检索每个记录的注释,我们需要解析文件名。每条记录以如下格式存储:年龄 _ 性别 _ 种族 _ 日期&time.jpg

其中:

  • 年龄是从 0 到 116 的整数
  • 性别是一个整数,其中 0 代表男性,1 代表女性
  • 种族是一个从 0 到 4 的整数,分别代表白人、黑人、亚洲人、印度人和其他人种
  • 日期和时间,表示照片拍摄的时间

如果你想进一步了解这个数据集,请查看他们的网站

让我们首先导入一些库并创建我们的字典来帮助我们解析来自数据集的信息,以及一些其他信息(数据集位置、训练分割、样本的宽度和高度)。

import numpy as np 
import pandas as pd
import os
import glob
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as snsdataset_folder_name = 'UTKFace'TRAIN_TEST_SPLIT = 0.7
IM_WIDTH = IM_HEIGHT = 198dataset_dict = {
    'race_id': {
        0: 'white', 
        1: 'black', 
        2: 'asian', 
        3: 'indian', 
        4: 'others'
    },
    'gender_id': {
        0: 'male',
        1: 'female'
    }
}dataset_dict['gender_alias'] = dict((g, i) for i, g in dataset_dict['gender_id'].items())
dataset_dict['race_alias'] = dict((r, i) for i, r in dataset_dict['race_id'].items())

让我们定义一个函数来帮助我们从数据集中提取数据。该函数将用于迭代 UTK 数据集的每个文件,并返回一个包含我们记录的所有字段(年龄、性别和性别)的熊猫数据帧。

def parse_dataset(dataset_path, ext='jpg'):
    """
    Used to extract information about our dataset. It does iterate over all images and return a DataFrame with
    the data (age, gender and sex) of all files.
    """
    def parse_info_from_file(path):
        """
        Parse information from a single file
        """
        try:
            filename = os.path.split(path)[1]
            filename = os.path.splitext(filename)[0]
            age, gender, race, _ = filename.split('_') return int(age), dataset_dict['gender_id'][int(gender)], dataset_dict['race_id'][int(race)]
        except Exception as ex:
            return None, None, None

    files = glob.glob(os.path.join(dataset_path, "*.%s" % ext))

    records = []
    for file in files:
        info = parse_info_from_file(file)
        records.append(info)

    df = pd.DataFrame(records)
    df['file'] = files
    df.columns = ['age', 'gender', 'race', 'file']
    df = df.dropna()

    return dfdf = parse_dataset(dataset_folder_name)
df.head()

数据可视化

作为理解数据集分布以及模型生成的预测的重要步骤,建议对数据集执行一些数据可视化过程。我们将首先定义一个助手函数,根据给定的 Pandas 系列生成饼图:

import plotly.graph_objects as godef plot_distribution(pd_series):
    labels = pd_series.value_counts().index.tolist()
    counts = pd_series.value_counts().values.tolist()

    pie_plot = go.Pie(labels=labels, values=counts, hole=.3)
    fig = go.Figure(data=[pie_plot])
    fig.update_layout(title_text='Distribution for %s' % pd_series.name)

    fig.show()

种族分布

让我们首先用我们预定义的 plot_distribution 方法绘制比赛分布图。

plot_distribution(df['race'])

快速浏览一下这个图,我们可以看到几乎一半的样本来自白色人种,所以我们可以期待这个组有很大的准确性。其他种族,如黑人、印度人和亚洲人也显示了大量的样本,可能也使我们获得了准确的数据。另一方面,种族“其他人”(西班牙裔、拉丁裔等)显示少量样本,更可能具有较小的准确性。

性别分布

plot_distribution(df['gender'])

对于男性和女性样本,我们有相当好的平衡数量的记录,所以当使用我们的模型时,我们应该对两类都有很高的准确性。

年龄分布

我们还可以使用一个简单的直方图来绘制年龄特征在数据集上的分布,该直方图包含 20 个条块/扇区。

import plotly.express as px
fig = px.histogram(df, x="age", nbins=20)
fig.update_layout(title_text='Age distribution')
fig.show()

我们也可以在饼图中显示同样的图。让我们将年龄列分组,然后用饼图绘制出来

bins = [0, 10, 20, 30, 40, 60, 80, np.inf]
names = ['<10', '10-20', '20-30', '30-40', '40-60', '60-80', '80+']age_binned = pd.cut(df['age'], bins, labels=names)
plot_distribution(age_binned)

我们可以观察到,我们的数据集主要由年龄在 20 至 30 岁之间的个体组成,其次是 30 至 40 岁以及 40 至 60 岁的个体。这些群体约占我们数据集的 70%,因此我们可以假设我们在预测这些范围内的个体时会有很好的准确性。

我们还可以对我们的数据集执行一些多变量分析,但由于这篇文章的范围是演示 Keras 的多输出模型的用法,所以我们不会涉及它——如果你们感兴趣的话,也许改天吧。

数据生成程序

为了将我们的数据输入到我们的 Keras 多输出模型中,我们将创建一个辅助对象作为数据集的数据生成器。这将通过生成批量数据来完成,这些数据将用于向我们的多输出模型提供图像及其标签。这一步也要完成,而不是一次将所有数据集加载到内存中,这可能会导致内存不足错误。

from keras.utils import to_categorical
from PIL import Imageclass UtkFaceDataGenerator():
    """
    Data generator for the UTKFace dataset. This class should be used when training our Keras multi-output model.
    """
    def __init__(self, df):
        self.df = df

    def generate_split_indexes(self):
        p = np.random.permutation(len(self.df))
        train_up_to = int(len(self.df) * TRAIN_TEST_SPLIT)
        train_idx = p[:train_up_to]
        test_idx = p[train_up_to:] train_up_to = int(train_up_to * TRAIN_TEST_SPLIT)
        train_idx, valid_idx = train_idx[:train_up_to], train_idx[train_up_to:]

        # converts alias to id
        self.df['gender_id'] = self.df['gender'].map(lambda gender: dataset_dict['gender_alias'][gender])
        self.df['race_id'] = self.df['race'].map(lambda race: dataset_dict['race_alias'][race]) self.max_age = self.df['age'].max()

        return train_idx, valid_idx, test_idx

    def preprocess_image(self, img_path):
        """
        Used to perform some minor preprocessing on the image before inputting into the network.
        """
        im = Image.open(img_path)
        im = im.resize((IM_WIDTH, IM_HEIGHT))
        im = np.array(im) / 255.0

        return im

    def generate_images(self, image_idx, is_training, batch_size=16):
        """
        Used to generate a batch with images when training/testing/validating our Keras model.
        """

        # arrays to store our batched data
        images, ages, races, genders = [], [], [], []
        while True:
            for idx in image_idx:
                person = self.df.iloc[idx]

                age = person['age']
                race = person['race_id']
                gender = person['gender_id']
                file = person['file']

                im = self.preprocess_image(file)

                ages.append(age / self.max_age)
                races.append(to_categorical(race, len(dataset_dict['race_id'])))
                genders.append(to_categorical(gender, len(dataset_dict['gender_id'])))
                images.append(im)

                # yielding condition
                if len(images) >= batch_size:
                    yield np.array(images), [np.array(ages), np.array(races), np.array(genders)]
                    images, ages, races, genders = [], [], [], []

            if not is_training:
                break

data_generator = UtkFaceDataGenerator(df)
train_idx, valid_idx, test_idx = data_generator.generate_split_indexes() 

构建我们的模型

在这一步,我们将定义我们的多输出 Keras 模型。我们的模型将由三个主要分支组成,每个分支对应一个可用的特征:年龄、性别和种族。

我们的卷积层的默认结构基于一个带有 ReLU 激活的 Conv2D 层,然后是 BatchNormalization 层、MaxPooling 层,最后是 MaxPooling 层。这些层中的每一层之后是最终的致密层。对我们试图预测的每个输出重复这一步。

这些默认层是在make _ default _ hidden _ layers方法中定义的,它将在构建我们模型的每个分支时被重用。在下面的代码中,我们将定义负责创建多输出模型的类。

from keras.models import Model
from keras.layers.normalization import BatchNormalization
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Dropout
from keras.layers.core import Lambda
from keras.layers.core import Dense
from keras.layers import Flatten
from keras.layers import Input
import tensorflow as tfclass UtkMultiOutputModel():
    """
    Used to generate our multi-output model. This CNN contains three branches, one for age, other for 
    sex and another for race. Each branch contains a sequence of Convolutional Layers that is defined
    on the make_default_hidden_layers method.
    """
    def make_default_hidden_layers(self, inputs):
        """
        Used to generate a default set of hidden layers. The structure used in this network is defined as:

        Conv2D -> BatchNormalization -> Pooling -> Dropout
        """
        x = Conv2D(16, (3, 3), padding="same")(inputs)
        x = Activation("relu")(x)
        x = BatchNormalization(axis=-1)(x)
        x = MaxPooling2D(pool_size=(3, 3))(x)
        x = Dropout(0.25)(x) x = Conv2D(32, (3, 3), padding="same")(x)
        x = Activation("relu")(x)
        x = BatchNormalization(axis=-1)(x)
        x = MaxPooling2D(pool_size=(2, 2))(x)
        x = Dropout(0.25)(x) x = Conv2D(32, (3, 3), padding="same")(x)
        x = Activation("relu")(x)
        x = BatchNormalization(axis=-1)(x)
        x = MaxPooling2D(pool_size=(2, 2))(x)
        x = Dropout(0.25)(x) return x def build_race_branch(self, inputs, num_races):
        """
        Used to build the race branch of our face recognition network.
        This branch is composed of three Conv -> BN -> Pool -> Dropout blocks, 
        followed by the Dense output layer.
        """
        x = self.make_default_hidden_layers(inputs) x = Flatten()(x)
        x = Dense(128)(x)
        x = Activation("relu")(x)
        x = BatchNormalization()(x)
        x = Dropout(0.5)(x)
        x = Dense(num_races)(x)
        x = Activation("softmax", name="race_output")(x) return x def build_gender_branch(self, inputs, num_genders=2):
        """
        Used to build the gender branch of our face recognition network.
        This branch is composed of three Conv -> BN -> Pool -> Dropout blocks, 
        followed by the Dense output layer.
        """
        x = Lambda(lambda c: tf.image.rgb_to_grayscale(c))(inputs) x = self.make_default_hidden_layers(inputs) x = Flatten()(x)
        x = Dense(128)(x)
        x = Activation("relu")(x)
        x = BatchNormalization()(x)
        x = Dropout(0.5)(x)
        x = Dense(num_genders)(x)
        x = Activation("sigmoid", name="gender_output")(x) return x def build_age_branch(self, inputs):   
        """
        Used to build the age branch of our face recognition network.
        This branch is composed of three Conv -> BN -> Pool -> Dropout blocks, 
        followed by the Dense output layer. """
        x = self.make_default_hidden_layers(inputs) x = Flatten()(x)
        x = Dense(128)(x)
        x = Activation("relu")(x)
        x = BatchNormalization()(x)
        x = Dropout(0.5)(x)
        x = Dense(1)(x)
        x = Activation("linear", name="age_output")(x) return x def assemble_full_model(self, width, height, num_races):
        """
        Used to assemble our multi-output model CNN.
        """
        input_shape = (height, width, 3) inputs = Input(shape=input_shape) age_branch = self.build_age_branch(inputs)
        race_branch = self.build_race_branch(inputs, num_races)
        gender_branch = self.build_gender_branch(inputs) model = Model(inputs=inputs,
                     outputs = [age_branch, race_branch, gender_branch],
                     name="face_net") return model

model = UtkMultiOutputModel().assemble_full_model(IM_WIDTH, IM_HEIGHT, num_races=len(dataset_dict['race_alias']))

让我们看一下我们的模型结构,以便更好地理解我们正在构建什么。从中我们可以看到,我们有一个单一的输入,在我们的情况下,是我们正在向 CNN 提供的图像,它确实分解为三个独立的分支,每个分支都有自己的卷积层,然后是各自的密集层。

训练我们的模型

现在,一旦我们有了可以使用的数据和定义的模型架构,就该训练我们的多输出模型了。但是在进行这一步之前,我们需要编译我们的模型。对于这个任务,我们将使用 0.0004 的学习率和 Adam 优化器,但是您也可以随意尝试其他超参数。我们还将为每个特征使用自定义损失权重和自定义损失函数。在构建我们的优化器时,让我们使用一个基于学习率除以时期数的衰减,因此我们将在时期内慢慢降低我们的学习率。

from keras.optimizers import Adaminit_lr = 1e-4
epochs = 100opt = Adam(lr=init_lr, decay=init_lr / epochs)model.compile(optimizer=opt, 
              loss={
                  'age_output': 'mse', 
                  'race_output': 'categorical_crossentropy', 
                  'gender_output': 'binary_crossentropy'},
              loss_weights={
                  'age_output': 4., 
                  'race_output': 1.5, 
                  'gender_output': 0.1},
              metrics={
                  'age_output': 'mae', 
                  'race_output': 'accuracy',
                  'gender_output': 'accuracy'})

现在,让我们用有效集和训练集的批量大小 32 来训练我们的模型。我们将使用一个模型检查点回调,以便在每个时期结束时将模型保存在磁盘上。

from keras.callbacks import ModelCheckpointbatch_size = 32
valid_batch_size = 32
train_gen = data_generator.generate_images(train_idx, is_training=True, batch_size=batch_size)
valid_gen = data_generator.generate_images(valid_idx, is_training=True, batch_size=valid_batch_size)callbacks = [
    ModelCheckpoint("./model_checkpoint", monitor='val_loss')
]history = model.fit_generator(train_gen,
                    steps_per_epoch=len(train_idx)//batch_size,
                    epochs=epochs,
                    callbacks=callbacks,
                    validation_data=valid_gen,
                    validation_steps=len(valid_idx)//valid_batch_size)

训练完模型后,让我们更好地了解一下模型在各个时期的训练集和验证集上的表现:

比赛准确性

plt.clf()
fig = go.Figure()
fig.add_trace(go.Scatter(
                    y=history.history['race_output_acc'],
                    name='Train'))fig.add_trace(go.Scatter(
                    y=history.history['val_race_output_acc'],
                    name='Valid')) fig.update_layout(height=500, 
                  width=700,
                  title='Accuracy for race feature',
                  xaxis_title='Epoch',
                  yaxis_title='Accuracy')fig.show()

我们可以看到,在第 50 个时期,我们的模型在验证集上稳定下来,仅在训练集上有所增加,准确率约为 80%。

性别准确性

plt.clf()fig = go.Figure()
fig.add_trace(go.Scatter(
                    y=history.history['gender_output_acc'],
                    name='Train'))fig.add_trace(go.Scatter(
                    y=history.history['val_gender_output_acc'],
                    name='Valid')) fig.update_layout(height=500, 
                  width=700,
                  title='Accuracy for gender feature',
                  xaxis_title='Epoch',
                  yaxis_title='Accuracy') fig.show()

与种族特征类似,我们可以看到,我们的模型能够学习大多数模式,以在第 30 个时期正确预测给定个体的性别,准确率约为 90%。

年龄平均绝对误差

plt.clf()fig = go.Figure()
fig.add_trace(go.Scattergl(
                    y=history.history['age_output_mean_absolute_error'],
                    name='Train'))fig.add_trace(go.Scattergl(
                    y=history.history['val_age_output_mean_absolute_error'],
                    name='Valid')) fig.update_layout(height=500, 
                  width=700,
                  title='Mean Absolute Error for age feature',
                  xaxis_title='Epoch',
                  yaxis_title='Mean Absolute Error')fig.show()

在预测年龄特征的任务中,我们可以看到,我们的模型需要大约 60 个时期来适当地稳定其学习过程,平均绝对误差为 0.09。

总体损失

fig = go.Figure()
fig.add_trace(go.Scattergl(
                    y=history.history['loss'],
                    name='Train'))fig.add_trace(go.Scattergl(
                    y=history.history['val_loss'],
                    name='Valid')) fig.update_layout(height=500, 
                  width=700,
                  title='Overall loss',
                  xaxis_title='Epoch',
                  yaxis_title='Loss')fig.show()

我们可以注意到,到了时期 50,我们的模型开始稳定,损失值大约为 1.4。在损失曲线中也有一个峰值,它确实出现在年龄特征的平均绝对误差中,这可以解释年龄特征的学习对总损失的影响。

在测试集上评估我们的模型

为了评估我们的模型在测试集上的表现,让我们使用我们的 UTK 数据生成器类,但是这次使用测试索引。然后,我们将从训练好的模型中调用 predict_generator 方法,该方法将输出测试集的预测。

test_batch_size = 128
test_generator = data_generator.generate_images(test_idx, is_training=False, batch_size=test_batch_size)
age_pred, race_pred, gender_pred = model.predict_generator(test_generator, 
                                                           steps=len(test_idx)//test_batch_size)

让我们在所有测试样本上再迭代一次,以便将它们的标签放在一个列表中。我们还将提取每个记录的 argmax ,以便检索顶级预测和基本事实。

test_generator = data_generator.generate_images(test_idx, is_training=False, batch_size=test_batch_size)
samples = 0
images, age_true, race_true, gender_true = [], [], [], []
for test_batch in test_generator:
    image = test_batch[0]
    labels = test_batch[1]

    images.extend(image)
    age_true.extend(labels[0])
    race_true.extend(labels[1])
    gender_true.extend(labels[2])

age_true = np.array(age_true)
race_true = np.array(race_true)
gender_true = np.array(gender_true)race_true, gender_true = race_true.argmax(axis=-1), gender_true.argmax(axis=-1)
race_pred, gender_pred = race_pred.argmax(axis=-1), gender_pred.argmax(axis=-1)age_true = age_true * data_generator.max_age
age_pred = age_pred * data_generator.max_age

最后,让我们打印测试集上每个特性的分类报告。

from sklearn.metrics import classification_reportcr_race = classification_report(race_true, race_pred, target_names=dataset_dict['race_alias'].keys())
print(cr_race)precision    recall  f1-score   support white       0.80      0.91      0.85      2994
       black       0.86      0.82      0.84      1327
       asian       0.86      0.79      0.83      1046
      indian       0.74      0.74      0.74      1171
      others       0.38      0.19      0.25       502 accuracy                           0.80      7040
   macro avg       0.73      0.69      0.70      7040
weighted avg       0.78      0.80      0.78      7040

从上面的报告中,我们可以看到,我们的模型在预测亚裔和黑人个体方面非常出色,准确率为 86%,其次是白人 80%,印度人 74%。“其他”种族的精确度仅为 38%,但我们需要考虑到,与其他群体相比,该群体由不同的种族和民族以及一些样本组成。这一分类任务的加权准确率为 78%,表明我们的分类器能够正确地学习模式以区分不同类型的种族。

cr_gender = classification_report(gender_true, gender_pred, target_names=dataset_dict['gender_alias'].keys())
print(cr_gender)**precision    recall  f1-score   support** **male       0.94      0.87      0.91      3735
      female       0.87      0.94      0.90      3305** **accuracy                           0.90      7040
   macro avg       0.90      0.91      0.90      7040
weighted avg       0.91      0.90      0.90      7040**

从这个报告中,我们可以注意到,我们的模型在预测给定个体的性别方面非常出色,对于这项任务,加权准确率为 91%。

from sklearn.metrics import r2_scoreprint('R2 score for age: ', r2_score(age_true, age_pred))

R2 年龄得分:0.582979466456328

参考

http://aicip.eecs.utk.edu/wiki/UTKFace UTK 人脸数据集:

Keras 多输出文档:https://keras.io/getting-started/functional-api-guide/

SanjayaSubedi 关于多输出模型的帖子:https://sanjayasubdi . com . NP/deep learning/multi output-keras/

时尚网上的 PyImageSearch 帖子:https://www . PyImageSearch . com/2018/06/04/keras-multiple-outputs-and-multiple-loss/

剧情:https://plot.ly/

构建朴素贝叶斯分类器:预测酒店取消

原文:https://towardsdatascience.com/building-a-naive-bayes-classifier-predicting-hotel-cancellations-31e3b8766614?source=collection_archive---------36-----------------------

在此示例中,构建了一个朴素贝叶斯分类器,以预测可能取消酒店预订的客户。

朴素贝叶斯分类器是一种概率分类器,也是最基本的分类模型之一。我们称该分类器为“幼稚”分类器的原因是因为该分类器天真地假设数据集中的所有特征相互独立,即条件独立。

来源:照片由埃里克·斯坦皮克斯拜拍摄。

从这个角度来看,特征选择通常不是朴素贝叶斯分类器的优势。假设所有的特征都是相互独立的,那么当特征之间存在显著的相关性时,这个分类器就有表现不佳的风险。

贝叶斯定理定义如下:

来源:作者图片

这个定理的基础是条件概率,即给定前一个结果的发生,一个结果发生的概率。在这种情况下,特定事件发生的概率随着新信息的收集而更新。

对于这个特定的场景,我们希望找到答案——在给定先验概率的情况下,客户取消酒店预订的概率是多少?

在这种情况下,将应用高斯朴素贝叶斯分类算法。尽管结果变量是分类变量(1 =取消,0 =不取消),但模型中包含的许多特征是连续的。因此,假设这些连续特征按照正态(高斯)分布分布。

数据操作

在这点上,在运行朴素贝叶斯模型之前不会进行特征选择。该模型使用以下功能构建:

  1. 交付周期
  2. 到达日期年份
  3. arrivaldateweekno
  4. 抵达日期
  5. staysweekendnights
  6. 周末夜
  7. 成年人
  8. 婴儿
  9. isrepeatedguest
  10. 以前的取消
  11. 先前预订未取消
  12. 预订变更
  13. dayswaitinglist
  14. adr
  15. RCP
  16. 总计数量
  17. 到达日期月
  18. 国家
  19. 细分市场
  20. 分销渠道
  21. reservedroomtype
  22. assignedroomtype
  23. 沉积类型
  24. 客户类型

定义了区间(或连续随机变量)。举两个例子:

leadtime = train_df['LeadTime']
adr = train_df['ADR']

使用'''类别代码' ' '定义具有分类成分的变量。

作为另外两个例子:

deposittypecat=train_df.DepositType.astype("category").cat.codes
deposittypecat=pd.Series(deposittypecat)
customertypecat=train_df.CustomerType.astype("category").cat.codes
customertypecat=pd.Series(customertypecat)

numpy 列堆栈是为独立变量(连续变量和分类变量)制定的:

x1 = np.column_stack((leadtime,arrivaldateyear,arrivaldateweekno,arrivaldatedayofmonth,staysweekendnights,staysweeknights,adults,babies,isrepeatedguestcat,previouscancellations,previousbookingsnotcanceled,bookingchanges,dayswaitinglist,adr,rcps,totalsqr,arrivaldatemonthcat,mealcat,countrycat,marketsegmentcat,distributionchannelcat,reservedroomtypecat,assignedroomtypecat,deposittypecat,customertypecat))
x1 = sm.add_constant(x1, prepend=True)

然后,数据被分成训练集和验证集:

X_train, X_val, y_train, y_val = train_test_split(x1, y1)

精确度与召回率和 f1 分数

在我们运行模型之前,让我们稍微谈一下精度召回

当比较准确度分数时,我们看到在每个混淆矩阵中都提供了大量的读数。

Precision = ((True Positive)/(True Positive + False Positive))Recall = ((True Positive)/(True Positive + False Negative))

这两个读数经常相互矛盾,也就是说,通常不可能在不降低召回率的情况下提高精确度,反之亦然。

对理想指标的评估很大程度上取决于所分析的具体数据。例如,癌症检测筛查出现假阴性(即表明患者没有患癌症,而事实上他们患有癌症)是一大禁忌。在这种情况下,召回是理想的衡量标准。

然而,对于电子邮件,人们可能更喜欢避免误报,例如,将一封重要的电子邮件发送到垃圾邮件文件夹,而实际上它是合法的。

f1 分数在设计一个更通用的分数时考虑了精确度和召回率。

哪个因素对预测酒店取消更重要?

从酒店的角度来看,他们可能希望更准确地识别出最终会取消预订的客户,这使得酒店能够更好地分配房间和资源。确定不打算取消预订的客户不一定会增加酒店分析的价值,因为酒店知道,无论如何,很大一部分客户最终都会坚持预订。

模型配置和结果

上面概述的相关特征包括在内,用于确定客户是否将取消他们的预订。

GaussianNB 库是从 scikit-learn 导入的:

from sklearn.naive_bayes import GaussianNB

高斯朴素贝叶斯模型被定义为:

>>> gnb = GaussianNB()
>>> gnbGaussianNB(priors=None, var_smoothing=1e-09)

在验证集上生成预测:

>>> y_pred = gnb.fit(x1_train, y1_train).predict(x1_val)
>>> y_predarray([1, 1, 0, ..., 0, 1, 1])

将预测与来自验证集的实际结果进行比较,生成混淆矩阵:

>>> from sklearn.metrics import classification_report,confusion_matrix
>>> print(confusion_matrix(y1_val,y_pred))
>>> print(classification_report(y1_val,y_pred))[[2842 4424]
 [ 165 2584]]
              precision    recall  f1-score   support 0       0.95      0.39      0.55      7266
           1       0.37      0.94      0.53      2749 accuracy                           0.54     10015
   macro avg       0.66      0.67      0.54     10015
weighted avg       0.79      0.54      0.55     10015

第 1 类的召回率为 94% ,而 f1 分数的准确率为 54% 。现在,让我们在 H2(测试集)上测试预测性能。

[[ 7863 38365]
 [ 2722 30380]]
              precision    recall  f1-score   support 0       0.74      0.17      0.28     46228
           1       0.44      0.92      0.60     33102 accuracy                           0.48     79330
   macro avg       0.59      0.54      0.44     79330
weighted avg       0.62      0.48      0.41     79330

我们看到,1 类的召回率略微下降至 92% ,而 f1 分数的准确率为 48%

显然,在较高的召回率和总体较高的准确率之间存在一种权衡。假设数据集中的大多数条目为 0(未取消),那么有理由认为具有总体高准确率的模型在预测未取消方面表现得相当好,但是在预测 1 条目(取消)方面表现不佳。

例如,当对此数据集运行 SVM 时,会获得以下结果:

[[25217 21011]
 [ 8436 24666]]
              precision    recall  f1-score   support 0       0.75      0.55      0.63     46228
           1       0.54      0.75      0.63     33102 accuracy                           0.63     79330
   macro avg       0.64      0.65      0.63     79330
weighted avg       0.66      0.63      0.63     79330

我们看到 f1 分数的准确率高达 63%,但是 1 类的召回率下降到 75%。

在这方面,如果希望优先识别取消,而不是最大化整体准确性,那么可以认为朴素贝叶斯模型在这种情况下工作得更好。然而,应该记住,最大化回忆只在一定程度上起作用。如果召回率为 100%,那么所有预订都可以归类为取消,这并不能揭示取消预订的客户和未取消预订的客户之间的差异。

限制

如前所述,朴素贝叶斯认为所有特征都是独立的。在这方面,在变量之间存在强烈的条件依赖性的情况下,该模型有表现不佳的风险,例如,假设在来自特定来源国的客户中观察到更多的取消。但是,我们也观察到,在特定的细分市场中,这些取消率要高得多。

在这方面,考虑到这两个特征之间的条件依赖性,我们不能再确定来自特定来源国的客户的取消率更高,因为来自特定细分市场的更高数量的客户可能正好出现在来自该特定国家的预订中。

特征选择是机器学习的重要组成部分,事实上,有许多模型能够解释哪些特征对影响结果变量的贡献更大,如下例所示。

来源:InterpretML 输出

但是,朴素贝叶斯假设所有要素的权重基本相等,这可能会根据数据显著影响读数的准确性。

结论

在这个例子中,我们看到了如何在 Python 中构建朴素贝叶斯模型,以及如何使用精度和召回率来评估模型的准确性。

本例的数据集和笔记本可从 MGCodesandStats GitHub 库获得,以及对该主题的进一步研究。

免责声明:本文是在“原样”的基础上编写的,没有担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。

参考

从 Twitter 数据中构建网络图

原文:https://towardsdatascience.com/building-a-network-graph-from-twitter-data-a5e7b8672e3?source=collection_archive---------15-----------------------

编写 Java 应用程序来收集 Twitter 数据,并以图表的形式显示出来。

在本文中,我们将构建一个数据科学项目。我们从 Twitter 上收集数据,因为它有大量的数据,这让我们可以获得这些数据。我们更喜欢 Java,因为它是一种编译语言,并且有强大的并发库。最后,我们使用开源图形平台 Gephi 对这些数据进行总结。

使用 Gephi 从 9/14/20 的样本推文中生成的图表。语言是 TH

我们需要以下做这个项目:

  • Java IDE。我们的选择是日蚀。
  • Twitter4j 库。从这里获取 jar 文件和教程。
  • Twitter 开发者账号。我们需要这个来调用 Twitter API。有一些资源提到了如何获得访问权限。
  • 任何符合 JDBC 标准的数据库。我们使用 Sqlite。它很轻。不需要安装软件。没有守护进程。只需将 Sqlite jar 文件复制到项目中。但是,有一些限制需要解决。
  • Gephi 是一个开源的图形工具。从这里下载。

顺便说一下,读者可以使用他们喜欢的任何语言或平台,Python 或 Node.js。

以下是构建 Twitter 网络图的步骤:

  • 收集推文和用户,并保存到数据库中。
  • 检索用户的朋友。从上一步的用户列表中,获取这些用户的朋友。我们将把这些保存到表格中
  • 筛选我们希望在图表中看到的数据
  • 将数据导出到 CSV 文件
  • 将 CSV 文件导入 Gephi。做一些格式化,布局。我们会得到一个 twitter 社交图

收集推文和用户

第一步,我们收集样本 tweets,然后将它们写到表中。为此:

  • 创建一个 twitter 流对象。对溪流进行采样。API 提供了所有 tweets 的随机子集。
  • 对于收到的每条 tweet,向 executor 服务提交一个可调用的任务。该任务将执行数据库操作和/或进一步的处理。

下面是代码:

可调用任务中的代码会将 tweets 和相关对象(如用户)保存到表中。通过使用 executor 服务,我们分离了 tweet 处理和数据库相关的任务。即使有时推文的速度超过了数据库的处理速度,我们的应用程序仍然不会错过任何东西。此外,因为我们使用 Sqlite 数据库,并且在一个时刻只能有一次对数据库的写入,所以 executor 服务必须是单线程 Executor。以下是该任务的部分代码:

检索用户的朋友

从上一步,我们得到了一个用户列表,我们想知道他们所有的朋友。Twitter API 返回指定用户的朋友 id,但单次请求不会超过 5000 个 id。如果该用户拥有更多,我们需要多次呼叫。此外,Twitter 有费率限制。它只允许每个 15 分钟的窗口有 15 个请求。基本上每分钟 1 个请求。

所以,我们得到了朋友 id。需要其他 API 调用来将用户 id 转换为用户对象。Twitter 为此提供了 API。对于每个请求,我们可以查询多达 100 个用户 id。对此速率限制是每 15 分钟窗口 300 个请求。所以,是每分钟 20 个请求。

Twitter API 和速率限制的更多细节点击这里

为了有效地处理速率限制,我们将有两个线程。第一个线程将调用朋友 id 查询。第二个线程将执行用户查找部分。朋友查找线程将通过阻塞队列将用户 id 传递给用户查找线程。基本上,我们在这里使用生产者-消费者模式。

朋友查找线程

以下代码是 FriendsLookupRunnable 的一部分。

一些要点:

  • 这个 runnable 的 run 方法将从要处理的用户 id 阻塞队列中轮询一个用户 id。
  • 对于每个 id,调用 getFriendIds 方法。这个方法返回朋友 id 列表。每个用户 id 和朋友 id 对都被插入到 User_friend 表中。
  • 得到朋友 id 也被放入另一个阻塞队列。这些 id 将由另一个线程检索并进行处理。
  • getFriendIds 方法跟踪最后一次调用它的时间,并通过使用 Thread.sleep()确保每次调用之间有足够的延迟(1 分钟)。
  • 即使我们这样做了,也很少有超出速率限制的异常情况发生。因此,我们捕获 TwitterException 并比较异常状态代码。如果超过了速率限制,我们就重试查询。
  • 还有一些其他的例外。例如,当用户受到保护时,twitter API 会给你一个未经授权的错误。

以下是创建 User_Friend 表的命令,该表存储第一个线程的结果:

CREATE TABLE User_Friend ( user_id       INT (8), friend_id     INT (8), PRIMARY KEY (user_id,friend_id));

用户查找线程

下面的代码是 UsersLookupRunnable 类。

以下是一些要点:

  • 在 run 方法中,有一个 while 循环从队列中检索用户 id。然后它将调用 lookupUsers 方法进行实际的查找
  • 因为 Twitter lookupUsers API 一次只能处理不超过 100 个用户 id,所以在调用 Twitter API 之前,我们将把一个用户 id 数组分割成包含 100 个或更少元素的数组。
  • lookupUsers 方法跟踪上次调用它的时间,并通过使用 Thread.sleep()确保每次调用之间有足够的延迟(3 秒)。
  • 该方法返回将被插入到用户表中的用户列表。表格的结构应该类似于 Twitter 用户界面。

以下是创建存储第二个线程结果的用户表的命令:

CREATE TABLE User ( id              INT (8)       PRIMARY KEY, name            VARCHAR (100), screen_name     VARCHAR (100), description     VARCHAR (255), email           VARCHAR (50), favorites_count INT, followers_count INT, friends_count   INT, statuses_count  INT, lang            VARCHAR (10), location        VARCHAR (255), url             VARCHAR (255), imageurl        VARCHAR (255), is_protected    INT (1), is_verified     INT (1), created         VARCHAR (20), last_modified   VARCHAR (20));

主要的方法是:

  • 设置数据库连接
  • 创建 2 个阻塞队列
  • 准备用户 id 列表。将其添加到第一个阻塞队列中。
  • 创建 2 个可运行线程和 2 个线程。
  • 启动两个线程。
  • 添加关机挂钩。所以,当进程终止时,它会中断两个线程。
  • 等到两个线程都完成。
  • 清理数据库

代码应该如下所示:

过滤数据(可选)

有时,我们希望只看到全部数据的一部分。这样做很简单,因为数据已经在 SQL 表中了。假设我们想看看在我们的样本推文中拥有最多关注者的前 100 名用户是如何相互关注的。以下是要做的事情:

  • 创建用于存储结果的表格。下面是使用的 SQL 语句:
CREATE TABLE Graph_Friend_Edge ( Source      INT, Target      INT );
CREATE TABLE Graph_Friend_Node ( id              INT      PRIMARY KEY, label           VARCHAR (50), name            VARCHAR (100),);
  • 仅用顶级用户填充边缘表。以下是 SQL 语句:
insert into graph_friend_edge(source, target)select user_id, friend_id from user_friendjoin user u1 on friend_id=u1.idjoin user u2 on user_id=u2.idwhere user_id in(select friend_id from user_friendgroup by friend_id order by count(*) desc limit 100)and friend_id in(select friend_id from user_friend group by friend_id order by count(*) desc limit 100);
  • 然后,用以下 SQL 填充节点表:
insert into graph_friend_node(id, label, name)select n.id, u.screen_name, u.namefrom(select source id from graph_friend_edgeunionselect target id from graph_friend_edge) n join user u on n.id = u.id;

将数据导出到 CSV 文件

这部分很简单。使用数据库工具将数据导出到 CSV 文件。

  • 将 user_friend 表导出到 edge CSV 文件。
  • 将用户表导出到节点 CSV 文件。

创建网络图

Gephi 是一个开源的图形分析和可视化工具。外面有很多 Gephi 教程。看一看这里。导入 CSV 文件教程,在这里找到

以下是在我们的项目中要做的步骤概述:

  • 打开 Gephi。创建新项目。
  • 导入边和节点 CSV 文件。最初的图表可能看起来不像这样:

9/14/20 应用样本推文布局前的前 100 名用户好友图表。语言是 TH

我们需要显示节点标签。配置节点大小和颜色。应用一些布局。

  • 启用节点标签
  • 配置与入度(传入边的数量)成比例的节点大小和标签大小
  • 选择“ForceAtlas2”的布局并运行它。
  • 运行社区检测算法
  • 根据模块等级设置节点颜色。这将根据它检测到的社区给节点着色。

完成这些后,图表看起来更有意义:

  • 用户的屏幕名称显示为节点标签。
  • 该组中拥有更多追随者的节点看起来更大。
  • 边,箭头线,代表跟随关系
  • 根据图算法,具有相同颜色的节点在相同的社区中。

使用 Gephi 从 9/14/20 的样本推文中生成的前 100 名用户的朋友图。语言是 TH

结论

我们构建了 Java 应用程序来从 Twitter 收集推文、用户和朋友数据,并将其放入关系数据库。我们对数据做了一些过滤。然后,导入到 Gephi,图形平台和可视化工具,产生一个社会网络图。

这只是我们利用 Twitter 数据所能做的很小一部分。Gephi 能给我们提供更多的东西。此外,还有更多图形分析平台。例如,Neo4j 可以让我们将数据存储到它的数据库中,并运行图形算法。

用 PyTorch Lightning 在亚马逊 SageMaker 上构建神经网络

原文:https://towardsdatascience.com/building-a-neural-network-on-amazon-sagemaker-with-pytorch-lightning-63730ec740ea?source=collection_archive---------25-----------------------

用现代工具为每个数据科学家民主化人工智能

图片由com break来自 Pixabay 。闪电的力量可以点燃火炬。

在现实世界的应用中,托管人工智能服务,如亚马逊认知亚马逊理解为专门的数据科学团队从零开始构建模型提供了一个可行的替代方案。即使当用例需要使用定制图像标签或文本实体等专门构建的数据集进行模型重新训练时,也可以使用 Amazon Rekognition 定制标签Amazon understand 定制实体轻松实现。

这些服务提供最先进的机器学习模型实现,涵盖几个用例。这种模型在某些情况下并不可行。这可能是因为底层网络需要根据数据进行深度定制,科学家需要实施先进的网络架构,如 LSTMs、GANs、OneShot learners、强化学习模型甚至模型集成。

在机器学习中,研究和模型构建是一项永无止境的工作,每天都开放一套全新的功能。然而,通常需要一个由不同专业人员组成的大型团队来构建从神经网络架构定义到生产部署的模型。

Amazon SageMaker 旨在为每个人实现机器学习的民主化,提供了一套针对数据科学家和软件工程师的工具。截至 2020 年,亚马逊 SageMaker (SM)是一套工具,专门用于数据集标签化(SM GroundTruth)、模型开发(SM 笔记本)、分布式训练和推理部署(SM 模型/端点)以及实验创建、调试和监控(SageMaker Studio)。

短短几年间,出现了许多深度学习框架,从 TensorFlow、Apache MXNet 和 PyTorch 开始,每一个都提高了模型创建和定制的门槛。最有前途的技术之一,由于它在动态计算图形定义和数据并行性支持方面的灵活性。

有了闪电,PyTorch 变得既简单又强大。

Amazon SageMaker 从第一天起就引入了对 PyTorch 的支持,并在过去几年中建立了稳定的用户基础。然而,PyTorch 错过了 Keras(tensor flow)等替代方案的简单性、低学习曲线和高抽象级别。开发了一些框架来填补空白,例如优秀的 Fast.ai 库,旨在为接近 PyTorch 的开发人员提供一个简单易学的解决方案。

2019 年,为了让机器学习的努力成为一个共同点,威廉·猎鹰发布了第一个生产就绪版本的 PyTorch Lightning ,这是一个架构 PyTorch 项目的框架,获得了对更少样板文件和改进代码阅读的支持。

在本文中,我们将从一个简单的神经网络创建开始,遵循一个统一的工作流程,在 Amazon SageMaker 上开发、测试和部署一个机器学习模型,并有一个循序渐进的教程,侧重于初学者。不需要预先了解 Amazon SageMaker 或 PyTorch,即使它有助于理解一些语言 API。

MNIST 是新的“你好世界”

我们将从一个用于手写数字识别的简单神经网络开始,使用著名的 MNIST 数据集。用例非常狭窄,但近年来,由于结果模型的简单性,它已经成为使用神经网络进行图像处理的“Hello World”。

亚马逊 SageMaker 笔记本

处理机器学习项目的第一步是在一些实验环境中建立模型。亚马逊 SageMaker 笔记本提供 JupyterLab 环境的简单设置。PyTorch 通过 torchvision 库提供了一个准备好的数据集。由于本文想要展示一个适用于通用模型训练的工作流,我们决定不使用 PyTorch 数据集,而是从互联网上下载 MNIST 图像并保存到 S3 桶中。

当使用 SageMaker Studio 构建模型时,我们建议在本地下载一堆数据,以加快开发和测试速度。我们可以使用以下命令轻松做到这一点:

现在,我们可以显示一些随机数据,只是为了在开始构建 Lightning 模型之前更好地理解它是如何组织的。

手写数字图像的小 MNIST 数据集。

MNIST 分类器和亚马逊 SageMaker

在我们建立 PyTorch 评估之后,Amazon SageMaker 管理来自 Python 代码的代码运行。估计器是一个类,包含训练所需的所有必需参数(或在 SageMaker 容器上运行的推理脚本)。

上图显示了如何为 PyTorch 创建 SageMaker 估计器。详细解释代码中的注释。

为了执行具有卷积层的神经网络的训练,我们必须使用 GPU 在 ml.p2.xlarge 实例上运行我们的训练作业。

Amazon Sagemaker 默认将训练代码放在我们项目中的代码文件夹中,但是它的路径可以在实例化 Estimator 时被覆盖。训练脚本是 PyTorch 闪电的神奇之处。

我们模特的培训班。详细解释代码中的注释。

我们的训练器可以在本地 GPU 平台或 Amazon SageMaker 容器上运行,无需任何更改。

Amazon SageMaker 的神奇之处在于默认为教练和模型参数的环境变量。在一个容器中,这些变量被设置到文件夹中,这些文件夹是在运行我们的脚本之前从 S3 复制的,在训练完成之后又被复制回 S3。

在这一点上,我们还没有定义一个模型,只是映射了一些变量并配置了一个估计器对象,但是一些 Lightning 特定的构造已经可见,例如训练器类。

Trainer,顾名思义,是一个 Python 类,能够抽象所有训练工作流步骤,加上一系列日常操作,如在每个纪元后保存模型检查点。培训师自动执行一系列活动,例如寻找最佳学习率确保可重复性、设置并行培训的 GPU 和多节点后端的数量、更多

Lightning 提供了一组默认设置,让训练变得超级简单。值可以被覆盖,因为它完全控制整个生命周期,因为我们的分类器类必须符合协议。

让我们分解代码,检查每一步发生了什么

1。导入库并扩展 LightningModule

每个 PyTorch Lightning 实现都必须扩展 base pl。继承自 nn 的 LightningModule 类。模块增加了一些实用方法。

2。准备网络层

在类构造函数中,我们准备了网络层,用于以后构建计算图。卷积层从图像中提取特征,并传递给随后的层,增加了非线性和随机性。

3.为训练、验证和测试数据集构建数据加载器

数据加载器类是从 PyTorch 图像加载器精心制作的。混洗和分割确保了从训练图像构建的随机验证数据集。

4.实施培训师要求的实用方法

PyTorch Lightning 实施了一个标准的项目结构,要求分类器实现某些方法,这些方法将由训练器类在执行训练和验证时调用。

5.机具向前传递

forward 方法相当于传统的 PyTorch forward 函数,必须实现该函数才能构建计算图。

6.实施培训步骤

训练器对每个图像批次调用训练步骤方法,计算网络预测和它们的相对损失函数。

7.验证计算和堆叠

Lightning 提供了对一组可选方法的支持,如 validation_stepvalidation_epoch_end、validation_end ,以允许开发人员定义如何计算验证损失并堆叠结果,从而在训练期间找到改进。这些方法要求代码返回符合特定模式的数据,然后 PL 以 TensorBoard 兼容格式输出所有指标。

可以实现等效的方法来支持模型测试,这在投入生产之前是非常鼓励的。

现在我们准备好让我们的模型旋转起来,并开始用 Amazon SageMaker 进行训练。

亚马逊 SageMaker 上的模型培训

训练开始从命令行或另一个 Jupyter 笔记本运行 main.py 。它也可以从 AWS Lambda 函数运行,由 AWS Step 函数调用,以使训练过程完全可脚本化且无需服务器。然而,日志被收集到控制台中,并被推送到 Amazon CloudWatch 以供进一步检查。当启动多个训练任务来微调超参数时,此功能非常有用。

亚马逊 SageMaker 培训作业的控制台输出。

Amazon SageMaker 代表我们启动 p2.xlarge 实例,然后将输入数据下载到容器中并启动我们的代码,在安装了我们的 requirements.txt 文件中的所有依赖项之后,启动 main.py、

亚马逊 SageMaker 培训作业的控制台输出。

Amazon SageMaker 以 JSON 格式构建一个作业描述符,并将其传递给训练上下文。在这个对象中,所有参数被发送到训练作业,输入目录被映射到 /opt/ml/ 子文件夹,从 S3 接收数据,输出被收集到结果桶中。训练代码也打包在不同的 S3 路径中,然后下载到容器中。

最后,在启动我们的训练脚本之前,环境变量被设置为标准的 SageMaker 值。

几分钟后,由于我们只训练了六个纪元,我们的验证显示出来,保存的模型被上传到 S3。由于 PyTorch Lightning 代表我们自动保存模型检查点,并且我们将其输出目录映射到 output_data_dir,因此我们还可以从 S3 收集中间检查点和验证数据,以备 TensorBoard 处理和分析。

S3 上有一个分类模型,可用于推理脚本、Amazon SageMaker 端点,或者使用 JIT 编译器部署在边缘设备上。

从这里去哪里?

在这篇文章中,我们讨论了 Amazon SageMaker 和 PyTorch Lightning 如何合作实现深度学习的民主化,减少了每个开发人员或数据科学家从零开始构建模型到生产的样板文件。Amazon SageMaker 只用几行代码就减轻了启动和配置训练机器的负担。同时,Lightning 使梯度管理、优化和反向传播等步骤变得透明,使研究人员能够专注于神经网络架构。

该项目的完整代码可在 GitHub 上获得。它可以作为一个独立的脚本在任何 PC 上运行,只需启动

安装 pipenv 的简单 shell 命令,然后运行我们的脚本。感谢 Amazon SageMaker,我们不需要任何 GPU 来训练我们的模型

如果你喜欢 Jupyter 笔记本界面,同样的代码可以在亚马逊 SageMaker、内运行,只需运行Notebook/SageMaker _ deploy . ipynb。由于 SageMaker 启动培训作业,因此不需要有 GPU 实例来运行笔记本。

本文只是一个展示 SageMaker 和 Lightning 如何协同工作的示例项目。尽管如此,它仍可用作图像分类等计算机视觉任务的起点,只需将网络架构更改为类似 VGG 或 ResNet,并提供足够的数据集。

在接下来的文章中,我们将深入研究图像处理的机器学习生产管道,并介绍我们在 Neosperience 中采用的一些架构解决方案,以实现图像记忆和客户行为分析。敬请期待!

我的名字是卢卡·比安奇。我是T5的首席技术官 , 无服务器设计模式和最佳实践 的作者。近十年来,我一直在 AWS 上为大规模生产工作负载构建软件架构。

Neosperience Cloud 是面向品牌的一站式 SaaS 解决方案,旨在带来技术上的共鸣,利用机器学习方面的创新为 1:1 客户体验提供支持。

你可以通过 TwitterLinkedIn 联系我。

使用 Numpy 构建单隐层神经网络

原文:https://towardsdatascience.com/building-a-neural-network-with-a-single-hidden-layer-using-numpy-923be1180dbf?source=collection_archive---------9-----------------------

使用 Numpy 实现具有单个隐藏层的两类分类神经网络

上一篇中,我们讨论了如何使用 NumPy 制作一个简单的神经网络。在本帖中,我们将讨论如何制作一个具有隐藏层的深度神经网络。

  1. 导入库

我们将导入一些基本的 python 库,如 numpy、matplotlib(用于绘制图形)、sklearn(用于数据挖掘和分析工具)等。这是我们需要的。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

2。数据集

我们将使用钞票数据集,该数据集涉及在给定从照片中获取的几个测量值的情况下预测给定钞票是否是真实的。这是一个二元(2 类)分类问题。有 1,372 个具有 4 个输入变量和 1 个输出变量的观察值。更多详情请参见链接。

data = np.genfromtxt(‘data_banknote_authentication.txt’, delimiter = ‘,’)
X = data[:,:4]
y = data[:, 4]

我们可以使用散点图来可视化数据集。我们可以看到两类(真实和非真实)是可分的。我们的目标是建立一个模型来拟合这些数据,也就是说,我们希望建立一个神经网络模型来定义区域是真实的还是不真实的。

plt.scatter(X[:, 0], X[:, 1], alpha=0.2,
 c=y, cmap=’viridis’)
plt.xlabel(‘variance of wavelet’)
plt.ylabel(‘skewness of wavelet’);

现在,让我们将数据分为训练集和测试集。这可以使用 sk learntrain _ test _ split()函数来完成。选择 20%的数据用于测试,80%用于训练。此外,我们将检查训练集和测试集的大小。这将有助于以后设计我们的神经网络模型。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)X_train = X_train.T
y_train = y_train.reshape(1, y_train.shape[0])X_test = X_test.T
y_test = y_test.reshape(1, y_test.shape[0])print (‘Train X Shape: ‘, X_train.shape)
print (‘Train Y Shape: ‘, y_train.shape)
print (‘I have m = %d training examples!’ % (X_train.shape[1]))

print ('\nTest X Shape: ', X_test.shape)

3。神经网络模型

构建神经网络的一般方法是:

1\. Define the neural network structure ( # of input units,  # of hidden units, etc). 
2\. Initialize the model's parameters
3\. Loop:
    - Implement forward propagation
    - Compute loss
    - Implement backward propagation to get the gradients
    - Update parameters (gradient descent)

我们将构建一个具有单一隐藏层的神经网络,如下图所示:

3.1 定义结构

我们需要定义输入单元的数量、隐藏单元的数量和输出层。输入单位等于数据集中的要素数量(4),隐藏层设置为 4(为此),问题是我们将使用单一图层输出的二进制分类。

def **define_structure**(X, Y):
    input_unit = X.shape[0] # size of input layer
    hidden_unit = 4 #hidden layer of size 4
    output_unit = Y.shape[0] # size of output layer
    return (input_unit, hidden_unit, output_unit)(input_unit, hidden_unit, output_unit) = **define_structure**(X_train, y_train)
print("The size of the input layer is:  = " + str(input_unit))
print("The size of the hidden layer is:  = " + str(hidden_unit))
print("The size of the output layer is:  = " + str(output_unit))

3.2 初始化模型参数

我们需要初始化权重矩阵和偏置向量。当偏差设置为零时,权重被随机初始化。这可以使用下面的函数来完成。

def **parameters_initialization**(input_unit, hidden_unit, output_unit):
    np.random.seed(2) 
    W1 = np.random.randn(hidden_unit, input_unit)*0.01
    b1 = np.zeros((hidden_unit, 1))
    W2 = np.random.randn(output_unit, hidden_unit)*0.01
    b2 = np.zeros((output_unit, 1))
    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}

    return parameters

3.3.1 正向传播

对于正向传播,给定一组输入特征(X),我们需要计算每一层的激活函数。对于隐藏层,我们使用 tanh 激活函数:

同样,对于输出层,我们使用 sigmoid 激活函数。

我们可以使用下面的代码来实现向前传播。

def **sigmoid**(z):
    return 1/(1+np.exp(-z))def **forward_propagation**(X, parameters):
    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']

    Z1 = np.dot(W1, X) + b1
    A1 = np.tanh(Z1)
    Z2 = np.dot(W2, A1) + b2
    A2 = sigmoid(Z2)
    cache = {"Z1": Z1,"A1": A1,"Z2": Z2,"A2": A2}

    return A2, cache

3.3.2 计算成本

我们将计算交叉熵成本。在上一节中,我们计算了 A2。使用 A2,我们可以使用以下公式计算交叉熵成本。

def **cross_entropy_cost**(A2, Y, parameters):
    # number of training example
    m = Y.shape[1] 
    # Compute the cross-entropy cost
    logprobs = np.multiply(np.log(A2), Y) + np.multiply((1-Y), np.log(1 - A2))
    cost = - np.sum(logprobs) / m
    cost = float(np.squeeze(cost))

    return cost

3.3.3 反向传播

我们需要计算不同参数的梯度,如下所示。

图片提供:吴恩达

def **backward_propagation**(parameters, cache, X, Y):
    #number of training example
    m = X.shape[1]

    W1 = parameters['W1']
    W2 = parameters['W2']
    A1 = cache['A1']
    A2 = cache['A2']

    dZ2 = A2-Y
    dW2 = (1/m) * np.dot(dZ2, A1.T)
    db2 = (1/m) * np.sum(dZ2, axis=1, keepdims=True)
    dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))
    dW1 = (1/m) * np.dot(dZ1, X.T) 
    db1 = (1/m)*np.sum(dZ1, axis=1, keepdims=True)

    grads = {"dW1": dW1, "db1": db1, "dW2": dW2,"db2": db2}

    return grads

3.3.4 梯度下降(更新参数)

我们需要使用梯度下降规则更新参数,即

其中 𝛼 是学习率 𝜃 是参数。

def **gradient_descent**(parameters, grads, learning_rate = 0.01):
    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']

    dW1 = grads['dW1']
    db1 = grads['db1']
    dW2 = grads['dW2']
    db2 = grads['db2'] W1 = W1 - learning_rate * dW1
    b1 = b1 - learning_rate * db1
    W2 = W2 - learning_rate * dW2
    b2 = b2 - learning_rate * db2

    parameters = {"W1": W1, "b1": b1,"W2": W2,"b2": b2}

    return parameters

4。神经网络模型

最后,把所有的功能放在一起,我们可以建立一个只有一个隐藏层的神经网络模型。

def **neural_network_model**(X, Y, hidden_unit, num_iterations = 1000):
    np.random.seed(3)
    input_unit = **define_structure**(X, Y)[0]
    output_unit = **define_structure**(X, Y)[2]

    parameters = **parameters_initialization**(input_unit, hidden_unit, output_unit)

    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']

    for i in range(0, num_iterations):
        A2, cache = **forward_propagation**(X, parameters)
        cost = **cross_entropy_cost**(A2, Y, parameters)
        grads = **backward_propagation**(parameters, cache, X, Y)
        parameters = **gradient_descent**(parameters, grads)
        if i % 5 == 0:
            print ("Cost after iteration %i: %f" %(i, cost)) return parametersparameters = **neural_network_model**(X_train, y_train, 4, num_iterations=1000)

5。预测

使用学习到的参数,我们可以通过使用前向传播来预测每个示例的类。

def **prediction**(parameters, X):
    A2, cache = forward_propagation(X, parameters)
    predictions = np.round(A2)

    return predictions

如果激活> 0.5,则预测为 1 否则为 0。

predictions = **prediction**(parameters, X_train)
print ('Accuracy Train: %d' % float((np.dot(y_train, predictions.T) + np.dot(1 - y_train, 1 - predictions.T))/float(y_train.size)*100) + '%')predictions = **prediction**(parameters, X_test)
print ('Accuracy Test: %d' % float((np.dot(y_test, predictions.T) + np.dot(1 - y_test, 1 - predictions.T))/float(y_test.size)*100) + '%')

正如我们所看到的,训练精度约为 97%,这意味着我们的模型正在工作,并且以高概率拟合训练数据。测试准确率在 96%左右。给定简单的模型和小的数据集,我们可以认为它是一个好的模型。

在这里成为 Medium 会员,支持独立写作,每月 5 美元,可以完全访问 Medium 上的每个故事。

从头开始构建新闻聚合器:新闻过滤、分类、线索分组和排名

原文:https://towardsdatascience.com/building-a-news-aggregator-from-scratch-news-filtering-classification-grouping-in-threads-and-7b0bbf619b68?source=collection_archive---------9-----------------------

假新闻头条来自https://www . design boom . com/design/the-fake-news stand-TBWA-chiat-day-Columbia-journalism-review-11-05-2018/

这篇文章背后的想法是展示一种合理简单的方法,人们可以在几周内实现这种方法来解决现实世界中的一个问题,即创建一个新闻聚合器,如谷歌新闻Yandex 新闻,从网上搜集的数百万条新闻中显示最热门的新闻线索。

问题陈述和限制

所以这是另一篇关于 NLP 的文章,我将描述在电报数据聚类竞赛中开发的文本过滤、分类、分组和排序的一些算法。这篇文章背后的动机是为了证明你可以构建一个像样的文本处理系统,甚至不需要 GPU 就可以在你的笔记本电脑上运行。

比赛包括五项任务——检测新闻语言,从其他文本中过滤新闻(如百科文章、一些随机的娱乐帖子、博客帖子等),从七个类别(社会、经济、体育、科学、技术、娱乐和其他)中选择一个进行新闻分类,将新闻按线索分组,并根据重要性对这些线索进行排序。此处有完整的比赛规则

特定算法和工具的选择在很大程度上取决于竞赛规则,这些规则对实施施加了一些限制——每个任务必须在 60 秒内执行,每 1000 篇文章一台 Debian 机器,有 8 个 CPU 和 16 Gb 的 RAM,不应该使用外部服务或 API,算法甚至不应该假设有互联网连接(例如,下载一些预训练的模型)。因此,没有像伯特,阿尔伯特或 GPT-2 SOTA 变压器模型应该被涉及。

本文中描述的高级解决方案体系结构如下所示:

  1. 文本预处理和矢量化
  2. 用具有 LSTM 和注意层的定制深度神经网络(DNN)进行文本分类
  3. 利用由每个组内的 Levenshtein 距离控制的最近邻搜索算法对线索中的文本进行分组。
  4. 按重要性排列新闻线索

注意:这篇文章中描述的所有代码和想法都是在比赛期间(2 周)开发的,尽管分组算法和代码样式的一些微调是在新年假期之后执行的。

原始数据解析

竞赛参与者被提供成千上万的出版物,这些出版物被保存为 html 文件,包含新闻标题、文本,有时还包含图像、出版日期、作者和媒体来源。我使用 Beatifulsoup 库作为一个方便的 html 解析器,将所有需要的数据提取到 pandas dataframe 中。

语言检测

这部分非常简单——我使用了一个快速的 langdetect 实现作为语言检测器,并在默认情况下用标题来加速检测——对平均长度大 10 倍的文本的语言检测速度较慢。

语言检测块

这一步每 1000 个文件用了 12 秒和 T5,检测准确率超过 99%。结果数据如下所示:

带有检测到的语言的新闻示例(仅标题)

文本预处理逻辑

文本矢量化逻辑是参赛者必须提出的核心算法决策之一。我们有一个足够大和足够多样化的约 100 万篇文章的语料库来使用预训练的单词嵌入,而不是基本的 TF-IDF 方法。但是首先我们必须执行通用的标记化和词干化过程。我使用了来自 nltk 库的停用词表和波特斯特梅尔。

标记化功能

在这一步之后,每个文本都由单词标记列表来表示。

下一步是用一个来自预先训练的语言模型的向量替换列表中的每个标记,该模型是 Glovefasttext

这个操作的结果是,每个文本现在都由一个语义丰富的单词向量列表来表示。我对列表的最大长度做了限制——50 个单词,标题与文章正文的开头连接在一起。

为了均衡所有向量的长度,已经执行了填充操作。我们现在已经得到了文本语料库的特征张量,每一行都代表了所选维度的一系列预先训练的词向量。

使用预训练单词嵌入的矢量化功能

深度神经网络架构

因为我们有足够的数据来进行神经网络训练,所以我决定使用深度神经网络(DNN)分类器来区分新闻和非新闻,并定义新闻主题。

考虑到这是一场算法竞赛,最大限度提高解决方案准确性的一个显而易见的选择是 SOTA NLP 模型架构,即某种大型转换器,如 BERT,但正如我之前提到的,这种模型太大太慢,无法通过对硬件和文本处理速度的限制。另一个缺点是,这种模型的培训需要几天时间,让我没有时间对模型进行微调。

我必须想出一个更简单的架构,所以我实现了一个轻量级的神经网络,它有一个 RNN (LSTM)层,接受代表文本的单词嵌入序列,并在其上有一个注意力层。网络的输出应该是类别概率(用于新闻过滤步骤的二元分类和用于新闻类别检测的多元分类),因此网络的上部由一组完全连接的层组成。

新闻话题检测——多类分类

我将使用多类分类器(检测新闻类别)作为例子来解释特定 DNN 体系结构的选择,因为它的目标更具挑战性,并且它的性能独立于在二元分类器中用来划分正负类之间的界限的阈值。

我们的神经网络的上部由三个密集层组成,输出层具有 7 个单元,对应于具有 softmax 激活函数和分类交叉熵作为损失函数的类的数量。

为了训练它,我使用了 News_Category_Dataset 并应用了映射逻辑,以便将最初的 31 个新闻类别归入 7 个类别之一:社会、经济、体育、科技、娱乐、科学和其他,以符合竞赛目标。

DNN 模型架构——多类分类器

我想分享神经网络模型的架构选择和超参数微调背后的逻辑。

  1. 漏失层增加了我们模型的泛化能力,并防止它过度拟合(漏失层在训练阶段的每次更新中随机地将给定百分比的权重归零)。学习曲线清楚地表明了模型在没有脱落层的情况下的过度拟合-训练集的精度增长到 95%,而验证数据集的精度在训练期间几乎没有增长。
  2. 应用于 LSTM 注意力结构顶部的批次标准化层在每批脱落后标准化激活,使激活平均值接近 0,激活标准偏差接近 1。它有助于提高较大批量的测试精度,降低较小批量的测试精度。
  3. 应用于密集层的正则化惩罚层参数的极值。
  4. 批量选择也会影响一个型号的性能。大小越大,模型训练越快,每步计算的梯度向量就越精确。这导致噪声减少,这使得模型更容易收敛到局部最小值,因此批量大小的选择通常是速度、内存消耗和模型性能之间的折衷。32 到 256 之间的值是常见的选择,在我们的例子中,模型显示出最高的精确度,批量大小为 64。将批量增加到 512 或 1024 会显著降低模型的准确性(相应地降低 2%和 4%)

模型的性能取决于架构和超参数

注意力层解释

关于我们模型中使用的注意机制,有必要说几句话。Raffel 等人的 arXiv 论文中描述了所用方法背后的理论这是一个简化的前馈神经网络注意力模型,用于解决长序列的 RNN 信息流问题。特别地,注意层提供了到完全连接层的最佳过渡,创建了上下文向量(输入单词向量序列的嵌入)作为输入序列的隐藏状态的加权平均,其中权重表示序列元素的重要性。显式符号如下所示:

其中 T 是序列的长度, a 是可学习的函数,即具有双曲正切激活函数的单隐层前馈网络,与全局模型共同训练。

注意层类,由 Kaggle 上的 qqgeogor 实现

该模型的缺点是它没有考虑输入序列中的顺序,但是对于我们的新闻标题矢量化任务来说,这并不像一些序列到序列问题(如短语翻译)那样重要。

有许多出版物描述了为序列到序列问题设计的更复杂的注意力机制,一个好的开始是谷歌研究院的带注意力的神经机器翻译教程,我也建议检查一下注意力?立正!Lilian Weng 的文章,概述了注意力机制及其进化,并确保您已经阅读了最初的 Bahdanau 等人,2015 年的论文。在后变形金刚时代最新的 LSTM +注意力论文中,我推荐阅读斯蒂芬·梅里蒂最近的单头注意力 RNN ,这证明了巨大的变形金刚不是唯一可能的方法。

另外,不要忘记在 Attention 类中添加一个保存配置,因为它可以无缝加载带有自定义层的保存模型。

另一种更简单的向致密层的过渡是用于张量整形的平坦层。

其他想法&结果

为了提高分类器质量,可以利用提供的其他信息,如出版物来源和作者,并将它们作为一次性编码特征添加到网络中,但竞赛规则明确表示,将在具有其他特定来源列表的不同数据集上评估算法。

为了加快训练阶段的速度,我在装有 TeslaK80 GPU 运行时的 colab 笔记本上运行了代码。

典型模型的学习曲线

具有新闻类别和二元新闻/非新闻分数的新闻样本

每 1000 个文本的分类步骤需要 13 秒。

新闻/非新闻—二元分类

为了从给定的出版物数据集中只过滤新闻,我们必须实现一个二元分类器。实际上这一步在新闻分类之前就已经完成了。二进制分类器具有非常相似的架构,但在输出层有明显的不同——最后一层有 1 个单元,具有 sigmoid 激活函数和二进制交叉熵作为损失函数。

竞赛组织者提供的数据包含了超过 90%的新闻出版物,所以我决定按来源(卫报、彭博、CNN 等)过滤 100%的新闻,然后用一个英文 Wikipedia atricles (好的,非宣传性的)来代表非新闻类。

典型二元模型的学习曲线

训练的二进制分类器模型输出对象是正(1)类的概率,为了解释这些概率,我们需要施加阈值,该阈值将区分新闻和非新闻。在对边缘病例进行了长时间的仔细观察之后,这种选择已经被手动执行。

每 1000 个文本的分类步骤需要 14 秒。分类结果可以在上表中观察到。

将新闻按线索分组

新闻分组任务通过在文本嵌入向量上构建球树来解决,然后在每组邻居内使用由归一化 Levenshtein 距离控制的自适应搜索半径来搜索该树。

文本矢量化

为了对新闻进行分组,我们首先应该在数据集上引入某种度量。因为我们使用 DNNs 进行文本处理和分类,所以获得文本向量的最明显的方法是通过将文本传递通过预训练的多类 DNN 而获得嵌入,而不需要最后一层。我使用 128 单位的密集层作为输出来创建文本嵌入向量。

后来我发现这种方法并不是最佳方法——当我切换到更简单的 TF-IDF 矢量化时,新闻分组的性能明显提高。这是很容易解释的——在新闻分类中,我们需要概括整个新闻的语义,而不管特定的政治家的名字、小工具、名人,甚至特定的环境,馈送给 DNN 的预训练单词向量的序列是这项任务的合适选择。在新闻分组中,我们处理不同的设置——每个线程应该描述一个非常特殊的事件——某人发生了一些事情,人物姓名,甚至动词和状语修饰语在整个新闻线程中应该是相同的,因此经典的 TF-IDF(计算每个文本中 n 元语法频率的向量,通过整个语料库中的 n 元语法频率归一化)是丢失较少有价值信息的方法。为了对抗 TF-IDF 输出矩阵的稀疏性,我应用了 SVD 分解,将每个文本的向量压缩到选定的维度(在我们的例子中是 1000)。

在 tom 上使用 SVD 对 TF-IDF 文本进行矢量化,以创建密集嵌入

快速最近邻搜索

下一步实际上是文本分组。这项任务的基本无监督方法是聚类,但由于我们不可能从第一次拍摄就获得完美的聚类,我们的算法需要迭代方法,并且整个数据集的聚类是昂贵的。此外,我们没有适当的分组质量指标来运行自动超参数调整程序,我们也不应该手动调整它们,因为我们很可能需要不同的超参数集来用于不同的新闻数据集。

我决定一个更精确和灵活的方法是在嵌入向量的文本上构建一个快速搜索索引,然后查询这个索引。快速高维最近邻搜索的有效方法是在文本嵌入上建立二叉空间划分树,即球树KD 树(k 维二叉查找树是一种用于组织 k 维空间中的点的空间划分数据结构),而无需显式计算数据集中的所有距离。这些算法的树构造复杂度为 O(N log(N))。我特别选择了一个 scikit-learn Ball Tree 实现,因为它比高维 KD 树具有更低的查询时间 O(D log(N)),并且我们必须优化查询时间,因为我们打算对数据集中的每个元素使用不同的搜索半径来执行迭代搜索。有关 KDtree 和 BallTree 数据结构之间的差异以及性能基准测试的更多详细信息,请参考 scikit-learn 撰稿人 Jake VanderPlasof 的这篇精彩文章。

初始化树结构

分组算法

好了,现在我们终于有了所有论文的索引,可以根据不同样本之间的距离将它们分组。

我没有足够的时间来思考一些更复杂的方法,只是在每个新闻类别中的所有论文上创建了一个循环(我们可以利用前面的算法步骤来按新闻类别划分我们的数据集)检查它们在半径 r_start** 中的邻居,r_start 是根据经验选择的,它使用的论文比实际包含的线程多一点。然后我计算了一个经验泛函 variative _ criterium _ norm——组内文本之间的归一化 Levenstein 距离——并迭代地减小搜索半径 r_curr,直到这个泛函变得小于经验发现的约束或搜索半径大小达到 r_min 约束。如果在给定区域没有新闻,我增加搜索半径,直到我们找到一些邻居,然后切换到半径递减分支。这种迭代搜索背后的想法是,相似的新闻有部分相似的标题(一些实体,如主语、宾语,有时动词,在新闻线索中是不变的)。从代码片段中可以更容易地看到所开发算法的其他细节。**

新闻分组逻辑

有 7 个超参数控制算法:r_min,r _ max 这些参数控制查询区域的大小,r_start,r _ step 控制查询区域动态,vc_min,vc_max,delta_max,控制组内归一化 Levenshtein 距离的值-这定义了组中新闻标题的方差。在选择了最终的文本嵌入大小(SVD 中的 n_components)和使用的 n_grams 范围(我使用了 1-3)等矢量化参数之后,应该对这些超参数进行调整。

我们如何估计一个“适当的”新闻分组并不是很明显,所以在我得到一个合理的分组结果后,我没有花太多时间玩超参数——我的意图是提出一个工作方法来解决给定约束条件下的问题。显然,还有一些改进的空间,比如检查我们是否可以合并一些组,以及过滤掉一些偶然的噪音。实际上,为了获得合理的组数量和密度,分组超参数应该针对每个数据集进行微调,因此可以有一个外部循环来对它们实施一种随机搜索。了解我们得到的特定分组并评估其质量的方法之一是检查分组大小分布直方图。

在测试数据集上获得的组大小分布直方图

事实上,所描述的方法可以被看作是 DBSCAN 集群的一个相关部分。

执行时间取决于为数据集选择的超参数和数据结构,典型值从 8.5 秒/ 1000 张纸到 25 秒/ 1000 张纸,包括由昂贵的 SVD 操作定义的矢量化时间。

很抱歉列出了这么长的列表,这里是按团体大小排列的社会类别的全部结果

分组结果—前 3 组(按大小排序)

线程排名

实际上,有很多功能可以用于线程排名,问题是这个排名可能非常主观,取决于特定用户的地区和兴趣。我们可能同意存在全球和本地新闻,对政治问题的一些猜测/意见和纯粹的事实,但关于 Trump 弹劾听证会的一些新信息可能比全球但遥远的悲剧更重要,如澳大利亚的森林火灾新闻的重要性是一种感知,而不是一种客观特征

鉴于上述情况,我将仅描述处理该任务的方法:线程排名的最明显特征是线程中的出版物数量、来源的排名(在社会类别中,例如彭博和金融时报是最受尊敬的来源)以及线程的语义,如“国际政治”、“全球经济”、“战争”、“全球事故”、“本地事故/犯罪”等。这种方法预先假定了这些语义类别的手动引入和排序以及新闻源的手动排序。如果我们不想手动创建特征,另一种可能的方法是手动对线程的一些选择进行排序,计算它们的平均语义向量(对我们使用的任何矢量化进行平均),然后使用这些向量作为预测器,根据我们分配给线程重要性的分数训练出排序模型(一种回归模型)。

事实上,只要按照大小对线程进行排序,就可以获得相当合理的排名。鉴于这一事实以及我在比赛期间没有实现排名部分的事实,我将让那些热情的人自由尝试上面讨论的任何方法。

一个重要的问题是,竞赛预先假定了一个静态排名——我们得到了同一日期的所有新闻,但实际上新闻是时间相关的,并且失去了它们的新颖性久而久之,这种相关性的衰减可以用 exp(-t)函数来描述。

感谢你阅读这篇长文,我希望你已经找到了一些可以在你的 NLP 项目中使用的想法。

用 TensorFlow 构建一个热编码层

原文:https://towardsdatascience.com/building-a-one-hot-encoding-layer-with-tensorflow-f907d686bf39?source=collection_archive---------10-----------------------

如何在 TensorFlow 中创建自定义神经网络图层以对分类输入要素进行热编码

一个热编码是机器学习模型预处理分类特征的一种常见方式。这种类型的编码为每个可能的类别创建一个新的二进制特征,并将值 1 分配给对应于其原始类别的每个样本的特征。这在视觉上更容易理解:在下面的例子中,我们对一个由三个类别组成的颜色特征进行了热编码(红色绿色蓝色)。

一个简单分类特征的热编码(作者图片)

Sci-kit Learn 提供了开箱即用的OneHotEncoder类,使用一个热编码来处理分类输入。简单地创建一个sklearn.preprocessing.OneHotEncoder的实例,然后将编码器安装到输入数据上(这是一个热编码器识别数据帧中可能的类别并更新一些内部状态,允许它将每个类别映射到一个唯一的二进制特征),最后,调用one_hot_encoder.transform()对输入数据帧进行一次热编码。关于OneHotEncoder类的伟大之处在于,一旦它适合输入特征,您可以继续向它传递新的样本,它将一致地对分类特征进行编码。

一个使用 Sci-kit Learn 的 OneHotEncoder 的热编码

张量流模型的一种热编码

最近,我正在处理一些作为输入传递给张量流模型的分类特征,所以我决定尝试找到一种热编码的“张量流原生”方式。

经过大量的搜索,我发现了两个建议:

用 Sci-kit Learn 的 OneHotEncoder 就行了

我们已经知道它是可行的,一个热编码就是一个热编码,所以为什么还要用 TensorFlow 来做呢?

虽然这是一个有效的建议,对于简单的示例和演示非常有效,但是在您计划将您的模型作为服务进行部署以便它可以在生产环境中执行推理的场景中,它可能会导致一些复杂性。

退一步说,将OneHotEncoder与 Sci-kit Learn 模型结合使用的一大好处是,您可以将它与模型本身一起作为 Sci-kit Learn 管道中的一个步骤,本质上是将一个热编码(可能还有其他预处理)逻辑和推理逻辑捆绑为一个可部署的工件。

具有一个热编码和预测逻辑的 Sci-kit 学习流水线

回到我们的 TensorFlow 场景:如果您要使用OneHotEncoder来预处理 TensorFlow 模型的输入特征,您将需要处理一些额外的复杂性,因为您必须:

  1. 在模型用于推理的任何地方复制一个热编码逻辑。
  2. 或者,将 fit OneHotEncoder和经过训练的 TensorFlow 模型作为单独的构件进行部署,然后确保它们被正确使用,并由使用该模型的所有应用程序保持同步。

使用 tf.one_hot 操作

这是我遇到的另一个建议。tf.one_hot操作接受一个类别索引列表和一个深度(对于我们的目的,本质上是一些独特的类别),并输出一个热编码张量。

tf.one_hot 操作

在上面的例子中,你会注意到OneHotEncodertf.one_hot之间的一些关键区别。

  • 首先,tf.one_hot只是一个操作,所以我们需要创建一个使用这个操作的神经网络层,以便将一个热编码逻辑包含到实际的模型预测逻辑中。
  • 其次,不是传入字符串类别(红色蓝色绿色),而是传入一个整数列表。这是因为tf.one_hot不接受类别本身,而是接受一个热编码特征的索引列表(注意,类别索引 0 映射到 1×3 列表,其中列 0 的值为 1,其他的值为 0)
  • 第三,我们必须传入一个唯一的类别计数(或深度 ) 该值决定了生成的一个热编码张量中的列数。

因此,为了将一个热编码逻辑作为 TensorFlow 模型的一部分,我们需要创建一个自定义层,将字符串类别转换为类别索引,确定输入数据中唯一类别的数量,然后使用tf.one_hot操作对分类特征进行热编码。我们接下来会做所有这些。

创建自定义层

首要任务是以一致的方式将字符串类别转换为整数索引(例如,字符串蓝色应该总是被转换为相同的索引)。

输入文本矢量化

实验性的TextVectorization层可用于标准化和标记化字符串序列,例如句子,但是对于我们的用例,我们将简单地将单个字符串类别转换成整数索引。

使文本矢量化图层适应颜色类别

我们在创建层时指定了output_sequence_length=1,因为我们只希望传递到层中的每个类别有一个整数索引。调用adapt()方法使图层适合数据集,类似于对OneHotEncoder调用fit()。在层被拟合之后,它维护唯一类别的内部词汇表,并将它们一致地映射到整数索引。你可以通过调用get_vocabulary()来查看图层的词汇。

OneHotEncodingLayer 类

最后,我们现在可以创建一个类来表示神经网络中的一个热编码层。

一个热编码分类要素的自定义图层类

该类继承自PreprocessingLayer,因此它继承了基础adapt()方法。当这个层被初始化时,TextVectorization层也被初始化,当adapt()被调用时,TextVectorization被拟合到输入数据,并且两个类属性被设置:

  • **self.depth** 是输入数据中唯一的类别数。该值在调用tf.one_hot时使用,以确定结果二进制特征的数量。
  • **self.minimum**TextVectorization层输出的最小指标。从运行时的索引中减去该值,以确保传递给tf.one_hot的索引落在范围[0,self.depth-1]内(例如,如果TextVectorization输出范围[2,4]内的值,我们将从每个值中减去 2,以便得到的索引在范围[0,2]内)。

get_config()方法允许 TensorFlow 在模型保存到磁盘时保存层的状态。当模型加载到内存中时,来自层配置的值将被传递给层的__init__()方法。注意,每当这些值被传入时,我们都显式地设置了词汇、深度和最小值。

使用自定义图层

现在我们可以在一个简单的神经网络中尝试新的层。

具有一个热编码的简单神经网络

这个简单的网络只接受分类输入,对其进行热编码,然后将热编码的要素与数字输入要素连接起来。注意,我在 DataFrame 中添加了一个数字列id,以说明如何将分类输入从数字输入中分离出来。

就是这样!我们现在有一个工作的神经网络层,可以热编码分类特征!我们还可以将这个模型保存为 JSON 配置文件,部署它,并将其重新加载到内存中以执行推理。请注意,它以与之前相同的方式对颜色类别进行了热编码,因此我们知道我们模型的后续层将按照它们在训练期间出现的相同顺序提供相同的功能。

从配置中保存和加载模型

你可以在这里找到包含所有代码示例的笔记本:https://github . com/gnovack/TF-one-hot-encoder/blob/master/onehotencoderlayer . ipynb

感谢阅读!欢迎在下面留下任何问题或评论。

参考

用 PyTorch 构建一次性学习网络

原文:https://towardsdatascience.com/building-a-one-shot-learning-network-with-pytorch-d1c3a5fafa4a?source=collection_archive---------4-----------------------

我们如何用每门课这么少的样本建立一个深度网络?

近年来,深度学习由于其高性能而在图像识别和分类任务中非常流行。然而,传统的深度学习方法通常需要一个大型数据集来训练模型,以区分非常少的不同类别,这与人类能够从甚至非常少的例子中学习的方式截然不同。

少击或单击学习是一个分类问题,旨在只给定有限数量的样本对对象进行分类,最终目标是创建一个更像人类的学习算法。在本文中,我们将通过使用一种特殊的网络结构:暹罗网络,深入研究解决一次性学习问题的深度学习方法。我们将使用 PyTorch 构建网络,并在 Omniglot 手写字符数据集上对其进行测试,并使用一次性学习评估指标进行多次实验,以比较不同网络结构和超参数的结果。

Omniglot 数据集

Omniglot 手写字符数据集是由 Lake 等人提出的用于一次性学习的数据集。它包含来自 50 个不同系列的字母表的 1623 个不同的手写字符,其中每个字符由 20 个不同的人手写。每个图像的大小为 105x105 像素。这 50 个字母被分成 30:20 的比例进行训练和测试,这意味着测试集是在一个全新的字符集上,这是以前从未见过的。

计算环境

训练和实验完全是通过谷歌实验室完成的,使用了包括特斯拉 K80 和 P100 在内的一系列 GPU。我们使用的库包括 Numpy、Matplotlib 和 PyTorch。

方法

传统的深度网络通常不能很好地进行一次或几次学习,因为每类很少的样本很可能导致过拟合。为了防止过度拟合问题,并将其扩展到看不见的字符,我们建议使用暹罗网络。

图一。卷积暹罗网络架构

图一。是卷积暹罗网络的主干架构。与传统的 CNN 采用 1 幅图像的输入来生成暗示图像所属类别的独热向量不同,Siamese 网络采用 2 幅图像并将它们馈入具有相同结构的 2 个 CNN。输出将被合并在一起,在这种情况下是通过它们的绝对差异,并被馈送到完全连接的层,以输出一个表示两幅图像相似性的数字。数字越大,表示两幅图像越相似。

暹罗网络不是学习哪个图像属于哪个类,而是学习如何确定两个图像之间的“相似性”。在训练之后,给定一个全新的图像,网络然后可以将该图像与来自每个类别的图像进行比较,并确定哪个类别与给定的图像最相似。

数据集预处理和生成

训练和验证数据加载器

为了训练暹罗网络,我们必须首先生成适当的输入(成对)并为模型定义基础事实标签。

我们首先定义两幅图像,它们来自相同字母表中的相同字符,相似度为 1,否则为 0,如图 3 所示。然后,我们根据 dataloader 迭代中索引的奇偶性,随机选择一对图像输入到网络中。换句话说,如果当前迭代是奇数,我们从同一个字符检索一对图像,反之亦然。这确保了我们的训练数据集对于两种类型的输出都是平衡的。两幅图像经历相同的图像转换,因为目标是确定两幅图像的相似性,所以将它们输入不同的图像转换没有意义。

以下是生成训练集的代码:

我们创建了 10000 对这些数据作为我们的训练集,然后以 80:20 的比例随机地进一步分成训练和验证。

测试加载器

对网络在一次学习中的性能的评估可以通过 n 路一次学习评估度量来完成,其中我们找到代表 n 个类别的 n 个图像和属于 n 个类别之一的一个主图像。对于我们的暹罗网络,我们计算了主图像相对于所有 n 个图像的相似性,具有最高相似性的对意味着主图像属于该类。

测试加载器是以支持上述评估的方式构建的,其中随机获取了一个主图像,并且还检索了代表 n 个类别的 n 个图像,其中一个图像来自主图像的相同类别。

以下是用于生成测试集的代码:

对于我们的最终测试,我们将我们的网络扩展到 4 路一次性学习,测试集大小为 1000,20 路为 200。

实验

实验一。用于一次性学习的传统连体网络

图二。Koch 等人的暹罗网络架构。

暹罗网络的主要部分是前面显示的双卷积架构。我们将尝试构建的第一个卷积架构来自 Koch 等人的论文“用于一次性图像识别的暹罗神经网络”,如图 2 所示。需要注意的一点是,在展平之后,两个卷积分支之间的绝对差异被馈送到全连接层,而不仅仅是一个图像的输入。

PyTorch 中的网络构建如下:

我们可以使用以下功能进行培训:

超参数设置

批量大小:因为我们正在学习两幅图像有多相似,所以批量大小需要相当大,以便模型具有通用性,特别是对于像这样有许多不同类别的数据集。因此,我们使用的批量大小为 128。

学习率:我们测试了从 0.001 到 0.0005 的几个学习率,并选择了 0.0006,它提供了最好的损失减少率。

优化器和损耗:我们采用传统的 Adam 优化器来优化该网络,并使用 logits 进行二进制交叉熵(BCE)损耗。

结果

图 3。原始网络的训练和验证损失

该网络被训练 30 个时期。图 3。是每个时期后的训练和验证损失图,正如我们所看到的,它显示了接近结束时的急剧下降和收敛。验证损失通常随着训练损失而减少,表明在整个训练中没有发生过拟合。在训练期间,将保存具有最低验证损失的模型。我们使用验证损失而不是训练损失,因为它是模型不仅仅对训练集表现良好的指标,这可能是过度拟合的情况。

实验二。添加批量标准化

图 4。使用 BatchNorm 的模型架构

为了进一步改善网络,我们可以添加批量标准化,这应该会使收敛过程更快、更稳定。图 4 是更新后的架构,每个卷积层后都有一个 BatchNorm2d。

结果

图 4。10 个时期后的训练结果

正如预期的那样,与原始网络相比,训练损失和验证损失都下降得更快。有了更好的结果,我们决定也训练模型更多的时期,看看它是否会比实验 1 表现得更好。

图 5。50 个时期后的训练结果

如损失图所示,结果略好于实验 1 的原始结果。由于损失在 40 和 50 代之间缓慢收敛,我们在第 50 代停止了训练。这是目前我们取得的最好成绩。

实验三。用轻型 VGG16 替换 ConvNet

在让原来的网络工作得相当好之后,我们还可以为我们的暹罗网络测试不同的成熟 CNN,看看我们是否能取得更好的结果。对于 105x105 的小图像大小,我们希望使用一个相对较小的网络,没有太多的层,但仍能产生不错的结果,因此我们借用了 VGG16 的网络架构。

最初的 VGG16 对于我们的尺寸来说仍然有点太大,其中最后 5 个卷积层只处理单个像素,所以我们取消了它们,最终网络如下:

结果

图 6。VGG16 暹罗网络结果

如损失图所示,训练损失比先前的实验下降得慢得多。这可能是由于卷积层的内核大小相当小(3×3),这给出了小的感受域。对于计算两个图像之间的相似性的问题,查看两个图像的“更大画面”而不是关注小细节可能是有益的,因此在原始网络中提出的更大的感受野工作得更好。

对模型的评价

评估网络的代码实现如下:

四路一次学习

我们首先使用一组全新的图像来测试 4 向一次学习进行评估,其中所有的测试图像在训练期间都没有使用,并且模型也不知道任何角色。结果显示大约 90%的准确率,这表明该模型可以很好地推广到看不见的数据集和类别,实现了我们在 Omniglot 数据集上一次性学习的目标。

20 路一次学习

之后,我们对 200 组进行了 20 路单镜头学习评估。结果仍然是 86%左右。我们将结果与 Lake 等人提供的基线进行了比较:

虽然我们没有超过或复制论文提出的 92%的准确性(可能是由于细节,如变化的层学习率),但我们实际上非常接近它。

此外,我们的模型实际上比许多其他模型表现得更好,包括正常的暹罗网络和最近邻居。

结论

所以你有它!这就是如何为一次性学习 Omniglot 数据集构建卷积暹罗网络。完整代码也发布在 Github 的以下目录中:

[## ttchengab/One_Shot_Pytorch

设置:从 https://github.com/brendenlake/omniglot 下载数据集,转到/python 并提取文件夹…

github.com](https://github.com/ttchengab/One_Shot_Pytorch.git)

感谢您坚持到现在🙏!我将发布更多关于计算机视觉/深度学习不同领域的文章,请务必查看我关于 3D 重建的另一篇文章!

构建个性化的实时时装收藏推荐系统

原文:https://towardsdatascience.com/building-a-personalized-real-time-fashion-collection-recommender-22dc90c150cb?source=collection_archive---------9-----------------------

我们的 RecSys 选择的服装。左:“任何有短裤的东西”。右上:“都市生活方式”。右下:《如花梦》。服装从 DeepFashion、开源由 刘 z 等人

现代 RecSys

我们将利用 PyTorch 中的迁移学习、近似最近邻和嵌入质心检测来构建我们的推荐器。

我在数据行业工作了七年多,有幸设计、构建和部署了两个推荐系统(RecSys ),并为数百万客户提供了服务。在本文中,我将通过一个带有代码的案例研究来介绍可视化推荐器的现代方法,并分享我设计 RecSys 的一些经验。

商业问题

假设你被一家电子商务公司happy panda co .聘用,负责他们的时装系列专题。产品团队概述了需求:

  • 该模型应该能够扫描所有 280,000+产品图像,并自动生成一组推荐产品,这些产品是根据用户查看/购买的内容定制的。
  • 速度对电子商务公司至关重要。该组推荐的产品应在 2ms 内生成,以满足管道的“实时”要求。
  • 该模型应该能够适应新产品和新用户。

听起来很有趣?让我们建造这个。

数据

我们将使用【deep fashion】的子集数据,由香港中文大学刘 z 等人开源,。我们的数据由 46 个类别的 28 万张时尚图片组成。你可以从他们的网站上下载数据。

此外,该团队发布了一个更新版本,增加了的数据。你需要填写谷歌表格来获取数据。

时尚系列——打造时尚系列的步骤

了解业务需求后,我们分解构建时装系列所需的步骤:

我打造时装系列的步骤

回顾时尚系列的成果

在深入研究代码之前,让我们看一下模型的输入/输出,以获得对问题和建议的解决方案的直觉。

输入:

  • 我和妻子商量,通过选择 12 套风格相似的服装来模拟用户查看/购买的服装。我们将关注三个用户:爱丽丝、贝拉和凯茜,每个人都有不同的口味偏好。
  • ****我只会将图像传递到模型中;模型不吸收额外的属性/描述/产品细节;这是因为我们希望模型能够自动学习和检测传递给它的时尚图像的风格,而无需进一步的人/机器标记。

输出:

  • 目标是让模型生成的集合包含输入的某些方面,但给用户带来惊喜。****

左图:爱丽丝查看/购买的服装。右图:时装系列推荐的服装。 DeepFashion、开源 刘 z 等人

A lice 来自阳光明媚的新加坡,喜欢短裤和适合炎热天气的服装。根据她选择的服装,《时尚收藏》推荐了各种各样的新服装,都配有短裤,看起来非常适合阳光下的生活。请注意,我们没有明确告诉模特根据短裤过滤服装。** Fashion Collection 可以捕捉到爱丽丝喜欢搭配短裤的服装的信号,并做出适当的推荐。**

左图:Bella 查看/购买的服装。右图:时装系列推荐的服装。服装来自 DeepFashion,开源来自 刘等

ella 来自艺术巴塞罗那,喜欢她衣服上的花卉图案和多彩设计。根据她选择的服装,时装系列推荐了各种颜色、图案和剪裁与她品味相似的各种新服装。

左图:Cathy 查看/购买的服装。右图:时装系列推荐的服装。服装从 DeepFashion、开源由 刘 z 等人

阿西来自国际化的纽约,穿着她熟悉的都市生活方式。城市生活方式是一种更复杂的风格,分层、破牛仔裤、配饰、靴子、图案 t 恤是其中一些定义特征。因此,令人兴奋的是,时装系列已经认识到了这种风格的一些关键特征,并推荐了带有层次感的服装组合,破旧的牛仔裤,配饰,靴子,图案 t 恤!

这也是为什么我们不想硬编码过滤器/按类别限制服装。我们希望时装系列能够响应不同用户和不断变化的用户偏好,即使是像城市生活方式这样多样化的风格。****

在下一节中,我将介绍一些主要的概念和代码片段。如果你不能在一次阅读中理解所有的理论,不要担心。本质上,这些都是不断发展的密集话题;我将提供一个高层次的概述,并在进一步的阅读材料中提供额外的资源供您参考。我们将遵循上面流程中概述的阶段(数据、准备、建模、搜索)。

代码

链接到 Colab 上的代码 (你只需要一个免费的 Google 账号就可以在云端的 GPU 上运行代码)。我们将使用杰瑞米·霍华德的 Fastai 包(以及著名的程序员实用深度学习课程)。

[Prep]代码:将图像转换为嵌入内容

这种转换是我们模型数据处理的第一步:

我们代码的结果——图像数据已处理,可用于训练。各路服装来自 DeepFashion,开源作者 刘 z 等人

理论:什么是嵌入,为什么我们需要它们?

为了解释和说明嵌入的概念,我们将使用一个更小的开源数据集,称为 FashionMNIST

****

左图:示例图像。右图:图像的数字表示。样本图片来自时尚达人,开源作者小 H.

传统上,我们将图像表示为一个巨大的整数数组(RGB 图像的 3D 数组和灰度图像的 1D 数组)。这些阵列非常庞大,并且呈指数级增长,我们将需要跟踪数百万个数字来分析数百张高分辨率图像!使用整数数组来缩放任何建模都是不可能的;因此,现代的嵌入方法产生了。

嵌入概念的一个很好的例子是 Will Koehrsen 的“神经网络嵌入解释”中的例子。传统上,我们利用像一键编码这样的技术来表示矩阵中的项目。例如,给定三本书,我们将有一个 3x3 矩阵,其中每一项都由一个由个离散的个数字组成的数组表示,这个数组的随着每增加一个新项而增长** (4x4 有 4 项,5x5 有 5 项……)。此外,没有相似感,也没有距离感,因为这些项目没有以任何形式的关系连接。**

**# One Hot Encoding Categoricals****books = ["Harry Potter and The Philosopher's Stone",
         "Harry Potter and The Chamber of Secrets", 
         "The Lean Startup"]****books_encoded = [[1, 0, 0],
                 [0, 1, 0],
                 [0, 0, 1]]****Similarity (dot product) between First and Second = 0
Similarity (dot product) between Second and Third = 0
Similarity (dot product) between First and Third = 0**

一旦我们应用一个转换来将对象转换成嵌入,我们现在在一个连续的尺度上限制表示每个项目的数组中的元素数量(在这个例子中限制为 2),并且这些值具有基于关系的含义。基于相似性(点积)彼此接近的对象是高度相关的。

**# Idealized Representation of Embedding****books = ["Harry Potter and The Philosopher's Stone",
         "Harry Potter and The Chamber of Secrets", 
         "The Lean Startup"]****books_encoded_ideal = [[0.53,  0.85],
                       [0.60,  0.80],
                       [-0.78, -0.62]]****Similarity (dot product) between First and Second = 0.99
Similarity (dot product) between Second and Third = -0.94
Similarity (dot product) between First and Third = -0.97**

嵌入是离散变量的矢量表示,而不是分析每幅图像的数百万个离散变量。对于深度学习,我们通常利用神经网络嵌入来将分类变量的维度降低到可管理的程度

时尚嵌入投影。图片来自 FashionMNIST,【Tensorboard 动画

因为我们可以控制向量表示的大小,所以我们可以将一个巨大的图像数组缩小成一个由更少的数字组成的小向量。从上图中的 FashionMNIST 对象可以看出结果,其中对象被投影到 3D 矢量空间。通过嵌入过程,相似的个图像向量将被投影成彼此靠近。因此,当我们有嵌入时,我们可以将对象投影到向量空间中,并为可视化和简单的推荐制定距离和邻居的概念。你可以用下面的笔记本探索嵌入的概念,并在进一步阅读部分阅读更多相关内容:****

[模型]代码:深度卷积神经网络(CNN)的迁移学习

Fastai 在建立神经网络的过程中抽象出了许多代码逻辑,允许我们用几行代码进行迁移学习:

用 Fastai 钩子运行模型并为每个图像生成嵌入也相当简单。注意,我们想要倒数第二个线性层,因为该层存储图像表示的嵌入;最后一个线性图层是输出图层。

请注意,倒数第二个线性图层是(4)

因此,当我们调用 learner.model.module[1][4]来获得具有嵌入的层时。

【模式】理论:CNN 是什么?

卷积并不是一项新技术。本质上,我们正在对图像中的每个像素应用内核以实现一个目标,通常是模糊、锐化或检测边缘/对象。对于每个像素,我们将用内核做一个元素级的乘积,然后将结果相加得到一个单一的数。

由于每个内核专门检测图像的一个方面,你可以想象我们将不同的内核堆叠起来,制定一个全面的策略。事实的确如此,内核的集合被称为过滤器。在 CNN 中,我们甚至可以堆叠多层过滤器,每个过滤器都有特定的任务。

如果你有兴趣,你应该试试 Victor Powell 开发的带有不同类型内核的工具。CNN 是一个迷人的模型,因为它结合了卷积和神经网络的力量。有许多不同的架构,但通常由卷积、子采样、激活和完全连接的组合组成,如 Algobeans 所述。你可以在进一步阅读部分了解更多关于内核和 CNN 的知识。

【模型】理论:迁移学习是如何工作的?

对于大多数现实部署,我们不会从头开始训练 CNN。多年来,像微软研究院这样的组织已经发布了最先进的大规模预训练深度 CNN (DCNN)模型,我们应该通过在他们的基线模型上进行训练来利用他们的工作。这就是所谓的迁移学习。

具体来说,我们拿一个像 ResNet50 (He K .,et al.) 这样的大型预训练 DCNN,冻结大部分层,在最后几层上训练。直觉是,对于大多数 DCNN,过滤器获得的知识是可转移的成分,例如边缘、图案、梯度、颜色等的检测。因此,我们对问题的最后几层进行微调,就可以得到一个可行的解决方案。你可以在进一步阅读部分探索迁移学习的概念。****

[搜索]代码:用骚扰和嵌入质心检测来近似最近邻居

我们遍历数据帧中的每一行,用 get_nss_by_vector 函数找到最近的邻居。

最后,我们将所有 12 个(或更多)用户选择的项目的嵌入插入到一个列表中,然后对每个维度的嵌入值进行平均这将创建一个虚拟对象,表示所有选定项目的聚合值。然后,我们可以找到这个虚拟物品的最近邻居,当我们调用 Annoy 时,这可以在大约 2ms 内完成。****

用 Shorts 集合生成任何内容所花费的时间

[搜索]理论:近似最近邻

如果我们只有一个小的图像搜索语料库,简单的距离度量,如余弦相似性将工作。在现实世界的部署中,比如电子商务,我们通常有数百万张图片需要相互比较,API 对每张图片进行成对比较是不切实际的。来自 Spotify 的 Erik Bernhardsson 编写了一个易于使用的 API,可以集成到我们的 PyTorch 工作流中。

更重要的是,它帮助我们找到最近的邻居,而不需要计算每张图像之间的成对距离。

如果你有兴趣了解更多关于 aroy 的知识,请在“进一步阅读”下查看 Erik 的文章。

我们学到了什么

我们将详细介绍构建个性化实时时装系列推荐器的整个过程。借助 PyTorch、Fastai 和 Annoy 等现代工具,我们构建了一个强大的产品,可以根据用户的风格生成相关的推荐。

进一步阅读

从 Google Sheets 构建一个精巧的 Dash 应用程序——第 1 部分

原文:https://towardsdatascience.com/building-a-plotly-dash-app-from-google-sheets-part-1-d37dc41ece10?source=collection_archive---------21-----------------------

Plotly Dash 应用程序

用众所周知的免费工具构建的非传统仪表板

介绍

对于大多数公司的数据科学家或分析师来说,仪表板仍然是一项非常受欢迎的任务。在一个完美的世界中,你可能会连接到大的数据流管道,或者用 OLAP 立方体建立一个单独的数据仓库,以提供一组复杂的实时分析。然后在应用程序中构建一些漂亮的灵活性,供业务团队用于即席号码。也许你甚至可以用一些预测算法来增加数据。听起来很有趣。这不是仪表板。

或者,有时您需要围绕现有的一组流程构建一个仪表板,并且尽量不干扰业务。那是仪表板着陆的地方。这个项目的想法是支持一个为虚构的自行车公司工作的现场营销团队。每个营销人员在全国各地举办实体活动,并需要向营销主管报告活动的类型、规模和频率。此外,这些指标需要跟踪员工奖金激励的进展。这家 T4 的大公司有很多繁文缛节,部门内部的部门和超负荷工作的 IT 团队。因此,营销负责人希望有一个非常简单的解决方案,可以在几天内完成,不需要召开 3 次预算会议来获得批准,也不需要培训现场员工使用新工具。

输入谷歌表单。我们将使用 Google 提供的简单、免费且非常熟悉的工具,而不是创建另一个生产级数据存储和 web 表单来接收数据。这允许团队快速调整和编辑数据。正如你将看到的,谷歌已经提供了一些他们用来构建 G-Suite 的相同代码,以制作我们自己的定制解决方案。

这个项目将分为 4 个部分。

  1. 使用 Google 和 code.gs 的设计和 ETL 过程
  2. 将 Google Sheets 数据连接到 python
  3. 打造一款 Plotly Dash app
  4. 在 Heroku 上主持[即将推出]

我们要建造这个:

我们示例仪表板的图像——作者提供的图像。

第 1 部分——使用 Google 和 code.gs 进行设计和 E.T.L

在开始 dashboard 和任何应用程序之前,我们必须首先列出构建它所需的重要元素。

  1. 按日期过滤—我们希望允许营销主管查看特定日期范围内的活动
  2. 聚合值-每个事件都有一个可量化的特征,如在诊所接受教育的员工人数或测试骑过自行车的消费者人数
  3. 地图——每个事件的规模和位置的直观概述,以便团队识别覆盖范围的缺口
  4. 季度日期范围—现场营销团队按季度获得奖金,我们需要按此固定日期进行筛选

为了构建这个项目,我们将创建一个简单的谷歌表单。这对于调查和快速数据输入来说非常方便,并且允许数据验证,比如日期和所需的响应,就像典型的 SQL db 一样。此外,Google Forms 会将每个响应存储在一个 Google Sheet 中,作为我们 Dashboard 应用程序的数据源。

谷歌表单样本——作者图片。

带有表单响应的 Google 表单—作者图片

地理编码

在上述需求中,几乎所有需求都可以在 python 中以足够快的速度处理,以加载一个应用程序。然而,在 Plotly 中在地图上绘制坐标的最佳方法是使用纬度和经度。我不想让营销团队在提交 Google 表单时查找这些坐标,从而使数据输入变得复杂。在这一点上,我无法找到一个预建的 Google form 解决方案来整合地图,以实现“放下大头针”的解决方案(也许是我的下一个项目想法?).我发现将地址转换成坐标需要调用 python 中的 API,我想在我们的仪表板加载时避免这种情况。

然而,在 Google 产品套件中,有一个内部 API 可以快速调用经度和纬度。接下来,我们将在新的 Google Sheet 中编写一个脚本,将纬度和经度附加到 Google Sheet 中存储响应的最后一列。

code.gs

https://developers.google.com/apps-script/reference

Google Apps Script 是一个非常强大的工具,它允许您构建脚本函数来执行 Google 表单、文档或幻灯片中尚不存在的任务。code.gs 的名字是 Node.js 的巧妙变化,因为这种脚本语言与基于 javascript 的语言的外观和感觉有很多相似之处。该工具允许您将自定义函数写入您的电子表格(或任何 g-suite 工具!)可以像在工作表中使用=SUM(A1:A5)一样使用。或者您可以使用它连接到您的 Google 日历,在 Google 文档中查找会议请求。我不是用 javascript 写的,也没见过多少代码,但是对代码有一些基本的理解可以让你开始运行一些东西。

Sheets 脚本语言的核心建立在几个类上,如.sheet().range().cell(),这允许脚本在工作表中找到特定信息,进行一些转换,并将新值返回到另一个特定位置。正是我们要找的。

此外,还有很多很多类可以使用其他谷歌服务,比如地图类中的Maps.newGeocoder()。有了这个类,我们就可以在脚本中使用健壮的谷歌地图服务,从非常基本的城市或邮政编码数据中调用我们的纬度和经度。

因此,为了准备仪表板的数据,要完成的第一项任务是运行一个脚本来插入纬度和经度。

在带有表单响应的 Google 表单中,打开脚本编辑器——作者图片

在 Will Geary 的这篇教程的帮助下,我能够在 code.gs 中创建一个函数来查找地址并插入纬度/经度坐标:

如果您熟悉 javascript,您可能会找到更简洁或更好的方式来编写这些代码。在伪代码中,这个函数的作用如下:

  1. 第 2 行:从特定于电子表格中获取数据。我有不确定性,因为我阅读的许多文档和我找到的示例代码片段似乎使用了这一行的通用版本,它只要求“当前的电子表格”。这个想法是,这个函数被专门绑定到我打开脚本编辑器的表单上。为了安全起见,我已经输入了该表的确切 ID。我不希望这个函数意外地将数据写入我的 Google drive 中的另一个工作表。您可以在下面找到唯一的 ID:

Google 工作表的唯一 ID—按作者分类的图片

  1. 从 G 列开始,检查下一行的数据。这将创建一系列包含数据的行。
  2. 从第 2 列到第 7 列中抓取我们刚刚找到的范围长度的单元格块,以获得每一行的邮政编码
  3. 遍历每个单元格并创建一个纬度/经度数据的列表——是的,每次函数运行时都会遍历整个列表,这是一种浪费的编程。但是,我选择保留这一步,以防有人稍后对响应表单中的数据进行手动更改,并且数据不太可能超过 1000 行。
  4. 将此数据列表插入工作表的最后一列。这不包括检查最后一列数据的逻辑。它被明确地告知去 AB 和 AC 列。如果对 Google 表单进行了修改并添加了问题,您将需要手动更新该脚本。

Logger.log 是一个很好的工具,可以测试过程中的各个步骤,并查看每个变量是否都按照应有的方式存储。

功能触发器

仪表板构建的第 1 部分中的最后一步是配置将运行该脚本的触发器。谷歌让这变得超级简单。标准的选择是当文件被打开或数据被更改时运行脚本,但是这只能识别用户的更改,而不能识别由 Google 表单或其他脚本所做的更改。很简单,Google 还设置了一个基于表单提交的特定触发事件。

1.从脚本编辑器中打开项目触发器—按作者排序的图像

2.为此脚本添加一个新的触发器—作者图片

3.用您需要的设置配置您的新触发器—按作者分类的图像

Code.gs

Code.gs 在这里是一个非常酷的工具。它有如此大的潜力,将极大地帮助我的实际工作。如果您的公司已经在使用 G-suite,那么使用您团队的现有流程,并添加一些自定义功能,作为 mvp 步骤来帮助他们。许多销售团队将为单个客户或项目存储他们的信息大型电子表格,只需要一点数据帮助。使用地图功能、电子邮件或日历连接工作表。

将 Python 连接到 Google Docs API

接下来,我们将把我们的应用程序直接连接到谷歌表单中的实时数据。

最初的搜索把我带到了 Google Docs Quickstar 页面。虽然它很全面,对于你可能在命令行中运行的应用程序来说也很棒,但对于我们在 Heroku 上托管这个应用程序的最终目标来说,它并不起作用。

更好的解决方案是使用谷歌服务账户

谢天谢地,另一个来自的帖子完美地解释了我们在这里需要做什么。

[## Python 与 Google Sheets 服务帐户:一步一步

几天前,我第一次体验了 Google Sheets API。我原以为这是一个简单的任务,但是,嗯…不是。

medium.com](https://medium.com/@denisluiz/python-with-google-sheets-service-account-step-by-step-8f74c26ed28e)

我不可能比上面的链接写得更好。相反,我会强调我在这个过程中遇到的地方,并指出我们将为我们的应用程序做出的一些轻微的偏差。

  1. 添加你的电子邮件——也许我读教程读得太快了,或者我认为因为我的个人电子邮件负责 API 和 Google 表单,权限已经设置好了。您需要将特殊的 API 电子邮件添加到 Google 工作表的“共享”部分,就像您邀请同事进行编辑一样。

服务帐户设置屏幕截图-按作者分类的图像

2.安装 Google 客户端库——像许多数据科学项目一样,我使用 Anaconda 作为包管理器。我总是试着用它来管理依赖项,并在安装了其他包之后,把安装 pip 作为最后的选择。令人欣慰的是,Anaconda conda install -c conda-forge google-api-python-client google-auth-httplib2 google-auth-oauthlib中也包含了连接到 Google API 所需的包。最终,当我们到达将应用程序加载到 Heroku 的最后一步时,这些包将与 pip 一起下载,但在我测试时,我喜欢使用 Anaconda。

3.stringy 凭据— 如果我们要将该应用程序与 Heroku 一起使用,这与上面的中级教程有很大的不同。代替应用程序在当前工作目录中查找 credentials.json 文件,我们将使用。json 文件作为一个大字符串,并在我们的函数中将其转换回 json。

这是为了防止我们传递凭证文件并可能暴露它。Heroku 有一个内置的系统来传递这样的环境变量到我们的应用程序,就像我们的本地系统一样。

现在,为了在本地测试我们的项目,我们需要将它们添加到中。bashrc。zshrc 文件。如果你以前没有这样做过:来自김영석的精彩教程

  • 在文本编辑器中打开凭证文件,高亮显示并复制所有的凭证文件(包括{ & })。
  • 打开你的。bashrc 文件并添加新的环境变量,用单引号' '将您要粘贴的信息括起来:
  • export GDRIVE_AUTH='<paste your credentials here>'

4.找到要连接的数据的工作表 ID。重复上述步骤,为它创建一个环境变量。

Google 表单的唯一 ID——按作者分类的图片

  • export SPREADSHEET_ID='<paste your unique ID here>'

5.最后,在工作表中添加需要数据的特定区域作为环境变量

  • export RANGE_NAME='Form Responses 1!A1:AF'

去拿数据

我们的 Python 代码中的第一个任务是调用 Google Sheet API,并用最新的值创建一个 Pandas DataFrame。

Pandas 将允许我们在创建图表和视觉效果之前对数据进行大量的操作,并且会以足够快的速度完成这个网页。

这个函数需要我们刚刚提到的三个全局变量来定义 Google Sheet API 应该寻找什么。在最终的 Dash 应用程序脚本中,我们将在上面的函数之前定义这些。

  • SPREADSHEET_ID = <the unique code from the URL of the Sheet>
  • RANGE_NAME = <The name of the tab and range to look for>
  • CREDS = The stringified version of our Google API Credentials above

接下来,我们添加一个简单的函数,将电子表格中的值转换成 Pandas 数据帧。

现在,我们准备用结果数据创建一个 Plotly Dash 应用程序。

结论

这里,我们已经完成了构建仪表板的第一部分。我们现在有了一个从我们的数据存储中获取最新数据的流程,然后我们将构建一些可视化并将应用程序部署到 Heroku。

第二部分:

构建一个 Plotly Dash 应用程序

[## 从 Google Sheets 构建一个精巧的 Dash 应用程序——第 3 部分

到目前为止,我们已经创建了一个免费的用户友好的数据存储,并通过 Python API 连接到它

medium.com](https://medium.com/@derrickjameslewis/building-a-plotly-dash-app-from-google-sheets-part-3-666c496c8a71)

从 Google Sheets 构建一个精巧的 Dash 应用程序——第 2 部分

原文:https://towardsdatascience.com/building-a-plotly-dash-app-from-google-sheets-part-3-666c496c8a71?source=collection_archive---------27-----------------------

Plotly Dash 应用程序

创建一个 web 应用程序来显示我们新数据存储中的一些可视化效果。

到目前为止,我们已经创建了一个免费的、用户友好的数据存储,并通过 Google Python API 连接到它。

第 1 部分— 使用 Google 和 code.gs 进行设计和 ETL 过程

接下来,我们将使用这些数据为现场营销团队构建仪表板,以跟踪他们的活动和奖金进度。

荒野中的自行车营销——作者图片

构建 Plotly Dash 应用程序

Dash 是 Plotly 的一个开源工具,它让数据科学家和其他像我一样对前端无知的人有机会组装一个交互式 web 应用程序,用几行 python 代码展示他们的 Plotly 图表。

Plotly Dash 上的文档非常棒,并且有很好的例子,直入主题。

仪表板基础

打开一个终端,为我们的项目创建一个新的环境。

conda create -n <yourEnvironmentName>

conda activate <yourEnvironmentName>

conda install plotly dash pandas numpy flask

从第 1 部分开始,我们将需要 Google API 库:

conda install -c conda-forge google-api-python-client google-auth-httplib2 google-auth-oauthlib

开始一个新的项目文件夹,并创建一个名为app.py的文件。我们已经准备好构建我们的 Dash 应用程序了。

  1. 【第 5 行】启动烧瓶
  2. [第 7–8 行 ]使用刚刚创建的服务器创建一个 Dash 对象
  3. [第 10–20 行] 使用布局方法将组件和样式添加到该 Dash 对象。
  4. 【第 23 行】运行服务器

就是这样。有了这 4 个核心部分,你现在就有了一个可以工作的应用程序。

Dash 的核心是应用程序的所有可视化组件都是 Python 类。对于您可能使用的组件类型,有特定的库可以导入,例如用于 div 和 image 等基本 HTML 项目的 HTML 库,用户友好的 Dash Core Components 库,其中包含预构建的下拉列表、列表、按钮、图形(!)等许多典型的 web 组件,最后是 Dash 数据表库来显示和操作页面上的大型数据表。

从终端的工作目录运行python app.py

如果没有错误,您应该会看到上面的内容。这意味着您的电脑正在运行该应用程序。打开浏览器,进入 http://127.0.0.1:8050/ (或者上面给你的任何回复)。您将看到应用程序正在运行,并从您的布局中显示<h2>消息。还要注意浏览器右下角的蓝色圆圈。这对于将来调试和跟踪回调非常方便。

复试

理解我们的应用程序如何运行的另一个非常重要的步骤是回调。在我们启动 Flask 之后,创建一个 Dash 对象,并设计我们的应用程序可以响应更改的布局,例如在下拉列表中选择一个值,单击一个按钮或对一个表格进行排序。

Dash 中回调的基本结构如下所示:

@ app.callback(
    Output(component_id='graph', component_property='figure'),
    [Input(component_id='dropdown', component_property='value')]
)
def build_graph(selection): The first arguement in our function is the first item in the
    list of Inputs above. Name it as you like Do something here with the input.
    In this case it is the values from the dropdown. return the property needed for the output 
            (in this case it is a plotly figure object)

Dash 现在将监听我们名为“dropdown”的组件中的任何变化。当事情发生变化时,它将运行连接到回调的函数。然后将函数的输出返回给列出的组件。因此,用我们的选择更新页面。

快进

Plotly 为其 Dash 应用程序和可视化库提供了令人难以置信的文档。因此,我会让您找到您想要使用的特定工具,然后继续讨论我们将如何连接我们的 Google Sheet 以在仪表板中使用。

我们的建筑

首先,我们需要添加两个函数来从第 1 部分的中获取 Google 数据到我们的app.py脚本中。这将从我们的谷歌表获取数据,并将其转换成熊猫数据框架。

布局

接下来,我们将构建 Dash 应用程序的布局。Dash 的想法是,它是为那些对前端开发、React 或 Javacript 知之甚少的人提供的工具。对于像我一样的初学者,我将在下面强调两点。

  1. 仪表板自举组件

Bootstrap 是一个流行的 CSS 框架,用于在手机和其他屏幕上浏览响应站点。

在开发我的前几个 Dash 应用时,我努力调整布局。简单的任务,比如将一段文字居中或者增加页边空白是很困难的,很少能得到我想要的结果。

Dash Bootstrap Components 是第三方库,用于将 bootstrap CSS 集成到 Dash 中。文档非常棒,我从他们的视觉效果中学到了很多布局的工作原理。看一看:

https://dash-bootstrap-components . open source . faculty . ai

该库将容器、行和列的 Python 类添加到页面布局中。将这种结构与您的组件一起使用将允许站点更好地响应其他屏幕。对我来说,Python 类使得调整大小和对齐变得简单

在您的环境中安装 Dash 引导组件:

conda install -c condo-forge dash-bootstrap-components

2。数据表

数据表是 Dash 的一个组件,用于查看、编辑和浏览大型数据集。表格允许我们的应用程序用户过滤、排序和选择可以直接输入到我们的可视化数据。

他们非常强大,但也很挑剔。构建表格、列和标题非常简单,但是理解每个样式设置如何与其他样式设置交互可能需要一些时间来理解并导致意外的布局。

我遇到了与下面的单元格匹配的固定行标题的问题,以及某些 CSS 设置切断了数据的最左边和最右边的像素。

第一个提示是理解所有样式设置的优先级顺序:

  1. style data 有条件
  2. 样式 _ 数据
  3. style filter 有条件
  4. 样式 _ 过滤器
  5. style header 条件
  6. 样式 _ 标题
  7. 样式_ 单元格 _ 条件
  8. 样式 _ 单元格

这意味着将类似minWidth=60的设置调整为“样式 _ 数据”,将覆盖“样式 _ 单元格”中maxWidth=50的任何重叠设置。

我在使用 Dash 数据表时的下一个技巧是为所有的样式设置建立一个单独的文件。在我在网上找到的许多例子和教程中,每一列数据都是使用 for 循环添加的,甚至一些条件格式的列和数据也是如此。虽然这不是最有效的,但使用单独的文件并手动构建每一列使我能够快速轻松地调试、测试和调整数据。因此,在学习用表格构建 Dash 应用程序时,明确一点是个好主意。您可以测试并学习如何更改数据格式、颜色和列宽。下面是我在这个仪表板上使用的例子:

请注意,在第三个列表“bonus_data_cond”中,我可以设置一个条件样式来检查我们的员工是否超过了他们的奖金目标。然后脚本相应地设置背景颜色。

我在我们的主脚本app.py中导入所有这些变量,并在上面的表格布局中分配它们,如下所示:style_cell_conditional=bonus_cell_cond

复试

接下来,我们将为每个可视化和交互式组件添加回调。我们要建造:

  1. 响应摘要统计
  2. 交互式地图
  3. 一个数据表,带有对应于数据选择的条形图。

特殊的数据回调

我们将从一些我在许多教程中没有发现的有趣的东西开始。在测试应用程序时,加载页面时数据通常不会刷新。此外,我发现一些资料提到了创建回调的最佳实践,该回调将数据作为字符串存储到html.Div()中,而不是让 python 脚本将数据作为每个函数都可以使用的全局变量存储在 Pandas DataFrame 中。对于这个数据存储库html.Div(),我们将设置style={'display':'none'}

但是为什么呢?

这为我们做了几件事。首先,它强制页面在每次加载时更新数据。其次,每个可视组件都将使用存储在这个隐藏组件中的数据来构建。API 调用和一些计算量更大的数据转换将只发生一次。对可视化的改变发生得更快,因为数据已经是干净的,只需要被过滤。最后,我知道如果数据不打算被看到或读取,这种做法有一点安全隐患。

因此,在我们的第一个页面加载期间,这个函数将由隐藏的html.Div()运行。主数据转换将在这里发生,日期被转换,数字被存储为整数。然后 2 个响应回调将使用这些干净的数据进行过滤。所有数据都以字符串格式存储在.Div()组件中,而不是存储在服务器的内存中。幸运的是,这个项目永远无法处理非常大的数据集。如果这是您的情况,您应该找到一个替代方案来保持较低的内存使用率。

实际上,我将设置两个数据收集回调。原因是允许仪表板在主地图和员工奖金表之间独立设置时间范围。

地图构建回调

在这里,我们深入了解 Plotly 的一些核心可视化优势。我们从我们的隐藏数据组件输入数据,并将其从字符串转换回 Pandas DF 进行一些操作,然后我们返回一个散点图以在上面的应用程序布局中呈现。

数据表回调

设置 Dash 数据表的大部分繁琐工作都是在布局和样式中完成的,这里我们使用 Pandas 对每个现场营销员工进行一些聚合,并返回一个字符串格式的数据供 dash_table 读取。布局中的 DataTable() 组件。

条形图回调

这是许多仪表板项目中我最喜欢的部分之一。数据表提供了选择行、突出显示、删除和过滤的灵活性。所有这些对表格的调整都可以作为结果可视化的输入发送(或者更好…机器学习预测!)

为什么这是我最喜欢的部分?因为我喜欢给仪表盘尽可能多的灵活性。用户可能想知道一个非常具体的问题的答案,“四月份在东部地区销售了多少个小部件?”一个好的仪表板设计给用户带来了灵活性,仪表板数据表本身就有这种功能。

这里,我们将从上表中的选定行中获取输入,并构建 4 个条形图。

这里需要强调的是,回调不仅可以接受多个输入,还可以将输出设置为一个列表并发送给多个组件。

汇总统计回调

这个回调简单明了地报告了给定初始日期选择器组件中设置的时间范围的清晰指标。大多数商业用户希望快速认知。这个报告的关键数字,有很大的空间。

把它们放在一起

以上所有部分组合成一个 Dash 应用程序。

下面的 Github 库包含了上面的核心部分,以及一些额外的地图,附加的过滤器和一些图片。

[## lewi 0332/谷歌仪表板

Plotly Dash 应用程序连接到 Google Sheets API。为 lewi0332/google_dashboard 开发做出贡献,创建一个…

github.com](https://github.com/lewi0332/google_dashboard)

结论

这是一个很大的步骤,需要在设计中进行大量繁琐的尝试和错误,但这是你可以让你的项目脱颖而出并为用户增加很多价值的地方。

第 3 部分—部署到 Heroku

[即将推出]

我们潜在仪表板的屏幕截图—作者提供的图片

构建预测模型来分类垃圾文本

原文:https://towardsdatascience.com/building-a-prediction-model-to-classify-texts-that-are-spam-a2ccded75e77?source=collection_archive---------32-----------------------

在这篇文章中,我和我的同事使用了一个文本信息数据集来建立一个预测模型,以分类哪些文本是垃圾邮件。

照片由杰米街Unsplash

数据集

该数据集包含 5,574 封被标记为垃圾邮件或非垃圾邮件的邮件。该数据集被视为黄金标准,因为合法文本是为新加坡国立大学计算机科学系的研究而收集的,而垃圾短信是从英国的一个论坛中提取的,手机用户在该论坛上公开声称收到垃圾短信。

步骤

应对挑战的步骤包括:数据探索、数据预处理(标记化、词干化、词条化、空白、停用词等。),通过词云识别排名靠前的垃圾词,建立训练集和测试集,在训练集上建立分类模型,测试模型,最后对模型进行评估。

初始发行

最初面临的一个问题是,大部分数据集包含更高比例的合法文本消息。在将欺诈/垃圾邮件检测建模为分类问题时,一个常见的挑战是,在现实世界的数据中,大多数都不是欺诈性的,留给我们的是不平衡的数据。我们必须确保我们的训练数据集不会偏向合法的消息。处理不平衡数据有多种方法,如 SMOTE、RandomUnderSampler、ENN 等。我和我的团队引入了分层抽样。我们希望避免这种情况,即我们的模型预测大多数消息是合法的,而团队接受模型是合适的,因为尽管有偏差,但准确性很高。

流程

开发垃圾短信分类解决方案的方法包括:

初步文本分析

  • 使用饼图检查有多少邮件是垃圾邮件或合法邮件
  • 创建一个由垃圾邮件和非垃圾邮件组成的单词云
  • 识别前 10 个垃圾邮件单词和前 10 个合法单词
  • 分析垃圾邮件和合法文本消息的长度,并分别绘制两个图表来检查它们的长度分布。

文本转换

  • 通过删除停用词、执行标记化、词干化、词条化、空白等来清理数据。
  • 我们使用 NLTK 库中的‘SnowballStemmer’从单词中移除形态词缀,只留下单词词干
  • 我们使用“TfidfVectorizer”从提供的计数矩阵执行 TF-IDF 转换
  • 我们在数据集中对类别进行了编码:“垃圾邮件”为 1,“合法”为 0
  • 我们以 80:20 的比例分割训练和测试数据

分析

我们通过数据可视化和探索注意到的几个快速观察结果是,大约 86.6%的数据是合法的,而其余 13.4%是垃圾数据。我们还捕获了最常见的垃圾邮件单词(“呼叫”、“免费”、“Txt”、“发送”、“停止”、“回复”)和合法单词(“u”、“gt”、“lt”、“ok”、“get”、“go”)。发现的其他见解是,与合法消息相比,垃圾消息的长度往往更长。我们绘制了以下图表进行探索性分析:

被归类为垃圾邮件或火腿的文本百分比(合法)

#Lets see what precentage of our data is spam/ham texts["category"].value_counts().plot(kind = 'pie', explode = [0, 0.2], figsize = (6, 6), a plt.ylabel("Spam vs Ham") plt.legend(["Ham", "Spam"]) plt.show()

来自数据集的前 10 条短信

#top ham/spam messages message toptexts = texts.groupby("text")["category"].agg([len, np.max]).sort_values(by = "len", asc display(toptexts)

垃圾词云

#Spam Word cloud spam_wordcloud = WordCloud(width=600, height=400).generate(" ".join(spam_words)) plt.figure( figsize=(10,8), facecolor='k') plt.imshow(spam_wordcloud) plt.axis("off") plt.tight_layout(pad=0) plt.show()

火腿(合法)字云

#Ham word cloud ham_wordcloud = WordCloud(width=600, height=400).generate(" ".join(ham_words)) plt.figure( figsize=(10,8), facecolor='k') plt.imshow(ham_wordcloud) plt.axis("off") plt.tight_layout(pad=0) plt.show()

火腿和垃圾短信长度分布

f, ax = plt.subplots(1, 2, figsize = (20, 6)) sns.distplot(texts[texts["category"] == "spam"]["messageLength"], bins = 20, ax = ax[0]) ax[0].set_xlabel("Spam Message Word Length") sns.distplot(texts[texts["category"] == "ham"]["messageLength"], bins = 20, ax = ax[1]) ax[0].set_xlabel("Ham Message Word Length") plt.show()

结果

模型应用

我们使用朴素贝叶斯来训练我们的模型。我们选择这种模型是因为在处理文本时,将每个独特的单词视为一个特征是非常常见的,并且由于典型的人的词汇量是成千上万的单词,这导致了大量的特征。当单词的多次出现在分类问题中很重要时,该算法是相关的。该算法的相对简单性和朴素贝叶斯的独立特征假设使其成为分类文本的强有力的执行者,因此我们决定使用朴素贝叶斯分类器来将文本消息分类为合法的或垃圾邮件。

模型评估

我们认为精确度是更好的评估标准,因为更有必要不将合法邮件归类为垃圾邮件。因此,我们致力于创建一个具有更好的可接受的 f-beta 分数的模型,并倾向于将精确度作为我们提出的问题的解决方案的准确性度量。结果,我们发现该模型的 f-beta 分数为 0.93,这可以被认为是足够好的,可以推断所建立的模型非常接近预期使用的理想模型。

娜塔莉·加尔塞斯 是一名来自大西雅图地区的数据分析师。她获得了华盛顿大学的商业和 MSBA 学士学位。她写作并热衷于数据可视化、投资和所有科技方面的东西。

在不发布的情况下构建 Python 包

原文:https://towardsdatascience.com/building-a-python-package-without-publishing-e2d36c4686cd?source=collection_archive---------13-----------------------

轻松访问和组织您的 Python 模块

UnsplashLeone Venter 拍摄的照片

python 中的包允许无缝分发 Python 模块。当我们使用 pip install 时,我们经常从 PyPI 下载一个公开可用的包。本地包对于代码组织和重用也很有用,允许您简单地导入一个模块,而不必导航到它的目录或重写代码。在本次演示中,我们将构建和访问一个基本的 Python 包。

让我们创建两个简单的模块并将它们打包。然后,我们将使用这个包编写一个简单的应用程序,提示用户从他们的计算机中选择一个. jpg 图像进行灰度化。

编写您的模块

ui.py

#ui.pyfrom tkinter import filedialog
from tkinter import Tkdef get_image_file():
    Tk().withdraw()
    filename =  filedialog.askopenfilename(title = "Select file",filetypes = [("jpeg files","*.jpg")])
    return filename

image_edits.py

#image_edits.pyfrom cv2 import imread, COLOR_RGB2GRAY, cvtColor, imwrite
import osdef write_grayscale_image(filepath):
    original_image = imread(filepath)
    grayed_image = cvtColor(original_image, COLOR_RGB2GRAY)
    grayed_filename=os.path.join(os.path.split(filepath)[0],'grayed_'+os.path.split(filepath)[1])
    print(grayed_filename)
    imwrite(grayed_filename, grayed_image) #export grayscaled image
    return grayed_filename

初始化和设置文件

创建一个空白的 init。py 文件,Python 将使用它来识别这个包。

$ touch __init__.py

此时,我们的文件结构应该如下所示:

dir/
    image_pkg/
              ui.py
              image_edits.py
              __init__.py

接下来,在您的包目录外创建一个 setup.py 文件

setup.py

import setuptoolssetuptools.setup(name='examplepackage',
version='0.1',
description='An example package',
url='#',
author='max',
install_requires=['opencv-python'],
author_email='',
packages=setuptools.find_packages(),
zip_safe=False)

注意,python 标准库中没有包含的包应该包含在 install_requires 中。我们的文件结构现在应该看起来像这样:

dir/
    image_pkg/
              ui.py
              image_edits.py
              __init__.py
    setup.py

构建并安装您的软件包

如果您正在使用虚拟环境(Python 开发的一般良好实践),创建并激活您的环境。

$ python3 -m venv myenv
$ source myenv/bin/activate

安装车轮。

$ pip install wheel

将软件包安装到您的环境中。

$ pip install .

我们的包已经创建好了,现在我们可以在任何地方使用它。让我们创建一个简单的应用程序,它包含了我们的包内容。

main.py

#main.pyfrom image_pkg.ui import get_image_file
from image_pkg.image_edits import write_grayscale_imagewrite_grayscale_image(get_image_file())

我们现在已经构建并实现了一个基本的 python 包!关于软件包分发、许可和安装的更多信息可以在文档中找到。

其他 Python 教程:

[## 用 Python 解迷宫

使用 Dijkstra 的算法和 OpenCV

towardsdatascience.com](/solving-mazes-with-python-f7a412f2493f) [## 为 Python 构建一个简单的 UI

Streamlit:一个基于浏览器的 Python UI,不需要 HTML/CSS/JS

towardsdatascience.co](/building-a-simple-ui-for-python-fd0e5f2a2d8b)

如何更新你所有的 Python 库

原文:https://towardsdatascience.com/building-a-python-ui-to-keep-your-libraries-up-to-date-6d3465d1b652?source=collection_archive---------23-----------------------

了解我如何使用 PySimpleGUI 来更新我的 Python 库

概观

就在几天前,我试图通过使用 python 库中最近引入的功能来解决我的一个问题。没多久就意识到不在了。我使用的是一个如此陈旧的库版本,以至于很多新功能都不存在。

我通过 pip 管理我的包,所以一次升级一个库非常简单。不幸的是,如果你想全部升级,情况并非如此。没有内置的功能让你一次升级所有的软件包。

我最终拼凑了一些东西,这些东西将循环遍历我的包并升级它们。然而,这个解决方案不允许我选择单独的库来升级;这意味着,无论出于什么原因,如果我不想升级我的某个库,我就会被卡住。这就是为什么我决定建立一个 UI,让我挑选要升级的库。

在这个博客里,我把这个作品分享给你,这样你也可以使用它。随意构建和改进它;或者大家有什么建议,留下评论,也许我会更新。

马库斯·斯皮斯克在 Unsplash 上的照片

调味汁

整个脚本不到 100 行,我使用了四个广泛使用的库来完成。

1.子过程

这个库允许我们与命令行交互,并传递我们想要的任何命令。这就是我将如何找出哪些库是过时的,然后升级它们。

2.熊猫

熊猫以处理数据而闻名。在这个实例中,我们将使用它将一个 CSV 文件读入数据帧,这也很适合我们选择的 UI 库:PySimpleGUI

了解有关将文件读入 pandas 的更多信息:

[## 用 Python 从 Excel 到数据库

了解如何使用 Python 进行快速数据分析

medium.com](https://medium.com/financeexplained/from-excel-to-databases-with-python-c6f70bdc509b)

3.铼

Re 是 Python Regex 库,它允许我们轻松地匹配模式。在这种情况下,我们将使用它来剔除任何不必要的信息,只显示有用的信息。

了解有关正则表达式的更多信息:

[## 正则表达式简介

使用 Python 逐步介绍正则表达式

medium.com](https://medium.com/better-programming/introduction-to-regex-8c18abdd4f70)

4.PySimpleGUI

最后,PySimpleGUI 将是我们用于 UI 的库。我们将定义 UI,然后定义事件:

了解有关构建 Python 用户界面的更多信息:

[## 了解如何用 Python 快速创建 ui

最后,你可以在 10 分钟内找到一个图书馆

towardsdatascience.com](/learn-how-to-quickly-create-uis-in-python-a97ae1394d5) [## 构建用于比较数据的 Python UI

如何快速让您的非技术团队能够比较数据

towardsdatascience.com](/building-a-python-ui-for-comparing-data-13c10693d9e4)

完整的代码

结论

好了,伙计们。在不到 100 行代码中,您可以看到所有 Python 过时的库,并选择想要升级的库。

出于几个原因,您当然应该定期这样做:

  1. 获取最新的错误修复
  2. 解决任何漏洞
  3. 性能增强
  4. 访问软件包的最新和最强大的功能

希望你觉得有用。

从零开始的随机森林算法

原文:https://towardsdatascience.com/building-a-random-forest-classifier-c73a4cae6781?source=collection_archive---------17-----------------------

直觉、伪代码和代码

从头开始实现随机森林 ML 算法听起来像是一项令人生畏的任务。仅仅是想到我们要做对多少细节,就很容易感到不知所措。或者至少我是这么觉得的。我从哪里开始?第一步是什么?我如何知道它是否有效?

图米苏Pixabay 上的照片

转折点是当我意识到我需要从而不是思考代码开始。想象一下,我站在算法里面,在一棵树的根部,我会怎么做?然后呢?问这些问题有助于分解和简化问题。回答这些问题将建立对算法内部工作的直觉。在本帖中,我们将和泰坦尼克号数据集一起探讨这些问题和答案。

我们的议程:

  1. 涵盖随机森林功能的高级概述
  2. 为一个二进制随机森林分类器编写伪代码
  3. 解决一些最小的数据预处理需求
  4. 编写代码(可在此处完整访问
  5. 对照 scikit-learn 算法检查结果

请注意,这篇帖子的灵感来自于 Fast.ai 机器学习课程,我强烈推荐给那些通过做来学习最好的人。

让我们开始吧!

如果你在泰坦尼克号上,你会幸存吗?

“均值”是指那个群体中每个人的平均存活率。

  • 开始时,船上每个人的预期存活率是 40%
  • 那么对于所有女性,75%
  • 而对于所有男性,20%……等等。

对我来说,我是一个女性,说我有一张三等票。按照这个决策树,我在泰坦尼克号上幸存的概率是 50/50。

另一个人,男性,也在第三类,将有 10%的生存机会;除非他未满 15 岁,否则他生还的可能性是 90%。

这是随机森林中的一棵决策树。我们已经被提供了根据哪个特征(即年龄)以及在哪个级别(即 15 岁以下)进行划分。为了预测一个新轮廓的存活几率,我们简单地跟踪这些分支。

现在让我们拿走树枝。想象我们在树根处。

据我们所知,所有样本中,有 40%存活了下来。我们必须决定拆分哪个功能,以及在什么级别上拆分。怎么会?

我们将尝试每一个功能和每一个级别,对每一个组合进行评分,并选择最好的。

for feature in list of features: 
     for (unique) row in data: 
          what is the score of we split here? 
          if the score is better what we have: update it 

但是分数是多少呢?我们如何知道哪种分割是最好的?

分数

对于分类问题,一个常用的指标是基尼不纯度(这也是 scikit-learn 的缺省值)。每个分割都有一个基尼系数:

让我们看一个简单的例子:

如果我把女性和男性分开,基尼系数会是多少?

x = [1, 1, 1, 1, 1, 2, 2, 2] #5 female & 4 male
y = [1, 1, 1, 1, 0, 0, 0, 0] #4 survived & 4 died

**Decision Tree:**def check_features: 
     for feature in list of features: 
          find_best_split of this featuredef find_best_split(feature):
     for (unique) row in data:
          left = list of all rows <= current row          
          right = list of all rows > current row 
          calculate the score           
          if the score is better than what we have: update itdef find_gini(left_split, right_split, y): 
     p(left) = n_left/n_y
     p(right) = n_right/n_y
     for each outcome: #in this case, Survived or Died
          p = probability of this outcome for the left 
          sum_left += p^2 
          p = probability of this outcome for the right
          sum_right += p^2
     gini = weighted average of (1-sum_left) and (1-sum_right)def prediction():  
     return array of predictions for this tree 

随机森林

一个森林由无数的决策树组成。随机部分呢?假设我们有一个包含 1000 个样本和 5 个特征的数据集。我们想建 10 棵树。所有的树都会在同一个地方裂开,最后形成 10 棵完全相同的树。这对我们帮助不大。

如果我们每次取数据集的不同部分会怎么样?假设我们想要 100 棵树,这意味着每棵树 10 个样本,这将导致相当高的方差。

有没有办法让我们每次都用 1000 个样品?而且每棵树的数据也略有不同?是: 自举 。我们从数据集中抽取 1000 个样本,进行替换。平均来说,大约 63%的原始观测值将被包括在内。这对于减少过度拟合很重要。

使用 3 个样本自举

使用这种方法,我们将为每棵树提供不同的数据。随机森林的目标是拥有彼此尽可能不同的树,但非常擅长预测给定的数据。然后,如果你有许多不相关的树,每个树都有很高的预测能力,当你把它们加起来时,误差总和将为零。剩下的将是 X 和 y 变量之间的真实关系。

**Random Forest**:def __init__ (x, y, n_trees, sample_size, min_leaf):
     for numbers up till 1-n_trees: 
          create a tree def create_tree():
     get sample_size samples, use np.random.choice w/ replacement
     create an instance of the Decision Tree class def predict():
     average of predictions from n_trees 
     return binary outcome 0 or 1 

我们现在有了这两个类的伪代码。让我们将它转换成代码,并与 scikit-learn 的 RandomForestClassifier 的结果进行比较。

数据

  • 输入和目标必须是数字
  • 分类特征是标签编码的(如果是有序的)或一个热编码的

离群值和特征缩放怎么办?原来随机森林一般对这些免疫。它的决定是有序的。请记住,在每次考虑分割时,我们将样本分为两组:大于分割值的样本,以及小于或等于分割值的样本。如果我们考虑在 15 岁分开:不管你的年龄是 16 岁还是 60 岁,两者都将被放在一组。随机森林很少假设数据的分布,这是一个很好的起点。

以下是预处理后的 Titanic 数据集的输入内容:

现在,让我们关注 2 个特性的子集:Pclass 和 Sex。

代码

第一次拆分

我们回到了第一棵树的根部。让我们写吧

scikit-learn 树告诉我们这是第一次分裂。

我们的树也做了同样的决定!

tree = RandomForest(x_sub, y_train, 1).tree[0]
[output] gini: 0.318; split:1, var: Sex

进一步分裂

如果我们允许 scikit-learn 树再分裂一次(深度=2):

第一次分开后,我们把所有的女人分在一组,所有的男人分在另一组。对于下一次拆分,这两个组将有效地成为他们自己的决策树的根。对于女性来说,下一步的划分是将第三等级从其他等级中分离出来。对男人来说,下一个分裂是把第一阶层从其他阶层中分裂出来。

让我们修改一下我们的伪代码:

def check_features: 
     for feature in list of features: 
          find_best_split of this feature
     left_hand_side = rows <= our split point 
     right_hand_side = rows > our split point 
     DecisionTree(left_hand_side)
     DecisionTree(right_hand_side) 

结果与 scikit-learn 的结果相匹配:

tree = RandomForest(x_sub, y_train, 1).tree[0]
[output] gini: 0.318; split:1, var: Sextree.lhs 
[output] gini: 0.264; split:2, var: Pclasstree.rhs
[output] gini: 0.272; split:1, var: Pclass

预测

让我们加入更多特性,看看我们的模型是如何工作的:

使用 10 个决策树,我们的模型在测试集上有 81%的准确率。分数低于 scikit-learn 的分数。但是对于一个我们从零开始构建的算法来说还不错!

所以你看,从零开始建立一个随机的森林并不一定是令人生畏的。学习过程的这一部分让我能够区分出算法的哪些部分我真正理解了,哪些部分我还需要继续努力。有时候,除非你尝试自己去实现,否则你不会明白。

谢谢你让我分享我所学到的东西。我希望这篇文章对你有所帮助。欢迎提出问题和建议!

参考资料:

直到下一次,

V

使用 Python Plotly 库和 Web 服务构建实时仪表板

原文:https://towardsdatascience.com/building-a-real-time-dashboard-using-python-plotly-library-and-web-service-145f50d204f0?source=collection_archive---------1-----------------------

变更数据

卢克·切瑟Unsplash 上拍摄的照片

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

仪表板是一个图形界面,提供与特定现象或业务相关的一些关键指标的综合视图。在这篇文章中,我将一步一步地展示我们如何使用 Python Plotly 支线剧情构建一个仪表板来实时执行新冠肺炎病例的每日报告。我们的目标是制作一个实时仪表板,如下所示:

显示全球新冠肺炎数据的仪表板

仪表盘的实时版本可从以下网址获得

https://covid-19-data-visualizer.herokuapp.com/

您在访问实时仪表盘时可能会遇到一些延迟,因为它是使用免费的 Heroku 帐户部署的,处理资源有限。

数据源和 web 服务

因为我们将基于实时数据构建一个仪表板,所以数据源来自 web 服务,而不是静态的 CSV 或文本文件。简而言之,web 服务是一个在线数据库,我们可以通过它联系并请求一些想要的信息,然后将它们获取到我们的应用程序中。

在本教程中,我们将使用从 Esri 提供的 Web 服务中获得的新冠肺炎数据来构建我们的仪表板。来自该网络服务的新冠肺炎数据每天更新。****

先决条件 Python 库

从 Github 下载源代码

为了让你更轻松地学习本教程,你可以从我的 Github 库获得完整的源代码(新冠肺炎 _ 仪表板. ipynb )。

您可以使用我的源代码作为参考来理解构建仪表板的过程,我将在下面的部分中介绍这个过程。

构建新冠肺炎控制板的步骤

第 1 部分:设置 Python 库

我们通过导入本教程所需的所有必要库来开始我们的 Python 脚本。

用于导入库的 Python 代码

第 2 部分:从 web 服务请求数据

接下来,我们访问 esri 网站 以获取一个查询 URL,并将该 URL 复制并粘贴到我们脚本中的 Python request 模块,以向 web 服务发送 HTTP 请求(第 1 行)。HTTP 请求将以 JSON 格式从 web 服务向我们的应用程序返回最新的新冠肺炎数据(第 2 行)。我们从" features "属性中选择数据,并使用它来构建一个 Pandas dataframe,df (第 3 行)。

esri Web 服务网站

请求 web 服务的 Python 代码

我们可以使用熊猫头方法预览返回的新冠肺炎数据的前五条记录。

预览数据的 Python 代码

web 服务数据预览

要更详细地查看属性值,我们只需选择其中一项。

查看属性的 Python 代码

单个记录的属性

从预览中,我们可以看到新冠肺炎记录由一个字典列表组成,其中包括地理属性(如省 _ 州、国家 _ 地区、纬度、经度 _ )和数字属性(如确诊、痊愈、死亡)。此外,它还包括一个时间戳属性( Last_Update )。

第 3 部分:转换数据

从上一部分中,我们了解到新冠肺炎记录的结构是一个字典列表,在这里我们试图将它们转换成一个新的 Pandas 数据帧,df_final 。为此,我们首先使用 tolist 方法将字典转换成一个列表,data_list (第 1 行)。接下来使用 data_list 构建一个新的数据帧 df_final (第 2 行)。接下来,我们使用 set_index 方法将“OBJECTID”属性设置为每条记录的索引(第 3 行)。最后,重新排序 df_final 数据框中的列(第 4 行)并预览转换后的记录(第 5 行)。

转换数据的 Python 代码

转换数据帧

第 4 部分:清理数据

显然,转换后的数据看起来不错,但这里仍然存在两个问题:

  1. 在“最后 _ 更新”和“省 _ 州”列中有一些值 na 丢失。
  2. Last_Update ”列中的值是一个以毫秒为单位的时间戳,它对日期没有太多意义。

要处理第一个问题,我们可以使用 dropna 方法从列" Last_Update "中删除缺失的值(第 5 行),使用 fillna 方法用一个空字符串替换列" Province_State "中所有缺失的值(第 6 行)。

为了解决第二个问题,我们编写了一个函数 convertTime ,使用 fromtimestamp 方法(第 1–3 行),将时间戳转换为格式为" yyyy-mm-dd-hh-mm-ss" 的日期。列“Last_Update”首先除以 1000(第 8 行),然后对整个列应用 convertTime 函数(第 9 行)。

清理数据的 Python 代码

清理数据框

第 5 部分:聚合数据

目前,记录中确诊、康复和死亡病例的累计总数是以省为基础的,而不是以国家为基础的。构建这个仪表板的目的之一是显示排名前 10 位的国家列表。因此,我们需要对“确诊”、“死亡”和“恢复”列进行求和,并将求和值按“国家/地区分组,从而执行数据聚合。聚集的数据被分配给新的数据帧 df_total

聚合数据的 Python 代码

汇总数据

第 6 部分:计算每日新冠肺炎病例总数

在此阶段,我们准备使用前面部分的转换和汇总数据来计算两个级别的新冠肺炎病例总数:

  • 全球一级
  • 十大国家级别

第一步:全局级

全球每日新冠肺炎病例总数的计算非常简单。我们只是将求和的方法应用到 df_final 的“确诊”、痊愈死亡列。 sum 方法将合计三列中每一列的所有值,并将最终总和分配给它们各自的变量 total_confirmedtotal_recoveredtotal_deaths

用于计算全球范围内每日新冠肺炎病例总数的 Python 代码

第二步:十大国家级别

Pandas 提供了一种简便的方法,即 nlargest ,它使我们能够在数据帧的特定列中选择前十个值。为了选择确诊病例最多的前 10 个国家,我们向 nlargest 方法(第 1 行)传递一个 n 最大值和一个列名,并将返回的数据帧分配给一个新变量 df_top10 。接下来,我们生成国家名称列表(第 2 行)和确诊病例总数列表(第 3 行),并将它们分别分配给两个新变量, top10_countries_1top10_confirmed,

接下来,重复上面类似的步骤,以获得已康复(第 5-7 行)和死亡病例(第 9-11 行)的前十个国家数据。

Python 代码获取前 10 个国家和确诊、恢复和死亡病例数

第 7 部分:使用 Python Plotly 子情节构建仪表板

仪表板应显示以下信息:

  1. 世界各地每日确诊、恢复和死亡病例总数
  2. 全球每个国家的确诊、痊愈和死亡病例总数。
  3. 确诊、康复和死亡病例数最高的前十个国家。

我们将使用 Python Plotly 支线剧情创建几个支线剧情(每个信息部分一个)并将它们加入到一个单一的仪表板中。

第一步:初始化支线剧情布局

Python Plotly 库提供了一个 make_subplots 函数,使我们能够初始化 subplots 的布局安排。我们可以设置行数和列数来定位仪表板中的每个子情节。

在这种情况下,我们在支线剧情布局中定义了 4 行 6 列。我们出发了

第 1 行第 1 列:

  • 散点图——在地图上显示每个国家的确诊、痊愈和死亡病例总数

第 1 行第 4–6 列:

  • 指示图——显示全球每日确诊、痊愈和死亡病例总数

第 2 行第 4 列:

  • 条形图 —显示确诊病例最多的前 10 个国家

第 3 行第 4 列:

  • 条形图 —显示恢复案例数量最多的前 10 个国家

第 4 行第 4 列:

  • 条形图 —显示死亡病例最多的前 10 个国家

初始化子情节布局的 Python 代码

步骤 2:创建注释文本

在为散点图生成子图之前(将在下一步中呈现),我们需要定义一个注释文本。每当用户将鼠标悬停在地图上的某个国家上方时,就会显示注释文本。注释文本应显示国家名称、确诊病例、死亡病例和恢复病例以及最后更新日期。

创建注释文本的 Python 代码

地图上的注释文本

第三步:创建子剧情——散点图

为了创建一个散点地图,我们可以使用 Python Plotly go。散点图对象。我们从先前生成的 dataframe、 df_finallonlat 属性(第 4–5 行)中设置“ Long_ 和“ Lat ”数据。接下来,我们将注释文本 df_final["text"] 设置为 hovertext 属性。每当用户将鼠标悬停在某个国家/地区上方时,这将使预定义的注释文本(来自步骤 2)显示在地图上。

接下来,我们继续设置标记的参数值,如大小、不透明度、符号、颜色等(第 8–23 行)。我希望在这里强调的参数是“颜色”属性。我们将确诊病例的数据序列 df_final['Confirmed'] 设置为“color”属性(第 19 行)。出发。散点图对象将根据每个国家的确诊病例水平为地图上显示的标记(方框)生成色标。

最后,我们将散点图的这个子图放置在第 1 行第 1 列(第 27 行)。

创建散点图的 Python 代码

散点图

第四步:创建子剧情—指示器

我们使用 Plotly go 创建了三个指标,显示全球每日确诊、痊愈和死亡病例总数。指示器对象。我们将 total_confirmed、设置为 value property(第 4 行),将标题设置为“ Confirmed Caes ”(第 5 行)这将生成一个标题为“确诊病例的指示器,确诊病例总数将显示在标题下方。最后,我们将指示器的这个子图放置在第 1 行第 4 列(第 7 行)。

我们重复上述类似步骤,为恢复病例和死亡病例创建指标,并将它们放置到适当的行和列编号(第 10–26 行)。

Python 代码生成三个指标

显示确诊、康复和死亡病例的三个指标

第五步:创建支线剧情——条形图

在这一阶段,我们将着手创建三个条形图,以显示确诊、恢复和死亡病例数最高的前十个国家。我们使用 Plotly go.bar 对象创建相关的条形图。

为了创建确诊病例的条形图,我们将前 10 个国家列表和前 10 个数字列表(来自第 6 部分步骤 2)分别设置为 x 轴和 y 轴属性(第 3–4 行)。最后,我们将条形图定位到适当的行和列编号(第 9 行)。

我们重复类似的步骤来制作条形图,根据康复和死亡病例的数量显示前 10 个国家,并将它们放置到适当的行号和列号(第 10-26 行)。

Python 代码创建条形图来显示排名前十的国家

确诊、康复和死亡病例最多的前十个国家

步骤 6:完成布局设置

这是最后一步,我们将完成支线剧情的布局设置:

  • 模板(第 2 行)-为仪表板设置深色主题。
  • 标题(第 3 行)-为仪表板设置标题,并将上次更新的内容附加到标题中。
  • 图例(第 4–6 行)—将图例设置为可见,并将其设置为水平方向。定义坐标 x 和 y 以显示图例。
  • geo(第 7–14 行)-将显示的地图设置为正交地球,并在地图上显示海岸线、陆地和海洋。
  • 注释(第 16–24 行)-在操控板上设置附加注释文本,以在特定坐标 x 和 y 处显示数据源链接

最后,我们准备呈现我们的仪表板(第 27 行)。

最终确定仪表板布局的 Python 代码

新冠肺炎仪表板

第 8 部分:仪表板导航

带标签的新冠肺炎仪表板

乍看之下,我们可以通过仪表板右上角的三个数字指示器轻松查看每日确诊、康复和死亡病例总数。

在这三个数字指标下面,有三个条形图显示了确诊、恢复和死亡病例数最高的前十个国家。

要查看单个国家/地区的新冠肺炎数据,我们只需将鼠标放在地图上的一个标记(正方形)上,就会出现一个注释文本,显示该国家/地区报告的确诊、康复和死亡病例数。

显示所选国家/地区的新冠肺炎详细信息的注释文本

我们可以使用平移工具旋转正交地图。只需点击仪表盘右上角的平移工具,然后点击地图并向左或向右拖动即可。

点击平移工具

旋转地图

最后的想法

仪表板只是由几个支线剧情组成的可视图形,我们可以一部分一部分地构建它们。一旦我们熟悉了 Python Plotly 库来创建单独的图,我们就可以使用 Plotly Subplots 特性轻松地将它们集成到仪表板中。

让我们的仪表板变得实时的关键是不断地使用来自 web 服务的最新数据,并更新仪表板上的数据。这可以使用 Python 请求模块轻松完成。在我们的例子中,我们可以每天重新启动我们的仪表板,运行在后端的请求模块将从 web 服务请求最新的信息,并在仪表板上显示最新的新冠肺炎数据。

我希望您能从本教程中受益,并应用这里介绍的过程为您关心的数据创建其他仪表板。

参考

  1. https://en . Wikipedia . org/wiki/Dashboard _(商务)
  2. https://plotly.com/python/subplots/

使用 Spark 结构化流和微服务构建实时预测管道

原文:https://towardsdatascience.com/building-a-real-time-prediction-pipeline-using-spark-structured-streaming-and-microservices-626dc20899eb?source=collection_archive---------8-----------------------

在本教程中,我们将讨论在处理低延迟数据管道时解耦机器学习模型的好处

凯文·Ku 在 Unsplash 上的照片

我们将为机器学习预测建立一个实时管道。我们将使用的主要框架是:

  • Spark 结构化流:成熟易用的流处理引擎
  • Kafka :我们将使用 Kafka 的融合版本作为我们的流媒体平台
  • Flask :用于构建 RESTful 微服务的开源 python 包
  • Docker :用于本地启动 kafka 集群
  • Jupyter 实验室:我们运行代码的环境
  • NLTK :带有预训练模型的 python 的 NLP 库。

TL;DR:代码在GitHub上。

将 ML 模型构建为微服务的优势

在实时 ML 管道中,我们以两种方式嵌入模型:将模型直接用于执行处理的框架中,或者将模型单独解耦到微服务中。通过构建 ML 模型的包装器,我们需要额外的努力,为什么要这么麻烦呢?有两大优势。首先,当我们想要部署一个新模型时,我们不需要部署整个管道,我们只需要公开一个新的微服务版本。其次,它给了你更多的能力去测试 ML 模型的不同版本。例如,我们可以使用 canary 部署,在模型的version1上使用 80%的数据流,在version2上使用 20%的数据流。一旦我们对version2的质量感到满意,我们就会向它转移越来越多的流量。

现在让我们深入研究应用程序的开发。

步骤 1:运行 docker compose 来启动 kafka 集群

为了构建集群,我们将使用一个docker-compose文件来启动所有需要的 docker 容器:zookeeper 和一个代理。

现在简单地说,kafka 是一个分布式流媒体平台,能够处理大量的消息,这些消息被组织或分组到主题中。为了能够并行处理一个主题,必须将它分成多个分区,来自这些分区的数据存储在称为代理的独立机器中。最后,zookeeper 用于管理集群中代理的资源。为了读写 kafka 集群,我们需要一个代理地址和一个主题。

docker-compose将在端口2181启动zookeper,在端口9092启动kafka broker。除此之外,我们使用另一个 docker 容器kafka-create-topic的唯一目的是在 kafka broker 中创建一个主题(称为 test)。

要启动 kafka 集群,我们必须在定义 docker compose 文件的同一文件夹中运行以下命令行指令:

docker-compose up

这将启动所有带有日志的 docker 容器。我们应该在控制台中看到类似这样的内容:

步骤 2:构建和部署微服务

我们将 REST 协议用于我们的 web 服务。我们将使用 NLTK 的Vader算法进行情感分析。这是一个预先训练好的模型,所以我们只能关注预测部分:

[@app](http://twitter.com/app).route('/predict', methods=['POST'])
def predict():
    result = sid.polarity_scores(request.get_json()['data'])
    return jsonify(result)

我们正在创建一个接收到形式为{"data": "some text"}JSON消息的POST请求,其中字段data包含一个句子。我们将应用该算法,并将响应作为另一个JSON发送回去。

要运行该应用程序,只需运行:

python app.py

休息服务将在[http://127.0.0.1:9000/predict](http://127.0.0.1:9000/predict)开始。

步骤 3:使用 Kafka 依赖项启动 pySpark

在我们启动 Jupyter 实验室笔记本之后,我们需要确保我们拥有 kafka jar 作为 spark 的依赖项,以便能够运行代码。在笔记本的第一个单元格中添加以下内容:

import os
os.environ['PYSPARK_SUBMIT_ARGS'] = "--packages=org.apache.spark:spark-sql-kafka-0-10_2.11:2.4.4 pyspark-shell"

接下来,我们可以使用findspark包启动 pySpark:

import findspark
findspark.init()

第四步:运行卡夫卡制作程序

为了能够实时消费数据,我们首先必须将一些消息写入 kafka。我们将使用 python 中的confluent_kafka库来编写一个生产者:

我们将发送与之前相同的JSON消息{"data": value},其中 value 是预定义列表中的一个句子。对于我们写入队列的每条消息,我们还需要分配一个键。我们将根据uuid随机分配一个,以实现集群中的良好分布。最后,我们还运行一个flush命令来确保所有的消息都被发送。

一旦我们运行了confluent_kafka_producer,我们应该会收到一个日志,告诉我们数据已经正确发送:

we’ve sent 6 messages to 127.0.0.1:9092

第五步:开始从卡夫卡那里读取数据

如前所述,我们将使用 Spark 结构化流来实时处理数据。这是一个易于使用的 API,将微批量数据视为数据帧。我们首先需要将输入数据读入数据帧:

df_raw = spark \
  .readStream \
  .format('kafka') \
  .option('kafka.bootstrap.servers', bootstrap_servers) \
  .option("startingOffsets", "earliest") \
  .option('subscribe', topic) \
  .load()

startingOffsetearliest,表示每次运行代码时,我们将读取队列中的所有数据。

该输入将包含不同的列,表示 kafka 的不同度量,如键、值、偏移量等。我们只对值、实际数据感兴趣,我们可以运行一个转换来反映这一点:

df_json = df_raw.selectExpr('CAST(value AS STRING) as json')

步骤 6:创建一个应用 ML 模型的 UDF

在结构化流中,我们可以使用用户定义的函数,这些函数可以应用于数据帧中的每一行。

def apply_sentiment_analysis(data):
    import requests
    import json

    result = requests.post('[http://localhost:9000/predict'](http://localhost:9000/predict'), json=json.loads(data))
    return json.dumps(result.json())

我们需要在函数中进行导入,因为这是一段可以分布在多台机器上的代码。我们向端点发送请求并返回响应。

vader_udf = udf(lambda data: apply_sentiment_analysis(data), StringType())

我们将调用我们的 udf 为vader_udf,它将返回一个新的字符串列。

步骤 7:应用 vader udf

在这最后一步,我们将看到我们的结果。输入数据的格式在JSON中,我们可以将其转换成一个字符串。为此,我们将使用助手函数from_json。我们可以对情绪分析算法的输出列做同样的事情,它也有JSON格式:

我们可以在控制台中显示我们的结果。因为我们正在使用笔记本,你将只能从你在 Jupyter 启动的终端上看到它。命令trigger(once=True)将只运行一小段时间的流处理并显示输出。

这就是它的乡亲,我希望你喜欢这个教程,并发现它有用。我们看到了如何通过使用结构化流 API 和调用 ML 模型的微服务,我们可以构建一个强大的模式,它可以成为我们下一个实时应用的主干。

构建推荐引擎在 Spark 中推荐图书

原文:https://towardsdatascience.com/building-a-recommendation-engine-to-recommend-books-in-spark-f09334d47d67?source=collection_archive---------21-----------------------

使用协同过滤来预测未读书籍在“好阅读”上的评级

沃伦·巴菲特曾被问及成功的关键,他指着旁边的一摞书说:“每天像这样读 500 页。知识就是这样运作的。它就像复利一样累积起来。你们所有人都可以做到,但我保证你们中没有多少人会去做

书籍是我们大多数人发展和获得观点的最佳资源。我本人喜欢读书。一旦我喜欢上了一本书,我就有一个习惯,那就是去找好书,或者请有类似品味的人给我推荐下一系列我可能会喜欢的书。

人工智能通过根据过去的数据向我们推荐书籍、电影和产品,节省了我们分析不同选项的时间和精力,从而使我们的世界变得如此简单。事实上,有时机器可以比我们想象的更好地推荐我们,因为它们不会受到情绪偏见的影响。

在这篇博客中,我将解释我是如何使用“好书”数据在 Spark 中构建推荐引擎的。我使用了 Spark 库中的交替最小二乘(ALS)算法,这基本上是网飞竞赛获奖者发表的论文的实现。在深入研究实现之前,让我先解释一下 ALS 算法。

如果你想直接进入“好书”的问题,请跳过这一部分。

交替最小二乘法背后的直觉

对于喜欢阅读学术论文的人来说,下面是论文的链接:https://data jobs . com/data-science-repo/Recommender-Systems-% 5 bnet flix % 5d . pdf

要了解不同类型的推荐系统,请访问我的其他博客,在那里我解释了不同类型的推荐系统,如基于内容、基于元数据和基于协同过滤的方法。以下是这些系列博客的链接:https://medium . com/analytics-vid hya/the-world-of-recommender-systems-e4ea 504341 AC?source = friends _ link&sk = 508 a 980d 8391 DAA 93530 a 32 e 9 c 927 a 87

基本上,基于内容的推荐系统就是根据以前产品的内容来推荐一些产品。如果你读了一本名为《思考致富》的书,你会被推荐其他有类似内容(或文本)的书,比如《唤醒内心的巨人》,因为它们都是自助书籍,可能包含类似的内容。

最重要的一种推荐系统是基于协同过滤的方法。假设你认识一个和你品味相同的朋友,因为你们都热爱心理学,那么你可能会喜欢读其他你朋友读过但你没有读过的书。这是协同过滤背后的唯一概念。现在我们具体说说交替最小二乘法

协同过滤可以通过矩阵分解技术轻松实现,如奇异值分解,其中用户评级矩阵被分解为用户概念矩阵、概念权重矩阵和评级概念矩阵。概念基本上是矩阵分解隐式生成的潜在或隐藏的因素,就像在书籍的情况下,不同的概念可以是心理学、数据科学、哲学等。

对于任何给定的项目,仅仅一个基本的点积就可以给出一个等级,但是这种方法有一个问题。

大多数矩阵分解技术,如奇异值分解,不知道如何处理不完整/稀疏矩阵,这意味着用户评级矩阵中有空值(这很常见,因为不是每个用户都读过所有的书)。传统上,工程师们在执行矩阵分解以进行协同过滤之前,一直用平均值或中值来输入这些值。这导致了过度拟合,因为从未被评级的书籍被均值或中值估算,这可能会使结果偏向它们。

最近的方法,如交替最小二乘法没有这些缺点。他们建议直接对观察到的评级进行建模,同时避免通过正则化模型进行过度拟合。为了学习因子向量(pu 和 qi),系统最小化已知评级集合上的正则化平方误差:

他们基本上试图像梯度下降一样将误差最小化。在上面的等式中,直觉是 r 是给定的评级,qi*pu 基本上是预测评级的矩阵(SVD 的结果)的点积,我们试图将其最小化,但最小化上面的等式还有另一个挑战。有两个未知数要最小化,所以这不是一个导致全局最小值的凸优化问题。

ALS 纠正了这个问题,同时也提供了一些其他的好处。ALS 技术在固定 qi 和固定 pu 之间轮换。当所有 pu 被固定时,系统通过解决最小二乘问题重新计算 qi,反之亦然。这确保了每一步都减少上述方程,直到收敛。这可能会导致算法的大规模并行化,因此可以在 Spark 中轻松实现。现在,让我们来谈谈好书的问题。

“好书”推荐系统

“好书”数据集包含了来自 T2 10000 本不同书籍的大约 100 万个评分。在大多数情况下,每个用户至少给10 本书打分,分数在 0 到 5 之间。我们将使用这 100 万个评分来预测所有其他没有被用户阅读的书籍的评分。此外,还有一个“to_read”数据集,其中包含用户保留以供未来阅读的书籍的详细信息(如 wishlist)。在建立我们的推荐系统后,我们将尝试预测这些“值得阅读”的书籍的评级,以了解我们的算法在这些书籍上的表现。因为用户已经希望阅读这些书籍,所以对这些要阅读的书籍的预测评级应该很高。

以下是数据集的链接:

[## goodbooks-10k

一万本书,一百万收视率。还有标着要读的书,还有标签。

www.kaggle.com](https://www.kaggle.com/zygmunt/goodbooks-10k?select=sample_book.xml)

我将使用‘data bricks’社区版,因为它是在 spark 上运行 ML 的最佳平台,而且是免费的。

让我们看看收视率和书籍的数据框架。“评级”数据包含 book_id、user_id 和评级。图书数据集类似于所有 10000 本图书的元数据,包含图书名称、评级数量、book_id 和图书封面图像的 URL。我发现把书的封面印在“熊猫”数据框里很有趣。

评级数据集

图书数据集

因为我喜欢看书,所以我对这些书做了一些调查,根据它们的出版年份来了解这些书有多老,它们的平均评级是多少,哪些书的评级最高,哪些书的评论数量最多。

我看到《基督之前》中的一些书也和这本一样。吉尔伽美什的这部史诗出版的年份是公元前 1750 年。有意思。不是吗?

公元前 1750 年出版的书

我们来看看 1950 年以后的图书出版数量分布。

%sqlselect original_publication_year, count(*) as count from books where original_publication_year > 1950 group by original_publication_year

出版书籍数量的分布

1990 年后,每年似乎有 100 本书,然后每年都在增加,直到达到顶峰。

来看看收视率最多的书。

 most_ratings = books_df.sort_values(by = ‘ratings_count’, ascending = False)[[‘original_title’,’ratings_count’, ‘average_rating’, ‘image_url’ ]][0:10]import pandas as pd
from IPython.display import Image, HTML
most_ratings[‘img_html’] = most_ratings[‘image_url’]\
 .str.replace(
 ‘(.*)’, 
 ‘<img src=”\\1" style=”max-height:124px;”></img>’
 )
with pd.option_context(‘display.max_colwidth’, 10000):

 display(HTML(most_ratings[[‘original_title’, ‘img_html’, ‘ratings_count’, ‘average_rating’ ]].to_html(escape=False)))

我们可以看到,收视率最高的书籍是《饥饿游戏》、《哈利·波特》等名著。

现在,让书籍按平均评分排名(不考虑评分的数量)。

high_rating_books = books_df.sort_values(by = ‘average_rating’, ascending = False)[[‘original_title’,’ratings_count’,’image_url’, ‘average_rating’ ]][0:10]high_rating_books[‘img_html’] = high_rating_books[‘image_url’]\
 .str.replace(
 ‘(.*)’, 
 ‘<img src=”\\1" style=”max-height:124px;”></img>’
 )
with pd.option_context(‘display.max_colwidth’, 10000):

 display(HTML(high_rating_books[[‘original_title’, ‘img_html’,’ratings_count’, ‘average_rating’ ]].to_html(escape=False)))

嗯,《加尔文与霍布斯全集》和《光辉之言》在 10000 本书中平均收视率最高。

来看看出书数量最多的作者:

authors_with_most_books = pd.DataFrame(books_df.authors.value_counts()[0:10]).reset_index()
authors_with_most_books.columns = [‘author’, ‘number_of_books’]

在数据集中,斯蒂芬·金有 60 本书是以他的名字命名的。

现在,让我们看看所有 10000 本书的平均评分分布:

import matplotlib.pyplot as plt
plt.figure(figsize=(12,6))
plt.title(‘Distribution of Average Ratings’)
books_df[‘average_rating’].hist()
displaay()

在评级“数据框架”中,大约有 100 万个评级,每本书大约有 100 个评级,这是一个非常公正的数据集。评分低于 100 的书很少。

现在,让我们看看用户评级矩阵的稀疏性,以了解如果我们不使用 ALS 而使用传统的 SVD 进行协同过滤,会产生多少偏差。

# Count the total number of ratings in the dataset
numerator = ratings.select(“rating”).count()# Count the number of distinct Id’s
num_users = ratings.select(“user_id”).distinct().count()
num_items = ratings.select(“book_id”).distinct().count()# Set the denominator equal to the number of users multiplied by the number of items
denominator = num_users * num_items# Divide the numerator by the denominator
sparsity = (1.0 — (numerator * 1.0)/ denominator) * 100
print(“The ratings dataframe is “, “%.2f” % sparsity + “% empty.”)

评级数据框 99.82%为空。

当然,不可能每个用户都给所有的书评分,因此最好只在原始评分的基础上建立一个算法。进入 ALS 世界。

算法-实现

现在,让我们数据分割成训练集和测试集,使用交替最小二乘法进行协同过滤。

(training, test) = ratings.randomSplit([0.8, 0.2])

让我们导入 ALS 和回归评估器来查找 RMSE。

from pyspark.ml.evaluation import RegressionEvaluator
from pyspark.ml.recommendation import ALS
from pyspark.sql import Rowals = ALS( userCol=”user_id”, itemCol=”book_id”, ratingCol=”rating”,
 coldStartStrategy=”drop”, nonnegative = True, implicitPrefs = False)

implicitPrefs '参数在我们不使用像评级数据这样的显式数据时使用。有时,公司没有明确的数据,如评分,但仍然希望使用其他代理,如视图、点击、意愿列表等来构建推荐引擎。在这种情况下,使用了隐式偏好,但这超出了我们好书项目的范围。当我们没有用户的任何数据时使用 coldStartStrategy ,如果测试集上的用户在训练集中没有评级,这可能导致零预测。我们已经放弃了冷启动策略,因为我们想为我们手头的问题避免这种情况。

现在,让我们建立我们的超参数列表,然后在训练数据上拟合算法。

from pyspark.ml.tuning import ParamGridBuilder, CrossValidatorparam_grid = ParamGridBuilder() \
 .addGrid(als.rank, [10, 50, 75, 100]) \
 .addGrid(als.maxIter, [5, 50, 75, 100]) \
 .addGrid(als.regParam, [.01, .05, .1, .15]) \
 .build()# Define evaluator as RMSE
evaluator = RegressionEvaluator(metricName = “rmse”, 
 labelCol = “rating”, 
 predictionCol = “prediction”)
# Print length of evaluator
print (“Num models to be tested using param_grid: “, len(param_grid))

使用 param_grid 测试的模型数量:64

总共有 64 款车型将在我们收到最终车型之前进行测试和调试。并行化和 spark 的力量将使它变得非常快。

# Build cross validation using CrossValidator
cv = CrossValidator(estimator = als, 
 estimatorParamMaps = param_grid, 
 evaluator = evaluator, 
 numFolds = 5)model = als.fit(training)predictions = model.transform(test)predictions.show(n = 10)

测试集上的预测表明,它非常接近原始评级。例如,user_id 14372 的评分最初是 3,我们的算法预测它是 3.13,这非常接近。

rmse = evaluator.evaluate(predictions)
print(“Root-mean-square error = “ + str(rmse))

均方根误差= 0.913,平均误差为 0.9,即原始评级和预测评级之间的差值。现在,让我们为每个用户预测 10 本书和评级。

# Generate n recommendations for all users
ALS_recommendations = model.recommendForAllUsers(numItems = 10) # n — 10ALS_recommendations.show(n = 10)
# Temporary table
ALS_recommendations.registerTempTable("ALS_recs_temp")clean_recs = spark.sql("""SELECT user_id,
                            movieIds_and_ratings.book_id AS book_id,
                            movieIds_and_ratings.rating AS prediction
                        FROM ALS_recs_temp
                        LATERAL VIEW explode(recommendations) exploded_table
                            AS movieIds_and_ratings""")
clean_recs.show()
# Recommendations for unread books
(clean_recs.join(ratings, ["user_id", "book_id"], "left")
    .filter(ratings.rating.isNull()).show())new_books = (clean_recs.join(ratings, ["user_id", "book_id"], "left")
    .filter(ratings.rating.isNull()))

为每个用户推荐 10 本书。

现在,让我们使用'来 _read '数据(愿望列表数据),看看我们的算法会为愿望列表中的书预测什么。

这应该是非常好的,因为用户把它们保存在他们的愿望清单中。

recommendations = new_books.join(to_read,
 on = [“user_id”, “book_id”], 
 how = “inner”)
print(recommendations.show())(recommendations
     .withColumn('pred_trunc', recommendations.prediction.substr(1,1))
     .groupby('pred_trunc')
     .count()
     .sort('pred_trunc')
    .show())import matplotlib.pyplot as plt
plt.figure(figsize=(12,6))
plt.title('Most of the predicted ratings are above 3.8', fontsize = 12)
plt.suptitle('Distribution of predictedd ratings for the to_do lists', fontsize = 18)
rec = recommendations.toPandas()
rec['prediction'].hist()
display()

愿望清单中的大多数书籍都被预测为预期的 4.5 或更高版本。

你可以在这里访问我的代码:-

https://github.com/garodisk/Goodreads-recommendation-engine

非常感谢你的阅读!

参考文献:

[## goodbooks-10k

一万本书,一百万收视率。还有标着要读的书,还有标签。

www.kaggle.com](https://www.kaggle.com/zygmunt/goodbooks-10k?select=sample_book.xml) [## 协同过滤

协同过滤通常用于推荐系统。这些技术旨在填补缺失的条目…

spark.apache.org](https://spark.apache.org/docs/2.2.0/ml-collaborative-filtering.html)

我的其他数据科学博客:-

语境多臂大盗——(网飞作品推荐背后的直觉)

https://medium . com/analytics-vid hya/contextual-multi-armed-bandit-直觉-背后-网飞-艺术品-推荐-b221a983c1cb?source = friends _ link&sk = 732 f 4 e 74 afce 45 c 184 dedc 7 c 817 de 844

用统计学家的大脑赌博。

[## 用统计学家的大脑赌博。

用蒙特卡罗模拟法分析赌场的胜算

medium.com](https://medium.com/analytics-vidhya/gambling-with-a-statisticians-brain-ae4e0b854ca2)

使用 Spark 对 Instacart 的 300 万份订单进行购物篮分析

https://medium . com/analytics-vid hya/market-basket-analysis-on-300 万-orders-from-insta cart-using-spark-24c 6469 a92e?source = friends _ link&sk = ad 580 EFA 7c 7697 b 731 EB 36 DD 2c 33 ad 82

使用 Slash GraphQL 构建推荐引擎—第 2 部分

原文:https://towardsdatascience.com/building-a-recommendation-engine-using-slash-graphql-part-2-c19e64659af4?source=collection_archive---------52-----------------------

【TL;DR:在本系列的第二部分,我微调了最初的推荐引擎,添加了一个辅助数据源,并编写了一个 Angular 客户端来消费数据。]

“使用 Spring Boot 和斜杠 GraphQL 构建推荐引擎”的文章中,最近发布的由 Dgraph 托管的斜杠 GraphQL 后端被用作基于 Java 的推荐引擎的记录系统。图形数据存储非常适合推荐引擎这样的用例,其中数据之间的关系与数据本身一样重要。使用 Slash GraphQL 允许我以最少的努力快速建立并运行一个完全托管的 GraphQL 数据库。

这篇文章还提供了关于如何利用 Slope One 系列的协同过滤算法,根据现有的评级来预测产品兴趣水平的见解。简而言之,Slope One 评级算法将是推荐引擎的核心。

文章最后通过在 Spring Boot 推荐引擎中提供 RESTful URIs 来提供来自存储在 Dgraph Slash GraphQL SaaS 服务产品中的数据的推荐。

本文将更进一步,介绍一个 Angular 客户端,以一种更容易使用的方式呈现这些数据……并希望得到赞赏。

Data Domain 的增强功能

虽然最初的文章展示了推荐引擎是如何工作的,但我觉得我的原始数据样本为一些样本客户提供了太多的评级。此外,我觉得我需要为第二个例子增加艺术家的数量。

因此,我清除了现有 Slash GraphQL 数据库中的数据,并重新开始。虽然它很容易更新,但在本练习中,底层模式不必更改,仍然如下所示:

type Artist {
   name: String! @id @search(by: [hash, regexp])
   ratings: [Rating] @hasInverse(field: about)
}type Customer {
   username: String! @id @search(by: [hash, regexp])
   ratings: [Rating] @hasInverse(field: by)
}type Rating {
   id: ID!
   about: Artist!
   by: Customer!
   score: Int @search
}

使用斜线 GraphQL 用户界面中的以下变化添加了新的Artist项目列表:

mutation {
 addArtist(input: [
   {name: "Eric Johnson"},
   {name: "Genesis"},
   {name: "Journey"},
   {name: "Led Zeppelin"},
   {name: "Night Ranger"},
   {name: "Rush"},
   {name: "Tool"},
   {name: "Triumph"},
   {name: "Van Halen"},
   {name: "Yes"}]) {
   artist {
     name
   }
 }
}

更新的Customer记录也被插入:

mutation {
 addCustomer(input: [
   {username: "David"},
   {username: "Doug"},
   {username: "Jeff"},
   {username: "John"},
   {username: "Russell"},
   {username: "Stacy"}]) {
   customer {
     username
   }
 }

使用与原始文章相同的突变,根据下表添加评级:

作者图片

H2(内存中)数据库简介

在第二篇文章中,我想介绍一个额外的数据源。这样做可以突出信息和事实通常来自多个数据源的事实。我决定使用H2——一个开源的、轻量级的内存 Java 数据库。使用以下 Maven 依赖项,可以快速轻松地将 H2 数据库添加到 Spring Boot:

<dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <scope>runtime</scope>
</dependency>

H2 数据库将为存储在 Slash GraphQL 中的Artist记录提供附加信息。这些记录将被存储在一个名为Artists的表中,主键就是Artist的名字:

@Data
@Entity
@Table(name = "artists")public class Artist {
   @Id
   private String name;
   private String yearFormed;
   private boolean active;
   private String imageUrl;
}

一个包含该表信息的data.sql文件被创建并存储在 Spring Boot 存储库的 resources 文件夹中。因此,每次服务器启动时,都会填充 H2 数据库。

发展推荐引擎

为了在推荐引擎中看到价值,引擎提供的结果需要包括关于推荐的所有必要信息。为了满足这一需求,响应中建议的有效负载被更新为包含更多的Artist属性,如下所示:

{
   "matchedCustomer": {
       "username": string
   }, "recommendations": [
       {
           "name": string,
           "yearFormed": string,
           "active": boolean,
           "imageUrl": string,
           "rating": number,
           "score": number
       } ...
   ]
}

推荐引擎需要增强以接受两种额外形式的元数据:

  • 当前选择的艺术家
  • 当前客户

通过知道当前选择的艺术家,推荐引擎将知道排除对同一艺术家的任何推荐。此外,了解当前客户的能力避免了简单地随机挑选客户的需要。

介绍 Angular 客户端

为了快速创建客户端,我决定使用 Angular CLI 。Angular CLI 是一个命令行界面,允许您快速轻松地创建和细分组件、服务和基本功能,允许开发人员专注于编写业务逻辑以满足他们当前的需求。对我的技能来说,这是一个理想的选择。

在很短的时间内,我能够使用 Angular CLI 介绍以下项目:

  • 与 Spring Boot 的艺术家、客户和推荐对象相关的服务
  • list-artists 组件提供艺术家的简单列表
  • view-artist 组件显示对活动客户和艺术家的推荐

因为有一个强大的 Angular 和npm社区,我甚至能够通过几个命令和基本的配置更改,使用 angular-star-rating 和 css-star-rating 包来包含一个图形化的星级评定解决方案。当然, @ng-bootstrap 和 bootstrap 包也包括在内,这使得造型看起来更像样一些。

使用 Angular 客户端

配置好 Angular 客户端并运行 Spring Boot 推荐引擎后,可以使用以下 URL 来启动应用程序:

[http://localhost:4200](http://localhost:4200)

当应用程序加载时,将显示以下屏幕:

作者图片

该列表(来自列表艺术家组件)提供了来自 H2 数据库的信息和来自 Dgraph Slash GraphQL 数据库的平均评级。

单击 Rush 条目将调用 view-artist 组件,并显示如下所示的信息:

作者图片

在这种情况下,我选择 Russell 作为当前客户。在屏幕的顶部,显示了相同的信息,并且在右侧显示了乐队的图像。下面是来自 Spring Boot 服务中推荐 API 的信息。

结果迎合了名为 Russell 的客户,并有意避免为名为 Rush 的乐队做推荐。

如果客户更改为 Stacy,相同的屏幕会更新,如下所示:

作者图片

虽然屏幕上半部分的数据保持不变,但推荐部分完全不同,并迎合了新选择的用户。

结论

在本文中,推荐引擎被连接到一个客户端应用程序,并被进一步优化以提供比原始文章更多的价值。

虽然这个例子的设计非常简单,但是所采用的概念和方法可以被合并到一个功能完整的推荐引擎中。

使用 Dgraph 的斜线 GraphQL 和 Spring Boot 当然有助于非常短的上市时间。它们使得基于经验教训的原型设计、分析和采用新设计变得容易。

对于那些对完整源代码感兴趣的人,请查看斜线-图形-ql-angular GitLab 资源库

(经原作者许可发表,约翰·维斯特)

构建动漫推荐系统

原文:https://towardsdatascience.com/building-a-recommendation-system-for-anime-566f864acea8?source=collection_archive---------31-----------------------

我已经决定做一个简单的动漫推荐系统。

背景资料

动漫是一种源自日本的手绘电脑动画,在世界各地吸引了大批追随者。动画产业由 430 多家公司组成。口袋妖怪和游戏王是西方电视上最受欢迎的动漫节目。由宫崎骏创作并由吉卜力工作室制作动画的《千与千寻》是动画电影中票房最高的一部。它在西方如此受欢迎的原因是宫崎骏的一个好朋友说服他将发行权卖给华特·迪士尼。像千与千寻,有数以千计的真正好的动画电影和节目是由同一家动画公司制作的。许多其他人可以以此为例,将其作为将此类艺术作品引入迪士尼+或西方任何流媒体网站的一种方式。这让我想到了我最近一直在做的事情:一个可以帮助任何人或任何公司查看/添加最高评级动漫的推荐系统。日本贸易振兴机构估计,2004 年该行业的海外销售额为 18 𝑏𝑖𝑙𝑙𝑖𝑜𝑛(仅美国就达 52 亿英镑)。这肯定已经增长,并有潜力进一步增长,尤其是在这个世界上的这段时间。像一些国家一样,日本正面临第一次长期衰退。

下面,你可以看到我对一个动漫推荐系统的逐步指导。这将有助于解决上述问题,并可以创造更多的需求动漫。它还可以帮助任何不熟悉小众流派的人快速找到收视率最高的项目。(帮助发展市场)。

我已经从https://www . ka ggle . com/Cooper union/anime-recommendations-database下载了动漫和用户评分。我将进行探索性的数据分析,让读者和我自己熟悉所呈现的数据。在那里,我使用奇异值分解(SVD)创建了一个基线模型。然后,我会做基于记忆的模型,将着眼于基于用户的 v 项目。我将使用 KNNBase、KNNBaseline 和 KNNWithMeans。然后我会选择表现最好的模型,评估其均方根误差(rmse)和平均绝对误差(mae)。

导入

import pandas as pd
import numpy as npimport random
from random import randintimport matplotlib.pyplot as plt
%matplotlib inline
import seaborn as snsfrom scipy.sparse import csc_matrix
from scipy.sparse.linalg import svdsfrom surprise.model_selection import train_test_splitfrom surprise.model_selection import GridSearchCV
from surprise.model_selection import cross_validatefrom surprise.prediction_algorithms import KNNWithMeans, KNNBasic, KNNBaselinefrom surprise.prediction_algorithms import knns
from surprise.prediction_algorithms import SVDfrom surprise.similarities import cosine, msd, pearsonfrom surprise import accuracyfrom surprise import Reader
from surprise import Dataset

在这个项目的大部分时间里,我决定坚持上面的方法,而且效果很好。我已经在 google colab 中尝试了下面的其他模型,我将在那里为导入库添加必要的代码。

擦洗/清洁

anime_df = pd.read_csv('./anime.csv')
anime_df.head()

形状看起来像什么?这很重要,因为它有助于查看任何空值

anime_df.shape

删除空值(如果存在)

anime_df.dropna(inplace=True)

我们将再次检查上述命令后的形状

anime_df.shape #this seemed to have reduced it down a bit

这实际上减少了我们的动漫数据框架!

在清理时,显示每一列代表什么是很重要的,这样我们就可以知道什么可以擦洗、转换,或者我们是否需要进行一些功能工程。

每列代表什么:

anime_id:每部动漫的 id 号片名
名称:电影片名
类型:类别
类型:描述动漫分成电视、电影、OVA 等 3 个类别
集数:总集数
评分:-1-10,最低到

接下来,它们和上面的匹配吗?

anime_df.info() #having a look at all of the columns and types from the above cell and current to remove#any unneccessary extraneous data

让我们看看这个推荐项目的第二个 csv 文件。

rating_df = pd.read_csv('./rating.csv')
rating_df.head()

让我们看看他们代表了什么。

每列代表什么:

user_id:不可识别的随机生成的 user-id
anime_id:用户已评级的动漫
评级:该用户已分配的 10 分中的评级(如果用户观看了该动漫但未分配评级,则为-1)

检查评级的形状

rating_df.shape

都有 anime_id。让我们将这两者结合起来,使事情变得容易得多。

df_merge = pd.merge(anime_df, rating_df, on = 'anime_id')
df_merge.head()

让我们再次检查形状。

df_merge.shape

我艰难地认识到奇异值分解(SVD)对如此大的数据集更敏感。我要看看最低评级。

df_merge.rating_x.min()

我已经决定去掉没有评级的列,它们表示为-1。在做推荐系统时,这取决于个人、任务和公司。我可能会在我的业余时间回去,把这个加回来,看看未完成的评级和它对推荐的影响。(确实起了巨大的作用)。我决定把它拿出来纯粹是为了娱乐。

df_merge = df_merge[df_merge.rating_y != -1]
df_merge.head()

现在,我再次检查形状,看看这减少了多少 SVD 数据。

df_merge.shape #have removed over 1 million rows

这对于免费的 google colab 来说仍然不够小。

sample = df_merge.sample(frac=.25)
sample.shape # this is still too large

我在我的 SVD 上运行了很多测试(这花了一天半的时间,我最终不得不满足于下面的样本大小)。

sample = df_merge.sample(n=5000)sample.shape #below I conduct SVD and it cannot handle anything larger than 5000 (i've tried)

让我们看看数据类型

sample.dtypes #rating_x needs to be an int, for it to work in ALS

让我们在这里转换它们

sample['rating_x'] = sample['rating_x'].astype(int)

可以在这里检查数据类型。从一开始,我就发现检查我的代码是非常重要的。当有调试问题时,它对消除问题很有帮助。

sample.dtypes

看起来评级数据框架是基于每个用户和他们对每个动画 id 的个人评级,而动画数据框架是来自其所有观众的平均总体评级。

#we are going to look at how many times each rating appears in a columnratings_x = sample['rating_x'].value_counts() #continuous
ratings_y = sample['rating_y'].value_counts() #discreteprint(ratings_x)
print(ratings_y)

另一件对 SVD 来说非常重要的事情是让变量变得谨慎,否则,它会占用你更多的时间。

sample.rating_x = sample.rating_x.apply(round) 
sample.head()

太好了,我想我已经洗完了。让我们进入有趣的部分!

探索性数据分析

用户评级的分布

# plot distribution in matplotlib
ratings_sorted = sorted(list(zip(ratings_y.index, ratings_y)))
plt.bar([r[0] for r in ratings_sorted], [r[1] for r in ratings_sorted], color='cyan')
plt.xlabel("Rating")
plt.ylabel("# of Ratings")
plt.title("Distribution of Ratings")
plt.show()

我还没有把输出添加到清洗中,视觉效果非常重要,所以我会把它们添加进去。

这是我自己的图表,也可以在我的 github 上找到

#number of users
print("Number of Users:", df_merge.user_id.nunique()# print("Average Number of Reviews per User:", df_merge.shape[0])/df_merge.user_id.nunique()avg_rate_peruser = df_merge.shape[0]user = df_merge.user_id.nunique()
avg_num_review_per_user = avg_rate_peruser/userprint("Average Number of Reveiws per User:", avg_num_review_per_user)

用户数量:15382

每个用户的平均评论数:88.69

sample[‘user_id’].value_counts()

5000 的样本量,给了我们总共 3,381 个做过评论的用户。以上是整套的。

每个用户的评论数量

ratings_per_user = sample['user_id'].value_counts()
ratings_per_user = sorted(list(zip(ratings_per_user.index, ratings_per_user)))
plt.bar([r[0] for r in ratings_per_user], [r[1] for r in ratings_per_user], color='pink')
plt.xlabel('User IDs')
plt.ylabel('# of Reviews')
plt.title('Number of Reviews per User')
plt.show()

这是我自己的图表,也可以在我的 github 上找到

从我们的样本集来看,给出的很多分数都是 1 分和 2-4 分。

不同类型的动漫

print("Number of users:", sample.user_id.nunique())
print("Number of types of different anime:", sample.type.nunique())
print("Types of type:", sample.type.value_counts())

由此,我们可以看到有 6 种类型。它们是什么?

6 种类型:

TV 3492 
Movie 666
OVA 461
Special 314 
ONA 46 
Music 21 
Name: type, dtype: int64

OVA 代表原创视频动画

ONA 代表原创网络动画

特价是一次性的视频。

音乐是以动漫为主题的,通常有一个动画与之搭配,但它通常是一个非常短的视频。

点击率最高的动漫

# PLOT them
fig = plt.figure(figsize=(12,10))
sns.countplot(sample['type'], palette='gist_rainbow')
plt.title("Most Viewed Anime", fontsize=20)
plt.xlabel("Types", fontsize=20)
plt.ylabel("Number of Views with Reviews", fontsize = 20)
plt.legend(sample['type'])
plt.show()

这是我自己的图表,也可以在我的 github 上找到

让我们开始实施吧!

分析

最重要的是第一件事!做一个基础模型。我从转换我的数据开始。

#for surprise, it likes its data in a certain way and only that specific datadata = sample[['user_id', 'anime_id', 'rating_x']] #may need to do rating_x rounded and then use rating_yreader = Reader(line_format='user item rating', sep='')
anime_loaded_data = Dataset.load_from_df(data, reader)#train_test_split
trainset, testset = train_test_split(anime_loaded_data, test_size=.2)

确保您的数据格式正确

anime_loaded_data

接下来,我们将实例化。

#INSTANTIATE the SVD and fit only the train set
svd = SVD()svd.fit(trainset)

现在来看看预测和准确性。这对于比较您的学员模型非常重要。

predictions = svd.test(testset) #
accuracy.rmse(predictions)

这是我的基线:RMSE: 2.3128,2.3127

嗯,肯定不是 0 到 1 之间。这些分数实际上取决于领域。肯定不完美。我最初的反应是吓坏了,但事实证明 RMSE 超过 1 是没问题的。

我想看看我是否能减少这种情况。

#perform a gridsearch CV
params = {'n_factors': [20,50,100],
'reg_all': [.02,.05, .10]}gridsearch_svd1 = GridSearchCV(SVD, param_grid=params, n_jobs=-1, joblib_verbose=3)gridsearch_svd1.fit(anime_loaded_data)print(gridsearch_svd1.best_score)
print(gridsearch_svd1.best_params)

{'rmse': 2.3178,' Mae ':2.2080 } { ' RMSE ':{ ' n _ factors ':20,' reg_all': 0.02},' mae': {'n_factors': 20,' reg_all': 0.02}}

它增加了。我现在将尝试其他模型,特别是基于内存的模型,然后是基于内容的模型。

k-最近邻(KNN)基本算法

#cross validate with KNNBasic
knn_basic = KNNBasic(sim_options={'name':'pearson', 'user_based':True}, verbose=True)
cv_knn_basic = cross_validate(knn_basic, anime_loaded_data, n_jobs=2)for i in cv_knn_basic.items():print(i)
print('-----------------')
print(np.mean(cv_knn_basic['test_rmse']))

将把你从其余的中拯救出来,这里是输出的一个简短剪辑

— — — — — — — — — 2.3178203641229667

您可以对均方距离(msd)进行同样的操作。

knn_basic_msd = KNNBasic(sim_options = {'name': 'msd', 'user-based':True})
cv_knn_basic_msd = cross_validate(knn_basic_msd, anime_loaded_data, n_jobs=2)for i in cv_knn_basic_msd.items():print(i)
print('-----------------')
print(np.mean(cv_knn_basic_msd['test_rmse']))

— — — — — — 2.31787540672289,得分较高。让我们试试另一个模型

KNNBaseline

#cross validate with KNN Baseline (pearson)
knn_baseline = KNNBaseline(sim_options={'name': 'pearson', 'user_based':True})
cv_knn_baseline = cross_validate(knn_baseline, anime_loaded_data, n_jobs=3)for i in cv_knn_baseline.items():print(i)
print('-----------------')
print(np.mean(cv_knn_baseline['test_rmse']))

— — — — — — — — — 2.317895626569356

同样,当我们希望它减少时,它却在增加。

KNN 基线与皮尔逊 _ 基线

knn_pearson_baseline = KNNBaseline(sim_options={'name': 'pearson_baseline', 'user_based':True})cv_knn_pearson_baseline = cross_validate(knn_pearson_baseline, anime_loaded_data, n_jobs=3)for i in cv_knn_pearson_baseline.items():print(i)
print('-------------------')
print(np.mean(cv_knn_pearson_baseline['test_rmse']))

这给了我们----- 2。46860 . 68868886861

KNNWithMeans

knn_means = KNNWithMeans(sim_options={'name': 'pearson', 'user_based': True})
cv_knn_means = cross_validate(knn_means, anime_loaded_data, n_jobs=3)for i in cv_knn_means.items():print(i)
print('------------')
print(np.mean(cv_knn_means['test_rmse']))

— — — — — — 2.3185632763331805

SVD 基线似乎具有最低的 RMSE。我会再次进行网格搜索

param_grid = {'n_factors': [5, 20, 100],
'n_epochs': [5,10],
'lr_all': [.002, .005],
'reg_all': [.02, .05, .5]}svd_gs = GridSearchCV(SVD, param_grid=param_grid, n_jobs=3, joblib_verbose=3)svd_gs.fit(anime_loaded_data)print(svd_gs.best_score)
print(svd_gs.best_params)

然后

#Now use this to fit test set, initial gridsearch was 2.77096, so will use that gs herehighest_perf_algo = gridsearch_svd1.best_estimator['rmse']#retrain the whole settrainset = anime_loaded_data.build_full_trainset()
highest_perf_algo.fit(trainset)#Biased Accuracy on trainset
predictions = highest_perf_algo.test(trainset.build_testset())print('Biased accuracy on Trainset', end='')
accuracy.rmse(predictions)#UnBiased Accuracy on testset
predictions = highest_perf_algo.test(testset)print('Unbiased Accuracy on test', end='')
accuracy.rmse(predictions)

我的结果是:训练集上的有偏精度 RMSE:2.3179301111112067,测试集上的无偏精度 RMSE:2.317938596

我做了一些合作模型,列在我的 Github repo 上。我的协作模型采用余弦相似度和基于用户的 v 项目。

基于内容

import nltk
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.corpus import stopwords
import string
from nltk import word_tokenize, FreqDist
import re
from sklearn.decomposition import TruncatedSVD
from sklearn.metrics.pairwise import linear_kernel

接下来,让我们提取必填字段。

genre_tag = sample.loc[:, ['anime_id','name','genre']]

让我们看看它是什么样子的

genre_tag.head()

目标是将每行的单词分开。

tags = {}
for col in ['genre']:
  for a_id in sample['name'].unique(): 
    for i in sample[sample['name'] == a_id][col]:
     if a_id in tags: 
       tags[a_id].append(' '.join(i.lower().split('|')))
     else: 
         tags[a_id] = i.lower().split('|')

将此转换成列表

tags_list = list(tags.values())

看看名单

tags_list[:5]

确保指定停用词为英语

stopwords_list = stopwords.words('english')
stopwords_list += list(string.punctuation)

目的是减少产生的噪音。

def process_article(article): 
  article = ' '. join(article)
tokens = word_tokenize(article)
tokens_2 = []
for token in tokens: 
  if token.lower() not in stopwords_list: 
     tokens_2.append(token.lower())
return tokens_2

让我们来处理这篇文章。这将把测试分成基于空格或撇号分隔的字符串列表

processed_tags = list(map(process_article, tags_list))

现在让我们从体裁中获取总词汇量。

articles_concat = []
for doc in processed_tags: 
  articles_concat += doc

每个单词出现多少次?

freqdist = FreqDist(articles_concat)
freqdist

让我们获得前 20 个单词,这将让我们看到最受欢迎的类型

most_common_genre = freqdist.most_common(20)
most_common_genre

让我们画出来

plt.figure(figsize=(22,12))
plt.bar([word[0] for word in most_common_genre], [word[1] for word in most_common_genre])
plt.title("Most Popular Genre", fontsize= 20)
plt.xlabel("Genre", fontsize=20)
plt.ylabel("Total Number of Times Genre is Present in Anime Data", fontsize=20)
plt.show()

这是我自己的图表,也可以在我的 github 上找到

我们的推荐系统可能会推荐喜剧、动作片、爱情片等。

现在,把它转换成矢量器

vectorizer = TfidfVectorizer(analyzer='word', ngram_range=(1,2), stop_words=stopwords_list)tags_list_2 = [‘ ‘.join(x) for x in tags_list]
tf_idf_data_train = vectorizer.fit_transform(tags_list_2)

接下来,让我们看看它如何符合标准。因为 NLTK 是一个完全不同的库,所以最好看看它解释的方差比。

#instantiate SVD
svd = TruncatedSVD(n_components=500, n_iter=7, random_state=42)#fit and transform the vectorized tf-idf matrix
tf_idf_data_train_svd = svd.fit_transform(tf_idf_data_train)

这里我们通过以下方式得到最终结果:

print(svd.explained_variance_ratio_.sum())

0.9962558733287571

在尝试了一堆模式之后,我觉得基于内容的模式是最好的。

在我的笔记本上,我还看着计算动漫和 TF-IDF 的相似度。

更多信息

基于所做的建模,最好是对来自相同动画工作室、作家、导演和媒体公司的收视率最高和收视率最高的动画进行更多的统计分析。从这里,我们可以调整推荐系统,以包括他们的最新发布。

另一个建议是看时间成分分析。电视节目是最受欢迎的动画类型,但是在一年中的什么时候呢?从这里开始,推荐系统可以帮助动画工作室填补财政年度内的空白。他们可以将日期分散开来,或者开辟一条新的渠道来推出更多特价商品。

参考资料:

[1]阿·库雷西,卡普斯顿 e (2020)

[2]苏珊·李, (2018)

[3] Derrick Mwiti,如何用 Python 构建一个简单的推荐系统 (2018)

[4] Robi56,深度学习推荐系统 (2020)

[5] JJ、梅和 RMSE — 哪个指标更好? (2016)

[6]维基百科,动漫 (2020)

[7]维基百科,千与千寻 (2020)

[8]玛丽·马瓦德,冠状病毒:欧洲流媒体服务也在蓬勃发展 (2020)

建立网站规划的推荐系统

原文:https://towardsdatascience.com/building-a-recommendation-system-for-site-planning-e0056b4a64c5?source=collection_archive---------21-----------------------

计算位置间相似性的多元方法

当涉及到场地规划应用时,组织强烈希望将来自不同来源的数据结合起来,这不仅是为了获得特定位置的见解,也是为了比较不同的地理位置,例如,为了找到显示相似特征的位置。

资料来源:CARTO

如果我们的目标是比较两个地理位置,我们可能需要考虑在该位置测量的各种数据点,既有来自“传统”来源(如人口普查)的,也有来自更现代来源的,如移动、金融交易和兴趣点(POI)数据。

在 CARTO,我们开发了一种方法来计算一组目标位置相对于现有站点的相似性得分,这可以证明是站点规划者在考虑开设、迁移或整合其站点网络时的一种重要工具。计算两个位置之间的相似性分数实际上归结为计算每个感兴趣的变量在这些位置的值之间的差异,或者在下文中称为“变量空间中的距离”,与地理距离相对。

为了估计两个位置之间的相似性,我们首先需要定义“位置”的含义。例如,一些数据可能在点一级可用(例如,POI 数据),而其他数据可能已经在空间上聚合(例如,人口普查数据通常在给定的行政单位一级可用),并且不同的数据源可能在不同的空间分辨率下可用。因此,比较不同的位置需要首先定义一个共同的空间支持。例如,我们可以使用一个使用四叉树数据结构构建的规则网格,其中每个网格单元都由一个称为四叉树键(quadtree keys,简称“quadkeys”)的一维位串唯一定义。然后(这是难点),我们需要将每个数据源转换到这个公共空间支持。出于本帖的目的,我们将求助于一个基于面积插值的快速(尽管不是最优)解决方案,它使用原始和公共支持面之间的相交面积作为权重来重新分配数据。

下面的地图显示了美国人口普查中通过面插值转换为四键格网的总人口示例:

资料来源:CARTO

共享工作空间公司基于计算相似性的选址示例

现在,假设您可以访问从我们的数据观测站转换到四键网格的第三方和制图数据,并且您想要使用这些数据计算不同位置(网格点)之间的相似性得分。例如,假设共享工作空间行业的市场领导者希望使用更多数据来推动其快速扩张战略。

假设我们想考虑这家公司在纽约的站点,结合人口统计、财务和 POI 数据来查找在洛杉矶具有相似特征的位置。这种相似性分析的结果将指出他们应该计划开设新空间/重新安置与纽约市目标位置具有相似特征的现有空间的最佳地点。

第一步是选择我们希望包含在分析中的相关变量。这里,我们将使用人口统计、POI 和财务数据的组合。然后,如上所述,目标是计算可变空间中的(一对一)距离:

在选定的原始单元格(I)和每个目标单元格(f)之间,其中索引 j 标识变量类型(例如,总人口)。对于这个用例,这里的目标区域是洛杉矶的整个城市。

虽然这种方法看起来很简单,但是为了正确计算距离,我们需要考虑一些缺点。

当变量有不同的方差时会发生什么?

分析中所选变量的箱线图。注意 y 轴上的对数刻度。来源:CARTO

很明显,在这种情况下,总人口和食物中毒人数中的距离将被赋予不同的权重。为了说明不同的方差,数据被标准化,使得每个变量的均值和单位方差为零。这意味着在计算距离时,所有变量都被赋予相同的权重。

当变量之间存在相关性时会发生什么?

当存在相关变量时,在距离的计算中存在大量冗余信息。通过在距离计算中考虑变量之间的相关性,我们可以消除冗余。为了理解相关性是如何混淆距离计算的,我们可以查看下图,该图显示了一组呈现正相关性的点。

相关性对距离计算影响的示意图。来源:CARTO

观察该图,我们知道蓝点比绿点更有可能与原点的红点属于同一簇,尽管它们与中心的距离相等。很明显,当有相关变量时,我们需要在距离计算中考虑相关性。

本分析中包含的变量的相关矩阵。矩阵中的每个元素代表皮尔逊相关系数,它是两个变量之间线性相关性的度量。来源:CARTO

正如预期的那样,上图显示了我们考虑的一些变量表现出相关性(例如,收入中值与租金中值正相关,所有财务变量彼此之间正相关)。为了考虑相关变量,距离不是在原始变量空间中计算的,而是在变量线性不相关的主成分空间(PCA)中计算的。

简单来说 PCA

主成分分析 (PCA)是一种将高维向量的数据集转换成低维向量的技术。例如,这对于特征提取和降噪是有用的。PCA 找到数据向量的较小维度的线性表示,使得原始数据可以从具有最小平方误差的压缩表示中重构。最流行的 PCA 方法是基于样本协方差矩阵的特征分解

其中 Y 是居中的(逐行零经验平均值)n×d 数据矩阵,其中 d 是数据点的数量,n 是变量的数量。在计算协方差矩阵的特征向量( U )和特征值( D )矩阵后

并按照特征值递减的顺序重新排列它们的列,主分量(PC 或因子)计算如下

其中 P 表示对应于最大 P 个特征值的特征向量,即对应于最大数量的解释方差。然后,原始(居中)数据可以重建为

这里,为了说明保留的 PC 数量的不确定性,我们创建了一个距离计算集合,对于每个集合成员,我们在由分别解释 90%和 100%方差的 PC 数量定义的范围内随机设置保留的 PC 组件的数量。

在缺失数据的情况下,我们如何计算距离?

不幸的是,PCA 对缺失数据不起作用。如果缺失数据是常见的,那么普通的内插或均值插补解决方案并不是一个好主意。

此分析中包含的每个变量的缺失数据部分。资料来源:CARTO

当给定位置的 POI 变量缺失时,我们可以有把握地假设该位置中该变量的 POI 数量为零。另一方面,对于其他变量(如金融变量),我们需要找到一种稳健的方法来处理缺失值。

为了考虑缺失数据,我们在这里使用一种概率方法进行 PCA,称为概率 PCA ,它使用一种迭代程序来交替插入缺失数据并更新不相关的分量,直到收敛。

PPCA 一言以蔽之

在 PPCA,完整数据通过生成潜在变量模型建模,该模型迭代更新预期完整数据对数似然和参数的最大似然估计。PPCA 还具有比 PCA 更快的优点,因为它不需要计算数据协方差矩阵的特征分解。

PCA 也可以被描述为概率潜变量模型的最大似然解,它被称为 PPCA:

随着

假设主分量 Z 和噪声ε都是正态分布的。可以通过使用期望最大化(EM)算法找到模型参数的最大似然(ML)估计来识别模型。EM 是用于学习具有不完全数据的参数的通用框架,其迭代地更新参数的期望完全数据对数似然和最大似然估计。在 PPCA,数据是不完整的,因为没有观察到主要成分 Z 。当缺失数据存在时,在 E-步骤中,根据给定的观察变量,对未观察变量的条件分布进行完全数据对数似然的期望。在这种情况下,更新 EM 规则如下。

电子步骤:

m 步:

其中 PZ* 的每一行仅基于 Z* 的那些列来重新计算,这些列有助于数据矩阵的相应行中的观测值的重建。

到目前为止,我们计算了可变空间中纽约给定共享工作空间位置和洛杉矶目标区域中每个位置之间的距离。然后,我们可以选择距离最短的目标位置作为在洛杉矶开设/搬迁办公室的最佳候选位置。

然而,我们如何知道距离足够小,或者我们如何定义相似性?

为了回答这个问题,我们通过将每个目标位置的得分与平均向量数据的得分进行比较,定义了相似性技能得分(SS)

其中分数仅代表可变空间中的距离,即

如果我们通过系综生成来考虑每个目标位置的距离计算中的不确定性,则每个目标位置的得分变成

其中 K 是系综成员的数量。

  • 当且仅当目标位置比平均向量数据更类似于原点时,技能得分(SS)将为正
  • 在该评分规则下,具有较大 SS 的目标位置将更类似于原点

然后,我们可以按照 SS 的降序对目标位置进行排序,并且只保留满足阈值条件的结果(SS = 1 表示完全匹配或零距离)。有关评分规则的更多信息,请参见费罗(2014)

将这一切结合在一起

下面我们可以看到纽约市两个原点位置的目标区域的相似性技能(SS)得分图,这两个原点位置目前有共享工作区,一个在曼哈顿,一个在布鲁克林。从该图中,我们可以看到,该方法为曼哈顿和布鲁克林办公室选择了不同的目标位置,这反映了起始位置变量之间的差异。特别是,对于曼哈顿办事处,洛杉矶的选定地点集中在贝弗利山和西好莱坞地区,在洛杉矶的所有不同地区中,这些地区在人口统计、金融和 POI 数据方面与曼哈顿最为“相似”。另一方面,根据布鲁克林的 SS 评分规则,被选为最相似的地点更加分散,这表明我们的示例公司在决定开设与布鲁克林具有相似特征的新办事处时,可能会考虑洛杉矶的不同街区。

资料来源:CARTO

本文原载于 CARTO 博客

特别感谢Mamata Akella,CARTO 的制图主管,对她在本帖地图创作中的支持。

用 Spark ML 和 Elasticsearch 构建推荐系统

原文:https://towardsdatascience.com/building-a-recommendation-system-with-spark-ml-and-elasticsearch-abbd0fb59454?source=collection_archive---------10-----------------------

使用交替最小二乘法和余弦相似度的产品推荐

作者图片

在不同产品公司的搜索团队工作时,总是有为用户建立推荐系统的持续需求。我们与流行的搜索引擎如 Elasticsearch、SOLR 建立了合作关系,并试图完善搜索相关性。但是当涉及到搜索相关性和仅仅用搜索引擎创建推荐系统时,总是有一个限制。我总是惊讶于亚马逊和网飞这样的公司根据我们的兴趣提供推荐。因此,通过使用 Apache spark 机器学习功能和 elasticsearch,我们将建立一个推荐系统。

如上图,如果用户 1 喜欢物品 A、物品 B、物品 C,用户 2 喜欢物品 B、物品 C,那么有很大概率用户 2 也喜欢物品 A,可以向用户 2 推荐物品 A。

在推荐系统领域,主要有三种用于提供推荐的技术。

  • 协同过滤
  • 基于内容
  • 混合技术

我们将使用 Pyspark 中的协同过滤技术来创建一个推荐系统。Apache Spark ML 实现了用于协同过滤的交替最小二乘法(ALS ),这是一种非常流行的推荐算法。

ALS 是一种矩阵分解算法,使用交替最小二乘法和加权λ正则化(ALS-WR)。

Spark ALS 的主要问题是,它只会为特定用户(用户-产品模型)推荐顶级产品,为特定产品(产品-用户模型)推荐顶级用户。

计算所有配对的相似性并不是针对大的产品目录。O(n2)组合数量的增长很快导致了代价过高的混洗操作和不可行的计算机时间。为了计算项目-项目相似性,我们使用来自 ALS 模型的项目因素的相似性,使用 spark 和 elasticsearch 建立了项目-项目模型。

ALS 算法本质上分解两个矩阵——一个是用户特征矩阵,另一个是项目特征矩阵。我们正在对项目特征等级矩阵进行余弦相似性运算,以找到项目间的相似性。

关于数据集

数据集主要包含来自 Amazon.com 的两种类型的数据。一个是元数据,它包含产品元数据,另一个是用户各自的不同产品的评级数据。

注:数据集可以从这个 站点 下载。

使用的 spark 版本是 2.4.6,elasticsearch 版本是 7.9.0

工作流程

作者图片

  1. 将产品数据集加载到 Spark 中。
  2. 使用 Spark DataFrame 操作来清理数据集。
  3. 将清理后的数据加载到 Elasticsearch 中。
  4. 使用 Spark MLlib,从评级数据中训练一个协同过滤推荐模型。
  5. 将生成的模型数据保存到 Elasticsearch 中。
  6. 使用弹性搜索查询,生成推荐。

加载数据

以下代码用于读取产品数据,并将其转换为 spark 数据帧。

在 spark 中加载数据后,数据帧如下所示。

作者图片

现在我们需要将产品数据索引到一个 Elasticsearch 索引中。为了将 elasticsearch 与 spark 连接起来,我们需要在类路径中添加一个 JAR 文件,或者将该文件放在 spark 的 jars 文件夹中。JAR 文件需要基于我们现有的 spark 版本下载。

既然已经在 Elasticsearch 中索引了产品元数据,我们需要根据主 id 索引文档的 model_factor 列中每个产品的特征向量。

准备特征向量

特征向量是通过使用 ItemFeatures 矩阵生成的,该矩阵是在我们对用户产品评级数据运行 MLib ALS 算法时生成的。

在 spark 中加载评级数据并转换为数据帧后,将如下所示。

作者图片

在对模型进行评估后,我们得到了一个均方根误差值 RMSE=0.032,这是相当不错的。值越低,模型越好。

现在我们必须将项目向量索引回 Elasticsearch。

现在项目向量已被索引到 elasticsearch,我们需要找到类似的产品。

为了找到两个项目之间的相似性,我们将使用余弦相似性功能。余弦相似性是内积空间的两个非零向量之间相似性的度量,度量它们之间角度的余弦。

作者图片

余弦距离值越小,项目越相似。

我们将使用 elasticsearch 中的 script_score 功能计算产品的相似性得分。余弦相似度函数计算给定查询向量和文档向量之间的余弦相似度。

以下查询已用于从 elasticsearch 获取类似的项目。我们用类别过滤也是为了在类别中得到更好的结果。我们可以根据需要更改过滤器选项。该脚本将余弦相似度加 1.0,以防止分数为负。为了利用脚本优化,提供一个查询向量作为脚本参数。

以下代码已被用于获得类似的产品。我们正在传递产品的 ASIN 和我们想要的产品推荐数量。

display_similar('B001A5HT94', num=5)

这将给出前 5 名产品的结果,这与我们已经通过的产品类似。

作者图片

还不错!结果与我们搜索的产品相似。我们可以随时调整 ALS 算法,以获得更好的性能和精度。

我们也可以采用隐式反馈参数来调整算法。本质上,这种方法不是试图直接对评级矩阵建模,而是将数据视为代表用户行为观察中的强度的数字(如点击次数或购买产品的次数)。

源代码可以在 Github 上找到。

参考

为标记音乐建立推荐系统

原文:https://towardsdatascience.com/building-a-recommender-system-for-tagging-music-cd8457d255cc?source=collection_archive---------22-----------------------

找出哪些标签描述了相似的音乐!

演讲者图像由皮克斯贝拍摄,背景图像由马库斯·斯皮斯克拍摄。

介绍

最近,我在听一个关于音乐行业人工智能的播客。当我们想到人工智能和音乐时,首先想到的通常是音乐分类和生成。然而,在本期播客中,《爱与数据》的亚历克斯·雅各比用一种完全不同的方式让我大吃一惊。和他的团队一起,他开发了一个 ML 模型,让媒体制作者为他们的广告、电影等找到合适的音乐。更有效率。当他们搜索一些关键词时,该模型还会向他们推荐没有任何关键词标记的音乐,但这些关键词与他们搜索的关键词有某种关联。这是天才!

想象一下,你错过了多少机会,查找书籍、学术文献、编程教程或猫视频的“错误”关键词。我觉得它令人惊叹。如果我们这样来看,标签是一种平台设置下,厂商和需求者之间的一种沟通方式。如果我们想在亚马逊上购买新袜子,搜索过程相当简单,因为我们可以口头描述我们感兴趣的对象。然而,在音乐的例子中,我们需要依靠标题和标签来描述我们寻找或提供的产品。因此,好的标签的重要性,即有效的标签将供应商和需求者聚集在一起,怎么强调都不为过!只有两种方法可以改进对带有标签的内容的搜索。

  1. 找到解决不良标签的方法
  2. 寻找使用更好标签的方法

亚历克斯·雅各比的工作是迈向第一步的重要一步。我想向后者迈出一小步,帮助创作者和媒体制作人通过更好的标签找到一起。我想建立一个推荐系统,计算标签之间的相似性,并使用这些来进行推荐。有很多模型是根据单词之间的关系来训练的。这些模型将能够推荐与前一个标签相匹配的标签。但音乐是一种非常特殊的东西,你是否能从博客帖子或聊天上训练的数据集得出好的音乐标记的结论是值得怀疑的。让创作者成为媒体经理要搜索的推荐标签,让媒体经理成为音乐人实际使用的推荐标签,会更有帮助。这是(现在仍然是)这个项目的目标!

我将遵循基于内容的过滤策略,计算标签之间的相似度。图 1 显示了这个项目的基本步骤。一切都将在 Python 中完成。

图 1 —这个项目的 3 个步骤

步骤 1 —收集数据

首先,我需要一个数据集。我真正需要的所有信息是许多音乐片段的标签数组。可能一首歌的标签是 t1 = ["funky "," groove "," guitar "," uplifying "],另一首歌的标签是 t2 = ["kids "," happy "," uplifying ",guitar"]。我的推荐系统应该发现“振奋”和“吉他”在某种意义上是相似的,因为它们经常一起用来描述一首音乐。因此,我想从网上搜集大量曲目的标签列表。我找到了网站www.bensound.com,,它提供免费的电影、商业或博客音乐。图 2 显示了 bensound 主页的外观。有超过 20 页,每一页有 12 个音轨。如果我可以遍历所有页面,打开该页面上的每个轨道并提取其标签,我就有了一个不错的数据集。

图 2-www.bensound.com 主页

[## MaxHilsdorf/music _ tag _ recommender

github.com](https://github.com/MaxHilsdorf/music_tag_recommender/blob/master/webscraping.ipynb)

您可以在这个 github 资源库中找到整个项目的注释 jupyter 笔记本以及所有数据文件。在本文中,我将只使用代码片段。

我用“请求”和 bs4 的“美汤”来刮数据。你将在本章中找到的代码在被解析的网页内容中做了大量的实验。可能有些数字或命令对您来说没有意义,但我希望我的函数的总体结构是清楚的。

首先,我编写了一个函数来获取任何页面上的所有跟踪 URL。

def get_tracks(page_url):

    # Setup soup for main page
    page_r = requests.get(page_url)
    page_soup = BeautifulSoup(page_r.text, "html.parser")
    page_html = page_soup.body.div.find_all("a")

    # Setup empty list and fill it with the URLS
    track_list = []
    for i in range(33,84, 5): # these are the positions where we find the track urls in this case        
        entry = page_html[i]["href"]
        track_list.append(entry)

    return track_list

现在我有了一些 track urls,我需要一个函数来从中提取标签。

def get_tags(track_url):

    # Setup soup for track page
    track_r = requests.get(track_url)
    track_soup = BeautifulSoup(track_r.text, "html.parser")
    taglist_html = track_soup.body.div.find("p", {"class": "taglist"})
    taglist_html = taglist_html.find_all("a")
    taglist = []
    for i in taglist_html:
        for j in i:
            taglist.append(j)          
    return taglist

最后,我结合了上面的两个函数,遍历所有页面并从所有音轨中提取所有标签。幸运的是,不同页面的 url 仅在结尾有所不同:

  1. https://www.bensound.com/royalty-free-music
  2. https://www.bensound.com/royalty-free-music/2
  3. https://www.bensound.com/royalty-free-music/3
  4. […]

这使得遍历所有页面变得更加容易,因为它可以用以下 4 行代码来处理:

url_template = “[https://www.bensound.com/royalty-free-music/{page](https://www.bensound.com/royalty-free-music/{page)}"page_urls = ["[https://www.bensound.com/royalty-free-music/](https://www.bensound.com/royalty-free-music/)"]
for i in range(2,24):
    page_urls.append(url_template.format(page = i))

这是抓取标签的最后一个功能:

def get_all_tags(page_urls):

    # Setup the dict that we will create the df from later
    tag_dict = {"URL" : [], "Tags" : []}

    # Loop through all page urls and extract the track urls
    for i, page_url in enumerate(page_urls):    
        track_list = get_tracks(page_url)

        # Loop through the track urls and extract the revleant information
        for track_url in track_list:
            tag_list = get_tags(track_url)
            tag_dict["URL"].append(track_url)
            tag_dict["Tags"].append(tag_list)

    return tag_dict

当我将 tag_dict 转换成熊猫数据帧时,它看起来像这样:

表 1 —原始数据帧

数据都在那里,有超过 250 行的标记列表。当然还是很乱,需要一些清理。

步骤 2 —准备数据

表 1 中的数据存在一些问题。在我意识到必须转换数据帧的基本结构之前,我尝试了很多清理技术。“标签”栏由列表组成,熊猫不适合这些列表。对于我想做的每一次计算,可以遍历每个列表中的每一项,但这绝对不节省时间。我想以某种方式转换数据帧,这样我就可以利用熊猫基于矢量的计算,这将节省我很多时间!

在转换之前,我仍然需要做一些清理工作,我将在这里总结一下,但不展示实际的代码。如果你感兴趣的话,github 代表会告诉你一切。

  1. 从 url 中提取曲目名称
  2. 将“标签”列中的值从字符串转换为列表对象
  3. 从标记中删除任何“\xa0”值(在 Latin1 中表示空格)

我的计划是创建一个基于布尔的数据帧,所有标签为列,所有轨道为行。在任何列中,轨道将具有 False 或 True 值,这取决于标签(列)是否在轨道标签列表中。这将使数据帧变得更大(从 500 到 200,000 个数据点),但之后将允许有效的矢量化操作。转换后,数据帧应如下所示:

Track   | Tag 1 | Tag 2 | Tag 3 | Tag 4
Track 1 | False | False | False | True
Track 2 | True  | False | True  | True
Track 3 | True  | True  | False | False

为此,我需要获得所有惟一标签的列表,这将是新数据帧中的列。

def get_all_unique(dataframe_of_lists):
    # Create empty list
    unique_tags = []

    # Loop through the dataframe rows (lists) and each item inside
    for row in dataframe_of_lists:
        for item in row:

            # Add item to all_tags if it's not already in it
            if item not in unique_tags:
                unique_tags.append(item)

    return unique_tags

通过这个函数,我创建了实际的数据帧:

def create_boolean_df(unique_tags, track_taglists): # Create new df with a column for every tag
    boolean_df = pd.DataFrame(columns = unique_tags)

    # Create an empty dict
    data_dict = {}

    # Loop through the columns (tags) in the boolean_df and add them to the dict
    for col in boolean_df:
        data_dict[col] = []

        # Loop through the taglists in the old dataframe
        for taglist in track_taglists:

            # Check if the column (tag) is in the tracks taglist. If yes append True else append False
            data_dict[col].append(col in taglist)

    # Use the boolean lists as values for the boolean_df's columns
    for col in boolean_df:
        boolean_df[col] = data_dict[col]

    return boolean_df

表 2 —布尔数据框架

第三步——建立推荐系统

第 3.1 步—数学

所以我准备好了数据。现在我需要我的推荐系统的底层算法。一种方法是使用条件概率。如果我已经标记了 t1 =“提升”,算法将为数据集中的所有标记 ti 计算 P(ti / t1)。这是假设 t1 已经被标记,您在 tracks 标记列表中找到标记 ti 的概率。这也意味着 P(ti/t1)!= P(t1/ti)。虽然这种方法对于标签推荐来说是最准确的,但是它相当复杂。

我在寻找一种解决方案,它能让我事半功倍。相关性呢?从技术上讲,您不能像我们的标签那样关联分类变量,但是您可以计算关联,这是一种有点类似的度量。Association 将返回介于 0 和 1 之间的值,表示在同一标记列表中找到 tag1 和 tag2 的概率,前提是它们中至少有一个存在。这将是一个更容易和更快的计算,但这将意味着没有条件概率包括在内。任何标签 t1 和 t2 被一起标记的概率将被假定是相同的,不管是 t1 还是 t2 先被标记。一般来说,我们不认为标记是一个连续的过程,而是一个预先确定的适合标记列表的执行。我们会认为,在输入第一个标签之前,就已经确定了一段音乐的最佳标签。出于这个原因,我坚持使用相关的方法,让每个人的生活更轻松。

在下面的代码中,您会发现我的相关性度量的原型:

def correlation_dummy(a_and_b, 
                      a_not_b, 
                      b_not_a):

    # Formula for probability: positive_outcomes / possible_outcomes
    positive_outcomes = a_and_b
    possible_outcomes = a_and_b + a_not_b + b_not_a

    # r is the number of cases where a and b are tagged relative to the number of cases where only a or only b is tagged
    r = positive_outcomes / possible_outcomes

    return r

最终的函数如下所示:

def correlate_with_every_tag(df, tag_a, dict_mode = True): 

    unique_tags = list(df.columns)

    # In dict_mode, the results are stored in a dict, which is good for analyzing one tag
    # However, in order to transform the data into a df later, we need a list output
    if dict_mode:
        # Loop through every tag and store the correlation in the dict
        correlation_dict = {}
        for tag_b in unique_tags:
            correlation_dict[tag_b] = correlation(df, tag_a, tag_b)
        return correlation_dict
    else:
        # Loop through every tag and store the correlation in a list
        correlation_list = []
        for tag_b in unique_tags:
            correlation_list.append(correlation(df, tag_a, tag_b))
        return correlation_list

在这里,我创建了一个字典,所有标签作为键,它们与其他标签的所有相关性作为值。

unique_tags = list(music_tags.columns)correlation_matrix_dict = {}for tag_a in unique_tags:
 correlation_matrix_dict[tag_a] = correlate_with_every_tag(music_tags, tag_a, dict_mode = False)

这个计算差点弄坏了我的电脑,但是在它折磨完我之后,它返回了这个数据帧:

表 3 —相关矩阵

有 250 个样本,从 500 到 900,000 个数据点。升级很快。

第 3.2 步结果

现在,你当然想看到结果!从这么小的样本中你能得到多好的标签推荐?

我编写了几个函数来选择与输入标签最匹配(相关性最高)的标签。有关所有功能,请参见 github rep。

def get_recommendations(df, tag, num_of_recommendations):

    corr_df = find_correlations(df, tag)

    recommendations_df = find_highest_correlations(corr_df, num_of_recommendations)

    print("Recommendations:", list(recommendations_df["tag"]))

此时,您可以输入一个标签并接收三个最佳推荐。

以下是一些常见起始标签的建议:

  1. 快乐:有趣、感觉良好、积极
  2. 悲伤的:感人的,感人的,忧郁的
  3. 精力充沛:能源、运动、电力

让我们尝试几个不常用的标签:

  1. 侵略性:西方,饱和,滑行# lol
  2. 侵略性(!):沉重、坚硬、极端
  3. 放松的:寒冷、平静、悠闲
  4. 戏剧类:电影、配乐、电影
  5. 平滑:放松,嘻哈,装饰

这些推荐有的真的很好!如果我现在正在标记我的音乐,我会发现这些真的很有帮助。然而,我们也确实看到了一些问题。显然,单词“aggressive”在 bensound 上通常被拼写为“aggressive ”,这就是为什么“aggressive”比正确拼写的版本得到更好的推荐。这是一个问题。对“平滑”的推荐看起来也不太好。这可能是由于样本量小,因为“平滑”没有足够的标签来计算可靠的相关性。总的来说,所有迹象都指向更多的数据!在我开始将这个推荐系统转化为实际可用的产品之前,我需要收集更多的数据,并希望对更不常见的标签获得更好的推荐。

在这篇文章的结尾,我将使用我的推荐系统为一首歌挑选尽可能多的合适标签。让我们使用互联网上最受欢迎的“全明星”由 Smash Mouth。我将从一个标签开始,从推荐给我的三个标签中选择最合适的标签。然后我将使用这个标签作为新的输入。

标签号:输入标签→输出 1、输出 2、输出 3 →输出选择

标签 1:“积极”→“光明”、“向上”、“广告”→“向上”

标签二:“振奋”→“流行”,“光明”,“激励”→“动机”

标签三:“动机”→“企业”,“成功”,“商业”→“成功”

标签四:“成功”→“企业”、“商业”、“励志”→“励志”

标签 5:“激励”→“企业”、“业务”、“演示”→停止

好的,我们有“积极的”、“振奋的”、“激励的”、“成功的”和“激励的”。现在,我们碰壁了。然而,这首歌的标签列表还不错。毕竟,推荐系统不是为自己做标记而构建的,而是为了支持人类做出创造性的标记决定。

接下来,我将把我的样本增加到 500 首左右,看看会发生什么。当这些完成后,我肯定会再写一篇博文!

感谢大家的阅读!

在喀拉斯建立一个 ResNet

原文:https://towardsdatascience.com/building-a-resnet-in-keras-e8f1322a49ba?source=collection_archive---------3-----------------------

利用 Keras 函数 API 构造残差神经网络

什么是残差神经网络?

原则上,神经网络应该得到更好的结果,因为它们有更多的层。一个更深层次的网络可以学到比它更浅层次的网络所能学到的任何东西,而且(可能)不止这些。对于给定的数据集,如果网络无法通过向其添加更多图层来了解更多信息,那么它只需了解这些附加图层的身份映射。这样,它保留了前几层的信息,不会比更浅的层差。如果找不到比这更好的东西,网络至少应该能够学习身份映射。

但实际上,事情并不是这样的。更深的网络更难优化。网络每增加一层,训练的难度就会增加;我们用来寻找正确参数的优化算法变得更加困难。随着我们添加更多的层,网络得到更好的结果,直到某一点;然后,随着我们继续添加额外的层,精度开始下降。

残余网络试图通过增加所谓的跳跃连接来解决这个问题。上图中描绘了一个跳过连接。正如我之前所说,更深层次的网络至少应该能够学习身份映射;这就是 skip 连接所做的:它们添加从网络中的一个点到一个转发点的身份映射,然后让网络学习额外的𝐹(𝑥).如果网络没有更多可以学习的东西,那么它就将𝐹(𝑥学习为 0。原来网络比身份映射更容易学习到更接近 0 的映射。

如上图所示的具有跳跃连接的块被称为残差块,残差神经网络(ResNet)就是这些块的串联。

一个有趣的事实是,我们的大脑具有类似于残余网络的结构,例如,皮层第六层神经元从第一层获得输入,跳过中间层。

Keras 函数式 API 简介

如果你正在阅读这篇文章,你可能已经熟悉了顺序类,它允许你通过一层一层地堆叠来轻松地构建神经网络,就像这样:

**from** keras.models **import** Sequential
**from** keras.layers **import** Dense, Activation

model **=** Sequential([
    Dense(32, input_shape**=**(784,)),
    Activation('relu'),
    Dense(10),
    Activation('softmax'),
])

但是这种建立神经网络的方式不足以满足我们的需求。对于顺序类,我们不能添加跳过连接。Keras 也有 Model 类,它可以和 functional API 一起使用来创建层,以构建更复杂的网络架构。
构造时,类keras.layers.Input返回一个张量对象。Keras 中的层对象也可以像函数一样使用,用张量对象作为参数调用它。返回的对象是一个张量,然后可以作为输入传递给另一个层,依此类推。

举个例子:

**from** keras.layers **import** Input, Dense
**from** keras.models **import** Model

inputs **=** Input(shape**=**(784,))
output_1 **=** Dense(64, activation**=**'relu')(inputs)
output_2 **=** Dense(64, activation**=**'relu')(output_1)
predictions **=** Dense(10, activation**=**'softmax')(output_2)

model **=** Model(inputs**=**inputs, outputs**=**predictions)
model.compile(optimizer**=**'adam',
              loss**=**'categorical_crossentropy',
              metrics**=**['accuracy'])
model.fit(data, labels)

但是上面的代码仍然构建了一个有序的网络,所以到目前为止还没有真正使用这种奇特的函数语法。这种语法的真正用途是在使用所谓的合并层时,通过它可以合并更多的输入张量。这些层的几个例子是:AddSubtractMultiplyAverage。我们在建造剩余的积木时需要的是Add

使用Add的例子:

**from** keras.layers **import** Input, Dense, Add
**from** keras.models **import** Model

input1 **=** Input(shape**=**(16,))
x1 **=** Dense(8, activation**=**'relu')(input1)
input2 **=** Input(shape**=**(32,))
x2 **=** Dense(8, activation**=**'relu')(input2)

added **=** Add()([x1, x2])

out **=** Dense(4)(added)
model **=** Model(inputs**=**[input1, input2], outputs**=**out)

这绝不是对 Keras functional API 的全面指导。如果你想了解更多,请参考文件

让我们实现一个 ResNet

接下来,为了进行比较,我们将实现一个 ResNet 和它的普通(没有跳过连接)对应物。

我们将在这里构建的 ResNet 具有以下结构:

  • 形状输入(32,32,3)
  • 1 个 Conv2D 层,带 64 个滤波器
  • 具有 64、128、256 和 512 个滤波器的 2、5、5、2 个残差块
  • 平均池 2D 层,池大小= 4
  • 展平图层
  • 具有 10 个输出节点的密集层

它总共有 30 个 conv+致密层。所有内核大小都是 3x3。我们在 conv 层之后使用 ReLU 激活和批处理规范化。
除了跳过连接外,普通版本是相同的。

我们首先创建一个辅助函数,它将一个张量作为输入,并向其添加 relu 和批量归一化:

**def** relu_bn(inputs: Tensor) **->** Tensor:
    relu **=** ReLU()(inputs)
    bn **=** BatchNormalization()(relu)
    **return** bn

然后我们创建一个函数来构造一个残差块。它接受一个张量x作为输入,并通过 2 个 conv 层;让我们把这两个 conv 层的输出称为y。然后把输入的x加到y,加上 relu 和批量归一化,然后返回结果张量。当参数为downsample == True时,第一个 conv 层使用strides=2将输出大小减半,我们使用输入为xkernel_size=1的 conv 层,使其形状与y相同。Add层要求输入张量具有相同的形状。

**def** residual_block(x: Tensor, downsample: bool, filters: int,                                        kernel_size: int **=** 3) **->** Tensor:
    y **=** Conv2D(kernel_size**=**kernel_size,
               strides**=** (1 **if** **not** downsample **else** 2),
               filters**=**filters,
               padding**=**"same")(x)
    y **=** relu_bn(y)
    y **=** Conv2D(kernel_size**=**kernel_size,
               strides**=**1,
               filters**=**filters,
               padding**=**"same")(y)

    **if** downsample:
        x **=** Conv2D(kernel_size**=**1,
                   strides**=**2,
                   filters**=**filters,
                   padding**=**"same")(x)
    out **=** Add()([x, y])
    out **=** relu_bn(out)
    **return** out

create_res_net()函数把所有东西放在一起。以下是这方面的完整代码:

简单网络以类似的方式构建,但是它没有跳跃连接,我们也不使用residual_block()助手函数;一切都在create_plain_net()里面完成。
平原网络的代码:

在 CIFAR-10 上进行培训并查看结果

CIFAR-10 是一个包含 10 个类别的 32x32 rgb 图像的数据集。它包含 50k 训练图像和 10k 测试图像。
以下是每个班级 10 张随机图片的样本:

我们将在这个数据集上训练 ResNet 和 plain net 20 个时期,然后比较结果。

在配有 1 个 NVIDIA Tesla K80 的机器上,每个 ResNet 和 PlainNet 的训练时间约为 55 分钟。ResNet 和 PlainNet 在训练时间上没有显著差异。
我们得到的结果如下所示。

因此,通过在该数据集上使用 ResNet,我们在验证准确性方面获得了 1.59% 的提升。在更深的网络中,差异应该更大。请随意尝试,看看你得到的结果。

参考

  1. 用于图像识别的深度残差学习
  2. 残差神经网络—维基百科
  3. 功能 API 指南— Keras 文档
  4. 模型(功能 API) — Keras 文档
  5. 合并层— Keras 文档
  6. CIFAR-10 和 CIFAR-100 数据集

我希望这些信息对你有用,感谢你的阅读!

这篇文章也贴在我自己的网站这里。随便看看吧!

使用机器学习构建混响检测系统

原文:https://towardsdatascience.com/building-a-reverb-detection-system-using-machine-learning-cba02a1710bf?source=collection_archive---------25-----------------------

德尔塔-梅尔光谱图

介绍

混响或简称混响是声学和心理声学中的一个术语,用来解释声音一旦产生后的持久性。一个例子是在一个大教堂里拍手(很有毅力),而不是在一个铺着地毯的小房间里拍手(没有那么多毅力)。

这是由构成声音产生环境的材料的反射和吸收造成的。与石头或砖造的大教堂相比,铺着地毯、有窗帘和家具的房间会吸收更多的声音。

我们想要检测这一点的原因是,如果有人在过于混响的环境中对着手机说话或唱歌。我们可能希望能够警告进行录音的人,因为这可能会降低录制的声音质量。

这里有两个声音示例,分别演示了混响很小的录音和混响很大的录音。

混响很小。

很多混响。

我们实际上试图用我们的机器学习(ML)模型来测量的是混响衰减时间。这可以定义为声音逐渐消失所需要的时间,以秒为单位。这种情况的技术术语是 RT-60 时间,即声音的压力水平下降 60db 所需的时间。

图一。这说明了 RT-60 的衰变时间(来源:Wkipedia)。

参考上面的两段录音,第二段录音听起来像是有人在小浴室里唱歌。在浴室唱歌的效果是歌手被所有回荡的声音淹没。这是不可取的。

了解 RT-60 时间的另一个用例是,它可以作为另一个 ML 系统的输入,用于去混响信号。这种系统的一个例子可以在[1]中找到。

我们为什么要做这个项目?

艾。我们正在开发一个允许用户对着手机唱歌的系统。我们将随后使用 ML 应用音频清理过程来处理歌手的声音。清理过程的目的是使歌手的声音听起来尽可能接近专业录音室录制的声音。然而,在用真实世界的数据进行测试时,我们发现用户在有太多混响的地方录音,比如浴室。这导致音频清理过程出现不良结果,我们需要降低该过程的风险。

我们是如何解决这个问题的?

我们提出了一个使用卷积神经网络(CNN)来解决问题的 ML 模型,其中我们设计了自己的卷积滤波器来解决问题。我们实际上采用了[2]中的模型来解决我们的问题。我们还通过脉冲响应卷积生成了自己的数据集。

我们用了什么数据?

我们收集了大约 4000 份人们唱歌和谈话的“干”录音。我们所说的“干燥”是指它们是在几乎没有声音反射(即混响)的环境中录制的。

我们使用“干”录音的原因是,我们可以使用不同的 RT-60 时间为每个录音人工添加混响,即我们可以给 1 号录音 1 秒的 RT-60 时间,给 2 号录音 1.1 秒的 RT-60 时间。

我们通过称为卷积的过程将人工混响添加到每个信号中。我们取一个 RT-60 时间为 1 秒的脉冲响应,并将其与“干”信号卷积,得到“湿”信号。

脉冲响应是指我们获取一个短暂的“脉冲”信号,并使其通过一个动态系统,以测量其输出,即其响应。为了捕捉音乐厅或大教堂的声学特征,我们会在空间中产生一个脉冲(我们刺破一个气球)并记录下来。一旦我们有了一个位置的脉冲响应,我们就可以用另一个录音(有人唱歌)进行卷积。这让我们能够听到他们在特定空间的声音。很酷吧?

从 OpenAIR 数据集[3]中收集了 70 个脉冲响应,我们的模型的 RT60s 从 0.24 秒到 12.3 秒不等。OpenAIR 是一个允许用户共享脉冲响应和相关声学信息的在线资源。

我们是如何创建数据集的?

我们将 4000 个声音记录中的每一个与所有 70 个脉冲响应进行卷积,并根据其 RT-60 时间标记每个数据点。这给了我们总共 280,000 个不同 RT-60 时间的记录。

为了模拟真实的背景噪声,我们还在每个记录中随机添加了信噪比为-55db 和-45db 的粉红噪声。

我们为所有 RT-60 时间创建了分类箱,这允许我们将它们分成 20 个不同的类。图 2 显示了 RT-60 时间的分布,表 1 描述了如何将它们放置到时间仓中。

图 2:所用数据集中的 RT-60 时间分布。

表 1:用于 RT-60 分类器的时间仓。

特征抽出

接下来,我们必须提取相关特征,以获得音频的良好表示。我们最初选择使用 Mel 声谱图,因为这些声谱图很好地代表了声音的音色。

音色可以描述为声音的颜色。如果我在钢琴上弹奏一个中 C 音,然后在吉他上弹奏相同的音,它们的音高相同,但听起来不同。这种声音上的差异就是音色。

Mel 光谱图看起来像图 3 的左侧。

图 3:同一声音的 Mel 声谱图和 delta-Mel 声谱图。

我们可以清楚地看到声音随着时间的推移而衰减。尾巴最长的部分在 3-6 秒。

在我们的特殊情况下,我们没有使用标准的 Mel 光谱图进行训练,而是使用 delta-Mel 光谱图。Delta-Mel 频谱图是音色随时间变化的微分或轨迹。我们认为这将更好地呈现应用于每个人声的不同 RT-60 时间。

图 3 右手侧示出了δ-Mel 谱图。你可以看到 delta-Mel 谱图中出现的视觉信息比 Mel 谱图中多得多。

一旦所有这些特征都被提取出来,我们需要把它们提供给 CNN 进行训练。我们用于特征提取的参数如下。参数:M = 40 个梅尔频带,N = 2381 帧,𝑓s = 44.1,1024 样本/帧,布莱克曼-哈里斯窗口,2048 样本 FFT 大小,1024 样本跳跃大小。

ML 模型

如前所述,我们使用 CNN 作为我们的 ML 模型,因为这种类型的 ML 模型已经被证明在音频和图像分类上都是有效的。我们使用了[2]中提出的滤波器模型,但是我们根据我们的问题调整了尺寸。

E-net 滤波器模拟对应于早期反射的时间特征:

R-net 滤波器对与可接受的记录反射相对应的时间特征进行建模:

T-net 滤波器模拟对应于混响尾音中较长反射的时间特征:

3 个卷积层与 ReLU 激活功能并行放置(E-Net、R-Net、T-Net)。e 网、r 网、t 网由 1 × 𝑛滤波核组成,其中𝑛从短到长变化。

接下来是内核大小为 4 x N 的 3 个最大池层、1 个平坦层和 1 个丢弃层,丢弃概率为 50%,以避免过度拟合。

最后,有一个具有 20 路软最大激活函数的密集层对应于我们的类。

分类交叉熵被选为损失函数。Adam 是最乐观的,初始学习率为 0.01,在每个时期递减 0.1。

选择 80%训练/ 10%验证/ 10%测试分割,通过 10 重交叉验证来评估模型。该模型如图 4 所示。

图 Keras 中 RT-60 估算模型的图示。

结果

结果显示该模型对于更长的 RT-60 时间是最有效的,而当我们具有更短的时间时会有些混乱。结果可以在图 5 中看到

图 5:用于测试数据的 RT-60 估计模型的标准化混淆矩阵。

结论

结果是令人鼓舞的,我们设计的系统的精确度相差不远。然而,我们肯定可以做更多的事情来改进模型,例如数据集分布。

我们发现我们使用的过滤器类型非常有效,并且通过使用 delta-Mel 光谱图,我们得到了略微更好的结果。我们计划在一个更复杂的去混响模型中使用模型来通知所需的 RT-60 时间估计,该模型用于我们在 AI 的另一个正在进行的项目。音乐。如果你想了解更多我们的工作,请查看我们的时事通讯(【https://www.aimusic.co.uk/newsletter-sign-up】T2)。

参考

[1] —吴,博等,“一种基于深度神经网络的混响时间感知语音去混响方法”(2016),IEEE/ACM 音频、语音和语言处理汇刊。

[2] — Pons,j .和 Serra,x .,“利用卷积神经网络设计用于建模时间特征的高效架构”(2017),声学、语音和信号处理国际会议(ICASSP)。

[3] — Murphy,Damian T .和 Shelley,Simon,“OpenAIR:交互式听觉化网络资源和数据库”(2010),音频工程学会第 129 次会议(AES)。

感谢

非常感谢方大卫(【https://www.linkedin.com/in/davidwengweifong/】)为这个项目付出的努力。

在 Keras 中构建路标分类器

原文:https://towardsdatascience.com/building-a-road-sign-classifier-in-keras-764df99fdd6a?source=collection_archive---------8-----------------------

编写一个 CNN,在 Keras 框架中对超过 43 种类型的路标进行分类

路标分类过程(来源

有这么多不同类型的交通标志,每一种都有不同的颜色、形状和大小。有时,有两个标志可能有相似的颜色,形状和大小,但有两个完全不同的含义。我们究竟怎样才能给计算机编程序来正确分类道路上的交通标志呢?我们可以通过创建自己的 CNN 来为我们分类不同的路标。

下载数据

在本教程中,我们将使用 GTSRB 数据集,该数据集包含超过 50,000 张德国交通标志的图像。共有 43 个类别(43 种不同类型的标志,我们将对其进行分类)。单击下面的链接下载数据集。

[## GTSRB -德国交通标志识别基准

多类别、单图像分类挑战

www.kaggle.com](https://www.kaggle.com/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign)

当你在电脑中打开数据集时,数据集内应该有 6 个路径(3 个文件夹和 3 个电子表格),如下所示。

meta 文件夹应该有 43 个不同的图像(范围从 0-42)。 测试 文件夹就是一堆测试图片。 train 文件夹应该有 43 个文件夹(范围也是从 0 到 42),每个文件夹包含各自类别的图像。

现在您已经有了数据集,并且数据集包含了所有需要的数据,让我们开始编码吧!

本教程将分为 3 个部分: 加载数据建立模型训练模型

不过在开始之前,请确保您的计算机上安装了 Jupiter 笔记本,因为本教程是在 Jupiter 笔记本上完成的(这可以通过安装 Anaconda 来完成。点击下面的链接安装 Anaconda。)

[## Anaconda Python/R 发行版-免费下载

开源的 Anaconda 发行版是在…上执行 Python/R 数据科学和机器学习的最简单的方法

www.anaconda.com](https://www.anaconda.com/distribution/)

加载数据

好了,现在我们已经安装了 Jupyter 笔记本,也安装了数据集,我们准备开始编码了(Yesss)!

首先,让我们导入加载数据所需的库和模块。

import pandas as pd
import numpy as np
import os
import cv2
import matplotlib.pyplot as plt
import randomimport tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.layers import Activation
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Dense
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import Adam

第一束是创建 load_data 函数所需的库。第二组是我们构建模型所需要的东西。如果您愿意,可以在不同的内核中导入每个束,但这真的无关紧要。

创建 L oad_Data 函数

要开始加载数据,让我们创建一个变量来表示数据集的存储位置。确保你把字母 r 放在你的路径字符串前面,这样你的计算机就知道它应该这个字符串。

注意:我的道路将与你的不同。要获得数据集的路径,您应该转到数据集所在的文件夹,单击一次数据集(不要打开它,只要让您单击它),然后单击屏幕左上角的按钮 复制路径

不要双击数据文件夹,只需单击一次将其高亮显示

然后把路径粘贴到你的 jupyter 笔记本上(就像我下面做的那样)。确保你在你的字符串前面加了一个 r ,这样 pc 就知道它应该读取这个文件了。

data_path = r"D:\users\new owner\Desktop\Christmas Break\gtsrb-german-traffic-sign"

接下来,让我们定义将数据从计算机加载到笔记本中的函数。

def load_data(dataset):
    images = []
    classes = [] rows = pd.read_csv(dataset)
    rows = rows.sample(frac=1).reset_index(drop=True)

我们的load _ data函数取 1 个参数,这是我们数据集的路径。之后,我们定义两个列表, 图片图像 列表将存储图像数组,而 列表将存储每个图像的类编号。

在下一行中,我们将打开 CSV 文件。

最后一行使我们的数据随机化,这将防止模型过度适应特定的类。

 *for i, row in rows.iterrows():
        img_class = row["ClassId"]
        img_path = row["Path"] image = os.path.join(data, img_path)*

for 循环遍历所有行。 。iterrows() 函数为每一行返回一个索引(第一行是 0,然后是 1,2,3,…)。直到最后一行)。

我们从 ClassId 列获取图像的类,从 路径 列获取图像数据。

最后,我们从电子表格中获取图像的路径,并将其与数据集的路径相结合,以获得图像的完整路径

 *image = cv2.imread(image)
        image_rs = cv2.resize(image, (img_size, img_size), 3) R, G, B = cv2.split(image_rs) img_r = cv2.equalizeHist(R)
        img_g = cv2.equalizeHist(G)
        img_b = cv2.equalizeHist(B) new_image = cv2.merge((img_r, img_g, img_b))*

首先,我们读取图像数组(将它从数字数组转换成实际的图片,以便我们可以调整它的大小)。然后,我们将图像尺寸调整为 32 X 32 X 3,(如果所有图像的尺寸都相同,那么训练模型的速度会更快)。

接下来的 5 行执行直方图均衡,这是一种提高图像对比度的均衡技术。如果您有兴趣了解直方图均衡化的更多信息,请单击此处的

注意:这段代码仍然在前面代码块的 for 循环中

 *if i % 500 == 0:
            print(f"loaded: {i}") images.append(new_image)
        classes.append(img_class) X = np.array(images)
    y = np.array(images)

    return (X, y)*

仍然在 for 循环中,我们将编写一个 if 语句,打印我们已经加载了多少图像。这条语句将每 500 幅图像打印一次,只是为了让我们知道我们的函数实际上在工作。

接下来,我们将刚刚从数据集中提取的图像添加到之前定义的列表中。

现在在 for 循环之外,我们将把 图像 列表重新定义为 Numpy 数组。这是为了我们以后可以在阵列上执行操作。

最后,当我们从数据集中提取完所有图像后,我们将返回元组中的 图像 列表。

定义超参数

超参数是神经网络无法学习的参数。它们必须由程序员在培训前明确定义

*epochs = 20
learning_rate = 0.001
batch_size = 64*

我们的第一个超参数(我会用缩写 HYP), epochs ,告诉神经网络应该完成多少次完整的训练过程。在这种情况下,神经网络将训练自己 20 次(检查所有 50,000 张图像,并用 12,000 张测试图像验证自己 20 次)!

学习率告诉我们每次会更新多少权重。学习率往往在 0 到 1 之间。

批量大小告诉我们神经网络将一次循环通过多少图像。计算机不可能一次循环通过所有 50,000 张图像,它会崩溃的。这就是为什么我们有批量大小。

载入数据

*train_data = r"D:\users\new owner\Desktop\TKS\Christmas Break\gtsrb-german-traffic-sign\Train.csv"
test_data = r"D:\users\new owner\Desktop\TKS\Christmas Break\gtsrb-german-traffic-sign\Test.csv"(trainX, trainY) = load_data(train_data)
(testX, testY) = load_data(test_data)*

首先,我们将定义测试和训练数据集的路径,使用我们以前用来定义数据集路径的相同方法

现在,我们将使用我们的 load_data 函数加载训练和测试数据。

我们将把 图片 列表存储在变量中,把 列表存储在 trainY 变量中,并对【testX】testY 进行同样的操作。**

****注意:这一步可能需要一段时间,取决于你电脑的规格。我的花了 10-15 分钟。

为培训准备数据

**print("UPDATE: Normalizing data")
trainX = train_X.astype("float32") / 255.0
testX = test_X.astype("float32") / 255.0print("UPDATE: One-Hot Encoding data")
num_labels = len(np.unique(train_y))
trainY = to_categorical(trainY, num_labels)
testY = to_categorical(testY, num_labels)class_totals = trainY.sum(axis=0)
class_weight = class_totals.max() / class_totals**

现在我们要对数据进行归一化处理。这使得我们可以将数据中的值缩小到 0 到 1 之间,而之前的值在 0 到 255 之间。

接下来,我们将一次性编码测试和训练标签。本质上,一键编码是用二进制值(1 和 0)而不是分类值(“红色”或“蓝色”)来表示每个类的一种方式。这是通过创建一个主对角线为 1,其余值为 0 的对角矩阵来实现的。矩阵的维数等于类的数量(如果有 20 个类,则矩阵是 20×20 的矩阵)。在矩阵中,每行代表一个不同的类,因此每个类都有其唯一的代码。如果你想了解更多关于一键编码的知识,这里有一个很好的资源

最后,我们将通过给每个等级分配一个权重来说明等级中的不平等。

构建模型

现在是时候构建实际的 CNN 架构了。首先,让我们导入必要的库和模块:

**import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.layers import Activation
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Dense**

这里,我们导入 Tensorflow,这是 Python 中的一个框架,允许我们构建 ML 模型,我们从 Tensorflow 导入 Keras,这进一步简化了我们的模型!之后,我们导入一系列不同的图层来构建模型。如果你想了解更多关于这些层的具体功能,请浏览我在 CNN 上的文章。

** [## 卷积神经网络的简单指南

卷积神经网络揭秘没有任何花哨的技术术语!

towardsdatascience.com](/a-simple-guide-to-convolutional-neural-networks-751789e7bd88)

在我们开始构建模型之前,我想指出没有“合适的”方法来构建模型。你的 CNN 没有固定的层数、尺寸或层数类型。你应该试着用它来看看哪一个能给你最好的准确度。我给你一个最准确的。

class RoadSignClassifier:
    def createCNN(width, height, depth, classes):
        model = Sequential()
        inputShape = (height, width, depth)

这一次,我们要创建一个类,名为RoadSignClassifier(任何名字都可以)。在该类中,有一个函数, createCNN, 接受 4 个参数。我们将使用顺序 API,它允许我们逐层创建模型。

 model.add(Conv2D(8, (5, 5), input_shape=inputShape,      activation="relu"))
        model.add(MaxPooling2D(pool_size=(2, 2)))

这是我们的第一个卷积层。我们定义了输出的维度(8 X 8 X 3),并使用了激活函数“relu”。我们继续使用 Conv2D — MaxPooling2D 序列 2 次以上。

 model.add(Conv2D(16, (3, 3), activation="relu"))
        model.add(BatchNormalization())
        model.add(Conv2D(16, (3, 3), activation="relu"))
        model.add(BatchNormalization())
        model.add(MaxPooling2D(pool_size=(2, 2)))

        model.add(Conv2D(32, (3, 3), padding="same", activation="relu"))
        model.add(BatchNormalization())
        model.add(Conv2D(32, (3, 3), padding="same", activation="relu"))
        model.add(BatchNormalization())

和上次一样,除了这次我们包括批量归一化。只是加速训练而已。

 model.add(Flatten())
        model.add(Dropout(0.5))
        model.add(Dense(512, activation="relu")) model.add(Dense(classes, activation="softmax"))
        return model

现在,我们展平最终卷积层的输出,执行一次丢弃,然后进入最终的密集层。最终密集层的输出等于我们拥有的类的数量。

这基本上就是构建模型的全部内容。是时候继续前进了!

训练模型

现在是有趣的部分(实际上这是我们必须等待 30 分钟模型训练 lol 的部分)。是时候训练我们的模型识别路标了!

data_aug = ImageDataGenerator(
rotation_range=10,
zoom_range=0.15,
width_shift_range=0.1,
height_shift_range=0.1,
shear_range=0.15,
horizontal_flip=False,
vertical_flip=False)

在这里,我们正在执行数据增强。数据扩充在我们的数据集中创建图像的修改版本。它允许我们向数据集添加图像,而无需我们收集新的图像。在 Keras 中,我们使用imagedata generator模块来执行数据扩充。

model = RoadSignClassifier.createCNN(width=32, height=32, depth=3, classes=43)
optimizer = Adam(lr=learning_rate, decay=learning_rate / (epochs))

第一行定义了我们的模型。我们使用类 RoadSignClassifier, 并定义类的宽度、高度、深度和数量。

在第二行中,我们创建了我们的优化器,在本例中是 Adam 优化器。我们将学习率初始化为之前设置的值(0.001),我们还将学习率设置为在每个时期减少(这是 衰减 参数,它减少了过度拟合)。

model.compile(optimizer=optimizer, loss="categorical_crossentropy", metrics=["accuracy"])fit = model.fit_generator(
    data_aug.flow(train_X, trainY, batch_size=batch_size), 
    epochs=epochs,
    validation_data=(test_X, testY),
    class_weight=class_weight,
    verbose=1)

第一行编译模型。我们创建模型并定义优化器、损失和时期数。

在第二行,我们装配模型(这是培训发生的地方)。我们的data _ aug . flow方法对我们之前定义的图像应用增强。 历元的数量 被设置为 20。对于验证数据,我们使用我们的测试数据。 verbose 被设置为 1,这意味着 Keras 将在您进行训练时显示模型的进度。

现在,您已经完成了模型代码的编写。是时候运行它了。运行一段时间后,您应该会得到如下输出:

前三个时期(在第三个时期,您的准确度应该是 70–80%)

然后,在您完成了所有的 epochs 之后,您应该会得到类似如下的输出:

最后三个纪元(你的准确率应该超过 90%)

你的准确率至少要达到 90%。如果没有,就去玩玩模型架构。最终,您的模型将返回大约 90%或更高的准确率。

酷!

现在你完成了你的分类器!感觉不错吧!好了,今天就到这里。希望你从这篇文章中学到了一些东西!如果你遇到什么困难,可以发邮件到 nushainef@gmail.com 给我,我会尽力帮助你。祝你的 ML 之旅好运。

其他很好的选择

如果这个教程对你没有吸引力,或者你只是在寻找另一个教程,这里有另一个很棒的教程,我发现它真的很有用!

[## 基于 Keras 和深度学习的交通标志分类——PyImageSearch

在本教程中,您将学习如何训练自己的交通标志分类器/识别器能够获得 95%以上的…

www.pyimagesearch.com](https://www.pyimagesearch.com/2019/11/04/traffic-sign-classification-with-keras-and-deep-learning/)**

使用 Tensorflow 和 OpenCV 与 Python 构建石头剪刀布人工智能

原文:https://towardsdatascience.com/building-a-rock-paper-scissors-ai-using-tensorflow-and-opencv-d5fc44fc8222?source=collection_archive---------18-----------------------

古老的游戏被重新想象和更新……

图片由 EsquireME

该项目的代码可以在我的 Github 找到

[## HOD101s/RockPaperScissor-AI-

这个回购是针对初学者谁想要尝试和建立自己的机器人容易。所以让我们开始吧!任何…的基础

github.com](https://github.com/HOD101s/RockPaperScissor-AI-)

简介:

这个项目的基础是实验深度学习和图像分类,目的是建立一个简单而有趣的臭名昭著的石头剪刀布游戏的迭代。首先,我想说这个项目是我在 5 月份的 COVID19 隔离期间无聊的产物,希望在你读到这封信的时候,一切都恢复正常了。通过这个解释的过程,我的目的是解释这个项目的基础,以简单的术语面向初学者。让我们开始吧...

在构建任何类型的深度学习应用时,都有三个主要步骤:

1.收集和处理数据

2.建立一个合适的人工智能模型

3.部署使用

整个项目涉及并与我的 Github repo 齐头并进,所以请做好准备以供参考。

收集我们的数据:

图片由 Sookyung An 来自 Pixabay

任何深度学习模型的基础都是数据。任何机器学习工程师都会同意,在 ML 中,数据远比算法本身更重要。我们需要收集石头、布、剪刀这些符号的图像。我没有下载别人的数据并在上面进行训练,而是制作了自己的数据集,并鼓励大家也建立自己的数据集。稍后,尝试更改数据并重新训练模型,以查看数据对深度学习模型的严重影响。

我已经使用 Python 的 OpenCV 库进行了所有与相机相关的操作。所以这里的标签也是指图片属于什么类 ie。RPS,根据标签,图像保存在适当的目录中。 ctmaxCt 是保存图像的起始和结束索引。剩下的是标准的 OpenCV 代码,以获取网络摄像头的饲料和保存图像到一个目录。一个需要注意的关键点是我所有的图片都是 300 x 300 尺寸。运行后,我的目录树看起来像这样。

C:.
├───paper
    │ paper0.jpg
    │ paper1.jpg
    │ paper2.jpg
│
├───rock
    │ rock0.jpg
    │ rock1.jpg
    │ rock2.jpg
│
└───scissor
     scissor0.jpg
     scissor1.jpg
     scissor2.jpg

如果你是指 Github repo getData.py 为你做的工作!!

预处理我们的数据:

计算机理解数字,我们有图像供我们使用。因此,我们将把所有的图像转换成它们各自的矢量表示。此外,我们的标签尚未生成,因为已建立的标签不能是文本,所以我已经使用 shape_to_label 字典为每个类手动构建了 One-Hot-Encoded 表示。

由于我们已经根据类别将图像保存在目录中,因此目录名用作标签,并使用 shape_to_label 字典将其转换为一键显示。接下来,我们遍历系统中的文件来访问图像,cv2 . imread()函数返回图像的矢量表示。我们通过翻转图像和放大图像来手动增加数据。这增加了我们的数据集大小,而无需拍摄新照片。数据扩充是生成数据集的关键部分。最后,图像和标签存储在单独的 numpy 数组中。

更多关于数据扩充的信息请点击。

用迁移学习构建我们的模型:

当涉及到处理图像数据时,有许多预先训练好的模型可用,这些模型已经在数据集上进行了训练,这些数据集有数千个标签可供我们使用,这要感谢 Tensorflow 和 Keras 通过它们的应用程序 api 分发了这些模型。这使得在我们的应用程序中包含这些预先训练好的模型变得轻而易举!

图片来自洛伦佐·法米格里尼

简言之,迁移学习采用预先训练的模型,不包括做出最终预测的最终层,从而留给我们模型的强大部分,该部分可以区分这种情况下图像中的特征,并将这些信息传递给我们自己的密集神经网络。

为什么不训练自己的模型?这完全取决于你!!然而,使用迁移学习可以在很多时候让你的进步更快,从某种意义上说,你可以避免重新发明轮子

其他一些受欢迎的预培训模型:

  • InceptionV3
  • VGG16/19
  • 雷斯内特
  • MobileNet

这里有一篇关于迁移学习的有趣的文章

注意:每当我们处理图像数据时,数据卷积神经层的使用几乎是已知的。这里使用的迁移学习模型有这些层次。欲了解 CNN的更多信息,请访问

实现:

gif by Gifer

我已经使用 DenseNet121 模型进行特征提取,其输出最终将输入到我自己的密集神经网络中。

要点:

  • 由于我们的图像是 300x300,指定的输入形状是相同的。额外的 3 代表 RGB 层,因此这一层有足够的神经元来处理整个图像。
  • 我们使用 DenseNet 层作为我们的基础/第一层,然后是我们自己的密集神经网络。
  • 我已经将可训练参数设置为真,这也将重新训练 DenseNet 的重量。这给了我更好的结果,虽然 twas 相当耗时。我建议在您自己的实现中,通过更改这些参数(也称为超参数)来尝试不同的迭代。
  • 因为我们有 3 个类石头剪子布,最后一层是一个密集层,有 3 个神经元和 softmax 激活。
  • 这最后一层返回图像属于 3 个类别中的特定类别的概率。

如果你指的是 GitHub repo train.py 负责数据准备和模型训练!

至此,我们已经收集了数据,构建并训练了模型。剩下的唯一部分是使用 OpenCV 进行部署。

OpenCV 实现:

这个实现的流程很简单:

  • 启动网络摄像头并读取每一帧
  • 将此帧传递给分类 ie 模型。预测类别
  • 用电脑随机移动
  • 计算分数

上面的代码片段包含了相当重要的代码块,剩下的部分只是让游戏更加用户友好,RPS 规则和得分。

所以我们从加载我们训练好的模型开始。接下来是石器时代的 for-loop 实现,在开始程序的预测部分之前显示倒计时。预测之后,分数会根据玩家的移动进行更新。

图片由马纳斯·阿查里亚

我们使用 cv2.rectangle()显式绘制一个目标区域。在使用 prepImg() 函数进行预处理后,只有这部分帧被传递给模型进行预测。

完整的 play.py 代码可以在我的回购协议上的这里获得。

结论:

我们已经成功地实施并理解了这个项目的运作。所以继续前进,分叉我的实现并进行试验。一个主要的改进可能是增加手部检测,这样我们就不需要明确地绘制目标区域,模型将首先检测手部位置,然后做出预测。我尽量让我的语言对初学者友好,如果你还有任何问题,请发表评论。我鼓励你改进这个项目,并把你的建议发给我。精益求精!

* [## Manas Acharya -机器学习工程师- KubixSquare | LinkedIn

机器学习和数据科学爱好者,曾在前端 Web 领域担任全栈开发人员…

www.linkedin.com](https://www.linkedin.com/in/manas-acharya/) [## 基于 Tensorflow 和 OpenCV 的人脸检测

有效的实时面具检测。

medium.com](https://medium.com/@manasbass.99/facemask-detection-using-tensorflow-and-opencv-824b69cad837)*

为每个使用人工智能的人建立一个更安全的互联网

原文:https://towardsdatascience.com/building-a-safer-internet-for-everyone-using-ai-175df5e02cee?source=collection_archive---------39-----------------------

使用 TensorFlow JS 构建的 web 扩展过滤 NSFW 图像。

来自 Pexels 的 Andrea Piacquadio 的照片

本项目使用的所有源代码都可以在 这里

互联网是一个未经过滤的地方。当你随意浏览你的订阅源时,没有人能保证你会偶然发现什么。

即使在互联网上不起眼的地方,你也可能偶然发现不合适的或“不适合工作”的图片。

这让我想到了一个可以从网上过滤掉这些内容的解决方案。有几点需要考虑:

  • 所有的图像应该从用户加载的网站进行监控。
  • 应该在不离开客户机的情况下处理图像。
  • 它应该很快,应该在所有网站上工作。
  • 它应该是开源的。

解? 一个 web 扩展,它会检查页面中加载的图像是否是 NSFW 的,并且只在发现它们是安全的情况下才显示它们。

输入 NSFW 滤波器

NSFW 过滤器 是一个 web 扩展,目前运行在 Chrome 和 Firefox 上,使用机器学习来过滤 NSFW 图像。

nsfwjs 模型用于检测加载图像的内容。该模型被训练用于检测 NSFW 图像的唯一目的。

使用这个已经优化为在浏览器上运行的模型,我们构建了一个扩展,它可以读取浏览器中加载的网页中的图像,并且只在发现它们是安全的情况下才使它们可见。

开源开发模式

NSFW 过滤器是完全开源的,它将永远是。

我们有一份来自世界各地的优秀贡献者名单,我们将继续改进它并添加更多功能。

因为这样的产品还不存在,所以可能会有更多的改进空间和功能,而这些肯定是当前团队完全忽略的。

因此,我们将它发布到野外,并开始接受来自世界各地具有广泛想法的开发人员的贡献。

现在,我们有了第一个版本。

它是如何在引擎盖下工作的

当一个网页被加载时,该扩展选择页面上加载的所有图像,并对用户隐藏这些图像。

这些图像然后由机器学习模型检查,该模型将检测 NSFW 内容。

如果图像被发现而不是具有 NSFW 内容,那么它们是可见的。NSFW 的图像仍然隐藏着。

NSFW 滤波的基本工作流程

用例

该扩展的用途很广泛。无论您是在工作电脑上使用它还是在孩子的电脑上使用它。

你不想在工作的时候偶然发现 NSFW 的内容吧?

你不希望你的孩子在做学校报告时偶然发现这些内容,对吗?

解决办法,用 NSFW 滤波

这个项目的所有源代码都可以在我们的 GitHub repo 中获得。

[## 纳文杜-波特卡特/nsfw-过滤器

从网站过滤 NSFW 图片的网络扩展。它使用 TensorFlow JS-一个机器学习框架-来…

github.com](https://github.com/navendu-pottekkat/nsfw-filter)

有不同想法的人的贡献可以极大地改进这个项目。

任何形式的贡献都是受欢迎的!

快乐编码!

构建面向大规模事实核查和问题回答的语义搜索引擎

原文:https://towardsdatascience.com/building-a-semantic-search-engine-for-large-scale-fact-checking-and-question-answering-9aa356632432?source=collection_archive---------20-----------------------

开发一个语义检索模型,并使用它来建立一个新冠肺炎语义搜索引擎。

段落检索是事实核查和问题回答系统的一个非常重要的部分。大多数系统通常只依赖稀疏检索,稀疏检索会对召回率产生重大影响,尤其是当相关段落与查询语句几乎没有重叠词时。在本文中,我们展示了我们如何开发一个优于稀疏段落检索的文本嵌入模型,以及我们如何利用它来构建 Quin ,一个关于新冠肺炎疫情事实的语义搜索引擎。

段落检索

段落检索问题定义如下:给定一个段落语料库 D 和一个查询 q,我们希望使用带有两个参数 q 和 d ∈ D 的评分函数 f 返回与查询最相关的前 k 个段落,该评分函数计算相关性分数 f(q,d) ∈ R。

稀疏表示的局限性

TF-IDF 和 BM25 将文本表示为稀疏的高维向量,可以使用倒排索引数据结构对其进行有效搜索。这些稀疏表示可以有效地减少基于关键字的搜索空间。比如,当我们想回答一个类似“电影《盗梦空间》是谁导演的?”,我们显然想把重点放在包含单词电影盗梦空间的段落上。然而,稀疏表示可能是限制性的,因为它们需要查询和段落之间的单词重叠,并且它们不能捕捉潜在的语义关系。例如,如果我们想要检索声明“年轻人死于新冠肺炎”的段落,包含类似于“婴儿死于新冠肺炎”“男孩死于新冠肺炎”的句子的相关段落将被遗漏。

潜在密集检索

基于变压器和语言建模任务预训练的神经模型,如 BERT、GPT 和 T5,已经导致许多自然语言处理任务的显著改进,包括段落检索。在我们的系统中,我们使用了一个基于 BERT 的文本嵌入模型。更具体地说,我们使用φ(q)和φ(d)的点积作为我们的段落评分函数:

段落评分功能

其中φ(。)是一个嵌入函数,它将一个段落或查询映射到一个密集向量。函数 f 的选择允许我们利用 FAISS 库进行有效的最大内积搜索,并轻松地将我们的系统扩展到数百万个文档。对于嵌入函数φ(。),我们使用 BERT-base 的平均令牌嵌入,它已经在许多任务上进行了微调:

段落嵌入函数

其中 BERT(d,I)是段落 d 中第 I 个标记的嵌入,而|d|是 d 中标记的数量。下图显示了称为 QR-BERT 的密集检索模型,该模型确定段落是否与查询相关。我们的密集检索模型由一个编码器组成,该编码器将查询和段落嵌入到相同的 k 维空间中。查询和段落之间的相似性(段落的相关性)由它们的嵌入表示的余弦相似性给出。

暹罗密集检索模型

训练嵌入模型

QR-BERT 通过一组查询段落示例进行训练。设 D+是正查询段落对的集合。我们通过最大化对数似然来估计评分函数的模型参数θ:

等式 1:损失函数

条件概率 p(d|q)由 softmax 近似表示:

等式 2:给定 q,检索 d 的概率

注意,获得等式 2 中所有通道的分母在计算上是昂贵的。因此,我们将计算仅限于当前训练批次中的段落。最终损失函数由下式给出:

等式 3:最终损失函数

其中 D_B 是训练批次 B 中的段落集,D_B+是 B 中的正查询-段落对集。使用 Adam 优化器在 MSMARCO 数据集上训练该模型。我们的实验表明,QR-BERT 比 BM25 段落检索好得多。

使用 NLI 数据进行预训练

我们发现,在自然语言推理数据上预先训练嵌入模型实际上可以改进它。我们将两个流行的 NLI 数据集(SNLI 和 MultiNLI)合并为一个,称为 NLI,并且我们还从现有的问答数据集派生出一个新的 FactualNLI 数据集。在我们的论文中详细描述了推导新 NLI 数据集的方法。FactualNLI 数据集用于训练和评估用于事实检查的检索模型,也用于预训练用于答案检索的模型。使用 NLI 数据,我们使用分类目标对模型进行预训练:

等式 4:分类目标

其中 u 是前提句的嵌入,v 是假设句的嵌入,W_3×3k 是线性变换矩阵,其中 k = 768 是 BERT-base 的隐藏表示的维数,而[u;五;| u v |]是 u、v 及其绝对差| u v |的级联向量。我们使用交叉熵损失和 Adam 优化器对 QR-BERT 进行预训练。我们的实验表明,在 NLI 和 FactualNLI 上的预训练提高了检索召回率。

混合检索

在我们的实验中,当我们合并 BM25 检索器和 QR-BERT 的顶部结果,并使用二元相关性分类器对它们重新排序时,我们得到了最佳结果。我们使用 MSMARCO 数据集(如 Nogueira 等人的 monoBERT)训练了基于 BERT-large 的二元相关性分类器。

关于模型评估的更多细节可以在我们的论文中找到。

定性分析

下表显示了 QR-BERT 和 BM25 检索到的一些问题和主张的主要摘录:

QR-BERT 和 BM25 检索到的与新冠肺炎相关的查询片段

对于前两个查询,只有 QR-BERT 返回相关段落。这是因为基于关键字的检索不足以显示最相关的段落。对于第三个查询,两个模型都成功地检索到了相关的片段。对这个查询的一个有趣观察是,QR-BERT 检索到的片段只有单词病毒与查询相同。这表明该模型有能力捕捉文本的潜在含义,并识别同义词术语,如取消(对于取消)和语义相近的术语,如会议(接近事件)。

一般来说,当查询足够具体以允许通过关键字匹配容易地发现相关段落时,稀疏检索工作得很好。然而,这在实践中是不够的。我们的实验表明,密集检索模型可以给出更准确的结果,并且当在具有稀疏检索结合重新排序的架构中使用时,我们可以实现显著更高的召回率。

奎因系统

使用密集检索模型,我们开发了 Quin,这是一个可扩展的语义搜索引擎,可以返回最多五个句子的片段,包含与新冠肺炎疫情相关的问题或声明的答案。

Quin 语义搜索引擎

Quin 有一个模块用于抓取 RSS 提要,并存储新闻文章的 html 源代码。我们去掉样板文件,分离出新闻文章的主要内容。通过在每篇文章的句子序列上使用滑动窗口,我们从干净的文本中提取每篇文章的 5 个句子的片段。我们利用 nltk 库将文档分割成句子。为了促进高效的大规模检索,我们在片段上构建了两个索引:(a)用于 BM25 检索的高效稀疏倒排索引(关键字索引),以及(b)支持最大内积搜索的 FAISS 密集(语义)索引。

索引(左)和搜索(右)

该查询用于在片段的稀疏和密集(FAISS)索引上执行搜索。我们从每个索引中检索前 500 个结果,并计算每个结果的相关性分数。结果按照它们的相关性分数排序,我们输出最终排序的结果列表。当查询是一个语句时,我们有一个额外的步骤,使用 NLI 模型将检索到的段落分为三类,这样它们显示在三个选项卡下;所有支持反驳的证据。

除了新闻,Quin 还支持与新冠肺炎相关的研究论文的语义搜索。在撰写本文时,Quin 拥有超过 20 万篇与新冠肺炎相关的新闻文章和 10 万篇研究出版物的索引。我们希望这个系统将有助于对抗错误信息,并帮助一些研究人员寻找新冠肺炎的治疗方法。

[ 项目页面,[ 论文,[ 演示

用 fastText 和 BM25 建立句子嵌入索引

原文:https://towardsdatascience.com/building-a-sentence-embedding-index-with-fasttext-and-bm25-f07e7148d240?source=collection_archive---------7-----------------------

探索如何建立一个文本搜索系统

杰西卡·鲁斯切洛在 Unsplash 上的照片

本文涵盖了句子嵌入和code question1.0。最新发布的 codequestion 使用了句子转换器。 此处阅读更多

自然语言处理是机器学习领域中发展最快的领域之一。许多领域都在发生深度创新,让用户能够更快地找到更好的数据。曾经只有拥有大量 IT 预算和资源的人才能实现的技术和算法现在可以在笔记本电脑上运行。虽然 NLP 不是一个新问题,但是有一些经过时间考验的方法表现得非常好。最简单的方案很多时候可能是最好的方案。

本文将探索各种方法,并对构建文本搜索系统进行评估。

全文搜索引擎

允许用户输入搜索查询并找到匹配结果的全文搜索引擎是一种可靠的解决方案,具有很好的性能历史。在这些系统中,每个文档都被标记化,通常去掉一列常用词,称为停用词。这些令牌存储在倒排索引中,每个令牌都根据令牌频率等指标进行加权。

搜索查询也使用相同的方法进行标记化,并且搜索引擎为查询标记找到最佳匹配记录。有一些高度分布式且非常快速的解决方案已经在生产中证明了自己多年,比如 Elasticsearch 。今天最常见的令牌加权算法是 BM25 。它工作得非常好,仍然很难被击败。

嵌入

单词嵌入在过去的 5-7 年里发展迅速,首先从 Word2vec 开始,接着是 GloVefastText 。这些算法通常都构建 300 维向量。现在有了更高级的嵌入,它们的尺寸更大(768+维度),能够理解句子中单词的上下文,其中 BERT 嵌入处于领先地位。换句话说,超越简单的单词包方法。

易于使用、健壮的库已经存在,使开发人员能够利用这些进步。 HuggingFace Transformers 是一个优秀的库,拥有一组快速增长的前沿功能。通用句子嵌入是另一个重要的发展领域。拥有一个单一的动态模型,可以将文本转换为下游学习任务的嵌入是至关重要的。句子变形金刚构建在变形金刚之上,是一个可以构建高质量句子嵌入的库的优秀例子。

性能考虑因素

随着构建完美嵌入的步伐越来越快,这对试图解决当前业务问题的实践者来说意味着什么。你总是使用最新和最大的进步吗?你总是需要吗?有更复杂的权衡。当处理数百万甚至数十亿个数据点时,处理时间与可接受的功能之间的关系总是一个需要讨论的话题。这些对话考虑了可用的资源、可用的时间以及满足给定问题的要求所必需的内容。

评估文本搜索解决方案时要问的一些问题。

  • 我需要多快的查询响应和索引速度?需要多高的精确度?
  • 我可以访问哪些计算资源?我可以访问 GPU 吗?
  • 我有多少条记录和多少存储空间?假设向量使用 32 位(4 字节)浮点,一个 300 维的向量每条记录需要 300x4 字节。对于 4096 维向量,它是 4096x4,对于相同的数据,需要 13 倍多的空间。
  • 一个全文搜索引擎能满足要求吗?

我们在建造什么?

codequestion 是一个允许用户直接从终端询问编码问题的应用程序。许多开发人员在开发和运行 web 搜索时会打开一个 web 浏览器窗口,因为会出现问题。codequestion 致力于加快这一过程,以便您可以专注于开发。它还允许无法直接访问互联网或互联网访问受限的用户运行代码问题查询。下面是一个实际应用的例子。

codequestion 应用程序演示

codequestion 由一个 SQLite 数据库提供支持,该数据库存储了问答回复。提供了使用堆栈交换数据的预训练模型。该数据库还可以加载自定义的问题列表。

精心设计解决方案

最好总是从最简单的解决方案开始,然后一步一步往上走。我们能不能对数据做一个全文索引,然后就到此为止?添加外部文本索引并不是我们所希望的,因为这个应用程序被设计为本地安装在开发人员的机器上。SQLite 确实提供了一个名为 FTS5 的文本索引解决方案。这是很容易添加的,似乎工作得很好。但是一种测量结果的方法对于真正判断它的效果是必要的。

评估结果

构建了一个包含 100 个查询的数据集来判断一个索引的工作情况。对于每个查询,手动运行 web 搜索,并为该查询存储顶部堆栈交换结果。选择了流行的查询(即在 python 中解析日期),并注意不总是在查询和答案之间有直接的标记匹配。

平均倒数排名(MRR) 用于测量人工注释的搜索查询的最高结果得分。标准 FTS5 索引对 100 个查询数据集的评分如下。

MRR = 45.9

作为开始还不算太坏。是时候增加复杂性来决定权衡是否值得了。

BM25

SQLite 的 FTS5 默认令牌加权方案是使用 tf-idf 。它还支持 BM25,得分为:

MRR = 49.5

绝对是个进步。但感觉还是有很大的提升空间。让我们试试句子嵌入。

快速文本句子嵌入

标准文本标记搜索正被同义词和不完全匹配所困扰。单词嵌入是找到不完全匹配的相似结果的好方法。

所需功能的示例如下:

linux 解码音频文件查询

查询“linux 解码音频文件”返回了类似“通过 linux 命令行播放 mp3 或 wav 文件”的问题。单词 decode 和 audio 没有出现在返回的结果中,但是 decode 类似于 play,audio 类似于 mp3/wav。

上面的示例查询被标记为["linux "," decode "," audio "," file"]。可以使用 fastText 为每个标记检索单词嵌入。为了构建句子嵌入,嵌入可以被平均在一起以创建单个嵌入向量。

快速文本+ BM25

平均效果出奇的好。但是如果我们可以两全其美,使用 BM25 来衡量每个标记对句子嵌入的贡献有多大呢?这就是 codequestion 采用的方法。BM25 索引建立在数据集之上。使用预先训练的快速文本向量加上 BM25,得分为:

MRR = 66.1

比直 BM25 (66.1 比 49.5)有相当大的进步!

定制训练的快速文本嵌入

这种级别的功能是性能和结果的可接受组合。但还有最后一件事可以尝试,这可能会进一步提高分数,即在问题数据库本身上定制训练的 fastText 嵌入模型。使用根据数据分数训练的 fastText 嵌入,如下所示:

MRR = 76.3

又一次,相当大的进步。我们可以继续尝试 BERT 嵌入模型,该模型得分更高,但也需要更多计算/存储。fastText + BM25 不考虑顺序,所以类似“python convert UTC to localtime”的查询可以匹配“python convert localtime to UTC”。BERT 会更好地处理这个用例。但是对于这个项目,嵌入方法工作得很好。

构建索引

嵌入本身只是一堆数字。一旦完整的数据存储库被转换为句子嵌入,就需要有一种方法来为查询找到相似的结果。

余弦相似度是比较两个向量相似程度的常用方法。最简单的方法是强力比较查询向量和每个结果,并返回最相似的结果。对于小型数据集,这种方法很有效。但是随着数据的增长,它无法扩展。

Faiss 是一个向量相似性搜索库,可以在这方面提供帮助。它可以量化向量以减少存储量,并支持可扩展的近似最近邻搜索。Faiss 支持高性能搜索,提供结果准确性和速度的良好结合。

结论

本文介绍了一种评估如何构建搜索系统的方法,从而产生一个句子嵌入索引。这条路不会总是通向同一个终点,但是像这样的渐进方法应该有助于找到问题的最佳解决方案。

使用 Scikit-Learn 构建情感分类器

原文:https://towardsdatascience.com/building-a-sentiment-classifier-using-scikit-learn-54c8e7c5d2f0?source=collection_archive---------6-----------------------

训练线性模型以将 IMDb 电影评论分类为正面或负面

Image by absolute vision @

情感分析是自然语言处理中的一个重要领域,是自动检测文本情感状态的过程。情感分析广泛应用于客户的声音材料,如亚马逊等在线购物网站的产品评论、电影评论或社交媒体。这可能只是一个将文本的极性分类为正/负的基本任务,或者它可以超越极性,查看情绪状态,如“快乐”、“愤怒”等。

在这里,我们将建立一个分类器,能够区分电影评论是正面还是负面的。为此,我们将使用 IMDB 电影评论的大型电影评论数据集 v 1.0【2】。该数据集包含 50,000 条电影评论,平均分为 25k 训练和 25k 测试。标签在两个类别(阳性和阴性)之间保持平衡。分数为<= 4/10 的评论被标记为负面,分数为>= 7/10 的评论被标记为正面。中性评论不包括在标记的数据中。该数据集还包含用于无监督学习的未标记评论;我们不会在这里使用它们。对一部特定电影的评论不超过 30 条,因为同一部电影的评级往往是相关的。给定电影的所有评论或者在训练集中或者在测试集中,但是不在两者中,以避免通过记忆电影特定的术语来获得测试准确度。

数据预处理

在数据集被下载并从档案中提取出来后,我们必须将其转换为更合适的形式,以便输入到机器学习模型中进行训练。我们首先将所有的审查数据组合成两个 pandas 数据帧,分别代表训练和测试数据集,然后将它们保存为 csv 文件: imdb_train.csvimdb_test.csv

数据帧将具有以下形式:

其中:

  • 评论 1,评论 2,… =电影评论的实际文本
  • 0 =负面评价
  • 1 =正面评价

但是机器学习算法只能处理数值。我们不能只是将文本本身输入到机器学习模型中,然后让它从中学习。我们必须,以某种方式,用数字或数字向量来表示文本。一种方法是使用单词袋模型[3],其中一段文本(通常称为文档)由该文档词汇表中单词计数的向量表示。这个模型没有考虑语法规则或单词排序;它所考虑的只是单词的频率。如果我们独立地使用每个单词的计数,我们将这种表示命名为单字。一般来说,在一个 n-gram 中,我们考虑出现在给定文档中的词汇表中 n 个单词的每个组合的计数。

例如,考虑这两个文档:

这两个句子中遇到的所有单词的词汇是:

d1 和 d2 的单字表示:

d1 和 d2 的二元模型是:

通常,如果我们使用所谓的术语频率乘以逆文档频率(或 tf-idf )来代替字数,我们可以获得稍微好一点的结果。也许听起来很复杂,但事实并非如此。耐心听我说,我会解释的。这背后的直觉是这样的。那么,在文档中只使用术语的频率会有什么问题呢?尽管一些术语在文档中出现的频率很高,但它们可能与描述出现它们的给定文档不太相关。这是因为这些术语也可能在所有文档集合中出现频率很高。例如,电影评论的集合可能具有出现在几乎所有文档中的特定于电影/电影摄影的术语(它们具有高的文档频率)。因此,当我们在文档中遇到这些术语时,这并不能说明它是积极的还是消极的评论。我们需要一种方法将术语频率(一个术语在文档中出现的频率)与文档频率(一个术语在整个文档集合中出现的频率)联系起来。那就是:

现在,有更多的方法用来描述术语频率和逆文档频率。但最常见的方法是将它们放在对数标度上:

其中:

我们在第一个对数中添加了 1,以避免在计数为 0 时得到-∞。在第二个对数中,我们添加了一个假文档以避免被零除。

在我们将数据转换成计数或 tf-idf 值的向量之前,我们应该删除英文的停用词[ 6][7]。停用词是在语言中非常常见的词,通常在自然文本相关任务(如情感分析或搜索)的预处理阶段被移除。

请注意,我们应该只基于训练集来构建我们的词汇表。当我们处理测试数据以进行预测时,我们应该只使用在训练阶段构建的词汇,其余的单词将被忽略。

现在,让我们创建数据框并将其保存为 csv 文件:

文本矢量化

幸运的是,对于文本矢量化部分,所有困难的工作都已经在 Scikit-Learn 类CountVectorizer【8】和TfidfTransformer【5】中完成了。我们将使用这些类将 csv 文件转换成 unigram 和 bigram 矩阵(使用计数和 tf-idf 值)。(事实证明,如果我们只对大 n 使用 n 元语法,我们不会获得很好的准确性,我们通常使用所有 n 元语法,直到某个 n。因此,当我们在这里说二元语法时,我们实际上是指 uni+二元语法,当我们说 unigrams 时,它只是一元语法。)这些矩阵中的每一行将代表我们数据集中的一个文档(review ),每一列将代表与词汇表中的每个单词相关联的值(在单字的情况下)或与词汇表中最多两个单词的每个组合相关联的值(双字)。

CountVectorizer有一个参数ngram_range,它需要一个大小为 2 的元组来控制包含什么 n 元语法。在我们构造了一个CountVectorizer对象之后,我们应该调用.fit()方法,将实际的文本作为参数,以便让它学习我们收集的文档的统计数据。然后,通过对我们的文档集合调用.transform()方法,它返回指定的 n-gram 范围的矩阵。正如类名所示,这个矩阵将只包含计数。为了获得 tf-idf 值,应该使用类TfidfTransformer。它有.fit().transform()方法,使用方式与CountVectorizer类似,但它们将前一步获得的计数矩阵作为输入,而.transform()将返回一个带有 tf-idf 值的矩阵。我们应该只在训练数据上使用.fit(),然后存储这些对象。当我们想要评估测试分数或者每当我们想要做出预测时,我们应该在将数据输入到我们的分类器之前使用这些对象来转换数据。

请注意,为我们的训练或测试数据生成的矩阵将是巨大的,如果我们将它们存储为普通的 numpy 数组,它们甚至不适合 RAM。但是这些矩阵中的大部分元素都是零。因此,这些 Scikit-Learn 类使用 Scipy 稀疏矩阵[9] ( csr_matrix [10]更准确地说),它只存储非零条目,节省了大量空间。

我们将使用具有随机梯度下降的线性分类器sklearn.linear_model.SGDClassifier【11】作为我们的模型。首先,我们将以 4 种形式生成和保存我们的数据:unigram 和 bigram 矩阵(每个都有计数和 tf-idf 值)。然后,我们将使用带有默认参数的SGDClassifier来训练和评估这 4 种数据表示的模型。之后,我们选择导致最佳分数的数据表示,并且我们将使用交叉验证调整具有该数据形式的模型的超参数,以便获得最佳结果。

选择数据格式

现在,对于每个数据表单,我们将其分成训练和验证集,训练 a SGDClassifier并输出分数。

这是我们得到的结果:

*Unigram Counts
Train score: 0.99 ; Validation score: 0.87

Unigram Tf-Idf
Train score: 0.95 ; Validation score: 0.89

Bigram Counts
Train score: 1.0 ; Validation score: 0.89

Bigram Tf-Idf
Train score: 0.98 ; Validation score: 0.9*

最好的数据形式似乎是带有 tf-idf 的 bigram,因为它获得了最高的验证精度:0.9;我们接下来将使用它进行超参数调整。

使用交叉验证进行超参数调整

对于这一部分,我们将使用RandomizedSearchCV [12],它从我们给出的列表中随机选择参数,或者根据我们从scipy.stats指定的分布(例如均匀);然后,通过进行交叉验证来估计测试误差,在所有迭代之后,我们可以在变量best_estimator_best_params_best_score_中找到最佳估计值、最佳参数和最佳得分。

因为我们想要测试的参数的搜索空间非常大,并且在找到最佳组合之前可能需要大量的迭代,所以我们将参数集分成两部分,并分两个阶段进行超参数调整过程。首先我们会找到 loss、learning_rate 和 eta0(即初始学习率)的最优组合;然后是惩罚和α。

我们得到的输出是:

*Best params: {'eta0': 0.008970361272584921, 'learning_rate': 'optimal', 'loss': 'squared_hinge'}
Best score: 0.90564*

因为我们得到了“learning_rate = optimal”是最好的,那么我们将忽略 eta0(初始学习率),因为当 learning_rate='optimal '时它没有被使用;我们得到这个值 eta0 仅仅是因为这个过程中的随机性。

*Best params: {'alpha': 1.2101013664295101e-05, 'penalty': 'l2'}
Best score: 0.90852*

所以,我得到的最佳参数是:

*loss: squared_hinge
learning_rate: optimal
penalty: l2
alpha: 1.2101013664295101e-05*

保存最佳分类器

测试模型

并且得到了 90.18% 的测试准确率。这对于我们简单的线性模型来说是不错的。有更先进的方法可以给出更好的结果。该数据集目前的最新水平是 97.42% [13]

参考

[1] 情感分析—维基百科
【2】用于情感分析的学习词向量
【3】词袋模型—维基百科
【4】Tf-IDF—维基百科
【5】TfidfTransformer—Scikit—学习文档
【6】停用词—维基百科
【7】A 压缩稀疏行矩阵
【11】SGD classifier—sci kit—learn 文档
【12】RandomizedSearchCV—sci kit—learn 文档
【13】使用余弦相似度训练的文档嵌入进行情感分类

朱庇特笔记本可以在这里找到。

我希望这些信息对你有用,感谢你的阅读!

这篇文章也贴在我自己的网站这里。随便看看吧!

使用 ML.NET 和 Azure 函数构建无服务器机器学习 API

原文:https://towardsdatascience.com/building-a-serverless-machine-learning-api-using-ml-net-and-azure-functions-ad3b24751106?source=collection_archive---------21-----------------------

构建无服务器 API 的回顾性学习,该 API 使用 ML 构建的回归模型。网

更新: 你现在可以从 Azure Serverless 社区网站 下载这个项目的完整样本 !(如果你想进一步探索 Azure 函数,还有一些很棒的例子!)

随着 ML.NET(API)的发布,C#开发人员可以用它来为他们的应用程序注入机器学习能力,我一直热衷于将我对 Azure 函数的知识与 API 结合起来,构建一些古怪的无服务器机器学习应用程序,这将允许我增强我的 GitHub 档案,并迎合所有的时髦爱好者!

[## ML。NET 文档-教程,API 参考

了解如何使用开源 ML.NET 来构建定制的机器学习模型,并将它们集成到应用程序中。教程…

docs.microsoft.com](https://docs.microsoft.com/en-us/dotnet/machine-learning/)

(当然,也是为了提高自己的技能和学习新的东西😂)

这个帖子不会是教程。我写这篇文章更多的是回顾我在构建应用程序时所做的设计决策,以及我所学到的关于不同组件如何工作的东西。如果你读了这篇文章,并决定在你的现实世界中应用它,希望你能在你的项目中应用我学到的东西,或者更好的是,扩展我正在处理的想法和场景。

我将更多地关注我对 ML.NET API 本身的了解,而不是花太多时间在 Azure 函数如何工作上。如果你想得到这个代码,这里有 GitHub 上的回购。

因为我做这个项目只是为了一点乐趣,我确实采取了一些在现实生活中不起作用的捷径,所以请对此表示同情(我相信你会的😊).

应用概述。

这个例子建立在 ML.NET 团队在其文档中提供的出租车旅行回归教程的基础上。但是对于这个示例,我已经针对下面的场景对该教程进行了一点扩展。

假设我们经营一家出租车公司,每天晚上我们都会收到一份全天出租车行程的文件。我们希望建立一个回归模型,让我们的客户可以用它来预测他们打车的费用。

为此,我构建了两个 Azure 函数:

  1. ServerlessPricePredictor。ModelTrainer 获取一个本地 CSV 文件,并在其基础上训练一个回归模型。如果模型非常适合(使用 R 平方值),那么模型将被上传到 Azure Blob 存储中的容器。该函数使用定时器触发器来模拟定时批处理作业。
  2. ServerlessPricePredictor。API 然后在一个 HTTP 触发器中使用 Azure Blob 存储中训练好的模型来创建基于输入数据(JSON 有效负载)的预测,并将该预测插入 Azure Cosmos DB。

模特训练器功能

在 MLContext,创建我们的机器学习管道所需的所有操作都是通过 MLContext 类提供的。这允许我们执行数据准备、特征工程、训练、预测和模型评估。

为了让我们加载数据来训练我们的回归模型,model 为我们提供了一个 IDataView 类来描述数字或文本表格数据。IDataView 类为我们提供了一个加载数据文件的方法,我只是将数据文件放在项目的一个文件夹中。

然后,我们可以使用 MLContext 类来执行我们的机器学习任务。首先,我使用 LoadFromTextFile 方法将本地文件加载到 IDataView 对象中。然后,为了创建我们的管道,我已经确定我想使用我们的 FareAmount 列作为我们的标签,我们希望我们的回归模型预测,我已经对我们的 VendorId、RateCode 和 PaymentType 列应用了一个热编码(因为这是一个回归模型,我们对分类值应用了一个热编码,以将它们转换为数值),然后我已经将我想使用的所有特性连接到一个特性列中。之后,我在我的管道上应用了一个回归任务。

我以前玩过一点 Spark MLlib 库,所以在 ML.NET 的过程非常相似,我认为这很酷!😎

最后,我创建了一个it transformer的模型对象,将我们的管道安装到 IDataView 对象上。

// Read flat file from local folder_logger.LogInformation("Loading the file into the pipeline");IDataView dataView = mlContext.Data.LoadFromTextFile<TaxiTrip>(trainFilePath, hasHeader: true, separatorChar: ',');// Create the pipeline_logger.LogInformation("Training pipeline");var pipeline = mlContext.Transforms.CopyColumns(outputColumnName: "Label", inputColumnName: "FareAmount").Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "VendorIdEncoded", inputColumnName: "VendorId")).Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "RateCodeEncoded", inputColumnName: "RateCode")).Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "PaymentTypeEncoded", inputColumnName: "PaymentType")).Append(mlContext.Transforms.Concatenate("Features", "VendorIdEncoded", "RateCodeEncoded", "PassengerCount", "TripDistance", "PaymentTypeEncoded")).Append(mlContext.Regression.Trainers.FastTree());// Fit the model_logger.LogInformation("Fitting model");var model = pipeline.Fit(dataView);

我用 LoadColumnAttribute 修饰了我的类属性,它指定了数据集中列的索引:

public class TaxiTrip{[LoadColumn(0)]public string VendorId;[LoadColumn(1)]public string RateCode;[LoadColumn(2)]public float PassengerCount;[LoadColumn(3)]public float TripTime;[LoadColumn(4)]public float TripDistance;[LoadColumn(5)]public string PaymentType;[LoadColumn(6)]public float FareAmount;}

对于我们的预测,我创建了另一个使用 ColumnNameAttribute 装饰的类。这允许我们使用 FareAmount 属性(这是我们试图创建预测的属性)来生成我们的分数。

public class TaxiTripFarePrediction{[ColumnName("Score")]public float FareAmount;}

在现实世界的机器学习场景中,我们不会只部署我们不知道表现良好或非常适合我们的数据的模型。

ML.NET API 为我们提供了可以用来评估模型有效性的指标。我创建了下面的 Evaluate()方法,它接受 MLContext、我们的模型和测试数据文件:

private double Evaluate(MLContext mlContext, ITransformer model, string testFilePath){IDataView dataView = mlContext.Data.LoadFromTextFile<TaxiTrip>(testFilePath, hasHeader: true, separatorChar: ',');var predictions = model.Transform(dataView);var metrics = mlContext.Regression.Evaluate(predictions, "Label", "Score");double rSquaredValue = metrics.RSquared;return rSquaredValue;}

在这里,我将测试数据加载到 IDataView 对象中,然后使用我的模型对该数据进行转换。这里的 Transform() 方法实际上并不做任何转换,它只是根据测试的模型来验证我的测试文件的模式。

对于这个例子,我只是使用 r 平方值来测试我的模型的有效性,但是 RegressionMetrics 类允许我们为我们的回归模型检索 LossFunctionmeansabsoluteerrormeansquadererrorrootmeansquadererrorRSquared 值。

一旦我们的模型产生了我们的 r 平方指标,并且提供了显示它非常适合的分数,我们就将模型的 zip 文件上传到 Azure Storage:

if (modelRSquaredValue >= 0.7){_logger.LogInformation("Good fit! Saving model");mlContext.Model.Save(model, dataView.Schema, modelPath);// Upload Model to Blob Storage_logger.LogInformation("Uploading model to Blob Storage");await _azureStorageHelpers.UploadBlobToStorage(cloudBlobContainer, modelPath);}

这里的重点是,我首先保存我的模型,然后将其作为文件上传到 Azure Storage。我们使用 MLContext 保存模型。Model.Save 行,它接受我们的模型、IDataView 对象的模式以及我们希望保存模型的路径。我已经创建了自己的助手类,将我保存的模型上传到 Azure Storage 中指定的 blob 容器。

(注意:我尝试过将模型上传为流而不是文件,但是当我试图将模型注入 HTTP 触发函数或 ASP.NET Web API 应用程序时,我总是会遇到问题。总有一天我会弄明白,或者,更有可能的是,某个比我聪明的人会告诉我哪里做错了😂)

在 HTTP API 函数中使用我们的模型

如果我们想在我们的 API 中进行预测,我们需要创建一个预测引擎。本质上,这允许我们使用训练好的模型进行单一预测。然而,这并不是线程安全的,所以我使用了一个 PredictionEnginePool,并将它注入到我的启动类中,这样我们的应用程序中就有了一个它的单例实例。如果我们在 API 函数应用程序中跨几个函数进行预测,我们需要为每个预测创建 PredictionEnginePool 的实例,这将是一场管理噩梦。我是这样做的:

builder.Services.AddPredictionEnginePool<TaxiTrip, TaxiTripFarePrediction>().FromUri(modelName: "TaxiTripModel",uri: "https://velidastorage.blob.core.windows.net/mlmodels/Model.zip",period: TimeSpan.FromMinutes(1));

在这里,我们调用我们的模型,该模型远程存储在 Azure Blob 存储中。period 参数定义了我们轮询新模型的 uri 的频率。模型不应该是静态的,所以您可以使用这个参数来设置您希望应用程序轮询新模型的频率。

一旦我们将其注入到我们的应用程序中,我们就可以使用我们的预测引擎池来预测我们的请求:

string requestBody = await new StreamReader(req.Body).ReadToEndAsync();var input = JsonConvert.DeserializeObject<TaxiTrip>(requestBody);// Make PredictionTaxiTripFarePrediction prediction = _predictionEnginePool.Predict(modelName: "TaxiTripModel",example: input);

这里的 Predict() 方法允许我们对 JSON 输入进行一次预测。我们定义了我们希望使用的模型,使用的名称与我们将它注入到应用程序中时给它的名称相同。

在本例中,我基于输入数据创建新的预测,然后将新的预测值插入到一个 Cosmos DB 容器中:

[FunctionName(nameof(PredictTaxiFare))]public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "PredictTaxiFare")] HttpRequest req){IActionResult returnValue = null;string requestBody = await new StreamReader(req.Body).ReadToEndAsync();var input = JsonConvert.DeserializeObject<TaxiTrip>(requestBody);// Make PredictionTaxiTripFarePrediction prediction = _predictionEnginePool.Predict(modelName: "TaxiTripModel",example: input);var insertedPrediction = new TaxiTripInsertObject{Id = Guid.NewGuid().ToString(),VendorId = input.VendorId,RateCode = input.RateCode,PassengerCount = input.PassengerCount,TripTime = input.TripTime,TripDistance = input.TripDistance,PaymentType = input.PaymentType,FareAmount = input.FareAmount,PredictedFareAmount = prediction.FareAmount};try{ItemResponse<TaxiTripInsertObject> predictionResponse = await _container.CreateItemAsync(insertedPrediction,new PartitionKey(insertedPrediction.VendorId));returnValue = new OkObjectResult(predictionResponse);}catch (Exception ex){_logger.LogError($"Inserting prediction failed: Exception thrown: {ex.Message}");returnValue = new StatusCodeResult(StatusCodes.Status500InternalServerError);}return returnValue;}

听起来很棒!我需要什么才能让这个样本自己工作?

如果你想自己开发(或者扩展)这个应用,你可以创建一个 Azure 存储账户,里面有一个你可以上传模型的容器。查看这篇文章,看看你如何做到这一点。您还需要创建一个使用 SQL API 的 Cosmos DB 帐户。查看这篇文章来开始吧。

你可以使用 Visual Studio 在本地运行 Azure 函数,也可以使用 Postman 在你的机器上测试 API。

结论

我希望你已经了解了一些关于 ML.NET 图书馆的知识,以及如何使用它来构建基本但非常棒的无服务器机器学习解决方案。记住我说的是基础。为了这篇博文,我确实走了一些捷径,但是在生产场景中这样做要复杂得多。但是这是可行的,ML.NET 是一个很好的库,如果你已经在使用。NET 堆栈。

如果你想看完整的代码,请到 GitHub 查看。如果你对我有任何问题,请在下面评论。😊

建立一个浅层神经网络

原文:https://towardsdatascience.com/building-a-shallow-neural-network-a4e2728441e0?source=collection_archive---------13-----------------------

解释了理论和实现

一个隐藏层神经网络

我们将构建一个具有一个隐藏层的浅层密集神经网络,以下结构用于说明目的。

在试图理解这篇文章之前,我强烈建议你看一下我之前的逻辑回归的实现,因为逻辑回归可以看作是一个 1 层神经网络,基本概念实际上是相同的。

其中在上图中,我们有一个输入向量 x = (x_1,x_2),包含 2 个特征和 4 个隐藏单元 a1、a2、a3 和 a4,并在[0,1]中输出一个值 y_1。(考虑这是一个带有概率预测的二元分类任务)

在每个隐单元中,以 a_1 为例,进行一个线性运算,然后是一个激活函数。因此,给定输入 x = (x_1,x_2),在节点 a_1 内,我们有:

这里 w_{11}表示节点 1 的权重 1,w_{12}表示节点 1 的权重 2。对于节点 a_2 也是如此,它应该有:

a3 和 a4 也是如此,以此类推…

一个输入的矢量化

现在让我们将权重放入矩阵并输入到向量中,以简化表达式。

这里我们假设第二激活函数为tanh,输出激活函数为sigmoid(注意上标[i]表示第 I 层)。

对于每个矩阵的维数,我们有:

单个值的损失函数 L 将与逻辑回归的损失函数相同(此处详细介绍)。

功能tanhsigmoid如下图所示。

请注意,这些函数的唯一区别是 y 的比例。

批量训练公式

上面显示了单个输入向量的公式,但是在实际训练过程中,一次训练一批而不是一个。公式中应用的更改是微不足道的,我们只需用大小为n x m的矩阵 X 替换单个向量 X,其中 n 是特征数量,m 是批量大小——样本按列堆叠,同样应用以下结果矩阵。

对于本例中每个矩阵的维数,我们有:

与逻辑回归相同,对于批量训练,所有训练样本的平均损失。

这都是为了正向传播。为了激活我们的神经元进行学习,我们需要获得权重参数的导数,并使用梯度下降来更新它们。

但是现在我们先实现正向传播就足够了。

生成样本数据集

这里,我们生成一个简单的二元分类任务,包含 5000 个数据点和 20 个特征,用于以后的模型验证。

权重初始化

我们的神经网络有 1 个隐层,总共 2 层(隐层+输出层),所以有 4 个权重矩阵要初始化(W[1],b[1]和 W[2],b[2]).注意,权重被初始化得相对较小,因此梯度会更高,从而在开始阶段学习得更快。

正向传播

让我们按照等式(5)至(8)实现正向过程。

损失函数

根据等式(9),每批的损耗可计算如下。

反向传播

现在到了反向传播,这是我们的权重更新的关键。给定我们上面定义的损失函数 L,我们有如下梯度:

如果你不明白为什么 Z^[2 的导数如上,你可以在这里查看。事实上,我们网络的最后一层与逻辑回归相同,所以导数是从那里继承的。

方程(4)中是元素式乘法,tanh{x}的梯度是 1 — x,你可以试着自己推导上面的方程,不过我基本上是从网上拿来的。

让我们分解每个元素的形状,给定每层的数量等于(n_x, n_h, n_y),批量等于m:

一旦我们理解了这个公式,实现起来就会很容易。

批量训练

我将每个部分都放在一个类中,这样它就可以像 python 的通用包一样训练。此外,还实施批量训练。为避免冗余,我没有放在这里,详细实现请查看我的 git repo

让我们看看我们实现的神经网络在数据集上的表现。

使用 10 个隐藏神经元,我们的模型能够在测试集上达到 95.1%的准确率,这是非常好的。

现在继续尝试实现你自己,这个过程将真正帮助你获得对一般密集神经网络的更深理解。

通过决策树构建一个简单的自动编码器

原文:https://towardsdatascience.com/building-a-simple-auto-encoder-via-decision-trees-28ba9342a349?source=collection_archive---------10-----------------------

自动编码器

如何使用随机决策树构建自动编码器

我可爱的妻子蒂娜蒂·库伯勒

决策树是非常通用的结构。您可以使用它们进行分类和回归( CART、随机森林、… ),用于异常检测(隔离森林、… ),正如我们将看到的,还可以用于构建自动编码器、以及其他构造。

声明:我没有想出这个主意。这种新的基于树的自动编码器是由吉峰和周志华[1]提出的,被称为“forest”。他们在 AAAI 18 上展示了他们的作品。

然而,我认为这篇论文在如何从潜在空间中解压元素方面缺乏一些清晰度,我将在本文中解决这个问题。我还将简单介绍用于制作森林的所有材料。

所以,在我们开始之前,让我们快速回顾一下什么是决策树和自动编码器。

重要概念的高度概括

决策树

决策树是一种将来自一个 n 维特征空间的一组样本聚类到不同箱中的方法。这是通过检查样本的 n 特征上的某些约束来完成的。

以特征空间 X = ℝ×ℝ×{0,1}×{A,b,C},以及生活在 X 内的样本 (1.7,4.3,0,a),(2.2,3.6,1,b),(3.5,2.6,0,C)(4.1,1.9,1,A) 为例。我构建了一个示例决策树来将这些样本分类到四个箱中。也许下面这张图甚至是不言自明的,即使你以前从未听说过决策树:

决策树。在每个节点(蓝色菱形)中,样本集被分成两个不相交的子集,这取决于某个特征是否满足特殊要求。例如,在 bin 4 中,我们可以找到第一个坐标严格大于 4,最后一个坐标为 A 或 C (=非 B)的所有样本。

最后,四个样本被分类到四个容器中。由于单个样本不能同时采用两个路径(一个特征不能小于或等于 4 严格大于 4),每个样本被准确分类到一个箱中。

自动编码器

自动编码器基本上是有损压缩算法。它们允许用更少的位来表示数据,从而节省了存储空间。它还使用这些压缩样本来加速(机器学习)算法,因为较短的输入大小通常会导致较短的运行时间。

自动编码器由两种算法组成:

  • 编码器:通过去除冗余和噪声来压缩数据。
  • 解码器:尝试从压缩形式恢复原始数据。

更准确地说,编码器将样本从 n 维特征空间投影到其在 m 维所谓的潜在空间中的压缩形式,其中 m < n.

解码器从第 m 维潜在空间中提取样本,并将其再次解压缩到第 n 维特征空间中。

一个好的自动编码器应该能够

  1. 取样 x
  2. 将其压缩为 x' = e(x)
  3. 并将其再次解压缩到性质为x≈x″= d(e(x))的x″= d(x′)

这意味着包装和打开样品 x 不会对其造成太大的改变。当然,这应该适用于特征空间的任何 x

通常,我们不能期望得到 x. 的完美重建,例如 n=1m=0 (即潜在空间仅由单个点x’组成)。两个不同的样品 x₁x₂ 将被任何编码器送到潜在空间的同一点x’。所以,在最好的情况下,任何解码器只能恢复x’x₁x₂ ,因此得到一个解码错误。如果x’被解压缩到某个其他的 x ,解码器甚至会将两个样本都弄错。

自动编码器的一个受欢迎的代表是主成分分析 ( PCA ),它将数据从 n 线性映射到 m 维度,然后反向映射,尽管人们通常只使用编码器来降低数据的维度。

一个玩具例子:eTree

现在让我们看看如何用决策树构建一个自动编码器。我声称我们已经在本文中看到了一个 eForest 映射到一个 1 维的潜在空间!姑且称之为 eTree

编码

滚动回决策树示例图片,或者让我来帮你做:

上图的快捷方式。真的,又是同一个决策树。

我们看到四个样本中的每一个都被分类到四个箱中的一个。

核心思想是使用样本映射到的 bin 的编号作为编码。

所以 (1.7,4.3,0,A)**(2.2,3.6,1,B) 被编码为 1, (3.5,2.6,0,C) 被编码为 2, (4.1,1.9,1,A) 被编码为 4,或者简而言之:
e((1

很简单,对吧?

当我们想再次解码这个数字时,问题就出现了。

解码

在[1]中,作者引入了规则和所谓的 MCRs 来进行解码概念不难,但一开始我发现从纸上很难理解。所以,我来换个角度解释一下。

让我们假设我们得到编码 1,即从特征空间有一个 x ,其中 e 是 eTree 编码器。沿着通向 bin 1 的唯一路径,我们获得关于输入 x. 的我称之为的线索

在 1 号仓着陆需要

  1. 线索 1: X₁ 小于等于 4 且
  2. 线索二: X₂ 要大于等于 3,

也就是说,我们知道 x 看起来像这样:

或者,更准确地说,我们可以推断

然后,我们必须从这个潜在候选集中挑选任何元素,并将其用作解码。我们可以用确定性或概率性的方法来做这件事,这并不重要。

[1]中也使用的一种方法是最小选择。只取每个集合的最小值,如果集合是没有最小值的区间,就取它的右界。使用这个确定性规则,我们将解码 1 到 (4,3,0,A) (假设 A < B < C )。其他简单的方法包括选择最大值或平均值,或者从集合中随机抽样。

在我们的例子中,解码 1 的潜在候选集合相当大,因此我们可以预期重构相当糟糕。解决这个问题的一个方法是让树变得更深,也就是使用更多的分裂。更多的分裂产生更多的线索,进而产生更小的候选集。让我们在玩具示例中再使用一个拆分:

多一层的玩具树。编码现在可以采用从 1 到 5 的值。

这里,编码 1 将被解码成

这为现在搞乱第一特征留下了更少的空间,给出了更低的重建误差。改善解码的其他方法是嵌入关于特征空间的知识,例如,有时特征总是大于零或小于一些界限,如 1 或 255(图片数据),因此我们可以移除无限或负无限的界限。

但是让决策树越来越深不是可持续的解决方案,因为我们会遇到过度拟合的问题,就像在回归和分类任务中一样。然而,到目前为止,我们仍然只使用一维!那么,我们能做什么呢?

埃弗斯特

让我们并行连接更多的决策树进行编码!那么每一棵树给我们一个潜在空间的维度,每棵树的箱数就是特征值。考虑以下 3 棵树的例子:

一个由三棵决策树组成的 Forest。加粗的箭头表示 x 选择的路径。

三个决策树中的每一个都给了我们一个潜在空间的坐标,在这个例子中是 3。在我们的例子中,潜在的每个特征可以是 1、2、3 或 4。但是一般来说,如果每个决策树有不同数量的箱也没问题。

所以,让我们想象我们的输入 x 在潜在空间中被编码为 (2,1,1) ,我们现在希望解码它。我们只需要再次收集所有的线索,并把它们放在一起,以创建一个潜在的候选人集。

线索是:

  • 从树 1,bin 2:
    • X₁ 小于或等于 4 - X ₂小于 3
  • 从树 2,bin 1:
    • X₁ 大于或等于 2-
      x
      ₃等于 0
  • 从树 3,bin 1:
    • X₄ 等于 C
    • X ₂大于 1

把所有东西放在一起给了我们

所以最小解码会给我们 d(x)=(2,1,0,C)。

这几乎是理解森林的全部内容!现在仍然缺少的是如何实际训练 eForest ,但这是一个简短的问题:

使用随机决策树,即使用随机特征和随机分界点(来自合理范围)进行分裂的树。

我也是这样编造例子的。没有复杂的算法。

现在,让我们转到一些实验,看看它们在性能方面是否有任何优势。

实验

[1]的作者进行了几项实验,其中包括 CNN 自动编码器大放异彩的图像编码。我将直接粘贴[1]中的结果、表格和图像。

你可以在 GitHub 上找到用于实验的代码。

数据集是具有 28x28x1=784 特征(1 个颜色通道)的经典 MNIST 和具有 32x32x3=3072 特征(3 个颜色通道)的 CIFAR-10。

关于实验中使用的自动编码器

MLP 是使用几个线性层的“正常”自动编码器。确切的规格可以从[1]中得到,但是 MLP₁使用 500 维的潜在空间和 1000 维的 MLP₂。
CNN-AE 是一个卷积自动编码器,即它在内部使用卷积。它遵循本规范。SWW AE 是一个更好的 CNN-AE。eForestˢ₅₀₀也是一家使用样品标签的林业公司,我们在这里没有涉及。它将输入数据压缩到 500 个特征(下标 1000 将其压缩到 1000 个维度)。最后,eForestᵘ₅₀₀是本文所讨论的森林。下标数字再次表示潜在空间的维度。

重建误差

结果看起来很有希望!MNISt 和 CIFAR-10 数据集的重建误差非常低。来自[1]:

原始测试样本(第一行)和重构样本。

但是,人们必须进行进一步的实验,以检查 eForests 是否过度拟合。至少作者复用了的模型,并最终得到了好的结果,这是一个很好的指标,表明 eForest 推广得很好,而不仅仅是用心学习训练样本。模型重用意味着在一个训练集上训练一个模型,并在不同的训练集上评估它。

原始测试样本(第一行)和重构样本。所有模型都在一些训练集上进行了训练,并在不同的训练集上进行了测试!使用 eForests 时,结果看起来不错。

我只是不明白,当原始数据只有 28*28=784 维时,作者为什么要为 MNIST 数据集使用 1000 维的潜在空间。在我看来,使用 500 维会更有意义。但是,即使我们使用这种人为的设置:eForest 比其他方法执行得更好,neark 实现了无损压缩,这也是我所期望的。

计算效率

与其他方法相比,训练时间非常短。然而,根据作者的说法,编码和解码需要更多的时间,这仍然有优化的空间。来自[1]:

我的概念验证实施

由于算法相当简单,我尝试自己实现。我甚至不用从头开始,因为编码器已经自带了 scikit-learn 类型的

randomtreesemleding也创建了许多随机决策树,并根据输入的位置对它们进行编码 x 。然而,它们使用二进制编码,这增加了潜在的空间维度。使用我的具有三棵树和每棵树 4 个箱的例子,编码将是 (0,1,0,0 | 1,0,0,0 | 1,0,0) 而不是 (2,1,1),即潜在空间将具有 12 的维度,而不是只有 3 个。但是一旦知道了每棵树的叶子数量,将二进制表示转换成每棵树的一个数字就很容易了。幸运的是,scikit-learn 为我们提供了一个方法。

因此,实现编码部分很简单!也可以从我代码中的短encode方法看出来。这仅仅是

output = self.random_trees_embedding.transform(X)
indices = []
start = 0
for estimator in self.random_trees_embedding.estimators_:
    n_leaves = estimator.get_n_leaves()
    indices.append(output[:, start:start + n_leaves].argmax(axis=1))
    start = start + n_leaves
return np.array(indices).transpose()

解码花了我更多的时间,这也是我效率低下的方式,请原谅我!😄,我只是需要一个快速的概念验证。

你可以在这里找到我的代码。请随意改进!

我的图形结果:

我认为重建看起来很好,所以可能我的解码工作。但是,请在使用这些代码进行任何有成效的工作之前,先检查一下这些代码。

如果你想要真正的交易,去官方克隆的 GitHub 上工作。但是要准备好创建一个虚拟环境并手动修补一些 scikit-learn 文件。

结论

我们已经看到了如何用决策树构建一个自动编码器。这是一个自动编码器,具有独特的,但易于理解的设计,可以训练得非常快。此外,重构精度可以与成熟的卷积自动编码器相媲美。

另一方面,编码和解码速度仍然很低,并且必须在野外的真实数据集上测试 eForest。也许你可以写一篇关于它的文章。😃

参考

[1]冯军,周志军,森林自动编码器 (2017),第 32 届人工智能大会

我希望你今天学到了新的、有趣的、有用的东西。感谢阅读!

作为最后一点,如果你

  1. 想支持我多写点机器学习和
  2. 无论如何,计划获得一个中等订阅,

为什么不通过此链接?这将对我帮助很大!😊

说白了,给你的价格不变,但大约一半的订阅费直接归我。

非常感谢,如果你考虑支持我的话!

如有任何问题,请在 LinkedIn 上给我写信!

用 Python 和 Google 云平台构建简单的 ETL 管道

原文:https://towardsdatascience.com/building-a-simple-etl-pipeline-with-python-and-google-cloud-platform-6fde1fc683d5?source=collection_archive---------6-----------------------

使用 Google Cloud 函数从 FTP 服务器提取数据并加载到 BigQuery

GCP

有很多 ETL 工具,有时它们可能会让人不知所措,特别是当你只想将文件从 A 点复制到 b 点时。所以今天,我将向你展示如何使用 python 3.6 和谷歌云函数从 FTP 服务器提取 CSV 文件(提取)、修改(转换)并自动将其加载到谷歌 BigQuery 表(加载)。

在本文的最后,您将能够从 FTP 服务器提取一个文件,并在 Google Cloud 函数中使用 Python 将其加载到数据仓库中。

在本文中,我们将做以下工作:

  • 设置云功能
  • 提取数据
  • 转换数据
  • 加载数据
  • 自动化我们的管道

首先,什么是 ETL?

提取、转换、加载(ETL)是将数据从一个或多个源复制到目标系统的一般过程,目标系统以不同于源的方式或在不同于源的上下文中表示数据。—维基百科

场景

在我们开始之前,让我给你一些背景信息。一家第三方服务提供商有一台 FTP 服务器,其中存储了多个 CSV 文件,每个文件都包含一家物流公司的日常交易数据。我们需要数据仓库中的数据,这样我们就可以在内部与利益相关者共享这些数据,并监控性能。

这家物流公司的基础设施团队每天从他们的数据库中导出一个 CSV 文件,并将其上传到 FTP 服务器。

我们的工作是每天从服务器上复制这些文件,对其进行清理,然后将其加载到我们的数据仓库中,这样我们就可以将其连接到其他数据源并对其进行分析。

这是我们的 ETL 管道图最终的样子:

使用 Lucidchart 创建

Google Cloud Functions:Cloud Functions(CF)是 Google Cloud 的无服务器平台,用于执行响应特定事件的脚本,如 HTTP 请求或数据库更新。CF 的替代方案是 AWS LambdaAzure Functions

设置您的云功能

  • 进入云功能概述页面
    确保您启用了云功能的项目被选中。
  • 单击创建函数。
  • 说出你的函数。
  • 在触发器字段中,选择 HTTP 触发器。
  • 在源代码字段中,选择内联编辑器。在本练习中,您将使用我们将要一起处理的 代码 ,以便您可以在编辑器中删除默认代码。
  • 使用运行时下拉列表选择运行时。

确保您的运行时设置为“Python 3.7”,并在“高级选项”下将区域更改为离您最近的区域。在撰写本文时,CF 并不是在每个谷歌数据中心区域都可用,所以请点击这里的查看哪里启用了云功能。

完成这些步骤后,您的显示应该如下所示:

来自 GCP 控制台的截图

我们的自定义代码

一个云函数有两个文件;一个 main.py 和一个 requirements.txt 文件。后者托管我们脚本工作所需的所有文件依赖项,因此单击 requirements.txt 选项卡,并确保编辑器中包含这些依赖项,如下所示:

所有依赖项的快速摘要:

  • google-cloud-bigquery:这个库允许我们访问 bigquery 并与之交互
  • python-csv:这个库用于用 python 操作 csv 文件
  • requests:是一个用于发送 HTTP 请求的 HTTP 库,我们将需要它来访问 FTP URL。
  • wget:用于从互联网下载文件
  • pytest-shutil:这用于 SSH 访问

提取

现在在 main.py 选项卡中,您可以开始包含下面的代码。看第 1 到 4 行。我们创建了一个名为“ftp_function”的函数,以后用 HTTP 请求访问云函数时会用到这个函数。然后,我们使用必要的凭证登录到 FTP 服务器,并导航到服务器上存储文件的适当目录。

请注意,我工作的 FTP 服务器有多个 CSV 代表不同日期的事务数据。所以为了获得目录中最新的文件,我使用了从第 7 行到第 9 行的代码。

其余的代码获取文件并下载它。

注意:要通过秘密管理器保护您的凭证,请遵循本指南

改变

为了“转换”数据,我们将对刚刚下载的 CSV 文件做一个简单的更改。我们将简单地将 CSV 文件中每次出现的“FBA”更改为“AMAZON”。下面是代码。

这里也要注意,Google Cloud Function 有一个*/tmp*目录,可以临时存放文件。该目录中的文件存储在实例的 RAM 中,因此写入/tmp会占用系统内存。一旦实例停止运行,目录中的所有临时文件都将被删除。

负荷

现在,确保你创建了你的大查询表。然后我们简单地使用下面的代码将转换后的 CSV 文件加载到您创建的 Bigquery 表中。因为我们启用了“自动检测”,所以 Bigquery 表在创建时不必有模式,因为它将基于 CSV 文件中的数据进行推断。

当您完成编写脚本时,您可以通过单击“创建”来部署云功能。当云功能部署成功时,您应该会看到一个绿色的复选标记,如下所示…

来源

使自动化

现在剩下要做的就是创建一个 cron 作业(Cloud Scheduler ),它将在某个预定义的时间间隔自动调用 CF。好消息是,在谷歌云平台上创建 cron jobs 非常简单,也是最简单的部分。你可以按照 这里 的指示或者复制下图。

来源

截图自 GCP

这里的“频率”字段将在每天凌晨 1:59 运行我们的脚本。

您可以使用这个很酷的站点编辑器来处理简单的 cron 调度表达式。

既然我们的数据已经存放在数据仓库中,我们可以将它连接到任何可视化工具并对其进行分析。

就是这样。希望这对你有帮助。这是一种非常简单的开发 ETL 的方法,任何人都可以在其上进行构建。

你可以 成为中等会员 享受更多这样的故事。

你可以在 Github 上找到完整脚本的链接。

如何用 Python 构建一个简单的营销组合模型

原文:https://towardsdatascience.com/building-a-simple-marketing-mix-model-with-ols-571ac3d5b64f?source=collection_archive---------5-----------------------

又一个使用 Python 代码的端到端数据科学项目!

亚伦·塞巴斯蒂安在 Unsplash 上拍摄的照片

目录

  1. 简介
  2. 你将学到什么
  3. 什么是营销组合模式?
  4. 营销组合模型演练

如果你喜欢这篇文章,请务必 订阅 千万不要错过另一篇关于数据科学指南、技巧和提示、生活经验等的文章!

介绍

由于高需求,我又带着另一个带 Python 代码的循序渐进的数据科学项目回来了!这个非常有趣,因为除了我将要介绍的内容之外,您还可以做更多的事情——然而,我相信这为任何对营销和数据科学感兴趣的人提供了一个良好的开端。

这个项目关系到许多企业面临的一个常见的现实问题— 营销归因。这是确定每个营销渠道对销售/转化有多大贡献的科学。当你引入电视或广播等线下营销渠道时,困难通常会出现,因为没有直接的方法来衡量这些渠道的影响。

你会学到什么

  • 您将了解什么是营销组合模型(MMM ),以及如何使用它来评估各种营销渠道
  • 在探索数据时,您将学习基本的概念和技术
  • 您将了解什么是普通最小二乘(OLS)回归,如何实现它,以及如何评估它

什么是营销组合模式?

营销组合模型(MMM) 是一种用于确定市场属性的技术。具体来说,它是一种对营销和销售数据进行统计的技术(通常是回归),以估计各种营销渠道的影响。

不同于归因建模,另一种用于营销归因的技术,营销组合模型试图衡量不可估量的营销渠道的影响,如电视、广播和报纸。

一般来说,你的输出变量是销售额或转化率,但也可以是网站流量。您的输入变量通常包括按时段(日、周、月、季度等)划分的渠道营销支出,但也可以包括我们稍后将讨论的其他变量。

营销组合模型演练

在这个项目中,我们将使用一个虚构的数据集,该数据集包括电视、广播和报纸上的营销支出,以及各个时期相应的美元销售额。

数据集是 这里是

设置

首先,我们将像往常一样导入库并读取数据。

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as pltdf = pd.read_csv("../input/advertising.csv/Advertising.csv")

理解我的变量

接下来,我们将查看数据集中的变量,并了解我们正在处理的内容。

print(df.columns)
df.describe()

很快,您可以看到这个未命名的变量:0 实际上是一个从 1 开始的索引——所以我们将删除它。

df = df.copy().drop(['Unnamed: 0'],axis=1)

因为这是一个虚构的简单数据集,所以有很多步骤我们不必担心,比如处理缺失值。但一般来说,您需要确保数据集是干净的,并为 EDA 做好了准备。

探索性数据分析

我总是喜欢做的第一件事是创建一个相关矩阵,因为它让我一眼就能更好地理解变量之间的关系。

corr = df.corr()
sns.heatmap(corr, xticklabels=corr.columns, yticklabels=corr.columns, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True))

马上,我们可以看到电视和销售之间有很强的相关性(0.78),广播和销售之间有中等的相关性(0.58),报纸和销售之间的相关性很弱(0.23)。现在下结论还为时过早,但这有利于我们继续前进。

与相关矩阵类似,我想创建一个变量的配对图,这样我可以更好地理解变量之间的关系。

sns.pairplot(df)

这似乎与相关矩阵相一致,因为电视和销售之间似乎有很强的关系,广播和报纸之间的关系更弱。

特征重要性

要素重要性允许您确定每个输入变量对预测输出变量的“重要性”。如果打乱某个要素的值会增加模型误差,则该要素非常重要,因为这意味着模型依赖该要素进行预测。

我们将快速创建一个随机森林模型,以便我们可以确定每个功能的重要性。

# Setting X and y variables
X = df.loc[:, df.columns != 'sales']
y = df['sales']# Building Random Forest model
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error as maeX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.25, random_state=0)
model = RandomForestRegressor(random_state=1)
model.fit(X_train, y_train)
pred = model.predict(X_test)# Visualizing Feature Importance
feat_importances = pd.Series(model.feature_importances_, index=X.columns)
feat_importances.nlargest(25).plot(kind='barh',figsize=(10,10))

似乎有一种模式,电视是最重要的,其次是广播,最后才是报纸。让我们实际建立我们的 OLS 回归模型。

OLS 模型

OLS 是普通最小二乘法的缩写,是一种用于估计线性回归模型中参数的方法。查看我的文章, 线性回归 5 分钟讲解 如果你不知道回归是什么!

Python 如此神奇的地方在于它已经有了一个库,我们可以用它来创建 OLS 模型:

import statsmodels.formula.api as sm
model = sm.ols(formula="sales~TV+radio+newspaper", data=df).fit()
print(model.summary())

。summary() 为我们的模型提供了丰富的见解。我要指出两件对我们最有用的事情:

  1. 调整的 R 平方是 0.896,这意味着我们的数据中几乎 90%的变化可以用我们的模型来解释,这非常好!如果你想了解更多关于 r 平方和其他用于评估机器学习模型的指标,请查看我的文章 这里
  2. 电视和广播的 p 值小于 0.000,但报纸的 p 值为 0.86,这表明报纸支出对销售没有显著影响。

接下来,让我们用实际销售值绘制预测销售值的图表,直观地了解我们的模型的表现:

# Defining Actual and Predicted values
y_pred = model.predict()
labels = df['sales']
df_temp = pd.DataFrame({'Actual': labels, 'Predicted':y_pred})
df_temp.head()# Creating Line Graph
from matplotlib.pyplot import figure
figure(num=None, figsize=(15, 6), dpi=80, facecolor='w', edgecolor='k')y1 = df_temp['Actual']
y2 = df_temp['Predicted']plt.plot(y1, label = 'Actual')
plt.plot(y2, label = 'Predicted')
plt.legend()
plt.show()

实际值与预测值

还不错!在给定电视、广播和报纸支出的情况下,这个模型似乎在预测销售方面做得很好。

更进一步

在现实中,数据可能不会像这样干净,结果可能不会看起来很漂亮。实际上,您可能需要考虑更多影响销售的变量,包括但不限于:

  • 季节性:公司的销售几乎总是季节性的。例如,一家滑雪板公司的销售额在冬季会比夏季高得多。在实践中,您可能希望包含一个变量来说明季节性。
  • 延续效应:营销的影响通常不会立竿见影。在许多情况下,消费者在看到广告后需要时间来考虑他们的购买决定。延续效应解释了消费者接触广告和对广告做出反应之间的时间差。
  • 基础销售与增量销售:并非每笔销售都归功于营销。如果一家公司在营销上完全没有花费,但仍然有销售额,这将被称为其基础销售额。因此,为了更进一步,你可以试着在增量销售而不是总销售额上模拟广告支出。

我希望你喜欢这个项目——让我知道你还想看什么样的项目!

感谢阅读!

如果你喜欢我的工作,想支持我…

  1. 支持我的最好方式就是在媒体上关注我这里
  2. Twitter 这里成为第一批关注我的人之一。我会在这里发布很多更新和有趣的东西!
  3. 此外,成为第一批订阅我的新 YouTube 频道 这里目前还没有视频,但即将到来!
  4. LinkedIn 这里关注我。
  5. 在我的邮箱列表 这里注册。
  6. 查看我的网站,terenceshin.com

从头开始构建一个简单的神经网络

原文:https://towardsdatascience.com/building-a-simple-neural-network-from-scratch-a5c6b2eb0c34?source=collection_archive---------38-----------------------

你有没有想过神经网络是如何工作的?它如何学习,如何扩展到我们输入的海量数据?

(来源)

在本文中,我们将研究只有一个神经元的简单神经网络的工作原理,并了解它在我们的“Cat v/s Non Cat 数据集”上的表现。

在本文结束时,您将能够-

  1. 从头开始编写你自己的神经网络
  2. 理解神经网络如何工作
  3. 如何转换输入数据以输入神经网络

目标

我们将对我们的神经网络进行编码,然后使用经过训练的网络来确定一幅图像中是否包含一只猫。这类问题被称为“二元分类问题”。它包括将输入分为两类,在我们的例子中是“Cat”或“Not cat”。

神经网络的基础

线性回归方程

神经网络中的单个神经元作为直线工作,其具有以下等式:

这是神经网络的整个概念所基于的基本方程。让我们打破这个等式:

y :因变量(神经网络的输出)

m :直线的斜率

x :独立变量(输入特征)

b : y 轴截距

绘制在图表上的线性方程(来源

就神经网络而言,我们将斜率指定为权重,截距指定为偏差,输出(y)指定为 z,因此等式变为:

在这里,我们只有一个特征,我们给模型。要输入多个特征,我们必须放大等式。

扩展到多种功能

上述等式可以扩展到“n”个特征,可以写成:

在这里,我们有“n”个输入特征提供给我们的模型。对应于每个输入特征,我们有一个权重,指定该特征对我们的模型预测输出有多重要。偏差项有助于在轴上移动我们的线,以更好地适应训练数据,否则线将始终穿过原点(0,0)。

同时做这件事

我们可以利用矩阵将所有权重与输入相乘,并向它们添加偏差。这可以通过以下方式完成:

这里,每一行代表一个训练示例(在我们的例子中是图像),每一列代表一个像素数组。

在 python 中,我们将使用矢量化来实现上述概念。

注意:在上面的等式中,我们使用“X.w+b ”,因为我们的输入矩阵是(mXn)的形状,其中“m”是样本的数量,“n”是特征的数量。

训练神经网络的目标是更新权重和偏差,以获得尽可能准确的预测。

神经元

(来源

神经元是神经网络中的一个单元。它模拟了我们大脑中的神经元,将“树突”作为输入,“核”作为身体,“轴突”作为输出。每个神经元接受一些输入,对其进行处理,然后根据激活函数给出一个输出。

如果你不能理解这些概念中的任何一个,请耐心听我说,一旦我们开始把事情放在一起,一切都会变得有意义。

编码我们的神经网络

从创建阶段到获得预测,整个过程分为以下几个部分:

  1. 准备输入到我们的网络
  2. 初始化权重和偏差
  3. 正向传播
  4. 计算损失
  5. 反向传播
  6. 更新权重和偏差
  7. 多次重复上述过程(时期)
  8. 获得预测

(来源)

准备输入

我们的输入是“猫”和“不是猫”的图像集合。每个输入图像都是 64x64 像素大小的彩色图像。我们在训练数据集中总共有 209 幅图像,在测试数据集中有 50 幅图像。为了将这些图像输入到我们的神经网络中,这些图像必须被改造成像素向量。因此,每个图像将按行的顺序排列成一维向量。

(来源)

最初,我们输入的形状是(209,64,64,3),但现在转换后,它将变成(209,64x64x3),即(209,12288)。现在这个“12288”是我们神经网络的输入数量,“209”是训练样本的数量。

我们的图像是 8 位的,所以图像中的每个像素都有一个在[0,255]范围内的值,即总共 256 个值的范围(2⁸=256).因此,我们必须通过将每个像素除以最大值(即 255)来标准化我们的图像。

神经网络对输入尺度非常敏感。我们不希望我们的输入变化太大,否则较大的输入可能会支配较小的输入。因此,如果输入的范围很大,对其进行归一化总是一个好的做法。

初始化权重和偏差

我们必须将权重和偏差初始化为某个小值,以便能够开始训练过程。

在这里,我们将权重乘以 0.01,使其在整个训练过程中不会爆炸(变得非常大)。

注意:在代码中,‘b’只是一个‘浮点’数,因为 python 中的广播。它会自动将这个“浮点数”转换成所需的矢量形状。

现在我们已经初始化了权重和偏差,让我们进入下一步。

正向传播

这里,我们将使用上面建立的等式计算输出“z ”,然后在输出上使用激活函数。

在二元分类的情况下,我们将使用 sigmoid 激活函数,因为 sigmoid 函数通过将输入变换到[0,1]区间来给出输出。因此,我们可以通过将值设置为大于 0.5 比 1 和小于 0.5 比 0 来轻松找到目标类。

乙状结肠的公式是:

在哪里,

让我们看看实现这两个步骤的代码:

现在我们已经得到了神经元的输出,我们可以计算损失,看看我们的模型表现得有多好/差。

计算损失

在二元分类中,使用的损失函数是二元交叉熵/对数损失。它由公式给出:

在哪里,

m :数据集中的样本总数

yᵢ:iᵗʰ样品的真实标签

aᵢ:iᵗʰ样本的预测值

这可以在 python 中实现为:

这个损失将告诉我们离预测正确的产量还有多远。如果损失为 0,那么我们就有了一个完美的模型。但实际上,如果损失为 0,那么我们的模型可能会过度拟合数据。

反向传播

这是奇迹发生的地方。在每次迭代中,基于模型输出和预期输出,我们计算梯度。梯度是我们需要改变多少权重和偏差来减少损失。

为了计算梯度,我们使用以下公式:

在 python 中,上述等式可以实现为:

现在,“dw”和“db”包含我们需要分别调整权重和偏差的梯度。

更新权重和偏差

我们现在需要用刚刚计算的梯度来调整权重和偏差。为此,使用以下等式:

其中' α' (alpha) 是学习率,它定义了我们的更新应该有多大/多小。

更新参数的代码是:

现在我们只需多次重复这些步骤来训练神经网络。

训练神经网络

为了训练神经网络,我们必须运行上述步骤一些时期(重复这些过程的次数)。

现在我们的神经网络已经训练好了,我们可以预测新输入的输出。

获得预测

为了从我们的神经网络获得预测,我们必须转换神经网络的输出‘a ’,使得小于 0.5 的输出值变成 0,否则变成 1。

虽然我们只有一个神经元,但我们仍然在训练数据上获得了 96%的准确率,在测试数据上获得了 76%的准确率,这还不错。

恭喜你!我们刚刚从零开始制作了第一个神经网络。在下一篇文章中,我将告诉你如何开发一个浅层神经网络,它将有一个包含多个神经元的隐藏层。

你可以在 Github 上找到完整的代码:

[## akarsh-sa xena/从头开始的神经网络

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/akarsh-saxena/Neural-Network-From-Scratch/tree/master/Artificial Neural Network/Simple Neural Network)

这就是从头开始创建和训练神经网络的整个过程。我希望你明白一切。不过,如果你还有什么不明白的,请在这里留言,我会尽力解答你的疑问。

关注我在 GithubLinkedIn 了解更多信息。

用 Google Trends 构建简单的 Python 应用程序

原文:https://towardsdatascience.com/building-a-simple-python-application-with-google-trends-9ece746cbd2f?source=collection_archive---------12-----------------------

米利安·耶西耶Unsplash 上拍摄的照片

xcel 是微软的一款产品,在专业环境、教育和个人工作流程中非常常用。如果您作为 Python 程序员遇到这个应用程序,应该不会感到惊讶。根据您正在编程的内容,了解更多关于如何在 Python 中与 excel 文件交互的信息可能会很方便。

谷歌趋势跟踪谷歌搜索引擎的搜索分析。我们将使用一个名为pytrends的非官方 API 来获取这个项目所需的数据。

我将从 Google Trends 获取关键字数据,然后在 Microsoft Excel 中显示这些数据。我将使用tkinter模块给用户一个漂亮的 GUI(图形用户界面)来输入搜索词。我将在这个项目中使用 PyCharm Professional。

[## py charm:JetBrains 为专业开发人员提供的 Python IDE

在 PyCharm 处理日常事务时节省时间。专注于更大的事情,拥抱以键盘为中心的方法…

www.jetbrains.com](https://www.jetbrains.com/pycharm/) [## Microsoft Excel Online,电子表格软件,免费试用

订阅了 Microsoft 365 的 Microsoft Excel 是 Excel 的最新版本。之前的版本包括 Excel 2016…

www.microsoft.com](https://www.microsoft.com/en-us/microsoft-365/excel) [## pytrends

谷歌趋势的非官方 API 允许从谷歌趋势自动下载报告的简单界面。只有…

pypi.org](https://pypi.org/project/pytrends/) [## Tcl/Tk - Python 3.8.6 文档的 tkinter - Python 接口

源代码:Lib/tkinter/init。py 包(“Tk 接口”)是 Tk GUI 的标准 Python 接口…

docs.python.org](https://docs.python.org/3/library/tkinter.html) [## 熊猫

pandas 是一个快速、强大、灵活且易于使用的开源数据分析和操作工具,构建于…

pandas.pydata.org](https://pandas.pydata.org/)

如果您是 Python 新手,我建议您阅读我写的一些其他文章,以获得本教程所需的基础知识。

[## Python 编程语言的简史

Python 编程语言是一种通用的编程语言,它已经在主流编程语言中占有一席之地

medium.com](https://medium.com/python-in-plain-english/a-brief-history-of-the-python-programming-language-4661fcd48a04) [## Python 基本概述

Python 有许多独特的特性,这些特性帮助它成为现在的样子。这些功能包括:

medium.com](https://medium.com/python-in-plain-english/python-basic-overview-76907771db60) [## Python 初学者完全参考指南

Python 是一种很好的初学者语言,但也适合高级用户。我将深入核心…

medium.com](https://medium.com/python-in-plain-english/python-beginners-reference-guide-3c5349b87b2) [## Python 的最佳 ide 和文本编辑器

我无法告诉你正确的 IDE(集成开发环境)对任何编程项目有多重要。只是…

medium.com](https://medium.com/analytics-vidhya/the-best-ides-and-text-editors-for-python-872ff1176c92)

此外,我将在这里包含我的 GitHub 资源库。

因此,我们将构建一个 Python 应用程序,它将用户输入的一个单词作为输入,并以 excel 文件的报告格式输出相关的 Google 关键字建议,为了用户的方便,该文件会自动弹出。

好的,首先我要在 PyCharm 开始一个新项目。我还将使用文件keywords.xlsxlogo_image.png。这些文件可以在我的 GitHub Repo 中找到。我将使用标准的 Python 虚拟环境。如前所述,我将使用pytrends非官方 API。记住现在安装项目的所有包依赖项。

首先,我会做我的进口。

from pytrends.request import TrendReq
import pandas as pd
from tkinter import *
import os

接下来,我将想要建立一个类。

# create class
class MyKeywordApp():
    def __init__(self):

然后我来定义newWindow()方法。

def newWindow(self):
    # define your window
    root = Tk()
    root.geometry("400x100")
    root.resizable(False, False)
    root.title("Keyword Application")

    # add logo image
    p1 = PhotoImage(file='logo_image.png')
    root.iconphoto(False, p1)

    # add labels
    label1 = Label(text='Input a Keyword')
    label1.pack()
    canvas1 = Canvas(root)
    canvas1.pack()
    entry1 = Entry(root)
    canvas1.create_window(200, 20, window=entry1)

现在我将定义嵌套在newWindow()方法中的excelWriter()方法。

def excelWriter():
    # get the user-input variable
    x1 = entry1.get()
    canvas1.create_window(200, 210)

    # get our Google Trends data
    pytrend = TrendReq()
    kws = pytrend.suggestions(keyword=x1)
    df = pd.DataFrame(kws)
    df = df.drop(columns='mid')

    # create excel writer object
    writer = pd.ExcelWriter('keywords.xlsx')
    df.to_excel(writer)
    writer.save()

    # open your excel file
    os.system("keywords.xlsx")
    print(df)

之后,当在嵌套的excelWriter()方法之后调用Button()时,我定义了按钮并通过command=参数将其链接到excelWriter()方法,但仍然在newWindow()方法内。

# add button and run loop
button1 = Button(canvas1, text='Run Report', command=excelWriter)
canvas1.create_window(200, 50, window=button1)
root.mainloop()

现在我们回到类代码开头的__init__()函数中,调用newWindow()方法。记住使用关键字 self 来正确引用方法。

self.newWindow()

要完成程序,在全局范围内的代码末尾(不属于任何代码块)调用MyKeywordApp()类。

# call class
MyKeywordApp()

就是这样。如果您运行该应用程序,它会弹出一个如下所示的窗口:

关键词程序窗口

只需输入一个单词,点击运行报告按钮提交即可。将打开一个 excel 文件,其中包含 Google 以报告格式为该搜索词建议的关键字。

Excel 关键字报表(keywords.xlsx)

结论

这是一个介绍性的演练,目的是开始使用 Python 项目,包括 Microsoft ExcelGoogle Trendstkinter 。感谢您的阅读,我希望这有助于任何人开始这样的项目。如果您有任何意见、问题或更正,我鼓励您在下面的回复部分发表。感谢您的阅读和快乐编码!

应用程序图像源

作者:openclippart-Vectors

https://pixabay.com/vectors/chat-key-keyboard-1294339/

用 Python 构建一个简单的文本识别器

原文:https://towardsdatascience.com/building-a-simple-text-recognizer-in-python-93e453ddb759?source=collection_archive---------12-----------------------

如何使用文本识别器改进笔记记录过程

照片由像素皮克斯拜拍摄

在这篇文章中,我将向您展示如何使用 Python 从图像中提取文本。这个过程简称为“文本识别”或“文本检测”。所以基本上你可以从标题中理解,我们将构建一个简单的 python 程序来为我们提取文本。提取之后,程序还会将结果导出到一个文本文档中。这样,我们可以记录我们的结果。

如果你以前没有听说过计算机视觉,这是了解它的最好时机。大多数机器学习和人工智能领域都与计算机视觉密切相关。随着我们的成长和探索,看到外面的世界对我们的发展有很大的影响。这对机器来说也是一样的,它们使用图像来观察外部世界,这些图像基本上被转化为计算机可以理解的数据。计算机视觉是一个非常深的海洋,我只是试图给出一些想法。如果你想了解更多关于计算机视觉的知识,这里有一个谷歌云平台的不错的视频:

在接下来的几周里,我想给你们展示许多不错的项目,让你们开始学习计算机视觉。你会惊讶于使用计算机视觉可以做多么强大的事情。文本识别只是大海中的一滴水。如果你准备好了,让我们开始吧!

步骤 1 —库

首先,让我们安装我们将在这个程序中使用的模块包。我们将安装 PIL,宇宙魔方软件包。PIL 代表 Python 图像库,它为你的程序增加了图像处理能力。该模块支持多种图像格式。PyTesseract 是我们将使用的另一个模块,它主要完成文本识别部分。这将有助于我们识别和阅读文本。

下面是 pip 同时安装多个模块的代码:

pip install Pillow pytesseract

如果您想了解关于这些产品包的更多信息:

现在让我们将库导入到我们的程序中:

# adds image processing capabilities
from PIL import Image# will convert the image to text string
import pytesseract

步骤 2 —文本识别

在这一步,我们将选择一个我们想要处理的图像。你可以从谷歌上下载图片,或者用手机拍照。两种方式都应该可以。选择你的图像后,在同一个目录下创建一个新的文件夹,你可以把它命名为“image_test ”,并把图像文件复制到那个文件夹中。

我将使用的图像

我下载了一张图片,上面引用了弗吉尼亚·伍尔夫的话。有趣的事实:我真的很喜欢读她的书:)

无论如何,在我们的 image_test 文件夹中粘贴图像之后,让我们回到编码。在下面的代码中,我们创建一个图像变量来存储图像文件,然后使用 image_to_string 方法识别文本。

# assigning an image from the source path
img = Image.open(‘image_test/virginia-quote.jpg’)# converts the image to result and saves it into result variable
result = pytesseract.image_to_string(img)

第 3 步—导出

在这一步中,我们将把前面代码的结果导出到一个文本文档中。这样,我们将同时拥有原始图像文件和我们从该图像中识别的文本。

with open(‘text_result.txt’, mode =’w’) as file:
 file.write(result)
 print(“ready!”)

干得好!您刚刚使用 Python 创建了自己的文本识别器。如果你想做得更好,检查下一个额外的步骤。这里还有一个你可能感兴趣的项目。

[## 用 Python 构建语音识别器

使用谷歌云语音 API 将您的音频文件转换为文本

towardsdatascience.com](/building-a-speech-recognizer-in-python-2dad733949b4)

额外—图像增强

PIL 是一个巨大的包裹,有许多功能。在这个额外的步骤中,我们将对图像做一些小的改动,以便我们的文本识别器可以更容易地识别或“读取”文本。在图像上做一些小小的改动在计算机视觉中占据了很大的位置。计算机需要我们的帮助来更好地处理图像。

没有图像处理,就像把菜谱食材放在孩子面前,让他/她吃。有了正确的图像处理,就像把煮好的食物放在孩子面前。差别是巨大的,我强烈推荐通过图像处理文档来了解更多。

这是添加了一些小改动的完整代码,换句话说,这是一段新鲜出炉的代码:)

# adds more image processing capabilities
from PIL import Image, ImageEnhance# assigning an image from the source path
img = Image.open(‘image_test/virginia-quote.jpg’)# adding some sharpness and contrast to the image 
enhancer1 = ImageEnhance.Sharpness(img)
enhancer2 = ImageEnhance.Contrast(img)img_edit = enhancer1.enhance(20.0)
img_edit = enhancer2.enhance(1.5)# save the new image
img_edit.save("edited_image.png")# converts the image to result and saves it into result variable
result = pytesseract.image_to_string(img_edit)with open(‘text_result2.txt’, mode =’w’) as file:
 file.write(result)
 print(“ready!”)

视频演示

结果呢

如何在日常生活中使用文本识别器?

就我个人而言,我正在使用我们刚刚创建的工具将我的书页转换成文本文档,它使记笔记的过程变得更加容易和快速。现在,我不再每次都写下我最喜欢的几行,而是给那一页拍张照,然后用文本识别器进行转换。这难道不是编码最酷的地方吗?创造一些能解决你生活中一个问题的东西。

我是贝希克·居文,我喜欢分享关于创造力、编程、动力和生活的故事。跟随我 中型 留下来受启发。

用 Python 构建简单的用户界面

原文:https://towardsdatascience.com/building-a-simple-ui-for-python-fd0e5f2a2d8b?source=collection_archive---------4-----------------------

用用户界面展示 Python 项目从未如此简单。使用 Streamlit 框架,您可以仅使用 Python 代码构建基于浏览器的 UI。在这个演示中,我们将为一个迷宫求解程序构建用户界面,这个程序在之前的文章中有详细描述。

[## 用 Python 解迷宫

使用 Dijkstra 的算法和 OpenCV

towardsdatascience.com](/solving-mazes-with-python-f7a412f2493f)

细流

Streamlit 是一个 web 框架,旨在让数据科学家使用 Python 轻松部署模型和可视化。它速度快,简约,但也漂亮和用户友好。有用于用户输入的内置小部件,如图像上传、滑块、文本输入和其他熟悉的 HTML 元素,如复选框和单选按钮。每当用户与 streamlit 应用程序进行交互时,python 脚本都会从头到尾重新运行一次,这是考虑应用程序的不同状态时需要记住的一个重要概念。

您可以使用 pip 安装 Streamlit:

pip install streamlit

并在 python 脚本上运行 streamlit:

streamlit run app.py

用例

在前面的演示中,我们构建了一个 Python 程序,它将在给定图像文件和开始/结束位置的情况下解决一个迷宫。我们想把这个程序变成一个单页的 web 应用程序,用户可以上传一个迷宫图像(或使用默认的迷宫图像),调整迷宫的开始和结束位置,并看到最终解决的迷宫。

首先,让我们为图像上传程序创建 UI,并创建使用默认图像的选项。我们可以使用像 st.write()st.title() 这样的函数来添加文本输出。我们使用 streamlit 的 st.file_uploader() 函数存储动态上传的文件。最后, st.checkbox() 将根据用户是否选择了复选框返回一个布尔值。

结果是:

然后,我们可以将默认或上传的图像读取为可用的 OpenCV 图像格式。

一旦图像上传,我们希望显示标有起点和终点的图像。我们将使用滑块来允许用户重新定位这些点。 st.sidebar() 函数向页面添加一个侧边栏,而 st.slider() 在定义的最小值和最大值范围内接受数字输入。我们可以根据迷宫图像的大小动态定义滑块的最小值和最大值。

每当用户调整滑块时,图像会快速重新呈现,并且点会改变位置。

一旦用户确定了开始和结束的位置,我们需要一个按钮来解决迷宫并显示解决方案。 st.spinner() 元素仅在其子流程运行时显示,而 st.image() 调用用于显示图像。

流线型按钮和微调按钮

显示已解决的迷宫

迷宫求解器在运行

摘要

在不到 40 行代码中,我们为 Python 图像处理应用程序创建了一个简单的 UI。我们不需要编写任何传统的前端代码。除了 Streamlit 能够消化简单的 Python 代码之外,每当用户与页面交互或脚本发生变化时,Streamlit 都会智能地从头到尾 重新运行脚本的必要部分。这允许直接的数据流和快速开发。****

你可以在 Github 上找到完整的代码,在这里你可以找到解释迷宫求解器背后的算法的第一部分。包含重要概念和附加小部件的 Streamlit 文档位于这里

[## 为 Python 部署简单的 UI

Streamlit 共享:Python 项目的游戏规则改变者

towardsdatascience.com](/deploying-a-simple-ui-for-python-88e8e7cbbf61)

建立一个简单的网页刮新冠肺炎可视化与散景按地区

原文:https://towardsdatascience.com/building-a-simple-web-scraped-covid-19-visualization-with-bokeh-by-region-84aa351f668?source=collection_archive---------29-----------------------

每个数据问题都始于良好的可视化

Unsplash 上由 Jochem Raat 拍摄的照片

就像任何数据爱好者所说的那样;有洞察力的数据可视化使我们能够获得对问题的直觉,对于任何类型的问题解决都是一个很好的起点,而不仅仅是数据繁重的问题。

在这个项目中,我致力于开发一个可视化工具,让人们了解我所在地区(加拿大安大略省)的哪些县市仍然是当前新冠肺炎疫情的重灾区。

您将需要什么:

  1. 要可视化的区域的 shapefile。我使用了大多数 GIS(地理信息软件)生成的. shp 文件格式。这里有一个来源的链接。(这是近 20 年前的资料,因此不是最新的)
  2. Bokeh 和 GoogleMaps 包已安装。在终端/命令提示符下安装软件包的代码如下:
**pip** **install** bokeh
**pip install** googlemaps

接下来,我们加载数据和必要的库。

**import** requests
**import** numpy as np
**import** pandas as pd
**import** googlemaps
**import** geopandas as gpd
**import** seaborn
**from** shapely.geometry **import** Point, Polygon

下面这段简单的代码支持将数据集自动下载、写入(或覆盖)到所选的目的地。

url = ‘[data_source_url'](https://data.ontario.ca/dataset/f4112442-bdc8-45d2-be3c-12efae72fb27/resource/455fd63b-603d-4608-8216-7d8647f43350/download/conposcovidloc.csv')
myfile = requests**.get**(url)
**open**(‘data/conposcovidloc.csv’, ‘wb’).**write**(myfile.**content**)

这可能是一个简单的周末项目的很大一部分原因是因为 data.ontario.ca 的研究员保持了数据的干净。然而,我们确实需要将数据集塑造成更好地用于此目的的方式。

covid_19 = pd.**read_csv**(‘covid_19_data_path.csv’)cv0 = pd.**get_dummies**(covid_19, columns = [‘OUTCOME1’,’CLIENT_GENDER’,’Age_Group’])
# this creates dummy variables for the categorical variables names
cv0 = cv0.**drop**(cv0.columns[0],axis = 1)
cv0 = cv0.**replace**(0,np.nan)cv1 = cv0.**groupby**(['Reporting_PHU','Reporting_PHU_Latitude','Reporting_PHU_Longitude','Reporting_PHU_City']).**count**().**reset_index**()

上面的代码块做了几件好事。首先,它使分类变量的结果,客户性别和年龄组列。但是,这就产生了 np。NaN 对象,我们希望在新创建的分类变量中使用零。上面的最后一行按可视化和。count()方法将 NaN 对象转换为零。

Counties = gpd.**read_file**(‘geo_data_path.shp’)
Counties = Counties.**sort_values**(‘OFF_NAME’)
for **i,v** in **enumerate**(city_order):
 city = cv1[‘Reporting_PHU_City’][v]
 county_city.**append**(city)

Counties[‘CITY’]=county_city

接下来,我们加载了地理数据。本项目中使用的地理数据源不包含报告新冠肺炎病例的公共卫生城市的数据。 city_order 是一个包含列表索引的列表,我们可以从新冠肺炎数据集中的列 Reporting _ PHU _ 城市生成该列表。这为合并两个数据集创建了一个起点。

# longitude must always come before latitude
geometry = [**Point**(xy) for xy in zip(cv1[‘Reporting_PHU_Longitude’],cv1[‘Reporting_PHU_Latitude’])]
geo_cv = gpd.**GeoDataFrame**(cv1, geometry = geometry)

这个简单的代码块做得相当不错。它根据城市的经度和纬度创建几何图形,并由此创建新的地理数据框架。

接下来,我使用均值归一化进行了一些基本的特征缩放,以产生一个更具代表性的疫情迄今为止受灾最严重的城市分布。然后,新列应合并成一个数据帧,用于散景图。

以下是数据帧的快照:

最后两个代码块在 GoogleMaps 库的帮助下生成散景图。

import json
from **bokeh**.io import output_notebook, show, output_file
from **bokeh**.plotting import figure
from **bokeh**.models import GeoJSONDataSource,LinearColorMapper, ColorBar, Label, HoverTool
from **bokeh**.models import Range1d, ColorMapper
from **bokeh**.models.glyphs import MultiLine
from **bokeh**.palettes import brewer, mplapi_key = ‘***YOUR_API_KEY***’
gmaps = googlemaps.**Client**(key=api_key)#Read data to json and convert to string-like object
Counties_json = json.**loads**(Counties.**to_json**())
json_data = json.**dumps**(Counties_json)#Provide GeoJSONData source for plotting.
geosource = GeoJSONDataSource(geojson = json_data)#Repeat for geo_cv GeoPandas DataFrame
geo_csv_json = json.**loads**(geo_cv.**to_json**())
json_data2 = json.dumps(geo_csv_json)geosource2 = GeoJSONDataSource(geojson = json_data2)

而对于剧情本身。

fig = figure(title = ‘Ontario Covid 19 Cases by Municipality’, plot_height = 750 , plot_width = 900
 ,active_scroll=’wheel_zoom’)
fig.**xgrid**.**grid_line_color** = None
fig.**ygrid**.**grid_line_color** = None# initialize the plot on south and eastern ontario
left, right, bottom, top = -83.5, -74.0, 41.5, 47.0
fig.**x_range**=Range1d(left, right)
fig.**y_range**=Range1d(bottom, top)# Creating Color Map by Recovery Rate
palette1 = brewer[‘RdYlGn’][11] 
cmap1 = LinearColorMapper(palette = palette1,
 low = Counties[‘PERCENTAGE_TOTAL_log’].**min**(),
 high = Counties[‘PERCENTAGE_TOTAL_log’].**max**())cmap2 = LinearColorMapper(palette = palette1,
 low = geo_cv[‘TOTAL_CASES’].**min**(),
 high = geo_cv[‘TOTAL_CASES’].**max**())#Add patch renderer to figure. 
f2 = fig.**patches**(‘xs’,’ys’, source = geosource, line_color = ‘black’, line_width = 0.25, line_alpha = 0.9, fill_alpha = 0.6,
 fill_color = {‘field’:’PERCENTAGE_TOTAL_log’,’transform’:cmap1})fig.**add_layout**(ColorBar(color_mapper=cmap2, location=’bottom_right’,label_standoff=10))hover2 = HoverTool(renderers = [f2], tooltips = [(‘Municipality Name’,’[@OFF_NAME](http://twitter.com/OFF_NAME)’)])
fig.add_tools(hover2)f1 = fig.**circle**(x=’Reporting_PHU_Longitude’,y=’Reporting_PHU_Latitude’,size = 10,
 color = ‘black’, line_color = ‘white’, source = geosource2, fill_alpha = 0.55)
hover1 = HoverTool(renderers = [f1], tooltips=[(‘Health Unit’,’[@Reporting_PHU](http://twitter.com/Reporting_PHU)’)
 ,(‘Health Unit City’,’[@Reporting_PHU_City](http://twitter.com/Reporting_PHU_City)’)
 ,(‘Fatalities’,’[@Outcome1_Fatal](http://twitter.com/Outcome1_Fatal)’)
 ,(‘Percentage Recovered’,’[@PERCENTAGE_Recovered](http://twitter.com/PERCENTAGE_Recovered)’),(‘Total Cases’,’[@TOTAL_CASES](http://twitter.com/TOTAL_CASES)’)
 ,(‘Male to Female Ratio’,’[@GENDER_RATIO1](http://twitter.com/GENDER_RATIO1)')])bfig.**add_tools**(hover1)
output_notebook()
show(fig)

感谢您的关注,我相信您会发现这很有价值

请随时通过以下平台联系我

TwitterLinkedInGithub 或者在 Medium 上关注我!

posted @ 2024-10-14 11:50  绝不原创的飞龙  阅读(173)  评论(0)    收藏  举报