【Nature / Google /论文摘要】利用电子健康记录进行可扩展的精确深度学习
GIF from this website
另一个很好的例子,或者深度学习如何使医疗保健行业受益。
请注意,这篇文章是让未来的我回顾和回顾这篇论文上的材料,而不是从头再看一遍。
摘要
使用电子健康记录(EHR)数据进行预测建模对医疗保健行业非常有益。然而,使用这些数据存在挑战,因为不同的医疗保健机构使用不同的格式,并且标准化所有这些数据是一个手动密集型过程,通常会丢弃许多患者数据。然而,这篇论文的作者使用原始 EHR 数据,并将其转换为快速医疗保健互操作性资源 (FHIR)格式,以训练深度神经网络来预测与患者相关的不同医疗状况。这导致了较高的准确性,特别是住院死亡率(受试者操作曲线下面积[AUROC]跨站点 0.93-0.94)、30 天计划外再入院(AUROC 0.75-0.76)、住院时间延长(AUROC 0.85-0.86)和患者最终出院诊断(频率加权 AUROC 0.90)。此外,他们总共使用了 46,864,534,945 个数据点。
简介
最近收集了越来越多的患者数据,不幸的是,并非所有这些数据都用于预测建模。发生这种情况的主要原因是因为数据需要大量处理,传统方法才能很好地工作。(此外,有如此多的数据,所以传统方法只从这些数据中选择几个公共变量。这可能会导致性能下降。).这篇论文的作者使用深度学习来克服这些问题。神经网络的一个优点是,研究人员不必指定要考虑哪些变量,因为网络本身会这样做。
相关工作
尽管我们有丰富的 EHR 数据集,但传统方法只使用 27 个变量的中位数。(而且多是广义线性模型。).另一个问题是,不同的机构使用不同的协议来保存数据,并且将这些数据预处理为规范化的数据需要大量时间。尽管它不能确保语义的一致性,但一种叫做 FHIR (快速医疗互操作性资源)的灵活数据结构变得可用。许多不同的研究人员使用不同类型的神经网络(自动编码器、CNN 和 RNN)来预测传统 EHR 数据的不同结果。但是,大多数先前的工作只集中在使用可用数据的子集。最后,作者指出了对世界的两大贡献。
- 一个通用的数据处理管道,可以将原始 EHR 数据作为输入,并在没有手动特征协调的情况下产生 FHIR 输出2)E深度学习模型在各种预测问题和设置(例如,多个预测时间)中的有效性。(使用两家医院的数据。)
结果
Table of Characteristics of hospitalizations in training and test sets
上表显示了从两个机构收集的数据的一些统计特性。作者指出的其他一些特性…
1)涉及 114,003 名患者的 216,221 次住院治疗的总数
2)住院期间死亡率为 2.3% (4930/216,221),非计划 30 天再入院率为 12.9% (27,918/216,221),长期住院率为 23.9%。
3)患者的出院诊断范围为 1–228。
4)平均入院有 137,882 个标记(将在方法部分描述)
5)考虑了出院时进行的 46,864,534,945 个 EHR 数据标记的预测。
结果:死亡率
在死亡率预测任务中,深度学习方法立即能够大幅度超越传统方法。如上所述,与增强预警分数相比,深度学习方法在两个机构上都具有更高的准确性。不仅拯救了宝贵的生命,也拯救了资源。
结果:再次入院/长期住院
同样,深度学习方法继续保持连胜,甚至预测了 30 天内的意外再入院,与传统预测方法相比有巨大的优势。
此外,对于预测入院 24 小时后的住院时间,深度学习方法再次以巨大的优势胜过传统方法。
结果:推断出院诊断
深度学习模型在三个不同的时间戳做出关于出院诊断的预测。(1 点在入院时,2 点在 24 小时后,3 点在医生给出诊断之前。)并且该模型能够以 86.5 的平均准确度成功地预测出院诊断,并且该准确度随着患者在医院停留的时间延长而提高。(高达 90 度)
结果:模型解释案例研究
完成了一个案例研究,作者将深度学习模型与传统方法模型进行了比较。对于一名患者,深度学习模型预测死亡风险为 19.9%,传统方法预测死亡风险为 9.3%。不幸的是,患者在入院 10 天后去世。上图显示了深度学习模型已经考虑进行预测的所有 175,639 个数据点。该模型对一些特征给予了很高的权重,这些特征包括来自 notes 的恶性胸腔积液和脓胸的证据、使用的抗生素和压疮高风险的护理文件(即 Braden 指数 41)。(上面加粗的部分是模型认为重要的所有特性。不涉及手动部分。)
讨论
作者对深度学习方法是否可以很好地扩展很感兴趣,所以他们使用单一的数据结构来进行所有的预测。(这优于传统方法。).这种方法一个额外的好处是,模型在做决策时考虑了更多的特征,这有助于获得更好的性能。
总的来说,深度学习模型能够优于预测死亡率、意外再入院和住院时间增加,由于设置的差异,其他领域很难直接进行比较。一个有趣的发现是,深度学习模型发出的警报数量是传统预测模型的一半,因为它的假阳性少得多。这项研究之所以重要的另一个原因是,它不涉及专家的干预。(选择功能时)
这项研究的一些局限性包括…
- 回顾性研究
2)需要更多的试验来证明这种模型如何更好地使用
3)个性化预测利用了许多特定于特定 EHR 的小数据点,而不是一些常见变量。
4)不清楚在一个地点训练的模型是否能在其他地点表现良好
5)计算成本高
6)由于 ICD-9 码的结构,可能会在预测中引入随机误差。
方法:数据集
所有数据均由加州大学和芝加哥大学医学系提供。(每个都有不同的时间线,所有的数据都被删除。)
方法:数据表示和处理
所有输入的数据都被转换成单一的数据结构,以模拟时间线事件,并使用 FHIR 标准数据结构。(所有数值都被归一化,FHIR 属性被分割成离散值,作者将其命名为令牌。)数据管线的图示可以在下面看到,更详细的解释可以在补充阅读中看到。
方法:结果
在这一节中,作者描述了他们所做预测的每一个属性,每一个属性都可以归纳为。
**住院死亡率:**预测即将发生的住院死亡
**30 天计划外再入院:**出院后 30 天内住院
**住院时间长:**住院时间至少 7 天
**诊断:**原发性和继发性 ICD-9 账单诊断
方法:队列研究
总之,患者年龄都在 18 岁或以上,住院时间最短为 24 小时,不包括没有 ICD-9 诊断的住院患者。,(自从医院制定了新的 ICD-10 协议)
方法:算法开发与分析
作者使用了三种不同的网络架构,循环神经网络(长短期记忆(LSTM)),80 一种是基于注意力的 TANN,另一种是基于增强的基于时间的决策树桩的神经网络。
方法:解释预测
更多的细节在补充阅读中,但简而言之 Tensorflow 和 C++被用来建立模型。和 scikit-learn 用于统计分析。
最后的话
我从来不知道通过使用 tensorflow 和 scikit-learn 我们可以完成多少工作。但是知道这篇论文(发表在《自然》杂志上)的作者使用 python 来构建他们的模型让我很兴奋。
参考
- (2018).Arxiv.org。检索于 2018 年 6 月 27 日,来自https://arxiv.org/ftp/arxiv/papers/1801/1801.07860.pdf
- 快速医疗互操作性资源。(2018).En.wikipedia.org。检索于 2018 年 6 月 27 日,来自https://en . Wikipedia . org/wiki/Fast _ health care _ inter operability _ Resources
- Anon,(2018)。[在线]可在:https://www.hl7.org/fhir/overview.html【2018 年 6 月 30 日获取】。
- 将生命体征转变为重要行动。(2018).飞利浦。检索于 2018 年 6 月 30 日,来自https://www . Philips . ca/health care/articles/early-warning-scoring-tools-for-rapid-response/turn-vital-signs-to-vital-action
- 回顾性队列研究。(2018).YouTube。检索于 2018 年 6 月 30 日,来自 https://www.youtube.com/watch?v=6jy8Q0bibgk
穿越数据隐私迷宫:给数据科学家的提示
决定如何最好地保护数据和隐私是很困难的。如果您是一名处理潜在敏感数据的数据科学家,这意味着确定您可以使用哪些数据以及如何最好地保护这些数据。这可能会导致您在失败中放弃——完全放弃并选择使用原始数据,这反过来会使您的数据分析和模型暴露于信息泄漏,并使它们容易受到攻击。
我们在ki protect的目标是尝试让这个过程对您来说更简单—您如何在专注于数据科学的同时还能确保您的数据受到保护?我最近在爱丁堡的 PyData 上给了一个关于这个的演讲——这启发了我写这篇文章(在 GitHub 上的完整幻灯片)。
我们将从概述您的困境开始:您是一名数据科学家,专注于使用客户数据分析或构建模型。您知道隐私和安全性很重要(理论上),但是您没有花太多时间考虑安全性,并且通常将它留给您的 IT 团队。也就是说,你知道你正在管理客户数据,你想做正确的事情**。**
那么,如何开始呢?我们将通过流程图探索您的旅行,因为——嗯——它们很有趣。当然,信息也很丰富。
你的第一选择是关于你的数据。最好的策略是一开始就不要使用任何敏感数据。让我们从这里开始:
所以,你可能会说——是的,我需要数据!很明显!但我真的希望你考虑一下。所以,我再问一次——这次用稍微不同的方式。
因为…我真的希望你考虑一下。如果你没有数据,你真的需要足够的数据去收集它吗?很多时候,拥有一些额外的数据或变量可能是件好事,但你并不真的需要它——或者你无法证明收集它的必要性。
现在,我在这一步得到了很多涉及未知的问题。它是这样的:“但是 kjam,我只是不知道是否需要它!如果后来发现,一个人名字的最后一个字符确实决定了他的信用度,那该怎么办?”(我们可以就这种类型的特征工程的伦理进行大量的讨论,但是我将把它留给另一篇文章)。
我要求你做的是像基线一样对待你最初的分析;就像你测试一个新的模型或技术一样。首先,您建立一个基线,这是您对隐私风险最小的数据进行的数据分析。如果你愿意的话,尽量少暴露。我保证你可以总是在以后添加数据回来。但是,根据您构建或使用分析的目的,稍后删除数据可能会很棘手。建立一个低隐私风险基线,并发现是的,你的数据有足够的信息,同时仍然保护隐私是最佳结果。因此,删除敏感数据的风险要小得多!
让我们进入流程图的下一步——假设您确定确实需要私人数据。让我们想想我们可以保护它的方法!
希望你不需要明确的私人信息,如姓名、地址或身份证号码。也许你想从这些属性中提取一些特征(比如,地理位置、性别或受教育程度)。只要有可能,首先尝试删除它们,并查看您的隐私基线对其他不太敏感的功能有何看法。但是,如果你已经确定你需要他们,继续前进到我们流程图的下一步…
如果您必须保留敏感数据,并且需要使用真实值(即邮政编码或城市或教育水平)。对于这些数据,确定 K-匿名是否有助于保护隐私。这个概念是由拉坦亚·斯威尼博士在她的论文k-匿名:保护隐私的模型 中首次提出的。在揭露马萨诸塞州州长威廉·韦尔德的健康数据可以通过将选民登记记录与“匿名化”的医院记录联系起来来识别之后,她提出了这一方法(这是在他声称健康记录发布将完全匿名化之后的)。
K-匿名通过创建桶来保护身份识别攻击,桶中的任何单个人都由一组 K 个人来代表。这意味着您实际上是在尝试缩小数据——使用城市而不是邮政编码或年龄范围(35-45)而不是实际年龄。这就允许了一些貌似合理的否认(确切地说,这不是我的记录——可能是我团队中其他 4 个人中的任何一个!).在研究 K-匿名时,还需要回顾一下l-多样性和t-亲密度,这有助于增强隐私——特别是如果你的小组有相当不平衡的目标或特征(即,一个小组中的所有个人都有相同的目标变量,因此知道小组暴露了目标)。
如果不需要保留敏感变量,使用同态假名化或合成数据将允许您保留数据集中的有效值,而不会暴露真实值。合成数据通常是仍然有效的虚构数据,所以虚构的名字代替真实的名字等等。这通常是不可逆的(或者,如果是这样的话,它通常被称为“令牌化”,并且需要有一个非常大的查找表,其中名称或其他数据被映射到不同的值,并且可以被映射回来。当然,这意味着名称被存储在一个大的查找表中…从安全性以及随着输入空间的增长而增加的大小和复杂性来看,这不是一个好主意。)
在 KIProtect,我们已经发布了我们的同态假名化 API ,它允许您在保护隐私的同时保留数据的某些有效性和结构。我们基于加密的方法意味着您还可以通过密钥对数据进行去假名化,以揭示真实值(如果您不确定以后是否需要真实值,这非常有用,因为您可以从假名化的值中恢复它们)。假名化方法允许前缀保留数据类型-例如,数据集中的所有年份都可以映射到同一个新年假名-保留那些日期或其他数据的信息,其中与附近点的关系是一个重要的功能(有兴趣尝试一下吗?注册我们的测试版 API 。
但是,假设您还不确定是否需要保留真正的价值…让我们通过流程图继续探索!
(I tease because I love)
同样,让我们关注基线用例。如果这只是为了研究或探索,请先使用化名或合成数据!同样,您可以在以后添加更多的信息——但是如果您在没有敏感数据的情况下获得有用的结果,那么您可以保护这些数据。
如果您不进行测试或研究,并且仍然需要使用私有数据,那么您的下一步就是开始研究如何安全地发布该数据分析或模型。让我们继续…
如果你正在发布一个基于敏感数据的机器学习模型,你应该知道保护隐私的机器学习——一个活跃的研究领域,旨在建立保护个人隐私(或来自机器学习服务或平台的数据隐私)的模型。在这个主题上有许多活跃的研究人员,包括尼古拉斯·帕伯诺特(目前在谷歌)、T2、SAP 莱昂纳多团队和 T4 新加坡大学的礼萨·肖克里教授等等。但是,如果您还没有在私有数据上训练您的模型(或者您已经事先对数据进行了适当的匿名化),那么您可以到这里来!(+1 用于隐私保护基线!)
如果你没有发布模型,而是展示数据分析结果,看看聚合匿名化——就像苹果差分隐私团队的表情符号研究。他们能够展示的是,差异隐私聚合结果仍然提供了足够的信息来做出产品改变——例如,预测法语键盘用户的亲吻脸表情符号和英语键盘用户的哭泣脸。
Apple Differential Privacy Team: Top Emoji Use by Keyboard Language
最后,假设您正在开发一个仅供内部使用的模型或数据分析,该模型或数据分析现在很流行,公司希望将其公开或与第三方共享。你如何着手保护它?
您的最佳策略是尝试通过采用相同的方法(隐私保护 ML 或聚合匿名化)来修复模型。这也指出了为什么拥有一个适当匿名(或在适用时使用假名)数据的基线是一个很好的起点。如果信息不属于隐私或敏感信息,那么您可以公开发布,而不必担心个人隐私受到侵犯。(您仍然应该考虑数据本身何时可能存在安全风险,例如最近的 Strava 运行地图显示了秘密军事基地,即使它不一定会造成个人隐私风险)。
如果您已经将基于私有数据训练的模型发布到生产中, 请 锁定您的 API,并与您的安全和工程团队讨论如何防止对模型的恶意访问。具有开放 API 的机器学习模型基本上就像在公共网络上有一个带有默认凭据的漂亮数据库,所以要采取相应的行动(想了解更多关于隐私风险和黑盒攻击的信息获取吗?参见 Shokri 的成员推理攻击论文)。
结论
我希望我已经让你笑了,哭了,并思考你当前的数据使用实践可能需要在数据隐私和安全方面进行一些调整。我在这里的目标不是公开羞辱你,而是给你一些导航提示和正确方向的帮助。
说到底,敏感数据就像辐射一样。你不想有长时间的暴露(或者任何可能的话),你想尽你所能来减轻不利影响,一般来说,少真的是多。像对待辐射一样对待您的敏感数据,您将从一开始就避免潜在的令人尴尬的泄漏和安全漏洞。
有关我们在 KIProtect 开发的数据安全和隐私解决方案的更多信息,请访问https://kiprotect.com查看我们的信息。我们的测试 API 可用于结构化假名化,我们还有一些其他保护隐私的数据科学工具,所以请随意注册并了解更多信息。
在数据海洋中导航:如何从数据中收获有意义的见解而不被淹没
正如最近一期《经济学人》杂志所指出的,“世界上最有价值的资源不再是石油,而是数据。”随着数字革命稳步改变我们的经济,我们正在产生创纪录数量的数据。据估计,在过去的两年中产生的数据比之前所有人类历史产生的数据都多。
尽管数据量之大无可争议,但是什么让数据如此有价值呢?首先,数据允许公司监控他们的表现,并将其与有意义的基准、竞争对手的表现或一般市场进行比较。其次,数据为了解客户的偏好、需求和行为提供了一个前所未有的窗口。
在一个运作良好的数据驱动型组织中,对公司业绩和消费者行为的洞察为决策者提供了做出更明智决策所需的信息,从而带来更高的投资回报(ROI)。事实上,经济学人信息部的一项研究发现,自称数据驱动的公司在财务表现方面比竞争对手高出三倍。
然而,正如未经提炼的原油用处不大一样,原始数据的用处也微乎其微。数据只有在能够从中提取相关见解的情况下才有价值。尽管数据驱动型公司正在市场上实现收益,但许多公司正在努力将数据洞察与决策有效整合。根据国际注册专业会计师协会(CGMA)发布的 2016 年对 16 个国家 300 名高管的研究,只有 27%的高管认为他们的公司“高效”利用了数据。与此同时,32%的高管声称,现在可用的数据浪潮实际上使事情变得更糟!
许多决策者(可以理解)被他们现在可以获得的大量信息淹没了。在他们的同名著作中,经验丰富的企业高管克里斯托弗·J·弗兰克和保罗·马格诺内将这种现象称为“从消防水管中喝水”决策者已经被一千个相互竞争的优先事项弄得捉襟见肘,他们如何利用数据的价值做出更好的服务客户的决策?正如《CGMA 报告》(第 13 页)所指出的:“高质量的决策从未像现在这样重要,也从未像现在这样困难。”
信息过载
虽然我们现在可以获得前所未有的信息,但这并不是我们人类第一次面临信息过载。事实上,早在智能手机和电脑发明之前,我们就已经面临着信息的洪流!即使我们今天设法抛开我们的数字工具,我们仍然会遇到比我们的大脑能够处理的更多的信息。
这些信息来自哪里?它来自我们周围的世界,通过我们的感觉器官:我们的眼睛、耳朵、鼻子、舌头和皮肤。我们的大脑不断受到感官信号的冲击。
世界上可用的信息比我们认知资源处理的信息多得多,比我们有意识处理的注意力资源更少。然而,不管怎样,我们必须通过一系列的决定在这个世界上闯出一条路来。我们该怎么做?
我们的大脑想办法缩小可用信息的范围,把注意力集中在最相关的片段上。
为了演示,看看下面闪烁的图像。这是两个图像之间的交替,它们之间有一个显著的区别。你能发现它吗?
你还在找吗?通常需要几秒钟,有时甚至几分钟才能发现差异。然而,一旦你发现了它,图像之间的差异似乎完全显而易见,很难不被发现!(如果你被卡住了,答案在这篇文章的底部。)
在心理学中,这种现象被称为变化盲视。这是我个人最喜欢的一幅插图,展示了有多少信息是我们意识不到的。即使当我们觉得我们正在吸收世界上大多数视觉信息时,我们有意识地处理的信息量实际上非常少。
大脑已经进化到可以通过 选择性过滤 来处理大量的感官输入。这意味着我们只关注一小部分信息,而忽略其他的。我们过滤掉不太可能重要的细节,以保存我们宝贵的认知资源。这样,我们就不会因为通过我们的感觉器官不断收到的大量信息而变得完全疯狂。
数据—第二次信息泛滥
尽管信息过载的现象可能并不新鲜,但我们现在正面临着第二种形式的信息过载。这一次,不是感官信息通过我们的眼睛、耳朵和其他感觉器官到达,而是信息以数字格式向我们袭来。我们已经进化了上亿年来处理感官信息,但只是在最近一二十年,我们才开始面对真正的数字信息浪潮。数据可能是新的石油,但我们如何利用它呢?面对数字信息的浪潮,决策者如何保持理智?
投资数据基础设施和人力资源(如分析师、数据工程师和数据科学家)是解决方案的一部分。然而,最终,为了让数据变得有用,它需要融入到决策中,这意味着任何处于决策角色的人都需要能够访问和利用数据洞察力。这意味着决策者需要不再问“我如何使用所有这些信息?”到问“什么信息是重要的,什么是可以忽略的?”换句话说,我们如何对数据进行过滤,找出对我们真正重要的东西?
在他们的书《从消防水管中喝水:在不被信息淹没的情况下做出更明智的决策》中,克里斯托弗·弗兰克和保罗·马格诺内建议决策者从问自己开始:“什么是最基本的商业问题?”
“把这个问题想象成数据软管上的一个阀门,或者一个过滤器。它让你掌控一切。它控制着你收集和处理数据的速度、流量和方向,甚至有助于决定你如何交付数据。”(Ch。1,标准杆。3)
人类产生的数据量已经高得惊人,估计每年增长 40%。随着数字革命的不断发展,每个公司都变成了数字公司。与此同时,组织仍在想办法准确地利用突然出现的大量信息。
存储数据不够。从数据中获得最大优势的组织是那些知道他们需要什么信息以及如何利用这些信息的组织。从基本问题开始,决策者可以对他们的数据进行选择性过滤。这意味着他们仍然掌握着主动权,用数据提供的强大洞察力推动他们的决策。
(变化盲演示答案:其中一张图片上,飞机机翼下少了一个喷气发动机)。
原载于www.heatherelizabethmann.com。
reddit 评论的 Net upvote 预测和基于 subreddit 的句子完成:
从互联网首页构建的模型
这个项目是由里沙布·拉伊、贾扬特·谢诺伊、陈亦飞、王巍和 Shruthi Krish 完成的
Photo by Brett Jordan on Unsplash
作为互联网上最受欢迎的网站之一,Reddit 是一个信息宝库。自 2005 年成立以来,Reddit 记录了世界各地人们就任何可以想象的话题进行的互动。
这些互动可以以评论的形式出现,每条评论都得到了用户的评分,用户要么投票赞成,要么投票反对。评论是按文章分组的,但是它们更一般的领域是由它们所在的子编辑指定的。
目标
因为 Reddit 用户既是网站的消费者也是贡献者,贡献者的用户体验是 Reddit 发展的关键。写评论时更好的体验会鼓励 Reddit 上更多的互动,我们的目标是通过模型的组合来创建这一点。
Redditors 非常重视他们的因果报应,这是通过向上投票获得的。通过创建一个预测净投票数的模型,我们可以帮助评论者更好地了解他们评论的预期质量。此外,由于子编辑的多样性,通过创建基于子编辑变化的句子完成系统,我们可以帮助用户更快更容易地做出贡献。
使用由 redditor 创建的优秀的累积评论数据集,我们能够创建评论模型。
构建净向上投票回归器:
为 Reddit 评论构建一个净 upvote 回归器的过程涉及训练许多不同的模型,以找到哪一个模型能够根据特征最好地预测 upvote 计数。
数据集
完整的评论数据集包含了自 2005 年以来 Reddit 上的所有评论。由于处理如此巨大的数据量(数百千兆字节的文本)超出了我们的资源范围,我们将训练集和测试集分别限制在 2018 年 2 月 1 日和 2 日的评论。每天的数据集包含超过 300 万条评论的数据,在删除无效数据后,我们分别剩下 280 万和 240 万个训练和测试示例。虽然我们更希望有更多的数据分布在一段时间内,但每组的大量数据使我们能够相当确定我们的
特征工程
让我们来看看数据集中存在的要素,以及我们可以从中获得什么:
作者
我们认为对作者姓名的句法或语义解释都不会产生有用的特征。虽然我们考虑了“一次性”账户的存在,这是一个临时的账户,往往有着莫名其妙的用户名,但不管是不是一次性账户发表的评论,都不太可能对它获得多少赞成票产生影响。同一个作者可以对各种主题发表评论,所以作者的用户名很可能与评论的内容无关。如果我们要考虑作者评论的历史以及它们有多成功,我们也许能够使用这些信息,但是由于缺乏时间和计算资源,这样做是不可行的。此外,包含此类信息很有可能会导致噪音(因为在实践中,以前评论的受欢迎程度对新评论的受欢迎程度影响很小)或导致模型对很少或没有评论历史的用户有偏见。
作者 Cakeday
用户的生日也绝对与他们的评论获得多少支持票无关。
作者风格 CSS 类和作者风格 CSS 文本
author flair css 类和文本引用与子编辑相关的标签。这些 flairs 向具有领域知识的 redditors 提供信息,并且它们通常需要领域知识来创建。在一个简单的例子中,在 NBA subreddit 上,flair 可以将用户标记为某个球队的球迷。在下面来自 r/TheLastAirbender 的例子中,尽管对任何人来说,第一个用户是一个名叫亚纱美的人的粉丝是显而易见的,但是只有具有领域知识的用户才会理解第二个用户是一只巨大的狮子龟的粉丝。
有天赋
虽然 flair 的实际语义可能不一定与评论的成功相关,但是它的存在意味着用户在这个子编辑上更活跃,并且具有更丰富的领域知识。这种领域知识可能意味着更高质量的评论更有可能获得更多的投票。
正文
注释的主体是指它的实际文本内容。这是最重要的功能,因为它是 upvotes 的来源,许多功能可以从它设计出来。
感悟
使用 NLTK VADER 图书馆,我们确定了评论中积极、中立、消极和复合情绪的数量。评论的情感极性可能是其成功的一个强有力的指标。
用户提及次数和子编辑提及次数
我们分析了评论主体中提到的其他用户或子编辑,因为将投票者引向外部来源可能会鼓励或阻碍投票。
Reddit 链接数量和外部链接数量
外部内容或其他 Reddit 内容的链接数量可能意味着更多的回复,因为有用的重定向,或者更少的回复,因为垃圾广告。不管怎样,这两个特性都是有用的,所以我们为它们解析了主体。
可读性
我们使用 textstat 库来确定每个注释的可读性,该库包含一个度量,它是各种标准可读性度量的集合。这样做可以让我们对一篇文章的可读性达成共识,尽管有各种各样的可用指标。
大写比例
大写字符占帖子总字符数的比率可以作为评论兴奋度或紧迫性的衡量标准。高比例也会吸引评论的注意。
长度
一篇文章的长度是读者首先注意到的方面之一。它经常作为一个评论是否会被阅读的决定因素,所以值得把它作为一个特性包含进来。
毒性
有毒和煽动性的评论可能会引起争议。至少,他们获得了回应。为了确定毒性,我们尝试对数据集应用预先构建的模型,但缺乏必要的计算资源迫使我们暂时跳过这一功能。
问题数量
评论主体中的问题越多,对评论的回应可能越多,因此可能是投票上升的指标。
Doc2Vec 嵌入
A training comment along with semantically similar comments determined by Doc2Vec
In this word cloud of the above example, we can see what these comments have in common
到语义空间的映射对于决定评论的成功是至关重要的。这可以使用 Doc2Vec 来完成,它将文档的语义表示为嵌入向量。Doc2Vec 通过在学习单词嵌入的同时添加文档标签,然后创建指定维度的文档嵌入,将文档映射到语义空间。我们从训练 dm 模型开始,该模型创建大小为 300 的嵌入向量,训练超过 125 个时期。虽然这个模型是准确的,但是所有评论的向量数据的庞大规模对我们的资源来说是太多了。结果,我们在 50 个时期内训练了新的 50 维嵌入模型。这个模型足够小,我们可以用它来进行预测,而且,在定性地检查了一些例子之后,看起来嵌入的整体准确性并没有受到太大的影响。从二维角度来看 Doc2Vec 嵌入,我们可以看到流行评论的集群。这可能是由于共同的语义,但它很可能只是某些子记录上更多活动的结果。
镀金
一条被镀金的评论在 Reddit 世界被赋予了一定的金额。我们放弃了这一功能,因为它是在发表评论后确定的,并且在他人发表评论前不可用。
可以镀金
这是指一个评论能不能镀金。因为镀金的评论在一个帖子上有更多的曝光和推广,一个可以镀金的评论有机会成为镀金的并获得更多的投票。
争议性
有争议的评论是那些有很多赞成票和反对票的评论。我们放弃了这个特性,因为它是在评论获得投票后确定的,因此不能用于进行预测。
创造了 UTC
我们决定放弃创建时间,因为尽管 Reddit 拥有庞大的北美用户群,但它在国际上得到广泛使用。这意味着一天中发表评论的时间可能是噪音,而不是成功的标志。此外,我们只有一天的数据,所以我们不能尝试使用日期作为区分因素。
被粘住
一个粘贴的评论被钉在了帖子的顶部,这导致了更大的曝光率和更多的投票。然而,由于评论在发表后可能会被其他用户粘贴,我们不能将此用作预测功能。
尊贵的
杰出评论当版主发表评论时,在用户名旁边添加一个“[M]”。因为区分对评论的排名没有影响,标签也没有像天赋一样给路人提供任何洞察力,所以评论是否被区分不太可能影响它的成功。
已编辑
因为编辑过的评论可能意味着该评论已经获得了关注,并且因为编辑过的评论可以被视为新的评论,所以编辑过的特征可以被用作未来成功的指示器。
是提交人
被批准的提交者被允许发布任意多次,这意味着这个人有相当多的评论经验,可能会获得更多的支持票。
永久链接
永久链接是评论的链接。它包含文章的标题。
帖子标题
我们从链接中提取标题,并使用字典来修复最初有撇号的单词(缩写不能是 url 的一部分)。虽然我们计划将 Doc2Vec 模型应用于这些标题,并计算标题嵌入与注释嵌入的余弦距离来确定相关性,但由于时间限制,我们无法完全实现该功能。
题目是问题
回复一个问题的评论可能会得到更多的支持票,但是唯一确定的方法是把这个作为从文章标题中提取的一个特征包括进来。
得分
这个作为标签,所以肯定是需要的。
子编辑
使用 Viterbi 算法进行单词分割,我们分割子编辑名称中的组合单词,以创建可以应用 Doc2Vec 模型的文档。同样,目标是计算评论与子编辑的相关性。然而,由于时间限制,我们无法完全实现这一功能。
检索于
检索到的日期和时间对于确定我们估计净 upvote 计数的时间段非常重要。训练集的周期为 11 天,而测试集的周期为 15 天。我们不认为这是预测评估中的一个大问题,因为天数的小差异对 upvotes 没有什么影响(因为评论可能在其存在之初获得大多数投票),特别是考虑到 Reddit 内容经常在几年内发挥作用。
ID、链接 ID、父 ID 和子编辑 ID
评论的 id 肯定和它的成功没有任何关系。
The correlation heatmap
构建和评估净增加投票回归器
在为我们的模型调整超参数时,为模型评分确定一个好的评估标准非常重要。基于训练数据的分数分布,绝大多数评论的上票数很少,这意味着数据是向右倾斜的。因此,使用某些回归评估指标,如 RMSE,对大错误给予高权重,可能会导致偏向高票数的评论。从 Zillow housing price kaggle 竞赛中汲取灵感,该竞赛涉及一个具有类似右偏数据集的回归问题,我们决定使用平均绝对误差(MAE)作为评估指标,因为它不会对无关评论产生偏见。
超参数调谐
上述梯度增强树模型的超参数调整是构建 upvote 预测器最耗时的方面。模型的调优是在使用 40GB RAM 和 GPU 的 google cloud 实例上完成的。我们尝试了几种不同的技术来优化我们的模型参数。在参数调整时,所有模型都使用 4 倍的训练集进行交叉验证。
使用超点的贝叶斯优化
超视是一种通过统计方法搜索参数空间的复杂方法。通过智能随机抽样,我们能够使用 HyperOpt 来适当地最小化梯度增强树模型的平均绝对误差。
随机搜索 CV
为了对我们的贝叶斯优化搜索结果进行健全性检查,我们还进行了随机搜索,以了解最佳匹配的大概值。
使用 XGBoost 的梯度增强决策树
动机
梯度推进决策树通常在表格数据的实践中工作得很好(正如它们在许多涉及回归的 Kaggle 竞赛中的成功所证明的那样),所以我们决定从梯度推进树构建几个不同的模型。我们首先将 XGBoostRegressor 调成默认模型。在训练模型之前,所有的分类特征都是一次性编码的。
输入特性
- 能镀金
- 编辑
- Is _ 提交者
- 积极情绪
- 中性 _ 情绪
- 消极情绪
- 复合 _ 情绪
- 用户提及次数
- 数量 _ 子编辑 _ 提及次数
- Has_flair
- 数量 _ 外部 _ 链接
- 数量 _reddit_links
- 标题是问题
- 可读性
- 大写 _ 比率
- 长度
- 所有 Doc2Vec 载体
Credit: http://arogozhnikov.github.io/2016/06/24/gradient_boosting_explained.html
结果
虽然 XGBoost 总体上表现不错,但是我们的 XGBRegressor 模型是这个场景中最差的模型。该模型的损耗计算为 12.34 CV MAE,测试 MAE 为 12.34 CV MAE。测试预测的散点图如下所示。预测的 upvote 值范围从-200 到 2000。根据散点图,该模型似乎对现实中得分较低的评论过高地给出了许多分数。
使用 CatBoost 的梯度提升决策树
动机
CatBoost 是 Yandex 开发的梯度提升树模型,它为分类特征提供输入。在训练之前,CatBoost 应用一种复杂的算法来正确编码指定的分类特征。因为我们的训练数据具有一些可能会给 XGBoost 模型带来问题的分类特征,所以我们尝试构建一个 CatBoost 回归器来更好地处理这些特征。在模型被训练之前,所有的分类特征都被 CatBoost 编码。
输入特性
- 能镀金
- 编辑
- Is _ 提交者
- 积极情绪
- 中性 _ 情绪
- 消极情绪
- 复合 _ 情绪
- 用户提及次数
- 数量 _ 子编辑 _ 提及次数
- Has_flair
- 数量 _ 外部 _ 链接
- 数量 _reddit_links
- 标题是问题
- 可读性
- 大写 _ 比率
- 长度
- 所有 Doc2Vec 载体
结果
与 XGBoost 模型相比,结果明显更好。与 XGBoost 的预测不同,CatBoost 预测值的范围要小得多。因此,该模型无法预测任何得分极高的外围评论。尽管如此,模型的损失被计算为 8.32 CV MAE,测试 MAE 为 8.32 CV MAE,表明分类特征的专门编码是朝着正确方向迈出的一步。基于模型的特征重要性分数,分类特征 has_flair 似乎对模型具有最大的影响,而 can _ guilded 和 edited 甚至没有被考虑。现在我们有了两个有趣的特征重要性图,是时候开始移除可能增加 MAE 的噪声特征了。
神经网络
动机
有了云实例和从梯度增强树多样化的愿望,我们决定尝试几个基于神经网络的模型。我们最好的一个涉及下面的架构,一个密集的顺序网络,有 67 个单元的输入,两个各有 50 个单元的隐藏层,使用 ReLU 激活函数,以及一个线性激活的最终输出层。对于培训,我们使用了 Adam 优化器和 MAE 评估指标。
此外,我们决定尝试通过删除某些不太适合神经网络的特征来减少以前模型中的模型噪声,这些特征在以前两个模型的特征重要性方面得分较低。
输入特性
- 积极情绪
- 中性 _ 情绪
- 消极情绪
- 复合 _ 情绪
- 用户提及次数
- 数量 _ 子编辑 _ 提及次数
- Has_flair(编码)
- 数量 _ 外部 _ 链接
- 数量 _reddit_links
- 标题是问题
- 可读性
- 大写 _ 比率
- 长度
- 所有 Doc2Vec 载体
结果
非常令人惊讶的是,神经网络产生了比预期好得多的结果。我们只能训练它几个时期,这可以通过下面的学习和验证曲线清楚地看到。该模型仍然没有完全收敛于我们为其训练的几次迭代,但它仍然设法获得了 7.27 的 CV MAE 和 7.17 的测试 MAE,因为总体曲线趋势保持不变。不同寻常的是,根据散点图,预测值的范围变得更小了。尽管我们最初选择 MAE 作为评估标准,但是这个模型似乎偏向于高值的评论。然而,似乎移除我们生成的一些特征有助于减少模型中的噪声。
4。混合合奏
The goal model
动机
对于我们的最终模型,我们希望尝试一些具有强大预测能力的东西,希望进一步降低我们的 MAE 测试分数。本质上,我们设计的模型是梯度增强树和 4 重组合序列神经网络的 4 重组合。来自这些主要模型的预测将由 supervisor XGBoost 回归器模型进行堆叠和预测,该模型将返回最终的得分预测集。我们设计这个主管模型的思考过程是结合我们以前调整过的模型的好与坏,看看结果会如何结束。
输入特性
- 积极情绪
- 中性 _ 情绪
- 消极情绪
- 复合 _ 情绪
- 用户提及次数
- 数量 _ 子编辑 _ 提及次数
- Has_flair(编码)
- 数量 _ 外部 _ 链接
- 数量 _reddit_links
- 标题是问题
- 可读性
- 大写 _ 比率
- 长度
- 所有 Doc2Vec 载体
结果
不幸的是,虽然我们能够完全编码我们的集合模型,但我们的计算能力阻止了我们实际训练模型。在神经网络和 CatBoost 模型的 k 倍训练阶段,我们的 google cloud 实例 GPU 不断耗尽内存。我们尝试了几次实验,但是在云服务器上训练失败的结果是一致的。
最终预测结果
上面我们可以看到我们得到的结果的比较。当我们用以前的经验来指导我们的努力,尝试新的模型时,我们看到我们的误差稳步下降。我们相信成功地实现目标模型将会延续这一趋势,并且我们的目标是在未来使用更多的计算资源来实现这一目标。
为不同的子编辑创建预测键盘
为了创建一整套工具供 Reddit 用户在评论时使用,我们为不同的子编辑构建了一个定制的预测键盘。一般而言,预测键盘观察过去的打字习惯和词汇使用以及当前的上下文,以估计哪些单词具有被键入的高可能性,并向用户建议这些单词。
预处理
在大多数自然语言处理问题中,第一步是处理文本以消除任何字符噪声。在我们的例子中,我们决定采取一种不干涉的方法,尽可能少地修改文本,以保留尽可能多的来自评论的信息。无论如何,一些语法元素,如标点符号和大写字母增加了更多的噪音,所以我们决定删除它们。
除了典型的预处理,我们还面临生成合适语料库的更新颖的问题。大多数 NLP 模型需要一个语料库来进行训练,因此模型可以首先了解文本中可能存在的模式。在我们的例子中,原始数据来自数以百万计的不同评论,而不是一个集中的语料库,所以我们必须从现有的数据中生成自己的语料库。为此,我们决定简单地将所有注释附加在一起,同时使用特殊的定界字符来区分不同的注释。
有了所有可用形式的数据和对预测键盘如何工作的简单理解,我们决定直接开始实现我们的第一个基于马尔可夫链的模型。
马尔可夫链模型
马尔可夫链模型似乎很适合我们的问题,因为它可以通过 n 元语法考虑单词的上下文,并通过记忆单词出现的概率来跟踪过去的历史。马尔可夫链可以被认为是有限状态机,其中每个状态都有一定的概率根据过去的历史转移到其他阶段。当应用于文本时,这意味着每组单词都是一种可能的状态,所有的边都是基于下一个单词出现的概率形成的,如下所示。对于我们的模型,我们决定在分离句子时使用二元语法,因此我们不是查看单个单词,而是一次查看两个单词,这允许我们考虑某些单词的上下文,同时不会使我们的训练数据过于稀疏。
在对我们的数据训练马尔可夫模型后,我们发现它非常善于生成大量可读的文本。这个模型的性能特别快,因为它只需要一遍所有的数据就可以记住所有的概率。这个模型能够接受非常短的起始短语,并能够从中推断出很多。例如,当在 subreddit r/Fitness 上训练模型时,我们让模型继续生成单词,直到它认为评论应该结束,从单词“我是”开始生成以下 commnet:“我倾向于认为你不可能每天都全力以赴而没有任何肌肉损伤”。
乍一看,这似乎很完美,但是仔细观察,这个自动生成的评论揭示了我们模型的一些主要优点和缺点。一方面,注释可读性很强,更重要的是,它符合 fitness 子编辑的上下文,因此我们的马尔可夫链似乎能够非常有效地生成特定于子编辑的注释。然而,我们理想的用例应该更多地关注建议更短的短语或单词,并高度准确地符合用户的期望。因此,如果我们再次运行这个模型,但在一个单词后停止,我们将得到短语“我倾向于”。这个短语在语法上可能非常好,但它实际上可能不是太准确的预测,因为单词“倾斜的”实际上可能不会经常跟在短语“我是”后面。当然,完美地预测下一个单词基本上是不可能的,特别是考虑到我们只有两个单词可以脱离上下文。这个问题的一个解决方案是使用一个更好地考虑上下文的模型(我们稍后使用 LSTM),另一个更直接的解决方案是将更多的数据输入到我们当前的模型中。我们决定尝试第二种方法来提高我们的准确性,只尝试在键入单词的中途预测单词,因此使用与前面相同的示例,如果用户已经键入了“我是公司”,我们将只预测“我倾向于”。为了得到这个想要的效果,我们需要修改我们的马尔可夫模型,使之基于角色。
这是一个极端的变化,因为这意味着我们不再预测单个单词,而是着眼于字符。作为其中的一部分,我们还决定一次将 4 个字母组合在一起,以获得更具可读性的文本。这让我们得到了我们想要的中间词预测,但它也带来了糟糕透顶的句子,甚至连合适的词都很少见。我们认为这是由于模型过于天真,在解释环境方面不够好。因此,我们决定重新考虑我们的第一个解决方案,寻找一个不同的模型,更好地考虑环境。
我们如何改进马尔可夫模型——神经语言建模
让我们想想人类是如何处理和解释句子的。人类通常从左到右浏览文本,在每个单词之后获得文本内容的一些上下文,直到到达结尾;因此,我们逐渐理解了整篇文章。鉴于这是人类阅读和理解句子的方式,我们可以获得一些关于人类如何预测给定单词的句子中的下一个单词或字符的见解:我们从句子开头的单词开始阅读并积累信息,直到我们到达结尾,然后给定这些单词的上下文,我们可以确定接下来什么是有意义的。递归神经网络(RNNs)背后的思想非常相似。
在其他神经网络中,网络的输入被认为是相互独立的。例如,您的标准多层感知器(MLP)或前馈神经网络通过神经元传递输入,神经元对模型的输入执行一些数学功能。通过训练这些模型,你可以对这些输入进行数学运算,看看你有多差,然后通过一个称为反向传播的过程,重新调整网络中神经元的权重。这对于一些用例来说很好,然而,在自然语言处理中,我们的输入通常不是相互独立的。过去的输入可以帮助我们识别当前输入的更好输出,这正是 rnn 试图做的:利用顺序信息。
递归神经网络是递归人工神经网络的变体,其中神经元之间的连接进行定向循环。它的输出不仅取决于当前的输入,还取决于先前步骤的状态;这种记忆使网络能够更好地处理先前输入的上下文很重要的问题。这个属性是使 RNNs 成为处理自然语言处理问题的非常强大的工具的关键因素,我们将尝试使用 RNNs 来创建更好的预测键盘。
LSTM 基于角色的模型
考虑到这些结果,我们决定尝试开发一个新的模型,它可以匹配 subreddit 行为,同时还引入了中词预测。最初,我们试图简单地将我们的马尔可夫链模型转换成基于 ac 字符的模型,这导致了糟糕的结果,因为该模型不够复杂,无法从它预测的字符中生成真实的单词。
因此,我们创建了一个长短期记忆(LSTM)递归神经网络。常规递归神经网络遭受消失和爆炸梯度问题,因此它们很少在实践中使用。相反,我们使用了 LSTM 递归神经网络(如下所示),该网络使用门来流动梯度并减少消失梯度问题。
图片取自 Colah 的博客
假设我们的数据是来自子编辑的注释,我们需要以一种特定的方式格式化数据,这种方式很好地与神经网络一起工作。将每个注释作为字符串数组传递在神经网络中并不合适,更好的方法是将它们表示为分类特征或数字特征。在我们的字符 LSTM 的例子中,我们首先创建一个字符到索引和索引到字符的映射,稍后我们将使用它对我们的序列进行一次热编码。我们还记录了字符集的大小,大约有 200 个不同的字符。
接下来,我们需要将我们的注释映射到 LSTM 可以接受的某种表示。为此,我们可以为整个文本创建长度为 40 的字符序列。当我们创建这些序列时,我们为序列中的每个字符创建一个 hot 编码向量来表示每个字符。这是有用的,因为神经网络通常对于具有分类特征的多类分类表现良好。创建完这些序列后,我们剩下一个三维矩阵(我们的 X):第一维表示序列号,第二维表示序列中的字符,第三维是表示特定字符的一键向量。在我们创建序列的同时,我们创建了下一个字母矩阵(我们的 Y)。对于序列 N,我们给出了字符 1 到 30,我们试图预测 Y,也就是字符 31。我们的 Y 数组应该是一个二维数组:第一维表示序列号,第二维是一个表示我们的模型试图预测的特定字符的一键向量。
然后,我们创建用于预测输入序列的下一个字符的模型。我们使用大小为 128 的 LSTM 层的 Keras 序列模型,进入大小为我们字符集大小的全连接密集层,最后我们将这些结果放入 softmax 激活层,以输出其奇异真实指数代表我们试图预测的字符的 one hot vector。我们使用 RMSprop 优化器(通常适用于递归神经网络的优化器)编译该模型,学习率为 0.01,损失函数为 categorical _ crossentropy(适用于多类分类中的神经网络)。我们将该模型拟合到上述 20 个时期的 X 和 Y 矩阵,并观察下面的精度和损失。
我们可以看到,对于我们的验证数据,我们的模型可以实现大约 0.55 的准确性,而损失大约为 1.9。这意味着给定一个长度为 30 的字符序列,模型有 55%的机会正确猜测序列中的下一个字符。对于我们在/r/2007scape 上训练的模型,它表现得相当好,因为它可以学习一些只在那些特定子编辑中使用的单词。例如,给定一个输入序列“Old School Runesc”,我们的模型可以预测[“cape”、“hools”、“ores”、“scenity”、“and”],这将使预测成为“Old School Runescape”。这突出了我们的模型与马尔可夫模型相比的一些优点和缺点:我们的模型现在能够在给定过去上下文的情况下以相当高的准确度预测不完整的单词。然而,给定非常模糊的上下文,例如“O”,我们的模型预测[“One”、“Other”、“Ore”、“Oin”、“Oent]],向我们显示我们的模型不能保证给我们有效的单词。此外,如果我们给它的序列已经有了完整的单词,我们的模型也不能很好地工作,例如“我想吃饭”给我们的输出是[“tion”、“h”、“the”、“er”、“o”],所以我们的模型实际上并不知道完整的单词,也不真正理解语法的概念。下面是我们为演示我们的模型而构建的 web 应用程序的快速浏览。
总之,我们的模型对于需要自动补全成在子编辑中使用但不在其他地方使用的词(例如游戏城市、老板、怪物等)的不完整的词工作得很好。).然而,对于预测下一个单词,我们的模型表现不佳,因为它没有真正理解单词/语法的概念,因为它是在字符而不是单词上训练的。接下来,我们将提出一个可以很好预测下一个单词的模型。
LSTM word2vec 嵌入模型( 演示此处 )
我们之前的字符神经语言模型在预测不完整单词和特定于子编辑的单词方面工作得很好。但是,有没有一个模型在预测单词时表现更好,符合语法规则的方法呢?现在,我们尝试创建一个模型,该模型使用 LSTM RNNs 和单词嵌入模型来预测给定单词序列的单词。同样,我们使用 LSTM rnn 而不是常规 rnn,因为它们能够处理消失和爆炸梯度问题,并且因为我们试图使用序列特征进行预测。
在我们开始尝试之前,回顾一下单词嵌入会给模型带来什么好处是很重要的。单词嵌入是将字符串转换为向量的过程。这个过程包括在数学上将每个单词的一个维度嵌入到一个更低维度的连续向量空间中。这允许我们减少“维数灾难”,因为一个单词词汇集的热编码可能导致词汇集长度超过十万。具体来说,我们探索了使用 Word2Vec,这是一个为每个唯一单词创建唯一单词嵌入向量的模型。Word2Vec 的特殊之处在于,它生成的单词向量的位置使得在语料库中共享共同上下文的单词在向量空间中彼此靠近。我们试图为我们的模型利用这个属性,因为我们认为 Word2Vec 向量捕获的上下文将为模型提供更多的上下文,从而提高模型的输出。下面是由 Word2Vec 模型生成的单词嵌入的可视化。
我们的输入仍然是相同的单词集,所以我们需要将这些数据转换成我们的模型可以接受的东西。我们首先将语料库标记为字符串数组,然后创建并训练一个 gensim Word2Vec 模型。在训练我们的模型之后,我们通过创建类似的三维数组(我们的 X 矩阵)在整个数据集上创建我们的 30 个单词长的滑动窗口序列:第一维仍然表示序列号,第二维表示单词序列,第三维表示单词(通过在 Word2Vec 模型中查找单词并使用单词嵌入)。我们还创建了一个表示 Y 矩阵的二维数组:第一维表示序列号,第二维表示我们试图预测的单词(作为单词向量)。
我们使用的模型非常类似于我们基于字符的神经语言模型。我们使用 Keras 序列模型,该模型使用大小为 128 的 LSTM 神经网络层,进入大小为我们的 Word2Vec 输出维度的完全连接的密集层,最后我们输出结果。我们用学习率为 0.01 的 AdamOptimizer 编译了这个模型,损失函数为 mean_absolute_error。我们用 X 和 Y 拟合这个模型 150 个时期,看看我们得到什么结果。
不幸的是,我们模型的结果相当糟糕。在我们将模型的结果转换回单词后,我们看到我们的模型一直输出一个或两个它认为最正确的单词。鉴于我们在网上看到的例子,我们认为我们的模型是不适合的。如果有更多的时间和资源,如果我们继续训练这个模型,我们相信这个模型会输出可以转换成实际单词的单词嵌入,并且应该是语法正确的。
结论
我们这个项目的目标是改善 Reddit 上的评论体验。使用 redditor 创建的数据集的一天评论,我们构建了两个不同的模型来帮助用户进行评论。我们项目的第一部分是创建一个向上投票预测器。顺序神经网络预测器是我们设法完全创建和训练的最佳模型;它在测试集上的平均绝对误差为 7.17。我们项目的第二部分是生成特定于每个子编辑的预测键盘。在整个过程中,我们一直面临的一个问题是数据量超出了我们的管理能力。
后续步骤
子编辑预测键盘改进
为了创建最佳模型,我们将用更多的资源和时间来完成我们的单词嵌入神经语言模型的训练。然后,我们将结合我们的字符语言模型和单词嵌入模型来创建一个自动完成键盘,它可以预测您正在键入的当前单词,并根据您刚刚键入的单词的上下文给出下一个单词的准确建议。这种模式更类似于 Gmail 新的智能撰写功能。创建更准确的模型的另一个考虑是尝试 seq2seq 模型,该模型使用两个 LSTM,一个 LSTM 用于编码当前上下文,另一个 LSTM 用于解码该序列,并在给定编码器权重的情况下生成预测。在谷歌的 AI 博客上,我们发现谷歌考虑使用 seq2seq 模型,但其性能太慢。然而,他们发现 seq2seq 模型具有更好的准确性,因此如果我们对单词嵌入神经语言模型的准确性不够,我们也可以考虑使用该模型。训练该 seq2seq 模型的计算复杂度高于训练单词嵌入神经语言模型,因此在实践中这可能是不可行的。
向上投票预测器
在改进 upvote 预测模型时,有许多方向可以探索。乍看之下,几乎可以肯定,我们尝试的所有模型的超参数都可以改进。如果我们能够以某种方式克服训练模型时遇到的 GPU 内存问题,那么将模型输入基于 XGBoost 的管理模型几乎肯定会带来改进。探索不同的神经网络架构也可能是有用的,特别是因为嵌入可能需要与独立特征区别对待。由于缺乏计算能力和/或时间,我们不得不放弃一些特性,在模型的下一次迭代中包含这些特性会非常有帮助。不管我们采取什么步骤,我们无疑都需要获得更多的计算资源。
组合模型
虽然这两种模式可以分别帮助 Redditors 改善用户体验,但一种组合模式可以为用户做更多的事情。upvote 预测器可用于测量评论的预计质量,并且该信息可被输入键盘用于帮助提高评论质量的完成。这对贡献者和消费者来说都意味着更好的体验。
网飞和希尔:在 Excel 中构建推荐系统
学习狂欢背后的机器学习“魔法”
在网上无限的货架空间里,找到你想看的东西可能会让人精疲力尽。幸运的是,对抗决策疲劳是网飞的工作……他们擅长这个。太擅长了。
他们神奇地给你推荐最完美的电影,让你的眼睛盯着电视,他们把你的拖延症变成沙发上的周末大餐。
该死的网飞。你的秘诀是什么?你怎么这么了解我们?
Netflix wins again…
这个“魔术”出奇的简单,在这个教程中,你可以下载 Excel ( 推荐)或 Google Sheets ( 计算速度较慢)的一步一步的电子表格来揭示其中的秘密;由于兼容性缺少 1 张图,请跟随以提高您的学习效果:
https://drive.google.com/open?id = 1y 4x 8h 56 ts 6m 7 axau 7 yim 0 eyxhqnuy1sz
尽管自 Netflix 奖项竞赛以来,有大量关于推荐系统的论文或视频,但大多数要么(A)太专业,初学者无法接触,要么(B)水平太高,不实用。
在这篇文章中,我们将从头开始建立一个电影推荐系统,用简单的英语解释和一步一步的公式,你可以在 Excel 中遵循。所有梯度下降推导都是手工完成的,您可以使用 Excel 下拉过滤器来微调模型的超参数,增强您的直觉。
您将了解到:
- 构建帮助赢得 100 万美元网飞奖的算法版本 SVD++背后的确切步骤。
- 机器实际上是如何学习的(梯度下降)。看着网飞了解你的电影品味,即使你从未告诉他们。
- **超参数调谐。**查看如何调整模型输入(学习率、L2 正则化、历元数、权重初始化)以获得更好的预测。
- **模型评估&可视化。**了解训练数据和测试数据的区别,如何防止过拟合,看看如何可视化一个模型的特征。
在简单介绍了推荐系统之后,我将介绍下面的 4 个部分,我们将建立一个模型来预测一些好莱坞明星的电影评级。
我将解释机器学习魔法背后的一步一步的数学,你可以跟随插入批量梯度下降中使用的公式中的实数(没有“宏”或“Excel 解算器”来隐藏细节)。
这是给谁的?
- 人们开始使用推荐系统
- 斋戒的学生。AI 的深度学习课程
- 对好奇心和机器学习感兴趣的人
特别感谢 Fast.AI 的杰瑞米·霍华德和瑞秋·托马斯,这里的电子表格灵感来自他们关于协同过滤的课程(见代码)。他们呈现的电子表格依靠 Excel 内置的求解器在幕后进行优化计算;然而,我构建的电子表格显示了梯度下降计算的每个步骤,并允许您微调模型的超参数。
如果这些电子表格对你有帮助,请考虑通过点击下面的链接注册我的电子邮件列表,我将向你发送更多的电子表格,帮助你开始机器学习和建立神经网络。
推荐系统介绍
电影推荐系统可以简化为两大类:
和
协同过滤(#1)
是基于相似行为的想法。
如果罗斯和瑞秋过去也喜欢过类似的东西,那我们就来拿几部罗斯没看过的瑞秋最喜欢的电影推荐给他。把他们想象成“味觉二重身”,他们与另一个人“合作”,过滤掉互联网货架上的所有噪音。2 如果用户的评级与另一个用户的评级具有很强的相关性,并且评级可以是隐式的或显式的,则认为用户是“相似的”:
- 罗斯和瑞秋整个周末都在狂饮老友记。尽管他们都没有“竖起大拇指”,但我们很确定他们喜欢它(他们可能有点自负)。
- 直白的(喜欢的【)——罗斯和瑞秋都对这部剧竖起了大拇指。
有两种类型的协同过滤:邻域方法和潜在因素模型(一种矩阵分解的形式)。这篇文章的重点是一个叫做 SVD++的潜在因素模型。
基于内容的过滤(#2)
是基于扮演媒人的想法。
使用明确的标签(类型、演员等。)从你过去喜欢的内容中,网飞向你推荐具有相似标签的新内容。
一百万美元的赢家是…
当数据集足够大时,协同过滤(CF)无疑是电影推荐器中基于内容的过滤的赢家。
虽然这两个大类之间有无数的混合和变化,但当 CF 模型足够好时,事实证明添加元数据根本没有帮助,这有点令人惊讶。
但这是为什么呢?
人们说他们喜欢的东西(用户偏好、调查等)之间有很大差距。)和他们的行为。最好是让人们的观影行为自己说话。(提示:为了获得更好的网飞推荐,在网飞上删除你的“观看活动”,点击 点击这里 删除你不喜欢的项目。)
2009 年,网飞奖给一个研究团队 100 万美元,他们开发的算法将网飞的预测准确率提高了 10%。虽然获胜的算法实际上是 100 多种算法的集合,但 SVD++(一种协作过滤)是贡献最大收益的关键算法之一,并且仍在生产中使用。
我们将要构建的 SVD++模型(“奇异值分解近似值”)类似于 Simon Funk 在 2006 年网飞竞赛开始时在一篇声名狼藉的博客文章中首次提出的想法。在 SVD++取得成功之后,几乎所有的网飞参赛者都在参赛作品中使用了它。
SVD++关键思想:
- **“奇异值”(电影评级)可以被“分解”或由一组隐藏的潜在因素(用户偏好和电影特征)**确定,这些因素直观地表示诸如类型、演员等事物…
- 潜在因素可以使用梯度下降和已知的电影分级来迭代学习。
- 用户/电影偏见对某人的评价有贡献,也是习得的。
简单,但功能强大。让我们开始吃吧。
1.1 数据
博客帖子模型使用 30 个虚构的评级(5 个用户 x 6 部电影)来简化教程。
- 为了跟进和试验这个模型,你可以在这里下载电子表格(Excel 或 Google Sheets)。
斋戒。AI lesson 根据 15 部最受关注的电影和 15 名最活跃的用户,使用了 225 个真实评级(在博客文章中很难说明)。除了虚假的“用户名”,收视率数据来自 MovieLens 。
- 查看基于快速的模型(Excel 或 Google Sheets)。AI 课,你可以在这里下载那个。
- 注意——斋戒。人工智能模型使用 15 个纪元而不是 50 个(由于更多的数据),并且在 Google Sheets 中计算相当慢,所以推荐使用 Excel。
1.2 拆分数据—培训与测试
我们将使用 25 个评分来训练我们的模型,并使用 5 个评分来测试模型的准确性。
我们的目标是建立一个对 25 个已知评级(训练数据)工作良好的系统,并且希望它对 5 个隐藏的(但已知的)评级(测试数据)预测良好。
如果我们有更多的数据,我们会将数据分成 3 组—训练组(70%)、验证组(20%)和测试组(~10%),然后使用验证集来验证我们的模型。
1.3 评级预测公式
评级预测是用户/电影特征+用户偏好+电影偏好的矩阵乘法或“点积”。
正式定义:
1.3.1 用户/电影特征
- 直观地说,这些特征代表了诸如类型、演员、电影长度、导演、电影年份等。即使我们并不十分清楚每个特性是什么,但是在我们将它们形象化到图表上之后,我们可以直观地猜测它们可能代表什么(参见第 4 部分)。
- 为了简单起见,我使用了 3 个特性,但是实际的模型可以有 50 个、100 个或者更多。功能的数量将随着数据的复杂程度成比例增长。如果有太多的特征,模型将“过度拟合/记忆”你的训练数据,并且当它预测隐藏的(但已知的)测试评级时,它不会很好地概括。
- 如果用户对于他们的第一个特征(假设它代表“喜剧”)具有高价值,并且该电影对于这个“喜剧”特征也具有高价值,这可能导致该电影的高评级。
1.3.2 用户/电影偏差
用户偏见是影评人有多苛刻或多好。如果网飞上所有电影的平均评分是 3.5,而你对所有东西的平均评分是 4.0,你就会有 0.5 的偏差。电影偏见也可以这么想。如果《泰坦尼克号》在所有用户中的平均评分为 4.25,那么它将有 0.75 的偏差(= 4.25-3.50)。
1.4 RMSE —评估预测精度
RMSE =均方根误差
RMSE 是一个试图回答“平均而言,你的预测评分与实际评分相差多少颗星(1-5 颗星)”的数字。
RMSE 越低,预测越准确…
观察:
- 我们只关心绝对差异。比实际评级高 1 的预测与比实际评级低 1 的预测具有相同的误差 1。
- **RMSE 是误差的量级的平均值,与绝对平均误差*不同。***在上述示例中,绝对平均误差为 0.75 (1 + 1 + 0.25 = 2.25/3 = 0.75),但 RMSE 为 0.8292。RMSE 对大误差给予较高的权重,这在不希望出现大误差时很有用。
正式的 RMSE 定义:
1.5 模型输入(超参数调整)
在电子表格中,有 3 个输入的下拉过滤器。您应该尝试这些输入,看看它们对您的错误有什么影响。
- 训练历元 — 1 历元是贯穿整个数据集的 1 个训练循环
- 学习率 —控制我们调整权重/偏差的速度
- L2 (lambda)惩罚因子 —这是一个帮助模型防止过度拟合或“记忆”训练数据的术语,因此它可以对看不见的测试数据进行归纳
现在,让我们来看看魔术,因为模型从随机权重开始,并学习最优权重。
观看梯度下降的动作感觉就像你在观看大卫·布赖恩魔术。
- 他怎么知道我会从 52 个选项中选出那张牌?
- 等等,他真的只是漂浮起来了吗?
最后你会感到敬畏,你想知道这个魔术是如何完成的。我将分两步向你展示这个技巧,然后揭示魔术背后的数学原理。
2.1“挑一张牌,任意一张牌”(权重初始化)
在训练开始时,权重被随机分配给用户/电影特征,然后算法在训练期间学习最佳权重。
为了证明我们可以随机猜测数字,然后让计算机学习最佳数字是多么“疯狂”,下面是两种权重初始化方法的比较:
- 简单的——我随机选择了 0.1、0.2 和 0.3 作为用户特性,其余的都是 0.1。
- “明凯何” —一种更正式/更好的初始化方法,使用零均值和由特征数量确定的标准偏差,在高斯分布(“钟形曲线”)中随机选择权重(详情如下)
2.2“观看魔术”(看训练误差)
当模型在两种方法的训练期间学习最优值时,观察 RMSE 训练误差从开始(时段 0)到结束(时段 50)发生了什么:
如下所示,两种权重初始化方法在训练结束时收敛到类似的“误差”(0.12 对 0.17),但“何”方法收敛到较低的误差更快。
要点提示:无论我们从哪种重量开始,机器都会随着时间的推移获得良好的价值!
注意:要试验其他初始权重,请转到工作表“超参数 _ 和 _ 初始 _ 权重”,并在单元格 G3-J7 和 N3-Q8 中键入您自己的值。介于-1 和 1 之间的任何权重都可以。
要了解更多关于何的初始化,见下文;否则,跳到第 3 部分来学习学习算法背后的数学。
何权重初始化
- 权重=使用平均值 0 和标准差(=平方根(2/)的正态分布的随机样本。
- 用于查找电子表格中的值的 Excel 公式:=NORMINV(RAND(),0,SQRT(2/3))
现在,是时候变得书呆子,一步一步地通过梯度下降数学。
如果你不想真的知道魔法如何工作,跳到第 4 部分。
You don’t have to be a wicked smart or need a degree in calc to understand the math.
梯度下降是在训练期间使用的迭代算法,用于更新电影特征、用户偏好和偏差的值,以获得更好的预测。
一般循环是:
步骤 1——定义成本/损失函数,以最小化并初始化权重
步骤 2 —计算预测值
步骤 3 —计算梯度(相对于每个重量的成本变化)
第 4 步——在最小化成本的方向上“稍微”更新每个权重(学习率)
步骤 5 —重复步骤 2–4
要跟进我们为蒂娜·菲更新的“用户功能 1 ”,请转到工作表“培训”并查看第 11–16 行。
由于我们有一个小数据集,我们将使用批量梯度下降。这意味着我们使用整个数据集(在我们的例子中为 1 个用户的所有电影)来训练算法,而不是像随机梯度下降(在我们的例子中为 1 个用户的 1 部电影)那样一次迭代 1 个样本,当你有一个大的数据集时,这样更快。
3.1 定义成本函数以最小化
使用下面的公式,我们的目标是找到潜在因子(矩阵 U 和 M)的值,这些值最小化 SSE(误差平方和)加上 L2 权重惩罚,以帮助模型泛化。
下面是我们的 Excel 模型中的成本函数 calc。该计算忽略了 1/2 项,因为它们仅在梯度下降过程中使用,以使数学更容易:
L2 正则化和过拟合:
我们添加了权重惩罚(L2 正则化或“岭回归”)来防止潜在因素变得过高。这确保了模型不会“过度拟合”(即记忆)训练数据,因为它不会在未看过的测试电影上表现良好。
早些时候,我们使用零 L2 正则化惩罚来训练模型,并且在 50 个时期之后,RMSE 训练误差是 0.12。
但是相对于测试数据,模型的表现如何呢?
如果我们将 L2 惩罚因子从 0.000 更改为 0.300,我们的模型将更好地概括未知的测试数据:
3.2.计算预测
使用随机初始权重,我们将计算蒂娜的电影预测。我们忽略泰坦尼克号,因为它是我们测试数据的一部分,不在我们的训练数据中。
3.3.计算渐变
目标是找到相对于您正在更新的重量的误差梯度(“斜率”)。
找到梯度后,你可以“稍微”移动那个重量,因为它在梯度的相反方向“下降”,在你对每个重量都这样做后,你应该在下一个训练时期有更低的成本。
“只是一点点”是你的学习率,在你找到梯度后,在下面的步骤 3 中使用。
3.4.更新权重
注:上述计算可在以下“培训”表的 X11-X16 单元格中找到。
如果您浏览 Excel calcs,您可以看到电影功能和用户/电影偏好是如何以类似的方式更新的。
在每个训练时期之后,所有电影/用户特征和偏好被同时更新,并且训练循环重复进行。
既然我们已经训练了这个模型,让我们想象一下电影中的两个潜在因素来获得一些洞察力。
如果我们的模型更复杂,有 10 个、20 个或 50 多个潜在因素,我们可以使用一种称为“主成分分析(PCA)”的技术来提取最重要的特征,然后将它们可视化在图表上。
相反,我们的模型只有 3 个特征,所以我们将为电影可视化其中的 2 个,并根据电影的学习特征绘制每部电影。在绘制之后,我们可以解释每个特征“可能代表什么”
直观地说,电影正片 1 可以被解释为戏剧与喜剧,而电影正片 3 可以被视为“面向男性”与“面向女性”
这并不完美,但却是一个合理的解释。《勇士》与其说是喜剧,不如说是剧情片,但其他的似乎也说得通。
摘要
电影评级可以被分解成电影向量和用户向量。一旦一个人对几部电影进行了评价(隐含地或明确地),推荐系统将利用大众的智慧和你的评价来预测你可能喜欢的其他电影。向量(或“潜在因素”)的大小是通过反复试验确定的,并且基于数据集的大小。
我鼓励您尝试使用电子表格,看看当您更改模型的超参数时会发生什么。
订阅和分享
如果你喜欢这一点,并希望获得更多优秀的学习和备忘单直接发送到您的收件箱,请点击下面并输入您的电子邮件地址(它们都是免费的)。
与人分享,传播机器学习魔法的快乐:)
使用 python 快速洞察学术领域的网络分析
每年十月初,科学界都会感到越来越兴奋。是时候宣布今年的诺贝尔奖得主了。从外部的角度来看,很难掌握正在发生的事情,报纸花费了大量的精力试图洞察这个世界的内部运作。现在,假设你对一个新的主题很感兴趣,你想获得一种洞察力,无论你是一名想要指导未来职业生涯的本科生,还是一名想要扩展自己视野或只是随便逛逛的有经验的科学家。当在自己的专业知识之外探索时,获得一个概述可能是压倒性的。谁是关键人物,我怎样才能认识他们,热门话题是什么?通常,在一个领域内需要几年的时间,去参加会议,阅读一份又一份出版物,才能对相关人员及其关系和贡献有一个直觉。幸运的是,通过一些 python 及其丰富的库,我们可以加速这个过程,并通过简单地分析所有相关的期刊出版物来快速洞察这个网络。
感兴趣的话题:2018 年诺贝尔物理学奖
例如,我们看看今年的诺贝尔物理学奖,授予亚瑟·阿什金“光镊及其在生物系统中的应用”同时获奖的还有热拉尔·穆鲁和唐娜·斯特里克兰,他们发明了啁啾脉冲放大。为了便于演示,我们将重点放在光镊领域。简而言之,光镊使用高度聚焦的激光,可以施加微微牛顿的力来固定小粒子。
获取摘要的生物制药
为了避免我们阅读所有的科学文献,我们将使用b[iophython](https://biopython.org/)
包从 PubMed 数据库中获取与我们的搜索查询相关的摘要。确保开始阅读 NCBI 的 Entrez 用户要求。具体来说,我们不想让这项服务超负荷,所以请在美国高峰时间之外提出大量请求,并正确设置电子邮件参数,以便可以联系到您。作为搜索参数,我们将把optical trap
作为关键字传递。请注意,光镊的最初术语叫做“单光束梯度力陷阱”,但由于大多数出版物都与几个关键词相关联,我们应该仍然能够获得相关的结果。为了获取,我们首先收集与关键字相关联的出版物的数量,然后收集它们的所有 id,以便以 100 个为一批连续下载。
Total number of publications that contain the term optical trap: 5059100%|██████████| 51/51 [01:20<00:00, 1.36s/it]Complete.
探索数据:顶级作者、时间序列、顶级期刊和顶级关键词
现在有了数以千计的出版物的信息,我们现在想深入了解这些数据。一些直接的问题可能是:谁是领先的科学家?这个领域还有人出版吗?应该看哪些期刊?我应该注意哪些关键词?为了对此有一个总体的了解,我们将研究这些数据。首先,我们将我们的record_list
转换成一个pandas
数据帧。感兴趣的列是作者姓名的FAU
、期刊标题的TA
、时间的EDAT
和与出版物相关的关键字列表的OT
。因为作者和关键字是作为列表存储在数据帧中的,所以我们需要首先将它们展平。这可以通过列表理解方便地完成。然后,我们可以使用集合中的计数器方法方便地提取最常见的元素,并通过使用seaborn
创建条形图来可视化它们。
Figure 1: Exploring the data
从这四幅图中,我们可以得出一些有趣的观察结果。首先,在考察顶级作者时,我们注意到诺贝尔奖获得者阿什金并不在场。顶级学者是Bustamante, Carlos.
当考虑一段时间内的出版物时,我们看到大多数作品都是在 2000 年之后出版的——当记住阿什金的出版物是在 1986 年时,很明显他的工作是多么重要。时间进程还告诉我们,我们现在正处于出版物数量下降的状态。与我们的搜索查询相关的出版物最多的期刊是 Optics Express。
可视化网络
我们现在可以更深入地挖掘我们的数据,并开始可视化科学网络。具体来说,我们将分析哪些作者一起发表了文章,以及发表的频率。为此,我们为每篇论文创建一个所有作者组合的列表,这将是我们的作者连接。这里,我们不考虑作者的立场,即一个作者是否是主要研究者。在将它转换成一个pandas
数据帧之后,我们可以用这个数据帧和networkx
包创建一个无向图。每个作者现在都变成了一个node
,两者之间的连接是一个edge.
,为了显示这个图形,我们使用了nxviz
库,并将其显示为一个CircosPlot
。在这里,作者排列在一个圆圈上,圆圈之间有联系。虽然我认为这对于给定的任务是一种有益的表示,但是一定要查看可以用于可视化的不同类型的图表
此外,我们将图表限制在前 50 名作者中。作者连接数将通过决定连接线宽的参数edge_width
来反映。我们将通过出版物计数来确定节点的数量,以便出版物的数量从拥有最多论文的学者开始顺时针减少(Bustamante, Carlos
)。
Figure 2: A CircosPlot of the scientific network of the TOP 50 Authors
有了 CircosPlot,我们现在有了一个科学网络的彩色表示,可以立即发现最重要的人在网络中的联系程度。我们可以看到,在这个前 50 名的网络中,许多作者都有很好的关系,而其他人,即使他们发表了很多,也完全没有关系。虽然这种表示对于获得该领域内人员的定性概述是理想的,但我们接下来将探索如何定量评估人员的重要性。
网络分析:度中心性和介数中心性
为了获得最佳连接的节点,我们将计算网络的两个相关参数:degree_centrality
和betweenness_centrality
。前者是与节点的所有可能连接相关的连接的度量,而后者是节点是否是两个节点之间最短路径的一部分的度量。转化为我们的案例:谁有最多的合作,谁是联系其他作者的关键?
现在我们可以用这两个指标来扩展我们最初的 10 大图表。为此,我们通过前 10 名作者的最大值来标准化每个参数,以获得 0 和 1 之间的相对值:
Figure 3: Top 10 Authors with Degree and Betweenness Centrality
这让我们验证了 CircosPlot 中已经存在的一个重要观察:拥有最多论文的人不一定是这个网络中联系最好的人。在这里,Rubinsztein-Dunlop, Halina
和Chemla, Yann R
可以被认为是作者网络中不可或缺的一部分。
寻路:如何与感兴趣的人取得联系
最后,我们将探索如何使用这个网络来寻找路径,也就是说,当你认识某个教授并且想要认识另一个教授时。这很容易通过使用networx
包装中的all_shortest_path
来完成。举个例子,如果你碰巧知道Ha, Taekjip
并且想要查看到Bustamante, Carlos
的连接,我们可以计算最短路径:
['Ha, Taekjip', 'Chemla, Yann R', 'Bustamante, Carlos']
['Ha, Taekjip', 'Yu, Jin', 'Bustamante, Carlos']
这里,我们发现两条路径,一条通过Chemla, Yann R
,我们已经在图 3 中确定了它的重要性,另一条通过Yu, Jin
。这些结果很容易在图示中得到验证。
结论
这里,我们使用了几个 python 包来分析与某个科学领域相关的期刊出版物的摘要。在网络分析的帮助下,只需几行代码就能提供很好的洞察力。最终,它有助于识别在该领域有良好关系和高产的科学家。然而,强调其局限性也很重要,这源于我们在分析中使用的核心指标,即出版物的数量。可以说,这并没有反映科学工作在社区内是如何被接受的。这里,考虑引用的数量将是有益的。当考虑阿什金 1986 年的出版物时,我们可以了解到这部作品被引用了 6000 多次,其重要性显而易见。其他试图衡量影响和生产力的作者级指标,如 h-或 i-index,似乎是有益的选择。
进一步的分析可能包括这些额外的指标。地理信息可以用来显示科学家的位置。示例应用可以是做进一步的网络分析和为科学家建立推荐系统。
网络分析始于一个患病的爱尔兰厨师
这是为那些可能在数据科学环境中使用网络的人解释网络原理的系列文章的第三篇。第一篇文章,主要讲图论的起源和图的基本性质,这里可以找到。
1906 年夏天,沃伦一家——一个富裕的纽约大家庭——正在长岛牡蛎湾的度假屋吃晚饭。最令人期待的部分是甜点。在一个炎热的夏天的晚上,桃子超古代龙美尔巴配冰淇淋是一种非常美味、凉爽和提神的食物,孩子们特别喜欢。
几天后,其中一个孩子开始生病,出现伤寒的症状。几天后,包括女佣和一名园丁在内的另外五个人开始出现这种疾病的症状。这令人困惑,因为伤寒被认为主要在肮脏和不卫生的环境中传播,通常与穷人有关。伤寒并没有在牡蛎湾爆发。
把度假屋租给沃伦斯的房东非常担心。这个特别有声望的租赁物业的运营成本很高,他不能因为传染病而让它闲置。他打电话给地方当局,他们检查了所有常见的嫌疑人,包括人和机器。厕所和自来水都接受了检查,在镇上购买食物的当地人也接受了检查。所有检测结果都不能确定是爆发源。
因此,汤普森去纽约市寻找他的伤寒猎人。他在乔治·索普医生身上找到了他——不是医学博士,而是卫生工程师。Soper 对 Warren 家庭的背景情况进行了彻底的研究,他意识到家庭环境最近发生了一个重大变化,这可能会导致新细菌的传播。八月初,他们雇佣了一名新厨师。当他采访沃伦斯,发现厨师的拿手好菜是一道凉菜,桃子超古代龙美尔巴,他变得更加怀疑,因为他知道凉菜更有可能携带活细菌。
厨师是一个名叫玛丽·梅伦的爱尔兰移民,却不见踪影——她在家人开始生病后不久就逃走了。Soper 对 Mallon 的历史进行了几个月的调查,发现了她以前做过厨师的七个家庭,每个家庭都导致了伤寒的爆发,总共感染了 22 人。如果马伦确实是伤寒的健康携带者,就需要尽快找到她。
在接下来的几年里,玛丽·梅伦——或伤寒玛丽——在媒体和公共卫生运动中广为人知——终于在 1907 年 3 月被索普找到,并被确认为伤寒杆菌的原始健康携带者。在接下来的 30 年里,她大部分时间都处于某种隔离状态,有一段时间,她逃跑了,回去给家人做饭,然后再次被捕,并被隔离。她死于 1938 年,不是死于伤寒而是肺炎。她一生中从未表现出伤寒的任何症状,但尸检显示她胆囊中有大量的杆菌。
通过网络传输
索普的工作标志着对疾病传播的首次理解。在过去的 50 年中,许多成功的疾病爆发鉴定都集中在对地点和场所的研究上,包括 19 世纪 50 年代在伦敦发现的著名的大街霍乱爆发。
但这是第一次通过人而不是地方成功追踪到疾病。这是理解事物如何通过人际网络流动的开始。在一定程度上,信息以类似于疾病的方式通过人们的网络流动,因此我们使用“病毒式”一词来描述今天快速而广泛的信息传播。这项早期的工作旨在了解疾病在网络中的传播,它代表了我们今天看待信息传播的方式的起源,无论是趋势、谣言还是广告。
以最简单的形式考虑信息流,一条信息是否从一个人流向另一个人的问题取决于两个因素:那个人连接的人数,姑且称之为 k ,以及信息被传递的概率,姑且称之为 p 。在玛丽·梅伦的例子中,当局意识到 p 很难被影响——你将很难改变一个没有受过教育的厨师一生的卫生习惯。所以通过隔离 Mallon 来降低 k 是控制疾病传播的唯一真正的选择。
在社交网络中,了解如何操纵 p(T1)和 T2(T3)对于管理营销、广告、新闻或假新闻的传播至关重要。 p 可以通过确保话题与个人的已知兴趣有很强的共同性,或者通过与个人明确约定信息将被传递来增加。通过网络中高价个体的工作,k 可以增加(见本系列上一篇关于价的更多信息)。
谣言和信息传播
实际上,我们上面的 p 和 k 代表了一个趋势和谣言如何在网络中传播的简单模型。一方面,信息是否在两个人之间进行交易既取决于传递信息的倾向也取决于接收信息的兴趣。它还假设我们正在处理的网络图是树,只向下传递信息,在复杂的社会网络中通常不是这样。**
在社交网络中,可能会发生多种类型的互动。如果 A 是收到信息的人的集合, B 是没有收到信息的人的集合,有几种情况是可能的。 A 可以传给 A , A 可以传给 B. 在这两种情况下,接受者都可以选择接受或者拒绝——即使他们之前已经选择了,他们也可以改变主意。
当比较趋势和谣言的传播与疾病的传播时,另一个很大的区别是,我们更感兴趣的是信息去了哪里,而不是它来自哪里。关于谣言如何在社交网络上传播的研究得出了一些非常有趣的观察结果。
像脸书和推特这样的大型网络可能会展示出无标度网络的一些特性。价数或联系数小的人多,联系数大的人少。如果你根据联系的数量来绘制人的图表,你会得到类似上图的东西,有一条渐近真实曲线或一条线性对数曲线。最近的研究这里表明,虽然我们不能精确地将社交网络与无标度的正式数学定义相匹配,但没有其他数学模型比无标度模型更适合它们。
无标度网络存在于许多领域,包括生物化学、技术和金融。在无标度网络中,信息传播与网络的规模直接相关。Twitter 和脸书是规模庞大的网络,但也有数学属性,使它们正好处于信息传播极快的范围内。例如,在 Twitter 上,一条信息只需 8 个信息交换步骤就可以覆盖近 5000 万用户。这些网络的力量是可怕的!
预测趋势
当你查看你的社交媒体订阅源时,你经常会被告知什么是“趋势”。社交媒体引擎利用对信息传播的研究来设计算法,以自动确定某个主题在网络中的传播速度何时超过其他主题。
简单的趋势模型遵循某个统计窗口内的“主题”或“标签”。如上图所示,该窗口显示了网络上大多数主题的预期传输活动。对这些主题的实时跟踪可以揭示出那些活动曲线意外跳出该统计窗口的主题,如果跳跃幅度很大,则被视为“趋势”。例如,上面的红点可以代表网络决定将主题分类为趋势的时间点和活动。
然而,这种根据期望窗口跟踪单个趋势的方法会导致错误,并且高度依赖于人类的判断,这在非常大的网络中是不可行的。趋势可能会以不可预测的方式出现,或者在被归类为趋势后很快就会“逆转”,这对于预测者来说可能会很尴尬。
2012 年,麻省理工学院的一项研究发现了一种全自动预测 Twitter 趋势的方法,比 Twitter 自己预测趋势早两个小时,准确率高达 95%。研究人员使用了一个以前有趋势和没有趋势的主题的数据库,并将任何当前主题的推文活动与该数据库进行了比较,计算了活动曲线之间的距离。那些其距离最接近趋势的先前主题的曲线的曲线本身被预测为趋势。这项研究引出了当今社交网络预测趋势最常用的方法。
在本系列的下一篇文章中,我将着眼于以促进高效网络分析的方式捕获数据的数据系统,以及这是如何实现许多令人着迷的发现的。这里读一下。****
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn 或Twitter上找我。
神经机器翻译—使用 seq2seq 和 Keras
基于编解码模型的英语到法语翻译
Photo by Kiarash Mansouri on Unsplash
本文是受此 的启发,以 和 为例阐述了 上的编解码网络*。*目的是从这个例子中获得直观和详细的理解。在我的 github 链接 中提供了我自己对这个例子的实现。
在我们开始之前,它可能有助于通过 我的另一篇关于 LSTM 的文章来帮助理解 LSTM 的基本原理。
下面是用于训练 seq2seq 编码器-解码器网络的详细网络架构。我们将引用这个数字。
Fig A— Encoder-Decoder training architecture for NMT — image copyright@Ravindra Kompella
首先,我们将着手训练网络。然后我们将看看如何把一个给定的英语句子翻译成法语的推理模型。推理模型(用于预测输入序列)有一个稍微不同的解码器架构,我们将在那里详细讨论。
训练网络—
那么训练数据看起来怎么样呢?
- 我们有 10,000 个英语句子和相应的 10,000 个翻译的法语句子。所以我们的 nb_samples = 10000。
培训总体计划—
- 为英语和法语句子创建一次性字符嵌入。这些将是编码器和解码器的输入。法语一键字符嵌入也将用作损失函数的目标数据。
- 一个字符一个字符地输入到编码器中,直到英文句子序列结束。
- 获得最终的编码器状态(隐藏和单元状态),并将它们作为解码器的初始状态提供给解码器。
- 解码器在每个时间步长有 3 个输入——2 个解码器状态和一个字符一个字符地输入的法国字符嵌入。
- 在解码器的每一步,解码器的输出都被发送到 softmax 层,与目标数据进行比较。
代码训练网络的详细流程—
参考代码片段 1——注意,我们在法语句子的开头附加了’ \t ‘,在法语句子的结尾附加了’ \n’。这些附加的法语句子将被用作解码器的输入。所有的英文字符和法文字符都收集在不同的集合中。这些集合被转换成字符级字典(对以后检索索引和字符值很有用)。
Snippet 1
参考片段 2—为编码器输入、解码器输入和目标数据嵌入准备嵌入。我们将为英语和法语中的每个字符分别创建一个热编码。这些在代码片段中被称为 tokenized_eng_sentences 和 tokenized_fra_sentences 。这些将分别是编码器和解码器的输入。请注意,与解码器输入嵌入相比,我们在 softmax 层输出比较的 target_data 法语字符嵌入偏移了(t+1 )(因为目标数据中没有起始标签,请参考上面的架构图以获得更多信息)。因此,下面代码片段中的 target_data 被相应地偏移(注意下面 target_data 数组的第二维中的 k-1 )
Snippet 2.
参考片段 2——正如我们在 中提到的,我在 LSTM ,中的嵌入(tokenized _ eng _ sentences和tokenized _ fra _ sentences和 target_data) 是 3D 数组。第一维对应于 nb_samples ( =本例中为 10,000)。第二维对应于英语/法语句子的最大长度,第三维对应于英语/法语字符的总数。
参考代码片段 3:我们将一个字符接一个字符(当然,它们对应的一个热嵌入)输入编码器网络。对于编码器 _LSTM,我们已经设置了返回 _ 状态=真。我们没有做 return_sequences = True (默认设置为 False)。这将意味着我们在输入序列结束时仅获得最终编码的单元状态和编码的隐藏状态,而不是每个时间步长的中间状态。这些将是用于初始化解码器状态的最终编码状态。
Snippet 3— Encoder model for training
参考代码片段 3 —还要注意,输入形状已经被指定为 (None,len(eng_chars)) 。这意味着编码器 LSTM 可以动态地展开与字符数一样多的时间步长,直到到达该句子序列的末尾。
参考代码片段 4——解码器的输入将是法语字符嵌入(包含在 tokenized_fra_sentences 数组中),在每个时间步一个接一个,以及先前的状态值。解码器第一步的先前状态将用我们之前在代码片段 3 中收集的最终编码器状态进行初始化。因此,请注意在下面的代码片段中已经设置了初始状态=编码器状态。从随后的步骤开始,解码器的状态输入将是其单元状态和隐藏状态。
Snippet 4 — Decoder model for training
同样从上面的代码片段中,请注意解码器设置为return _ sequences = True以及return _ state = True。因此,我们在每个时间步长获得解码器输出和两个解码器状态。虽然这里已经声明了return _ state = True,但是在训练模型时我们不打算使用解码器状态。其存在的原因是它们将在构建解码器推理模型时使用(我们将在后面看到)。解码器输出通过 softmax 层传递,该层将学习对正确的法语字符进行分类。
参考片段 5——损失函数是分类交叉熵,它是通过将 softmax 层的预测值与 target_data (一个热门法语字符嵌入)进行比较而获得的。
现在模型已经准备好进行训练了。针对指定数量的时期训练整个网络。
Snippet 5 — y = target_data ( containing one hot french character embeds)
测试(推理模式)——
以下是用于推理模型的架构——推理模型将利用训练期间学习的所有网络参数,但我们单独定义它们,因为推理期间的输入和输出不同于训练网络期间的输入和输出。
从下图可以看出,网络的编码器端没有变化。因此,我们将新的英语句子(嵌入一个热字符)向量作为输入序列馈送到编码器模型,并获得最终的编码状态。
Fig B— Encoder-Decoder Inference model architecture for NMT —image copyright @Ravindra Kompella
将解码器端的图 B 与图 A 进行对比。可以看到的主要变化如下—
- 在第一个时间步长,解码器有 3 个输入——开始标记’ \t ‘和两个编码器状态。我们将第一个字符作为’ \t '(它的一个热嵌入向量)输入到解码器的第一个时间步长中。
- 然后解码器输出第一个预测字符(假设是‘V’)。
- 观察蓝线是如何连接回下一个时间步长的解码器输入的。所以这个预测的字符“V”将在下一个时间步作为输入被馈送到解码器。
- 还要注意,在每个时间步,我们在 softmax 层的输出上使用 np.argmax 函数,仅获得预测字符的一个热嵌入向量。因此,我们在索引上进行反向字典查找,以获得实际的字符‘V’。
- 从下一时间步开始,解码器仍有 3 个输入,但不同于第一时间步。它们是先前预测字符的一个热编码、先前解码器单元状态和先前解码器隐藏状态
鉴于以上理解,现在让我们看看代码—
参考代码片段 6——编码器推理模型非常简单。这将只输出编码器状态。
Snippet 6 — Encoder inference model
参考代码片段 7——解码器模型更加复杂。注意,我们为解码器隐藏状态和解码器单元状态创建单独的“输入”。这是因为我们将在每个时间步长(而不是第一个时间步长)提供这些状态,回想一下,在第一个时间步长,我们仅将编码器状态提供给解码器,解码器推理模型是一个单独的独立模型。编码器和解码器都将被递归调用,用于在翻译后的序列中生成的每个字符。
Snippet 7 — Decoder inference model
参考代码片段 8——我们将编码器状态放入 states_val 变量。在 while 循环内的第一次调用中,来自编码器的这些隐藏和单元状态将用于初始化作为模型输入直接提供的 decoder_model_inf 。一旦我们使用 softmax 预测了字符,我们现在输入这个预测的字符(使用 target_seq 3D 数组用于预测字符的一次热嵌入)以及更新的 states_val (从先前的解码器状态更新而来)用于下一次的 while 循环迭代。注意,在我们每次在 while 循环中创建预测字符的一键嵌入之前,我们重置了我们的 target_seq 。
Snippet 8 — Function to recursively call the decoder for predicting the translated character sequence.
就是这样!现在我们有了一个训练有素的模型,可以把英语句子翻译成法语!下面是在训练网络 25 个时期后获得的结果。
Results obtained using some sample training data
如果你打算使用任何上述架构图的数字,请随时这样做,并要求你提到我的名字在图像学分。
如果你从这篇文章中发现了什么有用的信息,请举起鼓掌图标表示你的掌声。
用 Python 实现神经机器翻译
Photo credit: eLearning Industry
机器翻译,有时简称为 MT 是一项非常具有挑战性的任务,研究如何使用软件将文本或语音从一种语言翻译成另一种语言。传统上,它涉及使用高度复杂的语言知识开发的大型统计模型。
在这里,我们将使用深度神经网络来解决机器翻译的问题。我们将发现如何开发一个神经机器翻译模型来将英语翻译成法语。我们的模型将接受英语文本作为输入,并返回法语翻译。更准确地说,我们将练习构建 4 个模型,它们是:
- 简单的 RNN。
- 嵌入的 RNN。
- 双向 RNN。
- 编码器-解码器模型。
训练和评估深度神经网络是一项计算密集型任务。我使用了 AWS EC2 实例来运行所有代码。如果您打算继续下去,您应该能够访问 GPU 实例。
导入库
import collectionsimport helper
import numpy as np
import project_tests as testsfrom keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.models import Model
from keras.layers import GRU, Input, Dense, TimeDistributed, Activation, RepeatVector, Bidirectional
from keras.layers.embeddings import Embedding
from keras.optimizers import Adam
from keras.losses import sparse_categorical_crossentropy
我用[help.py](https://github.com/susanli2016/NLP-with-Python/blob/master/helper.py)
加载数据,[project_test.py](https://github.com/susanli2016/NLP-with-Python/blob/master/project_tests.py)
用于测试我们的功能。
数据
数据集包含相对较少的词汇,可以在这里找到。small_vocab_en
文件包含small_vocab_fr
文件中的英语句子及其法语翻译。
加载数据
english_sentences = helper.load_data('data/small_vocab_en')
french_sentences = helper.load_data('data/small_vocab_fr')print('Dataset Loaded')
数据集加载
例句
small_vocab_en
中的每一行都包含一个英文句子,而small_vocab_fr
中的每一行都有相应的翻译。
for sample_i in range(2):
print('small_vocab_en Line {}: {}'.format(sample_i + 1, english_sentences[sample_i]))
print('small_vocab_fr Line {}: {}'.format(sample_i + 1, french_sentences[sample_i]))
Figure 1
词汇
问题的复杂程度是由词汇的复杂程度决定的。更复杂的词汇是更复杂的问题。让我们看看我们将要处理的数据集的复杂性。
english_words_counter = collections.Counter([word for sentence in english_sentences for word in sentence.split()])
french_words_counter = collections.Counter([word for sentence in french_sentences for word in sentence.split()])print('{} English words.'.format(len([word for sentence in english_sentences for word in sentence.split()])))
print('{} unique English words.'.format(len(english_words_counter)))
print('10 Most common words in the English dataset:')
print('"' + '" "'.join(list(zip(*english_words_counter.most_common(10)))[0]) + '"')
print()
print('{} French words.'.format(len([word for sentence in french_sentences for word in sentence.split()])))
print('{} unique French words.'.format(len(french_words_counter)))
print('10 Most common words in the French dataset:')
print('"' + '" "'.join(list(zip(*french_words_counter.most_common(10)))[0]) + '"')
Figure 2
预处理
我们将使用以下预处理方法将文本转换为整数序列:
- 将单词标记为 id
- 添加填充以使所有序列长度相同。
符号化
使用 Keras 的[Tokenizer](https://keras.io/preprocessing/text/#tokenizer)
函数将每个句子转换成一系列单词 id。使用此函数来标记english_sentences
和french_sentences
。
函数tokenize
返回标记化的输入和标记化的类。
def tokenize(x):
x_tk = Tokenizer(char_level = False)
x_tk.fit_on_texts(x)
return x_tk.texts_to_sequences(x), x_tktext_sentences = [
'The quick brown fox jumps over the lazy dog .',
'By Jove , my quick study of lexicography won a prize .',
'This is a short sentence .']
text_tokenized, text_tokenizer = tokenize(text_sentences)
print(text_tokenizer.word_index)
print()
for sample_i, (sent, token_sent) in enumerate(zip(text_sentences, text_tokenized)):
print('Sequence {} in x'.format(sample_i + 1))
print(' Input: {}'.format(sent))
print(' Output: {}'.format(token_sent))
Figure 3
填充
通过使用 Keras 的[pad_sequences](https://keras.io/preprocessing/sequence/#pad_sequences)
函数向每个序列的末端添加填充,确保所有英文序列和所有法文序列长度相同。
def pad(x, length=None):
if length is None:
length = max([len(sentence) for sentence in x])
return pad_sequences(x, maxlen = length, padding = 'post')tests.test_pad(pad)# Pad Tokenized output
test_pad = pad(text_tokenized)
for sample_i, (token_sent, pad_sent) in enumerate(zip(text_tokenized, test_pad)):
print('Sequence {} in x'.format(sample_i + 1))
print(' Input: {}'.format(np.array(token_sent)))
print(' Output: {}'.format(pad_sent))
Figure 4
预处理管道
实现预处理功能
def preprocess(x, y):
preprocess_x, x_tk = tokenize(x)
preprocess_y, y_tk = tokenize(y)preprocess_x = pad(preprocess_x)
preprocess_y = pad(preprocess_y)# Keras's sparse_categorical_crossentropy function requires the labels to be in 3 dimensions
preprocess_y = preprocess_y.reshape(*preprocess_y.shape, 1)return preprocess_x, preprocess_y, x_tk, y_tkpreproc_english_sentences, preproc_french_sentences, english_tokenizer, french_tokenizer =\
preprocess(english_sentences, french_sentences)
max_english_sequence_length = preproc_english_sentences.shape[1]
max_french_sequence_length = preproc_french_sentences.shape[1]
english_vocab_size = len(english_tokenizer.word_index)
french_vocab_size = len(french_tokenizer.word_index)print('Data Preprocessed')
print("Max English sentence length:", max_english_sequence_length)
print("Max French sentence length:", max_french_sequence_length)
print("English vocabulary size:", english_vocab_size)
print("French vocabulary size:", french_vocab_size)
Figure 5
模型
在本节中,我们将实验各种神经网络架构。我们将从训练四个相对简单的架构开始。
- 模型 1 是一个简单的 RNN
- 模型 2 是具有嵌入的 RNN
- 模型 3 是双向 RNN
- 模型 4 是一个编码器-解码器 RNN
在对四个简单的架构进行实验之后,我们将构建一个更深层次的模型,该模型旨在超越所有四个模型。
id 返回正文
神经网络将把输入翻译成单词 ids,这不是我们想要的最终形式。我们想要法语翻译。函数logits_to_text
将在从神经网络到法语翻译的逻辑之间架起一座桥梁。我们将使用这个函数来更好地理解神经网络的输出。
def logits_to_text(logits, tokenizer):
index_to_words = {id: word for word, id in tokenizer.word_index.items()}
index_to_words[0] = '<PAD>'return ' '.join([index_to_words[prediction] for prediction in np.argmax(logits, 1)])print('`logits_to_text` function loaded.')
logits_to_text
函数已加载。
车型一:RNN
Figure 6
我们正在创建一个基本的 RNN 模型,它是将英语翻译成法语的序列数据的良好基线。
def simple_model(input_shape, output_sequence_length, english_vocab_size, french_vocab_size):
learning_rate = 1e-3
input_seq = Input(input_shape[1:])
rnn = GRU(64, return_sequences = True)(input_seq)
logits = TimeDistributed(Dense(french_vocab_size))(rnn)
model = Model(input_seq, Activation('softmax')(logits))
model.compile(loss = sparse_categorical_crossentropy,
optimizer = Adam(learning_rate),
metrics = ['accuracy'])
return model
tests.test_simple_model(simple_model)tmp_x = pad(preproc_english_sentences, max_french_sequence_length)
tmp_x = tmp_x.reshape((-1, preproc_french_sentences.shape[-2], 1))# Train the neural network
simple_rnn_model = simple_model(
tmp_x.shape,
max_french_sequence_length,
english_vocab_size,
french_vocab_size)
simple_rnn_model.fit(tmp_x, preproc_french_sentences, batch_size=1024, epochs=10, validation_split=0.2)# Print prediction(s)
print(logits_to_text(simple_rnn_model.predict(tmp_x[:1])[0], french_tokenizer))
Figure 7
基本的 RNN 模型的验证精度终止于 0.6039。
模式二:嵌入
Figure 8
嵌入是在 n 维空间中接近相似单词的单词的向量表示,其中 n 表示嵌入向量的大小。我们将使用嵌入创建一个 RNN 模型。
from keras.models import Sequential
def embed_model(input_shape, output_sequence_length, english_vocab_size, french_vocab_size):
learning_rate = 1e-3
rnn = GRU(64, return_sequences=True, activation="tanh")
embedding = Embedding(french_vocab_size, 64, input_length=input_shape[1])
logits = TimeDistributed(Dense(french_vocab_size, activation="softmax"))
model = Sequential()
#em can only be used in first layer --> Keras Documentation
model.add(embedding)
model.add(rnn)
model.add(logits)
model.compile(loss=sparse_categorical_crossentropy,
optimizer=Adam(learning_rate),
metrics=['accuracy'])
return model
tests.test_embed_model(embed_model)tmp_x = pad(preproc_english_sentences, max_french_sequence_length)
tmp_x = tmp_x.reshape((-1, preproc_french_sentences.shape[-2]))embeded_model = embed_model(
tmp_x.shape,
max_french_sequence_length,
english_vocab_size,
french_vocab_size)embeded_model.fit(tmp_x, preproc_french_sentences, batch_size=1024, epochs=10, validation_split=0.2)print(logits_to_text(embeded_model.predict(tmp_x[:1])[0], french_tokenizer))
Figure 9
嵌入模型的验证精度终止于 0.8401。
模型 3:双向 RNNs
Figure 10
def bd_model(input_shape, output_sequence_length, english_vocab_size, french_vocab_size):
learning_rate = 1e-3
model = Sequential()
model.add(Bidirectional(GRU(128, return_sequences = True, dropout = 0.1),
input_shape = input_shape[1:]))
model.add(TimeDistributed(Dense(french_vocab_size, activation = 'softmax')))
model.compile(loss = sparse_categorical_crossentropy,
optimizer = Adam(learning_rate),
metrics = ['accuracy'])
return model
tests.test_bd_model(bd_model)tmp_x = pad(preproc_english_sentences, preproc_french_sentences.shape[1])
tmp_x = tmp_x.reshape((-1, preproc_french_sentences.shape[-2], 1))bidi_model = bd_model(
tmp_x.shape,
preproc_french_sentences.shape[1],
len(english_tokenizer.word_index)+1,
len(french_tokenizer.word_index)+1)bidi_model.fit(tmp_x, preproc_french_sentences, batch_size=1024, epochs=20, validation_split=0.2)# Print prediction(s)
print(logits_to_text(bidi_model.predict(tmp_x[:1])[0], french_tokenizer))
Figure 11
双向 RNN 模型的验证精度终止于 0.5992。
模型 4:编码器-解码器
编码器创建句子的矩阵表示。解码器将该矩阵作为输入,并预测翻译作为输出。
def encdec_model(input_shape, output_sequence_length, english_vocab_size, french_vocab_size):
learning_rate = 1e-3
model = Sequential()
model.add(GRU(128, input_shape = input_shape[1:], return_sequences = False))
model.add(RepeatVector(output_sequence_length))
model.add(GRU(128, return_sequences = True))
model.add(TimeDistributed(Dense(french_vocab_size, activation = 'softmax')))
model.compile(loss = sparse_categorical_crossentropy,
optimizer = Adam(learning_rate),
metrics = ['accuracy'])
return model
tests.test_encdec_model(encdec_model)tmp_x = pad(preproc_english_sentences)
tmp_x = tmp_x.reshape((-1, preproc_english_sentences.shape[1], 1))encodeco_model = encdec_model(
tmp_x.shape,
preproc_french_sentences.shape[1],
len(english_tokenizer.word_index)+1,
len(french_tokenizer.word_index)+1)encodeco_model.fit(tmp_x, preproc_french_sentences, batch_size=1024, epochs=20, validation_split=0.2)print(logits_to_text(encodeco_model.predict(tmp_x[:1])[0], french_tokenizer))
Figure 12
编码器-解码器模型的验证精度终止于 0.6406。
型号 5:定制
创建一个将嵌入和双向 RNN 合并到一个模型中的 model_final。
在这个阶段,我们需要做一些实验,例如将 GPU 参数更改为 256,将学习率更改为 0.005,为超过(或少于)20 个时期训练我们的模型等。
def model_final(input_shape, output_sequence_length, english_vocab_size, french_vocab_size):
model = Sequential()
model.add(Embedding(input_dim=english_vocab_size,output_dim=128,input_length=input_shape[1]))
model.add(Bidirectional(GRU(256,return_sequences=False)))
model.add(RepeatVector(output_sequence_length))
model.add(Bidirectional(GRU(256,return_sequences=True)))
model.add(TimeDistributed(Dense(french_vocab_size,activation='softmax')))
learning_rate = 0.005
model.compile(loss = sparse_categorical_crossentropy,
optimizer = Adam(learning_rate),
metrics = ['accuracy'])
return model
tests.test_model_final(model_final)print('Final Model Loaded')
最终模型载入
预言;预测;预告
def final_predictions(x, y, x_tk, y_tk):
tmp_X = pad(preproc_english_sentences)
model = model_final(tmp_X.shape,
preproc_french_sentences.shape[1],
len(english_tokenizer.word_index)+1,
len(french_tokenizer.word_index)+1)
model.fit(tmp_X, preproc_french_sentences, batch_size = 1024, epochs = 17, validation_split = 0.2)
y_id_to_word = {value: key for key, value in y_tk.word_index.items()}
y_id_to_word[0] = '<PAD>'sentence = 'he saw a old yellow truck'
sentence = [x_tk.word_index[word] for word in sentence.split()]
sentence = pad_sequences([sentence], maxlen=x.shape[-1], padding='post')
sentences = np.array([sentence[0], x[0]])
predictions = model.predict(sentences, len(sentences))print('Sample 1:')
print(' '.join([y_id_to_word[np.argmax(x)] for x in predictions[0]]))
print('Il a vu un vieux camion jaune')
print('Sample 2:')
print(' '.join([y_id_to_word[np.argmax(x)] for x in predictions[1]]))
print(' '.join([y_id_to_word[np.max(x)] for x in y[0]]))final_predictions(preproc_english_sentences, preproc_french_sentences, english_tokenizer, french_tokenizer)
Figure 13
我们得到了两个句子的完美翻译和 0.9776 的验证准确度分数!
源代码可以在 Github 找到。我期待听到反馈或问题。
从头开始的神经网络(使用 Numpy)
image Source: Data Flair
这篇文章是关于使用 Python 中的 numpy 库为分类问题从头构建一个浅层 NeuralNetowrk(nn )(只有一个隐藏层),并与 LogisticRegression(使用 scikit learn)进行性能比较。
从头开始构建神经网络有助于理解神经网络在后端如何工作,这对于构建有效的模型是必不可少的。让我们毫不迟疑地从头开始构建简单的浅层神经网络模型。
完整的代码可在 这里 。
对于这项任务,我正在使用 scikit learn 数据集生成器 make_gaussian_quantiles 函数生成数据集(生成各向同性高斯样本并按分位数标记样本)。生成的输入数据集将有两个特征(“X1”和“X2”),输出“Y”将有两个类(红色:0,蓝色:1),共有 200 个示例。
def load_extra_datasets():
**N = 200**
**gaussian_quantiles** = **sklearn.datasets.make_gaussian_quantiles**
(mean=None, cov=0.7, n_samples=N, **n_features=2, n_classes=2**, shuffle=True, random_state=None)
return gaussian_quantilesgaussian_quantiles= load_extra_datasets()
X, Y = gaussian_quantiles
X, Y = X.T, Y.reshape(1, Y.shape[0])# Visualize the data
plt.scatter(X[0, :], X[1, :], c=Y, s=40, cmap=plt.cm.Spectral);
生成的数据集有两个类,分别标为红色和蓝色的点。我们的目标是建立一个机器学习分类器,在给定 X 和 Y 坐标的情况下预测正确的类别。正如我们在图中看到的,数据不是线性可分的,所以我们不能画一条直线来分隔这两个类。这意味着线性分类器,如逻辑回归,将无法适合这些类型的数据。在这种情况下,神经网络会帮助我们。在神经网络中,不需要特征工程,因为隐藏层会自动学习特征模式,以准确地对数据进行分类。
逻辑回归:
首先,让我们使用输入的 x 和 y 值训练一个 LR 分类器,输出将是预测的类(0 或 1)。我们将使用 scikit-learn 中的回归类
clf = sklearn.linear_model.LogisticRegressionCV()
clf.fit(X.T, Y.T)# Plot the decision boundary for logistic regressionplot_decision_boundary(lambda x: clf.predict(x), X, Y)
plt.title("Logistic Regression")# Print accuracyLR_predictions = clf.predict(X.T)
print ('Accuracy of logistic regression: %d ' % float((np.dot(Y,LR_predictions) + np.dot(1-Y,1-LR_predictions))/float(Y.size)*100) +
'% ' + "(percentage of correctly labelled datapoints)")
从上面我们可以看到,LR 只能正确分类 53%的数据点,因为这些数据点不是线性可分的。
神经网络:
现在让我们建立一个简单的神经网络,1 个隐藏层,4 个神经元。输入层将有 2 个节点,因为我们的数据有两个特征(X1 和 X2),输出层将有一个节点,根据概率阈值,我们将输出分类为红色或蓝色(0 或 1)。
Source: Andrew Ng’s Coursera
我们需要做以下步骤来建立我们的神经网络模型。
- 定义网络结构(输入单元数量、隐藏单元数量等)。
- 初始化模型的参数
- 循环执行以下步骤,直到我们获得最小成本/最佳参数。
- 实现向前传播
- 计算损失
- 实现反向传播以获得梯度
- 更新参数
- 然后将上述所有步骤合并成一个函数,我们称之为‘nn _ model()’。
一旦我们建立了“nn_model()”并学习了正确的参数,我们就可以对新数据进行预测。
- 定义网络结构:如前所述,输入层的节点数为 2,隐藏层的节点数为 4。通过在这一层选择更多的节点,我们可以使模型学习复杂的函数。但是进行预测和学习网络参数需要大量的计算。更多的隐藏层和节点也会导致我们的数据过度拟合。
#X and Y are the input and output variables **n_x = X.shape[0] # size of input layer`
n_h = 4
n_y = Y.shape[0] # size of output layer**
2。初始化模型的参数 : W1(隐藏层的权重矩阵)和 W2(输出层的权重矩阵)参数使用 numpy 随机函数随机初始化。乘以 0.01,因为我们不希望初始权重过大,因为这会导致学习速度变慢。b1 和 b2 被初始化为零。
W1 —隐藏层的形状权重矩阵(n_h,n _ x)
B1—形状偏差向量(n_h,1)
W2 —输出层的形状权重矩阵(n_y,n _ h)
B2—形状偏差向量(n_y,1)
W1 = np.random.randn(n_h,n_x) * 0.01
b1 = np.zeros(shape=(n_h, 1))
W2 = np.random.randn(n_y,n_h) * 0.01
b2 = np.zeros(shape=(n_y, 1))
**3。前向传播:**在前向传播期间,输入特征矩阵被馈送到隐藏层中的每个神经元。其将乘以相应的初始权重集(W1)和偏差集(b1)以形成 Z1 矩阵(给定输入的线性变换)。然后,我们通过激活函数将非线性应用于 Z1(以应用非线性)。我们选择“tanh”作为我们的激活函数,因为它适合许多场景。这个激活函数/隐藏层的输出将是 a1(这是一个大小为(4,1)的矩阵,包含来自 4 个神经元的激活,即 A1、a2、a3、a4)。
对于下一层,在我们的情况下是最终输出层,我们将来自前一层(A1)的输入乘以输出层(W2)的初始权重,加上偏差(b2)以形成 Z2。然后在 Z2 上应用 sigmoid 激活函数以产生最终输出 A2(这是我们的预测)。我们使用 sigmoid 作为最后一层,因为我们希望我们的输出介于 0 和 1 之间。基于概率阈值,我们可以决定输出是红色还是蓝色。这就是 nn 如何在前向传播期间进行预测,这只是一系列矩阵乘法和激活函数的应用。
# Implement Forward Propagation to calculate A2 (probabilities)
Z1 = np.dot(W1,X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2,A1) + b2
A2 = sigmoid(Z2) # Final output prediction
4。计算损失:现在我们有了我们的预测,下一步将是检查我们的预测与实际值有多大差异,即损失/误差。这里我们不使用均方差(MSE)来计算我们的损失,因为我们的预测函数是非线性的(sigmoid)。平方预测将导致具有许多局部最小值的非凸函数。在这种情况下,梯度下降可能找不到最优的全局最小值。因此,我们使用二元交叉熵损失(用于误差估计的对数似然方法),该成本函数本质上是凸的,因此到达全局最小点(最小损失点)将更容易。下面是成本函数公式和代码。
m:训练实例的数量
# Compute the cross-entropy costlogprobs = np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2)
cost = - np.sum(logprobs) / m
5。反向传播/梯度下降(GD) :反向传播用于计算损失函数相对于模型参数(w1,b1,w2,b2)的梯度(斜率/导数)。为了最小化我们的成本,我们使用 GD 算法,该算法使用计算的梯度来更新参数,使得我们的成本随着迭代不断降低,即,它有助于向全局最小值移动。
- 以下是每个模型参数的梯度/斜率计算公式。“m”是训练样本的数量。
Sourced from Coursera
dZ2 = A2 - Y
dW2 = (1 / m) * np.dot(dZ2, A1.T)
db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)
dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))
dW1 = (1 / m) * np.dot(dZ1, X.T)
db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)
6。更新参数:一旦我们计算出我们的梯度,我们将它们乘以一个称为学习率(收敛率)的因子,并从初始参数中减去以获得更新的参数(权重和偏差)。学习率应该是最小的,这样我们就不会错过全局最小点。
- 用学习率乘以梯度
- 从重量中减去
W1 = W1 - learning_rate * dW1
b1 = b1 - learning_rate * db1
W2 = W2 - learning_rate * dW2
b2 = b2 - learning_rate * db2
现在,我们已经为所有训练示例执行了一轮前向传播和后向传播,即,我们完成了 1 个时期。我们需要在多个时期重复这些步骤,直到我们的成本最小(模型达到全局最小点)或者学习停止(参数没有更新)。
下面是函数“nn_model ”,它在给定的时期数(num_iterations)内重复执行上述所有操作,并在每 1000 个时期后打印成本。该函数的输出将是最终的一组优化参数(重量/基数)。
7。预测:下面是使用学习到的参数进行预测的函数,只需向前传播即可。我们将阈值设置为 0.5,如果最终层(A2)的输出是> 0.5,那么我们将其分类为 1:蓝色,否则为 0:红色。
现在,让我们通过运行函数 nn_model 超过 5000 个时期来训练我们的最终模型,并查看结果。
从结果可以看出,我们的神经网络模型很好地学习了模式。其能够学习分隔类别的非线性决策边界。而我们的成本从 0.69 开始,经过 4000 个纪元达到 0.089。最终的准确率达到 93%,这比我们从逻辑回归得到的只有 53%要高得多。
调整隐藏层大小:下一步是决定隐藏层神经元的最佳数量,看看我们的模型是否能在不过度拟合的情况下做得更好。为此,让我们使用不同数量的节点(1、2、3、4、5、20、50)来训练模型,并查看结果。
以下是这次测试的结果。
- 较大的模型(具有更多隐藏单元)能够更好地拟合训练集,直到最大的模型最终过度拟合数据。我们可以看到,在 n_h = 50 时,该模型似乎过拟合(100%精度)。
- 最佳隐藏层大小似乎在 n_h = 4 左右。事实上,这里的一个值似乎与数据吻合得很好,而不会引起明显的过度拟合。
非常感谢您阅读到最后,请评论任何建议/修改。请吧👏如果你喜欢邮报…😉
神经网络架构
深度神经网络和深度学习是强大和流行的算法。他们的成功很大程度上在于神经网络架构的精心设计。
我想在深度学习的背景下重温过去几年神经网络设计的历史。
关于这里报道的所有网络的更深入的分析和比较,请参见我们的最近的文章(以及更新的帖子)。这篇文章中的一个代表人物是:
Top1 vs. operations, size ∝ parameters. Top-1 one-crop accuracy versus amount of operations required for a single forward pass. See also here
在多种流行的神经网络架构中,报告单次正向传递所需的最高单作物精度与操作量。
LeNet5
这是 1994 年,这是最早的卷积神经网络之一,推动了深度学习领域的发展。自 1988 年以来,经过多次成功的反复,Yann LeCun 的这项开创性工作被命名为 LeNet5 !
LeNet5 架构是基础,特别是图像特征分布在整个图像上的观点,并且具有可学习参数的卷积是在多个位置用很少的参数提取相似特征的有效方法。当时没有 GPU 来帮助训练,甚至 CPU 也很慢。因此,能够节省参数和计算是一个关键的优势。这与使用每个像素作为大型多层神经网络的单独输入形成对比。LeNet5 解释说,这些不应用于第一层,因为图像是高度空间相关的,使用图像的单个像素作为单独的输入特征不会利用这些相关性。
LeNet5 的特点可以概括为:
- 卷积神经网络使用 3 层序列:卷积、池化、非线性–>这可能是本文以来图像深度学习的关键特征!
- 使用卷积提取空间要素
- 使用地图空间平均值的二次抽样
- tanh 或 sigmoids 形式的非线性
- 多层神经网络(MLP)作为最终分类器
- 层间连接矩阵稀疏,避免计算量大
总的来说,这个网络是最近许多架构的起源,也是这个领域许多人的真正灵感。
差距
从 1998 年到 2010 年,神经网络处于酝酿阶段。大多数人都没有注意到他们不断增强的力量,而其他许多研究人员却在慢慢进步。由于手机相机和廉价数码相机的兴起,越来越多的数据可用。计算能力在上升,CPU 变得更快,GPU 成为通用计算工具。这两种趋势都推动了神经网络的发展,尽管速度很慢。数据和计算能力使得神经网络处理的任务越来越有趣。然后很明显…
丹·奇雷桑网
2010 年,Dan Claudiu Ciresan 和 Jurgen Schmidhuber 发表了第一批 GPU 神经网络的实现之一。该实现在一个高达 9 层神经网络的英伟达 GTX 280 图形处理器上向前和向后实现。
AlexNet
2012 年,Alex Krizhevsky 发布了 AlexNet ,这是 LeNet 的一个更深入、更广泛的版本,并以较大优势赢得了困难的 ImageNet 竞赛。
AlexNet 将 LeNet 的见解扩展为一个更大的神经网络,可以用来学习更复杂的对象和对象层次。这项工作的贡献是:
- 使用校正线性单位(ReLU)作为非线性
- 在训练过程中使用丢弃技术选择性地忽略单个神经元,这是一种避免模型过度拟合的方法
- 重叠最大池,避免平均池的平均效应
- 使用 GPU英伟达 GTX 580 减少培训时间
当时,GPU 提供的内核数量比 CPU 多得多,训练时间也快了 10 倍,这反过来又允许使用更大的数据集和更大的图像。
AlexNet 的成功引发了一场小革命。卷积神经网络现在是深度学习的主力,它成为“现在可以解决有用任务的大型神经网络”的新名称。
吃得过多
2013 年 12 月,Yann LeCun 的 NYU 实验室提出了 Overfeat ,这是 AlexNet 的衍生产品。这篇文章还提出了学习包围盒,这后来引发了许多其他相同主题的论文。我相信学习分割物体比学习人工包围盒更好。
VGG
牛津的 VGG 网络率先在每个卷积层中使用更小的 3×3 滤波器,并将它们组合成一个卷积序列。
这似乎与 LeNet 的原理相反,LeNet 使用大卷积来捕捉图像中的相似特征。取代 AlexNet 的 9×9 或 11×11 过滤器,过滤器开始变得更小,太危险地接近 LeNet 想要避免的臭名昭著的 1×1 卷积,至少在网络的第一层。但是 VGG 最大的优点是洞察到顺序的多重 3×3 卷积可以模拟更大感受野的效果,例如 5×5 和 7×7。这些想法也将用于最近的网络架构,如 Inception 和 ResNet。
VGG 网络使用多个 3×3 卷积层来表示复杂的特征。注意,VGG-E: 256×256 和 512×512 3×3 滤波器的块 3、4、5 被按顺序多次使用,以提取更复杂的特征和这些特征的组合。这实际上就像拥有 3 层 512×512 的大型分类器,它们是卷积的!这显然意味着大量的参数和学习能力。但是这些网络的训练是困难的,不得不分成更小的网络,一层一层地增加。所有这一切都是因为缺乏强有力的方法来正则化模型,或者以某种方式限制由大量参数促进的大规模搜索空间。
VGG 在许多层中使用了大的特征尺寸,因此推断在运行时是相当昂贵的。减少特征的数量,就像在初始瓶颈中所做的那样,将会节省一些计算成本。
网络中的网络
网络中的网络 (NiN)有着伟大而简单的洞察力,使用 1x1 卷积为卷积层的功能提供更多组合能力。
NiN 架构在每次卷积后使用空间 MLP 图层,以便在另一个图层之前更好地组合要素。同样,人们可能会认为 1x1 卷积违反了 LeNet 的原始原则,但实际上它们有助于以更好的方式组合卷积功能,而这是通过简单地堆叠更多的卷积层不可能实现的。这不同于使用原始像素作为下一层的输入。这里,1×1 卷积用于在卷积后跨要素地图在空间上组合要素,因此它们有效地使用非常少的参数,在这些要素的所有像素之间共享!
通过将单个卷积特征组合成更复杂的组,MLP 的能力可以大大提高它们的有效性。这个想法将会在最近的架构中使用,比如 ResNet、Inception 和 derivatives。
NiN 还使用了一个平均池层作为最后一个分类器的一部分,这是另一个将变得普遍的实践。这样做是为了在分类之前平均网络对输入图像的多个区域的响应。
谷歌网和盗梦空间
来自谷歌的克里斯蒂安·塞格迪开始了一项旨在减少深度神经网络计算负担的探索,并设计了第一个盗梦空间架构。
到现在,2014 年秋天,深度学习模型在对图像和视频帧的内容进行分类时变得非常有用。大多数怀疑论者已经承认,深度学习和神经网络这次回来了。考虑到这些技术的有用性,像 Google 这样的互联网巨头对在他们的服务器农场上高效和大规模地部署架构非常感兴趣。
Christian 想了很多方法来减少深度神经网络的计算负担,同时获得最先进的性能(例如,在 ImageNet 上)。或者能够保持相同的计算成本,同时提供改进的性能。
他和他的团队想出了盗梦空间模块:
乍一看,它基本上是 1×1、3×3 和 5×5 卷积滤波器的并行组合。但是,inception 模块的伟大之处在于使用 1×1 卷积模块(NiN)来减少昂贵的并行模块之前的功能数量。这就是通常所说的“瓶颈”。这值得单独一节来解释:参见下面的“瓶颈层”一节。
GoogLeNet 使用了一个没有初始模块的词干作为初始层,以及一个类似于 NiN 的平均池加 softmax 分类器。与 AlexNet 和 VGG 的分类器相比,这个分类器的运算量也非常低。这也促成了非常高效的网络设计。
瓶颈层
受 NiN 的启发,《盗梦空间》的瓶颈层减少了每一层的功能和操作数量,因此推理时间可以保持在较低水平。在将数据传递到昂贵的卷积模块之前,特征的数量减少了,比如说,4 倍。这导致了计算成本的大量节省,以及这种架构的成功。
让我们详细检查一下。假设你有 256 个特性进来,256 个出来,假设初始层只执行 3x3 的卷积。也就是说,需要执行 256×256×3×3 的卷积运算(589,000 次乘法累加或 MAC 运算)。这可能超过了我们的计算预算,比如说,在谷歌服务器上 0.5 毫秒内运行这一层。我们没有这样做,而是决定减少必须进行卷积的特征数量,比如减少到 64 或 256/4。在这种情况下,我们首先执行 256 -> 64 个 1×1 卷积,然后在所有初始分支上执行 64 个卷积,然后我们再次使用来自 64 -> 256 个特征的 1x1 卷积。现在的操作是:
- 256×64 × 1×1 = 16,000 个
- 64×64 × 3×3 = 36,000 个
- 64×256 × 1×1 = 16,000 个
总计约 7 万英镑,而之前我们有近 60 万英镑。几乎减少了 10 倍的操作!
而且虽然我们做的操作少了,但是在这一层并没有失去通用性。事实上,瓶颈层已经被证明可以在 ImageNet 数据集上以最先进的方式执行,并且还将被用在 ResNet 等后来的架构中。
成功的原因是输入特征是相关的,因此可以通过将它们与 1x1 卷积适当组合来消除冗余。然后,在与少量要素卷积后,它们可以再次扩展为对下一层有意义的组合。
盗梦空间 V3(和 V2)
克里斯蒂安和他的团队是非常高效的研究人员。2015 年 2 月批量规范化的 Inception 作为 Inception V2 被引入。批量归一化计算图层输出中所有要素地图的平均值和标准差,并使用这些值对其响应进行归一化。这相当于“白化”数据,从而使所有的神经图具有相同范围内的响应,并且具有零均值。这有助于训练,因为下一层不必学习输入数据中的偏移,并且可以专注于如何最佳地组合要素。
2015 年 12 月,他们发布了新版本的 Inception 模块和相应的架构这篇文章更好地解释了最初的 GoogLeNet 架构,给出了更多关于设计选择的细节。最初的想法有:
- 通过精心构建深度和宽度平衡的网络,最大化流入网络的信息。每次汇集前,增加特征地图。
- 当深度增加时,特征的数量或层的宽度也系统地增加
- 在每一层使用宽度增加来增加下一层之前的要素组合
- 如果 5×5 和 7×7 滤波器可以用多个 3×3 来分解,则尽可能只使用 3×3 卷积。见图:
- 因此,新的初始模块变成:
- 过滤器也可以通过扁平卷积分解成更复杂的模块:
- 在执行初始计算时,初始模块还可以通过提供池来减少数据的大小。这基本上等同于使用简单的池层并行执行步长卷积:
Inception 仍然使用一个池层加上 softmax 作为最终分类器。
雷斯内特
革命在 2015 年 12 月到来,大约与《盗梦空间 3》同时。 ResNet 有一个简单的想法:将两个连续卷积层的输出馈入,同时将输入旁路到下一层!
这类似于像这个这样的老创意。但在这里它们绕过了两层,被大规模应用。绕过两层后是一个关键的直觉,因为绕过一层不会有太大的改善。通过 2 层可以认为是一个小的分类器,或网络中的网络!
这也是第一次训练超过 100 层甚至 1000 层的网络。
拥有大量层的 ResNet 开始使用类似于 Inception 瓶颈的瓶颈层:
该图层通过首先使用具有较小输出(通常为输入的 1/4)的 1x1 卷积,然后使用 3x3 图层,然后再次使用 1x1 卷积来减少每个图层的要素数量。就像在 Inception 模块的情况下,这允许保持低计算量,同时提供丰富的特性组合。参见“GoogLeNet 和 Inception”之后的“瓶颈层”部分。
ResNet 在输入端使用了一个相当简单的初始层(stem):一个 7x7 的 conv 层,然后是一个 2 层的池。相比之下,在 Inception V3、V4 中,词干更复杂,更不直观。
ResNet 还使用一个池层加上 softmax 作为最终分类器。
关于 ResNet 架构的其他见解每天都在出现:
- ResNet 可以被看作是并行和串行模块,只要把 inout 看作是并行到许多模块,而每个模块的输出是串行连接的
- ResNet 也可以被认为是多个并行或串行模块的集合体
- 人们发现,ResNet 通常在深度相对较低(约 20–30 层)的区块上运行,这些区块并行运行,而不是在网络的整个长度上串行流动。
- ResNet,当输出反馈到输入时,就像在 RNN,网络可以被看作是大脑皮层的一个更好的生物模型
初始版本 4
克里斯蒂安和他的团队又开始了新版本的《盗梦空间》。
stem 之后的 Inception 模块与 Inception V3 非常相似:
他们还将 Inception 模块与 ResNet 模块结合起来:
在我看来,这一次的解决方案不太优雅,也更复杂,但也充满了不太透明的启发。很难理解这些选择,作者也很难证明它们是正确的。
在这方面,ResNet 获得了一个干净简单、易于理解和修改的网络奖。
挤压网
SqueezeNet 最近已经发布。它是 ResNet 和 Inception 中许多概念的重新组合,表明毕竟更好的架构设计将提供较小的网络大小和参数,而不需要复杂的压缩算法。
ENet
我们的团队着手将最新架构的所有功能整合到一个非常高效、轻量级的网络中,使用非常少的参数和计算来实现最先进的结果。这个网络架构被称为 ENet ,由亚当·帕兹克设计。我们用它来执行像素标记和场景解析。下面是 ENet 的一些视频。这些视频不是训练数据集的一部分。
有关 ENet 的技术报告可在此处获得。ENet 是一个编码器加解码器的网络。编码器是用于分类的常规 CNN 设计,而解码器是用于将类别传播回原始图像大小以进行分割的上采样网络。这种方法只使用了神经网络,没有使用其他算法来执行图像分割。
正如你在这个图中看到的,ENet 在所有的神经网络中,每个参数的精确度都是最高的!
ENet 从一开始就被设计成使用尽可能少的资源。因此,它的尺寸非常小,编码器和解码器网络总共仅占用 0.7 MB,fp16 精度。即使在这样小的尺寸下,ENet 在分割精度上类似于或高于其他纯神经网络解决方案。
模块分析
CNN 模块的系统评估已经提交。这一发现有利于使用:
使用不带 batchnorm 或 ReLU 的 ELU 非线性。
应用学习到的 RGB 色彩空间转换。
使用线性学习率衰减策略。
使用平均池层和最大池层的总和。
使用大约 128 或 256 的小批量。如果这对于你的 GPU 来说太大了,那就按照批量大小成比例地降低学习速率。
使用全连接层作为卷积层,并对最终决策的预测进行平均。
当投资增加训练集规模时,检查是否尚未达到稳定水平。数据的整洁比大小更重要。
如果您不能增加输入图像的尺寸,则减少后续层的步幅,效果大致相同。
如果您的网络具有复杂且高度优化的架构,例如 GoogLeNet,请谨慎修改。
例外
Xception 对 inception 模块和架构进行了改进,采用了一种更简单、更优雅的架构,与 ResNet 和 Inception V4 一样有效。
这里给出了异常模块:
该网络可以是任何人的最爱,因为其架构简单而优雅,如下所示:
该架构有 36 个卷积级,与 ResNet-34 非常相似。但是模型和代码就像 ResNet 一样简单,而且比 Inception V4 更容易理解。
这个网络的 Torch7 实现可用这里一个 Keras/TF 的实现可用这里。
有趣的是,最近的 Xception 架构也受到了我们关于可分离卷积滤波器的工作的启发。
移动网络
新的 M obileNets 架构也将于 2017 年 4 月推出。这种架构使用可分离的卷积来减少参数的数量。除了上面的例外,单独的卷积是相同的。现在,这篇论文声称参数有了很大的减少——在 FaceNet 的情况下大约是 1/2,正如论文中所报道的。以下是完整的模型架构:
MobileNets
不幸的是,我们在实际应用中测试了这个网络,发现它在 Titan Xp GPU 上的一批 1 上非常慢。看一下每张图片推理时间的比较:
- resnet18 : 0.002871
- alexnet : 0.001003
- vgg16 : 0.001698
- 挤压网:0.002725
- 移动网络:0.033251
显然这不是一个快速推理的竞争者!它可以减少磁盘上网络的参数和大小,但不可用。
其他著名的架构
FractalNet 使用了一种递归架构,这种架构没有在 ImageNet 上测试过,它是一种衍生或更通用的 ResNet。
更新
关于比较的更新,请见本帖。
今后
我们认为,打造神经网络架构对于深度学习领域的进步至关重要。我们小组强烈建议仔细阅读并理解这篇文章中的所有论文。
但是现在有人可能会问,为什么我们要花这么多时间来精心设计架构,为什么我们不用数据来告诉我们使用什么,以及如何组合模块。这将是美好的,但现在它正在进行中的工作。一些有趣的初步结果是这里。
还要注意,这里我们主要讨论了计算机视觉的架构。类似地,神经网络体系结构在其他领域得到了发展,研究所有其他任务的体系结构的演变也是很有趣的。
如果您对神经网络架构和计算性能的比较感兴趣,请参见我们最近的论文。
感谢
这篇文章的灵感来自与 Abhishek Chaurasia,Adam Paszke,Sangpil Kim,Alfredo Canziani 和其他人在我们普渡大学电子实验室的讨论。
关于作者
我在硬件和软件方面都有将近 20 年的神经网络经验(一个罕见的组合)。在这里看关于我:媒介、网页、学者、 LinkedIn 等等…
神经网络基准
我们正在经历神经网络架构的寒武纪大爆发。每个新设计都有一个基准——“它对猫的识别能力如何?”它能玩雅达利游戏吗?它能探测到停车标志吗?研究人员使用可用的基准数据集,将他们的神经网络的性能与其他架构进行比较。然而,这些数据集是有限的。
特别是有标签的数据,很难得到。测试非常深的神经网络需要大量的数据,并且很少有数据集大到足以允许对深度网络进行比较。因此,我们应该在产生的数据上测试新的神经网络。
通过生成数据,而不是管理,我们自动地给它们贴上标签。而且,生成的数据可以存在于准确性的连续统上,这允许我们看到一个网络是否擅长于识别微小的错误。这为我们提供了架构的敏感性和复杂性的度量,这在精选的数据集中是不可用的。有了生成的数据,我们可以更清楚地了解网络的学习情况,以及它在哪里出错。
生成训练和验证数据
作为生成数据的一个例子,考虑轨道力学:我们可以创建一个简单的软件,在 2D 平面上随机放置“行星”,每个都有质量、位置和速度。每次调用该软件时,它会在平面上放置一组“行星”,并在固定的时间内运行它们的轨道模型。这些样本可用于训练和验证,而无需耗尽数据集!该网络能够从任意大小的数据集进行采样——如果你想要更多的数据,只需再次调用物理软件。在训练期间,你可以很容易地生成十亿个样本轨道!
当软件模拟一个没有干扰的轨道时,我们可以自动将该轨道标记为“正确的”。为了生成“不正确”的轨道,我们引入了一些扰动*——在模拟的某个时刻,我们随机推动了一些“行星”,使它们不符合物理规律。神经网络的任务是区分“正确的”轨道力学和“不正确的”轨道。这是允许我们比较不同神经架构的性能的基准。*
因为我们正在生成我们的数据,我们可以调整发生多大的扰动。如果一个单独的“行星”被轻微推动,我们将其归类为“轻微不正确”。同时,当许多“行星”被大量推动时,我们可以将它们的轨道归类为“非常不正确”。以这种方式,我们形成了一个连续体:“完全正确”→“极度错误”。这是一个至关重要的能力,是猫照和手写数字所缺乏的。
比较网络的敏感性和复杂性
假设你想对一个新的神经网络进行基准测试,使用轨道力学软件,你给每个网络输入数十亿个轨道,并测量它们各自的精度。经过同样的训练后,两个网络都能识别出轨道何时“严重错误”——它们都能发现大的扰动。然而,你的新网络更善于识别“稍微不正确”的轨道!这表明你的新网络具有更高的灵敏度。
而且,你可以在增加“行星”数量的轨道上训练这两个网络。当只有 3 或 4 个“行星”时,两个网络都表现良好。然而,当“行星”的数量增长到 7 或 8 时,你的新网络仍然准确,而另一个网络开始失效。这表明你的新网络处理更大的复杂性。
这允许我们明确地测量网络深度的值。如果一个 4 层卷积神经网络很好地处理 3 个“行星”,但是当给定 4 个“行星”时变得有故障,那么该 4 层网络具有“3 行星复杂性”。为了诊断 4 颗或更多“行星”的轨道,我们需要增加网络的深度。
深度人脉的价值
通过连续增加神经网络的深度,并测试它可以处理多少个“行星”,我们得到了作为深度函数的网络复杂性的度量。我们可以回答结构性的问题:“如果我把网络的深度增加一倍,我能把行星的数量增加一倍吗?“也许,更深层次的网络处理复杂性的速度越来越快——如果一个 4 层网络处理‘3 星球复杂性’,一个 8 层网络可能在‘7 星球复杂性’上成功。如果是这样的话,**这是疯狂建立深层网络**的最强有力的论据。
然而,如果深层网络变慢(例如,8 层网络仅在“5 个星球的复杂性”下运行),这就是让许多浅层网络串联运行的理由。这是目前一个未解决的问题*。猫照永远也回答不了。沿着正确性和复杂性的连续体生成数据集为我们提供了一条通往答案的道路。*
解释了神经网络嵌入
(Source)
深度学习如何将战争与和平表示为一个向量
近年来,神经网络的应用从图像分割到自然语言处理再到时间序列预测都有了很大的发展。深度学习的一个显著成功的应用是嵌入,这是一种用于将离散变量表示为连续向量的方法。这种技术已经在实际应用中找到了用于机器翻译的单词嵌入和用于分类变量的实体嵌入。
在本文中,我将解释什么是神经网络嵌入,为什么我们要使用它们,以及它们是如何学习的。我们将在我正在解决的一个实际问题的背景下讨论这些概念:将维基百科上的所有书籍表示为向量,以创建一个图书推荐系统。
Neural Network Embedding of all books on Wikipedia. (From Jupyter Notebook on GitHub).
嵌入
嵌入是离散分类变量到连续数字向量的映射。 在神经网络的背景下,嵌入是低维、 学习到的离散变量的连续向量表示。神经网络嵌入是有用的,因为它们可以减少分类变量的维度并且有意义地表示变换空间中的类别。
神经网络嵌入有 3 个主要目的:
- 在嵌入空间中寻找最近的邻居。这些可以用来根据用户兴趣或聚类类别进行推荐。
- 作为监督任务的机器学习模型的输入。
- 用于可视化概念和类别之间的关系。
这意味着就图书项目而言,使用神经网络嵌入,我们可以获得维基百科上所有的 37,000 篇图书文章,并用向量中的 50 个数字来表示每一篇文章。此外,因为嵌入是习得的,在我们学习问题的上下文中更相似的书籍在嵌入空间中彼此更接近。
神经网络嵌入克服了表示分类变量的常用方法的两个局限性:一键编码。
一个热编码的局限性
一键编码分类变量的操作实际上是一个简单的嵌入,其中每个类别被映射到一个不同的向量。该过程采用离散的实体,并将每个观察值映射到 0 的向量和表示特定类别的单个 1。
独热编码技术有两个主要缺点:
- 对于高基数变量——具有许多独特类别的变量——转换后的向量的维数变得难以管理。
- 这种映射是完全不知情的:“相似的”类别在嵌入空间中不会彼此放置得更近。
第一个问题很好理解:对于每一个额外的类别——被称为一个实体——我们必须向独热编码向量添加另一个数字。如果我们在维基百科上有 37,000 本书,那么表示这些书需要每本书 37,000 维的向量,这使得在这种表示上训练任何机器学习模型都不可行。
第二个问题同样具有局限性:独热编码不会将相似的实体在向量空间中放置得更近。如果我们使用余弦距离来度量向量之间的相似性,那么在一次热编码之后,对于实体之间的每次比较,相似性都是 0。
这意味着像《T2》《战争与和平》《T3》《T4》《安娜·卡列尼娜》《T5》(都是列夫·托尔斯泰的经典著作)这样的实体彼此之间的距离并不比《战争与和平》《T7》和《银河系漫游指南》的距离更近,如果我们使用一键编码的话。
**# One Hot Encoding Categoricals****books = ["War and Peace", "Anna Karenina",
"The Hitchhiker's Guide to the Galaxy"]****books_encoded = [[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]****Similarity (dot product) between First and Second = 0
Similarity (dot product) between Second and Third = 0
Similarity (dot product) between First and Third = 0**
考虑到这两个问题,表示分类变量的理想解决方案需要的数字比唯一类别的数字少,并且将相似的类别彼此放置得更靠近。
**# Idealized Representation of Embedding****books = ["War and Peace", "Anna Karenina",
"The Hitchhiker's Guide to the Galaxy"]****books_encoded_ideal = [[0.53, 0.85],
[0.60, 0.80],
[-0.78, -0.62]]****Similarity (dot product) between First and Second = 0.99
Similarity (dot product) between Second and Third = -0.94
Similarity (dot product) between First and Third = -0.97**
为了构建分类实体的更好表示,我们可以使用嵌入神经网络和监督任务学习嵌入。
学习嵌入
独热编码的主要问题是转换不依赖于任何监督。我们可以通过在监督任务中使用神经网络来学习嵌入,从而极大地改进嵌入。嵌入形成了网络的参数——权重,其被调整以最小化任务上的损失。得到的嵌入向量是类别的表示,其中相似的类别(相对于任务)彼此更接近。
例如,如果我们有一个在电影评论集中使用的 50,000 个单词的词汇表,我们可以使用训练来预测评论情感的嵌入神经网络来学习每个单词的 100 维嵌入。(具体应用见这款 Google Colab 笔记本)。词汇表中与积极评价相关联的词,如“精彩”或“优秀”,将在嵌入空间中更接近地出现,因为网络已经知道这些都与积极评价相关联。
Movie Sentiment Word Embeddings (source)
在上面给出的书的例子中,我们的监督任务可以是“识别一本书是否是列夫·托尔斯泰写的”,由此产生的嵌入将把托尔斯泰写的书彼此放得更近。弄清楚如何创建受监督的任务来产生相关的表示是进行嵌入的最困难的部分。
履行
在维基百科图书项目(完整笔记本此处)中,监督学习任务被设定为预测给定的维基百科页面链接是否出现在一本书的文章中。我们提供成对的(书名,链接)训练示例,其中混合了正面-正确-和负面-错误-对。这种设置基于这样的假设,即链接到相似维基百科页面的书籍彼此相似。因此,最终的嵌入应该将相似的书籍在向量空间中更紧密地放置在一起。
我使用的网络有两个平行的嵌入层,用于将图书和 wikilink 映射为单独的 50 维向量,还有一个点积层,用于将嵌入合并为单个数字以进行预测。嵌入是网络的参数或权重,在训练期间被调整以最小化监督任务的损失。
在 Keras 代码中,如下所示(如果您没有完全理解代码,请不要担心,直接跳到图片):
虽然在监督机器学习任务中,目标通常是训练模型对新数据进行预测,但在这种嵌入模型中,预测可能只是达到目的的一种手段。我们想要的是嵌入权重,将书籍和链接表示为连续向量。
嵌入本身并不有趣:它们只是数字的向量:
Example Embeddings from Book Recommendation Embedding Model
然而,嵌入可以用于前面列出的 3 个目的,对于这个项目,我们主要感兴趣的是基于最近邻居推荐书籍。为了计算相似性,我们取一个查询书,并找到它的向量和所有其他书的向量之间的点积。(如果我们的嵌入是归一化的,这个点积就是向量之间的余弦距离,范围从-1,最不相似,到+1,最相似。我们也可以使用欧几里德距离来度量相似性)。
这是我构建的图书嵌入模型的输出:
**Books closest to War and Peace.****Book: War and Peace Similarity: 1.0
Book: Anna Karenina Similarity: 0.79
Book: The Master and Margarita Similarity: 0.77
Book: Doctor Zhivago (novel) Similarity: 0.76
Book: Dead Souls Similarity: 0.75**
(向量与其自身的余弦相似度必须为 1.0)。经过一些维度的缩减(见下文),我们可以做出如下图:
Embedding Books with Closest Neighbors
我们可以清楚地看到学习嵌入的价值!我们现在对维基百科上的每一本书都有 50 个数字的表示,相似的书彼此更接近。
嵌入可视化
关于嵌入最酷的部分之一是,它们可以用来可视化概念,如小说或非小说彼此之间的关系。这需要进一步的降维技术来使维数达到 2 或 3。最流行的约简技术本身就是一种嵌入方法:t 分布随机近邻嵌入(TSNE)。
我们可以获取维基百科上所有书籍的原始 37,000 个维度,使用神经网络嵌入将它们映射到 50 个维度,然后使用 TSNE 将它们映射到 2 个维度。结果如下:
Embedding of all 37,000 books on Wikipedia
(TSNE 是一种流形学习技术,这意味着它试图将高维数据映射到低维流形,从而创建一种嵌入,试图保持数据中的局部结构。它几乎专门用于可视化,因为输出是随机的,并且不支持转换新数据。一个很有前途的替代方案是均匀流形逼近和投影,UMAP,它更快并且支持将新数据转换到嵌入空间。
这本身并不是很有用,但是一旦我们开始根据不同的书籍特点给它上色,它就会变得很有洞察力。
Embeddings Colored by Genre
我们可以清楚地看到属于同一流派的书籍分组。这并不完美,但仍然令人印象深刻的是,我们可以只用两个数字来表示维基百科上的所有书籍,这仍然可以捕捉到不同流派之间的差异。
书中的例子(整篇文章即将发表)展示了神经网络嵌入的价值:我们有一个分类对象的向量表示,它是低维的,并且将相似的实体在嵌入的空间中彼此放置得更近。
额外收获:交互式可视化
静态图的问题是,我们不能真正探索数据和调查变量之间的分组或关系。为了解决这个问题,TensorFlow 开发了投影仪,这是一个在线应用程序,让我们可以可视化嵌入并与之交互。我将很快发布一篇关于如何使用这个工具的文章,但是现在,这里是结果:
Interactive Exploration of Book Embeddings using projector
结论
神经网络嵌入是作为连续向量的离散数据的学习低维表示。这些嵌入克服了传统编码方法的局限性,可用于诸如寻找最近邻居、输入另一个模型和可视化等目的。
虽然许多深度学习概念是用学术术语谈论的,但神经网络嵌入既直观又相对容易实现。我坚信任何人都可以学习深度学习并使用 Keras 等库构建深度学习解决方案。嵌入是处理离散变量的有效工具,并呈现深度学习的有用应用。
资源
一如既往,我欢迎反馈和建设性的批评。你可以通过推特 @koehrsen_will 或者我的个人网站 willk.online 找到我。
软件工程师的神经网络 2:小批量训练和验证
在我们之前的帖子软件工程师的神经网络 1 中,我们了解并实现了一些关于使用多层感知器的基本特性,并在 Python/Numpy 中实现了这些特性。
现在让我们看看如何将它应用到一个简单的现实世界问题中。让我们来看一下手写数字图像的分类。
首先,让我们浏览一下重要的,让我们导入数据,这些数据已经分成一个训练集和一个测试数据集,前者可以用来优化我们的网络,后者可以用来验证我们的性能。
接下来,我们将使用与上一篇博文几乎相同的代码,但这次我们将在训练集上进行训练,在测试集上进行验证,并绘制两条性能曲线。
另请注意,这次我们将执行小批量更新,而不是完整培训批量更新。这样,我们可以通过只查看数据集的一小部分来更快地执行更新。随机与小批量与全批量梯度下降是另一个主题,如果需要,我可以写另一篇博文来描述。
请注意,训练和验证的准确性仍然很糟糕,没有接近 100%。在这个系统真正工作之前,我们仍然有一些关键的改进要实现,但我们至少演示了如何将一个普通的神经网络应用到现实世界的问题中,以及通过 NumPy 矩阵数学理解的所有部分。
在这篇文章之后,我们将:
- 思考我们的数据的意义,并构建我们的模型以一种深思熟虑的方式来表示它。(链接到卷积后)
- 以一种有意义的方式思考我们的损失函数,建立我们的损失函数,给我们一个有意义的梯度。(房价亏损帖链接)
- 像上面那样思考我们想要什么,但是使用 Tensorflow 这样的神经网络 API 来实现。哇,太简单了!(链接 Tensorflow 房价贴)
软件工程师神经网络导论 1——香草 MLP
这第一篇博文将帮助你用 Python/Numpy 设计一个神经网络。它将展示普通多层感知器(MLPs)的衰落,提出一些简单的增强,并展示它们有多重要。最后,我们将展示这在一个组织良好的软件工程包中会是什么样子。
对于非技术前言,请阅读 ML 前言以了解回归。
为了理解数学,可选地将最初的 numpy 版本与包含可视化的https://medium . com/coin monks/the-mathematics-of-neural-network-60a 112 dd3 e 05进行比较。
软件工程师神经网络导论
首先,我们将建立一个简单的神经网络(NN 或多层感知器/MLP):
在数学上,我们将定义一个具有一个隐藏层的神经网络如下:
x: input matrix
w1: 1st weight matrix for multiplication
w2: 2nd weight matrix for multiplication
Hidden = matrix_multiplication(x, w1)
Hidden_rectified = Clip(Hidden, minimum_value = 0)
output = matrix_multiplication(Hidden_rectified, w2
这样,我们将输出计算为输入的函数。我们回顾微积分和线性代数,通过梯度下降最小化损失函数来优化(训练)我们的 MLP 以匹配数据集。
哦不!我们的损失激增。一个基本的神经网络对它的学习速率非常敏感,因为它的梯度会爆炸。一旦梯度变大,它们可以不断地来回摆动它们相应的权重,并爆炸到无穷大。
让我们通过将应用的渐变剪切到[-1,1]来解决这个问题。
让我们也将学习率衰减到 0,以允许网络首先以大的学习率接近合理的解决方案,然后通过小的调整确定特定的解决方案。
梯度削波也是通过将梯度削波到具有最大向量范数来完成的,并且学习率衰减有时被完全忽略,以利于其他微调策略,如 l2 正则化或批量增加。
太好了!我们的损失函数现在向零递减。
你听说过动量优化器或者亚当优化器吗?看看上面曲线中波动的损失,你是否注意到它上下摆动,而通常向下移动?
动量是在一个合理的恒定方向上保持速度的概念。当我们接收到一个梯度来调整我们的参数时,我们更新我们正在移动的速度,然后继续沿着我们认为在我们的参数空间中有效的方向行进。准确地说,
Value = Value-gradient
变成了:
velocity = velocity * momentum + gradient * (1-momentum)
Value = Value-velocity
现在,通过动量和函数化我们的损失函数作为一个抽象层,为备选损失函数做准备,我们的代码变成:
太好了!我们的损失变小得更快,接近一个更小的值。让我们再添加一个机器学习工具来帮助模型更可靠地学习,称为“内斯特罗夫动量”
内斯特罗夫的动量工程受到以下启发。在给定的有动力的一步,你大概知道你将采取的下一步。让我们看看我们期望移动的地方,计算那里的梯度,用这个梯度来修正我们的动量向量。然后用新的动量向量,我们像往常一样前进。
Theoretical_next_state = Value - Velocity
gradient = gradient at Theoretical_next_state
Velocity = Velocity * momentum + gradient * (1-momentum)
Value = Value-Velocity
同时,我们注意到 ReLU 非线性的一个问题,即 ReLU 曲线的“关闭”部分的导数为零。让我们用更流行的泄漏 ReLU 来代替我们的 ReLU,固定这个零导数,平坦区域有一个缓坡。
ReLU(x) = max(x, 0)
becomes:
lReLU(x) = max(x, .1*x)
请耐心等待这一段,因为演示数学的代码有点疯狂。在下一部分中,我们将组织它,以便观众中的软件工程师感到舒适。
太好了!内斯特罗夫的势头奏效了。但是看看这段代码!太恐怖了。我们硬编码了整个系统来实现一个神经网络
- 恰好一个隐藏层
- 泄漏的 relu 非线性
- 整批优化
如果我们想要改变其中的任何一个,我们就必须改变多个系统来硬编码我们想要尝试的其他系统。我暂时不做解释,但是让我们来看看这个系统到底有多干净和可重用。我们暂时把它作为一个文件,这样我们就可以很容易地在博客中展示它。
万岁!我们有干净的软件来定义、训练和评估一个模型。从机器学习和软件工程的角度来看,我们的实现仍然存在一些巨大的问题,但它展示了一般的概念。
在现实世界中,我们会(未来的连续博客文章):
- 解决一个真实世界的问题,然后在单独的验证数据集上训练和评估我们的问题。
- 思考我们的数据的意义,并构建我们的模型以一种深思熟虑的方式来表示它。(链接到卷积后)
- 以一种有意义的方式思考我们的损失函数,建立我们的损失函数,给我们一个有意义的梯度。(房价亏损帖链接)
- 像上面那样思考我们想要什么,但是使用 Tensorflow 这样的神经网络 API 来实现。哇,太简单了!(链接 Tensorflow 房价贴)
神经网络优化算法
基于张量流的比较研究
用于训练神经网络的常用优化算法有哪些?他们如何比较?
本文试图以一个卷积神经网络(CNN)为例,通过 TensorFlow 在 MNIST 数据集上进行训练来回答这些问题。
随机梯度下降
SGD 通过获取大小为( m )的数据子集或小批量数据,在梯度( g )的负方向上更新模型参数(θ):
神经网络用 f(x(i)表示;θ)其中 x(i) 是训练数据,而 y(i) 是训练标签,损失的梯度 L 是相对于模型参数θ计算的。学习率( eps_k )决定了算法沿梯度的步长大小(最小化时为负方向,最大化时为正方向)。
学习率是迭代 k 的函数,是一个最重要的超参数。学习率太高(如> 0.1)会导致参数更新错过最佳值,学习率太低(如< 1e-5)会导致不必要的长训练时间。一个好的策略是以 1e-3 的学习速率开始,并使用一个学习速率计划,该计划将学习速率降低为迭代的函数(例如,每 4 个时期将学习速率减半的步长计划器):
*def step_decay(epoch):
lr_init = 0.001
drop = 0.5
epochs_drop = 4.0
lr_new = lr_init * \
math.pow(drop, math.floor((1+epoch)/epochs_drop))
return lr_new*
一般来说,我们希望学习率( eps_k )满足罗宾斯-门罗条件:
第一个条件确保算法将能够找到局部最优解,而不管起始点是什么,第二个条件控制振荡。
气势
动量累积过去梯度的指数衰减移动平均值,并继续向其方向移动:
因此,步长取决于梯度序列的大小和对齐程度,动量参数α的常见值为 0.5 和 0.9。
内斯特罗夫势头强劲
内斯特罗夫动量的灵感来自内斯特罗夫的加速梯度法:
内斯特罗夫动量和标准动量的区别在于梯度的计算,而内斯特罗夫动量是在施加当前速度后计算梯度,因此内斯特罗夫动量为梯度增加了一个修正因子。
阿达格拉德
AdaGrad 是一种用于设置学习速率的自适应方法[3]。考虑下图中的两种情况。
在缓慢变化的物镜(左)的情况下,梯度通常(在大多数点)具有小的幅度。因此,我们需要一个大的学习率来快速达到最优。对于快速变化的物镜(右图),梯度通常会非常大。使用较大的学习速率会导致非常大的步长,来回摆动但达不到最佳值。
这两种情况的发生是因为学习率的设置与梯度无关。AdaGrad 通过累加目前所见梯度的平方范数并将学习率除以该和的平方根来解决这个问题:
结果,接收高梯度的参数将降低其有效学习率,而接收小梯度的参数将提高其有效学习率。净效应是在参数空间的更平缓倾斜方向上的更大进展,以及在存在大梯度的情况下更谨慎的更新。
RMSProp
RMSProp 通过将梯度累积改变为指数加权移动平均来修改 AdaGrad,即它丢弃了遥远过去的历史[4]:
注意,即使梯度由于从训练开始的梯度积累而保持恒定,AdaGrad 也意味着学习速率降低。通过引入指数加权移动平均线,与遥远的过去相比,我们更重视最近的过去。结果表明,RMSProp 是一种有效实用的深度神经网络优化算法。
亚当
Adam 源自“自适应矩”,它可以被视为 RMSProp 和 momentum 组合的变体,更新看起来像 RMSProp,只是使用了平滑版本的梯度而不是原始随机梯度,完整的 Adam 更新还包括偏差校正机制[5]:
推荐值为 beta_1 = 0.9,beta_2 = 0.999,eps = 1e-8。
实验
使用 TensorFlow 在 MNIST 数据集上训练简单的 CNN 架构,具有 1e-3 学习速率和交叉熵损失,使用四种不同的优化器:SGD、内斯特罗夫动量、RMSProp 和 Adam。下图显示了训练损失值与迭代次数的关系:
从图中我们可以看到,亚当和内斯特罗夫动量优化器产生最低的训练损失!
代码
下面的 ipython 笔记本中有全部代码。
结论
我们比较了用于训练神经网络的不同优化器,并获得了它们如何工作的直觉。我们发现,当在 TensorFlow 中对 MNIST 数据训练简单 CNN 时,具有内斯特罗夫动量和 Adam 的 SGD 产生最佳结果。
参考文献
[1]伊恩·古德费勒等人。艾尔。,“深度学习”,麻省理工出版社,2016
[2]安德烈·卡帕西,http://cs231n.github.io/neural-networks-3/
[3]杜奇,j .,哈赞,e .和辛格,y .“在线学习和随机优化的自适应次梯度方法”,JMLR,2011 年。
[4]t . tie leman 和 and Hinton,“讲座 6.5 — RMSProp,COURSERA:用于机器学习的神经网络”,技术报告,2012 年。
[5]迪耶德里克·金玛和吉米·巴,“亚当:一种随机优化方法”,2015