永久跟踪
Top Left: Total Productive Hours | Top Right: Total Miles Travelled | Bottom Left: Total Blog Posts | Bottom Right: Total Duolingo EXP
我虔诚地使用 Beeminder 一个月所学到的。
大约在过去的三十天左右,我一直在自己身上做实验。我试图努力追踪我生活的方方面面。可以说,这是我在吃自己的狗粮——过着一种在抽象层面上感觉良好的准动机生活。这是一个案例研究,这些是我的想法和结果。
这是对我之前文章的更新:
使用互联网和蜜蜂
medium.com](https://medium.com/@brennanbrown/planning-better-e0d60edbe271)
一.自我跟踪的初始问题
虽然我多年来一直是自我量化的粉丝,但我从未深入研究过。这有几个原因:
预先警告:我并不精通数据科学,这些论文只是我通过观察哪些对我有用,哪些没用,艰难地发现的东西。
- 错误的数据集。需要深入了解你自己和你每天实际使用的工具,才能知道你应该跟踪什么指标。我没能在Todoist*——*上追踪我的待办事项清单,只是因为我意识到我是那种只会把工作写在纸上的人。)
- 缺乏意义。类似地,追踪你追踪的东西必须有充分的理由——追踪必须能提供某种有益的帮助。一个强有力的、基于价值的目标会激励你坚持定期追踪。
- 缺乏威慑/鼓励。对于没有做你想追踪的事情,应该有一个固有的惩罚,对于做了这件事,应该有一个奖励*。*
- 缺乏自动化。在大多数情况下,我的数据集是用 API 或 IFTTT 收集的,或者有非常简单快速的手动输入。数据收集不应该是一件苦差事。
- 数据不一致。你所追踪的东西必须能够在一致的基础上产生数据。如果太频繁,你会太专注于跟踪本身。如果太不频繁,你最终会忘记跟踪。
所有这些都是我发现 Beeminder 对自我量化如此有效的原因。在大多数情况下,应用程序会为您完成所有的跟踪工作。你所要做的就是的工作。 Beeminder 是一种的关键习惯,如果你能养成在 Beeminder 上签到的习惯,你就可以把它作为你想改变或开始的任何其他习惯的起点。
二。蜜蜂之道
- 想清楚你想在生活中改变什么。所有的自我量化跟踪都应该从这里开始。坚定的目标就是一切。
例 1。我想多写点。
例二。我想更积极地锻炼身体。 - 找出定性目标有意义的量化。不要让含糊不清让你溜了——给你想要完成的事情一个确切的数字。
例 1。我想一年写 10 万字。
例二。我想一年跑/走 500 公里。 - 将你的定性目标转化为日常系统。上面的那些目标看起来令人畏惧,但是当你分解它们的时候,它们实际上更容易实现。
例 1。 10 万字/ 365 天≈每天 275 字
例 2。 500 公里/ 365 天≈每天 1800 步 - 想办法跟踪这个新的每日系统。现在有很多针对特定指标的应用程序和工具,通常都有完善的 API,可以轻松传输和绘制数据。
例 1。利用draft . in同步 Beeminder 上的每日字数。
例二。利用众多 健身应用 和 可穿戴设备 在 Beeminder 上同步每日步数。
三。我在追踪什么
手动输入的一个很大的好处是,它可以作为我实现其他 Beeminder 目标的日常检查。
写作 :另一个手动输入,这是我每天写的字数,每个数据点具体说明我主要写的是什么。通常要么只是日常日志写作或博客帖子。
博客文章 :跟踪我上传到 Medium 的文章数量。与其他活动不同,我追溯性地添加了我在 Medium 上的所有旧帖子,这些数据让我明白我真的需要开始发布更多。
生产性 / 非生产性 **时间:**这两者都通过时间记录器 RescueTime 进行跟踪。我试图每天完成一定数量的有成效的工作,无论是写作、编程还是参考/学习。我也试着限制我浪费在无脑和无结果的活动上的时间。
:记录我旅行的英里数,无论是走路、跑步还是骑自行车。我用 Runkeeper 追踪这个,没有花哨的可穿戴。它不计算我所有的旅行,只有当我特别记录一项活动时,它还会给我一张我的路线的 GPS 地图,这样我就可以看到那天我去了哪里。
编程 :跟踪我推送到 GitHub 的提交数量(以及其他贡献,如报告的问题和拉请求)。我承认这不是最好的跟踪方式,因为代码在达到适合部署的程度之前不应该提交,但我目前正在开发 熨斗学校 的课程,它会自动将我的作业实验室推送到我的 GitHub 帐户,这很酷。
社交媒体( )推特/insta gram):这可能对一些人来说是违反直觉的,但我很少使用任何社交媒体。通过跟踪我上传的照片和我写的推文,我被鼓励去寻找每天发生的有趣的事情,并与我的朋友和家人分享。
语言学习 :追踪我在 Duolingo 上赚取的经验值。在过去的几年里,我一直在努力自学法语,虽然很难,但每天练习一点点对我记忆的帮助远远超过了偶尔的补习班。
四。每日系统
以下是我在 Beeminder 上追踪的事情,展示我今天的样子。这实质上是将理论付诸实践,并落笔。事实是,除了编程,这些习惯根本不会占用我一天的太多时间,事实上,我因此有了更多的时间放松或尝试新事物。
- 以写下我感激的事情开始新的一天,并检查我在当前目标上的进展。
- 花十五或二十分钟在 Duolingo 和 TinyCards 上练习我的法语。
- 在我家附近散步或骑自行车。外出时拍摄任何有趣的东西。
- 花一两个小时编程。学习新的东西,很好的文档化,然后推送到 GitHub 上。
- 不要浪费时间漫无目的地浏览脸书或 Reddit。节约使用屏幕时间,当我想休息的时候做一些我真正喜欢的事情。(看一部纪录片,玩一个电子游戏,等等。)
- 花半个小时写我的日记或者写一篇博客。
- 在一天结束时,写一篇关于一天中发生的任何有趣事情的推文。
动词 (verb 的缩写)最后的想法
- 不要承诺任何不能让你兴奋的事情。对你的目标有自由意志的心理是必不可少的。如果你觉得你做的事情不仅仅是为了你自己,这将会是另一件苦差事。不要因为别人认为你应该而承诺什么。只有你。
- 对自己负责。我在我的脸书和推特个人资料里放了一个我的 Beeminder 账户的公开链接,这样任何人都可以看到我是否没有实现目标。我也写了这篇文章。利用公众压力作为动力和行善的工具。
- 任何事物都不会自己到位。自我的拼图有很多块,可能不会一下子全部拼起来。没有放之四海而皆准的方法,适合我的不一定适合你。T2 的普遍现象是良好价值观的重要性——如果你努力工作,幸运的 T4 法则最终会对你有利。
- 你的第一次尝试总是很糟糕。与上面类似,当你第一次尝试的时候,不要期望能搞定任何事情。我使用 Beeminder 快两年了,刚刚掌握了它的窍门。所有东西的初稿——不仅仅是写作——都将是垃圾。
- 慢行。我没有尝试一下子开始追踪所有的事情。我从最小和最容易的(我已经在做的事情)开始,每周添加一些新的东西。如果经过一周的跟踪,我发现有些东西不好用了,我会直接删除它。没什么大不了的。
- 成功的灵丹妙药就是认识到没有灵丹妙药。这只是许多艰苦的工作,并弄清楚如何为做这些艰苦的工作感到快乐。
使用 Kafka Streams 跟踪纽约市 Citi Bike 的实时利用率
卡夫卡流的实际使用案例
“Blue Citibike bicycles are parked in a row at the World Trade Center.” by Anthony Ginsbrook on Unsplash
说到构建分布式实时流处理系统,我们是 Apache Kafka 的忠实粉丝。它可大规模扩展,具有简单的发布-订阅语义,并提供容错的持久数据存储。这是一个处理事件流数据的绝佳平台,例如点击事件、分布式日志、时间序列指标等。我们在之前的一篇文章中写过关于使用 Apache Kafka 构建实时分析的文章。
但是在大多数用例中,数据流不是孤立处理的。当收到 Kafka 消息时,经常会查询一些有状态数据存储,以便获得足够的信息来处理该消息。例如,如果我们有一个接收客户订单的订单流,该订单很可能需要使用客户信息和/或产品元数据查询数据库才能进行处理,那么流数据如何与有状态数据(如数据库表)一起工作呢?
这就是《T2》和《T3》出现的原因。Kafka Streams 是一组应用程序 API(目前在 Java & Scala 中),无缝集成了无状态(流)和有状态(表)处理。这个设计的基本前提非常有趣。简而言之,它基于这样一个事实,即可以从变更数据捕获(CDC)流或事务日志记录中重建表。如果我们有一个变更日志流,那么表就是一个反映每个变更记录最新状态的本地存储。有了这个概念,流-流或流-表连接成为通过各种内部 Kafka 主题路由数据的统一操作。默认情况下,RocksDB 用于本地有状态存储,但也可以使用其他键值数据库。我鼓励你去读一下的博客文章,这篇文章解释了设计卡夫卡作品的动机。这让我大开眼界。
在本帖中,我们将使用 Kafka Streams 来跟踪纽约市花旗自行车使用率的实时统计数据。CitiBikeNYC 发布了包含自行车出行的历史数据集和每个自行车站点信息和可用性的实时 GBFS 反馈。虽然历史数据集是洞察的宝库,但通过实时数据馈送可以更好地获得一些利用率指标。我们将计算两个重要的利用率实时指标。
- 目前可用自行车少于 10%的站点,计算方法为(可用自行车数量)/(站点容量)。该指标可以作为自行车可用性低的实时通知。
- 每小时自行车周转率最高的站点,在滚动窗口中通过(站点自行车净变化)/(站点容量)计算。该指标可用于微调花旗自行车站再平衡战略。
数据流看起来像这样。
现在让我们开始编码。
首先,由于 Citi Bike feed 是一个 Restful API,我们需要添加一个 Java 应用程序来轮询端点,并将 JSON 响应转换为流并发布到 Kafka 主题上。
station_information 和 status JSON 的示例如下所示
我们使用 google http java 客户端将 http 响应转换成 POJO(普通旧 java 对象)。
然后我们将 station_information 和 statuses 对象的列表序列化为 string,并分别发布到它们命名的 Kafka 主题中。
关于向/从 Kafka 序列化/反序列化消息注释。对于生产级系统,Apache Kafka Streams API 使用基于 avro 的序列化,并使用模式注册表存储 avro 模式。我觉得对于这篇文章来说,这增加了很多不必要的麻烦,所以我把这部分去掉,尽可能使用基于字符串的序列化模式。如果你对基于 Avro 的 SerDes(序列化/反序列化)感兴趣,请查看 Avro Serdes 类。
现在我们有了来自 station_information 和 station_status 主题的数据流,让我们看看如何找到自行车利用率低于 10%的站点。完整的代码是这里是。
首先,我们用一系列配置构造一个 KakfaStreams 对象,包括 Kafka 引导服务器、文件系统上的本地状态和 Kafka 消费者选项。
然后,我们可以连接转换的每个步骤,就像我们正在构建一个流数据管道一样。
- 从 Kafka 主题 status 的输入构建一个 KStream。我们大量使用 Java8 Lambda 表达式,将输入流数据映射到 POJO,并提取 num_bikes_available 指标
2.从 Kafka 主题 station_information 的输入构建一个 KTable。
您可能会问,为什么我们使用 KStream 表示站点状态,而使用 KTable 表示站点信息。还记得流和表二元性吗?表是变更事件流的结束状态。在这种情况下,我们希望捕捉每个站点的状态变化,因为它告诉我们可用自行车的数量如何随时间变化。另一方面,站点信息是静态数据,包括容量、名称、地理位置等。我们只关心每条数据的最新值,因此 KTable 允许我们将一系列更改压缩到最终快照中。
3.现在是“这里发生了什么神奇的事情?”部分。让我们在 KStream 和 KTable 上做一个左连接。请记住,我们的指标是(可用自行车数量)/(车站容量)。分子来自 station_status 对象,但分母来自 station_information 对象,因此我们需要在这里做一个流表连接。这就是卡夫卡溪流的力量所在。能够在没有大量代码的情况下将一个不断发展的数据流与一个静态的本地存储连接起来是非常简单的。
在加入流之后,我们过滤计算出的小于 10%的可用性,并将数据映射到人类可读的输出字符串。
4.这一步并不是绝对必要的,但我们最终会将分析结果发布到 Kafka 的输出主题上,这样我们就可以检查它们了。
5.如果我们启动一个控制台 Kafka 消费程序,我们可以看到输出如下
station_id: 3699, longitude -73.98918, latitude 40.763603, bikes: 1, capacity: 30, ratio: 3.33%
station_id: 3700, longitude -73.95334, latitude 40.779408, bikes: 3, capacity: 39, ratio: 7.69%
station_id: 3704, longitude -73.941765, latitude 40.74375, bikes: 1, capacity: 19, ratio: 5.26%
现在,让我们来看看如何在会话窗口中计算周转率。我们有类似的步骤来建立站信息和站状态的 KStream/KTable。这里的代码是。
- 我们计算的分析是(可用自行车数量的净变化)/ (station_capacity),因此我们在这里引入了一个窗口聚合,我们可以折叠每个分组状态并计算净增量。聚合器接口接受一个初始化器和一个累加器。这类似于函数式编程中的 fold()或 reduce()操作。
2.既然计算了自行车的窗口化净变化,让我们再次连接 station_information KTable,并将我们的分析输出到输出主题。
3.输出如下所示。注意,本例中的关键字是一个窗口,因为我们在流上应用了一个滚动窗口。
station_id: [472@1535061600000/1535065200000], turnover: 72.22%
station_id: [473@1535061600000/1535065200000], turnover: 81.40%
station_id: [474@1535061600000/1535065200000], turnover: 5.13%
station_id: [476@1535061600000/1535065200000], turnover: 8.47%
station_id: [477@1535061600000/1535065200000], turnover: 55.32%
为了运行代码,按照这里的快速入门启动 Zookeeper、Kafka,创建主题并运行 Java 应用程序。
总之,我们如何看待在实践中使用卡夫卡作品?答案是“看情况”。这要看你的数据是什么样子,业务逻辑有多复杂。
Kafka Streams 站在 Apache Kafka 这个巨人的肩膀上,因此它无疑具有大规模分布式流数据平台的可扩展性和弹性。我们可以轻松地交替使用流数据和有状态数据,这说明了库 API 的设计有多好。如果你的数据在形式上非常简单,比如统计点击事件,排名页面浏览量,这是实时数据分析的一个很好的选择。
另一方面,由于 Kafka Streams 的内部使用 Kafka pub-sub 作为存储主干,您必须不断地考虑如何在数据管道的每个阶段序列化/反序列化您的数据。这意味着如果你在你的应用程序中使用了大量的 POJO(Plain old java object ),你就有了额外的任务来指定如何序列化它们,以便将它们传递到管道中,不管是不是 Avro 模式。虽然可以理解,但它增加了额外的复杂性,我不确定在业务逻辑繁重的应用程序中这样做是否值得。在撰写本文时,Kafka Streams 没有基于 python 的 API,因此对于执行大量分析的数据科学家来说,这是一个非常陡峭的学习曲线。
一如既往,你可以在 Cloudbox Labs github 上找到这篇文章中讨论的完整代码。
自动驾驶汽车跟踪行人
第四章:用数据做酷事!
自动驾驶汽车在行驶时需要周围的世界地图。它必须能够连续跟踪路上的行人、汽车、自行车和其他移动物体。在这篇文章中,我将通过一种称为扩展卡尔曼滤波器的技术进行讨论,谷歌自动驾驶汽车正在使用这种技术来跟踪道路上的移动物体。
下面是一个汽车在模拟器中跟踪行人的视频。激光雷达测量值为红色圆圈,雷达测量值为蓝色圆圈,估算标记为绿色三角形。有趣的是,与雷达相比,激光雷达的精确度有多高。经过一些试验,卡尔曼滤波器的精度可以提高到 0.09 的均方根误差。
Kalman Filter in action
链接到我的 GitHub 用 C++实现上述视频的完整代码。
在讨论卡尔曼滤波器之前,我想先谈谈汽车中使用的三种主要传感器——摄像头(前后)、激光雷达和雷达。
Car Sensors — Camera, LIDAR and RADAR
激光雷达使用激光进行测量,并生成周围世界的点云,为汽车提供相当准确的 x 位置和 y 位置值。它能够以非常高的精度探测汽车附近(20-40 米)的物体。然而,激光雷达在恶劣的天气条件下或传感器变脏时不是很准确。激光雷达云看起来像:
LIDAR point cloud
另一方面,雷达不太精确,但是能够提供对物体的位置和速度的估计。速度是使用多普勒效应估计的,如下图所示。雷达能够探测到离汽车 200 米远的物体。它也不易受天气条件的影响。
RADAR estimating velocity of a car using Doppler effect
卡尔曼滤波器是一种算法,可用于跟踪一段时间内移动行人的位置和速度,并测量与之相关的不确定性。它有两个主要步骤——一个预测步骤,预测行人在下一个时间步可能在哪里,假设他们以恒定的速度移动;一个更新步骤,使用传感器数据(激光雷达和雷达)更新我们的估计。并且这两个步骤无休止地重复。
让我们更详细地讨论一下这个问题:
首先,我们将行人的状态指定为一个四维向量,表示-位置 x,位置 y,速度 x,速度 y。以下是卡尔曼滤波器的主要步骤:
- 初始化 t=0 时行人的状态。我们通过读取传感器的第一个测量值来估计我们的位置和速度
- 预测步骤——在 t=1 时,我们使用简单的物理方程来估计物体在恒定运动(固定速度,无加速度)下的可能位置
px(t+1 时)= px(t 时)+ vx* dt(时间差)
vx(在 t+1 时)= vx(在 t 时)
类似地,我们可以更新我们的 y 位置和速度估计
3.测量值更新步骤-现在我们从雷达和激光雷达读取测量值,并使用它来更新我们在步骤 2 中计算的行人状态估计值。测量步骤后的新状态用于下一个预测步骤。
如下图所示,此过程不断重复以更新当前状态:
另一件要注意的事情是,在卡尔曼滤波器中,行人的状态被估计为具有均值和协方差的高斯(钟形曲线)。这是 1D 和 2D·高斯的长相:
1 D Gaussian
2D Gaussian
这里有个有趣的问题?—如果我们有传感器测量,为什么还需要进行预测?用传感器(激光雷达/雷达)测量来更新状态不是最好的吗?这些应该很准确。对吗?
不尽然!测量也可能有不确定性。设备制造商提供了传感器测量噪声的信息。此外,像雨/雾这样的局部环境条件会使传感器不太精确。
不要盲目相信测量结果,这是一个很好的做法。通过组合信息,用于预测和测量的高斯函数成倍增加,当这种情况发生时,最令人惊奇的事情发生了,由此产生的不确定性降低了,如下所示。
卡尔曼滤波方程有点复杂,你可以在维基百科上查看
我还构建了一个无味卡尔曼滤波器,它能够适应非线性运动,并且在预测行人的状态时更加准确。我的 Github 也有 C++内置的无味卡尔曼滤波器。
总的来说,构建我的第一个卡尔曼滤波器并使用它跟踪物体是一次很棒的经历,我对结果非常满意。
其他著述:https://medium.com/@priya.dwivedi/
PS:我住在多伦多,我希望将职业生涯转向深度学习。如果你喜欢我的帖子,并能把我联系到任何人,我将不胜感激:)。我的电子邮件是 priya.toronto3@gmail.com
参考文献:
Udacity 无人驾驶汽车 Nano Degree——我感谢 Udacity 给我机会成为他们新的无人驾驶汽车项目的一部分。这是一次非常有趣的旅程。我使用的大部分代码都是在课堂讲课中建议的。
使用机器学习跟踪街头艺术-更新
Mural from Reyes, Revok and Steel from MSK (https://www.fatcap.com/live/revok-steel-and-reyes.html)
感谢您关注公共艺术【⁰】项目,利用机器学习围绕街头艺术建立一个谱系。这个项目旨在创建一个记录世界各地街头艺术的中心,并使用现代图像分析技术为未来建立一个公共艺术的历史参考。
Public Art iOS application
作为一个快速更新,这个项目始于 2014 年,在 Gary Chou 的轨道训练营 [ ]期间,我建立了一系列小项目,探索软件和涂鸦如何在实验性的辅助项目中共存。其中一个副业项目是一项抓取 Instagram 图片的实验,并开发一个 iOS 来浏览你附近的街头艺术。这款功能不再完整的应用仍在 iOS 应用商店 [ ]。
去年 8 月,我开始参加先锋锦标赛,这是一个每月一次的锦标赛,围绕着一个由全球各地从事有趣项目的有创造力的年轻人组成的社区。我决定通过整合我对机器学习的熟悉程度,围绕记录涂鸦重新开始这个项目。
Kickstarter page
9 月份,我运行了一个“Quickstarter”,这是一个 100 美元的 Kickstarter 项目,令人惊讶的是,在朋友之外,我发现了一些完全陌生的人对这个项目感兴趣 [ ]。这个项目给了我进一步探索街头艺术和软件如何共存的信心。
在同一个项目中,我开始继续从网上的公共资源中抓取更多的图片,同样,我发现我的旧方法有一个巨大的问题。虽然我仍然可以抓取 Instagram,就像我在 2014 年做的那样,但我需要用于历史目的的许多元数据不再可用。特别是,我没有地理数据,而地理数据是让这些图像变得有用的关键。我在这里简要地写了这个:关于社交媒体的后中心化【⁴].
PublicArt.io current website’s functional prototype
从那以后,我把注意力从构建工具来抓取公共资源转移到构建一个可以在线存储公开记录的街头艺术的基础上。
这将效仿许多已经在线的照片分享服务,灵感来自 Flickr、Instagram、Imgur 等等。这项服务的重点将仅仅是记录街头艺术,帮助收集艺术作品的图像,观看艺术家的作品,并向公众提供这些数据。
我很自豪地宣布,来自乔治·梅森大学[⁶]墨卡托斯中心的泰勒·考恩[⁵],已经将他的新兴企业奖学金扩展到我的项目[⁷].]
Emergent Ventures
虽然这个项目最初是个人资助的,但我对能够将我的时间扩展到构建工具上更有信心。有了这笔赠款,我相信我正在建造的东西有能力维持其成本并证明其价值。
在我目前的探索状态之前,我正在尝试应用嵌入分析技术的图像特征提取工具来比较不同的街头艺术作品是如何相似还是不同。为了过度简化和简单解释:图像特征提取工具可以获取图像并量化单个参数的存在,其代表特征【⁸].
该参数可以简化为一个单一的数字,然后可以跨图像进行比较。通过机器学习工具,特别是 Tensorflow Inception 库【⁹】,可以从一张图像中提取数万个特征,然后用于与其他图像中的相似特征进行比较。
通过这些嵌入,我能够产生非常有趣的三维空间视觉效果,展示某些艺术家是如何相似或不同的。在最基本的情况下,模板涂鸦被映射到同一个维度空间,而涂鸦“炸弹”或更大的壁画会分别映射到相似的多维空间【⁰].
在地理数据无法访问之前,我从 Instagram 上抓取了成千上万张图片,利用这些图片,我分析了随着时间的推移,世界各地街头艺术的存在情况 [ ]。
由于 Instagram 的政策变化,这些数据不再与最初被编入索引的实际图像相关联,而是提供了对世界各地街头艺术和涂鸦的洞察。
有趣的是,图像频率也提供了一种视觉,这种视觉回避了城市中心和街头艺术之间的明显关系。如果进一步分析,街头艺术和房地产价值、社区社会关系、政治参与和其他社会现象之间可能存在明显的相关性。
在过去的几天里,我一直专注于综合我期望使用机器学习来分析街头艺术的各种手段。由于媒体对人工智能的歪曲以及机器学习在技术/营销领域的广泛意义,我自己也在纠结我的意思。
在这个项目实施之前,我曾认为有可能建立物体检测模型来识别图像中不同类型的涂鸦。例如,故意破坏的表现不同于社区认可的壁画。我还想象有可能在更大的字母形式的涂鸦作品中找到识别特定字母的方法。我相信将定义良好的标签和数据集与一个可变的自动编码器相结合来生成基于机器学习的字母形式的片段会很有趣。
更进一步,我认为有可能使用机器学习来检测一个地方的图像何时是“新的”,基于它在特定地方的先前图像中没有被检测到。我认为找到穿越美国的火车车厢的摄像头也很有趣,并建立一个管道来捕捉火车车厢上的涂鸦,识别火车车厢序列号,并跟踪火车车厢及其各自的艺术如何穿越这个国家。
以上各点都是基于机器学习的分析技术的实际表达。
虽然这些都是有趣的项目,但我暂时将我的注意力集中在以下六点上:识别艺术家的作品,跟踪类似的风格/影响,地理定位图像 [ ],对风格进行分类,关联社会现象,并发现新的艺术。基于跟踪图像,内容,图像图像的频率,并使这些数据可供他人使用,我相信街头艺术可以创造更多的价值,并获得更多的尊重。
基于最近的工作,我得到了一个功能齐全的应用程序,允许用户创建帐户,上传图像,将重要的元数据(艺术家/位置/创作数据)与图像相关联。虽然用户体验和设计不是我引以为豪的地方,但我会继续用现有的涂鸦鉴赏家测试当前的形式。
当我继续分享这个项目时,如果你有任何兴趣或者想了解更多,请联系我。
[0]:https://www . public art . io
【1】:https://orbital.nyc/bootcamp/
【2】:http://graffpass.com
【3】:https://www . kickstarter . com/projects/remember Lenny/new-public-art-foundation-a-genetics-of-public-ST/updates
【4】:https://medium . com/@ remember Lenny/on-the-insta
拖拉机、大数据和公司
Photo by Caique Silva on Unsplash
你好鲍勃
鲍勃是一个农民。鲍勃是现代人,他有无人驾驶飞机、机器人和一辆闪亮的拖拉机帮助他耕种他的田地。不仅仅是帮助他,这些用于工业农业的工具产生数据,大量的数据。这些数据通常是 Excel 表格上的数百万个数字。它们可以提供关于温度、风速、水资源、土壤湿度、营养成分、植物健康等信息。这种快速产生的、廉价的、海量的数据对 Bob 来说没有任何意义。他能用它们做什么?
大数据,鲍勃和朋友们
关于植物、气候和金融市场的数据对鲍勃来说是一个获得关于他的文化的最新和本地具体信息的绝佳机会。他的数据也与邻近农民的数据库进行比较。由于这一点,他可以精确地调整他的现场管理,以降低他的生产成本,增加他的利润。例如,Bob 知道他的植物每天的营养需求,因此他可以在正确的时间添加正确数量的肥料,而不会过度使用。当鲍勃掌握了商品市场的数据后,他可以在最佳时机出售他的作物,以获得最高利润。
从数据中创建的信息使做出最佳决策变得更加容易,但是 Bob 无法独自管理所有这些数据,他需要专家的外部帮助。过去,那些专家是他的祖父和村里的智者;今天的专家属于私人公司。这些公司拥有存储、交换和分析大量数据的基础设施。
数据的收集和交易是一项非常有利可图的活动。像 Acxiom 或 Experian 这样的数据经纪人专注于从世界各地获取数据,并对其进行管理和分发。它们确保了数据的可追溯性、匿名性和质量。
数据分析师位于这个链条的末端。他们将数据转化为农民可以实施建议。数据分析创造了新的商业机会,吸引了愿意创建咨询机构的企业家来帮助农民增加利润。印度的 FarmGuide 就是这样一家农业科技初创公司,它是“整合机器学习和数据分析等技术,以创建定制信息来迎合农场企业和种植者”。它通过向印度小农提供有关天气、市场机会和新作物种子的信息,帮助他们做出最佳决策。这些信息通过预先安排和预先录制的语音电话发送给农民,农民可以做出完全知情的决定。
大数据中的权力不对称
在获取数据的过程中,单独一个农民的作用可以忽略不计,但所有农民的共同作用是至关重要的。他们创造原始数据,然后由外部公司货币化。理想情况下,农民应该学习并接受使用大数据的培训,然而今天,大多数来自工业化农场的农民只是在孟山都等公司的指导下工作的简单特许经营者。这些农民可能会对他们的伴侣产生依赖,变得更加脆弱。
公司可以接触到每个农民的秘密,例如土地质量、植物生长和作物产量……此外,农民不知道他的信息如何以及在哪里被保存或使用。农业大数据业务的全球领导者 Climate corp 承认农民对数据的所有权,但它并未授予农民任何关于从这些数据中生成的分析和信息的权利。这些公司可用的专业知识和数据量给了他们力量。由于一个农民对这些公司没有太大的影响力,农民们组织起来组成合作社来谈判他们的权利。他们担心第三方(如另一家公司或政府)会在他们不知情和未同意的情况下获取他们的私人信息。
即使农民通过大数据获得了关于他们农场的新见解,如果数据落入坏人之手,他们也会面临生存威胁。例如,产量数据可用于在商品金融市场上投机股票,这可能会减少收入并威胁农民的生计。
未来需要的不仅仅是数据
农业领域的大数据有可能彻底重构经济。越来越多的人意识到全球环境问题,许多人想解决它。消费习惯已经发生了变化。人们想要一种健康的、公平的、可持续生产的食品。有了用智能手机扫描二维码并了解水果生长方式的可能性,消费者将能够购买环保产品并抵制具有高负外部性的公司。尽管如此,这一由大数据推动的进步不应危及农民的生计。即使基于大数据的技术开启了令人兴奋的新机遇,我们也需要小心谨慎。社会科学和伦理必须赶上技术,以创建一个全球性的立法和保护数据提供商免受权力滥用。此外,有必要对农民进行大数据教育,并培训他们安全地利用大数据。
再见鲍勃,注意安全
Bob 创建数据。这些数据有着巨大的潜力。这有可能增加他的收入,养活和拯救世界。为了利用这种潜力,鲍勃需要好的盟友:能给他同等权力的专家——但不剥削他。我们需要回答的问题是:这些盟友在哪里?
偏差-方差和精确-回忆权衡:如何瞄准最佳点?
如何在偏差-方差&精确-召回权衡中找到甜蜜点?理解在此过程中起主要作用的所有重要参数。
权衡是介于理智但无聊的生活和复杂、冒险但冒险的生活之间的一件事。生活中的每一点,甚至每一秒我们都做出某种‘取舍’。冒险与否的权衡总是帮助我们找到最佳平衡点或中间地带。当我们让机器像人类一样思考时,它们也受到“权衡”的困扰。
机器学习通常需要处理两个权衡,
- 偏差-方差权衡
- 精确召回的权衡
第 1 部分:偏差-方差权衡
1.1 首先,什么是偏差,什么是方差?
偏置:
要理解它,就要知道它的大概意思。剑桥词典称,
以不公平的方式支持或反对特定的人或事的行为,因为允许个人观点影响你的判断。
→所以在统计学的世界里,它被定义为,
统计偏差是统计技术或其结果的一个特征,由此结果的期望值不同于被估计的真实的潜在定量参数。
受够了“书生气”的定义,让我们通过与现实世界更相关的类比来理解它。
→用简单的英语来说,“机器学习技术无法捕捉真实关系是偏见”。
- 低偏差:预测数据点接近目标。此外,该模型对目标函数的形式提出了更少的假设。
- 高偏差:预测数据点远离目标。此外,该模型对目标函数的形式提出了更多的假设。
- **低偏机器学习算法的例子:**决策树、k 近邻、支持向量机。
- **高偏差机器学习算法的例子:**线性回归,线性判别分析,逻辑回归。
→因此,理想情况下,我们的主要目标是整体低偏置(但不总是如此)。具有高偏差的模型很少关注训练数据,并且过度简化了模型。它总是导致训练和测试数据的高误差。
1.1.2 差异:
再次要理解它,我们必须知道它的大致意思。剑桥词典称,
两个或多个事物不同的事实,或它们不同的数量或数目。
→所以在统计学的世界里,它被定义为,
在概率论和统计学中,方差是随机变量与其均值的方差平方的期望值。通俗地说,它测量一组(随机)数从它们的平均值分散开多远。
这又是一个“书生气”的定义。因此,让我们通过它在现实世界中的类比来弄清楚这个想法。
→用简单的英语来说,“它是给定数据点或数值的模型预测的可变性,它告诉我们数据的分布”。这里的数据分布就是数据点和平均值之差的平方(即偏差的平方,σ)
- 低方差:数据点相互接近,结果接近函数。此外,该模型建议随着训练数据集的改变而对目标函数的估计进行小的改变。
- 高方差:数据点分散,结果远离函数。建议随着训练数据集的改变而对目标函数的估计进行大的改变。
- **低方差机器学习算法的例子:**线性回归、线性判别分析、逻辑回归。
- **高方差机器学习算法的例子:**决策树、k 近邻、支持向量机。
→因此,理想情况下,我们的总体目标是低偏置。(但并不总是)。高方差模型非常重视训练数据,不会对以前没有见过的数据进行归纳。结果,这样的模型在训练数据上表现得非常好,但是在测试数据上有很高的错误率。
1.2.到目前为止,一切似乎都很好,那么偏差-方差权衡的结果是什么呢?
→要理解这一点,首先我们必须理解误差,因为它们或多或少只与误差有关。不管使用什么算法,都不能减少不可约误差&从问题的选择框架中引入。由影响输入变量到输出变量的映射的未知变量等因素引起。
→因此,为了最小化误差,我们必须最小化偏差和方差。
→任何有监督的机器学习算法的目标都是实现低偏差和低方差。反过来,该算法应该实现良好的预测性能。你可以在上面的例子中看到一个总的趋势:
- 参数或线性机器学习算法通常具有高偏差但低方差。
- 非参数或非线性机器学习算法通常具有低偏差但高方差。
机器学习算法的参数化通常是一场平衡偏差和方差的战斗。
→在机器学习中,偏差和方差之间的关系是不可避免的。
- 增加偏差会减少方差。
- 增加方差将减少偏差。
Bias-Variance Trade-off as a Function of Model Capacity
→ 从上图我们可以解读如下:
I .高偏差和低方差使数据欠拟合,因为它错过了许多假设。此外,点数与预期预测值有偏差。
二。低偏差和高方差过度拟合数据,因为模型过于关注训练数据,不能很好地概括。
三。当两者都找到中间点或最佳点时,误差最小。
左上是我们的目标。
二。左下具有高偏差,因此它们远离目标,但由于低方差而彼此接近。
三。右上点由于高方差而展开,但是由于低偏差而接近目标。
四。右下方离目标很远,而且点数本身也是因为高方差和高偏差。
→为了建立一个好的模型,我们需要在偏差和方差之间找到一个好的平衡,这样可以使总误差最小化。偏差和方差的最佳平衡不会使模型过拟合或欠拟合。这是通过在反复试验的基础上进行超参数调整来实现的
第 2 部分:精确召回权衡
2.1.首先,什么是精确,什么是回忆,或者其他术语?
它们是分类问题的性能矩阵。我认为分类的每一个概念都可以用一个例子来解释。
**例子:**假设你正在考虑给可能会再次光顾的顾客额外赠送一块方糖。但是你当然想避免不必要的分发方糖,所以你只把方糖给那些模型显示至少有 30%可能会再次光顾的顾客。
Confusion Matrix
- TP:被模型分类为的将返回,而实际上已经返回了
- FP:被模型归类为将返回,但实际上没有返回 (类型 1 错误或告警)
- TN:被模型归类为不会返回,实际上并没有返回
- FN:被模型归类为不会返回,但实际上已经返回。(类型 2 错误或遗漏)
(注:我是假设读者了解‘混淆矩阵’,如果不了解,请先过一遍。)
Venn Dig for Precision & Recall
2.1.1 精度:
检索到的实例中相关实例的比例。
→计算如下:TP / (TP + FP)
→从上面的例子,我们可以解读为,“被归类为会回归的,实际做了的比例是多少?”
→因此,精度表示我们的模型所说的相关数据点的比例实际上是相关的。
2.1.2 召回(又称灵敏度):
已检索的相关实例占相关实例总数的比例。
→计算如下:TP /( TP + FN)
→从上面的例子中,我们可以将它解释为,“在那些实际返回的人中,有多少比例是这样分类的?”
→一般来说,灵敏度告诉我们**目标 被正确识别的百分比。也称为“真阳性率”,可互换使用。在正确识别阳性的基础上选择模型时很有用,在这种情况下,就是给额外的方糖。
→因此,回忆表示在数据集中找到所有相关实例的能力
在继续之前,我们应该了解一些其他有用的术语。
2.1.3 特异性(又称假阴性率):
**→ 被正确识别的 阴性靶 的百分比。在正确识别负面因素的基础上选择模型时很有用,在这种情况下,不会给出额外的方糖。
→计算为:TN/(TN + FP)
2 . 1 . 4 F1-分数:
→精确度和召回率的最佳结合我们可以使用所谓的 F1 分数来组合这两个指标。
→F1 分数是精确度和召回率的调和平均值,在以下等式中考虑了这两个指标:
→我们使用调和平均值而不是简单平均值,因为它会惩罚极值。精度为 1.0、召回率为 0.0 的分类器的简单平均值为 0.5,但 f 1 值为 0。
2.2 回到最初的问题,精确召回权衡还是精确 vs 召回?
→在任何一个模型中,您也可以决定强调精确度或召回率。也许你很缺方糖,所以你只想把方糖给那些你很有信心会再次光顾的人,所以你决定只把方糖给那些有 60%可能会再次光顾的顾客(而不是 30%)。
我们的精确度会提高,因为只有当你确信有人会回来的时候,你才会分发方糖。我们的召回率将会下降,因为将会有很多人最终会退回那些你没有足够信心给他们一块方糖的人。
精度:62% → 80%
召回:60% → 30%
→或者,如果你觉得方糖很丰富,你可以把它们分发给任何一个至少有 10%机会再次购买的人。
精确度:62% → 40%
召回率:60% → 90%
您可以使用此图表来跟踪精确度和召回率之间的权衡:
→更好的模型具有更高的精度和召回值。
- 你可以想象一个模型有 94%的准确率(几乎所有被标识为的都将返回 do 事实上)和 97%的召回率(几乎所有返回的都被标识为这样)。
- 一个较弱的模型可能有 95%的精度,但 50%的召回率(当它识别某人为将返回,这在很大程度上是正确的,但它错误地标记为不会返回,而事实上是那些后来返回的人中的一半返回)。
- 或者这个模型有 60%的准确率和 60%的召回率
这些数字会让你对你的模型有多精确有一个很好的感觉,即使你实际上从来不想做任何预测。
包装完毕:
就像现实世界中的权衡决策是基于当前环境做出的一样,这两种权衡也是如此。一天结束时,我们所要做的就是根据我们的需求做出判断。
交易策略:用 Backtrader 进行回溯测试
Photo by Chris Liverani on Unsplash
(我的博客里也有这个帖子)
在我的一篇旧文章中,我演示了如何计算技术指标,这些指标可以逻辑地结合起来建立交易策略。正如帖子中所强调的,在将策略应用于实际市场之前,应该先验证策略在回溯测试中的表现。
回溯测试是将交易策略或分析方法应用于历史数据的过程,以查看该策略或方法预测实际结果的准确性。
-摘自投资答案
回溯测试就像机器学习中的交叉验证。但也不完全一样。回溯测试需要像交叉验证一样将数据分成两部分。一套用于训练,另一套用于验证。不同的是,训练测试分割可以随机进行交叉验证。在交易回溯测试中,你的数据是时间序列。您的训练数据必须比您的测试数据旧。否则你会偷窥未来,导致对你的策略的不正确衡量。因此,在回溯测试中,数据集的分割不能是随机的。回溯测试涉及真实世界中的市场模拟。实现自己的回溯测试库可能很难,而且容易出错。幸运的是,还有反向交易者。
Backtrader 是一个非常棒的开源 python 框架,它可以让你专注于编写可重用的交易策略、指标和分析工具,而不是花时间构建基础设施。它还支持回溯测试,让你评估自己想出的策略!
也就是说,这是一个免费的完整的技术人员建立自己的策略的解决方案。让我们开始浏览一下。
安装和设置
pip install backtrader[plotting]
制定战略
Backtrader 为您定义了一个策略界面。您需要创建一个实现此接口的类。一个重要的方法是 next(),你应该根据某一天的技术指标来决定是买进、卖出还是什么都不做。一个简单的策略是这样的。
**import** backtrader **as** bt **class** **MyStrategy**(bt.Strategy):
**def** __init__(self):
self.sma = bt.indicators.SimpleMovingAverage(period=15)
**def** next(self):
**if** self.sma > self.data.close:
*# Do something*
**pass**
**elif** self.sma < self.data.close:
*# Do something else*
**pass**
如你所见,backtrader 附带了一套通用的技术指标。意味着你不需要在你自己或 TA lib 上回复来计算技术指标。
Backtrader 还提供模拟市场交易的功能。Once 可以在您的交易操作中根据美元或百分比计算佣金。
cerebro.broker.setcommission(commission=0.001)
下面是用脸书历史市场数据进行回溯测试的完整示例。注意,历史交易数据是从雅虎财经下载的。它还支持熊猫数据帧。我有一个关于收集熊猫交易数据的帖子。这个例子由一个简单的 TestStrategy 和一段启动回溯测试的驱动代码组成。简单策略只考虑买入/卖出信号的 RSI。你应该为你选择的股票添加更多的逻辑。
**from** __future__ **import** (absolute_import, division, print_function,
unicode_literals)
**import** datetime
**import** os.path
**import** sys
**import** backtrader **as** bt
**class** TestStrategy(bt.Strategy):
**def** log(self, txt, dt=**None**):
dt = dt **or** self.datas[0].datetime.date(0)
print(**'%s, %s'** % (dt.isoformat(), txt))
**def** __init__(self):
self.dataclose = self.datas[0].close
self.order = **None** self.buyprice = **None** self.buycomm = **None** self.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=15)
self.rsi = bt.indicators.RelativeStrengthIndex()
**def** notify_order(self, order):
**if** order.status **in** [order.Submitted, order.Accepted]:
**return
if** order.status **in** [order.Completed]:
**if** order.isbuy():
self.log(
**'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f'** %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
**else**: *# Sell* self.log(**'SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f'** %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
**elif** order.status **in** [order.Canceled, order.Margin, order.Rejected]:
self.log(**'Order Canceled/Margin/Rejected'**)
*# Write down: no pending order* self.order = **None
def** notify_trade(self, trade):
**if not** trade.isclosed:
**return** self.log(**'OPERATION PROFIT, GROSS %.2f, NET %.2f'** %
(trade.pnl, trade.pnlcomm))
**def** next(self):
self.log(**'Close, %.2f'** % self.dataclose[0])
print(**'rsi:'**, self.rsi[0])
**if** self.order:
**return
if not** self.position:
**if** (self.rsi[0] < 30):
self.log(**'BUY CREATE, %.2f'** % self.dataclose[0])
self.order = self.buy(size=500)
**else**:
**if** (self.rsi[0] > 70):
self.log(**'SELL CREATE, %.2f'** % self.dataclose[0])
self.order = self.sell(size=500)
**if** __name__ == **'__main__'**:
cerebro = bt.Cerebro()
cerebro.addstrategy(TestStrategy)
cerebro.broker.setcommission(commission=0.001)
datapath = **'FB.csv'** *# Create a Data Feed* data = bt.feeds.YahooFinanceCSVData(
dataname=datapath,
fromdate=datetime.datetime(2013, 1, 1),
todate=datetime.datetime(2018, 8, 5),
reverse=**True**)
cerebro.adddata(data)
cerebro.broker.setcash(100000.0)
print(**'Starting Portfolio Value: %.2f'** % cerebro.broker.getvalue())
cerebro.run()
print(**'Final Portfolio Value: %.2f'** % cerebro.broker.getvalue())
cerebro.plot()
在执行结束时,你可以找出你的投资组合的最终价值。此外,你还可以根据时间绘制股票价格、技术指标、你的买入/卖出操作和你的投资组合价值。
正如你所看到的,这个简单的策略对 FB 很有效,因为它抓住了一些买卖机会。
这就是 backtrader 的回溯测试。如果你想深入了解,我建议你访问 backtrader 的文档了解更多高级用法。如果你想了解更多关于机器学习的知识,在 educative.io 网站上有一系列有用的课程。这些课程包括像基本的 ML,NLP,图像识别等主题。编码和交易快乐!
推荐阅读:
用于数据分析的 Python:与 Pandas、NumPy 和 IPython 的数据争论
我的帖子:
从 CRUD web 应用开发到语音助手中的 SDE——我正在进行的机器学习之旅
全栈开发教程:将 AWS Lambda 无服务器服务集成到 Angular SPA 中
全栈开发教程:用运行在 AWS Lambda 上的无服务器 REST API 提供交易数据
交易策略:用 Python TA-Lib 进行技术分析
Photo by Vladimir Solomyani on Unsplash
(我的博客里也有这个帖子)
在金融领域,交易策略是一个固定的计划,旨在通过在市场上做多或做空来实现盈利回报。正确研究交易策略的主要原因是它的可验证性、可量化性、一致性和客观性。
对于每一个交易策略,你都需要定义交易的资产、进场/出场点和资金管理规则。糟糕的资金管理会让潜在的盈利策略变得无利可图。
—来自维基百科
策略分为基于基本面分析和基于技术分析。基本面分析关注公司的资产、收益、市场、股息等,而技术分析只关注股价和成交量。技术分析广泛使用技术指标,这些指标是根据价格和交易量计算出来的,用来洞察交易行为。技术指标进一步分类为波动性、动量、趋势、成交量等。有选择地组合一只股票的指标可能会产生很好的盈利策略。一旦建立了策略,人们应该用模拟器回测该策略,以在实时交易前测量性能(回报和风险)。我有另一个帖子涉及反向交易者的反向测试。
由于技术指标在构建策略中起着重要的作用,我将演示如何使用 TA-Lib 来计算技术指标并构建一个简单的策略。(请不要直接使用策略进行实时交易,因为需要进行回溯测试)。如果你想自己算指标,参考我上一篇在熊猫里怎么做。
在这篇文章中,我将用 RSI (一个动量指标)和布林线 %b(一个波动指标)构建一个策略。高 RSI(通常高于 70)可能表明股票超买,因此这是卖出信号。低 RSI(通常低于 30)表明股票超卖,这意味着买入信号。布林线告诉我们两个波段之间的大部分价格行为。因此,如果%b 高于 1,价格可能会回落到区间内。因此,这是一个卖出信号。而如果低于 0,则认为是买入信号。这个策略是一个简单的投票机制。当两个指标认为是买入的时候了,它就发出买入指令进场。当两个指标都认为是时候卖出时,它就发出卖出指令退出。
在 Mac 上安装 TA-Lib 和其他依赖项
python3 -m venv tutorial-env
source ~/tutorial-env/bin/activate
pip install panda
pip install pandas_datareader
pip install matplotlib
pip install scipy
pip install cython
brew install ta-lib
pip install TA-lib
计算布林线或 RSI
**import** pandas_datareader.data **as** web
**import** pandas **as** pd
**import** numpy **as** np
**from** talib **import** RSI, BBANDS
**import** matplotlib.pyplot **as** pltstart = **'2015-04-22'** end = **'2017-04-22'** symbol = **'MCD'** max_holding = 100
price = web.DataReader(name=symbol, data_source=**'quandl'**, start=start, end=end)
price = price.iloc[::-1]
price = price.dropna()
close = price[**'AdjClose'**].values
up, mid, low = BBANDS(close, timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)
rsi = RSI(close, timeperiod=14)
print(**"RSI (first 10 elements)\n"**, rsi[14:24])
输出
RSI (first 10 elements)
[50.45417011 47.89845022 49.54971141 51.0802541 50.97931103 61.79355957
58.80010324 54.64867736 53.23445848 50.65447261]
将布林线转换为%b
**def** bbp(price):
up, mid, low = BBANDS(close, timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)
bbp = (price[**'AdjClose'**] - low) / (up - low)
**return** bbp
根据指标计算持仓量
holdings = pd.DataFrame(index=price.index, data={**'Holdings'**: np.array([np.nan] * index.shape[0])})
holdings.loc[((price[**'RSI'**] < 30) & (price[**'BBP'**] < 0)), **'Holdings'**] = max_holding
holdings.loc[((price[**'RSI'**] > 70) & (price[**'BBP'**] > 1)), **'Holdings'**] = 0holdings.ffill(inplace=**True**)
holdings.fillna(0, inplace=**True**)
此外,我们应该得到基于持有量的交易行为
holdings[**'Order'**] = holdings.diff()
holdings.dropna(inplace=**True**)
让我们想象一下我们的行动和指标
fig, (ax0, ax1, ax2) = plt.subplots(3, 1, sharex=**True**, figsize=(12, 8))
ax0.plot(index, price[**'AdjClose'**], label=**'AdjClose'**)
ax0.set_xlabel(**'Date'**)
ax0.set_ylabel(**'AdjClose'**)
ax0.grid()
**for** day, holding **in** holdings.iterrows():
order = holding[**'Order'**]
**if** order > 0:
ax0.scatter(x=day, y=price.loc[day, **'AdjClose'**], color=**'green'**)
**elif** order < 0:
ax0.scatter(x=day, y=price.loc[day, **'AdjClose'**], color=**'red'**)
ax1.plot(index, price[**'RSI'**], label=**'RSI'**)
ax1.fill_between(index, y1=30, y2=70, color=**'#adccff'**, alpha=**'0.3'**)
ax1.set_xlabel(**'Date'**)
ax1.set_ylabel(**'RSI'**)
ax1.grid()
ax2.plot(index, price[**'BB_up'**], label=**'BB_up'**)
ax2.plot(index, price[**'AdjClose'**], label=**'AdjClose'**)
ax2.plot(index, price[**'BB_low'**], label=**'BB_low'**)
ax2.fill_between(index, y1=price[**'BB_low'**], y2=price[**'BB_up'**], color=**'#adccff'**, alpha=**'0.3'**)
ax2.set_xlabel(**'Date'**)
ax2.set_ylabel(**'Bollinger Bands'**)
ax2.grid()
fig.tight_layout()
plt.show()
下面,我用调整后的麦当劳收盘价(2015 年 4 月至 2017 年 4 月)用绿点(进场点)和红点(出场点)标出了行动。除此之外,RSI 指标和布林线也显示了这两个指标是如何影响交易的。从图中可以看出这个策略是好的。它捕捉了一对夫妇在此期间相对的一些低价和高价。应该进行回溯测试,以了解该策略与基准测试相比表现如何。
结果在图表中
这个帖子到此为止。如果你想了解更多关于机器学习的知识,educative.io 网站上有一系列课程很有帮助。这些课程包括像基本的 ML,NLP,图像识别等主题。投资和编码快乐!
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
推荐阅读:
用于数据分析的 Python:与 Pandas、NumPy 和 IPython 的数据角力
我的帖子:
从 CRUD web 应用开发到语音助手中的 SDE——我正在进行的机器学习之旅
全栈开发教程:将 AWS Lambda 无服务器服务集成到 Angular SPA 中
全栈开发教程:用运行在 AWS Lambda 上的无服务器 REST API 提供交易数据
全栈开发教程:在 Angular SPA 上可视化交易数据(1)
交易:用熊猫计算技术分析指标🐼
(我的博客里也有这个帖子)
在金融学中, 技术分析 是通过研究过去的市场数据,主要是价格和成交量来预测价格走向的分析方法论。技术分析师依靠技术指标的组合来研究股票,并给出交易策略的见解。常用的技术指标有 SMA 和布林线等。这是一份技术指标的清单。
在之前的一个故事中,我讲过如何用熊猫收集这样的信息。在这个故事中,我将演示如何计算布林线,并用它来提供潜在的买入/卖出信号。
布林线
布林线用于定义市场中的最高价和最低价,以表征金融工具或商品的交易区间。布林线是一个波动指标。波段是由移动平均线(MA)组成的,有上波段和下波段。上下波段只是 MA 加和减标准差。标准差是波动性的度量。这就是为什么它是一个波动指标。
Upper Band = (MA + *Kσ*)Lower Band = (MA − *Kσ*)
MA 是典型的 20 天移动平均线,K 是 2。我将在这个例子中使用它们。
example of Bollinger Bands
先决条件环境设置(遵循此帖子中的步骤 1)
数据:
在本例中,我们将使用从之前的帖子中收集的 csv 文件(AMZN.csv)
代码:
**import** pandas **as** pd
**import** matplotlib.pyplot **as** plt
symbol=**'AMZN'** *# read csv file, use date as index and read close as a column* df = pd.read_csv(**'~/workspace/{}.csv'**.format(symbol), index_col=**'date'**,
parse_dates=**True**, usecols=[**'date'**, **'close'**],
na_values=**'nan'**)
*# rename the column header with symbol name* df = df.rename(columns={**'close'**: symbol})
df.dropna(inplace=**True**)
*# calculate Simple Moving Average with 20 days window* sma = df.rolling(window=20).mean()
*# calculate the standar deviation* rstd = df.rolling(window=20).std()
upper_band = sma + 2 * rstd
upper_band = upper_band.rename(columns={symbol: **'upper'**})
lower_band = sma - 2 * rstd
lower_band = lower_band.rename(columns={symbol: **'lower'**})
df = df.join(upper_band).join(lower_band)
ax = df.plot(title=**'{} Price and BB'**.format(symbol))
ax.fill_between(df.index, lower_band[**'lower'**], upper_band[**'upper'**], color=**'#ADCCFF'**, alpha=**'0.4'**)
ax.set_xlabel(**'date'**)
ax.set_ylabel(**'SMA and BB'**)
ax.grid()
plt.show()
输出
Amazon price and its Bollinger Bands
买入/卖出信号的解释
大约 90%的价格波动在两个波段之间。因此,波段可以用来识别潜在的超买或超卖情况。如果股价突破了上限,这可能是一个超买状态(做空的迹象)。同样,当它突破低波段时,可能是超卖状态(多头的迹象)。但是布林线不是一个独立的系统,总是给出准确的买入/卖出信号。应该考虑频带的整体趋势来识别信号。否则,只有布林线,一个人可以不断地做出错误的订单。在上面的亚马逊例子中,趋势是上升的。因此,只有在低频带被标记时,才应该做多。更多信息可以在这里找到。
这就是计算技术指标的简单方法🐼!
如果你想了解更多关于机器学习的知识,educative.io 网站上有一系列课程很有帮助。这些课程包括像基本的 ML,NLP,图像识别等主题。
推荐阅读:
用于数据分析的 Python:与 Pandas、NumPy 和 IPython 的数据争论
我的帖子:
从 CRUD web 应用开发到语音助手中的 SDE——我正在进行的机器学习之旅
全栈开发教程:将 AWS Lambda 无服务器服务集成到 Angular SPA 中
全栈开发教程:用运行在 AWS Lambda 上的无服务器 REST API 提供交易数据
全栈开发教程:在 Angular SPA 上可视化交易数据(1)
像人类一样准确地阅读交通标志
用数据做酷事
自动驾驶汽车将不得不实时解读我们道路上的所有交通标志,并在驾驶中考虑这些因素。在这篇博客中,我们使用深度学习来训练汽车以 93%的准确率对交通标志进行分类。
我已经用 Python 分享了我的 GitHub 的链接和全部代码。
Traffic Signs!
数据集
这个练习使用的数据集(可以从这里下载)由德国道路上看到的 43 个不同的交通标志组成。交通标志图像是从实际道路图像中裁剪出来的,因此处于不同的光照条件下,如下所示。
Cropping stop sign from actual road images
它总共有 5 万张图片。图像为 32x32 像素,并且是彩色的。
理解数据
任何建模练习的第一步都应该是熟悉所涉及的数据。这里有 43 个不同的交通标志。如下图所示,数据分布不均匀。一些标志只有 200 张图片,而另一些有超过 1200 张图片。
如下图所示,可视化数据集中的图像,我们可以看到图像很小,具有不同的亮度,有些图像很模糊。此外,交通标志并不总是在图像的中心。
Traffic Sign images from the dataset
数据预处理
在将图像输入神经网络之前,我对图像进行了归一化处理,使像素值介于 0 和 0.5 之间。我这样做是通过将所有像素值除以 255。这样做是因为当原始数据在 0 和 1 之间时,神经网络表现得更好。我决定使用彩色交通标志,而不是将其转换为灰色,因为人类使用标志的颜色进行分类,所以机器也可以受益于这些额外的信息。最后,我将数据集分为训练集、验证集和测试集。测试集是模型永远看不到的 30%的样本。
模型架构
对于这个项目,我决定使用 LeNet 架构,这是一个简单的卷积神经网络(CNN),在 MNIST 数据集上表现良好。如下所示,该模型有两个卷积层,后跟两个最大池层。第一个卷积层使用 5x5 的面片大小和深度为 6 的过滤器。第二个卷积层也使用 5x5 的面片大小,但深度为 16 的过滤器。在卷积之后,我们展平输出,然后使用两个完全连接的层。第一个有 120 个神经元,第二个有 84 个神经元。在所有层之间使用 RELU 激活。最后,我们有一个输出层,它使用 Softmax 将图像分为 43 类。
LeNet Architecture
LeNet 架构在这个问题上表现得非常好,在 30 个时期内,我们在验证样本上获得了 98%以上的准确率。请参见下面的准确度和损失图:
Model training using LeNet Architecture
从未接触过该模型的测试样本的准确度约为 93%,这是相当可靠的。
如果我们使用图像增强——亮度、旋转、平移等方面的变化,精确度可以进一步提高。增加样本量。
可视化神经网络
虽然神经网络可以是一个很好的学习设备,但它们通常被称为黑盒。我们可以通过绘制其特征图来了解神经网络正在学习什么——这是过滤器的输出。从这些绘制的特征地图中,可以看出网络对图像的哪些特征感兴趣。对于标志,内部网络要素地图可能会对标志的边界轮廓或标志的着色符号中的对比度做出高度激活的反应。
查看这个链接,了解更多关于可视化神经网络的信息。
让我们看看第一个卷积层的 6 个不同的过滤器如何响应“请勿进入”的标志。这里亮点反映了神经元被激活的地方。可以看出,网络集中在圆形标志和中间的扁平线上。
Do Not Enter Sign
Feature map — Do Not Enter Sign
相比之下,我们从没有交通标志的天空图像来看特征图。大多数过滤器是黑色的,这意味着神经网络无法识别该图像中的任何明显特征。
这不是超级有趣吗!
其他著述:https://medium.com/@priya.dwivedi/
PS:我住在多伦多,我希望将职业生涯转向深度学习。如果你喜欢我的帖子,并能把我联系到任何人,我将不胜感激:)。我的电子邮件是 priya.toronto3@gmail.com
参考文献:
Udacity 无人驾驶汽车 Nano Degree——感谢 Udacity 和巴斯蒂安·特龙给我机会成为他们新的无人驾驶汽车项目的一部分。这是一次非常有趣的旅程。我使用的大部分代码都是在课堂讲课中建议的。这里的图片和视频参考也在讲座中分享
德国交通标志数据集:http://benchmark.ini.rub.de/?section=gtsrb&分部=数据集
训练人工智能在你的浏览器中玩蛇
最近,我写了一篇文章,讲述了我设计能够自己学习玩贪吃蛇游戏的人工智能的过程。人工智能的设计过程很复杂。许多早期的小决定会导致完全不同的结果。现在,经过一点清理后,任何人都可以在他们的浏览器中调整、调整和发展他们自己的蛇形人工智能。
[## 设计人工智能:用进化解决蛇
在你的浏览器中训练、调整和调整人工智能。
pbingeser . github . io](https://pbinggeser.github.io/snake-ai/)
可调参数
群体规模— 每一代要创建的神经网络的数量
精英百分比— 用于培育下一代的优秀员工的百分比
美食积分— 因食用美食而获得的积分
迈向美食得分— 迈向美食的每一步所获得的分数
远离食物得分— 远离食物每一步的得分
蛇的起始长度— 每条蛇的初始长度,在网格单元中测量
网格分辨率— 组成蛇的环境的网格单元的宽度(和高度)的数量
显示尺寸— 每个贪吃蛇游戏占多少像素宽*(不影响游戏)*
游戏性切换
- 蛇撞墙就死了。
- 蛇打自己就死了。
- 蛇吃东西的时候会变长。
耐心点。有时,有利的随机突变发生得很快,有时这些突变证明最好谨慎行事,有时它们似乎永远不会发生…
🐍
用 5 行代码训练图像识别人工智能
在本文中,我们将简要介绍人工智能领域,特别是计算机视觉领域,所涉及的挑战,现有的应对这些挑战的现代解决方案,以及如何方便、轻松地应用这些解决方案,而无需花费太多时间和精力。
几十年来,人工智能一直是一个研究领域,科学家和工程师们都在努力解开让机器和计算机感知和理解我们的世界,从而采取适当行动为人类服务的谜团。这项研究工作最重要的一个方面是让计算机理解我们周围每天产生的视觉信息**(图像和视频)**。这个让计算机感知和理解视觉信息的领域被称为计算机视觉。
在 20 世纪 50 年代到 80 年代人工智能研究的兴起期间,计算机被人工告知如何识别图像、图像中的物体以及需要注意哪些特征。这种方法是传统的算法,被称为专家系统,因为它们需要人类费力地为每个必须识别的物体的独特场景识别特征,并以计算机可以理解的数学模型来表示这些特征。这涉及到大量繁琐的工作,因为有成千上万种不同的方法可以表示一个对象,并且有成千上万(甚至数百万)不同的场景和对象是唯一存在的,因此找到优化和精确的数学模型来表示每个对象或场景的所有可能的特征,并且对于所有可能的对象或场景,更多的工作将永远持续下去。****
然后,在 1990 年代,引入了机器学习的概念,它开创了一个时代,不再告诉计算机在识别图像和视频中的场景和对象时要注意什么,而是我们可以设计算法,让计算机学习如何自己识别图像中的场景和对象,就像孩子通过探索学习理解他/她的环境一样。机器学习为计算机学习识别我们想要的几乎任何场景或物体开辟了道路。
随着功能强大的计算机的出现,如 NVIDIA GPU 和最先进的图像识别深度学习算法,如 Alex Krizhevsky 等人在 2012 年推出的 T4 Alex net、Kaeming He 等人在 2015 年推出的 ResNet、Forrest Landola 等人在 2016 年推出的 SqueezeNet 和 DenseNet 可以将许多图片(更像计算机的图画书)放在一起,并定义一个人工智能模型来自己学习这些图片中的场景和对象的特征,并使用从学习过程中获得的知识来识别它之后将遇到的该类型场景或对象的所有其他实例。
要训练一个人工智能模型,让它能够识别你希望它在图片中识别的任何东西,传统上需要大量应用数学方面的专业知识和深度学习库的使用,更不用说你必须经历的时间和压力来编写算法代码并使代码适合你的图像。这是我们提供解决方案的地方。
我们在AI Commons的团队开发了一个 python 库,可以让你训练一个人工智能模型,它可以识别你希望它在图像中识别的任何对象,只需使用5 行简单的 python 代码。python 库是ImageAI,这个库旨在让学生、开发人员和具有各种专业知识水平的研究人员使用 5 到 15 行简单代码来构建具有最先进的计算机视觉功能的系统和应用程序。现在,让我们带你创建你的第一个人工智能模型,它可以识别你想要它识别的任何东西。****
为了训练你的人工智能模型,你需要一个名为数据集的图像集合。**一个数据集包含成百上千个你希望你的人工智能模型识别的对象的样本图像。**但是你不用担心!我们不是要求你现在就去下载成千上万的图片,只是为了训练你的人工智能模型。对于本教程,我们提供了一个名为 IdenProf 的数据集。identified prof(可识别的专业人士)是一个数据集,包含 10 种不同专业人士的 11,000 张照片,人类可以通过他们的穿着模式来查看和识别他们的工作。照片在该数据集中的专业人员类别如下:
厨师
医生
工程师
农民
消防员
法官
机械师
先导
警察
服务员
**这个数据集被分割成 9000 (每个职业 900 张)张图片来训练人工智能模型,以及 2000 (每个职业 200 张)张图片来测试人工智能模型在训练时的性能。IdenProf 已经被妥善安排,准备好训练你的人工智能模型,通过穿着方式识别专业人士。作为参考,如果您使用自己的图像数据集,您必须为您希望人工智能模型识别的每个对象或场景收集至少 500 张图片。要使用 **ImageAI、训练您自己收集的任何图像数据集,您必须将图像排列在文件夹中,如下例所示:
**idenprof//train//chef// 900 images of chefs****idenprof//train//doctor// 900 images of doctors****idenprof//train//engineer// 900 images of engineer****idenprof//train//farmer// 900 images of farmers****idenprof//train//firefighter// 900 images of firefighters****idenprof//train//judge// 900 images of judges****idenprof//train//mechanic// 900 images of mechanics****idenprof//train//pilot// 900 images of pilots****idenprof//train//chef// 900 images of chef****idenprof//train//police// 900 images of police****idenprof//train//waiter// 900 images of waiters****idenprof//test//chef// 200 images of chefs****idenprof//test//doctor// 200 images of doctors****idenprof//test//engineer// 200 images of engineer****idenprof//test//farmer// 200 images of farmers****idenprof//test//firefighter// 200 images of firefighters****idenprof//test//judge// 200 images of judges****idenprof//test//mechanic// 200 images of mechanics****idenprof//test//pilot// 200 images of pilots****idenprof//test//chef// 200 images of chef****idenprof//test//police// 200 images of police****idenprof//test//waiter// 200 images of waiters**
现在,您已经了解了如何准备自己的图像数据集来训练人工智能模型,我们现在将继续指导您使用 ImageAI 训练人工智能模型来识别专业人员。
首先你必须通过这个链接下载 IdenProf 数据集的 zip 文件。你也可以在 IdenProf GitHub 知识库中查看人工智能模型的所有细节和样本结果,这些人工智能模型经过训练可以识别职业,其链接如下。
https://github.com/OlafenwaMoses/IdenProf
因为训练人工智能模型需要高性能的计算机系统,我强烈建议你确保你要用于这次训练的电脑/笔记本电脑有英伟达 GPU。或者,你可以使用谷歌 Colab** 进行这个实验,它提供了一个免费的 NVIDIA K80 GPU 用于实验。**
然后你必须安装 ImageAI 及其依赖项。
安装 Python 3.7.6 和 pip
(如果您已经安装了 Python 3.7.6,请跳过本节)
发布日期:2019 年 12 月 18 日现在 Python 3.7 有了更新的 bugfix 版本,取代了 3.7.6,Python 3.8 是…
www.python.org](https://www.python.org/downloads/release/python-376/)
安装 ImageAI 和依赖关系
(如果您已经安装了库,请跳过本节中的任何安装说明)
-张量流
pip install tensorflow==2.4.0
-其他
pip install keras==2.4.3 numpy==1.19.3 pillow==7.0.0 scipy==1.4.1 h5py==2.10.0 matplotlib==3.3.2 opencv-python keras-resnet==0.2.0
安装 ImageAI 库
pip install imageai --upgrade
创建一个 python 文件,使用您想要的任何名称,例如 “FirstTraining.py” 。
将 IdenProf 数据集的 zip 文件复制到 Python 文件所在的文件夹中。然后解压到同一个文件夹。
然后将下面的代码复制到 python 文件中(例如 FirstTraining.py )。
就是这样!这就是你训练人工智能模型所需的全部代码。在您运行代码开始培训之前,让我们解释一下代码。
在第一行,我们导入了 ImageAI 的模型培训班。在第二行中,我们创建了模型训练类的一个实例。在第三行中,我们将模型类型设置为 ResNet50 (有四种模型类型可用,分别是 MobileNetv2 、 ResNet50 、 InceptionV3 和 DenseNet121 )。在第四行,我们将数据目录(数据集目录)设置为您解压缩的数据集 zip 文件的文件夹。然后在第五行中,我们调用了 trainModel 函数,并指定了以下值:
number _ objects:这是指 IdenProf 数据集中不同类型专业人员的数量。
num _ experiments:这是模型训练者为了达到最大精度而研究 idenprof 数据集中所有图像的次数。
Enhance _ data(可选):这是告诉模型训练员在 IdenProf 数据集中创建图像的修改副本,以确保达到最大的准确性。
**batch _ size:**这是指模型训练器在研究完 IdenProf 数据集中的所有图像之前,一次研究的图像集的数量。
Show _ network _ summary(可选):这是为了显示你正在用来训练人工智能模型的模型类型的结构。
现在,您可以开始运行 Python 文件并开始培训。当培训开始时,您将看到如下结果:
=====================================
Total params: 23,608,202
Trainable params: 23,555,082
Non-trainable params: 53,120
______________________________________
Using Enhanced Data Generation
Found 4000 images belonging to 4 classes.
Found 800 images belonging to 4 classes.
JSON Mapping for the model classes saved to C:\Users\User\PycharmProjects\FirstTraining\idenprof\json\model_class.json
Number of experiments (Epochs) : 200Epoch 1/100
1/280 [>.............................] - ETA: 52s - loss: 2.3026 - acc: 0.25002/280 [>.............................] - ETA: 52s - loss: 2.3026 - acc: 0.25003/280 [>.............................] - ETA: 52s - loss: 2.3026 - acc: 0.2500..............................,
..............................,
..............................,279/280 [===========================>..] - ETA: 1s - loss: 2.3097 - acc: 0.0625Epoch 00000: saving model to C:\Users\User\PycharmProjects\FirstTraining\idenprof\models\model_ex-000_acc-0.100000.h5
280/280 [==============================] - 51s - loss: 2.3095 - acc: 0.0600 - val_loss: 2.3026 - val_acc: 0.1000
让我们解释一下上面显示的细节:
1.语句“保存到 C:\ Users \ User \ PycharmProjects \ first training \ idenprof \ JSON \ model _ class . JSON的模型类的 JSON 映射”意味着模型训练器已经为 iden prof 数据集保存了一个 JSON 文件,您可以使用该文件来识别带有自定义图像预测类的其他图片(进一步阅读时可获得解释)。
2.线 Epoch 1/200 意味着网络正在执行目标 200
3 的第一次训练。线 1/280 [ > ……………………]—ETA:52s—loss:2.3026—ACC:0.2500代表本实验已经训练好的批次数
4。行 Epoch 00000:保存模型到 C:\ Users \ User \ PycharmProjects \ first training \ iden prof \ models \ model _ ex-000 _ ACC-0.100000 . H5是指本次训练后保存的模型。 ex_000 表示本阶段的实验,而ACC0.100000和valACC:0.1000表示本次实验后测试图像上模型的精度(精度的最大值为 1.0)。此结果有助于了解可用于自定义图像预测的最佳执行模型。
一旦你完成了对你的人工智能模型的训练,你就可以使用" CustomImagePrediction "类来执行图像预测,你就是达到最高准确度的模型。
为了防止您由于无法访问 NVIDIA GPU 而无法自己训练人工智能模型,出于本教程的目的,我们提供了一个我们在 IdenProf 数据集上训练的人工智能模型,您现在可以使用它来预测数据集中 10 位专业人士中任何一位的新图像。经过 61 训练实验,该模型达到了超过 79% 的准确率。点击此链接下载模型。此外,如果您自己没有进行培训,也可以通过此链接下载 idenprof 模型的 JSON 文件。然后,你就可以开始使用训练好的人工智能模型识别专业人士了。请按照下面的说明操作。
接下来,创建另一个 Python 文件并给它命名,例如firstcustomimagerecognition . py。复制你在上面下载的人工智能模型或你训练的达到最高准确度的模型,并将其粘贴到你的新 python 文件所在的文件夹中(例如firstcustomimagerecognition . py)。另外,复制您下载的或者由您的训练生成的 JSON 文件,并将其粘贴到与您的新 python 文件相同的文件夹中。将属于 IdenProf 数据集中类别的任何专业人员的样本图像复制到与新 python 文件相同的文件夹中。
然后复制下面的代码,并将其放入新的 python 文件中
查看下面的样本图像和结果。
waiter : 99.99997615814209chef : 1.568847380895022e-05judge : 1.0255866556008186e-05
那很容易!现在让我们解释一下上面产生这个预测结果的代码。
上面的第一行和第二行代码导入了 ImageAI 的CustomImageClassification 类和 python os 类,其中 CustomImageClassification 类用于使用训练好的模型预测和识别图像。第三行代码创建一个变量,该变量保存对包含您的 python 文件(在本例中是您的firstcustomimagerecognition . py)和您自己下载或训练的 ResNet50 模型文件的路径的引用。在上面的代码中,我们在第四行创建了一个CustomImageClassification()类的实例,然后我们通过调用。第五行中的 setModelTypeAsResNet50() 然后我们将预测对象的模型路径设置为我们复制到第六行的项目文件夹文件夹中的人工智能模型文件(iden prof _ 061–0.7933 . H5)的路径。在第七行,我们设置了复制到第七行的文件夹中的 JSON 文件的路径,并在第八十行加载了模型。最后,我们对复制到文件夹中的图像进行预测,并将结果打印到命令行界面。
到目前为止,你已经学会了如何使用 ImageAI 来轻松训练你自己的人工智能模型,它可以预测图像中任何类型的对象或对象集。
如果您想通过链接了解更多有用和实用的资源,请访问下面链接的 图像识别指南 。
现在我们知道了一些关于什么是图像识别,不同类型的图像识别之间的区别…
www.fritz.ai](https://www.fritz.ai/image-recognition/)
你可以在官方 GitHub 知识库上找到使用 ImageAI 训练定制人工智能模型的所有细节和文档,以及包含在 ImageAI 中的其他计算机视觉功能。
这是一个开源 python 库,旨在使开发人员能够使用自包含的深度…
github.com](https://github.com/OlafenwaMoses/ImageAI)
如果你觉得这篇文章很有帮助并且喜欢,请给它一个的掌声。此外,请随意与朋友和同事分享。
你有什么问题、建议或者想要联系我吗?给我发邮件到guymodscientist@gmail.com。我也可以通过账号 @OlafenwaMoses 在 twitter 上联系,通过https://www.facebook.com/moses.olafenwa在脸书联系。**
在 Python 中训练/测试分割和交叉验证
大家好!在我上一篇关于 Python 中的线性回归的文章之后,我认为写一篇关于训练/测试分割和交叉验证的文章是很自然的。像往常一样,我将对这个主题做一个简短的概述,然后给出一个用 Python 实现它的例子。这是数据科学和数据分析中两个相当重要的概念,被用作防止(或至少最小化)过度拟合的工具。我将解释这是什么-当我们使用统计模型(例如线性回归)时,我们通常将模型拟合到训练集,以便对未经训练的数据(一般数据)进行预测。过度拟合意味着我们对模型的拟合过于依赖训练数据。很快就会明白的,我保证!
什么是过度拟合/欠拟合模型?
如上所述,在统计学和机器学习中,我们通常将数据分为两个子集:训练数据和测试数据(有时分为三个子集:训练、验证和测试),并根据训练数据拟合我们的模型,以便对测试数据进行预测。当我们这样做时,可能会发生两种情况之一:我们使模型过拟合或者使模型欠拟合。我们不希望这些事情发生,因为它们会影响我们模型的可预测性——我们可能会使用一个准确性较低和/或不通用的模型(这意味着你不能根据其他数据概括你的预测)。让我们来看看欠拟合和过拟合的实际含义:
过度拟合
过度拟合意味着我们训练的模型已经训练得“太好”,并且现在与训练数据集太接近了。这通常发生在模型过于复杂的时候(例如,与观察值相比,特征/变量太多)。该模型在训练数据上非常准确,但在未训练或新数据上可能非常不准确。这是因为这个模型不是一般化的(或者说不是一般化的),这意味着你可以对结果进行一般化,而不能对其他数据进行任何推断,而这正是你最终想要做的。基本上,当这种情况发生时,模型学习或描述训练数据中的“噪声”,而不是数据中变量之间的实际关系。显然,这种噪声不是任何新数据集的一部分,也不能应用于它。
欠拟合
与过度拟合相反,当模型拟合不足时,意味着模型不适合训练数据,因此错过了数据中的趋势。这也意味着该模型不能推广到新的数据。正如你可能猜到的(或者想出来的!),这通常是一个非常简单的模型(没有足够的预测器/自变量)的结果。例如,当我们用线性模型(如线性回归)拟合非线性数据时,也会发生这种情况。几乎不言而喻,这个模型的预测能力会很差(对训练数据,无法推广到其他数据)。
An example of overfitting, underfitting and a model that’s “just right!”
值得注意的是,适配不足不像适配过度那样普遍。然而,我们希望在数据分析中避免这两个问题。你可能会说,我们正试图找到一个中间地带之间的不足和过度拟合我们的模型。正如您将看到的,训练/测试分割和交叉验证有助于避免过度拟合多于欠拟合。让我们深入了解这两个问题!
训练/测试分割
我之前说过,我们使用的数据通常分为训练数据和测试数据。训练集包含一个已知的输出,模型学习这个数据,以便以后推广到其他数据。我们有测试数据集(或子集)来测试我们的模型对这个子集的预测。
Train/Test Split
让我们看看如何在 Python 中实现这一点。我们将使用 Scikit-Learn 库,特别是 train_test_split 方法来完成这项工作。我们将从导入必要的库开始:
import pandas as pd
from sklearn import datasets, linear_model
from sklearn.model_selection import train_test_split
from matplotlib import pyplot as plt
让我们快速浏览一下我导入的库:
- Pandas —加载数据文件作为 Pandas 数据框并分析数据。如果你想了解更多关于熊猫的信息,请随时查看我的帖子!
- 从 Sklearn 中,我已经导入了数据集模块,因此我可以加载一个样本数据集,以及 linear_model ,因此我可以运行一个线性回归
- 从 **Sklearn,**子库 model_selection ,我已经导入了 train_test_split ,这样我就可以,嗯,拆分到训练集和测试集
- 从 Matplotlib 中,我导入了 pyplot 来绘制数据的图形
好了,都准备好了!让我们加载糖尿病数据集,将其转换为数据框并定义列名:
# Load the Diabetes dataset
columns = “age sex bmi map tc ldl hdl tch ltg glu”.split() # Declare the columns names
diabetes = datasets.load_diabetes() # Call the diabetes dataset from sklearn
df = pd.DataFrame(diabetes.data, columns=columns) # load the dataset as a pandas data frame
y = diabetes.target # define the target variable (dependent variable) as y
现在我们可以使用 train_test_split 函数来进行拆分。函数中的 test_size=0.2 表示应该保留下来进行测试的数据的百分比。一般是 80/20 或者 70/30 左右。
# create training and testing vars
X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.2)
print X_train.shape, y_train.shape
print X_test.shape, y_test.shape(353, 10) (353,)
(89, 10) (89,)
现在,我们将根据训练数据拟合模型:
# fit a model
lm = linear_model.LinearRegression()model = lm.fit(X_train, y_train)
predictions = lm.predict(X_test)
如您所见,我们正在根据训练数据拟合模型,并尝试预测测试数据。让我们看看有哪些预测:
predictions[0:5]
array([ 205.68012533, 64.58785513, 175.12880278, 169.95993301,
128.92035866])
注意:因为我在预测后使用了[0:5],所以它只显示了前五个预测值。删除[0:5]会使它打印出我们的模型创建的所有预测值。
让我们绘制模型:
## The line / model
plt.scatter(y_test, predictions)
plt.xlabel(“True Values”)
plt.ylabel(“Predictions”)
并打印准确度分数:
print “Score:”, model.score(X_test, y_test)Score: 0.485829586737
这就对了。以下是我所做工作的总结:我加载了数据,将其分为训练集和测试集,对训练数据拟合了回归模型,基于这些数据进行了预测,并对测试数据的预测进行了测试。看起来不错,对吧?但是训练/测试分割确实有它的危险——如果我们做的分割不是随机的呢?如果我们数据的一个子集只有某个州的人,有某个收入水平的员工,而没有其他收入水平的,只有女性或只有某个年龄的人,会怎么样?(想象一个由这些文件之一排序的文件)。这将导致过度拟合,即使我们试图避免它!这就是交叉验证的用武之地。
交互效度分析
在前一段中,我提到了训练/测试分割方法中的注意事项。为了避免这种情况,我们可以执行一种叫做的交叉验证。它非常类似于训练/测试分割,但是它适用于更多的子集。也就是说,我们将数据分成 k 个子集,并在其中的 k-1 个子集上进行训练。我们要做的是保留最后一个子集进行测试。我们可以对每个子集都这样做。
Visual Representation of Train/Test Split and Cross Validation. H/t to my DSI instructor, Joseph Nelson!
有很多交叉验证方法,我将介绍其中的两种:第一种是 K 重交叉验证第二种是留一交叉验证 (LOOCV)
k 重交叉验证
在 K 折叠交叉验证中,我们将数据分成 K 个不同的子集(或折叠)。我们使用 k-1 个子集来训练我们的数据,并将最后一个子集(或最后一个折叠)作为测试数据。然后,我们根据每个褶皱对模型进行平均,然后最终确定我们的模型。之后,我们用测试集来测试它。
Visual representation of K-Folds. Again, H/t to Joseph Nelson!
这里有一个来自 K 折叠的 Sklearn 文档的非常简单的例子:
from sklearn.model_selection import KFold # import KFold
X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]]) # create an array
y = np.array([1, 2, 3, 4]) # Create another array
kf = KFold(n_splits=2) # Define the split - into 2 folds
kf.get_n_splits(X) # returns the number of splitting iterations in the cross-validatorprint(kf) KFold(n_splits=2, random_state=None, shuffle=False)
让我们看看结果——褶皱:
for train_index, test_index in kf.split(X):
print(“TRAIN:”, train_index, “TEST:”, test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]('TRAIN:', array([2, 3]), 'TEST:', array([0, 1]))
('TRAIN:', array([0, 1]), 'TEST:', array([2, 3]))
如您所见,该函数将原始数据分割成不同的数据子集。再次,非常简单的例子,但我认为它很好地解释了这个概念。
遗漏一项交叉验证(LOOCV)
这是另一种交叉验证的方法,省去一个交叉验证(顺便说一下,这些方法不是唯一的两种,还有一堆其他的交叉验证的方法。在 Sklearn 网站查看。在这种类型的交叉验证中,折叠(子集)的数量等于我们在数据集中的观察数量。然后,我们对所有这些折叠进行平均,并用平均值构建我们的模型。然后,我们根据最后一次折叠测试模型。因为我们会得到大量的训练集(等于样本数),这种方法计算量很大,应该在小数据集上使用。如果数据集很大,最好使用不同的方法,比如 kfold。
让我们看看 Sklearn 的另一个例子:
**from** **sklearn.model_selection** **import** LeaveOneOut
X = np.array([[1, 2], [3, 4]])
y = np.array([1, 2])
loo = LeaveOneOut()
loo.get_n_splits(X)
**for** train_index, test_index **in** loo.split(X):
print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
print(X_train, X_test, y_train, y_test)
这是输出结果:
('TRAIN:', array([1]), 'TEST:', array([0]))
(array([[3, 4]]), array([[1, 2]]), array([2]), array([1]))
('TRAIN:', array([0]), 'TEST:', array([1]))
(array([[1, 2]]), array([[3, 4]]), array([1]), array([2]))
再次,简单的例子,但我真的认为它有助于理解这个方法的基本概念。
那么,我们应该用什么方法呢?多少折?我们有越多的折叠,我们将减少由于偏差引起的误差,但是增加由于方差引起的误差;显然,计算成本也会上升——折叠次数越多,计算时间就越长,并且需要更多内存。随着折叠次数的减少,我们减少了方差引起的误差,但偏差引起的误差会更大。这也将在计算上更便宜。因此,在大数据集中,通常建议 k=3。在较小的数据集中,正如我之前提到的,最好使用 LOOCV。
让我们看看我之前使用的例子,这次是使用交叉验证。我将使用 cross_val_predict 函数返回测试切片中每个数据点的预测值。
# Necessary imports:
from sklearn.model_selection import cross_val_score, cross_val_predict
from sklearn import metrics
如您所知,之前我已经为糖尿病数据集创建了训练/测试分割,并拟合了一个模型。我们来看看交叉验证后的分数是多少:
# Perform 6-fold cross validation
scores = cross_val_score(model, df, y, cv=6)
print “Cross-validated scores:”, scoresCross-validated scores: [ 0.4554861 0.46138572 0.40094084 0.55220736 0.43942775 0.56923406]
如你所见,最后一次折叠提高了原始模型的分数——从 0.485 提高到 0.569。不是一个惊人的结果,但嘿,我们会采取我们能得到的:)
现在,让我们在执行交叉验证后,绘制新的预测:
# Make cross validated predictions
predictions = cross_val_predict(model, df, y, cv=6)
plt.scatter(y, predictions)
你可以看到它与早期的原始情节有很大的不同。因为我用了 cv=6,所以是原图的 6 倍多。
最后,让我们检查模型的 R 得分(R 是一个“表示从自变量可预测的因变量中方差的比例的数字)”。基本上,我们的模型有多精确):
accuracy = metrics.r2_score(y, predictions)
print “Cross-Predicted Accuracy:”, accuracyCross-Predicted Accuracy: 0.490806583864
这次到此为止!我希望你喜欢这篇文章。一如既往,我欢迎大家就您想阅读的主题提出问题、笔记、评论和请求。下次见!
关于机器学习中训练、验证和测试集
这旨在成为任何需要在训练机器学习模型时了解各种数据集分割之间的差异的人的简短入门。
对于这篇文章,我会引用 Jason Brownlee 的优秀文章中关于同一主题的基本定义,它非常全面,请查看更多细节。
训练数据集
训练数据集:用于拟合模型的数据样本。
我们用来训练模型的实际数据集(神经网络中的权重和偏差)。模型看到并且从该数据中学习。
验证数据集
验证数据集:在调整模型超参数时,用于对模型拟合训练数据集提供无偏评估的数据样本。随着验证数据集的技能融入到模型配置中,评估变得更有偏差。
验证集用于评估给定的模型,但这是为了频繁的评估。作为机器学习工程师,我们使用这些数据来微调模型超参数。因此,模型偶尔会看到该数据,但绝不会从该数据中“学习”。我们使用验证集结果,并更新更高级别的超参数。所以验证集影响模型,但只是间接的。验证集也称为开发集或开发集。这是有意义的,因为该数据集在模型的“开发”阶段有所帮助。
测试数据集
测试数据集:用于提供最终模型在训练数据集上的无偏评估的数据样本。
测试数据集提供了用于评估模型的黄金标准。它仅在模型完全定型后使用(使用定型和验证集)。测试集通常用于评估竞争模型(例如,在许多 Kaggle 竞争中,验证集最初与训练集一起发布,而实际测试集仅在竞争即将结束时发布,测试集上的模型结果决定了获胜者)。很多时候,验证集被用作测试集,但这不是一个好的实践。测试集通常是精心策划的。它包含在现实世界中使用时,模型将面临的各种类别的仔细采样数据。
A visualization of the splits
关于数据集分割比率
既然您已经知道了这些数据集的作用,您可能正在寻找关于如何将数据集划分为训练集、验证集和测试集的建议。
这主要取决于 2 件事。首先是数据中的样本总数,其次是您正在训练的实际模型。
有些模型需要大量数据来进行训练,因此在这种情况下,您应该针对更大的训练集进行优化。具有很少超参数的模型将易于验证和调整,因此您可能会减少验证集的大小,但是如果您的模型具有许多超参数,您也将希望拥有一个大的验证集(尽管您还应该考虑交叉验证)。此外,如果您碰巧有一个没有超参数或者不容易调优的模型,您可能也不需要验证集!
总而言之,就像机器学习中的许多其他事情一样,训练-测试-验证分流比也非常具体地取决于你的用例,随着你训练和建立越来越多的模型,做出判断变得越来越容易。
交叉验证的注意事项:很多时候,人们首先将他们的数据集分成两部分——训练和测试。在此之后,他们将测试集放在一边,并随机选择其训练数据集的 X%作为实际的 训练 集,剩余的(100-X)%作为 验证 集,其中 X 是一个固定的数(比如 80%),然后在这些不同的集上对模型进行迭代训练和验证。有多种方法可以做到这一点,通常称为交叉验证。基本上,您使用训练集来生成训练集和验证集的多个拆分。交叉验证避免了过度拟合,并且变得越来越流行,K-fold 交叉验证是最流行的交叉验证方法。 查看本 出更多。
如果你想进一步讨论这个问题,请在评论中告诉我。和你们许多人一样,我也是一个初学者,但我肯定会尽我所能帮助你们🙂
最初发现于
http://tarangshah . com/blog/2017-12-03/train-validation-and-test-sets/
在人工神经网络上训练你的神经元
C祝贺!你刚刚迈出了成为巫师的第一步。拿杯咖啡坐下。
神经网络像魔法一样工作!使用 ResNet50 用不到 50 行代码就可以实现一个图像识别神经网络,它会以相当高的准确度识别你的猫或狗的图片。这是纯粹的魔法,这在今天成为可能的本质,即使在理解了它是如何工作的之后,对我来说仍然像是魔法。理解深度学习不是知道这不是魔术而是纯粹的统计和代码,而是理解这种魔术是如何工作的。它是知道如何成为一个数据向导。
我打算让这篇文章尽可能地让对神经网络了解很少或没有背景的人容易理解。在揭开它的神秘面纱之后,我们将在 Keras 上训练一个简单的神经网络(没有什么太复杂的。我们暂时不会深入到图像识别或 GANs 中去寻找乐趣。我将提供链接和其他资源,以便更好地直观理解,我强烈建议您在阅读本文时浏览它们。在文章的最后,我会添加我个人用来发展我对任何概念的理解的所有资源,我相信这些资源对于任何在这个领域入门的人来说都是非常棒的。
来回答人们关于深度学习最常见和最受欢迎的问题之一:
我学习深度学习和制作神经网络需要多少时间?是不是涉及很多复杂的数学(微积分和矩阵)?
在深度学习中发展任何重要的技能都需要花费大量的时间。领域很大!当然,你可以凭直觉知道代码在做什么,然后立刻构建一些奇特的项目,但是你真的想这么做吗?至于第二部分,是的,它确实涉及大量的数学尤其是微积分。最初的主题很容易理解,但随着你在该领域的进展,复杂性成了一个切线斜率。我发现很多话题真的很难理解。但是有一次我联系了一个研究生,告诉他我发现数学对我的水平来说有点太复杂了。我得到的建议是我得到过的最好的建议之一:找出你为什么要学习深度学习?如果原因是为了挣钱或者跟风,很容易迷失方向。找到你想做的东西,并为之努力。老实说,这是我听到的最好的事情,我想它一直伴随着我。
拥抱!
神经网络是如何出现的
关于神经网络和深度学习的工作和研究可以追溯到 20 世纪 50 年代,当时研究人员实际上使用了电路来实现一个简单的神经网络。这项研究的潜在灵感是实现我们实际的神经元如何工作,以及是否有可能实现一种可以以类似方式工作的机器。从那以后,关于这个话题的研究越来越多。但直到最近几年,我们才找到在日常生活中实现这些算法的方法,以最大限度地提高效率并降低复杂性。
我们从感知器开始,最终出现了更有用的概念,如支持向量机、反向传播和针对不同应用的不同类型的神经网络。我们已经达到了这样一个阶段,我们可以使用一个预先训练好的模型,只需修改它的末端,使它适用于我们的使用(转移学习),这就像把记忆从一个大脑转移到另一个大脑一样!
因此,我们有了这个完全基于数据的蓬勃发展的产业。
你可以通过以下链接了解更多关于神经网络的历史。它们真的很有趣,知道这些概念是如何产生的总是好的:
Chris Bishop. Source: Wikipedia
“机器学习的基础。。。深度神经网络”
克里斯·毕晓普
神经网络如何工作
理解神经网络的最好方法是用可视化的例子。在这一节的最后,我会提供一些很棒的资源,但重要的是要从文本上理解这个主题,或者为了更好的理解而阅读一遍。
需要记住的一件重要事情是,人工神经网络与我们大脑中的神经网络密切相关。
唯一的区别是,我们大脑的网络能够理解更广泛的领域,而人工神经网络仅限于一个或几个理解领域。你可以认为这是音乐家和音乐播放器之间的区别。一个音乐家可以发明、修改和演奏一种音乐类型等等。音乐播放器可以播放你输入的任何歌曲。它将能够一遍又一遍地播放同样的音乐,没有任何错误。一个音乐家在这里会失败,因为无论他多么努力,在再次演奏同一首曲子时总会有一些不同。也许一个和弦以一种微不足道的不同力量敲击着。但问题是,如果我们把音乐播放器想象成一个神经网络,它能够做音乐家能做的事情。但它仅限于一件事(或一个应用领域)。除了它能做的一件事,它什么也做不了,而且从不失败。
神经网络通常以这种方式工作:
- 你把信息输入到网络的输入端。
- 信息流经网络的边缘和节点。
- 最后,我们只剩下一个最终输出。这个输出不一定是一个数字,而是输出是一个对象的概率,以防我们对某个东西进行分类。因此,在分类的情况下,我们将剩下神经网络来告诉我们输出的概率。这是我们的网络的理解,它认为哪个输出与输入匹配得更好。
Source: https://www.extremetech.com
一个神经网络由 3 种类型的层组成:输入层(我们在其中输入),隐藏层(处理发生的地方)和输出层(我们获得的结果)。你可能想知道为什么我们堆叠神经元的“层”来构建神经网络,以及我们如何确定我们需要的层数或每层中的节点数。这是一个非常简短的主题,没有选择层数和节点数的硬性编码规则。有一些通用的方法,但是层数和节点数决定了你的模型的过拟合和欠拟合。因此,通常我们必须测试和评估我们的模型,以检查哪一个效果最好。说到层的概念,学习是将许多小信息包组合成一个大信息包的过程。假设让你解这个方程:“4 + 7”。你会立刻得出答案是 11。但是让我们想一想。这个信息是硬编码到你的大脑中的吗,无论何时你看到这个等式,你都可以推导出它等于 11?不会,举个例子:“1234 * 432”。我相信你需要一点时间来解决这个问题,但你最终会的。当我们看一个等式时,我们的大脑首先把它分解成小的信息包。在这种情况下,我们首先看到的是“4”、“7”和“+”运算符。我们的大脑假设“4”和“7”是操作数。我们大脑的下一步是决定我们需要对这两个数做什么运算,或者在我们的例子中做加法。所以我们的大脑最终决定,我们必须将这两个数字相加,输出结果是“11”。为什么我们这么快就评估了这两个数字,而不是另外两个更大的数字?这就是“权重”概念的由来。当我们在很小的时候就开始学习数学时,我们的大脑是在较小的数字例子上接受训练的。随着我们的成长,我们倾向于做更多这样的小操作。“22”是“4”,我们几乎不需要一个分数来确定这个原因,因为在我们的生活中,我们通常要处理这个方程成千上万次。每一次,我们的大脑都在输入“22”和“4”之间增加权重,就像我们的神经网络在每一层映射不同的神经元一样。这两层的边连接被赋予权重,随着时间的推移我们重复这个等式,权重继续增加。我们对输出为“4”感觉更积极,而我们肯定地知道输出不会是“5”(因此,连接输入和输出的边的权重是“0”)。
确定神经网络输出的概念完全基于*“激活”。神经网络的神经元只保存一个数字。在输入层的不同神经元中可能有不同的数目,或者可能没有(等于 0)。所有神经元的数据通过加权边流向下一层。边缘被加权以表示哪些神经元在决定我们的结果时更重要。当加权数据到达下一层神经元时,它会遇到一个激活函数。另外,我们称这个网络为前馈神经网络*,因为信息向前流动。激活函数的作用是:它只是将输入转换为正值或负值,同时增加一些复杂性以支持梯度下降算法。通过将输入转换为带符号的值,我们可以确定神经元是否应该激活/激发,也就是说,它是否应该向前传递信息。神经元本质上决定这个输入对我们的下一步是否重要,或者如果我们就此停止会更好,因为它不会增加更多的价值,只会混淆我们的网络。
但是,即使在激活之后,我们也可以预期一些不需要的值会到达输出,以防我们的神经网络无法访问足够多的信息,使其足够智能来识别这些差异。假设我们必须识别一个“5”,那么我们可能得到两个输出:一个“5”和一个“S ”,因为它们在某种程度上在视觉上是相似的。输出有一个 0 到 1 之间的数字,它告诉我们输出是我们实际答案的概率。因此,如果我们的神经网络完全愚蠢,它可能更喜欢“S”而不是“5 ”,但如果它相当聪明,它可能会说输入是“5”的概率是 0.78,而输入是“S”的概率是 0.52。我们的神经网络非常真实。他们不会说谎。如果他们感到不确定,他们会简单地告诉我们,他们认为两个或更多的输出是可能的,但他们觉得其中一个比其他的更有可能。
以下是关于神经网络如何工作一些极好的视觉解释:
人工神经网络中的一些重要概念
Source: https://nbmpub.com/
**反向传播:**反向传播的概念对于理解深度神经网络的训练非常重要。一开始,当我们的神经网络结构固定时,我们对模型的所有边初始化一些随机权重。之后,我们开始通过神经网络传递训练数据。当然,大多数时候,我们在开始时不会得到一个正确的输出,因为我们的模型没有为它调整,因为我们随机初始化了边的权重。这就是反向传播概念发挥作用的地方。当我们得到一个输出时,我们可以计算出与实际值相比的输出的误差。我们将这个误差反馈给我们的神经网络,并告诉它调整它的权重和模型参数,以最小化这个误差,从而提高它的准确性。这是使用梯度下降和链式法则完成的。(观看 RimstarOrg 的视频,它直观地解释了这个概念)
如果你想理解这个概念背后的数学原理,这里有一个很好的资源解释了反向传播。Brilliant.org 上的反向传播
**激活功能:**当一个神经元接收到一个输入时,该神经元被分配两个任务: 1。根据需要修改输入产生输出& 2。决定是否将其作为输出传递。激活函数主要为我们提供了一个非线性函数,这对于训练神经网络来解决复杂问题是必不可少的。没有激活函数的神经网络只是一个线性回归模型。为了实现反向传播,我们需要使用梯度下降,如果我们有一个线性函数就不能实现。如果来自激活函数的输出是正的和相关的,神经元将把它传递给下一个神经元,否则忽略它。
有许多种激活函数在它们自己的应用领域中更有效(举几个流行的例子,二进制步进分类器,ReLU,Tanh )。请参考以下资源,深入了解激活功能及其类型,以及如何为您的应用选择一种功能:
**正则化:**在神经网络中需要正则化以避免过度拟合。“惩罚”一词与正规化的概念产生了很好的共鸣。有许多方法可以通过调整神经网络的参数来调整它。
理解正则化技术的参考:
- [根据安德烈·卡帕西的材料制作的幻灯片](http://Andrej Karpathy)
- 詹姆斯·d·麦卡弗里的博客
**迁移学习:**迁移学习可用于这样的情况:我们已经有了一个训练好的模型,我们想用它来完成与该模型所训练的任务相似的其他任务。想象一个被训练识别各种动物的模型。这个模型应该在一个大的训练集上被训练过。现在我们有了这个模型,但是我们不想识别所有的动物。我们想建立一个可以识别狗品种的模型。为此,我们不必训练一个全新的模型。我们已经有了一个高效的模型。我们需要做的就是根据我们的需要调整这个模型。这种调整是通过改变预训练神经网络的最后一层来完成的,以便根据我们的需要进行预测。
一个很好的例子就是 ImageNet 模型,这是一个高效的预训练模型,可用于图像识别。我们可以直接在 Keras 中拉动模型,移除最后一层,并根据我们希望它识别的对象为其提供我们的最后一层。
点击此处了解有关迁移学习的更多信息:
**优化:**我们说神经网络优化,其实是指减少目标函数中的误差,也就是均方误差函数(损失/代价函数)。我们必须优化神经网络的权重以最小化目标函数。反向传播是目前最广泛使用的训练神经网络的优化技术,但它的范围在一定程度上是有限的。此外,还有其他优化方法可能会产生相同的结果,但可以显著减少训练时间,这是深度学习中的一个重要商品。这些其他优化技术易于使用,并且可以在训练 Keras 模型时使用参数进行设置。
阅读优化技术很重要,因为我们在训练模型时会经常用到它们。这些是我用来了解其他优化技术基础的一些好资源:
- 伊恩·古德菲勒深度学习著作中的优化相关章节
- 学习优化神经网络——李柯和吉滕德拉·马利克的论文
- 【CS231n 的参数更新部分
**死亡神经元:**如果我们使用类似 ReLU( 整流线性单元)的激活函数,我们可能会面临死亡神经元的问题。如果输出为正,ReLU 函数返回整数,如果输出为负(经过校正),则返回零。有些情况下,神经元必须处理许多负值作为其输入,这些输入的梯度将始终为 0,因为负输入的梯度始终为 0。由于激活功能的这种性质,一些神经元可能永远不会因为训练集的性质而调整和死亡。一般来说,当使用 ReLU 激活时,我们会处理网络中的一些死亡神经元,但这不是问题。但在某些情况下,如果死亡神经元的数量过多,我们的训练可能会出现重大问题。对此的解决方案可以是使用泄漏 ReLU 激活功能。
神经网络的类型
神经网络的类型如此之多,以至于可能需要一整篇文章来讨论高级别的基本概念。
Source: asimovinstitute.org
每组应用程序都有一个神经网络。最受欢迎的肯定是卷积神经网络 (CNN),因为它在从图像中学习方面具有出色的能力,这是深度学习最常用的应用之一。
但是你不能用 CNN,如果假设,你想开发一个程序,可以生成梵高风格的艺术。你需要使用生成对抗网络 (GAN)。gan 是神经网络中最好的部分,我喜欢它!如果深度学习是魔法,那么 GANs 就是下一个维度。谷歌大脑团队利用敌对网络开发了一种新的加密形式。这是一篇非常有趣的论文。一定要去看看! 官方论文来自 arXiv
旁边的图片总结了目前可用的所有类型的神经网络。一定要看一看。试着想想它们之间有什么不同。
Python 的深度学习库
说到制造人工神经网络,数据科学社区拥有大量的工具和选择!
一些最受欢迎的是:
对于初学者来说,使用这些库可能有点困难,因为对于完全陌生的人来说,理解它们的代码可能有点复杂。所以有更好的,易于理解和直观的框架可用,它使用上面提到的库作为它们的后端。因此,构建新模型变得非常容易,代码也很短,而且非常直观。最受欢迎的两个是:
所有这些库都非常灵活,易于设置和开始。个人比较喜欢 Tensorflow 后端的 Keras。我非常喜欢 Keras 的一个原因是因为神经元层的堆叠和编译模型非常直观和简单。您可以随意查看所有代码示例,看看哪一个对您来说更直观。
Keras 简介
Source: blog.keras.io
如果要我说为什么我更喜欢 Keras 而不是其他框架,我只会说:“ Keras 优先考虑开发者体验”。这很重要。大多数框架在构建时都有一个主要目标,那就是使它们快速高效,由于这个原因,大多数时候它们错过了开发人员的体验,即开发人员使用它们和学习使用它们有多容易。
Keras 支持 Python 从 2.7 到 3.6 的所有主要版本,根据对 Stackoverflow 和 arXiv 论文的分析,它是最受欢迎的深度学习库之一。
Keras 还支持许多硬件配置,包括 Nvidia GPUs 和 Google TPUs,后者扩展到多 GPU 和分布式培训支持。
下面是来自 Keras 主页的示例代码。你能猜出它在做什么吗?
**from** keras.models **import** Sequential
**from** keras.layers **import** Dense, Activationmodel = Sequential()
model.add(Dense(32, input_dim=784))
model.add(Activation('relu'))
如果你能从样本代码中做出一些推论,你将❤️·克拉斯!
请浏览其主页上的 Kera 入门 指南,看看 Keras 在行动。
在 Keras 中实现神经网络
好吧!所以这是最好的部分。我们将在 Keras 中实现一个非常简单的神经网络。(《15 行代码之下》还有 yada yada!)
我们将向神经网络输入一个 8 位二进制值的样本。它必须识别出哪一个是奇数。下面是一个例子,说明我们将向神经网络输入什么,以及它应该产生什么输出:
__________________________
Input | Output
__________________________
1 1 1 0 0 1 1 1 1 | 1
1 0 0 0 1 0 0 0 0 | 0
1 1 0 0 1 1 0 1 0 | 0
1 0 0 1 0 1 0 0 0 | 0
1 0 0 1 1 0 1 0 1 | 1
0 0 1 0 0 0 0 1 1 | 1
__________________________ . . . and so on.
这个任务看起来相当简单!" n%2 ",我们就完事了。但话又说回来,目的不是将其作为一种应用,而是以最简单的方式演示神经网络如何学习。
对于这个应用,我们将只需要 2 层神经元。我们现在不需要任何隐藏层,因为基本上不需要它们。你可以在左边的插图中看到我们的神经网络。
我们将 Keras 与 Tensorflow 后端一起使用。
*#We set the seed value with a constant number to get consistent #results every time our neural network is trained.
#This is because when we create a model in Keras, it is assigned #random weights every time. Due to this, we might receive different #results every time we train our model.
#However this won't be a general issue, our training set is small, #so we take this precaution*
**import numpy as np
np.random.seed(1)
import tensorflow as tf
tf.set_random_seed(1)
import keras***#We create a training set of fifteen 8-bit binary numbers* **train_X = np.array([[0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1], [0,0,0,0,0,0,1,0], [0,0,0,0,0,0,1,1], [0,0,0,0,0,1,0,0], [0,0,0,0,0,1,0,1], [0,0,0,0,0,1,1,0], [0,0,0,0,0,1,1,1], [0,0,0,0,1,0,0,0], [0,0,0,0,1,0,0,1], [0,0,0,0,1,0,1,0], [0,0,0,0,1,0,1,1], [0,0,0,0,1,1,0,0], [0,0,0,0,1,1,0,1], [0,0,0,0,1,1,1,0], [0,0,0,0,1,1,1,1]])
train_y = np.array([0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1])
test_X = np.array([[1,0,0,1,1,1,0,1], [1,0,0,0,0,1,1,0]])***#We create a Sequential model* **model = keras.models.Sequential()***#In the next line, we add both the required layers to our model
#The input_dim parameter is the number of input neurons and the #first parameter, "1" is the number of neurons in our first hidden #layer(which happens to be the output layer)* **model.add(keras.layers.Dense(1, input_dim=8, activation='sigmoid'))***#Configuring the model for training*
**model.compile(loss='binary_crossentropy', optimizer=keras.optimizers.SGD(lr=1.0), metrics=['accuracy'])***#We have defined all parameters, so we train our model with the training data we created.
#epochs: Number of times the dataset is passed through the network
#batch_size: Number of samples passed at a time*
**model.fit(train_X, train_y, epochs= 20, batch_size= 5)***#Our Neural Network has been trained now. We pass two inputs to the #model to check the results it produce.
#The results would be in the range of 0.98 or 0.02 cause we might #still be left with some error rate(which could've been fixed if we #used a bigger training set or different model parameters.
#Since we desire binary results, we just round the results using the #round function of Python.
#The predictions are actually in*
**print([round(x[0]) for x in model.predict(test_X)])**
我们清楚地知道,输入的第 8 位决定了数字是偶数还是奇数。但这并不为神经网络所知。它在创建时已被分配了随机权重。现在,我们知道,要判断一个偶数或奇数,我们只需要关心最后一位,因此直观地说,将最后一位连接到输出的神经元应该是唯一被激活的神经元(应该将权重设置为“1”),而其余的应该在训练过程结束时死亡。这就是所发生的一切!神经网络确定输出误差,并使用反向传播,逐渐改变权重,直到前七个神经元全部死亡。因此,我们的神经网络决定一个偶数或奇数。
恭喜你!你已经建立了你的第一个人工神经网络!
进一步的学习资源
正如我在开始时提到的,这里有一些优秀的资源可以用来开始深度学习。我从一般的路线走了弯路,以一种非常随意的方式学习,没有致力于一种资源,这不是一种非常有效的做法。但我发现的一件事是,在互联网上四处搜寻,寻找一个能教会你关于深度学习一切的最佳课程/书籍/视频,实际上是没有用的。
可能有更多更好的学习资源可用,但我只提到其中的一些,因为我个人使用这些资源作为参考。
Youtube 频道:
书籍(这两本书都可以在网上免费阅读):
一些网站:
关于论文,你可以去 arXiv.org 找。
我还没有参加过任何课程,但我确实打算很快参加。社区中真正受欢迎的两门课程是:
用深度强化学习训练猎豹奔跑
HalfCheetah Model featured by OpenAI Gym + MujoCo
猎豹可能有点夸张,但使用深度强化学习,我能够训练一个基于猎豹的物理模型来运行!
虽然这可能看起来并不令人兴奋,但让我这么说吧——在训练之前,代理(猎豹)没有任何关于运动的先验知识。它可以进入它的行动空间和观察空间,并且知道它必须尽可能地移动,但仅此而已!任何协调的运动都只是使用强化学习算法训练的产物。
在这篇文章中,我将分解我如何训练我的代理运行,以及我用来这样做的 DRL 算法。
Video of my trained Agent
连续动作空间中的强化学习
由于 half cheetah 模型使用连续的动作空间而不是离散的动作空间(即,其中一组实数被用作动作,而不是一组可能的选项),所以基于值近似值的方法不能很好地工作。通常,值函数需要使用 argmax 来确定最优策略,这反过来会使处理连续动作空间变得非常不方便,因为动作空间需要离散化。因此,我们转向策略梯度方法作为我们的算法选择。
与基于价值的方法相反,策略梯度直接逼近代理的策略!这反过来使得它非常方便地用于连续动作空间,因为不再需要使用 argmax 之类的东西(从而提高了准确性,并且通常需要较少的计算能力)。
DDPG 算法
通常,策略梯度会在动作空间上产生一个概率分布,其中动作在从该分布抽样后返回。然而,在训练期间,概率分布变得更窄,最终导致特定动作(即最优动作)的峰值概率。
X axis would be the action space
DDPG 算法(深度确定性政策梯度)利用了这一事实——鉴于政策梯度产生的概率分布将总是收敛于特定的行动,DDPG 只产生单一输出。简单概述一下,DDPG 是一种被称为“参与者评价算法”的东西,它同时逼近一个价值函数(评价者)和一个政策函数(参与者)。直觉上,演员要对动作负责,而评论家帮助演员决定它的动作有多好。
评论家通过使用称为 TD 误差的东西作为其梯度的损失来更新自身,而演员使用以下梯度进行更新:
As mentioned before, the critic is used to help the actor determine how good its action was — as such, the gradient of the critic is used in finding the gradient of the actor.
虽然这看起来非常复杂,但是实现起来非常简单。
Gradients are divided by batch_size for normalization, as batches of data may be used as inputs.
较小的变化
虽然 DDPG 算法采用了许多在 DRL 使用的标准技术(例如,经验回放),但它调整了两件事——目标网络的更新程序,以及如何执行探索。
目标网络:
DDPG 算法不是周期性地将目标网络设置为主要参与者和批评者网络,而是用“软”更新来更新目标网络。参考上面的代码片段,通过用当前主网络逐步替换少量(tau)目标网络来更新目标参数,从而使目标网络更新更稳定,并提高训练效率。
探索:
由于使用了连续的动作空间,诸如 epsilon greedy 的探索技术就不能再使用了。话虽如此,DDPG 通过在预测的行动中增加噪音来使用探索——这反过来又给政策增加了一些“随机性”。
The noise can be generated with many different methods —a zero centered gaussian was used for my program.
就是这样!在用 DDPG 训练了我的特工几百集之后,我的猎豹特工学会了跑步是最快的移动方式。
结论
DQNs 等基于值的方法可能对强化学习至关重要,但 DDPG 等算法提供的效用简直疯狂。虽然本文只关注它在训练猎豹奔跑中的应用,但潜在的影响要深远得多。以机器人技术为例——如果 DDPG 能够训练机器猎豹奔跑,那么是什么阻止了它训练更复杂的机器人呢?
最终,我们仍然面临着一系列障碍,这些障碍目前阻止我们在复杂的机器人技术中使用深度 RL。然而,随着 DRL 不断发展,基于政策梯度的方法,如 DDPG,很可能有一天会成为这种技术的支柱。
最后,这里是我文章中的一些摘录:
- 处理连续动作空间与处理离散动作空间非常不同
- DDPG 是一种行动者批评策略梯度算法,它利用了正常策略梯度的分布在特定行动时达到峰值的事实
- DDPG 使用噪音进行探索(随机性),使用“软”目标网络更新来实现稳定性
https://github.com/JL321/PolicyGradients-torchDDPG 更新实现的代码可以在这里找到
如果你喜欢这篇文章,一定要拍下这篇文章,并与你的网络分享!
另外,如果你有兴趣关注我在媒体之外做的一些事情,那么请在 LinkedIn 上联系我!
用深度强化学习训练面向目标的聊天机器人——第一部分
第一部分:介绍和培训循环
在这个系列中,我们将学习面向目标的聊天机器人,并用 python 训练一个具有深度强化学习的聊天机器人!一切从零开始!这个系列教程的代码可以在这里找到。
系列内容
第一部分:介绍和培训循环
什么是面向目标的聊天机器人?
面向目标(GO)的聊天机器人试图为用户解决特定的问题。这些聊天机器人可以帮助人们订票、寻找预定等。训练围棋聊天机器人有两种主要方式:使用编码器-解码器直接将用户对话映射到响应的监督学习,以及通过与真实用户或基于规则的用户模拟器的试错对话来训练聊天机器人的强化学习。通过深度强化学习训练的围棋聊天机器人是一个非常令人兴奋和成熟的研究领域,有许多实际应用!
对话系统
使用强化学习的围棋聊天机器人的对话系统分为三个主要部分:对话管理器(DM)、自然语言理解(NLU)单元和自然语言生成器(NLG)单元。此外,DM 被分成对话状态跟踪器(DST)或仅状态跟踪器(ST)和用于代理本身的策略,在许多情况下,代理由神经网络表示。此外,系统循环包含具有用户目标的用户。用户目标代表用户希望从对话中得到什么,在下图的情况下是餐馆预订。
Dialogue flow for a GO chatbot system
在这个循环中,用户说出一些由 NLU 组件处理成所谓的语义框架的东西,语义框架是可以由代理处理的自然语言话语的低级表示。DST 将用户对话行为(语义框架)和当前对话的历史处理成代理策略可以使用的状态表示。然后,这个状态被输入到代理的策略或神经网络中,并以语义框架的形式输出一个动作。还可以查询数据库(DB)以向代理动作添加信息,例如餐馆信息或电影票信息。然后,代理(在此图中也称为“系统”)动作由 NLG 组件处理,该组件将其转换为用户可读的自然语言。
MiuLab TC-Bot
Dialogue flow for TC-Bot
本教程和附带的代码是基于 MiuLab 的一个对话系统,名为 TC-Bot 。他们的论文的主要贡献是,它展示了如何使用基本规则模拟用户,以便与用真人训练代理相比,代理可以用强化学习非常快速地训练。其他论文也做了同样的事情,但是这篇论文是一个很好的例子(有代码!)如何制定一个成功的培训体系。
用户模拟器和误差模型控制器
我们将在后面的系列文章中更详细地介绍用户 sim,但是现在要理解它是一个基于确定性规则的模拟器,试图模拟一个真实的用户。在这种情况下,它基于用户议程建模,这意味着它使用代表用户 sim 的约束和需求的内部状态。这种内部状态跟踪当前的对话,以及完成当前目标还需要做什么。目标是从可用用户目标列表中随机挑选的,其中目标由一组约束和其他信息组成,这些约束和信息在用户 sim 试图实现其当前目标时指导用户 sim 的动作。误差模型控制器(EMC)被用于在语义框架的级别上向用户 sim 的动作添加误差,这被显示为改善训练的结果。
对于这个系列教程,您应该知道什么
下面是您应该知道的一些事情,这些事情不会在本系列中涉及,但是对于理解代码非常重要:
- 非常了解如何用 python 编码
- 知道如何使用 python 中的字典,因为我们会经常用到它们!
- 知道如何编写简单的代码 DQN
- 知道如何用 Keras 制作一个非常简单的神经网络模型
我们将使用 Python ≥ 3.5、 Keras (任何最新版本),当然还有 numpy。
现在让我们继续讨论我们将要使用的数据!在这一部分,我们将讨论[train.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/train.py)
。
电影票数据
数据库 :该数据库为不同属性的电影票或时段。以下是其中几项(排名不分先后):
它被组织成一个字典,关键字是长整型(类似整数)票的索引,值也是包含票代表的电影信息的字典。如您所见,并非所有的票据都有相同的属性,显然也不总是相同的值!
数据库字典 :另一个文件包含一个字典,其中的键是可以在一个标签中的不同槽,值是每个槽的可能值的列表。以下是一些不同的项目(截断值列表):
用户目标列表 :最后,我们将用户目标作为包含每个目标的请求和通知槽的字典列表。稍后我们将更详细地讨论这意味着什么。示例:
该数据库的目标是让代理商找到一张符合用户约束的票,该约束由该集的用户目标给出。这不是一件容易的事,因为每张票都是独一无二的,而且大多数都有不同的位置!
动作剖析
理解这个系统中动作的结构是非常重要的。如果我们暂时忽略自然语言,用户 sim 和代理都以语义框架的形式作为输入和输出动作。动作包含意图、通知和请求槽。本教程系列中的 Slot 指的是键、值对,通常指的是单个通知或请求。例如,在字典{‘starttime’: ’tonight’, ‘theater’: ’regal 16’}
中,‘starttime’: ’tonight’
和‘theater’: ’regal 16’
都是插槽。示例操作:
意图代表行动的类型,如下所列。剩下的动作被分成包含约束的通知槽和包含需要填写的信息的请求槽。可能的关键字列表在[dialogue_config.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/dialogue_config.py)
中列出,它们的值在上面提到的数据库字典中。通知槽是发送者希望接收者知道的信息。它由键列表中的一个键和该键的值列表中的一个值组成。请求槽包含一个键,发送方希望从接收方找到该键的值。所以它是密钥列表中的一个密钥,而值‘UNK’
意味着“未知”,因为发送者还不知道什么值适用于这个槽。
所有意图
- 通知:以通知槽的形式提供约束
- 请求:请求用值填充请求槽
- 感谢:仅供用户使用;它只是向代理表明它已经做了一些好事,或者用户已经准备好结束对话
- 找到匹配项:仅由代理使用;向用户表明它有一个它认为将满足用户目标的匹配
- 拒绝:仅供用户使用;仅用于响应具有匹配意图的代理操作,表明匹配不符合其约束条件
- 完成:代理使用此功能来结束对话,并查看是否已完成当前目标,当情节持续时间过长时,用户操作会自动执行此意图
状态
ST 创建一个状态作为代理选择适当动作的输入。这是来自当前对话历史的有用信息的 numpy 数组。我们将在第二部分对此进行更深入的讨论。
现在簿记已经完成,让我们进入训练循环和一些代码!
培训代理
Our training loop
这个图代表了训练中一个完整循环的流程。该系统的 4 个主要部分是代理dqn_agent
、对话状态跟踪器state_tracker
、用户(或用户模拟器)user
和 EMC emc
。让我们来看看一轮比赛的各个阶段:
- 获取当前状态,该状态相当于之前的下一个状态,或者如果这是情节的开始,则获取初始状态,并将其作为输入发送到代理的 get action 方法
- 获取代理的操作,并将其发送到 ST update 方法以获取代理操作:ST 在该方法中更新自己的当前会话历史,并使用数据库查询信息更新代理操作
- 更新的代理动作作为输入被发送到用户的步骤方法中:在步骤中,用户 sim 制作其自己的基于规则的响应,并且还输出奖励和成功信息(未示出)
- 用户操作被 EMC 注入了错误
- 带有错误的用户操作被作为输入发送到用户操作的 ST 更新方法中:类似于带有代理操作的 ST 更新方法,但是,它只是在其历史中保存信息,而不是以重要的方式更新用户操作
- 最后,从 ST 的 get 状态输出下一个状态,这完成了添加到代理的存储器中的该轮的当前经验元组
Code of diagram
一个重要的注意事项是,与任何 DQN 代理一样,内存缓冲区在某种程度上是在“预热”阶段填充的。与 dqn 在游戏中的许多用途不同,代理在这个阶段不采取随机行动。相反,在预热期间,它使用一个非常简单的基于规则的算法,这将在第二部分解释。
如你所见,我们没有使用任何自然语言(NL)组件,所以动作总是语义框架。在本系列中,我们将培训不需要 NL 的 DM。NLG 和 NLU 与代理分开进行预训练,不需要了解如何用 DRL 训练代理。不要烦恼!你仍然会学到很多,老实说,学习如何用 DRL 训练代理比知道如何用监督学习训练 NL 组件有趣得多。看一看本系列的第五部分,看看在哪里可以学习添加 NL 组件!
情节重置
在我们开始热身和训练循环之前,这里是每集之前调用的集重置功能。还要注意的是,对话和一集是一回事,我可以互换使用。
简而言之,剧集重置会刷新对象并获取该剧集的初始用户操作。
预热代理
首先,我们定义外部循环只运行到代理的内存被填充到WARMUP_MEM
或者它的内存缓冲区完全满了。接下来,我们必须重置每个循环的情节,并获得初始状态。内部循环运行run_round(state, warmup=True)
直到done == true
意味着这一集结束。
培训代理
忽略一些额外的变量,循环与预热非常相似。到目前为止,主要的区别是,当剧集数量达到NUM_EP_TRAIN
时,该方法结束其外部循环。
训练模块的工作原理
在一定数量的剧集(TRAIN_FREQ
)的每个周期之后,代理人被训练其对经历的记忆。
- 如果该周期的成功率大于或等于当前最佳成功率(在
train_run()
开始时初始化为 0.0),并且高于某个SUCCESS_RATE_THRESHOLD
,则清空代理的内存。这是为了消除基于先前版本的代理模型的动作的旧经验,即由次优模型采取的动作。然后,这允许来自模型的更好版本的更新的体验填充存储器。这样,训练和表现是稳定的。 - 接下来,代理的行为模型权重被复制到目标模型中,这是今天使用的所有 dqn 所需要的,以稳定学习。
- 最后,代理被训练,这意味着当前的记忆被用于提高模型的权重。
培训总结
请看一下[train.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/train.py)
中的完整代码,了解全貌!
- 加载数据库数据
- 创建对象
- 呼叫
warmup_run()
- 打电话给
train_run()
这就是 DRL 训练的围棋聊天机器人的主要训练循环。理解图表很重要。接下来我们将了解代理、它可以采取的行动种类、预热政策和内部权重优化流程。
那里见!
用深度强化学习训练面向目标的聊天机器人——第二部分
第二部分:DQN 代理人
如果你还不知道什么是面向目标的聊天机器人,我们正在使用的数据库和我们对话系统的训练循环,看看这个系列教程的的前一部分!
在这一部分,我们将深入探讨代理人,在这种情况下,代理人由 DQN 代表。
本教程和附带的代码是基于 MiuLab 的 TC-Bot。本教程的代码可以在这里找到。我们将从[dqn_agent.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/dqn_agent.py)
开始这一部分的工作。
我们正在遵循的总体图表:
Dialogue flow of a single round
代理的目的是什么?
面向目标(GO)的聊天机器人代理的目的是接受训练,以便熟练地与真实用户交谈,从而完成一个目标,例如找到一个符合用户约束的预订或电影票。代理的主要工作是采取一种状态,并产生一个接近最优的行动。具体来说,代理从对话状态跟踪器(ST)接收表示当前对话历史的状态,并选择要采取的对话响应。
深度 Q 网(DQN)
dqn 的细节超出了本教程的范围,所以请查看这些资源以了解更多信息:编码一, 以不同的方式编码一
现在让我们来看一些代码!
代理的对话配置
以下是代理使用的[dialogue_config.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/dialogue_config.py)
中的对话配置常量:
agent_inform_slots
是座席代表通知的所有可能的关键值。agent_request_slots
是代理请求的所有可能的键值。还显示了可能的代理操作。
神经网络模型
我们使用 Keras 来建立代理的模型。该模型是一个单隐层神经网络。这很简单,但是对这个问题有很好的效果。
该代码片段中的实例变量被分配给[constants.json](https://github.com/maxbren/GO-Bot-DRL/blob/master/constants.json)
中“agent”下的常量
政策
在给定的状态下,代理用来选择动作的策略取决于对话是处于预热阶段还是训练阶段。在训练前运行热身,通常使用随机策略来填充代理的记忆。在这种情况下,代理在预热期间使用非常基本的基于规则的策略。在训练中,行为模型被用来选择一个动作。在这种情况下,use_rule
表示预热。
这个方法返回动作的索引和动作本身。
基于规则的策略
在预热期间,采用一个简单的基于规则的策略。
首先注意代理的重置方法,该方法仅用于重置该基于规则的策略的几个变量:
该策略简单地请求请求槽列表中的下一个槽,直到它没有更多的请求为止,然后它采取“找到匹配”动作,最后在最后一轮采取“完成”动作。
我们将在第三部分和第四部分讨论 match found 和 done 含义。
下面是一个使用这个简单策略的单集示例:
这个策略对于以某种有意义的方式热启动代理很重要。这是一个简单的策略,但比采取随机行动能改善结果。
DQN 政策
培训期间使用:
训练方法
正如在系列的第一部分中所描述的,dqn_agent.train()
在训练中每隔几集就会被调用一次。
Note: Some of this code is based off of an awesome tutorial by Jaromír which can be found here.
我不打算遍历这段代码的大部分,因为它是非常基本的,你们中的许多人应该已经看到了 DQN 代码,看起来很像现在这样。然而,我要指出的是,与许多其他 DQN 训练方法不同的是,这个代码并不是随机抽取一批样本。相反,它会计算当前内存中有多少批次,然后根据这些批次训练权重。这有点奇怪,但对 TC-Bot 的原始代码是准确的。摆弄一下这个,看看你能否用不同的批量取样技术得到更好的结果!
在摘要中,该代理根据一个状态选择一个动作,该状态的策略要么是预热期间的一个简单请求列表,要么是训练期间的单个隐藏层行为模型。这种训练方法很简单,与其他 DQN 训练方法只有几处不同。尝试模型的架构,添加优先体验回放并制定更高级的基于规则的策略!
下一部分将涵盖 ST 和查询系统!在那里,您将了解 ST 如何更新其历史/对对话的理解,以及状态准备是什么样的。
用深度强化学习训练面向目标的聊天机器人——第三部分
第三部分:对话状态跟踪器
如果你还不知道我们在哪里了解这个领域的培训和 DQN 代理,请查看前面的部分!这个代理的目标是为用户选择合适的电影票。
在这一部分中,将解释状态跟踪器以及状态跟踪器所使用的数据库的查询系统。
这个系列教程是基于 TC-Bot 的。这个系列的 github 代码可以在这里找到。我们将与[state_tracker.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/state_tracker.py)
和[db_query.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/db_query.py)
一起工作。
这是我们根据前两部分得出的图表:
Dialogue flow of a single round
对话状态跟踪器
在面向目标的对话系统中,对话状态跟踪器(st)的主要工作是为代理准备状态。正如我们在前一部分所讨论的,代理需要一个有用的状态,以便能够对采取什么行动做出好的选择。ST 通过收集用户和代理采取的动作来更新其对话的内部历史。它还跟踪当前剧集中迄今为止包含在任何代理和用户动作中的所有通知片段。代理使用的状态是由来自 ST 的当前历史和当前通知的信息组成的 numpy 数组。此外,每当代理希望通知用户一个槽时,ST 查询数据库以获得给定其当前通知时有效的值。本质上,ST 为代理准备了一个状态,给出了它的情节历史和到目前为止在情节中由用户和代理发出的所有通知时隙,并且为代理查询数据库。
重要的操作类型
在继续之前,让我们回顾一下第一部分中一些值得注意的动作意图:通知、请求和匹配找到。
通知 表示动作包含发送方希望提供给接收方的通知槽。
请求例如,如果发送者请求一个日期(“UNK”的值),那么接收者要采取的适当行动(尽管它不是必须的)将是通知原始发送者“明天”或某个其他值。
只有代理可以向用户发送匹配发现动作。这意味着,当 ST 接收到代理操作时,它会找到一个与当前通知一起工作的票据,并用票据中的所有槽填充该操作的通知槽,此外还有实际的票据 ID 本身。然而,如果代理决定采取匹配发现操作,但是实际上没有有效的票据,那么操作通知槽保持为空,除非有没有匹配的特殊指示。这种动作类型很重要,因为代理必须在剧集中的某个点采取匹配发现动作,即包含与用户的约束条件相匹配的标签以在剧集中成功,这将在下一部分中解释。
最后注意:代理只能包含一个插槽,而用户 sim 操作可以包含多个插槽。唯一的例外是匹配发现操作,因为它可能包含票据的所有插槽。
下面是匹配找到操作的示例。
更新状态跟踪器的历史记录
update_state_agent(self, agent_action)
将代理动作作为输入,并更新 ST 的历史和当前通知。update_state_user(self, user_action)
将用户动作作为输入,并更新这两个变量。
该类的重置方法(在[train.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/train.py)
中的重置函数中调用)重置当前通知、历史以及回合数,该回合数指示剧集的当前回合:
使用用户操作更新
- 用操作中的任何通知槽更新当前通知
- 将操作附加到历史记录
- 增加回合数(当前回合结束)
使用代理操作更新
在某些情况下,把代理的动作想象成原始的或者未填充的版本,把状态跟踪器想象成用数据库信息填充任何通知槽。如果代理操作是通知,则将在数据库中查询与当前通知不冲突的匹配值。如果该动作是找到的匹配,那么将查询数据库以寻找符合当前通知的匹配票据。对于所有其他意图,没有必要进行询问。注意:在对话配置中,下面的self.match_key
被设置为'ticket'
。
意向动作‘inform’
和‘match_found’
以特定的方式处理。
处理意向动作 **‘inform’**
- 通过使用当前通知作为约束查询数据库来填充动作的通知槽(最初值为
‘PLACEHOLDER’
) - 用填充的通知槽更新当前通知
处理意图动作 **‘match_found’**
- 从数据库中获取一个票据列表,其中每个票据的槽与当前通知的槽(键和值)相匹配,当前通知充当约束
- 如果有匹配的票据,则将代理操作的通知槽设置为此列表中票据的槽;此外,创建并设置代理动作的通知槽中的值
self.match_key
为该票据的 ID - 否则设置
self.match_key = ‘no match available’
- 用上面找到的新值更新当前通知中
self.match_key
的值
成功查询找到匹配的示例操作:{'intent': 'match_found', 'inform_slots': {'ticket': 24L, 'moviename': 'zootopia', 'theater': 'carmike 16', 'city': 'washington'}, 'request_slots': {}}
一个不成功查询匹配发现动作的例子 : {'intent': 'match_found', 'inform_slots': {'ticket': ‘no match available’}, 'request_slots': {}}
最后,将轮数添加到代理操作,并将代理操作附加到历史记录。
请记住,动作是字典,在 python 中是可变的,所以发送到该方法中的原始代理动作实际上是由查询信息和轮数值自行更新的。
状态准备
st 最重要的工作是为代理提供当前事件历史的有用状态或表示。get_state(self, done)
取一个 done bool,表示本轮结束后该集是否结束,并输出一个 numpy 形状的数组(state size,)
。知道州的大小并不重要,因为它只是基于我们在州中存储了多少信息。但是如果您想删除或添加更多信息,您可以很容易地更改它。
状态由关于剧集状态的有用信息组成,例如最后用户动作和最后代理动作。这是为了通知代理最近的历史,这足以让代理采取接近最佳的行动。此外,round_num
被编码以让代理知道该集的紧急程度(如果该集接近其允许的最大回合数,代理可以考虑采取匹配发现动作以在太晚之前查看它是否有匹配)。最后,状态由关于当前通知的信息以及数据库中有多少项匹配那些当前通知的信息组成。
有很多研究和工作被投入到状态跟踪中,例如编码信息的最佳方式以及在状态中提供什么信息。这种状态准备方法可能远非最佳,但需要进行大量调整来优化这一过程。请看一下第五部分中关于状态跟踪的参考资料。
查询系统
正如我们在上面看到的,状态跟踪器需要查询票据信息的数据库,以填充通知并匹配找到的代理动作。状态准备方法也使用它来为代理收集有用的信息。这里实现的查询系统可以用于任何与这个电影票数据库结构相同的数据库。
我不打算详细介绍[db_query.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/db_query.py)
中方法的实际实现,因为理解这一点并不能真正提高对这个对话系统如何工作的理解。然而,如果有足够的需求来实现完整的运行,那么我会做一个关于这个类的新帖子。
公共方法总结:
获取数据库结果
get_db_results(constraints) -> dict
:在update_state_agent(self, agent_action)
中调用,以响应具有意图‘match_found’
的代理动作,如上所述。查看数据库中的每个项目,如果项目槽包含所有约束键,并且具有这些槽的匹配值,则将该项目添加到返回字典中。因此,它在数据库中查找给定约束的所有匹配项。
例如,假设数据库如下所示:
{0: {'theater': 'regal 6', 'date': 'tonight', 'city': 'seattle'},1: {'date': 'tomorrow', 'city': 'seattle'},2: {'theater': 'regal 6', 'city': 'washington'}}
约束条件是:{'theater': 'regal 6', 'city': 'seattle'}
输出将是{0: {'theater': 'regal 6', 'date': 'tonight', 'city': 'seattle'}}
,因为这是唯一包含所有约束键并匹配其所有值的项目
填充通知槽
fill_inform_slot(inform_slot_to_fill, current_inform_slots) -> dict
:在update_state_agent(self, agent_action)
中调用,以响应带有意图‘inform’
的动作,如上所述。首先,它调用get_db_results(current_informs)
来获取所有的数据库匹配。然后计算matches[inform_slot_to_fill]
的值,并返回出现的最高值。
例如,假设这些是从get_db_results(constraints)
返回的匹配:
{2: {'theater': 'regal 6', 'date': 'tomorrow', 'moviename': 'zootopia'},45 : {'theater': 'amc 12', 'date': 'tomorrow'},67: {'theater': 'regal 6', 'date': 'yesterday'}}
如果inform_slot_to_fill
是'theater'
,那么这个方法将返回{'theater': 'regal 6'}
,同样,如果inform_slot_to_fill
是'date'
,那么输出将是{'date': 'tomorrow'}
。选择我们关心的键的多数值。
获取插槽的数据库结果
get_db_results_for_slots(current_informs) -> dict
:调入get_state(self, done=false)
。遍历整个数据库,统计当前通知中每个槽(key, value)
的所有出现次数,并返回所有键的key: count
字典;此外,'matching_all_constraints': #
是状态中另一个有用的信息,它存储了多少数据库项匹配所有当前的通知槽。
例如,使用与上面相同的数据库:
{0: {theater: regal 6, date: tonight, city: seattle},1: {date: tomorrow, city: seattle},2: {theater: regal 6, city: washington}}
如果 current informs 为:{'theater': 'regal 6', 'city': 'washington'}
,则输出将为{'theater': 2, 'city': 1, 'matching_all_constraints': 1}
,因为两个数据库项具有‘theater’: ‘regal 6’
,一个数据库项具有‘city': 'washington’
,并且一个数据库项匹配所有约束(项 2)。
在结论中,状态跟踪器使用每个代理和用户动作来更新其历史和当前通知,以便在代理需要采取动作时为其准备有用的状态。它还使用一个简单的查询系统来为通知和匹配找到的操作填充代理通知槽。
在下一部分中,我们将学习用强化学习训练代理的最重要的部分之一:用户模拟器。我们将学习我们的用户 sim 将使用的特定规则来做出类似人类的动作!
用深度强化学习训练面向目标的聊天机器人——第四部分
第四部分:用户模拟器和误差模型控制器
查看本系列之前的部分,包括训练循环、DQN 代理和状态跟踪器,天啊!
这一部分解释了非常重要的用户模拟器和错误模型控制器。
这个系列教程是基于 TC-Bot 的。这个系列的代码可以在这里找到。这部分重点介绍的两个文件是[user_simulator.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/user_simulator.py)
和[error_model_controller.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/error_model_controller.py)
。
我们正在遵循的图表:
Dialogue flow of a single round
用户模拟器
用户模拟器用于模拟真实的用户,这样可以比真实用户被迫坐下来接受几个小时的培训更快地培训代理。聊天机器人领域的用户模拟器研究是一个热门的研究课题。本教程中涉及的是一个相当简单的确定性的基于规则的模拟器,基于 TC-Bot 的用户 sim,有一些小的改动。这个用户模拟器,像目前大多数一样,是一个基于议程的系统。这意味着用户对于该情节具有目标,并且它根据该目标采取行动,同时跟踪内部状态,这允许它跟随对话以采取明智的行动。每一轮动作都是响应于主体动作而精心设计的,主要使用确定性规则和一些随机规则来创建不同的响应。
什么是用户目标?
用户目标是从真实对话或手工制作(或两者兼有)的语料库中抽取的。每个目标都由通知时段和请求时段组成,就像一个动作,但没有意图。从语料库中获取目标有几种标准方法。第一:在一集里,用户最初动作的所有时段(请求和通知)都有一个目标。第二:一集里所有用户动作的所有时段被组合起来,形成一个单一的目标。除了这种自动收集之外,一些手工制作的规则用于降低用户目标的多样性,以便它们对于代理来说更容易实现。幸运的是,TC-Bot 附带了我们将使用的用户目标的文件,因此我们不需要自己从语料库中生成它们。
用户目标的通知时段模拟用户在寻找适合他们的票据时的约束。请求槽模拟用户获取关于什么票可用的信息。该系统与真实用户之间的主要区别在于,当用户更多地了解有哪些票可用时,他们可能会改变主意。这在这里不会发生,因为在一集里目标不会改变。想想你可以用什么方法来增强这个系统,让它更像一个真正的用户!
最后注意,默认槽(在本例中为“ticket ”)被添加到每个目标的请求槽中。代理必须成功地通知一个值来填充默认时段,以实现目标并在一集中成功。
来自第一部分的几个用户目标的例子:
用户模拟器内部状态
用户 sim 的内部状态(不同于来自状态跟踪器的状态)跟踪目标位置和当前对话的历史。它用于设计每一步的用户操作。具体来说,状态是 4 个槽字典和一个意图的列表:
- Rest 槽:代理或用户尚未通知的来自目标的所有通知和请求槽
- 历史插槽:迄今为止用户和代理操作的所有通知插槽
- 请求槽:用户希望在不久的将来的操作中请求的请求槽
- 通知插槽:通知插槽,代理打算在当前正在制定的操作中通知插槽
- 意图:当前操作的意图
用户模拟器动作
用户可以采取的操作比可能的代理操作更加多样,有时甚至更加复杂。一个用户操作可以有多个请求槽或多个通知槽。在某些情况下,例如初始操作,它实际上还可以包含请求和通知槽。
现在进入代码!
对话配置
以下是[dialogue_config.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/dialogue_config.py)
中用户 sim 的对话配置常量:
重置
用户 sim 重置很重要,因为它选择新的用户目标,重置状态并返回初始动作。
解剖学:
- 选择一个随机目标
- 将默认位置(“入场券”)添加到目标中
- 清除状态的所有方面
- 将所有目标通知和请求槽添加到
‘rest_slots’
;在整个谈话过程中,他们都需要被告知 - 将约束检查初始化为失败(在下面的成功约束中讨论)
- 返回剧集的初始动作
初始用户操作
- 初始操作必须始终是一个请求
- 它还必须始终包含在
dialogue_config.py
中定义的usersim_required_init_inform_keys
中列出的所有通知槽。在我们的例子中,这仅仅意味着槽‘moviename’
,它也是每个用户目标中必需的通知槽,即它总是在初始动作中被通知 - 必须包含来自目标的随机请求槽,而不是默认槽,除非这是唯一的一个
分步方法
用户响应 step 方法中的代理操作,该方法将代理操作作为输入。Step 接受这个动作和用户 sim 的内部状态,并返回一个精心制作的响应(动作)、标量奖励、完成布尔值和成功布尔值。这类似于 openai gym environments 中的 step 函数,目的相同!
具体来说:
- 清除状态通知槽和意图,因为它们不需要逐轮结转,不像历史、休息和请求那样结转
- 如果回合等于最大回合,则回复意图
‘done’
并设置success = FAIL
- 否则,基于代理动作意图来设计动作。3.a)如果意图是
‘done’
,那么也计算该集是否算作代理的成功,并回复‘done’
- 回应国家的意图,请求和通知槽
- 计算该步骤的标量奖励
- 返回响应、奖励、完成布尔值和指示成功的布尔值
顺便说一句,意图‘done’
的这两种使用是用户 sim 动作将其作为意图的唯一时间,即‘done’
象征着对话的结束
注意:success
可以是NO_OUTCOME
如果该集没有完成,可以是FAIL
如果该集已经完成并且失败,或者SUCCESS
如果该集已经完成并且成功
[utils.py:](https://github.com/maxbren/GO-Bot-DRL/blob/master/utils.py)
中的奖励功能
这个奖励函数通过给代理一个巨大的成功奖励来帮助它学习成功。让它学会避免失败,方法是给它一个大的失败惩罚,但没有成功的奖励那么大。我相信这有助于代理人不要太害怕为成功的巨大奖励而冒险,否则它可能会过早地结束一集以减少负面奖励。最终,像这样的奖励形成往往是一种平衡行为。试试这个奖励函数,看看是否能得到更好的结果。
回应的类型
一些回应的规则很复杂或者看起来很随意。但是请记住,许多设计响应的规则都很复杂,因此用户 sim 卡可以更像人类,这将有助于代理与真实用户打交道。然而,这些绝不是最好的规则。
响应的重要要求:
- 对于用户动作:如果意图是
‘inform’
,那么必须有通知槽,但是没有请求槽,以便不与下面的要求#2 冲突 - 对于用户动作:如果意图是
‘request’
,它可以让同时拥有通知和请求槽,但必须至少拥有请求槽:这是一个复杂的动作,目的是向请求添加信息,使其更像人类 - 每当代理操作或用户操作包含通知槽时,该通知槽必须从 rest 槽中移除(如果在 rest 槽中键入),并在历史槽中添加/更新
- 每当代理动作包含通知槽时,必须将其从状态请求槽中移除(如果键入状态请求槽),并遵循上述要求 3
对请求的答复
用于响应请求的 4 种主要情况:
案例 1)如果代理请求目标通知槽中的某个内容,但它没有被通知,则从目标本身通知它
情况 2)如果代理请求目标请求槽中的某些东西,并且它已经被通知,那么从历史中通知它
情况 3)如果代理请求目标请求槽中的某样东西,但它没有得到通知,那么也用随机通知请求相同的槽
情况 4)否则用户 sim 不关心被请求的时隙;告知特殊值‘anything’
为请求槽的值
回复:通知
两种主要的应对情况:
情况 1)如果代理告知目标告知中的内容,而其告知的值不匹配,则告知正确的值
情况 2)否则选择一些时隙来请求或通知
2.a)如果国家有任何要求,则提出要求
2.b)如果在休息时段有什么要说的,请选择一些内容
2.c)否则用‘thanks’
回应,真正的意思是“无话可说”;事实上,这向代理表明它的 rest 槽是空的,这是下面讨论的成功的必要条件
成功限制
在继续讨论“匹配发现响应”和“完成响应”之前,了解一集的成功限制很重要。请记住,目标通知槽代表找到的匹配必须包含的约束。以下是代理要取得成功必须做的事情:
- 带着
‘match_found’
的意图采取行动,检查比赛是否满足所有目标约束 - 在
‘match_found’
之后采取意图为‘done’
的动作,检查剩余槽是否为空
这些成功约束需要匹配的票据,因为这是任务的目标,并且空的 rest 槽显示代理已经通知了所有目标请求槽。这有助于代理学会让用户在提交匹配之前提出问题(请求)。
回复:找到匹配项
- 动作中的默认槽必须有一个实际的匹配 ID 作为值,而不是
‘no match available’
,这意味着它实际上找不到与当前状态跟踪器通知的匹配 - 目标中的所有通知时段必须位于此操作的通知时段中,因为这些时段是票证本身的属性
- 该操作的所有通知时段值必须与目标通知时段值相匹配
- 如果所有这些都成功,那么
self.constraint_check
被设置为SUCCESS
,否则设置为FAIL
如果匹配成功,则回复 intent ‘thanks’
和任何仍处于请求状态的请求槽。否则回复意图‘reject’
并且没有通知或请求槽。‘thanks’
向代理表明该票据有效。‘reject’
表示该票不起作用。
回复:完成
约束 1) self.constraint_check
必须设置为SUCCESS
,表示找到一个有效的匹配
约束 2)剩余槽必须为空
注意:如 step 方法所示,回复的意图是‘done’
,没有槽
误差模型控制器
在从步骤接收到用户动作之后,它被发送到错误模型控制器(EMC)以注入错误。在 TC-Bot 中,发现这样做实际上有助于代理处理现实生活中的自然语言组件错误或用户在回复中出错。EMC 可以将错误添加到通知槽和用户动作的意图中。
各通知槽中动作的槽级错误类型:
- 用该键的随机值替换该值
- 替换整个槽:随机键和该键的随机值
- 删除该插槽
- 对于一个插槽,上述所有 3 种错误的概率相等
意图级别错误:
- 用随机意图替换意图
在总结中,我们在这里创建的用户模拟器使用简单的规则来创建类似人类的响应,目的是训练代理与现实生活中的用户打交道。错误模型控制器的目的是将错误添加到用户 sim 动作的意图和/或通知槽中,这提高了真实测试中代理的质量。
在的最后一部分中,我们将介绍如何实际运行我们创建的代码(来自回购)以及今后的发展方向。T4:有很多需要改进的地方,还有很多研究要做!
最后部分再见!
用深度强化学习训练面向目标的聊天机器人——第五部分
第五部分:代理运行及未来研究
https://www.nasa.gov/mission_pages/shuttle/shuttlemissions/sts127/launch/index.html
在前面的部分中,我们介绍了面向目标的代理的所有部分和代码!
这是第五部分,也是最后一部分,我们将介绍如何运行代码以及未来的研究和改进!
这个系列教程是基于 TC-Bot 的。这个系列的代码可以在这里找到。在这一部分,我们将快速回顾一下[user.py](https://github.com/maxbren/GO-Bot-DRL/blob/master/user.py)
和[test.py.](https://github.com/maxbren/GO-Bot-DRL/blob/master/test.py)
运行代码
您既可以培训代理,也可以测试经过培训的代理。此外,代替使用用户模拟器,你可以作为一个真正的用户自己输入动作。
培训代理
运行train.py
,用给定的constants.json
文件从头开始训练。改变常数值,看看是否能找到更好的超参数。
保存和加载模型权重
通过将constants.json
中的"save_weights_file_path”
设置为您想要保存行为和目标模型权重的相对文件路径,您可以将训练模型的权重保存在一个目录中。要加载保存的重量,将"load_weights_file_path”
设置到相同的路径。例如,要加载回购中的权重,将其设置为"weights/model.h5"
。权重文件必须是. h5 文件,这是 Keras 使用的文件类型。您可以加载已经训练好的重量,并对其进行更多训练!
测试代理
通过运行test.py
并将"load_weights_file_path”
设置为正确的文件路径,可以使用经过训练的权重对代理进行测试。
用真实用户测试(或培训)代理
您可以通过将constants.json
中“run”
下的"usersim”
设置为false
,以用户身份输入您自己的动作(而不是使用用户 sim)来测试代理。你在控制台中输入一个动作和一个成功指示器。动作输入的格式是:意图/通知槽/请求槽。
动作输入示例:
- 请求/电影名称:房间,日期:星期五/开始时间,城市,剧院
- 通知/电影名称:疯狂动物城/
- 请求//开始时间
- 完成//
此外,控制台将询问代理是否成功的指示器(除了在一集的初始动作输入之后)。允许的输入是-1 表示失败,0 表示没有结果,1 表示成功。
与训练有素的代理人一起玩得开心,并定性测试您的改进!
结果
我的数据是使用[constants.json](https://github.com/maxbren/GO-Bot-DRL/blob/master/constants.json)
中设置的超参数收集的,并且是 10 次训练运行的平均值。
常数:
按一段时间的最大成功率/到该集为止的训练频率(每 100 集)列出的集数(每 40000 集中的 2000 集)表:
未来的研究和实验
我们刚刚编写的代码是一个非常简单的面向目标的聊天机器人系统的例子。用户 sim 不是太先进,不像 TC-Bot 在这个系统中没有自然语言组件。代理还有很大的改进空间,包括允许更复杂的操作。然而,这是进一步研究和试验这个主题的一个非常好的起点。这里有一些重要的地方需要改进或添加到现有的代码中,或者只是为了研究:
自然语言
Diagram from an NTU and Microsoft paper
在 TC-Bot 中添加自然语言组件,这样您就可以在更真实的对话环境中测试它。请记住,自然语言组件不是用这种深度强化学习循环来训练的,它们是用 LSTMs 使用不同的通常受监督的学习方法单独进行预训练的。这里有几个关于这个话题的资源:媒体文章、 NTU 论文、 NTU 和微软当然还有 TC-Bot 及其论文。
其他数据集和语料库
我们只看到了这个系统如何与一个简单的电影票数据库一起工作。在与此数据库结构相同的另一个数据库上尝试它。请确保相应地更改对话配置,但记住这是一个简单的系统,它只能以找到单个项目来实现用户目标为目标。看看你是否能改变它来找到一个目标需要的多个项目!这里有一些谷歌数据集和一个来自 T2 斯坦福大学的数据集。但是外面还有很多。
对话状态跟踪
状态跟踪的发展可能是聊天机器人中最突出的话题。对于系统的状态跟踪器来说,准备一个有用的状态让代理采取接近最优的行动是非常重要的。如果重要的信息丢失了,比如用户的行为是什么,那么代理就很难很好的回复。此外,这些信息的编码方式以及是否有无用信息也会影响所采取行动的优化。这里有一些关于 ST: 剑桥论文、雅虎和对话状态跟踪挑战的资源。
高级 DRL 算法
虽然我找不到任何讨论这一点的论文或其他资源,但我尝试了更高级/不同的 DRL 算法,如 A3C、PPO、TRPO、ACKTR、基于模型的方法、基于混合模型的方法等。将是一个伟大的领域进行实验的围棋机器人!请记住,因为这段代码中的训练方法集中在使用内存和在特定时间刷新内存,所以新的训练方法必须伴随不使用内存池的算法(这是大多数算法)。
高级用户模拟器
目前有很多关于创建更像人类的用户模拟器的研究,因为这对于获得高质量的培训很重要。这里构建的用户 sim 是可靠的,但仍然可以大大改进。这篇论文用于构建真实的用户模拟人生。
复杂域
Hierarchical successor to TC-Bot
这里涉及的电影票领域是 GO 聊天机器人的一个实际用例,但仍然非常简单。在大多数情况下,问题的复杂性在现实世界中是上升的,在这里也是如此。面向目标的问题往往是复合的和分层次的,这意味着问题实际上是一堆必须完成的子问题。这篇论文解释了如何增强现有的 TC-Bot 框架,以允许完成更复杂的层次目标。这又可以添加到这里创建的代码中。
更多资源
用您目前所学的知识和编码进行实验!随着机器和深度学习的新功能,这个领域正在快速发展!
感谢您的关注,希望您能从这个系列和代码中获益良多!如有任何问题,欢迎随时评论!