使用 GraphQL 的快速应用原型——一种思考数据和 API 设计的不同方式
标签 : GraphQL,Graphene,Python,Docker。
Python-石墨烯框架中的多态性
这篇文章的主要目的是说明如何使用 Python-Graphene 框架(https://github.com/graphql-python/graphene)来构建 GraphQL 端点。具体来说,它说明了在表示数据时使用石墨烯中的联合和接口构造来模拟多态性。
这个项目的源代码可以在 GitHub 上找到(下面的链接)。按照 README 中的说明在 docker 容器中运行该示例。
[## husseinmoghnieh/graph QL-多态性
GitHub 是人们构建软件的地方。超过 2800 万人使用 GitHub 来发现、分享和贡献超过…
github.com](https://github.com/husseinmoghnieh/graphql-polymorphism)
介绍
GraphQL 是一种查询语言,它使数据的消费者(即前端/ UI)能够通过单个 API 端点查询数据。这是一种不同于使用 RESTful 端点的方法,在 RESTful 端点中,每个端点都是针对特定于服务的功能定制的,并且具有固定的响应结构。
在 RESTful API 设计中,产品需求被转化为一组 API,这些 API 主要在数据存储上执行 CRUD(创建、读取、更新和删除)操作。这个过程非常耗时,尤其是当目标是提供一个原型时。GraphQL 可以加速应用程序原型化的过程,因为它提供了一个 API 端点,充当 UI 和数据存储之间的数据代理。
我将带您去看这篇博客文章,这篇文章很容易说明 RESTful 和 graphQL 端点之间的区别。
通过 HTTP 发送数据的两种方式:有什么区别?
blog.apollographql.com](https://blog.apollographql.com/graphql-vs-rest-5d425123e34b)
总体而言,GraphQL 在以下情况下具有优势:
- 数据自然地以图表的形式出现
- 快速原型制作。一个服务于所有查询场景的 API
- 代表问题域的所有实体之间的多种关系
电影行业——图表示例
选择以电影行业为例来展示 GraphQL 的强大之处,是因为在这个行业中,任何类型的制作都涉及许多实体的参与,每个实体在作品制作中都有不同的角色,包括演员、作家、制片人等…制作公司和流媒体服务。因此,这个问题可以用图形来表示。
这篇文章的其余部分解释了完全工作的 GraphQL 示例的组件。
下一个:
- 数据表示法
- 模式设计
- 密码
- 查询示例
数据表示法
让我们假设电影业中每个实体的信息都以 JSON 格式存储,如下所示,为了简单起见,数据保存在磁盘上。该解决方案可以很容易地扩展到从任何数据源获取数据(关系数据库、NoSQL、S3,甚至更好图形数据库)。
华纳兄弟公司:
{
"id": "company/production/warnerbro",
"companyName": "Warner Bros.",
"established" : 1923,
"type": "company",
"links": [
{
"relationship": "distributed",
"target": "media/movie/ocean11"
},
{
"relationship": "produced",
"target": "media/movie/troy"
}
]
}
上面显示了与*(简体)相关的数据及其与两部电影(特洛伊和海洋 11 )的关系。华纳兄弟生产了第一种,发行了第二种。图形表示:*
另一方面海洋 11(电影),可以这样表示(简化):
*{
"id": "media/movie/ocean11",
"title": "Ocean 11",
"premier": "December 12, 2014",
"sequel" : "1/3",
"links": [
{
"relationship": "distributed by",
"target": "entity/company/WarnerBro"
},
{
"relationship": "produced by",
"target": "entity/person/JerryWeintraub"
},
{
"relationship": "produced by",
"target": "entity/company/VillageRoadshow"
},
{
"relationship": "starred",
"target": "entity/person/BradPitt"
}
]
}*
华纳兄弟和海洋 11 的集合图形表示为:
模式设计
用面向对象的术语来说,我们可以将上述实体分为两大类。一个我们称之为媒体,代表电影、表演等…另一个我们称之为参与者,代表一个人或一家公司。一个人可以是制片人、发行人、演员、作家等,一个公司可以是制作公司、发行人、流媒体公司等
将上述实体扩展为子类会产生下面的类图。同样,这个博客的范围是处理几种类型的媒体和参与者。
简单的例子
在深入研究技术细节之前,让我展示一个示例 GraphQL 查询及其相应的输出:
样本查询:
内容如下:
- 找到媒体海洋 11**
- 如果媒体是一部电影,则显示其标题并查找其参与者中有关系的"制作的
- 对于参与者满足产生的条件*,如果参与者是人则显示名称,如果参与者是公司则显示**公司名称*******
输出结构映射输入结构,如下所示。
输出:
这实质上是显示下面突出显示的图形节点的内容
密码
1 —链接接口
我将从表示实体间链接的代码(即链接接口)开始。该接口由所有类实现。
2-参与者接口和参与者实体
以下代码包含由所有参与者类实现的参与者接口。**
注意,每个类都实现了参与者接口和链接接口*。最后,一个名为 ParticipantResult 的附加类充当占位符,聚合通过解析不同类型的参与者(即 PersonDetails 和 CompanyDetails)而产生的对象。***
在面向对象中,结果类类似于声明一个保存父类类型对象的数组。例如,在 Java 中,这大致翻译为:
***List<**Participant**> participantResult = new ArrayList<**Participant**>();
participantResult.add(**companyDetails**)
participantResult.add(**personDetails**)***
3 —媒体接口和媒体实体
下面是媒体接口和相关实体的代码。
4-查询模式定义
在定义了表示存储数据的所有类之后,定义了一组查询(媒体查询和参与者查询)。然后,使用定义的查询初始化模式,如下所示**
4- API GraphQL 端点
下面所有的代码都是配置一个 FLASK,启动一个 FALSK 应用。公开上面的模式的代码在第 29 行:**
***app.add_url_rule('/graphql', view_func=GraphQLView.as_view
('graphql', schema=schema, graphiql=True))***
使用 Docker 运行
要运行这个示例,只需下载项目并运行:
***docker-compose builddocker-compose up***
将您的浏览器指向http://localhost/graphql和 Graphene 提供了一个交互式界面,允许您编写和执行 graph QL 查询。它还提供了一个模式浏览器(最右边)。**
GraphQL 查询示例
显示华纳兄弟制作的所有电影。
显示布拉德·皮特主演的所有电影
重新编码你自己的神经瘤
你是你的神经瘤的创造。
我知道这是一个有争议的评论。这是我的哲学,如果你不同意,我不会生气。我认为这是一种思考我们思想的有用方式,所以如果你好奇,请继续读下去。
你的神经瘤是一个超复杂的生化系统;它是由数万亿个脉冲和通信分子产生的,这些分子在多个相互连接的反馈回路中工作。它的许多系统致力于创建一个或多或少可用的世界模型,以及你与它的互动。(你的神经瘤是什么?看我的文章这里。你的神经瘤是活的,并且是它的感知机器,你的身体的一部分。
思考就是行动,就像走路或呼吸一样
思想是一种物质的东西;它产生于你意识中较小的部分,是你物质精神状态的结果。
如果你接受了你头脑的物质本质,那么各种各样的可能性就为如何从物质上改变你的头脑而敞开了大门;字面意思是用简单且容易获得的物理工具记录你自己的可能性。
你的神经瘤是个模棱两可的多系统智能。用简化的方法来检查它总是有帮助的,但它通常是作为一个整体来工作的,而且你也可以通过用这种精神来接近你的神经瘤来了解你自己。
它暴露于这个世界,而这个世界包括你自己的身体。
它使用你的身体与世界一起工作,当它这样做时,它的状态会暂时或永久地改变,这就是你所体验的思想的改变。身体活动也会影响你的神经瘤的长期几何形状,表现为身体上的联系和路径,我们将其描述为新的能力,或更稳定或僵化的思想,如习惯和信念。
你自己的身体,是你的思想向世界散发的一部分,是一个奇怪的有用工具,用来检查似乎来自你的神经瘤的一个或多个自我。
时代精神是正念。
东方文化中的佛教徒和武术运动,以及其他人,几千年来已经理解了身体工作的价值。他们的方法在现代西方广为人知,并在上个世纪逐渐流行起来。
现在,随着科学的探索,尤其是正念(冥想)已经走向主流。它在创造更好的应对策略方面的有用性正在被很好地记录和广泛使用。
然而,冥想虽然美妙,却只是用身体影响我们思想的一种方式。有用的是,它给了我们一个线索,告诉我们这是如何工作的。
正念的第一个转变是让意识平静下来,这有助于提升觉知。你可以用很多方法做到这一点,但最常用的一种方法是注意你的呼吸。
另一种说法是,冥想通常是通过将我们的意识带到我们的物质本性上来开始的,这有助于我们忽略思考时的正常干扰。
这是为了让意识和潜意识重新同步。你这样做是通过将你的意识意识与一个过程联系起来,这个过程通常是体内平衡的,但也可能是有意识的(体内平衡可能不是呼吸的完美术语,它指的是身体在没有意识干预的情况下自然做的事情,以维持我们的生命,如循环、温度、消化等)。我们通常不会想到呼吸或心跳,它们作为我们神经系统的一部分受到潜意识的调节。但是我们可以思考它们,我们可以用我们的思想影响它们。
专注于像呼吸这样的物理过程,你通常不会意识到,会重新连接你的交感神经系统和副交感神经系统(两个物理系统),并使它们更加一致,这可能会感觉像稳定、坚实或平静。
像呼吸这样的东西是一个明显的桥梁。它们是你重新发现你与你的物质自我的联系的途径。大多数情况下,这非常令人平静,有助于你以全新的视角体验思维的改变。
请注意,对想法有强烈的情绪想法(担心,感到不知所措,感觉无法停止关注特定的负面情况或想法)将对你的神经系统产生强烈的物理影响,反馈到思想螺旋中。
因为思想是你的物理环境的一部分,我们的神经瘤会通过它的物理报警系统对令人担忧的思想做出反应。这些可以在夜里唤醒我们,或者在白天制造恐慌;这是由身体向血液中泵入酶和激素引起的,以使身体对感知的危险采取行动,也许是由真正的危险引发的,但最常见的是由你自己的(非理性)想法引发的。
心理健康只是健康
顺便说一句,现在是我们改变关于精神健康的可怕的社会歧视的时候了。我明白,我们都害怕向他人透露自己的内心世界,部分原因是我们自己的敏感,也因为害怕他人的反应。但心理健康只是健康;比如心脏健康,或者内脏健康。所有这些都有心理学的成分,现在真的是时候改变我们个人和社会对心灵的态度了;它体内的神经瘤。
我们的神经瘤对我们的健康至关重要,需要我们以积极开放的态度对待它。
我觉得现在这样就够了。我计划在以后的文章中用一系列实用的物理工具来补充这一点,你可以用它们来重新编码你自己的神经瘤。
我希望你觉得它有趣并且容易理解,如果你觉得有问题和意见可以发表,我会很高兴。
React + D3:数据可视化世界的通心粉和奶酪
React and D3, just melting all over one another in gooey, data-driven deliciousness (aka a slice of mac ‘n cheese)
React 处于 SPA UI 开发的最前沿——目前没有其他技术像 react 这样强大和广泛使用。当我们谈论 web 上的数据可视化时,我们很可能是在谈论 D3(说真的,如果你所看到的 D3 只是一些快速的直方图,我不得不推荐这个奇妙的 D3 v4 课程,它将带你深入了解这个库实际上能够做什么的本质。剧透:这太疯狂了。PS:我和那门课没有任何隶属关系,我只是拿了,挖了)。
但是,一个悲剧即将发生:显然,在你的代码库中,一次只能有一个这么棒的库,对吗?
看,React 如此快速和轻便的部分原因是它在高效更新 DOM 方面非常聪明,所以当您使用 React 时,您通常不会直接接触 DOM——您只是放松下来,让所有甜蜜的、声明性的 MVC jazz 为您处理一切。
而 D3 则是给你一条直接进行 DOM 操作的干净的路径。
因此,实现的重叠可能会给我们带来潜在的问题——如果您没有正确地计划它,React 和 D3 可能会……妨碍彼此,并且表现得非常不可预测。人们已经编写了一些包来为您处理这个问题,但是缺点是您会被锁定在 React 和 D3 之上的第三个系统中。这通常意味着你只能使用数量相对有限的预制模板,或者无法使用大量的 D3 特性。限制自己似乎真的很遗憾,尤其是当让他们守规矩和轮流真的很简单的时候。
为了说明我们想如何解决这个问题,以我的猫为例。
Ellis and Sol about to fight over a windowsill spot on the left, and the two of them comfortably snoozing and sharing on the right.
本质上,我们想把 React 和 D3 当作我的猫来对待。我们就假设穿着整洁晚礼服的埃利斯是 React,右边穿着优雅晨装的索尔是 D3,窗户前面的阳光点是 DOM。
如果只有一个位置,我们只是让它们自己解决,就像左边的照片一样,那么…那些抬起的爪子在照片里可能看起来超级可爱,但让我告诉你,在这张照片拍摄后大约三秒钟,就有一些严重的争吵。只有一个位置,他们都决心要独占它。
然而,右边阳光充足的窗户大小完全一样,得到的阳光也一样多,但是,因为我们给了他们每人一个单独的枕头,他们可以称之为自己的枕头,他们可以完全做主,他们都在非常平静地做他们的事情。
给他们一点喘息的空间,给他们一种完全掌控的错觉,我就能让他们两个都表现得最好。
a screenshot of what we’re building — live at https://d3-react-tutorial.herokuapp.com
所以,尽管我很讨厌这样做,让我们把我的猫的寓言抛在脑后,谈谈我们要做什么。为了确保我们让每个库真正做它应该做的事情,我们有一个用户界面,让你选择颜色和大小,并根据这些选择生成可爱的小飞行 SVG 圆。这是一个非常小的玩具,但这正是我们完成工作所需的代码量。你可以在这里查看代码或者在这里摆弄玩具本身。
a relatively simple Controller Component, which renders a form and keeps track of form submission results in its state.
就像猫一样,我想给 React 和 D3 他们自己的独立空间,在那里他们可以负责并做他们所做的事情,这与“React-y”的思维方式非常好——我们想给每个库分配一个适当的角色,并将该角色的工作(以及库)隔离到单独的组件中。这样,当我们想知道谁可以操作 DOM 时,答案变得非常简单:我们在哪个组件中?
React 在交互性、状态管理和结构化用户界面方面非常出色,所以这就是我要让它做的事情——在上面显示的这个组件中,控制器。它只是一个漂亮、简单的表单,每个更改和提交都存储在组件的状态中——我们知道用户现在在做什么,以及他们已经做了什么。这就是我们在这里所做的——没有 SVG,我们甚至没有将 d3 导入到这个文件中。
所有这些都在第 39 行进行管理,其中“Viz”是一个子组件,它唯一的工作是获取控制器生成的数据,并使用 D3 来绘制图片。
虽然从技术上讲我们可以颠倒这些角色(例如,人们确实构建了只使用 D3 的整个 UI),但关键是要充分利用每个库,对我来说这是最合理的分解。
a teeny, tiny, tidy, twelve-line Viz component, which renders a single, empty div
D3 组件,即,将会非常小,即使我们使用它来制作的可视化将会占据绝大部分的视口——我们不希望 React 介入或访问它,所以我们真正需要的只是一个参考点——第十三行的空 Div。该 div 基本上是一个小花园围栏,标记 React 停止的位置,D3 开始。
a helper function which searches out an empty div with a ‘.viz’ class on it, and uses it as a reference to hang the SVG element and all its children on.
而这就是 D3 拿起来的样子!这里我们有一个有用的“绘制”功能。将它定义为 Viz 类的一个方法很有诱惑力,但是没有必要这样做,最终,我建议不要这样做。
一旦我们进入了 D3,我们就想尽可能地“用 D3 的方式”做所有的事情,对吗?这不仅是因为这是确保 D3 能够在最高水平上工作的好方法,也是因为这是确保下一个接触您的代码库的人知道正在发生什么以及如何有效地构建它的好方法。
因为 D3 将直接接触 DOM,在 React 的模型-视图-控制 jam 之外,它不需要知道关于它最终将被调用的组件的任何事情——它与应用程序的整体 React 结构无关,并且可以在某处的一些 helpers.js 文件中非常舒适地存在。就像我们在 React 空间中不引用 D3 一样,我们在这里也不会引用 React。
所有这一切的关键在于,D3 接触到的所有东西都在这里产生,并且只在这里生存。我们使用这个空的 to div 来挂我们的 SVG,并在这个空间内创建图片的每个部分——所有的子元素和它们的属性,以及它们可能有的任何交互。甚至这些元素的样式也存在于此——这降低了 CSS 冲突和不可预测的结果的可能性,也意味着当您需要改变可视化的外观和感觉时,您可以一站式购买,这在您开始使用 D3 的一些更大规模的构建功能时尤其方便。(顺便问一下,您是否知道可以生成色标,该色标将映射到您用作范围的任何数值上?相当狂野。)
在我们继续之前,关于可访问性有一个简短的说明:有几件事你可以相对容易地做,以便在广大用户遇到你的应用程序时给他们最完整的体验。
首先:您知道 SVG 有一个
<title>
元素吗,它可以被设置为类似于改变图像文本的功能。要使它工作,它必须是 SVG 的直接第一个子对象。想出为你的数据自动生成适当的和信息丰富的标题/alt 的方法可能是具有挑战性的,但绝对值得努力来制作一个包容性的应用程序。对于你所创造的形象,需要理解的最重要的事情是什么?你希望你的用户带走什么?第二:你打算让你的可视化互动吗?通过点击或悬停,是否有更多信息或操作变得可用?并不是所有的用户都能够访问它们,使用屏幕阅读器或有运动障碍的人可能不会使用鼠标。任何对你的 UX 来说重要的功能都应该可以通过键盘导航来实现。还好,那不是太难!SVG 形状有效地采用了 tabindex 属性,这将允许您的用户在可视化的每个部分之间切换。一旦到了那里,如果您将您的
element.on('hover',...)
行为复制到element.on('focusin',...)
,将您的element.on('click',...)
复制到element.on('keydown',...)
,在那里您检查以确保击键来自确认键,会怎么样?有多少人能享受到你辛勤工作的成果?
a teeny, tiny, tidy, twelve-line Viz component, which renders a single, empty div
所以,回到我们的 Viz 组件。一旦我们设置好了 draw 函数,我们需要做就是使用它。如果你还记得我们的控制器组件是如何工作的,它只会在实际有形状要画的时候进行渲染,所以一旦我们安装了我们的组件,很明显在那一点上我们想要调用 draw 并把我们得到的数据传递给它。但是如果我们的用户添加更多的形状呢?嗯,componentDidUpdate
钩子将被触发,因为关于这些形状的信息将改变 Viz 从控制器获得的道具,我们可以告诉 draw 再次做它的事情,但这次是用最新的数据。我们也不必担心 React 的干扰,因为实际上 React 甚至不知道我们的 SVG 在那里——它只是接收新的道具并做它被告知的事情。
如果你是在去年这样做的(或者你确实读过我的第一篇关于让 React 和 D3 在一起时表现自己的文章),你可能会记得这个过程稍微复杂一点——你必须使用shouldComponentUpdate
手动关闭 React 重新渲染,并且在它们变成this.props
之前,使用componentWillReceiveProps
用nextProps
处理你的重绘。幸运的是,这两种生命周期方法都被弃用了,它们的功能包含在更少的函数调用中,这很好。
这不禁让人想知道,有没有更好、更酷、更紧凑、更先进的方法来做这件事?
我很高兴你这么问。看看这个,伙计们:
A six — count ’em SIX — line Viz Component, just as functional, but short and sweet
React 钩子仍然在 alpha 中,所以它们可能不太适合您的产品级代码,但是看看这个组件看起来有多光滑!钩子让我们保持组件的功能,即使我们需要生命周期方法或内部状态。这使得调试和阅读我们的代码更加容易。
这个组件中发生的事情与它上面的基于类的组件完全相同。useEffect
实质上取代了我们之前的componentDidMount
和componentDidUpdate
功能。useEffect
需要两个参数来完成工作——一个函数,它将在组件进行渲染的任何时候运行(在本例中,是我们熟悉的老 draw 函数),以及一个比较器,它使用该比较器来判断是否发生了足够多的变化来运行该函数。在这种情况下,我们告诉 useEffect 只在 shapes 数组的长度改变时运行它的函数,因为这就是我们如何知道我们有一个新的形状要绘制。很简单,对吧?React 向我们承诺,在可预见的未来,类不会消失,我也不特别希望它们消失,但是有另一种选择是很酷的。
我希望这篇简短的文章已经说明了在 React 应用程序中使用 D3 是多么容易和不令人生畏(顺便说一下,这是一个很好的路线图,可以将 React 与任何使用 DOM 的第三方库一起使用)——它是否启发了你用它来制作很酷的东西?给我看看!跟我说说!或者,告诉我你认为我哪里错了,这也很有趣。
a gratuitous cat picture of Ellis, holding a catnip banana
阅读 NIPS/NeurIPS 2018 的摘要!以下是我学到的东西
Photo by chuttersnap on Unsplash
我决定读完 NIPS/NeurIPS 2018 的所有摘要。但事实证明,在我想要的时间框架内,这在身体上和精神上都是难以置信的。本次会议共收到 1011 篇论文,其中包括 30 篇口头论文、168 篇聚焦论文和 813 篇海报论文,论文接受率为 20.8%。(来源)
我想在会议开始前的 24 小时内读完所有的摘要。我花了 1440 分钟阅读了 1011 篇摘要,平均时间为 1.42 分钟。我完全是愚蠢的,我想把摘要总结成一个迷你摘要,这样当我以后回到它或者分享它时,就可以很容易地理解一个简明的摘要。
我开始阅读摘要,从会议的第一个海报会议“Tue 海报会议 A”(它有 168 篇论文)中选取了 20 篇(前 20 篇)。我花了 210 分钟多一点的时间来阅读和总结(提取方式,提取一些摘要),平均每篇论文 10.5 分钟。我加快了速度,不太担心总结,我在大约 150 分钟内完成了接下来的 20 个,平均 7.5 分钟。接下来的 20 分钟大约 90 分钟。接下来的 20 分钟大约需要 70-80 分钟。接下来的 20 分钟将在 60-70 分钟内完成。140 篇论文后,我放弃了时间限制,休息了一会儿。
尽管如此,当我结束一个 20 人的小组,去另一个小组时,奇妙的事情发生了。阅读一份扎实的研究调查的浓缩摘要真的令人生畏和不知所措,即使是一份,我也要读 20 份这样的论文并继续读下去。阅读前 20 篇论文,任何我不知道的理论或我不熟悉的主题都会阻止我理解他们正在解决的问题或他们解决方案的价值。
但是,最终我不那么害怕他们使用的理论或他们解决问题的独特新颖性,并把它们视为解决特定限制或扩展现有工作多功能性的灵感或见解。当我阅读摘要时,我感到很容易注意到他们正在解决的问题以及他们的解决方案对该领域的新颖性、有效性和影响。
总的来说,我真的很高兴我让自己阅读了非正常数量的摘要,尽管从很多方面来看这似乎是致命的!!我仍然想阅读会议的所有摘要,但这可能需要一周的时间。我会通知你的。
这些是我必须阅读的论文(除了整个“周二海报会议 A”还有 18 篇论文)和他们的摘要。标签在表现这些论文时并不那么有效,它们仅仅是人类潜在的感知开销,有时被视为感觉。
使用椭圆分布的 Wasserstein 空间概括点嵌入
基本原则
一种新的嵌入框架,它是数值灵活的,并且扩展了 wessserstein 空间中的点嵌入、椭圆嵌入。Wasserstein 椭圆嵌入更直观,并且产生比具有 Kullback-Leibler 散度的高斯嵌入的替代选择在数值上表现更好的工具。本文通过将椭圆嵌入用于可视化、计算词的嵌入以及反映蕴涵或上下级关系来展示椭圆嵌入的优点。
甘人生而平等吗?大规模研究
系统评估,真正了解
尽管大量的研究活动产生了许多有趣的 GAN 算法,但仍然很难评估哪些算法的性能优于其他算法。我们对最先进的模型和评估方法进行了中立的、多方面的大规模实证研究。我们发现,通过足够的超参数优化和随机重启,大多数模型都可以达到类似的分数。这表明,除了基本的算法变化之外,更高的计算预算和调整也能带来改进。为了克服当前度量的一些限制,我们还提出了几个数据集,在这些数据集上可以计算精度和召回率。我们的实验结果表明,未来的氮化镓研究应基于更系统和客观的评估程序。最后,我们没有发现任何测试算法始终优于在{ cite good fellow 2014 generate }中介绍的不饱和 GAN 的证据。
渔网:图像、区域和像素级预测的多功能支柱
基本面,在核心
设计卷积神经网络(CNN)结构以预测不同级别(例如图像级别、区域级别和像素级别)上的对象的基本原理是不同的。通常,专门为图像分类设计的网络结构被直接用作包括检测和分割在内的其他任务的默认主干结构,但是很少有主干结构是在考虑统一为像素级或区域级预测任务设计的网络的优点的情况下设计的,这些预测任务可能需要具有高分辨率的非常深的特征。朝着这个目标,我们设计了一个类似鱼的网络,称为鱼网。在 FishNet 中,所有分辨率的信息都被保留下来,并为最终任务进行优化。此外,我们观察到现有的工作仍然不能直接将梯度信息从深层传播到浅层。我们的设计可以更好的处理这个问题。已经进行了大量的实验来证明鱼网的卓越性能。特别是在 ImageNet-1k 上,FishNet 的精度能够以较少的参数超越 DenseNet 和 ResNet 的性能。渔网被用作 COCO Detection 2018 挑战赛获奖作品的模块之一。该代码可在https://github.com/kevin-ssy/FishNet获得。
辉光:具有可逆的 1x1 卷积的生成流
实用神奇,美观大方
具有 1x1 可逆卷积的基于流的生成模型,证明了对数似然和定量样本质量的显著改善。也许最引人注目的是,它证明了朝着简单对数似然目标优化的生成模型能够有效地合成大的和主观上逼真的图像。
卷积神经网络的一个有趣的失败和 CoordConv 解决方案
有意思,是时候了
我们已经展示了 CNN 对坐标转换任务建模的奇怪无能,展示了 CoordConv 层形式的简单修复,并给出了表明包括这些层可以在广泛的应用中提高性能的结果。在 GAN 中使用 CoordConv 产生的模式崩溃更少,因为高级空间延迟和像素之间的转换变得更容易学习。在 MNIST 检测上训练的更快的 R-CNN 检测模型显示,当使用 CoordConv 时,IOU 提高了 24%,并且在强化学习(RL)领域中,玩 Atari 游戏的代理从 CoordConv 层的使用中显著受益。
哪些神经网络架构会产生爆炸和消失梯度?
基础知识,理解
我们给出了随机初始化的全连通网络 N 中梯度的统计行为的严格分析。我们的结果表明,N 的输入-输出雅可比矩阵中的项的平方的经验方差在简单的结构相关常数β中是指数的,由隐藏层宽度的倒数之和给出。当β较大时,N 在初始化时计算的梯度变化很大。我们的方法补充了随机网络的平均场理论分析。从这个观点出发,我们严格地计算了混沌边缘梯度统计的有限宽度修正。
具有稀疏和量化通信的分布式深度学习的线性加速分析
实际的
巨大的通信开销已经成为分布式随机梯度下降(SGD)训练深度神经网络的性能瓶颈。先前的工作已经证明了使用梯度稀疏化和量化来降低通信成本的潜力。然而,对于稀疏和量化通信如何影响训练算法的收敛速度,仍然缺乏了解。本文研究了非凸优化的分布式 SGD 在两种减少通信量的策略下的收敛速度:稀疏参数平均和梯度量化。我们证明了如果稀疏化和量化超参数配置得当,可以达到 O (1/√ MK )的收敛速度。我们还提出了一种称为周期量化平均(PQASGD)的策略,在保持 O (1/√ MK )收敛速度的同时,进一步降低了通信开销。我们的评估验证了我们的理论结果,并表明我们的 PQASGD 可以像全通信 SGD 一样快地收敛,而通信数据大小仅为 3 %- 5%。
通过激活样本方差的方差进行正则化
基本原理,标准化
规范化技术在支持深度神经网络的高效且通常更有效的训练中起着重要作用。虽然传统的方法显式归一化的激活,我们建议添加一个损失项代替。这个新的损失项鼓励激活的方差保持稳定,而不是从一个随机小批量到下一个随机小批量变化。最后,我们能够将新的正则项与 batchnorm 方法联系起来,这为它提供了正则化的视角。我们的实验表明,对于 CNN 和全连接网络,在准确性上比 batchnorm 技术有所提高。
卷积神经网络的突触强度
突触修剪,神经科学
卷积神经网络(CNN)是计算和存储密集型的,这阻碍了它们在移动设备中的部署。受神经科学文献中相关概念的启发,我们提出突触修剪:一种数据驱动的方法,用一种新提出的称为突触强度的参数来修剪输入和输出特征图之间的连接。突触强度被设计为基于其传输的信息量来捕捉连接的重要性。实验结果表明了该方法的有效性。在 CIFAR-10 上,我们为各种 CNN 模型修剪了高达 96%的连接,这导致了显著的大小减少和计算节省。
DropMax:自适应变分 Softmax
干净的
我们提出了 DropMax,一个随机版本的 softmax 分类器,它在每次迭代中根据每个实例自适应决定的丢弃概率丢弃非目标类。具体来说,我们在类输出概率上覆盖二进制掩蔽变量,这是通过变分推理输入自适应学习的。这种随机正则化具有从具有不同决策边界的指数级分类器中构建集成分类器的效果。此外,对每个实例上的非目标类的辍学率的学习允许分类器更多地关注针对最混乱的类的分类。我们在多个用于分类的公共数据集上验证了我们的模型,在该数据集上,它获得了比常规 softmax 分类器和其他基线显著提高的准确性。对学习到的丢弃概率的进一步分析表明,我们的模型在执行分类时确实更经常地选择混淆类。
关系递归神经网络
革命的
基于记忆的神经网络通过利用长时间记忆信息的能力来模拟时态数据。然而,还不清楚他们是否也有能力用他们记忆的信息进行复杂的关系推理。在这里,我们首先确认我们的直觉,即标准内存架构可能会在大量涉及理解实体连接方式的任务中挣扎,即,涉及关系推理的任务。然后,我们通过使用一种新的内存模块(关系内存核心(RMC))来改善这些缺陷,这种内存模块采用多头点积注意力来允许内存进行交互。最后,我们在一组任务上测试了 RMC,这些任务可能受益于跨顺序信息的更有能力的关系推理,并显示了在 RL 域(BoxWorld & Mini PacMan)、程序评估和语言建模方面的巨大收益,在 WikiText-103、Project Gutenberg 和 GigaWord 数据集上实现了最先进的结果。
在知识图上嵌入逻辑查询
少数方法
学习知识图的低维嵌入是一种用于预测实体之间未观察到的或缺失的边的强大方法。然而,该领域的一个公开挑战是开发能够超越简单边缘预测并处理更复杂逻辑查询的技术,这可能涉及多个未观察到的边缘、实体和变量。例如,给定一个不完整的生物学知识图表,我们可能想要预测“什么药物可能针对与 X 和 Y 疾病都相关的蛋白质?”—需要对可能与疾病 X 和 y 相互作用的所有可能蛋白质进行推理的查询。这里,我们介绍了一个框架,以在不完整的知识图上有效地对合取逻辑查询进行预测,这是一个灵活但易于处理的一阶逻辑子集。在我们的方法中,我们在低维空间中嵌入图节点,并在该嵌入空间中将逻辑运算符表示为学习到的几何运算(例如,平移、旋转)。通过在低维嵌入空间内执行逻辑运算,我们的方法实现了与查询变量的数量成线性的时间复杂度,相比之下,基于简单枚举的方法需要指数复杂度。我们在两个对具有数百万关系的真实世界数据集的应用研究中展示了该框架的效用:预测药物-基因-疾病相互作用网络中的逻辑关系,以及来自流行网络论坛的基于图形的社会相互作用表示。
作为多目标优化的多任务学习
大问题
在多任务学习中,多个任务被联合解决,在它们之间共享归纳偏差。多任务学习本质上是一个多目标的问题,因为不同的任务可能会发生冲突,需要进行权衡。一个常见的折衷方案是优化一个代理目标,使每个任务损失的加权线性组合最小化。但是,这种解决方法仅在任务不竞争时有效,这种情况很少发生。在本文中,我们明确地将多任务学习视为多目标优化,总目标是找到一个帕累托最优解。为此,我们使用在基于梯度的多目标优化文献中开发的算法。这些算法不能直接应用于大规模学习问题,因为它们与梯度的维度和任务的数量的比例很差。因此,我们提出了一个多目标损失的上限,并表明它可以有效地优化。我们进一步证明,在现实的假设下,优化这个上限会产生一个帕累托最优解。我们将我们的方法应用于各种多任务深度学习问题,包括数字分类、场景理解(联合语义分割、实例分割和深度估计)和多标签分类。我们的方法比最近的多任务学习公式或每任务训练产生更高性能的模型。
Mesh-TensorFlow:超级计算机的深度学习
解决方案
批处理分裂(数据并行)是主要的分布式深度神经网络(DNN)训练策略,因为它的普遍适用性及其对单程序多数据(SPMD)编程的适应性。然而,批量分割存在一些问题,包括无法训练非常大的模型(由于内存限制)、高延迟以及小批量时效率低下。所有这些都可以通过更通用的分布策略(模型并行)来解决。不幸的是,有效的模型并行算法往往难以发现、描述和实现,尤其是在大型集群上。我们介绍网格张量流,这是一种用于描述一般分布式张量计算的语言。在数据并行性可以被视为沿着“批处理”维度拆分张量和操作的情况下,在 Mesh-TensorFlow 中,用户可以指定要在多维处理器网格的任何维度上拆分的任何张量维度。一个网格张量流图编译成一个 SPMD 程序,该程序由并行操作和集体通信原语(如 Allreduce)组成。我们使用 Mesh-TensorFlow 来实现变压器序列到序列模型的高效数据并行、模型并行版本。使用多达 512 个核心的 TPU 网格,我们训练了多达 50 亿个参数的变压器模型,超过了 SOTA 在 WMT 的 14 个英语到法语翻译任务和 10 亿词语言建模基准上的结果。网格张量流在https://github.com/tensorflow/mesh可用
我无法停止思考 NeurIPS!!也不写它。
**编辑:**我发表了前两次海报会议的部分论文(330 多篇论文)
[## NIPS/NeurIPS 2018:前两次海报会议的最佳*
330 多篇论文的阅读清单,根据它们的效用或优点分组
towardsdatascience.com](/neurips-2018-reading-list-from-tue-poster-sessions-a-b-fce561e56be8)
就绪…设置…人工智能—为未来准备 NHS 医学成像数据
Image courtesy of the Invisible Light X-ray art gallery (http://www.invisiblelight.com.au/)
除非放射科医生在过去的几年里把自己关在黑暗的房间里。),他们将听说即将到来的放射学人工智能算法海啸,它将使他们的工作更快,他们的报告更精确,他们的实践更有影响力。我们中的积极分子将开始考虑如何参与开发放射学人工智能,有些人,像我一样,将积极致力于特定任务的用例、研究和验证。这很好——但我保证无论你在做什么数据集都不够大,你渴望更多。也许你可以从 NIH 获得免费的 10 万张胸透照片?或者你说服了你的医院让你检查他们的 PAC?或者也许你在 IBM 工作,可以接触到所有甜蜜的合并医疗数据?
对你有好处。获取医疗数据并使其独享和专有的热潮让我想起了两个世纪前的淘金热。勘探者成群结队地来到这里,与投资者讨价还价以获得开始挖掘的资金,乞求资金来购买地块,并在承诺黄金财富的同时寻求设备投资。然而,在挖掘真正有价值的东西和取出大块的固体矿石之前,有一个心照不宣且经常被忽视的障碍需要跨越…
问题是…医学成像数据还没有为人工智能做好准备
在医学成像数据上开发机器学习算法不仅仅是获取数据的问题。虽然访问本身当然是一个非常令人头疼的问题(看看 DeepMind 就知道一个明显的例子),但这并不是比赛中唯一的障碍。在本文中,我将解释数据准备的概念,以及在准备数据方面的投资为何比开发第一个算法更重要。
数据准备阶段
没有定义和普遍接受的尺度来描述准备好的数据如何用于机器学习。许多管理咨询公司会提供漂亮的幻灯片,告诉你如何收集数据并从中创造见解(并为这种特权收取高额费用),但数据就绪性的基本原则仍然是一个很大程度上无法量化的过程。
Neil Lawrence 教授(谢菲尔德,亚马逊)写的一篇鲜为人知但非常重要的关于数据就绪的论文引起了我的注意,在阅读了这篇论文并与他联系讨论后,我提出了自己的数据就绪量表的修改版。
Medical imaging data readiness scale
让我们从头开始,从 D 级开始…
每个人都想要 D
想象你拥有一个巨大的油田。想象一下这是多么美好的事情。除非你是 NHS,在这种情况下,你不必想象,因为你已经拥有一个巨大的油田!问题是,你的油田对于那些想把石油挖出来并把它变成汽油来为你赚取巨额利润的人来说是完全无法进入的。不仅如此,还有法律和道德的阻碍(甚至不要让我开始谈论 GDPR)。没有人,甚至是你,知道你的油田里到底有什么。你的油田就是我所说的‘D 级’数据。
D 级数据在数量和质量上都无法验证,不可访问,并且其格式使得机器学习很难或不可能做任何事情。这种级别的未匿名数据存在于每一家医院的 trust PACS 归档中,数量庞大,除了记录临床活动之外,什么也不做。(而且……我一想到这个就不寒而栗……由于数据存储问题,NHS 信托基金经常会删除这些积压的数据。比如扔油……)
为了将 D 级数据提升到 C 级,你需要建造一个精炼厂。数据提炼的第一步是获得访问数据的道德许可。在实践中,这是通过一个数据共享协议来实现的,要么通过一个道德委员会在本地与你自己共享,要么与第三方(大学、公司或初创企业)共享。NHS 信托可能在任何时候都有数以千计的数据共享协议。这些协议还将包括数据匿名化的条款,因为显然没有人希望 NHS 泄露机密的患者信息。到目前为止还不错…但是,数据仍然是非结构化的,不能代表一个完整的集合。这也将是非常嘈杂的,充满了错误,遗漏和只是简单怪异的条目。无论是谁,只要能接触到这些数据,现在都必须想办法让它们变得有用,然后才能开始算法开发。c 级数据已经准备好提供给人工智能开发者,但还远远没有准备好派上用场。
让它 B…
现在需要将数据进一步细化为 B 级数据,对其进行结构化,确保其代表您认为自己拥有的数据,并对其进行可视化,以便能够深入了解噪声特征和其他分析指标。这个过程实际上比 D 到 C 阶段更难,因为它是为每个数据集定制的。没有检查医学成像数据的标准方法,每个有权访问您的数据的小组将运行他们自己的数据可视化和分析。这是因为来自不同医院的数据将具有不同的特征和不同的格式(例如,不同的 DICOM 标题、日期和时间戳等)。将 C 级转化为 B 级的过程可能需要几个月——这可不是研究人员或初创企业在争夺金牌的过程中所需要的。只有有了 B 级的数据,你才能对它的可能性有一个概念,以及 AI 在哪里可以用来解决实际问题。
仅仅是最好的(比所有其他的都好)
对于算法开发来说,A 级数据是最接近完美的——它是结构化的,完全注释的,噪音最小,最重要的是,它在上下文中是适当的,并为特定的机器学习任务做好了准备。例如,100 万次肝脏超声检查的完整数据集,包括患者年龄、性别、纤维化评分、活检结果、肝功能测试(lft)和诊断,所有这些都在相同的元标签下构建,可用于深度学习算法,以确定哪些患者在 B 型超声扫描中有患非酒精性脂肪性肝病(NAFLD)的风险。
注释可能是放射学数据集提炼中最困难的部分——理想情况下,每一个图像发现都应该由经验丰富的放射科医师进行注释,以便在整个数据集内准确一致地突出显示所有可能的病理。问题是——世界上几乎没有任何现有的医学成像数据是以这种方式标注的。事实上,大多数“野生”图像甚至没有注释。这就是为什么有一个围绕数据标签的整个行业。有没有登录一个网站,被要求点击包含路标或汽车的图片?你在为自动驾驶汽车算法标记数据!当然,并不是每个互联网用户都是放射科医生,所以这种众包模式并不适用于医学成像(除非你经营无线医疗——有一个免费的商业创意给你们!).相反,研究人员不得不乞求或支付放射科医生的时间来注释他们的数据集——这是一项极其缓慢和昂贵的任务(相信我,我在论文期间花了 6 个月时间绘制前列腺周围的轮廓……)。另一种方法是在成像报告上使用自然语言处理(NLP)来挖掘概念,并使用它们来标记图像——然而,这种模型还远远没有证明足够健壮。
推测积累
从 D 级数据一直到 A 级数据的上述提炼过程在时间和资源方面都是昂贵的。我经常看到小型研究小组开始时提出一个大胆的建议,用机器学习来解决一个特定的任务,急于获得数据访问权,却被为什么他们的算法从未达到有用的准确率所困扰,然后放弃。他们试图避开提炼过程,结果被抓了出来。甚至像 IBM 这样的大玩家也在这个问题上苦苦挣扎。他们可以访问大量的数据,但是需要花费大量的时间和精力来准备这些数据,使其具有可操作性和实用性。
与任何投机性投资一样,你必须为基础设施建设融资,才能在下游获得收益。这就是为什么我提出了一个承担这项工作的国家框架,我称之为英国放射学人工智能网络(大脑)。这个想法是利用最近宣布的政府生命科学战略来获得资金,以创建一个基于 NHS 成像数据的全新产业。BRAIN 将充当匿名成像数据的“数据信托”或仓库,允许研究人员和公司访问,以换取知识产权权益。通过建立 BRAIN,NHS 将立即将数据准备程度提高到 C 级,然后随后的每一项研究活动都将有助于完善汇集的数据,将数据从 C 级提升到 A 级,为放射学人工智能的发展创造丰富的资源,增加数据集的价值。
这种设置的优势是巨大的 NHS 不仅在保持控制的同时开放了大量的数据,还通过对数据进行精炼和分享任何产生的知识产权,从人工智能发展的回报中获益两倍。此外,NHS 医院不再需要管理成千上万的数据共享协议(这是一项资源密集型任务)——它们只需将人们引向 BRAIN。
对研究人员和公司来说,好处也很大——他们都可以通过一个集中的数据共享协议访问数据(不再需要一个接一个地催促各个医院),数据池比他们以前可以访问的任何数据都大,随着时间的推移,他们花在数据提炼上的资源越来越少,而花在开发有用算法上的时间越来越多。好处不止于此——通过汇集来自 NHS 的数据,您可以减少数据中的偏差,并将算法暴露于更广泛的成像技术、报告风格和病理,最终使最终产品算法更具通用性,可用于任何设置。
发展新产业
梅特卡夫定律(Metcalfe’s Law)指出,网络的价值随着用户数量的平方增长而增长(看看脸书或 Twitter——庞大的网络,巨大的价值)。通过集中访问大型汇集数据集并邀请数百名研究人员参与,您可以立即显著增加网络的价值。所需要的只是一个建立它的承诺。人们只需要看看英国生物银行的成功就能明白为什么这样的网络是至关重要的(他们只有 1000 多台核磁共振成像仪)。
放射学人工智能领域就像是蛮荒的西部——它需要一个镇上的警长。通过汇集结构化数据,英国和 NHS 可以催生一个新的研究行业,同时收获回报。这是我对医学影像和 AI 海量数据的大梦想;我希望我已经说服你分享它!
如果你和我一样对放射学人工智能的未来感到兴奋,并想讨论这些想法,请保持联系。我在推特@drhughharvey
如果你喜欢这篇文章,点击推荐并分享它会很有帮助。
关于作者:
Harvey 博士是一名委员会认证的放射科医生和临床学者,在英国国民医疗服务体系和欧洲领先的癌症研究机构 ICR 接受过培训,并两次获得年度科学作家奖。他曾在 Babylon Health 工作,领导监管事务团队,在人工智能支持的分诊服务中获得了世界第一的 CE 标记,现在是顾问放射科医生,皇家放射学家学会信息学委员会成员,以及人工智能初创公司的顾问,包括 Kheiron Medical。
使用 Python 和 SAS 事件流处理进行实时分析
实时或接近实时应用的分析为从事这项工作的公司带来了最大的经济效益。这里的论点是,从数据中获取最大收益的最佳方式是提取即时洞察力,以便为生成该数据的业务提供增量价值。现在有很多公司都这么做(网飞、亚马逊等)。)——还有很多人想尽快完成这项工作,并有实现目标的路线图。这是我们都同意的——至少我最近在这个领域交谈过的大多数人似乎都这么认为。虽然对静态数据的分析不会有任何进展,但实时分析如今却变得相当流行。我确信这个时髦的词汇工厂会制造出诸如机器智能、认知计算、全渠道、物联网、云战略等词汇。会同意。
T 这篇文章的目的是展示一种“ 开放技术” 如 SAS 事件流处理(ESP) (参见 此处 了解 SAS ESP) 如何使用户能够快速创建一个实时事务处理管道,并在此过程中实现分析——即应用业务规则如果我告诉你,你可以用 Python 只使用 SAS ESP 自带的 GUI 工具完全做到这一点,那不是更好吗?好吧,我们就这么做,让静态数据科学变得生动起来!
我们将利用 SAS ESP 附带的微分析服务(MAS)插件,快速解决复杂的实时分析处理和决策问题。可以把 MAS 想象成“一桶任意代码”,它保存着我们想要为流处理任务执行的业务逻辑。
当我考虑这么做的时候,我不得不专注于一些需要实时解决方案的实际问题——一些企业需要处理并且必须立即采取行动的问题。因此,我决定在这篇文章中,我们将构建一个实时防欺诈引擎,它将对流中的交易进行评分/评估。我个人最喜欢的一个是实时推荐引擎——所以我改天再回到这个话题。此外,我认为个性化值得自己的关注——而不是隐藏在一个像这样谈论实时分析的帖子中。
好了,现在我已经把这篇文章推销了不少,足以让你恼火,让我们开始吧,希望我们能看到所有这些是如何与我们的防欺诈用例一起工作的。
创建流:
我们将使用位于 这里的 的数据集。它是一个 sqlite 数据库,允许我们将事务数据连续地流入我们的 ESP 应用程序。现在,我们将使用它来模拟一个流媒体源。我设置了一个小的 python 脚本来简化这个过程 这里 。所有这些都是初始设置项目,所以让我们浏览一下这些部分,如果您自己正在尝试,只需足够的细节就可以完成。这样,我们就不会陷入困境,并转移到用例的核心部分。这里有一个快速窥视我们的流媒体源
注意:此时,您将在您想要尝试的机器上部署(或已经拥有)SAS 事件流处理,并为微分析服务插件配置它。在 这里可以找到该任务的所有相关文档 。这是一个相当简单的过程。链接中的部署文档非常深入,一目了然。
现在,我们准备冒险设置我们的流应用程序。
思考整个过程(3TP):
使用 SAS ESP 的一个亮点是能够使用 GUI 快速编写复杂的流内转换和模式匹配逻辑。
我们将使用 GUI 为我们的检测过程建立一个整体的处理管道/流程。我们将通过以下方式实现这一目标
a.设置微分析服务(MAS)来管理我们的 python 文件,然后使用程序窗口在流中调用它
b.实施我们的机器学习算法,用于检测以及完成工作流程所需的规则、过滤器、连接和其他处理逻辑
当我做研究和思考什么是对的/什么是错的时,我喜欢思考高层次设计/架构的抽象过程,但帮助别人理解你的观点并不总是好的。因此,本着先做最后一件事的精神&为了帮助我们看到我们将到达的地方,这里是最终设置在 GUI 上的实际样子。
Streaming set up for Fraud Detection
上面你看到的是 窗口 相互连接的有向图。关键概念*:ESP 中的“窗口”是独立的节点,即高效执行单一任务/功能的流处理管道中的接触点。*
虽然上面的图片对我所说的内容提供了一些清晰度,但是图形用户界面中的东西看起来如何并不那么重要。重要的是,ESP 自动地将管道翻译成 XML 文件,供开发人员在生产环境中运行时部署在 ESP 服务器上。
这非常方便,因为迭代思想变得很容易。一旦你掌握了窍门,它会成为一个令人陶醉的玩具。如果你写代码(开发人员/研究人员/科学家等),这可能是一个甜蜜点。)因为你可以享受试验想法的自由,而不会陷入管理逻辑和句法细节的认知超载。所有这些越重要,你就越能理解你的逻辑在深层是如何运作的。此外,如果需要,您也可以选择深入研究。就这样,我又跑题了。
问题解析— 有什么快速解答 :
O K,为了检测欺诈,我们需要业务规则(陷阱/停止规则和释放规则)和 机器学习模型 (我们将使用 SAS E-Miner 实现一个,并将其移动到 ESP 中进行流内评分。在这篇文章中,我们不会关注 ML 模型的生成——那是另外一个时间了。
Ok, we’ll take some of it too!!
2017 规则#1 : 没有机器学习,就没有足够好的解决方案。想要证据吗?去看看 炒作周期 的巅峰。
但是,为什么规则?基本上,这些规则是企业用来帮助处理潜在的欺诈事件的。他们还可以使用规则来定义他们不想花费时间和精力的基于某种经验证据的交易特征。
最终,所有这些导致将可疑交易推入警报管理/交易审查工具,如可视调查器(或类似的东西),让审查代理/调查器处理这些交易的过程(取消/完成)。他们给银行打电话,做更深入的核实等等。诸如此类的事情。
设置脚本:
我们将使用 Python 编写陷阱规则和释放规则。我们将使用 MAS 插件设置它在 ESP 中工作。这将针对流中的所有事务运行。您可以从 GUI 工具配置 MAS 插件,如下所示:
Setting up the Micro Analytic Service
为了简单起见,我只为我们的虚拟项目使用了几条规则——在现实生活中可能有数百条——很容易以敏捷的方式修改。就像标准 python 一样,我们可以自由地返回任意数量的感兴趣的作用域变量。ESP 只需要一个提示,这个需求是在主函数的 docstring 中管理的,例如 manager 函数。否则,其他一切都保持不变。例如,你可以从其他模块或用户定义的对象(类/函数)借用多个辅助函数/方法,就像标准 python 一样。正如你在这里看到的,我们使用几个助手函数来管理我们的代码。
接下来,我们将设置 MAS 插件来引用 python 脚本,就像我已经展示的那样。它非常简单,您可以将整个 python 函数作为文本粘贴进去,也可以只提供脚本位置的路径(推荐)。在这之后,我们使用管道中的程序窗口指向代码定义的 MAS 插件中的主函数。
最后,我们将我们用 SAS E-Miner 创建的机器学习模型合并到 ESP 中,在将 SAS 分数代码翻译成 DS2 代码之后再次使用程序窗口。对于这一步,我使用了 PROC DSTRANS 并推荐这种方法。在这一步之后,你可以做一些简单的改变,但是这是非常直接的,结果看起来像T5。
注:如果你正在寻找用 E-Miner 构建机器学习模型的教程,请前往此 链接 。你会在那里找到很多资源。或者,您也可以挑选您的 scikit 学习模型并在 stream 中对其评分。
至此,我们用于欺诈检测的流引擎已经完成。我们已经制定了业务规则,检查了部署我们在待办事项列表上的机器学习模型。我甚至要让你知道这个卑鄙的小秘密。再次注意代码文件——我也用我的 sklearn 模型对事务进行评分。很容易,不是吗!因此,在所有这些之后,我们的流程会对交易进行评分,如下例所示:
Sample Scoring Result
请注意这一切是如何完美地工作的,其中规则和模型(SAS 和开源 ML 模型)都是为了实现相同的目标——根据一个公式分配一个警报分数(人类可以理解),当 ML 模型检测到警报时,该分数会偏高,而规则更有可能产生误报。上图还展示了 SAS ESP 为用户提供的处理能力。另一个例子是,如果你回到本文开头的流程图/有向图,过滤窗口(标有“截止”窗口)充当控制旋钮,允许我们根据企业希望吸收的风险大小,以灵活的阈值进行操作。从这一点开始,您可以定制您认为合适的流程,并让下游订户获取结果,并将其与支持更大业务流程的系统集成。
所以,你走吧!如果有一种简单的方法可以利用团队现有的技能来创建和部署实时解决方案,那么机会将是无限的。然后,您可以开始挑选用例库存中更高的东西&创建优雅的解决方案来解决它们。以前不可能的事情,现在变成了可能!
使用 Tensorflow,OpenCV 和 Docker 的实时和视频处理对象检测。
在本文中,我将介绍如何在 Docker 容器中使用 Tensorflow 对象检测 API 来执行实时(网络摄像头)和视频后处理。我使用 OpenCV 和 python3 多处理和多线程库。
我将把重点放在我遇到的障碍,以及我找到了什么解决方案(或者没有!).完整的代码在我的 Github 上。
Video processing test with Youtube video
动机
我从这篇优秀的 Dat Tran 文章开始探索实时对象检测的挑战,引导我用 Adrian Rosebrock 的网站研究 python 多处理库来增加 FPS。为了进一步增强可移植性,我想将我的项目集成到 Docker 容器中。这里的主要困难是处理进入和来自容器的视频流。
此外,我在我的项目中添加了一个视频后处理功能,也使用了多处理来减少处理时间(当使用原始 Tensorflow 对象检测 API 时,处理时间可能会非常非常长)。
在我的个人笔记本电脑上,仅使用 8GB CPU,实时和视频处理都可以高性能运行。
数据科学码头工人
我不会花时间描述 Tensorflow 对象检测 API 实现,因为关于这个主题的文章很多。相反,我将展示如何在我作为数据科学家的日常工作中使用 Docker。请注意,我使用了 Tensorflow 的经典 ssd_mobilenet_v2_coco 模型,以获得速度性能。我复制了这个模型。pb 文件)和相应的本地标签映射(在模型/目录中)以保持以后使用个人模型的可能性。
我相信今天使用 Docker 已经成为数据科学家的一项基本技能。在数据科学和机器学习领域,每周都会发布许多新的算法、工具和程序,将它们安装到您的计算机上进行测试是让您的操作系统崩溃的最佳方式(有经验的!).为了防止这种情况,我现在使用 Docker 容器来创建我的数据科学工作区。
你可以在我的知识库中找到我正在为这个项目工作的 docker 文件。下面是我如何安装 Tensorflow 对象检测(遵循官方安装指南):
# Install tensorFlow
RUN pip install -U tensorflow# Install tensorflow models object detection
RUN git clone [https://github.com/tensorflow/models](https://github.com/tensorflow/models) /usr/local/lib/python3.5/dist-packages/tensorflow/models
RUN apt-get install -y protobuf-compiler python-pil python-lxml python-tk#Set TF object detection available
ENV PYTHONPATH "$PYTHONPATH:/usr/local/lib/python3.5/dist-packages/tensorflow/models/research:/usr/local/lib/python3.5/dist-packages/tensorflow/models/research/slim"
RUN cd /usr/local/lib/python3.5/dist-packages/tensorflow/models/research && protoc object_detection/protos/*.proto --python_out=.
同样,我安装了 OpenCV:
# Install OpenCV
RUN git clone [https://github.com/opencv/opencv.git](https://github.com/opencv/opencv.git) /usr/local/src/opencv
RUN cd /usr/local/src/opencv/ && mkdir build
RUN cd /usr/local/src/opencv/build && cmake -D CMAKE_INSTALL_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local/ .. && make -j4 && make install
图像构建有点长,需要几分钟时间。然后,使用它是快速和容易的。
实时目标检测
我首先尝试应用对象检测到我的网络摄像头流。这项工作的主要部分在 Dat Tran 的文章中有完整的描述。困难在于将网络摄像头流发送到 docker 容器中,并使用 X11 服务器恢复输出流以显示它。
将视频流发送到容器中
在 Linux 中,设备位于/dev/目录中,可以作为文件进行操作。通常,您的笔记本电脑网络摄像头是“0”设备。要将其流发送到 docker 容器中,在运行 docker 映像时使用设备参数:
docker run --device=/dev/video0
对于 Mac 和 Windows 用户来说,将网络摄像头流发送到容器中的方式不像 Linux 那样简单(尽管 Mac 是基于 Unix 的)。我没有深入研究这个问题,但是 Windows 用户的解决方案是使用虚拟盒子来启动 docker 容器。
从容器中恢复视频流
这是我花了一些时间解决的问题(解决方案不令人满意)。我在 Docker 这里找到了关于使用图形用户界面的有用信息,特别是将容器连接到主机的 X 服务器进行显示。
首先,您必须公开您的 xhost,这样容器就可以通过 X11 unix 套接字读写来正确显示。首先设置 X 服务器主机的权限(这不是最安全的方法)让 docker 访问它:
xhost +local:docker
然后,当您使用完项目后,将访问控制恢复为默认值:
xhost -local:docker
然后,创建两个环境变量 XSOCK 和 XAUTH:
XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth
第一个引用 X11 Unix 套接字,第二个引用我们现在创建的具有适当权限的 X 身份验证文件:
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
最后,我们只需更新 docker 运行行命令。我们转发我们的 DISPLAY 环境变量,为 X11 Unix 套接字和 X 身份验证文件挂载一个卷,该文件带有一个名为 XAUTHORITY 的环境变量,它链接到:
docker run -it --rm --device=/dev/video0 -e DISPLAY=$DISPLAY -v $XSOCK:$XSOCK -v $XAUTH:$XAUTH -e XAUTHORITY=$XAUTH
现在我们可以运行 docker 容器了,它已经完成了:
Me with common objects at work (I’m a shy person).
尽管主机的 X 服务器配置,我不能完全删除我的代码中似乎是一个错误。OpenCV 需要通过使用 cv2.imshow 函数调用 python 脚本( init-openCV.py )进行“初始化”。我得到以下错误消息:
The program 'frame' received an X Window System error.
然后,可以调用主 python 脚本( my-object-detection.py )并且视频流被很好地发送到主机显示器。我对使用第一个 python 脚本来初始化 X11 系统的解决方案不是很满意,但是到目前为止我还没有找到任何解决这个问题的方法。
编辑:我终于(而且不小心!)通过使用 OpenCV (3.4.1)的稳定版本,而不是在本地克隆 git repo,找到了这个问题的解决方案。因此,现在不需要在主 python 脚本之前调用 init-openCV.py 。
视频处理
为了设法用我的网络摄像头实时运行对象检测 API,我使用了线程和多处理 python 库。一个线程被用来读取网络摄像头流。帧被放入队列中,由一组工作线程(Tensorflow 对象检测在其中运行)进行处理。
出于视频处理的目的,不可能使用线程,因为在工人能够对放入输入队列的第一个帧应用对象检测之前,所有视频的帧都被读取。输入队列已满时读取的帧会丢失。也许使用大量工作人员和庞大的队列可以解决这个问题(计算成本高得令人望而却步)。
简单队列的另一个问题是,由于不断变化的分析时间,帧在输出队列中的发布顺序不同于在输入队列中的顺序。
为了增加我的视频处理功能,我移除了读取帧的线程。相反,我使用下面几行代码来读取帧:
while True:
# Check input queue is not full
if not input_q.full():
# Read frame and store in input queue
ret, frame = vs.read()
if ret:
input_q.put((int(vs.get(cv2.CAP_PROP_POS_FRAMES)),frame))
如果输入队列未满,则从视频流中读取下一帧并放入队列。否则,当帧没有从输入队列中获取时,什么也不做。
为了解决帧顺序的问题,我使用了一个优先级队列作为第二个输出队列:
- 读取帧并将其与相应的帧编号一起放入输入队列(实际上,一个 python 列表对象被放入队列)。
- 然后,工人从输入队列中取出帧,对它们进行处理,并将其放入第一个输出队列中(仍然使用它们的相对帧号)。
while True:
frame = input_q.get()frame_rgb = cv2.cvtColor(frame[1], cv2.COLOR_BGR2RGB)
output_q.put((frame[0], detect_objects(frame_rgb, sess, detection_graph)))
3.如果输出队列不为空,则帧被提取并放入优先级队列,其对应的帧号作为优先级号。优先级队列的大小被任意设置为其它队列大小的三倍。
# Check output queue is not empty
if not output_q.empty():
# Recover treated frame in output queue and feed priority queue
output_pq.put(output_q.get())
4.最后,如果输出优先级队列不为空,则采用优先级最高的帧(优先级最小的帧)(这是标准优先级队列)。如果先前对应于预期的帧号,则该帧被添加到输出视频流(并且如果需要的话写入),否则该帧被放回到优先级队列中。
# Check output priority queue is not empty
if not output_pq.empty():
prior, output_frame = output_pq.get()
if prior > countWriteFrame:
output_pq.put((prior, output_frame))
else:
countWriteFrame = countWriteFrame + 1
# Do something with your frame
为了停止这个过程,我检查了所有的队列都是空的,并且所有的帧都已经从视频流中提取出来:
if((not ret) & input_q.empty() &
output_q.empty() & output_pq.empty()):
break
结论
在本文中,我将介绍如何使用 docker 通过 Tensorflow 实现一个实时对象检测项目。如上所述,docker 是测试新数据科学工具以及打包我们向客户交付的解决方案的最安全方式。我还向您展示了我是如何改编 Dat Tran 的原始 python 脚本来执行多处理视频处理的。
如果你从头到尾看完这篇文章,谢谢你!正如你所看到的,这个项目有很多可能的改进。不要犹豫给我一些反馈,我总是渴望得到建议或意见。
在 python 中监视子编辑的实时机器人。
大家好,Reddit 是美国最大的社交新闻聚合之一。所有成员都可以在相关的子编辑中发表任何内容。如果你有一个被很多人使用的产品,那么了解他们对这个产品的感受是非常重要的。facebook、Twitter、reddit 等社交媒体平台。是人们使用最广泛的方法之一。Reddit 也是一个论坛,人们可以谈论和讨论任何事情。几乎所有的产品,无论是微软 Azure 还是 AWS,都有与用户交流的子界面。那么,如果你想了解用户的情绪,并从子编辑中获得所有负面的标题,以便你可以相应地改进产品,或者如果你想与用户实时互动,该怎么办呢?在这里,我将解释如果任何用户开始对与你相关的产品进行负面讨论,你如何通过标题的 URL 链接获得通知。
现在,除此之外,假设您还希望看到一个时间序列图,显示用户对您的产品进行负面评价的频率,并且您希望以某种形式显示出来,以便您可以看到有多少负面标题,有多少人对这些标题投了赞成票,以及有多少人参与了这些标题。
我想现在你一定已经知道我想要达到的目标了。假设你是一家为 PUBG、堡垒之夜、使命召唤、坦克世界等大型游戏提供语音服务的公司,你想知道人们在网上对语音服务的讨论。如果很多人投票赞成一个标题,那么这意味着它是一个普通的问题,你可以实时处理它。但是如果只有很少的投票,那么问题可能出在用户端,比如速度慢之类的。
那么,让我们开始吧。
1.)首先,我们需要像下面这样的一些细节,可以通过在 twitter 上创建并遵循【https://redditclient.readthedocs.io/en/latest/oauth/
T2 的指示。你可以使用自己的 reddit 帐户,因为没有必要使用官方 vivox 帐户,我不知道我们是否有任何官方 reddit 帐户。
客户端标识 = ‘客户端标识’,\
客户端秘密 = ‘客户端秘密’,\
用户代理 = ‘用户代理’,\
用户名 = ‘用户名’,\
密码=‘密码’
2.)要与 slack 交互,我们需要创建一个 slack bot API,您可以按照下面的说明创建它:-
松弛 API= ’ xox b-44323424–234324243-dfsdfdsfsf ’
3.)我们还将维护一个 csv 文件,在该文件中,我们将以如下格式维护客户 twitter 名称信息:-
4.)我们需要一些库来设置整个过程。因此,请将以下库安装到您的环境中:-
5.)之后,我们将使用 praw 方法设置 reddit,因为 praw 是与 reddit 数据交互的 api。如果你想了解更多关于 praw 的信息,请点击这里https://praw.readthedocs.io/en/latest/。
6.)然后我们将 CSV 文件读入熊猫的数据帧。CSV 文件包含子编辑的所有细节,如果您需要添加或删除任何子编辑,您可以在 CSV 文件中完成,无需编辑 python 脚本。
7.)之后,由于我们是动态进行的,所以我们将创建两个变量,一个是读取子编辑名称,另一个是客户端名称。
8.)现在,我们将阅读子编辑的标题。因为我们在这里构建一个动态机器人,所以我们将只阅读新的标题,为此我们将遵循下面的代码行。在这里,我们首先将 subreddit 的名称放入一个变量 subreddit 中,然后我们在这里只读取新的注释。我已经通过了这里的限制= 1000,你也可以不通过,但你将无法获得超过 1000 个标题,默认为 100。
9.)那么,如果你需要所有的历史头条呢。我们在这里不需要它,但是如果你想下载所有的,你可以使用 pushshiftapi(【https://github.com/pushshift/api】T2)
10.)现在我们将为我们将从 reddit 中读取的键创建一个字典。reddit 提供了 95 种不同的值,但我们并不需要所有的值。按照我们的要求,我正在使用下面的。
11.)一旦我们声明了字典的结构,现在就该从 reddit 将数据读入字典了:-
12.)最后,我们有了数据,现在我们将把它转换成一个 pandas 数据框,以便对它执行进一步的操作:-
13.)Reddit 总是以纪元格式给出时间,我们需要一个通用时间戳来读取和执行操作:-
14.)现在,是时候决定我们的机器人的时间间隔了,假设你想每 15 分钟做一次。此外,由于 reddit 和 yor 时区可能不同,所以选择一个共同的时区总是明智的,这就是为什么我把两者都转换成 UTC。
15.)现在,是时候过滤掉标题了,你可以按照下面的代码来做
16.)发布到 slack 频道:-
17.)现在,如果我们想将数据存储到某个数据库中,并在 grafana 上可视化该数据,该怎么办呢?我在这里使用 InfluxDB,所以只需用下面的代码替换步骤 15,数据将存储在 InfluxDB 中。
18.)为时间序列可视化设置 Grafana,您将获得如下图表
在上面的图表中,我们可以看到,在午夜,一些人发布了一个标题,在短短的 15 分钟内,有 247 人投了赞成票,115 人发表了评论。所以,这是一个问题。grafana 仪表板将如下图所示
结束注释:-
- 如果您设置了 15 分钟的时间间隔,那么请确保您为所有客户端编写的脚本花费的时间少于该时间间隔。
- 我们总是可以根据我们的需要修改脚本,比如我们想要什么样的通知。
我还写了一篇关于制作 twitter 机器人的文章。请阅读:-
[## Python 中的实时动态 tweet 监控机器人。
如果你正在阅读这篇博客,那么你可能正在寻找为 slack 开发某种推特监控机器人。在这个…
towardsdatascience.com](/real-time-dynamic-tweet-monitor-bot-for-slack-in-python-d0409b66de62)
如果你在评论区有任何错误,请告诉我。请添加任何有价值的建议,我甚至可以改善这个脚本。我是东北大学的研究生,目前在 Vivox 做数据科学家。
请访问下面的 Github 库获取代码:-
[## abhimanyu3/RedditBot_for_slack
设置一个 Reddit 机器人来监控关于用户情绪的实时子编辑标题,并将其放入 slack…
github.com](https://github.com/abhimanyu3/RedditBot_for_slack)
请联系 Linkedin:-
[## Abhimanyu Kumar -数据科学家(Co Op) - Vivox | LinkedIn
查看 Abhimanyu Kumar 在世界上最大的职业社区 LinkedIn 上的个人资料。Abhimanyu 有 8 份工作列在…
www.linkedin.com](https://www.linkedin.com/in/abhimanyu0301/)
针对 slack 的实时推特通知机器人。
如果你正在阅读这篇博客,那么你可能正在寻找为 slack 开发某种推特监控机器人。在这篇文章中,我将描述我如何用 python 创建了一个动态 tweet monitor bot 来监控客户是否在 tweet 上发布了某些特定的内容。假设您想监控您的一个客户何时发布关于某件特定事情的推文。如果你只想监控一个账户,那没问题,但是想想你监控 100 个 twitter 账户的情况。你肯定会错过你的 slack 频道中的 tweet 洪流中的重要 tweet。假设您正在监控 Zara,并想知道他们何时在推特上发布销售信息。当 Zara、Columbia、North face 等大公司都在推特上发布出售消息时,你只是想要一个宽松的通知。那可能是任何一种公司。所以,你不想为 50 家公司写 50 个脚本,而是创建一个动态脚本,为所有客户完成工作。现在,如果您想在您的观察列表中添加或删除某些客户,该怎么办?我们赢了;不接触脚本,但我们将维护一个 CSV 文件或任何类型的数据库,它将服务于目的。
1.)首先,我们需要像下面这样的一些细节,这些细节可以通过在 twitter 上创建,并遵循https://chimpgroup.com/knowledgebase/twitter-api-keys/上的指示
#消费者:
消费者 _ 密钥 = ‘消费者 _ 密钥’
消费者 _ 秘密 = ‘消费者 _ 秘密’
#访问:
访问令牌 = ‘访问令牌’
访问密码 = ‘访问密码’
2.)要与 slack 交互,我们需要创建一个 slack bot API,您可以按照下面 youtube 视频中的说明来创建它
SLACK API= ’ xox b-gfgdfgdfgdgfdfg ’
从 xoxb 开始,你会得到类似上面的 slack api。
3.)我们还将维护一个 csv 文件,在该文件中,我们将以如下格式维护客户 twitter 名称信息:-
4.)我们需要一些库来设置整个过程。因此,请将以下库安装到您的环境中:-
5.)之后我们会声明 twitter 开发者账户和 slack API 的密钥。您可以使用任何帐户,但如果您想使用 Vivox 的详细信息,请联系 JIM。你总是可以自己创建 slack API,我已经分享了上面的链接,作为如何创建 slack API 密钥的参考。
6.)然后我们将 CSV 文件读入熊猫的数据帧。CSV 文件包含客户 twitter 名称的所有详细信息,如果您需要添加或删除任何 twitter 名称,您可以在 CSV 文件中完成,无需编辑 python 脚本。
7.)然后我们将定义 tweepy 函数,稍后我们将使用它作为提取器:-
8.)现在,我们将创建一个 datafrme“数据”:
9.)现在,Twitter 会在每条推文中提供各种细节。所以,如果你想知道每条推文的所有细节,你可以使用下面的代码
10.)现在,用下面的代码将您想要提取的任何信息作为一列添加到数据帧中。我刚刚添加了三个细节,但你可以添加你想要的。
11.)我们不希望任何用户发布任何推文,也不希望我们的客户在推文中回应任何用户的推文。要忽略所有这类推文,请使用以下代码:-
12.)现在,我们不希望相同的推文作为通知出现两次,所以我限制我的推文窗口只检查最后 1 分钟的推文,并且 cron 作业每分钟都在运行。这里的问题是 twitter 数据在不同的时区,而我们的系统时区是不同的。因此,我将两个时间都改为通用格式,即 UTC。
13.)在我们完成这一步后,我们将创建一个值列表,在此基础上,我们将根据我们想要的 tweets 过滤 tweets,其中包含某些词,如停机时间、维护等。
14.)在最后一步中,我们将检查数据帧“ndata”中是否有任何数据,并将其作为松弛通知发送:-
15.)完成上述所有步骤后,在终端上使用以下命令设置 cron 作业:-
16.)然后为 cron 作业创建条目,如下所示,它将每分钟运行一次:-
结束注释:-
- )确保任何帐户名都不是无效的或私有的。
- )根据您的要求修改您的 my_list。
如果你在评论区有任何错误,请告诉我。请添加任何有价值的建议,我甚至可以改善这个脚本。我是东北大学的研究生,目前在 Vivox 做数据科学家。
请访问下面的 Github 库获取代码:-
[## abhimanyu 3/Twitter bot _ for _ slack
设置一个 twitter 机器人来实时监控多个 twitter 帐户,并在空闲时获得实时通知…
github.com](https://github.com/abhimanyu3/twitterbot_for_slack)
让我们连接起来:-
[## Abhimanyu Kumar -数据科学家(Co Op) - Vivox | LinkedIn
查看 Abhimanyu Kumar 在世界上最大的职业社区 LinkedIn 上的个人资料。Abhimanyu 有 8 份工作列在…
www.linkedin.com](https://www.linkedin.com/in/abhimanyu0301/)
实时人脸识别:一个端到端的项目
逐步了解如何使用 PiCam 实时识别人脸。
1.介绍
在我探索 OpenCV 的教程中,我们学习了自动视觉物体跟踪。现在,我们将使用 PiCam 实时识别人脸,如下图所示:
这个项目是用这个神奇的“开源计算机视觉库” OpenCV 完成的。在本教程中,我们将专注于 Raspberry Pi(所以,Raspbian 作为操作系统)和 Python,但我也在我的 Mac 上测试了代码,它也运行良好。
“要在 Mac 上运行它,需要对代码做一些修改。不要担心,我会对此进行评论”
OpenCV 是为计算效率而设计的,非常注重实时应用。因此,它非常适合使用摄像头进行实时人脸识别。
三个阶段
为了创建一个完整的人脸识别项目,我们必须在三个截然不同的阶段开展工作:
- 人脸检测和数据收集
- 训练识别器
- 人脸识别
下面的框图恢复了这些阶段:
2.安装 OpenCV 3 包
我用的是 Raspberry Pi V3,更新到了 Raspbian (Stretch)的最新版本,所以安装 OpenCV 的最好方法是遵循 Adrian Rosebrock 开发的优秀教程: Raspbian Stretch:在你的 Raspberry Pi 上安装 OpenCV 3+Python。
我尝试了几种不同的指南在我的 Pi 上安装 OpenCV。阿德里安的教程是最好的。我建议你也这样做,一步一步地遵循他的指导方针。
一旦您完成了 Adrian 的教程,您就应该有一个 OpenCV 虚拟环境,可以在您的 Pi 上运行我们的实验。
让我们进入虚拟环境,确认 OpenCV 3 安装正确。
Adrian 建议每次打开新终端时运行命令“source ”,以确保系统变量设置正确。
source ~/.profile
接下来,让我们进入虚拟环境:
workon cv
如果您在提示前看到文本(cv ),则您处于 cv 虚拟环境中:
(cv) pi@raspberry:~$
Adrian 提醒注意, cv Python 虚拟环境 完全独立于 Raspbian Stretch 下载中包含的默认 Python 版本。因此,全局站点包目录中的任何 Python 包对于 cv 虚拟环境都是不可用的。类似地,任何安装在 cv 的 site-packages 中的 Python 包对于 Python 的全局安装都是不可用的。
现在,在 Python 解释器中输入:
python
并确认您运行的是 3.5(或更高)版本。
在解释器内部(会出现" > > > "),导入 OpenCV 库:
import cv2
如果没有出现错误消息,则 OpenCV 已正确安装在您的 PYTHON 虚拟环境中。
您也可以检查安装的 OpenCV 版本:
cv2.__version__
3.3.0 应该会出现(或者将来可能发布的更高版本)。
上面的终端打印屏幕显示了前面的步骤。
3.测试您的相机
一旦你在 RPi 中安装了 OpenCV,让我们来测试一下你的相机是否工作正常。
我假设您已经在您的 Raspberry Pi 上安装并启用了 PiCam。
在您的 IDE 上输入以下 Python 代码:
import numpy as np
import cv2cap = cv2.VideoCapture(0)
cap.set(3,640) # set Width
cap.set(4,480) # set Heightwhile(True):
ret, frame = cap.read()
frame = cv2.flip(frame, -1) # Flip camera vertically
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', frame)
cv2.imshow('gray', gray)
k = cv2.waitKey(30) & 0xff
if k == 27: # press 'ESC' to quit
breakcap.release()
cv2.destroyAllWindows()
上述代码将捕获您的 PiCam 生成的视频流,以 BGR 彩色和灰色模式显示这两种视频流。
注意,由于组装的方式,我垂直旋转了我的相机。如果不是你的情况,评论或删除“翻转”命令行。
你也可以从我的 GitHub 下载代码: simpleCamTest.py
要执行脚本,请输入命令:
python simpleCamTest.py
要完成该程序,您必须按键盘上的[ESC]键。在按[ESC]键之前,在视频窗口上单击鼠标。
上图是结果。
一些人在试图打开相机时发现问题,并得到“断言失败”的错误消息。如果在 OpenCv 安装过程中没有启用相机,相机驱动程序就不会正确安装,这种情况就会发生。要进行更正,请使用以下命令:
sudo modprobe bcm2835-v4l2
您还可以将 bcm2835-v4l2 添加到/etc/modules 文件的最后一行,以便在引导时加载驱动程序。
了解 OpenCV 的更多内容,可以关注教程:加载-视频-python-OpenCV-教程
4.人脸检测
人脸识别最基本的任务当然是“人脸检测”。在做任何事情之前,你必须“捕捉”一张脸(阶段 1),以便在与未来(阶段 3)捕捉的新脸进行比较时识别它。
最常见的检测人脸(或任何物体)的方法,是使用哈尔级联分类器
使用基于 Haar 特征的级联分类器的目标检测是由 Paul Viola 和 Michael Jones 在 2001 年的论文“使用简单特征的增强级联的快速目标检测”中提出的一种有效的目标检测方法。这是一种基于机器学习的方法,其中从大量正面和负面图像中训练级联函数。然后,它被用于检测其他图像中的对象。
这里我们将使用人脸检测。最初,该算法需要大量的正面图像(人脸图像)和负面图像(没有人脸的图像)来训练分类器。然后我们需要从中提取特征。好消息是 OpenCV 带有一个训练器和一个检测器。如果你想为任何物体训练你自己的分类器,比如汽车,飞机等等。您可以使用 OpenCV 创建一个。这里给出了它的全部细节:级联分类器训练。
如果你不想创建自己的分类器,OpenCV 已经包含了许多预先训练好的人脸、眼睛、微笑等分类器。那些 XML 文件可以从 haarcascades 目录下载。
理论够了,我们用 OpenCV 造一个人脸检测器吧!
从我的 GitHub 下载文件: faceDetection.py 。
import numpy as np
import cv2faceCascade = cv2.CascadeClassifier('Cascades/haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture(0)
cap.set(3,640) # set Width
cap.set(4,480) # set Heightwhile True:
ret, img = cap.read()
img = cv2.flip(img, -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(20, 20)
)
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
cv2.imshow('video',img)
k = cv2.waitKey(30) & 0xff
if k == 27: # press 'ESC' to quit
breakcap.release()
cv2.destroyAllWindows()
信不信由你,上面的几行代码就是你检测一张脸所需要的全部,使用 Python 和 OpenCV。
当您与用于测试相机的最后一个代码进行比较时,您会发现添加到其中的部分很少。请注意下面一行:
faceCascade = cv2.CascadeClassifier('Cascades/haarcascade_frontalface_default.xml')
这是加载“分类器”的一行代码(必须位于项目目录下名为“Cascades/”的目录中)。
然后,我们将设置我们的摄像机,在循环中,以灰度模式加载我们的输入视频(和我们之前看到的一样)。
现在我们必须调用我们的分类器函数,给它传递一些非常重要的参数,如比例因子、邻居数量和检测到的人脸的最小尺寸。
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(20, 20)
)
在哪里,
- 灰度是输入的灰度图像。
- 比例因子是指定在每个图像比例下图像尺寸缩小多少的参数。它用于创建比例金字塔。
- minNeighbors 是一个参数,指定每个候选矩形应该有多少个邻居来保留它。数字越大,误报率越低。
- 最小尺寸是被视为面的最小矩形尺寸。
该功能将检测图像上的人脸。接下来,我们必须“标记”图像中的人脸,例如,使用蓝色矩形。这是通过这部分代码完成的:
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
如果找到了人脸,它会将检测到的人脸的位置返回为一个矩形,左上角为(x,y),宽度为“w ”,高度为“h ”= = >(x,y,w,h)。请看图片。
一旦我们得到这些位置,我们就可以为面部创建一个“ROI”(绘制的矩形),并用 imshow() 函数呈现结果。
使用 Rpi 终端,在您的 python 环境中运行上述 python 脚本:
python faceDetection.py
结果是:
您还可以包括用于“眼睛检测”甚至“微笑检测”的分类器。在这些情况下,您将在面部循环中包含分类器函数和矩形绘制,因为在面部之外检测眼睛或微笑是没有意义的。
请注意,在 Pi 上,几个分类器使用相同的代码会减慢处理速度,因为这种检测方法(HaarCascades)使用了大量的计算能力。在台式机上,运行它更容易。
例子
在我的 GitHub 上,您可以找到其他示例:
在图片中,你可以看到结果。
您也可以按照下面的教程来更好地理解人脸检测:
哈尔级联物体检测人脸& Eye OpenCV Python 教程
5.数据采集
首先,我必须感谢 Ramiz Raja 在照片人脸识别方面的出色工作:
使用 OPENCV 和 PYTHON 的人脸识别:初学者指南
还有阿尼班·卡尔,他用视频开发了一个非常全面的教程:
我真的建议你看一看这两个教程。
说到这里,让我们开始我们项目的第一阶段。我们在这里要做的是,从最后一步(人脸检测)开始,我们将简单地创建一个数据集,其中我们将为每个 id 存储一组灰色照片,其中一部分用于人脸检测。
首先,创建一个开发项目的目录,例如 FacialRecognitionProject:
mkdir FacialRecognitionProject
在这个目录中,除了我们将为项目创建的 3 个 python 脚本之外,我们必须在上面保存面部分类器。可以从我的 GitHub 下载:Haar cascode _ frontal face _ default . XML
接下来,创建一个子目录,我们将在其中存储面部样本,并将其命名为“数据集”:
mkdir dataset
并从我的 GitHub 下载代码: 01_face_dataset.py
import cv2
import oscam = cv2.VideoCapture(0)
cam.set(3, 640) # set video width
cam.set(4, 480) # set video height
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')# For each person, enter one numeric face id
face_id = input('\n enter user id end press <return> ==> ')
print("\n [INFO] Initializing face capture. Look the camera and wait ...")# Initialize individual sampling face count
count = 0
while(True):
ret, img = cam.read()
img = cv2.flip(img, -1) # flip video image vertically
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2)
count += 1
# Save the captured image into the datasets folder
cv2.imwrite("dataset/User." + str(face_id) + '.' +
str(count) + ".jpg", gray[y:y+h,x:x+w])
cv2.imshow('image', img)
k = cv2.waitKey(100) & 0xff # Press 'ESC' for exiting video
if k == 27:
break
elif count >= 30: # Take 30 face sample and stop video
break# Do a bit of cleanup
print("\n [INFO] Exiting Program and cleanup stuff")
cam.release()
cv2.destroyAllWindows()
该代码与我们看到的人脸检测代码非常相似。我们添加的是一个“输入命令”来捕获一个用户 id,它应该是一个整数(1,2,3 等)
face_id = input('\n enter user id end press ==> ')
对于每一个捕捉到的帧,我们应该将其保存为“数据集”目录中的一个文件:
cv2.imwrite("dataset/User." + str(face_id) + '.' + str(count) + ".jpg", gray[y:y+h,x:x+w])
请注意,要保存上述文件,您必须导入库“os”。每个文件的名称将遵循以下结构:
User.face_id.count.jpg
例如,对于 face_id = 1 的用户,数据集/目录上的第 4 个样本文件将类似于:
User.1.4.jpg
如我的 Pi 中的照片所示:
在我的代码中,我从每个 id 中捕获 30 个样本。最后一个“elif”可以改。样本数量用于打破捕捉面部样本的循环。
运行 Python 脚本并捕获一些 id。每次您想要聚合新用户(或更改已存在用户的照片)时,您都必须运行该脚本。
6.运动鞋
在第二阶段,我们必须从我们的数据集中获取所有用户数据,并“训练”OpenCV 识别器。这是由特定的 OpenCV 函数直接完成的。结果将是一个. yml 文件,该文件将保存在“trainer/”目录中。
因此,让我们开始创建一个子目录,用于存储训练数据:
mkdir trainer
从我的 GitHub 下载第二个 python 脚本: 02_face_training.py
import cv2
import numpy as np
from PIL import Image
import os# Path for face image database
path = 'dataset'
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml");# function to get the images and label data
def getImagesAndLabels(path):
imagePaths = [os.path.join(path,f) for f in os.listdir(path)]
faceSamples=[]
ids = []
for imagePath in imagePaths:
PIL_img = Image.open(imagePath).convert('L') # grayscale
img_numpy = np.array(PIL_img,'uint8')
id = int(os.path.split(imagePath)[-1].split(".")[1])
faces = detector.detectMultiScale(img_numpy)
for (x,y,w,h) in faces:
faceSamples.append(img_numpy[y:y+h,x:x+w])
ids.append(id)
return faceSamples,idsprint ("\n [INFO] Training faces. It will take a few seconds. Wait ...")faces,ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))# Save the model into trainer/trainer.yml
recognizer.write('trainer/trainer.yml') # Print the numer of faces trained and end program
print("\n [INFO] {0} faces trained. Exiting Program".format(len(np.unique(ids))))
# recognizer.save() worked on Mac, but not on Pi
确认您的 Rpi 上是否安装了 PIL 库。如果没有,请在终端中运行以下命令:
pip install pillow
我们将使用 OpenCV 包中包含的 LBPH(局部二进制模式直方图)人脸识别器作为识别器。我们用下面的代码行来实现这一点:
recognizer = cv2.face.LBPHFaceRecognizer_create()
函数“getImagesAndLabels (path)”,将拍摄目录:“dataset/”上的所有照片,返回 2 个数组:“Ids”和“faces”。将这些数组作为输入,我们将“训练我们的识别器”:
recognizer.train(faces, ids)
因此,名为“trainer.yml”的文件将保存在我们之前创建的培训师目录中。
就是这样!我包括了最后一个打印声明,其中我显示了我们已经训练的用户面部的数量以供确认。
每次执行阶段 1 时,也必须运行阶段 2。
7.承认者
现在,我们到了项目的最后阶段。在这里,我们将在我们的相机上捕捉一张新面孔,如果这个人的脸之前被捕捉并训练过,我们的识别器将进行“预测”,返回其 id 和索引,显示识别器对这一匹配的信心程度。
下面从我的 GitHub 下载第三期 python 脚本: 03_face_recognition.py 。
import cv2
import numpy as np
import os recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
cascadePath = "haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath);
font = cv2.FONT_HERSHEY_SIMPLEX#iniciate id counter
id = 0# names related to ids: example ==> Marcelo: id=1, etc
names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z', 'W'] # Initialize and start realtime video capture
cam = cv2.VideoCapture(0)
cam.set(3, 640) # set video widht
cam.set(4, 480) # set video height# Define min window size to be recognized as a face
minW = 0.1*cam.get(3)
minH = 0.1*cam.get(4)while True:
ret, img =cam.read()
img = cv2.flip(img, -1) # Flip vertically
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor = 1.2,
minNeighbors = 5,
minSize = (int(minW), int(minH)),
)
for(x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
id, confidence = recognizer.predict(gray[y:y+h,x:x+w])
# If confidence is less them 100 ==> "0" : perfect match
if (confidence < 100):
id = names[id]
confidence = " {0}%".format(round(100 - confidence))
else:
id = "unknown"
confidence = " {0}%".format(round(100 - confidence))
cv2.putText(
img,
str(id),
(x+5,y-5),
font,
1,
(255,255,255),
2
)
cv2.putText(
img,
str(confidence),
(x+5,y+h-5),
font,
1,
(255,255,0),
1
)
cv2.imshow('camera',img)
k = cv2.waitKey(10) & 0xff # Press 'ESC' for exiting video
if k == 27:
break# Do a bit of cleanup
print("\n [INFO] Exiting Program and cleanup stuff")
cam.release()
cv2.destroyAllWindows()
我们在这里包含了一个新的数组,所以我们将显示“名称”,而不是编号的 id:
names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z', 'W']
所以,举个例子:Marcelo 将 id = 1 的用户;宝拉:id=2,等等。
接下来,我们将检测一张脸,就像我们之前用哈斯卡德分类器所做的一样。检测到人脸后,我们可以调用上面代码中最重要的函数:
id, confidence = recognizer.predict(gray portion of the face)
recognizer.predict()将把要分析的面部的捕获部分作为参数,并将返回其可能的所有者,指示其 id 以及识别器与该匹配相关的置信度。
注意,如果被认为是完美匹配,信心指数将返回“零”
最后,如果识别器可以预测人脸,我们就在图像上放一段文字,说明可能的 id 以及匹配正确的“概率”是多少(百分比)(“概率”= 100 —置信度指数)。如果没有,就在脸上贴上“未知”的标签。
下面是结果的 gif:
在图片上,我展示了这个项目的一些测试,我也用照片来验证识别器是否工作。
8.结论
一如既往,我希望这个项目可以帮助其他人找到进入令人兴奋的电子世界的方法!
有关详细信息和最终代码,请访问我的 GitHub 仓库:
https://github.com/Mjrovai/OpenCV-Face-Recognition
更多项目,请访问我的博客:【MJRoBot.org
来自世界南部的 Saludos!
我的下一篇文章再见!
谢谢你,
马塞洛
使用深度学习的实时噪声抑制
基于最大似然的噪声抑制介绍
想象一下在机场等你的航班。突然,一个重要的商务电话点亮了你的手机。成吨的背景噪音扰乱了你周围的声景——背景噪音,飞机起飞,也许是航班通知。你必须接电话,你想听起来清楚。
我们都曾处于这种尴尬、不理想的境地。这只是现代商业的一部分。
背景噪音无处不在。而且很烦。
现在想象一下,当你接听电话并讲话时,噪音神奇地消失了,任何人在电话那头听到的都是你的声音。没有一丝噪音传进来。
这个愿景代表了我们在 2Hz 的激情。让我们听听好的降噪带来了什么。
两年前,我们坐下来决定开发一种技术,可以完全消除人与人交流中的背景噪音,使交流更加愉快和清晰。从那以后,这个问题就成了我们的困扰。
让我们看看是什么让噪声抑制变得如此困难,构建实时低延迟噪声抑制系统需要什么,以及深度学习如何帮助我们将质量提升到一个新的水平。
噪声抑制的现状
我们先明确一下什么是噪声抑制。乍一看,这似乎令人困惑。
本文中的噪声抑制指的是抑制从你的背景传到你与之通话的人的噪声,以及从他们的背景传到你的噪声,如图 1 所示。
Figure 1. Noise comes from both calling sides. Noise Suppression filters it out for both callers.
这与主动噪音消除(ANC) 形成对比,主动噪音消除是指抑制来自周围环境的有害噪音进入您的耳朵。主动噪声消除通常需要多麦克风耳机(如 Bose QuiteComfort),如图 2 所示。
这篇文章关注的是噪声抑制,不是主动噪声消除。
噪声抑制的传统方法
传统的噪声抑制已经在边缘设备——电话、笔记本电脑、会议系统等——上得到有效实施。这似乎是一种直观的方法,因为它是首先捕获用户语音的边缘设备。一旦被捕获,设备就过滤掉噪音,并将结果发送给电话的另一端。
10 年前的手机通话体验相当糟糕。一些移动电话仍然是这种情况;然而,越来越多的现代手机配备了多个麦克风(mic),有助于在通话时抑制环境噪音。
当代手机包括两个或更多麦克风,如图 2 所示,最新的 iPhones 有 4 个。第一个麦克风放置在通话时最靠近用户嘴巴的手机前底部,直接捕捉用户的声音。手机设计师将第二个话筒放在离第一个话筒尽可能远的地方,通常放在手机的背面上方。
Figure 2. Pixel 2016. The two mics are marked yellow
两个话筒都能捕捉周围的声音。离嘴越近的话筒捕捉到的声音能量越多;第二个捕捉到的声音更少。软件有效地将这些声音相减,产生(几乎)干净的声音。
这听起来很容易,但是这种技术在很多情况下都失败了。想象一下,当这个人不说话,所有的麦克风都是噪音。或者想象这个人在说话的时候主动摇晃/转动手机,就像在跑步一样。处理这些情况很棘手。
对于设备 OEM 和 ODM 而言,两个或更多麦克风还会使音频路径和声学设计变得非常困难和昂贵。音频/硬件/软件工程师不得不实施次优权衡,以支持工业设计和语音质量要求…
鉴于这些困难,今天的移动电话在适度嘈杂的环境中表现良好…现有的噪声抑制解决方案并不完美,但确实提供了改善的用户体验。
使用分离式麦克风时,外形会发挥作用,如图 3 所示。第一个和第二个话筒之间的距离必须满足最低要求。当用户把手机放在耳朵和嘴上说话时,它工作得很好。
Figure 3. Necessary form factor for noise cancellation when using multi-mic arrays
然而,现代手机的“直板”外形可能不会长期存在。可穿戴设备(智能手表、胸前麦克风)、笔记本电脑、平板电脑和智能语音助手(如 Alexa)颠覆了平板直板手机的外形。用户从不同的角度和不同的距离与他们的设备对话。在大多数情况下,没有可行的解决方案。噪声抑制完全失败。
从多麦克风设计转向单麦克风设计
多麦克风设计有几个重要缺点。
- 它们需要特定的外形,因此仅适用于特定的使用情形,如带有粘性麦克风的电话或耳机(专为呼叫中心或入耳式监听系统设计)。
- 多话筒设计使音频路径变得复杂,需要更多硬件和代码。此外,为次级话筒钻孔会造成工业 ID 质量和产量问题。
- 只能在边缘或设备端处理音频。因此,由于低功率和计算要求,支持它的算法不可能非常复杂。
现在想象一个解决方案,您只需要一个麦克风,所有的后处理都由软件处理。这使得硬件设计更简单、更高效。
事实证明,在音频流中分离噪声和人类语音是一个具有挑战性的问题。这个函数没有高性能的算法。
传统的数字信号处理(DSP)算法试图通过逐帧处理音频来不断发现噪声模式并适应它。这些算法在某些用例中运行良好。然而,它们不能适应我们日常环境中存在的各种各样的噪音。
存在两种基本噪声类型:平稳和非平稳,如图 4 所示。
Figure 4. Spectrogram of White Noise (stationary) and Chirp Noise (non-stationary)
把稳定的噪音想象成一种可重复但不同于人声的声音。当过滤这种噪声时,传统的 DSP 算法(自适应滤波器)可能相当有效。
非平稳噪声具有复杂的模式,很难与人的声音区分开来。信号可能很短,来去很快(例如键盘打字或警笛声)。参考这篇 Quora 文章获得更多技术上正确的定义。
如果你想击败平稳和非平稳噪声,你需要超越传统的 DSP。在 2Hz,我们相信深度学习可以成为处理这些困难应用的重要工具。
利用深度学习分离背景噪声
一篇关于将深度学习应用于噪声抑制的基础论文似乎已经由 Yong Xu 在 2015 年写了。
Yong 提出了一种回归方法,该方法学习为每个音频产生一个比率掩模。这种产生的比率遮罩应该会完整地保留人声,并删除外来的杂讯。虽然远非完美,但这是一个很好的早期方法。
在随后的几年里,许多不同的方法被提出来;高层次的方法几乎总是相同的,包括三个步骤,如图 5 所示:
- 数据收集:通过混合干净语音和噪声,生成大数据集的合成噪声语音
- 训练:将这个数据集输入给 DNN,输出给干净的语音
- 推断:制作一个屏蔽(二元、比例或复合),它将保留人声并过滤掉噪声
Figure 5. Data Collection and Training Pipeline
在 2Hz 时,我们试验了不同的 DNN,并提出了我们独特的 DNN 架构,对各种噪声产生了显著的效果。平均 MOS 得分(平均意见得分)在嘈杂言论上上升 1.4 分,这是我们看到的最好结果。这一结果令人印象深刻,因为在单个麦克风上运行的传统 DSP 算法通常会降低 MOS 分数。
语音延迟。实时 DNN 可能吗?
低延迟在语音通信中至关重要。人类在交谈时可以忍受高达 200 毫秒的端到端延迟,否则我们在通话中会互相交谈。潜伏期越长,我们越注意到这一点,我们就变得越烦躁。
三个因素会影响端到端延迟:网络、计算和编解码器。通常网络延迟的影响最大。编解码器延迟范围在 5-80 毫秒之间,取决于编解码器及其模式,但现代编解码器已经变得非常高效。计算延迟实际上取决于许多因素。
计算延迟使 DNNs 面临挑战。如果您希望使用 DNN 处理每一帧,那么您将面临引入大量计算延迟的风险,这在现实部署中是不可接受的。
计算延迟取决于多种因素:
计算平台能力
在耳机中运行大型 DNN 不是你想做的事情。有 CPU 和电源的限制。实现实时处理速度是非常具有挑战性的,除非该平台有一个加速器,使矩阵乘法更快,功耗更低。
DNN 建筑
DNN 的速度取决于您有多少超参数和 DNN 层以及您的节点运行什么操作。如果你想以最小的噪声产生高质量的音频,你的 DNN 不能很小。
例如, Mozilla 的 rnnoise 速度非常快,或许可以放入耳机中。然而,它的质量在非平稳噪声上并不令人印象深刻。
音频采样率
DNN 的性能取决于音频采样率。采样率越高,需要为 DNN 提供的超参数就越多。
相比之下, Mozilla 的 rnnoise 使用分组频率的频段,因此性能对采样率的依赖最小。虽然这是一个有趣的想法,但它对最终质量有负面影响。
窄带音频信号(8kHz 采样速率)质量较低,但我们的大部分通信仍在窄带中进行。这是因为大多数移动运营商的网络基础设施仍然使用窄带编解码器来编码和解码音频。
由于窄带每频率需要的数据较少,因此它可以作为实时 DNN 的一个很好的起始目标。但是,当您需要添加对宽带或超宽带(16kHz 或 22kHz)以及全频带(44.1 或 48kHz)的支持时,事情就变得非常困难了。如今,许多基于 VoIP 的应用程序都在使用宽带编解码器,有时甚至是全频带编解码器(开源的 Opus 编解码器支持所有模式)。
在一个简单的设计中,您的 DNN 可能需要它增长 64 倍,因此支持全频带会慢 64 倍。
如何测试噪声抑制算法?
测试语音增强的质量具有挑战性,因为你不能相信人耳。由于年龄、训练或其他因素,不同的人有不同的听力。不幸的是,没有公开和一致的噪声抑制基准,所以比较结果是有问题的。
大多数学术论文都是用 PESQ 、 MOS 和 STOI 来比较结果。您向算法提供原始语音音频和失真音频,它会产生一个简单的度量分数。例如,PESQ 分数在-0.5 到 4.5 之间,其中 4.5 是完全干净的讲话。PESQ、MOS 和 STOI 并不是为评定噪音等级而设计的,所以你不能盲目信任它们。在你的过程中也必须有主观测试。
ETSI 房间
进行主观音频测试并使其可重复的更专业的方法是满足由不同标准团体创建的此类测试的标准。
3GPP 电信组织定义了 ETSI 室的概念。如果你打算将你的算法部署到现实世界中,你的设备中必须有这样的设置。ETSI 室是构建可重复的和可靠的测试的一个很好的机制;图 6 显示了一个例子。
Figure 6. Real ETSI room setup. Image from [Aqustica](http://Figure 8. Real ETSI room setup. Image from http://aqustika.com/en/casestudies/etsi-room).
这个房间隔音效果极佳。它通常还包含一个人造人体躯干、一个在躯干内部模拟声音的人造嘴(扬声器)以及一个在预定距离的支持麦克风的目标设备。
这使得测试人员能够使用周围的扬声器模拟不同的噪声,播放来自“躯干扬声器”的声音,并在目标设备上捕获结果音频,然后应用您的算法。所有这些都可以编写脚本来自动化测试。
出站噪声与入站噪声
噪点抑制真的有很多阴影。
假设你正在和你的团队参加一个电话会议。包括您在内,通话中有四个参与者。现在混合中可能有四种潜在噪声。每个人都把自己的背景噪音发给别人。
传统上,噪声抑制发生在边缘设备上,这意味着噪声抑制与麦克风绑定在一起。你从麦克风接收信号,抑制噪声,然后将信号发送到上游。
由于单麦克风 DNN 方法只需要一个单一的来源流,你可以把它放在任何地方。现在,假设您想要抑制来自所有参与者的麦克风信号(出站噪声)和进入扬声器的信号(入站噪声)。
我们构建了我们的应用程序, Krisp ,明确地处理入站和出站噪声(图 7)。
Figure 7: Software noise suppression enables filtering both inbound and outbound noise
以下视频演示了如何使用 DNN 完全消除非平稳噪声。
对于入站噪声抑制,问题变得更加复杂。
您需要处理噪声抑制算法中不常见的声学和语音差异。例如,您的团队可能正在使用会议设备,并且坐在远离该设备的地方。这意味着到达设备的声音能量可能较低。或者他们可能在他们的汽车上用连接在仪表板上的 iPhone 给你打电话,这是一个固有的高噪声环境,由于距离扬声器较远,声音较低。在另一种情况下,可能会有多人同时发言,您希望保留所有的声音,而不是将其中的一些声音作为噪音抑制掉。
当您拨打 Skype 电话时,您会在扬声器中听到电话铃声。那个响到底是不是噪音?或者等待音乐是不是噪音?我将把那个留给你。
向云迁移
到目前为止,您应该对噪声抑制的艺术状态以及围绕用于此目的的实时深度学习算法的挑战有了坚实的想法。您还了解了使问题更具挑战性的关键延迟要求。噪声抑制算法增加的总延迟不能超过 20 毫秒,这确实是一个上限。
既然算法是完全基于软件的,那么它能移到云中吗,如图 8 所示?
Figure 8. There are multiple benefits for doing noise suppression in the Cloud.
答案是肯定的。首先,基于云的噪声抑制适用于所有设备。其次,它可以在两条线路上执行(或者在电话会议中在多条线路上执行)。我们认为噪音抑制和其他语音增强技术可以转移到云上。这在过去是不可能的,因为需要多个麦克风。移动运营商已经制定了各种质量标准,设备原始设备制造商必须执行这些标准,以提供合适的质量水平,迄今为止的解决方案是多话筒。然而,深度学习使在支持单麦克风硬件的同时将噪声抑制放在云中的能力成为可能。
最大的挑战是算法的可扩展性。
使用 Nvidia GPUs 扩展 20 倍
如果我们希望这些算法能够扩展到足以服务真实的 VoIP 负载,我们需要了解它们的性能。
大型 VoIP 基础设施同时服务于 10K-100K 流。我们知道的一家 VoIP 服务提供商在一台裸机媒体服务器上提供 3000 个 G.711 呼叫流,这令人印象深刻。
有许多因素会影响像 FreeSWITCH 这样的媒体服务器可以同时提供多少音频流。一个明显的因素是服务器平台。与裸机优化部署相比,云部署的媒体服务器的性能明显较低,如图 9 所示。
Figure 9. Average stream concurrency of cloud-hosted vs bare metal media servers
服务器端噪声抑制必须经济高效,否则没有客户愿意部署它。
我们的第一个 2Hz 实验是从 CPU 开始的。一个 CPU 内核可以处理多达 10 个并行流。这不是一个非常划算的解决方案。
然后,我们在 GPU 上运行实验,结果令人惊讶。单个 Nvidia 1080ti 可以在没有任何优化的情况下扩展到 1000 个流(图 10)。在正确的优化之后,我们看到了扩展到 3000 个流;更多是可能的。
Figure 10. The DNN algorithm scales quite well on Nvidia 1080ti
包括处理流和编解码器解码在内的原始媒体服务器负载仍然发生在 CPU 上。使用 GPU 的另一个好处是能够简单地将外部 GPU 连接到您的媒体服务器机箱,并将噪声抑制处理完全卸载到其上,而不会影响标准音频处理管道。
使用 CUDA 进行配料
让我们来看看为什么 GPU 比 CPU 更好地扩展这类应用程序。
CPU 厂商传统上花费更多的时间和精力来优化和加速单线程架构。他们实现了算法、流程和技术来从单线程中获得尽可能高的速度。由于过去大多数应用程序只需要一个单线程,CPU 制造商有充分的理由开发最大化单线程应用程序的架构。
另一方面,GPU 供应商针对需要并行性的操作进行了优化。这源于 3D 图形处理的大规模并行需求。GPU 的设计使得它们的数千个小内核能够在高度并行的应用中很好地工作,包括矩阵乘法。
批处理是允许并行化 GPU 的概念。你把一批批的数据和操作发送给 GPU,它并行处理,然后发送回来。这是处理并发音频流的完美工具,如图 11 所示。
Figure 11. This simplified diagram shows how batching can be used to process multiple audio frames concurrently on GPU
我们已经使用 NVIDIA 的 CUDA 库直接在 NVIDIA GPUs 上运行我们的应用并执行批处理。
如果你想在你的 Mac 上尝试基于深度学习的噪音抑制——你可以用 Krisp 应用来完成。
下一步是什么?
音频是一个令人兴奋的领域,噪声抑制只是我们在这个领域看到的问题之一。深度学习将实现新的音频体验,在 2Hz,我们坚信深度学习将改善我们的日常音频体验。查看修复语音中断和高清语音回放的博客帖子,了解此类体验。
声明:原本我已经以 客座博文 的身份在 NVIDIA 开发者博客上发表了这篇文章。
使用 Tensorflow 和 OpenCV 的实时对象检测 API
在过去几年中,当今世界的视觉数据量呈指数级增长,这主要是由于到处都有大量的传感器。构建能够在单个图像中定位和识别物体的机器学习模型仍然是计算机视觉中的核心挑战。致力于解决这个问题点燃了我对这个领域的兴趣。
作为我探索的一个途径,我发现 Google 刚刚发布了一个对象检测 API。该 API 已经在具有不同可训练检测模型的微软 COCO 数据集(90 个常见对象的大约 300,000 个图像的数据集)上进行训练。
different trainable detection models
地图越高(最小平均精度),模型越好
项目描述
我首先在 github 上克隆了 Tensorflow 对象检测库。该 API 是一个基于 tensorflow 的开源框架,可以轻松构建、训练和部署对象检测模型。
对于这个项目[am on windows 10,Anaconda 3,Python 3.6],我只关心安装部分,并遵循包括
- 使用 pip(最新版本)安装最新版本的 tensorflow 时会附带安装所需的库,例如 pillow、lxml 等
- 下载与我的系统兼容的最新版本的 protobuf 用于在 google protobuf 版本上编译
- 将 tensorflow/models 文件夹克隆为 zip 文件
- 在我的 Anaconda 提示符下,运行这个命令进行 protobuf 编译,没有它这个例子就不能工作。
# From tensorflow/models/research/
protoc object_detection/protos/*.proto --python_out=.
- 我更喜欢使用 Spyder 作为我的编辑器,所以我复制了示例中的笔记本,并将其转换为 python 文件
测试模型
使用预先训练好的 ssd_mobilenet_v1_coco 模型(虽然速度很快,但准确性最低),我决定在自己的图像上测试一下,结果令人惊讶!
Django girls event in my school
This was actually my dinner
Ongoing free python training organized by @lautechdatasci team
**技巧:**测试图片是用我的手机和数码相机拍摄的。调整它们的尺寸有助于模型的检测。
现在我想要实时检测,所以我用我的网络摄像头连接了 OpenCV。OpenCV 是一个用于图像处理、机器学习和实时检测的开源计算机视觉库。
这是结果:
请不要介意我的网络摄像头的质量😊,这是一个旧的。我希望我能安装升级程序
我的下一个任务
使用预先训练好的模型真的很酷,但是我喜欢在我自己的数据集上为超级应用程序训练 API。这可能不容易,但事实上,我已经准备好战斗了!!!
你可以在我的库上获得完整的代码,这样你就可以直接运行文件并进行测试。如果你觉得我的帖子有趣😍,尽可能地按下鼓掌按钮。
在推特上关注我:@danielajisafe,@lautechdatasci
#fromlautechtotheworld
YOUTUBE 参考
https://www.youtube.com/watch?v=MoMjIwGSFVQ
https://www.youtube.com/watch?v=COlbP62-B-U&list = plqvvaa 0 qudcnk 5 gecqnxynssaar 2 tpku
https://www.youtube.com/watch?v=Rgpfk6eYxJA
基于张量流检测模型的实时目标检测
最近,我完成了 deeplearning.ai 通过 Coursera 提供的课程 4,“ 卷积神经网络”作为“深度学习专业化”的一部分。吴恩达、基安·卡坦弗什和尤尼斯·本苏达·莫里在这一专业领域提供了大量的实践和理论知识。因此,我强烈推荐任何想获得深度学习经验的人。
自从我开始学习以来,我就对 CNN 的潜力充满了雄心和好奇,在那门课程的一周中,我学习了在图像分类中实现的思想如何对具有定位的图像分类有用,以及从定位中学到的思想如何对检测有用。嗯,在完成完全基于物体探测的第三周之后,一些事情困扰着我。
但是,在深入探讨困扰我的细节之前。我先简单解释一下什么是图像分类,我提到带定位的图像分类是什么意思。首先,让我们看看下面的图片,我知道这些狗太可爱了,所以我亲爱的读者,不要失去你的焦点:)。因此,我所说的图像分类是指每当一种算法看到这张图片[图 1]时,可能会做出反应并说这是一只狗,这意味着它能够将图像分类为一只狗的图像。
和[图 2],显示了该算法如何在图像中狗的位置周围放置一个边界框或绘制一个蓝色矩形。因此,这被称为定位分类,术语定位指的是计算出狗在照片中的哪个位置被检测到。
以及[图 3]示出了该算法如何检测和定位图像中的不止一个而是多个对象。
在这个简洁的解释之后,我应该把你的注意力集中到我反复提到的“事物”的问题上。我脑海中的问题是,是否存在比你只看一次(YOLO) 更准确的物体检测方法,以及比更快的 R-CNNs 更快的每秒帧数(FPS)。除此之外,我甚至开始寻找可以在没有高计算能力或没有利用 Nvidia GPU 能力的设备上运行的网络架构,如 Titan X 或 Jetson。
俗话说“为了发现任何东西,你必须寻找某些东西”。因此,我花了几个小时的时间进行研究,找到了“ TensorFlow 对象检测 API ”,这是一个基于 TensorFlow 构建的开源框架,可以轻松构建、训练和部署对象检测模型,并且它还提供了一系列在 COCO 数据集、 Kitti 数据集和开放图像数据集上预先训练的检测模型。众多检测模型中的一种是单次检测器(SSD)和 MobileNets 架构的组合,其快速、高效且不需要巨大的计算能力来完成对象检测任务,其示例可在下图中看到。所以,简而言之,我的每一个问题都通过 SSDs 和 MobileNets 模型的结合得到了回答。
在向大家介绍了计算机视觉领域中经常使用的各种术语并自我回答了我的问题之后,现在我应该跳到实践部分,告诉大家如何通过使用 OpenCV 和 TensorFlow 以及 ssd_mobilenet_v1 模型[SSD _ mobilenet _ v1 _ COCO】在 COCO[上下文中的常见对象]数据集上训练,我能够使用一个 7 美元的网络摄像头和一台笔记本电脑进行实时对象检测。
那么,不多说了,让我们开始吧
- 首先到达这个 链接 ,在目录下,设置部分,点击安装子部分。
- 基本上,安装部分由 TensorFlow 对象检测 API 所依赖的库列表组成。因此,在前进之前安装每一个依赖项。
- 在所有的库中,你需要再安装一个库,就是 Protobuf 2.6 。由于我用的是 Windows 10【你可以根据你用的操作系统下载 zip 文件】我下载并解压了这个文件protocol-3 . 5 . 1-win32 . zip。
- 安装好所有要求后,就该下载模型了,你可以在这里 找到 。这完全取决于你是想克隆还是下载这个库。做好决定后,解压 文件 ,确保你的协议和模型文件在同一个文件夹里。
- 然后,我们需要将模型主文件夹的名称更改为模型,如果您在模型文件夹中查找研究文件夹,然后在研究文件夹中查找对象检测文件夹,在对象检测文件夹中查找 protos 文件夹。
- 一旦你打开它,你会发现没有像 box.predictor_pb2.py,faster_rcnn_box_coder_pb2.py 这样命名的文件,为了得到这些文件,我们需要编译 Protobuf 库。
- 因此,为了编译 Protobuf 库,打开 Anaconda 提示符,将目录更改为保存这两个文件夹的位置,然后执行[change directory]CD models/research,然后给出这个命令,该命令包含您的 protoc.exe 文件所在的完整路径,后跟[protoc object _ detection/protos/*。proto — python_out=。].
- 例如,[C:/Users/ADMIN/TF _ obj _ det/protoc-3 . 4 . 0-win32/bin/protoc object _ detection/protos/*。proto — python_out=。],这里 tf_obj_det 是我解压后保存模型和协议文件的文件夹。
- 现在,完成编译部分后,只需在 Anaconda 提示符/ Anaconda 终端上键入 jupyter notebook,然后一旦 jupyter notebook 打开,您就可以为实时对象检测编写代码了。
- 你可以使用我的资源库中的这个项目的代码,这个资源库在“参考资料”一节中提到,我还包括了 YouTube 视频的链接,它实际上演示了我的网络摄像头如何检测一帧中的每个对象,你可以在下图中体验。
最后一件事…
如果你喜欢这篇文章,请点击👏下面,并与他人分享,这样他们也可以享受它。
参考资料:
- 这个项目代码的 GitHub 库链接可以在这里找到。
- 为了了解更多关于物体探测的信息,你可以点击这里。
- 为了了解更多关于卷积神经网络的知识,你可以点击这里。
- 最后但同样重要的是,你可以在这里查看 YouTube 视频。
来自人工智能会议的应用机器学习的真实世界示例
了解像优步和 ZocDoc 这样的公司如何使用机器学习来提高关键业务指标
Ramping up for the keynotes at Strata Data Conference in New York — photo credit to the official O’Reilly flickr site
围绕机器学习和人工智能的大多数讨论都集中在计算机化的 Dota 游戏或真实的 T2 语音合成上。虽然这些领域很有吸引力,对该领域具有现实价值,但对实用的机器学习和实现实际管道带来的挑战关注不够。
由于不灵活的框架、缺乏可重复性、协作问题和不成熟的软件工具的挑战,机器学习团队仍然在努力利用 ML。
在过去的一个月里,我有机会参加了奥莱利传媒的 AI 会议和地层数据会议。有这么多的会议和伟大的公司出席,总是很难选择参加哪些会议。有许多不同的方法(这里有一个来自缪斯的很棒的指导手册,但是我个人倾向于围绕应用机器学习的会议,涵盖实际的实现。
这些实用的 ML 演示很有价值,因为:
- 演示者通常来自构建实际管道和处理特定需求的团队
- 内容诚实地讲述了失败的方法和团队经历的痛点,即使是在后来的迭代中
- 业务指标(如支持票烧毁率、客户满意度等)和机器学习模型之间有着真正的联系
**我在这两个会议上看到的最好的会议来自优步和 ZocDoc。**在这篇文章中,我将解释这些会议的关键收获,以及您的团队如何将这些经验融入到您自己的机器学习工作流程中。
会话深度潜水
优步和 ZocDoc 以自己的方式具有颠覆性,但两家公司都在使用机器学习作为竞争优势和改善用户体验的方法。
优步:利用自然语言处理和深度学习改善客户支持
仅在 2017 年就有超过 40 亿次乘坐,可以想象优步的支持系统需要可扩展。
在优步的支持下,机器学习团队希望通过推荐三个最相关的解决方案来专注于提高客户支持代表(CSR)的效率,这三个解决方案本质上是一个名为“客户痴迷票务助理”或 COTA 的“人在回路”模型架构。
优步大学的机器学习团队决定创建并比较两种不同的模型管道来实现规模支持:(1) COTA v1,它将多类分类任务转换为排序问题;(2)COTA v2,它使用了一种称为编码器-组合器-解码器的深度学习方法。
在 AI 大会上,来自优步团队的 Piero Molino、Huaixiu Zheng 和 Yi-Jia Wang 做了一项令人难以置信的工作,逐步展示了他们的模型架构以及他们的两种不同方法对收入和票务处理时间的影响。
优步已经实施了一个 ML 和 NLP 系统,该系统向其客户支持部门建议最可能的解决方案…
conferences.oreilly.com](https://conferences.oreilly.com/artificial-intelligence/ai-ca/public/schedule/detail/68612)
皮耶罗非常友好地在这里 分享了他们演示的幻灯片 。
你可以在皮耶罗的个人网站上看到更多他的作品:【http://w4nderlu.st/publications
Uber’s support UI with three suggested replies surfaced through the COTA models.
这两个模型都接收了机票、用户和旅行信息,为 CSR 建议机票分类和回复模板(答案)。
您可以在下图中看到这两种模型的架构。总而言之,COTA v1 随机森林模型将分类算法与逐点排序算法相结合,而 COTA v2 利用深度学习架构,可以通过优化几种不同类型的编码特征(文本、类别、数字和二进制)的损失来学习预测多个输出。该小组对每个模型进行了超参数搜索(用 COTA v1 进行网格搜索,用 COTA v2 进行平行随机搜索。
我强烈推荐阅读 他们的论文 以获得完整的细节和实现决策
From feature engineering to predictions, the Uber team maps out how they processed different inputs to populated suggested replies to the CSR team.
优步团队能够将他们的模型的影响与 A/B 测试(围绕 A/B 测试的良好资源 此处 )以及围绕他们的支持体验的客户调查进行比较。该团队最终发现,在他们的 A/B 测试中,COTA v2 比 COTA v1 准确 20–30%。COTA v2 还将处理时间减少了约 8%,而 COTA v2 减少了约 15%。虽然这两种方法都有助于提高客户满意度,但很明显,COTA v2 是冠军架构。
The Uber team set up an A/B test for both versions of COTA where COTA v2’s accuracy 20–30% higher than COTA v1’s (Slide 23 of 30)
优步的演讲展示了**如何将机器学习整合到客户支持等流程中是一个迭代过程。**他们必须测试不同的架构,还要围绕影响准确性的性能做出决策(考虑合理的错误)。
Zocdoc:逆向工程你的人工智能原型和可复制性之路
ZocDoc 是一种在线医疗保健预约服务,通过整合医疗实践和医生个人时间表的信息,为最终用户提供医疗保健搜索平台。
[## 逆向工程你的人工智能原型和可复制性之路——人工智能…
在更好的软件、云基础设施和预训练网络的帮助下,人工智能模型变得更容易构建…
conferences.oreilly.com](https://conferences.oreilly.com/artificial-intelligence/ai-ca/public/schedule/detail/68656)
ZocDoc 团队专注于用户旅程中非常特殊的部分:根据医疗保险范围寻找网络内医生。
对于 ZocDoc 的用户来说,找到一个网络内的医生可能意味着节省大量成本。通常情况下,如果您向网络内的医师或其他提供者就诊,您需要支付的费用将少于向网络外提供者就诊的费用(来源)。
ZocDoc 团队建立了一个保险卡检查器,允许患者扫描他们保险卡的照片,然后从卡中提取相关细节,以检查特定医生和特定程序是否被覆盖。
ZocDoc 的图像识别任务非常困难,因为:
- 用户提交的图像通常具有较差的分辨率和变化的尺寸(由于缺乏格式约束),导致较差的训练数据质量
- 保险卡包含大量其他类型的信息,有时可能会重复成员 ID
- 该团队必须快速构建一个原型,然后将他们的流程转化为可重复的流水线
在人工智能大会上,ZocDoc 的 Brian Dalessandro(数据科学负责人)和克里斯·史密斯(高级首席软件工程师)通过他们模型架构的不同阶段概述了这些技术挑战(见下面的截图)。
会议中最有趣的部分是 Chris 描述团队出于可扩展性和可再现性的考虑,决定彻底拆除原型的基础设施。团队很难识别和跟踪关键的模型工件,例如使用的超参数、软件依赖性,以及迭代过程中的更多内容。
关于具体模型实现的更多细节,可以在这里 阅读 ZocDoc 关于这个项目 的原创博文
ZocDoc’s MemberID extraction model architecture involved a base classification network, an alignment network, and an optical character recognition (OCR) model.
ZocDoc 团队最终能够通过他们的三部分模型管道超越 82%的基线准确性(用户报告的统计数据)!然而,围绕数据和模型管理的体验,他们的旅程是一个不断迭代和挫折的旅程。
ZocDoc 的演示令人印象深刻,因为它表明即使是用户体验的小调整也可以为客户带来巨大的价值,但也需要数据科学家的大量投资——正如引用他们的博客文章所表达的那样:
“然而,我们很快就认识到,要达到适合生产级个人健康应用的质量,需要更多的独创性和反复试验,而不仅仅是简单地将开源组件串联起来。”
阿卡什·库沙尔
应对实际的 ML 挑战
来自优步和 ZocDoc 的这两个演示说明了机器学习在实践中如何不仅仅是使用最新的建模框架。想象一下,当 Chris 和 Brian 不得不重建他们的管道以准备生产,但意识到他们没有跟踪他们原型的度量、超参数或代码时,他们感到多么沮丧。
如今,有效的机器学习的最关键障碍之一是可重复性。重现性通过减少或消除重新运行过去的实验时的变化来实现稳健的模型。
在 Comet.ml ,我们允许数据科学团队自动跟踪他们的数据集、代码更改、实验历史和生产模型,从而提高效率、透明度和可重复性。
观看 Comet.ml 如何帮助成千上万的用户使他们的机器学习实验更加有效和可跟踪的快速视频:
对于纽约地区的人们,请在 10 月 4 日加入我们,了解 Precision Health AI 如何应用机器学习来检测癌症。
我们将邀请 PHAI 的客户服务总监、数据科学家和软件工程师来解释他们是如何构建丰富的 ML 管道的。 RSVP 此处 !
想看更多应用机器学习的惊人例子?
- 在 Airbnb 分类房源照片:https://medium . com/Airbnb-engineering/categoring-Listing-Photos-at-Airbnb-f 9483 F3 ab 7 e 3
- Spotify 怎么这么了解你?(发现周刊):https://medium . com/s/story/spotifys-Discover-Weekly-how-machine-learning-finds-your-new-music-19 a 41 ab 76 EFE
- 缝合修复算法之旅:https://algorithms-tour.stitchfix.com/
- ZestFinance for 承销
- 来自 Red Pixie 、tech emergency和 ranee 的关于 ML x marketing 的帖子的应用 ML 的更高层次概述
用数学重新排列 NHL
为什么埃德蒙顿和卡尔加里应该在不同的赛区比赛
This is the best possible NHL divisional alignment, according to the immutable laws of math. Read on!
12 月 4 日,星期二,准备好参加西雅图的大型派对吧,人们普遍预计这座城市将获得第 32 届 NHL 特许经营权。在 2008 年输给超音速队后,热情的球迷们终于可以享受冬季运动了,温哥华将获得一个区域性的竞争对手。
增加第 32 支队伍也需要 NHL 重新调整其部门。目前,NHL 在太平洋地区有 8 支球队,在中部有 7 支球队。西雅图几乎肯定会被放在太平洋赛区,导致西部联盟内部暂时不平衡。有很多关于哪支球队将被转移到补偿的互联网聊天,领先的候选人是亚利桑那郊狼队,因为缺乏传统的竞争,以及他们作为太平洋赛区中位于最东边的球队的位置。
但是,如果团队仅仅根据紧密度被分配到不同的部门,而不考虑传统的竞争,那会怎么样呢?这些部门会是什么样子?
幸运的是,这是一个可以解决的问题。通过计算每个 NHL 城市之间的距离,我们可以将 32 支球队分成 4 个分区,这样可以最小化分区内的总旅行距离。
假设和免责声明
1)我使用离每个 NHL 队的比赛场地最近的主要机场作为每个城市的起点/终点。这就产生了一些有趣的边缘案例——例如,两个纽约团队都将他们的起点/终点列为拉瓜迪亚机场,这使得他们在我们的模型中彼此之间的有效旅行距离为 0 英里。虽然这显然是不正确的,但模型的目的是做出有用的预测,而不是 100%精确。况且,两个在同一个城市打球的球队应该留在同一个赛区的建议,也不会让任何人震惊。
2)值得再次强调的是,这种模式并不重视将传统竞争对手团结在一起。该模型完全是通过最小化旅行距离来生成最紧凑的分区。我不打算说我的结果从商业角度来看有意义,但这些信息可以作为关于重组的更广泛对话中的数据点。
最优会议
首先,我们需要通过最小化会议间的距离,将我们的 32 个团队分成两个 16 人的会议。有趣的是,目前的团队联盟是最佳的。NHL 在这方面做得很好,最近几年将哥伦布、底特律和多伦多从西部转移到东部。
The current NHL conference setup is optimal…
东部联盟
…but there’s room for improvement in the Eastern Conference.
尽管东部联盟并没有因为西雅图的加入而改变其组成,但目前的联盟仍然值得研究。不出所料,还有很大的改进空间——我们的模型显示,总的部门内距离可以减少 15.8%。
东部 16 支球队中有 10 支通过我提议的重组变得更好了。让坦帕湾和佛罗里达与加拿大和新英格兰北部的球队在同一个分区比赛一直是一种好奇,更多的是出于一时的便利而不是常识,几乎所有这些球队都通过重新调整而明显改善。
Units are in miles.
我当然可以看到匹兹堡、多伦多和华盛顿的球迷在这里大喊犯规。匹兹堡将失去与费城的分区竞争,但这将是回到不久前的状态——就在 1998 年,匹兹堡和费城处于不同的分区。让水牛城和多伦多在不同的部门比赛可能会感觉不太直观,但是回想一下,这个练习的目标是最小化总行程距离。虽然多伦多有一个势均力敌的对手可能对更好,但这对其他车队的伤害大于对多伦多的帮助。然而,如果我们把华盛顿换成布法罗,我们只会差 582 英里(1.29%),同时保留几个传统的对手。
西部联盟
Can I ever set foot in Edmonton again?
Units are in miles. Note that the “old distance” condition consists of the current divisional alignment with Phoenix in the Central, consistent with popular speculation.
这是一个非常接近的电话,但全国曲棍球联合会将通过交换埃德蒙顿到中央分区和保持菲尼克斯在太平洋上节省 530 英里的分区旅行距离。虽然这样的举动显然会使卡斯卡迪亚+阿尔伯塔团队旅行更长的距离,但这种变化对西南团队的好处大于对北方团队的伤害。最终,这些信息应该放在适当的背景下——当成本是打破阿尔伯塔省的战斗时,节省 0.6%的总旅行距离真的值得吗?我的猜测是没有。
结论
虽然注意力理所应当地集中在未来几周的西部联盟重组上,但 NHL 将会很好地以紧凑的重点重组东部联盟。这样做,NHL 可以大大减少旅行时间和碳足迹的产品。然后,他们可以将这些积分中的一部分用于类似无会议斯坦利杯季后赛的活动,这将是未来帖子的主题!
带着归属和感激
所有的地图都是用 Tableau 设计的;NHL 标志是在合理使用原则下使用的。我已经把我的距离矩阵和数据文件上传到 GitHub 它们在这里有售。
我要感谢华盛顿大学的陈石教授在我着手这个项目时给予我的建议和鼓励。我还要感谢伊恩·马丁内斯,他的指导和富有感染力的乐观精神是我灵感的源泉。
使用 Spark 结构化流、XGBoost 和 Scala 进行实时预测
在本文中,我们将讨论如何构建一个完整的机器学习管道。第一部分将集中在以标准批处理模式训练二元分类器,第二部分我们将做一些实时预测。
我们将使用来自众多 Kaggle 竞赛之一的泰坦尼克号:从灾难中学习机器的数据。
在开始之前,请了解您应该熟悉 Scala 、 Apache Spark 和 Xgboost 。
所有的源代码也可以在 Github 上找到。酷,现在让我们开始吧!
培养
我们将使用 Spark 中的 ML 管道训练一个 XGBoost 分类器。分类器将被保存为输出,并将在 Spark 结构化流实时应用程序中使用,以预测新的测试数据。
步骤 1:开始 spark 会话
我们正在创建一个 spark 应用程序,它将在本地运行,并将使用与使用local[*]
的内核一样多的线程:
**val** spark = SparkSession.*builder*()
.appName("Spark XGBOOST Titanic Training")
.master("local[*]")
.getOrCreate()
步骤 2:定义模式
接下来,我们定义从 csv 读取的数据的模式。这通常是一个比让 spark 推断模式更好的实践,因为它消耗更少的资源,并且我们完全控制字段。
**val** schema = StructType(
*Array*(*StructField*("PassengerId", DoubleType),
*StructField*("Survival", DoubleType),
*StructField*("Pclass", DoubleType),
*StructField*("Name", StringType),
*StructField*("Sex", StringType),
*StructField*("Age", DoubleType),
*StructField*("SibSp", DoubleType),
*StructField*("Parch", DoubleType),
*StructField*("Ticket", StringType),
*StructField*("Fare", DoubleType),
*StructField*("Cabin", StringType),
*StructField*("Embarked", StringType)
))
步骤 3:读取数据
我们将 csv 读入一个DataFrame
,确保我们提到我们有一个头。
**val** df_raw = spark
.read
.option("header", "true")
.schema(schema)
.csv(filePath)
步骤 4:删除空值
所有空值都被替换为 0。这并不理想,但对于本教程的目的来说,这是可以的。
**val** df = df_raw.na.fill(0)
第五步:将标称值转换为数值
在浏览这一步的代码之前,让我们简单地浏览一下 Spark ML 的一些概念。他们引入了 ML 管道的概念,这是一组建立在DataFrames
之上的高级 API,可以更容易地将多个算法合并到一个进程中。管道的主要元素是Transformer
和Estimator
。第一个可以表示一种算法,可以将一个DataFrame
转换成另一个DataFrame
,而后者是一种算法,可以适合一个DataFrame
来产生一个Transformer
。
为了将名义值转换成数值,我们需要为每一列定义一个Transformer
:
**val** sexIndexer = **new** StringIndexer()
.setInputCol("Sex")
.setOutputCol("SexIndex")
.setHandleInvalid("keep")
**val** cabinIndexer = **new** StringIndexer()
.setInputCol("Cabin")
.setOutputCol("CabinIndex")
.setHandleInvalid("keep")
**val** embarkedIndexer = **new** StringIndexer()
.setInputCol("Embarked")
.setOutputCol("EmbarkedIndex")
.setHandleInvalid("keep")
我们使用StringIndexer
来转换值。对于每个Transformer
,我们将定义包含修改值的输入列和输出列。
步骤 6:将列组合成特征向量
我们将使用另一个Transformer
将 XGBoost Estimator
分类中使用的列组装成一个向量:
**val** vectorAssembler = **new** VectorAssembler()
.setInputCols(*Array*("Pclass", "SexIndex", "Age", "SibSp", "Parch", "Fare", "CabinIndex", "EmbarkedIndex"))
.setOutputCol("features")
步骤 7:添加 XGBoost 估计器
定义将生成模型的Estimator
。估计器的设置可以在图中定义。我们还可以设置特征和标签列:
**val** xgbEstimator = **new** XGBoostEstimator(*Map*[String, Any]("num_rounds" -> 100))
.setFeaturesCol("features")
.setLabelCol("Survival")
步骤 8:构建管道和分类器
在我们创建了所有单独的步骤之后,我们可以定义实际的管道和操作顺序:
**val** pipeline = **new** Pipeline().setStages(*Array*(sexIndexer, cabinIndexer, embarkedIndexer, vectorAssembler, xgbEstimator))
输入DataFrame
将被转换多次,最终将产生用我们的数据训练的模型。我们将保存输出,以便在第二个实时应用程序中使用。
**val** cvModel = pipeline.fit(df)
cvModel.write.overwrite.save(modelPath)
预言;预测;预告
我们将使用 Spark 结构化流从一个文件中传输数据。在现实世界的应用程序中,我们从 Apache Kafka 或 AWS Kinesis 等专用分布式队列中读取数据,但对于这个演示,我们将只使用一个简单的文件。
简要描述 Spark 结构化流是一个基于 Spark SQL 构建的流处理引擎。它使用了与DataFrames
相同的概念,数据存储在一个无界的表中,该表随着数据的流入而增加新的行。
步骤 1:创建输入读取流
我们再次创建一个 spark 会话,并为数据定义一个模式。请注意,测试 csv 不包含标签Survival
。最后我们可以创建输入流DataFrame,
df
。输入路径必须是我们存储 csv 文件的目录。它可以包含一个或多个具有相同模式的文件。
**val** spark: SparkSession = SparkSession.*builder*()
.appName("Spark Structured Streaming XGBOOST")
.master("local[*]")
.getOrCreate()
**val** schema = StructType(
*Array*(*StructField*("PassengerId", DoubleType),
*StructField*("Pclass", DoubleType),
*StructField*("Name", StringType),
*StructField*("Sex", StringType),
*StructField*("Age", DoubleType),
*StructField*("SibSp", DoubleType),
*StructField*("Parch", DoubleType),
*StructField*("Ticket", StringType),
*StructField*("Fare", DoubleType),
*StructField*("Cabin", StringType),
*StructField*("Embarked", StringType)
))
**val** df = spark
.readStream
.option("header", "true")
.schema(schema)
.csv(fileDir)
第二步:加载 XGBoost 模型
在对象XGBoostModel
中,我们加载预训练模型,该模型将应用于我们在流中读取的每一批新行。
**object** XGBoostModel {
**private val** *modelPath* = "your_path"
**private val** *model* = PipelineModel.*read*.load(*modelPath*)
**def** transform(df: DataFrame) = {
// replace nan values with 0
**val** df_clean = df.na.fill(0)
// run the model on new data
**val** result = *model*.transform(df_clean)
// display the results
result.show()
}
}
步骤 3:定义自定义 ML 接收器
为了能够将我们的分类器应用于新数据,我们需要创建一个新的接收器(流和输出之间的接口,在我们的例子中是 XGBoost 模型)。为此,我们需要一个自定义接收器(MLSink
)、一个抽象接收器提供者(MLSinkProvider
)和一个提供者实现(XGBoostMLSinkProvider
)。
**abstract class** MLSinkProvider **extends** StreamSinkProvider {
**def** process(df: DataFrame): Unit
**def** createSink(
sqlContext: SQLContext,
parameters: Map[String, String],
partitionColumns: Seq[String],
outputMode: OutputMode): MLSink = {
**new** MLSink(process)
}
}
**case class** MLSink(process: DataFrame => Unit) **extends** Sink {
**override def** addBatch(batchId: Long, data: DataFrame): Unit = {
process(data)
}
}**class** XGBoostMLSinkProvider **extends** MLSinkProvider {
**override def** process(df: DataFrame) {
XGBoostModel.*transform*(df)
}
}
步骤 4:将数据写入我们的自定义接收器
最后一步是定义一个将数据写入自定义接收器的查询。还必须定义一个检查点位置,以便应用程序在失败时“记住”流中读取的最新行。如果我们运行该程序,每一批新的数据将显示在控制台上,其中也包含预测的标签。
df.writeStream
.format("titanic.XGBoostMLSinkProvider")
.queryName("XGBoostQuery")
.option("checkpointLocation", checkpoint_location)
.start()
接收器工作特性曲线解密(Python 语言)
在数据科学中,评估模型性能非常重要,最常用的性能指标是分类得分。然而,在处理具有严重类别不平衡的欺诈数据集时,一个分类分数没有太大意义。相反,接收机工作特性或 ROC 曲线提供了一个更好的选择。ROC 是信号(真阳性率)对噪声(假阳性率)的图。通过查看 ROC 曲线下的面积(或 AUC)来确定模型性能。最好的 AUC 可能是 1,而最差的是 0.5(45 度随机线)。任何小于 0.5 的值都意味着我们可以简单地做与模型建议完全相反的事情,以使值回到 0.5 以上。
虽然 ROC 曲线很常见,但并没有太多的教学资源解释它是如何计算或得出的。在这篇博客中,我将逐步展示如何使用 Python 绘制 ROC 曲线。之后,我将解释基本 ROC 曲线的特征。
类别的概率分布
首先,让我们假设我们的假设模型为预测每个记录的类别产生了一些概率。与大多数二元欺诈模型一样,让我们假设我们的类别是“好”和“坏”,并且该模型产生 P(X=“坏”)的概率。为了创建这个概率分布,我们绘制了一个高斯分布图,每个类别有不同的平均值。想了解更多关于高斯分布的信息,请阅读这篇博客。
import numpy as np
import matplotlib.pyplot as pltdef pdf(x, std, mean):
cons = 1.0 / np.sqrt(2*np.pi*(std**2))
pdf_normal_dist = const*np.exp(-((x-mean)**2)/(2.0*(std**2)))
return pdf_normal_distx = np.linspace(0, 1, num=100)
good_pdf = pdf(x,0.1,0.4)
bad_pdf = pdf(x,0.1,0.6)
现在我们有了分布,让我们创建一个函数来绘制分布。
def plot_pdf(good_pdf, bad_pdf, ax):
ax.fill(x, good_pdf, "g", alpha=0.5)
ax.fill(x, bad_pdf,"r", alpha=0.5)
ax.set_xlim([0,1])
ax.set_ylim([0,5])
ax.set_title("Probability Distribution", fontsize=14)
ax.set_ylabel('Counts', fontsize=12)
ax.set_xlabel('P(X="bad")', fontsize=12)
ax.legend(["good","bad"])
现在让我们使用这个 plot_pdf 函数来生成绘图:
fig, ax = plt.subplots(1,1, figsize=(10,5))
plot_pdf(good_pdf, bad_pdf, ax)
现在我们有了二元类的概率分布,我们可以用这个分布来推导 ROC 曲线。
推导 ROC 曲线
为了从概率分布得出 ROC 曲线,我们需要计算真阳性率(TPR)和假阳性率(FPR)。举个简单的例子,假设阈值在 P(X=‘bad’)=0.6。
真阳性是阈值右侧指定为“坏”的区域。假阳性表示阈值右侧指定为“好”的区域。总正值是“差”曲线下的总面积,而总负值是“好”曲线下的总面积。我们将图中所示的值相除,得出 TPR 和 FPR。我们推导出不同阈值下的 TPR 和 FPR,得到 ROC 曲线。利用这些知识,我们创建了 ROC 绘图函数:
def plot_roc(good_pdf, bad_pdf, ax):
#Total
total_bad = np.sum(bad_pdf)
total_good = np.sum(good_pdf)
#Cumulative sum
cum_TP = 0
cum_FP = 0
#TPR and FPR list initialization
TPR_list=[]
FPR_list=[]
#Iteratre through all values of x
for i in range(len(x)):
#We are only interested in non-zero values of bad
if bad_pdf[i]>0:
cum_TP+=bad_pdf[len(x)-1-i]
cum_FP+=good_pdf[len(x)-1-i]
FPR=cum_FP/total_good
TPR=cum_TP/total_bad
TPR_list.append(TPR)
FPR_list.append(FPR)
#Calculating AUC, taking the 100 timesteps into account
auc=np.sum(TPR_list)/100
#Plotting final ROC curve
ax.plot(FPR_list, TPR_list)
ax.plot(x,x, "--")
ax.set_xlim([0,1])
ax.set_ylim([0,1])
ax.set_title("ROC Curve", fontsize=14)
ax.set_ylabel('TPR', fontsize=12)
ax.set_xlabel('FPR', fontsize=12)
ax.grid()
ax.legend(["AUC=%.3f"%auc])
现在让我们使用这个 plot_roc 函数来生成绘图:
fig, ax = plt.subplots(1,1, figsize=(10,5))
plot_roc(good_pdf, bad_pdf, ax)
现在绘制概率分布图和 ROC 图,以便直观比较:
fig, ax = plt.subplots(1,2, figsize=(10,5))
plot_pdf(good_pdf, bad_pdf, ax[0])
plot_roc(good_pdf, bad_pdf, ax[1])
plt.tight_layout()
阶级分离的影响
既然我们可以得到两个图,让我们看看 ROC 曲线如何随着类别分离(即模型性能)的改善而变化。我们通过改变概率分布中高斯分布的平均值来做到这一点。
x = np.linspace(0, 1, num=100)
fig, ax = plt.subplots(3,2, figsize=(10,12))
means_tuples = [(0.5,0.5),(0.4,0.6),(0.3,0.7)]
i=0
for good_mean, bad_mean in means_tuples:
good_pdf = pdf(x, 0.1, good_mean)
bad_pdf = pdf(x, 0.1, bad_mean)
plot_pdf(good_pdf, bad_pdf, ax[i,0])
plot_roc(good_pdf, bad_pdf, ax[i,1])
i+=1
plt.tight_layout()
如您所见,AUC 随着我们增加类别之间的间隔而增加。
放眼 AUC 之外
除了 AUC,ROC 曲线也可以帮助调试模型。通过观察 ROC 曲线的形状,我们可以评估模型的错误分类。例如,如果曲线的左下角更接近随机线,则暗示模型在 X=0 处分类错误。然而,如果右上角是随机的,则意味着误差发生在 X=1 处。此外,如果曲线上有尖峰(而不是平滑的),这意味着模型不稳定。
附加说明
数据科学是一个相当大且多样化的领域。因此,做一个万事通真的很难…
towardsdatascience.com](/data-science-interview-guide-4ee9f5dc778) [## 极端类别不平衡下的欺诈检测
数据科学中的一个热门领域是欺诈分析。这可能包括信用卡/借记卡欺诈、反洗钱…
towardsdatascience.com](/fraud-detection-under-extreme-class-imbalance-c241854e60c)