伟大假说的形成
比尔和梅林达·盖茨最喜欢的书factfulity将如何超越你的数据科学实践
动机
到目前为止,数据科学教育主要关注数据争论、假设检验和因果推断。我们很少听说前一步——假设形成。
形成错误的假设代价高昂
一旦你开始测试一个假设,你可以花费几个小时、几天、几个月甚至几年的时间来收集数据、清理数据、可视化数据、构建花哨的预测和因果模型,但都无济于事。你最喜欢的假设根本不成立——什么都不重要!
这标志着你身份危机的开始。你开始为你浪费的时间感到抱歉。你人生中第一次开始质疑自己的聪明。“也许我没有我 SAT/GRE/LSAT 第 99 分显示的那么聪明,”你害怕地说。但是你已经投入了这么多。真的可以这么轻易认输吗?你的手指无法抗拒轻微调整设计的冲动,看看 1000 版本是否是符合你理论的神奇设计。你认为你是一个诚实正直的公民。但是在你对意义的执着追求中,你已经把自己置身于 p-hacking 的土地上了。
它发生在我们最好的人身上
问题是:我们怎样才能形成更好的假设?上周偶遇刚好合适的书: Factfulness *。*它讲述了“我们对世界错误的 10 个理由,以及为什么事情比你想象的要好”。我个人犯了不少单子上的错误。我认为,形成更聪明假说的关键在于深入理解我们的系统性偏见。通过避开这些诱人但被误导的假设,我们可以为自己节省大量时间和痛苦。
免责声明
这个博客帖子是一个备忘单,为自己使用和与朋友分享而创建。如果你觉得有用,我强烈建议你在亚马逊上购买这本书。我简直无法公正地评价我多年来读过的最伟大的平装本。我相信你会对基于数据的精彩故事感到高兴。你甚至可能会发现许多本备忘单中没有的见解。
1.差距本能
定义
通过二元透镜看世界的人类冲动。
例子
最低 x%对最高 y%
巴西最富有的 10%的人赚取了总收入的 41%。令人不安,对吗?听起来太高了。我们很快会想象一个精英阶层从其他人那里窃取资源。媒体用最富有的人——通常不是最富有的 10%,但可能是最富有的 0.1%,即超级富豪——及其船只、马匹和巨大豪宅的图片来支持这种印象。
是的,这个数字高得令人不安。同时,已经很多年没有这么低了。统计数据经常被戏剧性地用于政治目的,但重要的是,它们还能帮助我们驾驭现实……事实上,即使在世界上最不平等的国家之一,也不存在差距。大部分人都在中间。
控制差距本能
- 当你听到一个缺口的时候,就要识别出来。
- 平均值可能具有欺骗性。尝试绘制分布图(随着时间的推移)。
- 大多数学者关注平均治疗效果,并使用异质性效果作为稳健性检查。在真实的商业环境中,你也许应该把异质效果放在前面和中间。
2.消极本能
定义
“认为世界正在变得更糟的巨大误解。”
例子
- 调查显示,人们认为极端贫困已经恶化,犯罪率上升。通过使用来自世界银行和联合国的几十个结果变量,作者表明这是不正确的。(我没有张贴这些情节,因为我可能侵犯了版权。但是我强烈建议你自己去看看。)比如 2017 年的赞比亚比 1891 年的瑞典好。
诱惑
- “大多数事情过去都是更糟,而不是更好。但是对于人类来说,忘记事情真正的“过去”是什么样子是极其容易的"
- 选择性报告
如何控制我们的消极本能
- 认可选择性报告——因为关于逐步改善的故事并不畅销。
- 更多新闻!=更痛苦。“更多的坏消息有时是由于对苦难的更好监测,而不是世界的恶化.”
- 认识到大多数人都把过去浪漫化了。
- 不要执着于水平,要好奇改变的方向。绘制一些时间序列数据,看看过去是否真的更好。
3.直线本能
定义
- 过度依赖线性模型
- 过度依赖线性外推
例子
“认为‘世界人口正在不断增加’的巨大误解"
诱惑
- 作者举了许多例子来说明世界上不同收入和职业的人是如何喜欢假设直线的。
- 个人认为,一个相关的原因是线性模型受到了很多学术上的关注。所以如果你使用线性模型,你可以调用许多花哨的证明和很酷的技术来为你的策略辩护;而非参数仍然相对研究不足。
解药
- **作者:**请注意,数据可以以多种形状分布:直线、S 形弯曲、A 形滑动、驼峰、指数等。他们还谈到不同的社会和经济力量如何产生不同的形状。它们很有趣。自己去看吧:)
- **我:**对产生这些数据的底层力量有了更深入的了解。结构模型 s 虽然复杂而笨拙,但有时却非常有用。
4.恐惧本能
定义
恐惧是有用的,但前提是它指向正确的事物。恐惧本能是理解世界的可怕向导。它让我们把注意力放在我们最害怕的不太可能发生的危险上,而忽略了实际上最危险的东西。
例子
作者绘制了许多关于自然灾害、飞机和汽车事故、战争和冲突等的时间序列。
诱惑
- 将媒体报道频率误认为真实频率。
- “风险=危险*暴露”。大多数人忘记了暴露的部分,并且不必要地担心他们很少暴露的事件。
解药
- f(媒体报道)!=(事件)
- “风险=危险*暴露”
5.尺寸本能
定义
我们倾向于夸大事情,尤其是当:
- 它与我们有关
- 一个统计数据被挑选出来
结果
规模本能的两个方面,加上消极本能,使我们系统地低估了世界上已经取得的进展。
例子
在关于全球比例的测试问题中,人们一致认为大约 20%的人的基本需求得到了满足。大多数情况下,正确答案接近 80%,甚至 90%。同时,我们系统地高估了其他比例。我们国家的移民比例。反对同性恋的人的比例。在每一种情况下,至少在美国和欧洲,我们的解释都比现实更加戏剧化。
解药
**将统计数据放在上下文中:**不要报告绝对数字,尝试报告百分比。
6.泛化本能
定义
需要进行一些概括。类别对于我们的功能来说是绝对必要的。它们给我们的思想提供了结构。想象一下,如果我们认为每一件物品和每一个场景都是独一无二的——我们甚至不会有一种语言来描述我们周围的世界。”但当我们过度概括时,这就成了一个问题。
负面后果
当你错误地将一组结果推广到另一组时,你就冒了风险
- 以为有商机,其实没有;
- 以为有商机就没有商机。
例子
每次怀孕都会导致大约两年的月经不调。如果你是月经垫的制造商,这对生意不好。所以你应该知道,而且应该为全世界每个妇女的婴儿数量下降而感到高兴。你应该知道,而且也应该为越来越多受过教育的女性离家工作感到高兴。因为在过去的几十年里,这些发展已经为你的产品创造了一个爆炸式的市场,在现在生活在 2 层和 3 层的数十亿经期妇女中。
解药
假设你不正常,其他人也不是白痴
- 寻找更好的方法将人们分类。
- **跨组:**寻找相似之处,但不要将结果从一组归纳到另一组,除非你有足够的证据支持它
- **组内:**寻找差异
- 注意轶事证据:他们通常是离群值
- **注意没有数据的英文报告。**例如,多数可以是 50.00001%
7.命运本能
定义
声称 X(人、国家、宗教、文化)注定有某种结局,因为这些都是不可改变的特性。
诱惑
- 事实上,国家、宗教和文化正在缓慢但稳定地转变。有时,人们会把缓慢的变化误认为没有变化。
- 许多畅销书都在延续这个神话,这也于事无补。
消极后果
刻板印象、歧视和错失的机会。
解药
- 变化慢!=无变化
- 已经抛弃了文化/宗教命运的讨论。
8.单一视角本能
定义
当我们在寻找一个能解释一切的解释时。
诱惑
人们,尤其是学者,喜欢简单、优雅的解决方案。
解药
拿个工具箱,而不是锤子
- 做你自己的魔鬼代言人。试着收集你最喜欢的叙述的反例。
- **认识到现实是复杂的。**由此推论,要提防简单的想法和简单的解决方案。
- 永远不要相信单一来源——即使那个来源是某个领域的专家。认识到专家只是他们研究领域的专家。调查显示,作者在其他问题上也犯了同样的错误。
- 小心空想家。甚至民主也不是唯一的解决方案。
9.责备的本能
定义
“为不好的事情发生寻找一个清晰、简单的原因的本能.”
例子
不缺例子:)所以我就略过了。
消极后果
- 夸大任何个人/团体的重要性。
- 有损于对问题的理解,也不利于提出建设性的解决方案。
解药
忍住责备所有人的冲动。因为问题是当我们识别出坏人时,我们已经不再思考了。如果你真的想改变这个世界,你必须了解它实际上是如何运作的,并且忘记打任何人的脸。
- “找原因,不找小人。”
- “找系统,不找英雄。”
10.急迫的本能
定义
“机不可失,时不再来!明天可能就来不及了!特价!仅限今天!”
诱惑
事实证明,这是一个有效的点击诱饵和增长黑客。它触及了我们最原始的恐惧本能。
消极后果
你在做次优的选择:在真正重要的任务上花费更少的时间和精力。
解药
- **“坚持数据”**具有相关且准确的紧急程度衡量标准。
- **“当心算命先生,**因为任何对未来的预测都是不确定的。”
- **“警惕激烈的行动,”**因为副作用可能很难消除。更好的方法是进行小的、渐进的改进,并评估每一步的补救措施。
结束了
您已到达此备忘单的结尾。但从某种意义上来说,这只是一个开始。
在我自己的研究中,我已经发现自己陷入了几个这样的陷阱。我多么希望这本书是在我刚开始攻读经济学博士时写的。实际上,它可以拯救我多年的生命。谢天谢地,认识到自己的错误并从中吸取教训永远不会太晚:)有了这些见解,我就能避开诱人但不真实的假设。
你在实践中遇到过哪些陷阱?请在下面留下你的评论,这样我们就可以互相关注了。
下次见!
相亲:让有视觉障碍的人更容易接触到移动约会平台
想象一下,在看不到个体的情况下,在 Tinder 或 Bumble 这个已经疯狂的世界中导航。对于任何不熟悉屏幕阅读器输出的人来说,这听起来可能是这样的:
有人知道查德长什么样吗,他喜欢什么,或者你想在他身上左右滑动吗?不,我不这么认为。
作为一个有视力的人,我从来没有真正想过一个有视力障碍的人在移动约会领域可能会遇到的问题。我的盲人朋友坐在我的办公桌前,把他的手机递给我,让我对个人资料中的个人进行口头描述,这让我意识到使用带有屏幕阅读器的约会平台是一种多么糟糕的用户体验。
我半开玩笑地对我的朋友说,为了让他别来烦我,好让我回去工作,我打算写一个程序,自动为他的个人资料照片加标题。我们笑了几秒钟,然后我们想起我们都是计算机科学的博士生,实际上可以相对容易地完成这一点。让他截屏一个个人资料,将图像发送到服务器,做一些计算机视觉魔术,还有 Viola,这不会太难!,我们可以发送回一个标题,它可以提供更多关于谁实际上在个人资料中的信息。
这个想法是在新学期开始时产生的,我参加了几门机器学习课程,所以我向我的一个小组提议,我们做这个项目作为一个学期的项目。他们喜欢这个想法。
首先,我们决定对大学生进行一项调查,看看人们在约会档案中寻找什么样的信息。对于每个类别,人们可以在 tinder 档案中选择最多三个对他们来说重要的选项。
星号:这项调查的收集方式非常不正式,而且它也涉及一般的大学生群体,而不是更具体的视觉障碍人群。不要把这些图表视为彻底探索的科学结果,而是在他们评估约会档案时对年轻人大脑的简要观察。
Survey results from primarily college students on what they look for when they evaluate a tinder profile. The data is split into 4 graphs that show people are the most interested in seeing an individual’s hair color, body shape, whether they are indoor or outdoor, and if they are smiling or not.
不出所料,调查结果中出现了一些模式。当评估简档时,用户发现简档中关于个人的几个特征是重要的。他们通常想知道头发的颜色和长度,个人是否在微笑,照片是在室内还是室外拍的,以及个人的体型。
由于这是一门关于统计机器学习的课程,教学大纲只是勉强进入深度神经网络,所以我们采取了一种相对幼稚的方法来制作字幕。基本上,我们将任务分成几个二元分类器(长发/短发、浅色/深色头发、室内/室外、微笑/不微笑等),每个小组成员负责一个分类器。下面的视频展示了我们开发的系统:
截屏拍摄后,我们会等待手机接收到一个新的截屏添加到截屏文件夹中的事实,这是一个明显的延迟。正如所展示的,这个系统仍然是一个原型。仍然有大量的错误需要克服和改进,但是我认为我们的系统在演示概念验证方面做得很好。
很明显,下一步是摆脱简单的分类器,而是使用在 image net 上训练的深度神经网络来为图像添加标题。一旦该版本实现,我将更新这篇文章,并给出一些更彻底和明确的结果,甚至可能是一些来自视觉障碍用户的反馈。
因此,不可避免地,你们中的一些人会问一个相对不敏感但并非完全不相关的问题:“这个人的长相到底有什么关系?反正他看不见他们。”这很重要,我保证。从一个人的个人资料中可以收集到比外表更多的信息。你可以从环境中获得信息,乍得,例如,是一个喜欢船和越野车和四轮车的户外运动者,也许这是你的事情,也许不是,但如果不能看到照片,信息是无法访问的。你也可以通过个人资料中的照片暗示个人生活方式的某些方面。如果个人资料包括五张赤膊健身房自拍,而你又不是特别喜欢去健身房,也许这些信息会帮助你决定这个人是否值得一试。
所以我想这个故事的寓意是,可悲的是,可访问性不是设计师在构建技术时通常会考虑的事情。这给许多人带来了挑战,也给技术世界制造了障碍。计算机视觉已经被证明是一种不可思议的工具,可以用来为有视觉障碍的人拆除一些障碍,然而它不应该走到那一步。在我看来,可访问性的最大问题之一就是简单的认知。在我的计算机科学课上,可访问性从未被提及。教授只需花 15 分钟介绍通用设计的概念(即我们应该设计出每个人都可以使用的东西)。
制作音乐:当简单概率胜过深度学习
When a simple contestant competes against a deep army.
概述:我是如何发现一个利用深度学习制作音乐的问题,并通过创建自己的原创模型来解决的。
概述
问题 :我是如何发现使用深度学习技术生成流行音乐的问题的。
解决方案: 我如何构建了一个原创的音乐制作机器,它可以媲美深度学习,但解决方案更简单。
评价: 我是如何创造出一个评价指标,能够从数学上证明我的音乐比深度学习的音乐“听起来更像流行”。
一般化 : 我是如何发现一种方法来一般化我自己的模型,应用于创作音乐以外的情况。
也请查看该项目的 YouTube 版本:
编辑:我已经关闭了网站(EC2),因为我必须继续支付费用。
笑点是
我做了一个简单的概率模型来生成流行音乐。有了客观的衡量标准,我可以说这个模型产生的音乐听起来更像流行音乐,而不是一些由深度学习技术产生的音乐。我是怎么做到的?我这样做,部分是因为我把注意力集中在我认为流行音乐的核心:和声和旋律之间的统计关系。
Melody is the vocals, the tunes. Harmony is the chords, the chord progression. In the piano, the melody is played by the right hand, and the harmony by the left.
问题是
在深入探讨他们的关系之前,我先来定义一下问题。我开始这个项目的简单愿望是利用深度学习(外行人称之为“人工智能”)创作流行音乐。这很快让我想到了 LSTMs(长短期记忆单元),这是一种特殊版本的递归神经网络(RNN),在生成文本和制作音乐方面非常受欢迎。
[## 如何在 Keras 中使用 LSTM 神经网络生成音乐
使用 LSTM 神经网络创作音乐的介绍
towardsdatascience.com](/how-to-generate-music-using-a-lstm-neural-network-in-keras-68786834d4c5)
但是随着我对这个主题了解的越来越多,我开始质疑应用 rnn 和它们的变体来产生流行音乐的逻辑。这个逻辑似乎是基于对(流行)音乐内部结构的几个假设,我并不完全同意。
一个具体的假设是和声和旋律之间的独立关系(以上是对两者的描述)。
以多伦多大学 2017 年的出版物为例:来自 Pi 的歌曲:流行音乐一代的音乐似是而非的网络(初航等)。在这篇文章中,作者明确地“假定……和弦是独立的给定的旋律”(3,斜体是我的)。基于这一规范,作者建立了一个复杂的多层 RNN 模型。旋律有自己的生成音符层(键和按键层),它独立于和弦层。除了独立性之外,这种特殊的模式还决定了一代人在旋律上的和谐。这只是意味着和声依赖于音符生成的旋律。
Hang Chu, et al.’s stacked RNN model. Each layer is responsible for addressing different aspect of a song.
这种建模对我来说感觉很奇怪,因为它似乎不太接近人类创作流行音乐的方式。就我个人而言,作为一名受过古典音乐训练的钢琴家,在没有首先考虑和声音符的情况下,我绝不会考虑写下旋律音符。这是因为和声音符定义和限制了我的旋律音符。很久以前,Axis of Awesome 在他们曾经风靡一时的 YouTube 视频中展示了这个想法。
Video demonstrating how different pop melodies are all dependent on the same four chords.
他们的视频展示了西方流行音乐的一个定义属性:和声,或那四个和弦,强烈地决定了旋律将会是什么。在数据科学语言中,我们可以说条件概率调节和解决了和声和旋律之间的统计关系。这是因为旋律音符自然地依赖于和声音符。因此,有人可能会认为和声音符在本质上限制并允许在特定的歌曲中选择旋律音符。
解决方案
我喜欢构建自己的解决方案来解决复杂的问题。因此,我决定构建自己的模型,以自己的方式捕捉音乐数据丰富的底层结构。我开始这样做的时候,关注的是支配不同种类音符之间关系的预定概率命运。一个例子就是我上面提到的——和声和旋律之间的“垂直”关系。
(处理)数据
对于数据,我使用了 20 首不同的 midi 格式的西方流行歌曲(完整的歌曲列表可以在这里找到:www.popmusicmaker.com)。
使用 music21 python 库,我基于马尔可夫过程对这些 midi 文件进行了大量(但不完全)处理。这使我能够提取输入数据中不同类型音符之间的统计关系。具体来说,我计算了音符的转移概率。这基本上意味着,当音符从一个音符过渡到下一个音符时,我们可以得到该过渡发生的概率。(下面有更深入的解释)
midi: a digitized version of a song.
首先,我提取了和声音符和旋律音符之间的“垂直”转换概率。我还根据数据集计算了旋律音符之间所有的“水平”转换概率。我也为和声音符完成了这个任务。下图展示了音乐数据中不同类型音符之间的三种不同过渡矩阵的示例。
Transition Probabilities, examples. Top: between Harmony and Melody notes — Middle: between Melody notes — Bottom: between Harmony notes
模型
使用这三个概率矩阵,我的模型将遵循这些简单的方向。
1.从数据中随机选择一个和声音符。
2.使用上面看到的第一个概率矩阵,根据那个和声音符选择一个旋律音符。
3.使用上面看到的第二个概率矩阵,根据旋律音符选择一个旋律音符。
4.重复步骤 3,直到某一截止线。
Steps 1–4.
5.使用第三概率矩阵基于先前的和声音符选择新的和声音符。
6.重复步骤 1-4,直到某一截止线。
Steps 5–6.
这是这 6 个简单步骤的一个具体例子。
- 机器随机选择和声音符 F。
- 和声音符 F 有 4 个旋律音符可供选择。使用第一转移矩阵,它可能选择旋律音符 C,因为旋律音符 C 具有相对高的可能性(24.5%的机会被选择)。
- 旋律音符 C 将转向第二过渡矩阵以选择下一个旋律音符。它可能会选择旋律音符 A,因为它的概率很高(88%)。
- 步骤 3 将继续生成新的旋律音符,直到预设的截止线。
- 和声音符 F 将转到第三个过渡矩阵来选择下一个和声音符。它可以基于它们相对高的可能性选择和声音符 F 或和声音符 C。
- 将重复步骤 1-4,直到某个预设的截止线。
以下是通过这种架构产生的流行音乐的例子(来自www.popmusicmaker.com):
估价
现在到了困难的部分——如何评估不同的模型。毕竟,我的文章声称简单概率可以胜过神经网络。但是我们如何从一个神经网络模型评估我的模型呢?怎么才能客观的宣称我的音乐“更像流行”而不是人工智能制作的音乐?
要回答这个问题,我们首先要问的是,最初到底是什么定义了流行音乐。我已经给出了第一个定义:和声和旋律之间的统计关系。但是流行音乐还有另一个定义元素。这就是为什么流行音乐有一个清晰的开头、中间和结尾(引子、独唱、过渡、合唱、结尾等等)。)在一首歌曲中重复多次。
例如,“让它去吧,让它去吧,不能再让它回来了…”是在音乐的中间部分,而不是开始和结束。这一段在歌曲中重复了三次。
考虑到这一点,我们可以使用所谓的自相似矩阵。简单地说,自相似矩阵从数学上直观地显示了歌曲的开头、中间和结尾。下面是歌曲的一个自相似矩阵,从电影里慢慢落下一次。
Each tiny block represents every note played in four beats of time in the song. Each big block in 45 degree angle represents a segment of a song.
第一个蓝色集群代表歌曲的开始部分,而下一个黄色集群代表该歌曲的另一个片段。第一个和第三个聚类由于它们的(自)相似性而具有相同的阴影。第二个和第四个聚类由于其自身(相似性)而被相同地着色。
我做了 20 个这样的自相似矩阵,是我用来作为输入数据的 20 首流行歌曲。然后我让我的机器尽可能忠实地复制它们的结构(平均)(更多细节,请在评论中提问!).
结果
结果很说明问题。在自相似矩阵之前,我的机器产生的声音没有内部重复结构。但是在复制了输入数据的结构之后,你可以在我生成的音乐中看到这些边界,如下所示。
Before and after utilizing the self-similarity matrix.
与此相比,多伦多大学神经网络产生的流行音乐的自相似矩阵看起来是这样的:
这就是你如何比较和评估不同的模型——基于它们的自相似矩阵的边界!
一般化
我想解决的最后一个问题是泛化。通过概括,我问:我们如何才能概括我的数据驱动音乐模型,以便它可以应用于制作流行音乐以外的情况?换句话说,有没有另一个人造发明与我的流行音乐制作机有着相同的架构?
经过深思熟虑,我发现还有一种人类文化创造的数据内部也有这种结构——那就是流行歌词!
举个例子我将是爱德华·麦肯。它的一个片段是这样的:
我将是你哭泣的肩膀
我将是爱情的自杀
当我长大后我会变得更好
我将是你生命中最大的粉丝
让我们分解歌词,使用机器学习中相同的生成上下文。我们可以将“I’ll be”作为语言模型中的第一个输入单词。这个二元模型会用来生成‘你的’,生成‘哭’,导致‘肩膀’。
接下来是一个非常重要的问题:下一句话的第一个词(另一个‘我会是’)是否依赖于最后一个词‘肩膀’?换句话说,第一句的最后一个字和下一句的第一个字有关系吗?
对我来说,答案是否定的。由于这个句子以‘should’结尾,下一个单词是基于前一个单词‘I’ll be’生成的。这是因为每个句子的第一个词被故意重复,表明每个句子的第一个词之间存在类似的条件关系。这些第一个单词成为下一个单词序列的触发点。
我发现这是一个令人着迷的发现。流行音乐和流行歌词似乎都将这种架构作为其数据的内部结构!是不是超级迷人?
你可以访问我的网站www.popmusicmaker.com来创作流行音乐和流行歌词。
这个项目的 github 在这里:【https://github.com/haebichan/PopMusicMaker
如果您有任何问题,请随时联系我@【hj2444.columbia.edu
我对开源软件的第一个贡献
开源软件汇集了许多无私的程序员,他们自由地向世界发布他们的代码。作为一名利用开源软件谋生的程序员,我一直想为开源社区做点贡献。在过去的这个周末,我在全球熊猫文献冲刺中实现了这个目标。
我知道我不必等待这个全球性的事件来做出开源的贡献。事实上,我经常爬上我经常使用的开源软件的发布板。然而,这是我第一次为开源项目做贡献,得到社区的支持和详细的指导真的很有帮助。也给了我一个很具体的任务,也有帮助。
pydata TO group 在多伦多的 hacklab space 举办了一次活动。组织者给我分配了熊猫。DataFrame.all 文档,但在开始之前,我必须设置我的环境。熊猫的网页上有很好的说明,可以在这里找到。
[## 为熊猫做贡献-熊猫 0.22.0 文档
如果你不是开发人员,对文档做出贡献仍然有巨大的价值。你甚至不必…
pandas.pydata.org](http://pandas.pydata.org/pandas-docs/stable/contributing.html#creating-a-python-environment-pip)
我更喜欢用 venv 管理我的虚拟环境,尽管有很多警告,但一切都运行得很好。我现在可以开始写文档了,开始如下:
我运行了下面一行代码来产生文档字符串输出。
python ../scripts/validate_docstrings.py pandas.DataFrame.all
在第一组散列标签下面是文档字符串当前的样子,在第二组下面是当前的错误列表。第一个错误是:
Docstring text (summary) should start in the line immediately after the opening quotes (not in the same line, or leaving a blank line in between)Use only one blank line to separate sections or paragraphs
我得到了一个与这个文档字符串相关的行,当我阅读代码时,遇到了困惑。
我期待的是更接近实际医生的样子。经过一些调查后,我意识到我正在失去装饰者的魔力。appender decorator 追加在 _bool_doc 变量中找到的内容。_bool_doc 变量本身引用了从替换装饰器中给出的参数中插入的变量。
当我跟踪 _bool_doc 变量时,我发现了第一个错误的来源。
%(desc)的变量占位符在左引号后有一个空行。这是不允许的。所以我去掉了这条空行,瞧!我已经排除了第一个错误。
我一直在努力纠正这些错误,然后面临一个挑战。我正在完成 DataFrame.all 的文档,但它实际上与 DataFrame.any 方法共享文档。因此,当我需要放入“另请参阅”和“示例”部分时,我必须向这些文档的实例化函数添加参数。这将允许这两个相关的方法共享它们文档的模板,但是在需要的地方有所不同。
我将示例和 see_also 参数添加到 _make_logical_function 中,并将它们作为变量传入。
这是一个传递给生成文档的参数的变量的例子。
请注意我是如何将 _all_doc、_all_examples 和 _all_see_also 变量添加到 cls.all 对象中的。
这些更改导致新的文档页面如下所示
python make.py -单身熊猫。DataFrame.all
肯定是一个进步。
下一步是准备合并这个分支。包括确保它编译并通过了 pep8 标准。
git diff upstream/master -u -- "*.py" | flake8 --diff
我提交了一个拉取请求,几分钟内就有了评论。评论的范围从风格上的改变到请求添加有关适用于系列数据结构的 all 方法的信息。三个独立的核心熊猫开发者评论了这个分支。虽然我经常在工作中经历这一过程,但和世界各地我从未见过的人一起做这件事真的很酷。
最终在 3 月 11 日上午 10:42,我的分支被合并,我正式成为 0.23.0 版本中熊猫项目的贡献者。
我希望对开源软件做出更多的贡献,也希望对实现细节和更多的文档做出贡献。
https://pixabay.com/en/background-art-wallpaper-panorama-3104413/
让你的神经网络说“我不知道”——使用 Pyro 和 PyTorch 的贝叶斯神经网络
构建图像分类器已经成为新的“hello world”。还记得你第一次遇到 Python 的那一天,你的*打印“hello world”*感觉很神奇吗?几个月前,当我跟随py torch 官方教程并为自己构建了一个简单的分类器时,我也有同样的感觉。
我被我的简单分类器的准确性震惊了。如果我没记错的话,在 MNIST 手写数字数据集上,它在测试集上超过 98%。(作为旁注,这显示了当一个高度准确的图像分类器可以在几个小时内建立起来时,我们已经走了多远。ML 社区——是的,包括你——因为这种自由的知识和工具共享而令人敬畏
尽管分类器的准确度很高**,但有一个问题一直困扰着我:**
神经网络会吐出一个类别,即使我给它完全不相关的图像。
你知道该怎么做。训练一个猫和狗的分类器,扔出一个人的图像,网络会将它分类为猫或狗。(也许——如果网络有些幽默感的话——开心的人当狗,不开心的人当猫)。
Build your model to throw up its (metaphorical) hands when it’s not sure (Photo via Pixabay)
我知道我对分类器的期望是不现实的。它完全按照程序运行。如果我将最终层(softmax)输出解释为概率,那么对于作为输入给出的任何图像,总会有一个具有最大值的类别。该网络根本不知道这样一个概念,即抛出双手说:“这看起来像是我没有接受过的训练。”
但这正是我想要我的神经网络做的。
在几乎所有现实世界的问题中,你想要的不仅仅是一个结果,你还需要对这个结果有信心/确定性的知识。如果你正在制造无人驾驶汽车,你不仅要检测行人,还要表达你对物体是行人而不是交通锥的信心。同样,如果您正在编写一个在股票市场上交易的机器人,您希望它能够识别情况何时超出其舒适区,这样它就可以停止行动,而不会破产。当一个人不确定的时候,很大一部分智慧是不行动的。因此,令人惊讶的是,对于许多 ML 项目来说,表达不确定性并不是它的目标。
Probably one noisy boi (via Tricking Neural Networks: Create your own Adversarial Examples)
我想通过构建一个 MNIST 分类器来探索这一方向,该分类器可以表达输入图像是特定数字的(不)确定性。当你向它展示数字时,这种分类器会有很高的准确性,但当你向它扔不相关的图像时,它会拒绝分类。我的最终分类器对 MNIST 的准确率约为 97%,它拒绝对白噪声和大多数无关(非 MNIST)图像进行分类。你可以在这里访问代码,并且可能想跟随 repo 中包含的 Jupyter 笔记本以及本教程。
贝叶斯神经网络如何工作
我不会在这里介绍贝叶斯分析的全部内容,但是我会提供足够的上下文让你理解,然后修改代码。
关键思想非常简单:在贝叶斯世界观中,每件事都有一个概率分布,包括模型参数(NNs 中的权重和偏差)。在编程语言中,我们有可以取特定值的变量,每次你访问这个变量,你都会得到相同的值。与此相反,在贝叶斯世界中,我们有类似的被称为随机变量的实体,它们在你每次访问它时都会给出不同的值。所以如果 X 是一个代表正态分布的随机变量,每次你访问 X,它都会有不同的值。
这个从随机变量中获取新值的过程被称为采样。得出什么值取决于随机变量的相关概率分布。与随机变量相关的概率分布越宽,其值的不确定性就越大,因为它可以按照(宽)概率分布取任何值。
If your random variable is the sum of digits of two dice throws, at each throw you’ll get a value whose probability depends on the distribution above. This means the most likely sum that you can get is 7, and least likely is 2 and 12. (From Wikipedia)
在传统的神经网络中,你有固定的权重和偏差,它们决定了如何将输入转化为输出。在贝叶斯神经网络中,所有的权重和偏差都有一个概率分布。为了对图像进行分类,你要对网络进行多次运行(正向传递),每次都使用一组新的采样权重和偏差。您得到的不是一组输出值,而是多组输出值,每次运行一组。这组输出值代表输出值的概率分布,因此您可以找出每个输出的的置信度和不确定度。正如您将看到的,如果输入图像是网络从未见过的,对于所有输出类,不确定性将会很高,您应该将网络解释为:“我真的不知道这个图像是关于什么的”。
用 Pyro 和 PyTorch 编写您的第一个贝叶斯神经网络
该代码假设熟悉概率编程和 PyTorch 的基本思想。如果你对这些都不熟悉,我推荐以下资源:
- 黑客的贝叶斯方法学习贝叶斯建模和概率编程的基础知识
- 【PyTorch 深度学习:60 分钟闪电战。特别是关于训练分类器的教程。
PyTorch 有一个名为 Pyro 的配套库,它提供了在 PyTorch 编写的神经网络上进行概率编程的功能。这种将神经网络“自动”转换成贝叶斯对等体的过程有两个步骤:
- 首先,它有助于将概率分布分配给网络中的所有权重和偏差,从而将它们转换为随机变量
- 其次,它有助于使用训练数据来推断概率分布,这样你就可以用它来对图像进行分类
推理是整个过程中最困难的一步。它基于著名的贝叶斯定理,你可能以前见过。
The deceptively simple equation that rules the world
深入这个等式的本质已经超出了本教程的范围,但是我会试着给你发生了什么的直觉。假设 A 是权重和偏差的初始概率分布(称为**先验,**通常是一些标准分布,如正态或均匀随机),而 B 是训练数据(图像/标签的输入/输出对)。
你应该记住的贝叶斯定理的关键思想是,我们希望使用数据找出权重和偏差的更新分布 P(A | B) ( 后验)。就像使用初始随机分配的权重和网络偏差一样,参数的初始分布(先验)会给我们错误的结果。只有在使用数据获得参数的更新分布后,我们才能使用网络对图像进行分类。
权重和偏差的概率分布通过贝叶斯定理更新,考虑到它们的初始值 P(A) 和那些初始分布的似然来描述输入数据 P (B|A) (它被理解为给定 A 的 B 的概率)。权重的更新分布 P(A | B) ( 后验)取决于哪一个具有更强的吸引力——先验或可能性。(如果你对 P(B)项感到好奇,在本教程的后面部分你会明白的)。
我知道上面那段话可能会让严格的贝叶斯人吓哭。我知道这些定义并不精确。但是本教程并不是要介绍贝叶斯方法看待数据的全部荣耀。有完整的书籍和课程在上面,我无法在一个教程中对其进行公正的评价。本教程是关于贝叶斯神经网络的实际实现。我绞尽脑汁钻研 Pyro 教程好几天,试图将他们的一个例子转换成分类器。我终于在 IBM Watson 的网站上找到了一个关于在 MNIST 上使用 Pyro 的简短教程。我的代码基于该教程,但我将其扩展到非 MNIST 和白噪声数据,以观察贝叶斯神经网络在面对它们从未见过的输入时是否真的能说“我不知道”。
尽管我将尝试解释 Pyro 的基础知识,但如果你通读他们的前三个教程,你会从本教程中获得很多价值——第一部分,第二部分和第三部分。
准备好了吗?让我们直接进入代码
在导入 PyTorch、Pyro 和其他标准库(如 matplotlib 和 numpy)后,我们定义了一个 1024 个隐层的标准前馈神经网络。我们也加载 MNIST 数据。
在 Pyro 中, model() 函数定义了如何生成输出数据。在我们的分类器中,当我们用展平的 2828 像素图像运行神经网络(在上面的网络变量中初始化)时,生成对应于每个数字的 10 个输出值。在模型()*中,函数 pyro.random_module() 将我们的神经网络的参数(权重和偏差)转换为随机变量,这些随机变量具有由 fc1w_prior 、 fc1b_prior 、 outw_prior 和 outb_prior 给出的初始(先验)概率分布(在我们的例子中,正如您所看到的,我们用一个正态分布来初始化这些)最后,通过 pyro.sample(),我们告诉 pyro 这个网络的输出本质上是分类的(即它可以是 0、1、2 等等。)
理解这个部分——由 guide() 函数表示——对我来说是最棘手的事情。很长一段时间,我不明白为什么需要它,特别是因为它看起来非常像*模型()*函数。解释起来会很难,但我会尽力。(如果你不能理解我的解释,我推荐 Pyro 教程或者下面我提供的关于这个主题的链接)。
再看一下贝叶斯方程:
在 model() 函数中,我们定义了 P(A) —权重和偏差的先验。方程的 P(B|A) 部分由神经网络表示,因为给定参数(权重和偏差),我们可以对图像、标签对进行多次运行,并找出训练数据的相应概率分布。在训练之前,最初由于权重和先验都是相同的(都是正态分布),对于给定的图像,获得正确标签的高概率的可能性将是低的。
事实上,推理是学习权重和偏差的概率分布的过程,其最大化了获得正确图像、标签对的高概率的可能性。
这个推理过程用 P(A |B) 表示,它是给定输入/输出对( B )时参数 A 的后验概率。我之前写过推论很难。那是因为你在分母中看到的术语 P(B) 。这个术语被称为证据,它只是在所有可能的参数值下观察到数据(输入/输出对)的概率,用它们各自的概率加权。
计算这个总数很难,原因有三:
- 假设,参数 Aj 的值可以从-无穷大到+无穷大
- 对于在该范围内的 Aj 的每个值*,您必须运行模型,以找到生成您观察到的输入、输出对的可能性(总数据集可能有数百万对)*
- 这种参数可以不是一个而是多个(j >> 1)。事实上,对于我们这种规模的神经网络,我们有大约 800 万个参数(权重数= 10242828*10)。
我上面描述的后验概率的枚举方法类型除了非常琐碎的模型之外,对任何东西都不实用。如果我们可以进行随机抽样,而不是这种网格状的枚举,会怎么样呢?事实上,基于抽样的方法被广泛使用,它们被命名为蒙特卡罗方法。特别地, Metropolis-Hastings 是蒙特卡罗抽样的流行算法。(它包含在 Pyro 和大多数其他概率编程语言中)。
不幸的是,对于复杂的贝叶斯模型,如具有 800 万个参数的神经网络,蒙特卡罗方法仍然收敛缓慢,可能需要数周才能发现完整的后验概率。
令人欣慰的是,有一种越来越受欢迎的方法叫做变分贝叶斯,这种方法似乎非常适合寻找神经网络参数的后验概率,甚至对于大型数据集也是如此。为了理解这种技术背后的直觉,我强烈推荐观看下面的视频(直到前 40 分钟)。
变分贝叶斯方法的要点是,由于我们不能精确地计算后验概率,我们可以找到与它最接近的“表现良好”的概率分布。我所说的“表现良好”是指一种分布(如正态分布或指数分布),它可以用一小组参数(如均值或方差)来表示。因此,在随机初始化“表现良好”的分布中的参数后,您可以进行梯度下降并每次稍微修改分布的参数(如均值或方差),以查看最终的分布是否更接近您想要计算的后验概率。(如果你在想我们如何知道结果分布是否更接近后验分布,如果后验分布正是我们想要计算的,那么你已经理解了这个想法。答案是,令人惊讶的是,我们不需要确切的后验概率来找出它和其他“良好”分布之间的接近程度。观看上面的视频,了解我们实际优化的贴近度:证据下限或 ELBO。我也发现这个系列 的 帖子对题目有用)。
要直观地理解变分贝叶斯,请参见下图:
Via A Beginner’s Guide to Variational Methods: Mean-Field Approximation
蓝色曲线是真正的后验概率,如果你进行我们之前讨论过的长时间(枚举)计算,你会得到它。这条曲线可以采取任意形状,因为它是枚举计算的结果。与此相反,因为它是一个像正态分布一样的良好分布,所以绿色曲线的整个形状可以用一个参数 Z 来描述。变分贝叶斯方法所做的是使用梯度下降方法将 Z 参数的值从初始随机初始化值更改为其结果分布最接近真实后验值的值。在优化结束时,绿色曲线不完全像蓝色曲线,但非常相似。我们可以安全地使用近似的绿色曲线代替未知的真正的蓝色曲线来进行预测。(如果这一切难以理解,我推荐看上面的视频。)
这就是向导功能的用武之地。它帮助我们初始化一个行为良好的分布,稍后我们可以优化它来逼近真实的后验概率。再看一看:
此 guide() 函数描述了 Z 参数(如权重和偏差的均值和方差),可以对这些参数进行更改,以查看结果分布是否非常接近来自*模型()的后验分布。*现在,在我们的例子中,*模型()看起来与向导()*非常相似,但不一定总是如此。理论上, model() 函数可能比 guide() 函数复杂得多。
有了 model() 和 guide() 函数,我们就可以进行推理了。首先,让我们告诉 Pyro 使用哪个优化器来做变分推断。
您会注意到我们正在使用 PyTorch 的 Adam 优化器(要了解它和其他优化算法的更多信息,这里有一个精彩的系列)。我们用于优化的损失函数是 ELBO(这就像在通过反向传播训练非贝叶斯神经网络时使用均方误差或交叉熵损失)。
让我们写优化循环。
你会注意到这个循环差不多就是我们训练一个标准神经网络的方式。有多个时期/迭代(在本例中是 5)。在每一次迭代中,我们都要经历一个小批量的数据(图像、标签的输入/输出对)。变分推理的另一个好处是,我们不必一次输入整个数据集(可能有数百万)。由于优化器需要成千上万个步骤来寻找引导函数参数的最佳值,因此在每个步骤中,我们可以向其提供单独的小批量数据。这极大地加快了推理速度。
一旦损失似乎稳定/收敛到一个值,我们就可以停止优化,看看我们的贝叶斯神经网络有多精确。下面是这样做的代码。
在 predict() 函数中要注意的第一件事是,我们使用学习过的 guide() 函数(而不是 model() 函数)来做预测。这是因为对于模型(),我们只知道权重的先验,而不知道后验。但是对于优化迭代后的 guide() 来说,参数值给出的分布近似于真实的后验概率,因此我们可以用它来进行预测。
第二件要注意的事情是,对于每个预测,我们对一组新的权重和参数采样 10 次(由 num_samples 给出)。这实际上意味着,我们正在对一个新的神经网络进行 10 次采样,以进行一次预测。正如你将在后面看到的,这使我们能够给出输出的不确定性。在上面的例子中,为了进行预测,我们对给定输入的 10 个采样网络的最终层输出值进行平均,并将最大激活值作为预测数字。这样,我们看到我们的网络在测试集上 89%的时候是准确的。但是请注意,在这种情况下,我们强迫我们的网络在每种情况下做出预测。我们还没有使用贝叶斯定理的魔力来让我们的网络说:“我拒绝在这里做预测”。
这正是我们接下来要用下面的代码做的。
我就不赘述估计不确定性的完整代码了(你可以在笔记本里看到)。本质上,我们正在做的是:
- 对于输入图像,取 100 个神经网络样本,从最后一层得到 100 个不同的输出值
- 通过指数运算将这些输出(对数软式最大值)转换成概率
- 现在,给定输入图像,对于的每个数字,我们有 100 个概率值
- 我们将这 100 个概率值的中间值(第 50 个百分位数)作为每个数字的阈值概率
- 如果阈值概率大于 0.2,我们选择该数字作为网络的分类输出
换句话说,我们希望神经网络输出一个数字作为推荐,如果在多个概率样本中,该数字的中值概率至少为 0.2。这意味着对于一些输入,网络可以输出两位数作为分类输出,而对于其他输入,它可以不输出数字(如果我们给它非数字图像,这正是我们想要的)。
MNIST 数据集上的结果
当我在包含 10,000 张图像的整个 MNIST 测试集上运行网络时,我得到了以下结果:
- 网络拒绝分类的图像百分比:12.5%(10000 张中的 1250 张)
- 其余 8750 张“已接受”图像的准确率:96%
请注意,当我们给网络一个拒绝分类的机会时,这种 96%的准确性远远高于强制分类时的 88%的准确性。
想象引擎盖下发生了什么。我从 MNIST 测试批次中随机绘制了 100 幅图像。对于这 100 张图片中的大部分,网络分类准确。
上面的图显示的是输入图像的真实标签是 3,对于 10 个数字中的每一个,显示了对数概率的直方图。对于标签 3,中值对数概率实际上接近 0,这意味着该图像为 3 的概率接近 1 (exp(0) = 1)。这就是为什么它用黄色突出显示。由于网络选择的标签与真实标签相同,所以显示“正确”。您还可以看到输入图像的实际样子。
在我对 100 张图像的多次运行中,网络进行预测的准确率为 94–96%。网络通常选择不预测 10-15%的图像,看着网络说“我不太确定”的一些图像很有趣。
连我都很难看出这个数字是“2”。从直方图中可以看出,网络对于 2 个和 3 个标签都具有很高的不确定性。对于这种网络未确定的情况,所有标签的对数概率分布都很宽,而在上图中“3”的准确分类情况下,您会注意到数字 3 的分布很窄,而所有其他数字的分布都很宽(这意味着网络非常确定它是 3)。
又一个网络未定的案例。
你看图像都被搞乱了。传统的神经网络可能会吐出一些东西,但我们的贝叶斯网络拒绝说出任何东西。
随机生成图像的结果
为了观察网络在输入纯白噪声时的表现,我随机生成了 100 张图像。
当这些图像被作为输入时,网络拒绝对其中的 95%做出预测。
这是一个典型的随机生成的图像的样子:
非 MNIST 数据集上的结果
我更进一步,下载了非 MNIST 数据集,这是一个字母而不是数字的数据集。看起来是这样的:
对于非 MNIST 测试集,网络拒绝分类约 80%的图像(测试集中总共 459 个中的 363 个)。
下面是一个非 MNIST 图像的例子。
很高兴看到我们的网络在训练内容(MNSIT)上给出了很好的准确性,同时没有被定制设计来愚弄它的数据集所愚弄(不是 MNIST)。
结论和如何使我们的贝叶斯网络更好
在 MNIST 数据集上的最新结果具有 99.8%的准确率。所以我们 96%的准确率(当我们想要做一个预测的时候)与此相差甚远。
有四种方法可以获得更高的精度:
- 我们使用了一个非常简单的模型:具有 1024 个神经元的单层神经网络。如果我们使用更先进的卷积网络,我相信我们可以提高我们的准确性。
- 如果我们继续运行我们的优化更长的时间,我们可以提高我们的准确性
- 如果我们对每幅图像采样更多的数据点(而不是 100 个),结果可能会有所改善
- 如果我们使我们的接受标准从中值概率最小为 0.2 到可能第 10 百分位概率最小为 0.5,我们的网络将拒绝更多的图像,但是在接受的图像上,它可能具有更高的准确性
总的来说,我对结果很满意。我希望你玩代码:)玩得开心
请随意评论这篇文章,我会尽力回答你的问题。如果你能够改进代码,请在 github 上向我发送一个 pull 请求。如果你在新的数据集或问题上使用 basic 代码,请发邮件给我,地址是 paras1987 gmail com,我很乐意收到你的来信。
感谢 Nirant Kasliwal、Divyanshu Kalra 和 S. Adithya 审阅草稿并提出有益的建议。
PS:我最近制作了一个 20 分钟的视频,讲述是什么让深度学习如此有效。现在就去看!
喜欢这个教程吗?也可以看看我的其他教程:
- 一个神经网络,多种用途。使用单一模型构建图像搜索、图像字幕、相似文字和相似图像
- 让深度神经网络作画,了解它们是如何工作的。用 100 行 PyTorch 代码生成抽象艺术,并探索神经网络如何工作
- 通过机器学习为机器学习项目产生新的想法。使用预先训练的语言模型从 2.5k 句子的小型语料库中生成风格特定的文本。PyTorch 代码
- 无梯度强化学习:使用遗传算法进化智能体。在 PyTorch 中实现深度神经进化为 CartPole 进化一个 agent 代码+教程]
我发关于深度学习和 AI 的推特。在https://twitter.com/paraschopra跟着我
[## Paras Chopra (@paraschopra) |推特
Paras Chopra 的最新推文(@paraschopra)。如果你想知道宇宙为什么存在,请跟我来…
twitter.com](https://twitter.com/paraschopra)
制作自己的 Spotify Discover 每周播放列表
每周一醒来我都很兴奋。在你认为我是那些喜欢每天去上课的怪人之一之前,让我向你保证,我不是。然而,每周一,Spotify 都会发布一个名为 Discover Weekly 的播放列表。里面装满了我以前没听过的新歌。接下来几周,我几乎总能在上面找到我的新果酱。但是,他们是怎么做到的呢?
索菲亚·乔卡的这篇文章应该会让你对此有更好的理解,
[## Spotify 的 Discover Weekly:机器学习如何找到你的新音乐
个性化音乐推荐背后的科学
hackernoon.com](https://hackernoon.com/spotifys-discover-weekly-how-machine-learning-finds-your-new-music-19a41ab76efe)
但是我想试着弄清楚我是否可以建立我自己的系统来做类似的事情!跟我一起去兜风吧!
如果你想继续,这是我的 Python 笔记本!
在 GitHub 上创建一个帐户,为 SpotifyML 的发展做出贡献。
github.com](https://github.com/nab0310/SpotifyML/blob/master/spotify/Final%20Pretty%20Spotify%20Data%20Classifier.ipynb)
创建您的第一个 Spotify 应用程序并设置您的环境
使用 Spotify API 的第一步是在 Spotify 开发者环境中创建一个应用程序。为此,首先进入 Spotify 开发者页面,登录并导航至“我的应用程序”页面。
[## 我的应用程序| Spotify 开发者
创建和管理 Spotify 应用程序以使用 Spotify Web API。获取凭证以通过 Spotify 进行认证,并…
developer.spotify.com](https://developer.spotify.com/my-applications/#!/applications)
一旦创建了一个新的应用程序,并给它一个漂亮的名字。单击创建屏幕,记下客户端 ID 和客户端密码,我们稍后会用到它们。
The screen after you create an application, take note of the Client ID and Client Secret.
在应用程序创建屏幕上,我们还需要设置重定向 URIs 字段。这是您的应用程序登录 Spotify 成功或失败后的位置。为了方便使用,我只是将它设置为 localhost:8888,这对于我的大多数应用程序来说都很好,但是如果你在一个完整的网站中实现这一点,请确保你有一个为 Spotify 回调定义的路径。
Spotify app 创建完成后,我们就可以开始钻研音乐的奇妙世界了!为了这个项目,我将 Python 与 Jupyter Notebook 结合使用,让我可以轻松地跨计算机开发,并给我一个漂亮的 UI 来查看我的图形。
注意:本文的其余部分我将使用 spotipy,Spotify API 的 python 包装器,以下是它们的文档供您阅读:
[## 欢迎来到 Spotipy!- spotipy 2.0 文档
编辑描述
spotipy.readthedocs.io](https://spotipy.readthedocs.io/en/latest/)
从 Spotify API 开始
在我们进行任何分析之前,我们需要学习如何登录,我是这样做的:
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import spotipy.util as utilcid ="<Client ID from Earlier>"
secret = "<Client Secret from Earlier>"
username = ""client_credentials_manager = SpotifyClientCredentials(client_id=cid, client_secret=secret)
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)scope = 'user-library-read playlist-read-private'
token = util.prompt_for_user_token(username, scope)if token:
sp = spotipy.Spotify(auth=token)
else:
print("Can't get token for", username)
这样做的第一件事是初始化一个 client_credentials_manager,它告诉 Spotify 要连接到哪个 Spotify 应用程序。一旦我们知道我们想要连接到哪个应用程序,我们就定义了一个范围。这个范围告诉 Spotify 我们的应用程序需要做什么,查看下面的链接了解更多信息。
当您的应用程序寻求访问用户相关数据的授权时,您通常需要指定一个或多个…
developer.spotify.com](https://developer.spotify.com/web-api/using-scopes/)
定义好范围后,我们就可以登录了。如果这行得通,这个脚本应该会把你重定向到一个奇特的 Spotify 登录页面。登录后,它会将您重定向到我们之前定义的重定向 URL。此外,笔记本会要求您将重定向到的 url 粘贴到提示中以继续。一旦你这样做,它接受请求,你就登录到 Spotify!
随着基本的 Spotify 东西的方式,我们可以转向该项目的数据分析部分。
数据采集
这是整个过程中最乏味的部分。我需要收集两个播放列表,一个装满我不喜欢的歌曲,另一个装满我喜欢的歌曲。
找到我喜欢的歌曲相对容易,我只是添加了我保存的所有歌曲和我喜欢的一些播放列表中的所有歌曲。但这只是成功的一半。
你有没有试过找出不好的音乐??相信我:这很痛苦。
我首先拜访了一些音乐品味我不喜欢的朋友,并添加了一些他们最喜欢的歌曲。最终,我没有朋友了。但是,后来我想起来 Spotify 有流派分类播放列表!万岁。我加入了自己不喜欢的流派,还加了一堆歌。这最终让我开始思考我想要多少首歌。
免责声明:我知道这不是收集数据的最佳方式,但我真的不想花时间去获得我不喜欢的歌曲的代表性样本,我只想获得足够好的东西。
所有这些歌曲的收集都涉及到将歌曲从一个播放列表转移到另一个播放列表。下面是将歌曲从一个播放列表转移到另一个播放列表的代码片段:
sourcePlaylist = sp.user_playlist("<source user>", "<Source Playlist ID>")
tracks = sourcePlaylist["tracks"]
songs = tracks["items"]
while tracks['next']:
tracks = sp.next(tracks)
for item in tracks["items"]:
songs.append(item)
ids = []
print(len(songs))
print(songs[0]['track']['id'])
i = 0
for i in range(len(songs)):
sp.user_playlist_add_tracks("<target user>", "<Target Playlist ID>", [songs[i]["track"]["id"]])
为了移动歌曲,您需要用户和播放列表 id。你可以从播放列表的链接中获得,这里有一个例子:【https://open.spotify.com/user/】T4<用户>/playlist/
边注:在本文的最后,我会在你的好的和不好的播放列表中推荐大约 1500–2000 首歌曲。
数据分析
获取音频功能
现在我们有了好歌和烂歌的播放列表,我们该如何分析它们呢?
幸运的是,Spotify 为我们提供了一种方法——音频功能对象。
这是文档中的对象:
获取由唯一的 Spotify ID 标识的单曲的音频特征信息。去找 https://api.spotify.com/v1…
developer.spotify.com](https://developer.spotify.com/web-api/get-audio-features/)
这个对象是我们分析的基石。我们实际上无法访问原始音频波形或其他统计数据(即播放次数,我们听一首歌多长时间,等等。)让我们的分析更好。虽然这并不完美,但它有助于我们对歌曲中我们喜欢的特征得出一些基本的结论。
要获取一首歌的音频特征,我们需要使用 sp.audio_features( )调用。这需要我们传入一个歌曲 ID 来获取该音轨的特性。
问:但到目前为止,我们只有两首好歌和坏歌的播放列表,我们如何获得所有这些歌曲的歌曲 ID?
我明白了。
good_playlist = sp.user_playlist("1287242681", "5OdH7PmotfAO7qDGxKdw3J")good_tracks = good_playlist["tracks"]
good_songs = good_tracks["items"]
while good_tracks['next']:
good_tracks = sp.next(good_tracks)
for item in good_tracks["items"]:
good_songs.append(item)
good_ids = []
for i in range(len(good_songs)- 500):
good_ids.append(good_songs[i]['track']['id'])
首先,我们通过用户 ID(“1287242681”)和播放列表 ID(“5 odh 7 pmotfao 7 qdgxkdw 3j”)来抓取播放列表。一旦我们有了播放列表,我们需要遍历它来挑选出播放列表中的每首歌曲,然后从那首歌曲中挑选出 id。在这个块结束之后,我们将在 good_ids 数组中有好的歌曲 id。
现在,我们打电话从 Spotify 获取音频功能:
features = []
for i in range(0,len(good_ids),50):
audio_features = sp.audio_features(good_ids[i:i+50])
for track in audio_features:
features.append(track)
features[-1]['target'] = 1
音频功能调用的唯一奇怪之处是我们一次只能获得 50 首歌曲的功能。所以,我们可以把 id 分成 50 份,一次传递 50 份。在这里,我们将所有的音频特性和一个“目标”字段一起添加到一个数组中,以指定我们是否喜欢这首歌。
剩下的就是对坏的播放列表重复相同的步骤,我们可以开始做一些实际的分析了!
图上的图
为了开始查看我们的图形优势,我们需要做的就是将数据插入到熊猫数据框架中。
trainingData = pd.DataFrame(features)
我使用 matplotlib 进行绘图。以下是我的听力数据中一些有趣的对比。
注:蓝色代表我喜欢的歌,红色代表我不喜欢的歌。
Tempo comparison between songs I like and don’t
Valence comparison between songs I like and don’t
第一张图显示了歌曲的节奏。从图表中,我们可以看到我们不能真正用节奏来可靠地预测我是否会喜欢一首歌。下一张图叫做化合价。效价是衡量一首歌听起来有多快乐的标准。这张图表显示我更喜欢悲伤的歌曲,而不是快乐的歌曲。所有其他音频特性的其余图表可以在笔记本中找到。
现在我们有了一些图表,让我们训练一个分类器,看看它在预测我喜欢的歌曲方面有多好!
使用不同的分类器并观察它们如何执行
在我们开始之前,只需要一点点定义。
分类器:试图根据不同的输入值将数据分类到几个不同的桶中。
这是不同分类器之间的一个很好的比较,以及它们如何围绕不同的数据形成。
[## 分类器比较-sci kit-了解 0.19.1 文档
scikit-learn 中几种分类器在合成数据集上的比较。这个例子的目的是为了说明…
scikit-learn.org](http://scikit-learn.org/stable/auto_examples/classification/plot_classifier_comparison.html)
如果你还想进一步了解不同类型的分类器,Google 是你的好朋友!
为了使任何分类器工作,我们需要将我们的数据分成训练和测试集,这样我们就有一些数据来训练我们的模型,还有一些数据来测试前面提到的模型。这可以通过一个名为 train_test_split()的 sklearn 函数来实现,该函数根据方法中指定的 test_size 百分比来拆分数据。下面的代码将数据分成 85%训练,15%测试。
from sklearn.model_selection import train_test_split
train, test = train_test_split(trainingData, test_size = 0.15)
在我们分割数据之后,我们将把它放入训练/测试 x 和 y 变量中,以输入到我们的分类器中。
#Define the set of features that we want to look at
features = ["danceability", "loudness", "valence", "energy", "instrumentalness", "acousticness", "key", "speechiness", "duration_ms"]#Split the data into x and y test and train sets to feed them into a bunch of classifiers!
x_train = train[features]
y_train = train["target"]x_test = test[features]
y_test = test["target"]
决策树分类器
决策树分类器是我要看的第一个分类器,因为它最容易可视化。下面的代码片段显示了如何使模型符合训练数据,根据测试数据预测值,然后显示模型的准确性。
c = DecisionTreeClassifier(min_samples_split=100)
dt = c.fit(x_train, y_train)
y_pred = c.predict(x_test)
score = accuracy_score(y_test, y_pred) * 100
print("Accuracy using Decision Tree: ", round(score, 1), "%")
这个分类器配置最重要的部分是 min_samples_split 值。这是基于特征的树分割的值。这是决策树的一小部分。
A snippet of the Decision Tree to show the decisions and number of samples in each bucket
决策树给我的准确率只有 80%,这很好,但我们可以做得更好。
近邻分类器
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(3)
knn.fit(x_train, y_train)
knn_pred = c.predict(x_test)
score = accuracy_score(y_test, knn_pred) * 100
print("Accuracy using Knn Tree: ", round(score, 1), "%")
K-最近邻分类器查看数据点的邻居,以确定输出是什么。因此,在我们的例子中,它接收一首新歌曲的音频特性,绘制它并查看它周围的歌曲,以确定我是否会喜欢它。这种方法只给了我们 80%的准确率,和决策树一样。我对这种类型的分类器不抱太大希望,因为我训练的数据没有很好地按照不同的特征分开。
AdaBoostClassifier 和 GradientBoostingClassifier
from sklearn.ensemble import AdaBoostClassifier
ada = AdaBoostClassifier(n_estimators=100)
ada.fit(x_train, y_train)
ada_pred = ada.predict(x_test)
from sklearn.metrics import accuracy_score
score = accuracy_score(y_test, ada_pred) * 100
print("Accuracy using ada: ", round(score, 1), "%")from sklearn.ensemble import GradientBoostingClassifier
gbc = GradientBoostingClassifier(n_estimators=100, learning_rate=.1, max_depth=1, random_state=0)
gbc.fit(x_train, y_train)
predicted = gbc.predict(x_test)
score = accuracy_score(y_test, predicted)*100
print("Accuracy using Gbc: ", round(score, 1), "%")
这两种分类器的操作方式相似。它们都是从创建一个相对较弱的“学习者”(用来做预测的东西)开始,然后用分类的结果来修改“学习者”,让它更好地预测未来的事情。
AdaBoost 的工作原理是拟合学习者,然后在数据的每次迭代之间,它修改预测的方式,以便尝试以更高的精度对更困难的情况进行分类。当我运行这个分类器时,它有 84.3%的准确率。
梯度增强使用损失函数(预测值与真实值相差多远的度量),并尝试在每次迭代中减少损失函数。当我运行这个分类器时,它有 85.5%的准确率。
免责声明:每次运行分类器时,这些精度值都会发生变化,所以如果您没有得到与我相同的值,请不要担心。
我们现在要做的就是选择对我们的训练数据具有最高准确度的分类器(对我来说是梯度提升),并测量它在现实世界中的表现如何!
结果
为了测试我的分类器,我在我的 Discover Weekly 上运行了 4 周。Discover Weekly 是 30 首歌,所以我总共测试了 120 首歌。为了做到这一点,重复我们加载好的和坏的播放列表的步骤,但之后,只需调用分类器的预测功能。
pred = gbc.predict(playlistToLookAtFeatures[features])i = 0
for prediction in pred:
if(prediction == 1):
print ("Song: " + playlistToLookAtFeatures["song_title"][i] + ", By: "+ playlistToLookAtFeatures["artist"][i])
i = i +1
分类器挑选了 66 首它认为我会喜欢的歌曲。听了所有的歌,我挑出了 31 首我喜欢的歌。分类器和我个人喜欢分享了 23 首歌。因此,我的分类器识别出了 43 首它说我喜欢但不喜欢的歌曲。然而,它只错过了我喜欢的 8 首歌。尽管得到了一堆假阳性,我会称之为我的第一次钻研像这样的成功!
未来
最终我想开始使用谷歌的开源机器学习库 Tensorflow ,并希望用他们提供给我的工具制作一个更好的模型。我最终还想将这个分类器整合到一个更大的系统中,每天为我挑选一个“每周发现”播放列表,这样我就可以不断地寻找新音乐。
如果你喜欢这个,一定要看看我的 Github 或者至少是 Python 笔记本 所有这些代码都是你可以随意摆弄的!此外,如果你认识在Spotify工作的人,我很乐意与你联系!如果你有任何建议或者意识到我做错了什么,一定要在评论里告诉我!
人类计划,上帝大笑:计划谬误
所以你打算看完整篇文章?让我想想…
从前,有一个男孩和一个女孩。他们在悉尼歌剧院有个约会。她像往常一样迟到了——意想不到的事情发生了——她无法立即找到她 100 种化妆品中的一种。(其他时候她找不到其他的,所以结果一样总是不一样。)
by Jovana Đukić
在等待的时候,他谷歌了关于这部歌剧的有趣事实来打动她。这是他在维基百科上找到的:
“悉尼歌剧院原定 4 年,预算 700 万澳元。它最终花了 14 年才完成,耗资 1.02 亿澳元。”
“太酷了!”他想。她听后也这么说。在接下来的几个月里,他们经常使用同一个短语,所以他们决定结婚。(她喜欢他有趣的事实,他喜欢她迟到——所以他有足够的时间去发现它们。)
他与父亲离婚的固执的母亲警告他,他们有 33%到 50%的机会离婚。“不是我们,妈妈。我们非常相爱。”“当然,因为我和你父亲是出于仇恨才结婚的。”
他们还是结婚了,而且比一些婚姻做得更好。
“没有什么能把我们分开。我们可能会再结婚十年。”——伊丽莎白·泰勒,在她和理查德·伯顿宣布离婚的五天前
但比大多数婚姻都糟糕。确切的说,比他们中的 67%到 50%还要差。
她得到的结婚礼物是一个可以存放化妆品的盒子。结果她不再迟到了;所以这家伙没时间去找有趣的事实。谁想在一段婚姻中,最有趣的事实是对你离婚的预测?
“不是我!”她抓起盒子扔在地板上。那天,盒子和婚姻都破裂了。
规划谬误
人们总是迟到,项目花费数百万而不是数千,战争花费数年而不是数月,为什么我妈妈总是带着满满一袋子杂货回家,不管她打算买什么?是规划谬误!
计划谬误的概念是由诺贝尔奖获得者丹尼尔·卡内曼和他的同事阿莫斯·特沃斯基首先提出的。它描述了过于乐观的计划和预测
- 不切实际地接近最佳情况
- 可以通过参考类似案例的统计数据进行改进。
by Jovana Đukić
在他的书《思考,快与慢》中,卡尼曼描述了下面的预测故事。他和他的同事正在设计一本在高中教授判断和决策的教科书。在一年中每周会面一次后,他们已经取得了一些进展:写了几个章节,构建了一个教学大纲的大纲,并进行了一些示范课程。
他们只是在讨论如何估计不确定的量,所以卡尼曼提议每个人在完成课本之前写下他们对持续时间的估计。结果集中在两年左右。
然后卡尼曼转向课程专家(两人估计和其他人一样)问他:“构建一个课程通常需要多长时间?”
“七到十年。更不用说之前几乎有一半的群体放弃了,”他回答道。
卡尼曼进一步挖掘道:“与其他群体相比,我们有多优秀?”
“略低于平均水平,”课程专家说。过了一会儿,他扬起眉毛,意识到他的估计有矛盾。低于平均水平的群体如何超过其他人三年以上?
它可以,但假设它会是愚蠢的。
出现这种差异是因为他使用了两种不同的计划策略。当写下他的估计时,他在脑海中搜寻信息*,试图想象未来。后来,在卡尼曼的帮助下,他根据来自世界之外的的类似情况的统计数据做出了预测。*
内部视图
这是一个小组成员写下他们的评估的策略。该战略关注我们的具体情况,并在我们的经验中寻找证据。这是推断——假设现有的趋势将会继续。有一个问题:
“未来不再是过去的样子了”—约吉·贝拉
“这种(过于乐观的预测)的原因是,我们通过压缩可能的不确定状态的范围(通过减少未知的空间)来低估不确定性,”纳西姆·尼古拉斯·塔勒布在他的畅销书《黑天鹅》中解释道。换句话说,我们低估了我们所不知道的。在卡尼曼的情况下,这些可能是更复杂的章节,疾病,官僚问题…数百件你甚至无法想象的事情。
“意外总是朝着一个方向推进:更高的成本和更长的完成时间.”—纳西姆·尼古拉斯·塔勒布
任务越长、越复杂、越独特,预测就越难。想想最基本的,从椅子上站起来。如果你不想再坐着了,你可以预测你什么时候会站起来——除非你的朋友喜欢用胶水恶作剧。
另一边是战争。每场战争都有自己的属性:人员、地形、天气、战术、技术。它们通常持续多年(尽管预测时间较短)。更多的时间意味着更多意想不到的机会。如果日本可以预测他们核武器的发展,他们会攻击美国吗?
即使在今天,战争预测也悲惨地失败了。布什政府低估了伊拉克战争费用超过 30 倍;目前的支出约为 2 万亿美元(最初为 600 亿美元),并且还在增长。
如果说从内心深处可以学到什么,那就是霍夫施塔特定律:
"它总是比你想象的要长,即使你把霍夫施塔特定律考虑在内."道格拉斯·霍夫施塔特
外面的景色
使用类似项目的统计信息是解决规划谬误的方法。一般来说,你会面临和其他人一样多的意想不到的麻烦。
称为参考类预测的方法是由 Flyvbjerg 提出的。它包含三个步骤,我在其中添加了卡内曼故事中的实际例子:
- 确定一个合适的参考班:其他课程项目。
- 获取参考类的统计数据,生成基线预测 : 7 到 10 年,40%失效率。
- 利用案件具体信息调整基线预测:有没有证据表明我们组比其他组好/差?
卡尼曼的团队用了八年时间完成了这个项目,接近最快的项目。那些年,很多事情都变了:他不再是这个团体的一员,对教授决策也没什么兴趣。教科书从来没有出现在学校的长凳上。
在某些情况下,我们已经在某种程度上使用了外部视图。想想寿命预测。通常使用平均寿命,并根据生活方式、遗传和健康状况增加或减少几年。一个人不会看着自己的经历宣布:“我感觉很好,我还没有死,根据这个证据,我会永远活着。”
by Jovana Đukić
乐观偏见
规划谬误还有一个偏见;乐观偏见。总结如下:
“我们中的大多数人认为世界比实际情况更好,我们自己的属性比实际情况更好,我们采纳的目标比他们可能实现的目标更容易实现。”—丹尼尔·卡内曼
我们不对称地感知事件。我们把成功归因于我们的技能,把失败归因于运气不好。但只针对我们自己和与我们密切相关的人,而不是其他人——这创造了虚幻的优越感。
研究人员发现,90%的司机认为自己比普通司机强,大多数学生认为自己比普通学生更聪明。按照这种逻辑,我们为什么不能成为成功的人呢?
因为每个人都认为自己有点特别,但这并不能让任何人特别。
“你有没有注意到,开车比你慢的人是白痴,比你快的人是疯子?”—乔治·卡林
这个刚刚单身的男人出去喝啤酒来治愈他受伤的心灵。他想赢回他的乐观(偏见,但他不承认)。当他转向投篮时,他打偏了。他对未来并不乐观,反而对过去感到悲伤。朋友们还没来得及阻止他(他们正忙着检查手机),手机已经到了他手里。
“我 miz u;“d”是开始把破裂的婚姻粘在一起的信息。(她睡着了,所以没有立即回应——我们都知道谁喜欢等待。)
然而,他们不需要把化妆盒粘在一起。他买下它作为他们再生爱情的标志——这是让她再次说“太酷了”的东西。
对他们来说,“哦,太酷了”离说“我愿意”不远了。
他们计划好了,上帝笑了。
原载于 2017 年 12 月 29 日 新锐 。
人与机器:理解人工智能的危险
当谈到人工智能(AI)的话题时,世界显然分成了两派:一派强烈认为人工智能是件好事,另一派强烈否认这一点。双方都有合理的论据。我个人在这个问题上的观点仍然是,赞成和反对的观点都与环境有关——谁在开发它,用于什么应用,在什么时间框架内,为了什么目的?没有明确的黑与白。这也意味着,随着人工智能领域的进一步发展,有机会主动识别、隔离和解决风险。
这有助于理解争论的双方。所以让我们试着仔细看看反对者说了什么。最常引起争论的担忧可分为三大类:
A. 大规模失业:这可能是在人工智能背景下强调的所有风险中最切实、最广为人知的。技术和机器代替人类做某些类型的工作并不新鲜。我们都知道,由于技术的发展,整个职业正在减少,甚至消失。工业革命也导致了大规模的失业。
然而,尽管人们担心就业,但在过去的 3-4 个世纪里,人们普遍承认,这些技术进步通过创造新的途径、降低价格、增加工资等方式,大大弥补了短期的就业损失。
然而,今天的故事非常不同。请考虑以下情况:
- 越来越多的经济学家不再相信,从长期来看,技术会对整体就业产生积极影响。
- 仅在过去十年中,中低技能工作的流失在几个领域都很严重——令人不安的事实是,这些工作大多不是受到人工智能的影响,而只是受到自动化的影响——人工智能的影响预计会更大。
- 多项研究预测技术进步将导致大规模失业,包括 2016 年的一份联合国报告称,预计发展中国家 75%的工作将被机器取代。
失业,尤其是大规模的失业,是一件非常危险的事情,常常会导致大范围的社会动荡。因此,人工智能在这一领域的潜在影响需要非常仔细的政治、社会学和经济学思考,以有效地应对它。
奇点:奇点的概念是人们想象中只能在未来科幻小说中看到的东西之一。然而,从理论上说,今天这是一个真正的可能性。简而言之,奇点是指人类文明中的一个点,当人工智能达到一个临界点,超过这个临界点,它就会进化为一种超越人类认知能力的超级智能,从而对我们今天所知的人类存在构成潜在威胁。
虽然围绕机器智能爆炸的想法是一个非常中肯和广泛讨论的话题,但与技术驱动的失业不同,这个概念仍然主要是理论性的。围绕这一思路的两个主要问题尚不明确,即
- 这个临界点在现实中真的能达到吗?
- 如果是的话,在中短期内可能发生吗?
C. 机器意识:与前两点不同,这两点可以被视为与人工智能进化相关的风险,机器意识方面或许最好被描述为一个伦理难题。这个想法涉及将类似人类的意识植入机器的可能性,使它们超越*‘思维’的领域,进入‘感觉、情感和信念’*的领域。
这是一个复杂的话题,需要深入研究哲学、认知科学和神经科学的融合。“意识”本身可以有多种解释,集合了过多的属性,如自我意识、心理状态的因果关系、记忆、经验等。要让机器达到类似人类的意识状态,需要复制人脑中神经层面发生的所有活动——这绝不是一项简单的任务。
如果要实现这一目标,就需要世界运作模式的转变。当今社会是一个完善的、结构化的系统,它指导着人们相互交往的方式。这个系统将需要一个重大的重新定义,以纳入与人类共存的具有意识的机器,以及两者之间的相互关系。这在今天听起来有些牵强,但像这样的问题需要现在就思考,以便能够影响我们在人工智能和机器意识方面的发展方向,而事情仍然处于“设计”阶段。
虽然以上都是中肯的问题,但我相信它们不一定会超过人工智能的优势。当然,有必要系统地解决它们,控制人工智能发展的路径,并将不利影响降至最低。在我看来,最大和最迫在眉睫的风险实际上是第四项,在讨论人工智能的陷阱时,并不经常被考虑在内。
D. **寡头:**或者换个说法,控制的问题。由于人工智能的本质——它需要在技术和科学上的巨大投资——现实中只有少数组织(私人或政府)能够以可扩展的方式跨越一系列广泛的应用程序,将人工智能纳入主流。
除此之外,开发人工智能最重要的组成部分之一是持续的反馈和学习,这来自于拥有最大量的数据来获得反馈或学习。这是一个自我实现的良性循环——你拥有的数据越多,你的人工智能平台就越好,导致更多用户采用你的人工智能平台,而你获得更多数据进行更多学习。你认为谁会赢得这场比赛?同样,只有少数组织可能做到。无论小型新贵有多聪明,他们都没有多少空间与这些公司大规模竞争。
鉴于我们生活的巨大部分可能将由人工智能机器来控制,那些控制这种“智能”的人将对我们其他人拥有巨大的权力。所有熟悉的短语*‘权力越大,责任越大’*将有全新的含义——处于普遍可用的人工智能应用前沿的组织和/或个人可能比历史上最专制的独裁者拥有更多权力。这是一个真实的危险,它的某些方面已经成为人们关注的领域,比如围绕隐私的讨论。
总之,像人类历史上所有重大变革事件一样,人工智能肯定会产生广泛深远的影响。但是经过仔细的深思熟虑,这些问题是可以解决的。从短期到中期来看,人工智能在改善我们生活方面的优势可能会超过这些风险。任何广泛触及人类生活的重大概念,如果处理不当,都会带来巨大的危险。我能想到的最好的类比是宗教——如果引导不当,它可能会构成比任何技术进步都更大的威胁。
在早期管理您的数据科学项目结构。
Jupyter Notebook(或 Colab,databrisk 的 Notebook 等)为在短时间内建立一个项目提供了一个非常有效的方法。我们可以在笔记本中创建任何 python 类和函数,而无需重新启动内核。有助于缩短等待时间。它适合于小规模的工程和实验。然而,这可能不利于长期增长。
“white and multicolored building scale model” by Alphacolor 13 on Unsplash
看完这篇文章,你会明白:
- 什么时候我们需要一个定义良好的项目文件夹结构?
- 模块化
- 建议
什么时候我们需要一个定义良好的项目文件夹结构
概念证明(PoC)
直觉上,速度是我们进行概念验证(PoC)时的主要考虑因素。在之前的一个项目中,我探索了文本摘要技术是否可以应用到我的数据科学问题中。我不打算为我的 PoC 构建任何“美丽”或“结构”,因为我不知道它是否有用。
换句话说,我使用“快速和肮脏”的方式来进行 PoC,因为没有人关心它是否结构良好或性能是否得到优化。从技术角度来看,我可能会在笔记本内部创造功能。好处是我不需要处理任何外部化文件(例如加载其他 python 文件)。
包装解决方案
“four brown gift boxes on white surface” by Caley Dimmock on Unsplash
在多次运行 PoC 后,应确定解决方案。由于多种原因,代码重构从此刻开始是必要的。它不仅组织得很好,而且有利于实现更好的预测。
模块化
“editing video screengrab” by Vladimir Kudinov on Unsplash
首先,你必须让你的实验可重复。当你最终确定(至少是初始版本)时,你可能需要与其他团队成员一起工作来组合结果或构建一个系综模型。其他成员可能需要检查和审查你的代码。如果他们不能复制你的作品,这不是一个好主意。
另一个原因是超参数调整。我不关注早期阶段的超参数调整,因为它可能会花费太多的资源和时间。如果解决方案得到确认,那么在启动预测服务之前,应该是寻找更好的超参数的好时机。不仅在嵌入层的维度上调整神经网络中神经元的数目,还可以进行不同的架构(例如比较 GRU、LSTM 和注意机制)或其他合理的改变。因此,模块化您的处理、培训、度量评估功能是管理这种调整的重要步骤。
此外,你需要将你的代码运送到不同的集群(比如 Spark,或者自建分布式系统)进行调优。由于一些原因,我没有使用 dist-keras (分布式 keras 培训库)。我自己构建了一个简单的集群来加速分布式训练,同时它可以支持 Keras、scikit-learn 或任何其他 ML/DL 库。将实现打包成 python 而不是 notebook 会更好。
建议
在交付了几个项目后,我重温了论文和项目结构模板,并遵循敏捷项目管理策略。我将塑造我的项目结构如下风格。它使我在每个项目迭代或冲刺中拥有组织良好的项目和更少的痛苦。
Rounded rectangle means folder. python code, model file, data and notebook should be put under corresponding folder.
src
存储服务于多种场景的源代码(python、R 等)。在数据探索和模型训练过程中,我们必须为特定目的转换数据。在线预测期间,我们也必须使用相同的代码来传输数据。因此,它更好地将代码从笔记本中分离出来,以服务于不同的目的。
- 准备:数据摄取,例如从 CSV、关系数据库、NoSQL、Hadoop 等检索数据。我们必须一直从多个来源检索数据,所以我们最好有一个专门的数据检索功能。
- 处理:作为源数据的数据转换并不总是符合模型的需要。理想情况下,我们有干净的数据,但我从来没有得到它。你可能会说我们应该让数据工程团队帮助我们进行数据转换。但是,在学习数据下,我们可能不知道自己需要什么。一个重要的要求是离线训练和在线预测都应该使用相同的流水线来减少未对准。
- 建模:建模,如解决分类问题。它不仅包括模型训练部分,还包括评估部分。另一方面,我们必须考虑多模型场景。典型的用例是集成模型,如结合逻辑回归模型和神经网络模型。
测试
在 R&D,数据科学侧重于建立模型,但并不确保在意想不到的情况下一切正常。但是,如果将模型部署到 API,这将是一个麻烦。此外,测试用例保证向后兼容的问题,但它需要时间来实现。
- 断言 python 源代码的测试用例。更改代码时确保没有 bug。自动化测试是成功项目的一个基本难题,而不是使用手工测试。假设测试用例有助于验证代码更改不会破坏以前的用法,团队成员将有信心修改代码。
型号
用于存储本地使用的二进制(json 或其他格式)文件的文件夹。
- 仅在此存储中间结果。对于长期来说,它应该单独存储在模型库中。除了二进制模型,您还应该存储模型元数据,如日期、训练数据的大小。
数据
用于存储实验子集数据的文件夹。它包括原始数据和临时使用的处理过的数据。
- raw:存储从“准备”文件夹代码生成的原始结果。我的做法是存储一个本地子集副本,而不是不时地从远程数据存储中检索数据。它保证您有一个静态数据集来执行其余的操作。此外,我们可以将数据平台不稳定问题和网络延迟问题隔离开来。
- 已处理:为了缩短模型训练时间,保存已处理的数据是一个好主意。它应该从“处理”文件夹中生成。
笔记本
存储所有笔记本,包括 EDA 和建模阶段。
- eda:探索性数据分析(又名数据探索)是为后面的步骤探索您所拥有的东西的一个步骤。对于短期的目的,它应该显示你探索了什么。典型的例子是显示数据分布。长期存放时,应集中存放。
- poc:由于某些原因,你不得不做一些 PoC(概念验证)。它可以在这里临时展示。
- 建模:笔记本包含您的核心部分,其中包括模型建立和培训。
- 评估:除了建模,评估是另一个重要的步骤,但很多人并不知道。为了获得产品团队的信任,我们必须展示模型有多好。
拿走
要访问项目模板,您可以访问这个 github repo。
- 前述对中小型数据科学项目有好处。
- 对于大型数据科学项目,它应包括其他组件,如特征库和模型库。以后会为这部分写博客。
- 根据你的情况修改了。
关于我
我是湾区的数据科学家。专注于数据科学、人工智能,尤其是 NLP 和平台相关领域的最新发展。你可以通过媒体博客、 LinkedIn 或 Github 联系我。
参考
使用 MLflow 管理您的机器学习生命周期—第 1 部分。
重现性,良好的管理和跟踪实验是必要的,以方便测试他人的工作和分析。在第一部分中,我们将从简单的例子开始学习如何记录和查询实验,包装机器学习模型,以便它们可以在任何使用 MLflow 的平台上重现和运行。
机器学习生命周期难题
机器学习(ML)并不容易,但创建一个良好的工作流,让您可以重现、重新访问并部署到生产中,就更难了。在为 ML 创建一个好的平台或管理解决方案方面已经取得了很多进展。注意,t his 不是数据科学(DS)生命周期,后者更复杂,有很多部分。
ML 生命周期存在于 DS 生命周期中。
您可以在此处查看一些用于创建 ML 工作流的项目:
厚皮动物-大规模可再生数据科学!
github.com](https://github.com/pachyderm/pachyderm) [## 燃烧/泄漏
mleap - MLeap:将 Spark 管道部署到生产中
github.com](https://github.com/combust/mleap)
这些包很棒,但是不容易理解。也许解决方案是这三者的混合,或者类似的东西。但在这里,我将向您展示由 Databricks 创建的最新解决方案,名为 MLflow。
MLflow 入门
MLflow 是一个完整的机器学习生命周期的开源平台。
MLflow 设计用于任何 ML 库、算法、部署工具或语言。将 MLflow 添加到您现有的ML 代码中非常容易,因此您可以立即从中受益,并且可以使用您组织中的其他人可以运行的任何 ML 库来共享代码。MLflow 也是一个用户和库开发者可以扩展的开源项目。
安装 MLflow
安装 MLflow 非常简单,您只需运行:
pip install mlflow
这是根据创作者所说的。但是我在安装的时候遇到了几个问题。所以下面是我的建议(如果安装 ignore 后可以在终端中运行 mlflow 的话):
来自 Databricks: MLflow 不能安装在 Python 的 MacOS 系统安装上。我们推荐使用
brew install python
通过自制包管理器安装 Python 3。(在这种情况下,安装 mlflow 现在是pip3 install mlflow
)。
这对我不起作用,我得到了这个错误:
~ ❯ mlflow
Traceback (most recent call last):
File "/usr/bin/mlflow", line 7, in <module>
from mlflow.cli import cli
File "/usr/lib/python3.6/site-packages/mlflow/__init__.py", line 8, in <module>
import mlflow.projects as projects # noqa
File "/usr/lib/python3.6/site-packages/mlflow/projects.py", line 18, in <module>
from mlflow.entities.param import Param
File "/usr/lib/python3.6/site-packages/mlflow/entities/param.py", line 2, in <module>
from mlflow.protos.service_pb2 import Param as ProtoParam
File "/usr/lib/python3.6/site-packages/mlflow/protos/service_pb2.py", line 127, in <module>
options=None, file=DESCRIPTOR),
TypeError: __init__() got an unexpected keyword argument 'file'
解决这个问题的方法并不容易。我用的是 MacOS btw。为了解决这个问题,我需要更新 protobuf 库。为此,我安装了 Google 的 protobuf 库,其来源为:
protobuf -协议缓冲区-谷歌的数据交换格式
github.com](https://github.com/google/protobuf/releases)
下载 3.5.1 版本。我之前有过 3.3.1。请遵循以下步骤:
[## 安装协议
使用现代 Haskell 语言和库模式的协议缓冲 API。
google.github.io](http://google.github.io/proto-lens/installing-protoc.html)
或者试着用自制的。
如果您的安装工作正常,运行
mlflow
你应该看看这个:
Usage: mlflow [OPTIONS] COMMAND [ARGS]...Options:
--version Show the version and exit.
--help Show this message and exit.Commands:
azureml Serve models on Azure ML.
download Downloads the artifact at the specified DBFS...
experiments Tracking APIs.
pyfunc Serve Python models locally.
run Run an MLflow project from the given URI.
sagemaker Serve models on SageMaker.
sklearn Serve SciKit-Learn models.
ui Run the MLflow tracking UI.
MLflow 快速入门
现在您已经安装了 MLflow,让我们运行一个简单的示例。
**import** **os**
**from** **mlflow** **import** log_metric, log_param, log_artifact
**if** __name__ == "__main__":
*# Log a parameter (key-value pair)*
log_param("param1", 5)
*# Log a metric; metrics can be updated throughout the run*
log_metric("foo", 1)
log_metric("foo", 2)
log_metric("foo", 3)
*# Log an artifact (output file)*
**with** open("output.txt", "w") **as** f:
f.write("Hello world!")
log_artifact("output.txt")
将其保存到 train.py,然后使用
python train.py
您将看到以下内容:
Running test.py
就这样吗?没有。使用 MLflow,您可以通过编写以下内容轻松访问用户界面:
mlflow ui
您将看到(localhost:默认为 5000):
那么到目前为止我们做了什么?如果你看到代码,你会看到我们使用了两个东西,一个 *log_param,*log _ metric 和 *log_artifact。*第一个记录当前运行下传入的参数,如果需要的话创建一个运行,第二个记录当前运行下传入的度量,如果需要的话创建一个运行,最后一个记录一个本地文件或目录作为当前活动运行的工件。
通过这个简单的例子,我们了解了如何在生命周期中保存参数、指标和文件的日志。
如果我们点击运行的日期,我们可以看到更多的信息。
现在,如果我们单击该指标,我们可以看到它在运行过程中是如何更新的:
如果我们单击工件,我们可以看到它的预览:
物流跟踪
MLflow 跟踪组件允许您使用 REST 或 Python 记录和查询实验。
每次运行记录以下信息:
代码版本: Git commit 用于执行运行,如果它是从 MLflow 项目中执行的。
**开始&结束:**运行的开始和结束时间
**源:**为启动运行而执行的文件的名称,或者如果运行是从 MLflow 项目中执行的,则为运行的项目名称和入口点。
**参数:**键值输入你选择的参数。键和值都是字符串。
**指标:**值为数字的键值指标。在整个运行过程中,可以更新每个指标(例如,跟踪模型的损失函数如何收敛),MLflow 将记录并让您可视化指标的完整历史。
**工件:**输出任意格式的文件。例如,您可以将图像(例如,png)、模型(例如,腌制的 SciKit-Learn 模型)甚至数据文件(例如,拼花文件)记录为工件。
可以有选择地将运行组织成实验,这些实验将特定任务的运行组合在一起。您可以通过mlflow experiments
CLI、使用[**mlflow.create_experiment()**](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.create_experiment)
或通过相应的 REST 参数创建一个实验。
*# Prints "created an experiment with ID <id>*
mlflow experiments create face-detection
*# Set the ID via environment variables*
export MLFLOW_EXPERIMENT_ID=<id>
然后你开始一个实验:
*# Launch a run. The experiment ID is inferred from the MLFLOW_EXPERIMENT_ID environment variable***with** mlflow.start_run():
mlflow.log_parameter("a", 1)
mlflow.log_metric("b", 2)
跟踪示例:
一个使用葡萄酒质量数据集的简单例子:包括两个数据集,分别与来自葡萄牙北部的红葡萄酒和白葡萄酒相关。目标是基于物理化学测试来模拟葡萄酒质量。
首先下载该文件:
https://raw . githubusercontent . com/databricks/ml flow/master/example/tutorial/wine-quality . CSV
然后在文件夹中创建文件 train.py,内容如下:
*# Read the wine-quality csv file*
data = pd.read_csv("wine-quality.csv")
*# Split the data into training and test sets. (0.75, 0.25) split.*
train, test = train_test_split(data)
*# The predicted column is "quality" which is a scalar from [3, 9]*
train_x = train.drop(["quality"], axis=1)
test_x = test.drop(["quality"], axis=1)
train_y = train[["quality"]]
test_y = test[["quality"]]
alpha = float(sys.argv[1]) **if** len(sys.argv) > 1 **else** 0.5
l1_ratio = float(sys.argv[2]) **if** len(sys.argv) > 2 **else** 0.5
**with** mlflow.start_run():
lr = ElasticNet(alpha=alpha, l1_ratio=l1_ratio, random_state=42)
lr.fit(train_x, train_y)
predicted_qualities = lr.predict(test_x)
(rmse, mae, r2) = eval_metrics(test_y, predicted_qualities)
print("Elasticnet model (alpha=*%f*, l1_ratio=*%f*):" % (alpha, l1_ratio))
print(" RMSE: *%s*" % rmse)
print(" MAE: *%s*" % mae)
print(" R2: *%s*" % r2)
mlflow.log_param("alpha", alpha)
mlflow.log_param("l1_ratio", l1_ratio)
mlflow.log_metric("rmse", rmse)
mlflow.log_metric("r2", r2)
mlflow.log_metric("mae", mae)
mlflow.sklearn.log_model(lr, "model")
在这里,我们将为 SciKit-Learn 介绍 MLflow 集成。运行后,您将在终端中看到:
Elasticnet model (alpha=0.500000, l1_ratio=0.500000):
RMSE: 0.82224284976
MAE: 0.627876141016
R2: 0.126787219728
然后在包含mlruns
目录的同一个当前工作目录中运行 mlflow ui,并在浏览器中导航到 http://localhost:5000 。你会看到:
每次跑步你都会有这个,这样你就可以跟踪你做的每一件事。该模型还有一个 pkl 文件和一个 YAML,用于部署、复制和共享。
敬请关注更多
在下一篇文章中,我将介绍项目和模型 API,我们将能够在生产中运行这些模型,并创建一个完整的生命周期。
请务必查看 MLflow 项目以了解更多信息:
mlflow -完整机器学习生命周期的开源平台
github.com](https://github.com/databricks/mlflow)
感谢你阅读这篇文章。希望你在这里发现了一些有趣的东西:)
如果你有任何问题,请在推特上关注我
Favio Vázquez 的最新推文(@FavioVaz)。数据科学家。物理学家和计算工程师。我有一个…
twitter.com](https://twitter.com/faviovaz)
还有 LinkedIn。
[## Favio Vázquez —首席数据科学家— OXXO | LinkedIn
查看 Favio Vázquez 在世界上最大的职业社区 LinkedIn 上的个人资料。Favio 有 15 个工作职位列在…
linkedin.com](http://linkedin.com/in/faviovazquez/)
那里见:)
管理深度学习中的实验
使用深度学习包括运行无数的实验来测试一个人可能有的各种假设,以解决特定的问题,或者通过尝试多个超参数来获得更好的结果。随着时间的推移,这些实验的数量越来越多,管理它们甚至试图反映几周前做了什么可能会有点困难。在这篇文章中,我计划分享一些我使用的技巧或窍门(作为一名全职从事深度学习的研究生),以保持事情有序,防止自己迷失在一堆懒洋洋定义的日志文件中,如 exp0、exp1、newexp。
保持同步
我(我想也有很多其他人)在基于 GPU 的 linux 服务器上运行实验,然后将结果复制回主机进行分析。这种类型的数据可能包括 csv/txt 文件、tensorboard 日志或图像。
我发现 rsync 是一个完美的工具(我以前习惯于 scp ),它的主要优点是只同步源和目的地之间的差异。当培训正在进行中(预计需要很长时间)并且我们想要监控进度时,这是很有帮助的。我通常在生成模型上工作,所以我需要不时地通过浏览各个时期生成的东西来检查我的 GAN 是否变得疯狂了。
最简单的方法是:
rsync -av <username>@remote-host:<path_to_results_folder> .
在这里,-a
将递归地传输所有内容,-v
代表详细程度。这相当快。此外,如果你的服务器是通过网关,你需要事先登录。
使用 rsync 可以做很多事情,例如,在生产环境中部署模型,或者设置一个 cronjob 以固定的时间间隔提取日志。参考这篇文章来看看后者是如何实现的。
张量板
许多人都不知道 Tensorflow 的惊人可视化工具 Tensorboard 可以作为一个独立的实用程序来绘制几乎任何东西的漂亮的交互式曲线。我通常坚持只绘制标量,以使事情变得更快更轻(传输和加载时间)。APItensor board-py torch在这方面真的很牛逼。我不知道为什么他们称它为“-Pytorch”,因为它很普通。通过pip install tesorboardX
安装。
from tensorboardX import SummaryWriter
writer = SummaryWriter(log_dir=<path_to_log>)
for i in range(num_epochs):
loss = forward_pass()
writer.add_scalar('loss', loss)
我们结束了。接下来,启动 tensorboard 并查看剧情:tensorboard --logdir <path_to_log>
。为了比较来自多个实验的损失(或任何其他度量),<path_to_log>
可以是tb_log/<exp_name>
,其中tb_log
是包含每个实验的子目录的目录。接着,启动 tensorboard 时的logdir
标志的值会变成tb_log
。
如果在远程服务器上,我建议将日志文件拉回到本地,然后从那里启动 tensorboard。上一节中的rsync
命令可用于定期更新tb_log
中的文件,同时保持 tensorboard 在后台运行。
或者,tensorboard 可以在远程服务器上启动,仪表板可以通过public IP:port(6006 is default)
导航。如果远程服务器没有公共 IP 地址,可以使用 SSH 隧道。例如,如果我在默认端口 6006 上的某个 IP 为 10.11.12.13 的服务器上启动 tensorboard,我可以通过以下方式将其传输到我的本地计算机:
ssh -N -f -L localhost:6006:10.11.12.13:6006 username@10.11.12.13
其中localhost:6006:10.11.12.13:6006
为<destination_address>:<destination_port>:<source_address>:<source_port>
。
通过 gif 跟踪图像生成进度
为了容易地定性评估模型的进展,可以很容易地创建随时间生成的样本的 gif。
from torchvision import make_grid
import imageio
grid = []
for i in range(num_epochs):
samples = forward_pass()
# the following functions are in context of pytorch
grid.append(make_grid(samples).permute(1, 2, 0).numpy())
imageio.mimsave('generations.gif', grid)
我们需要将生成的形状样本(batch_size,channels,height,width)转换为(height,width,channel ),因此首先将图像连接起来形成一个网格,然后转置维度并转换为 numpy 数组。
这使得人们不必仔细检查和比较为每个时期分别生成和保存的图像。
Source: https://docs.floydhub.com/examples/dcgan/
测井实验
并不是我们运行的所有实验都在 excel 表中,即使这样,也很难在一个紧凑的二维表中捕获所有信息,即与每个实验相关的所有设置和更改。为了确保我过去运行的所有实验都被记录在某个地方,而不需要任何额外的努力(因为我不在乎在凌晨 3 点记录实验),从 bash 文件运行所有实验(并不断注释掉以前运行的实验)。
这也让你可以自由地输入关于这些实验的任何注释或评论。您可以对某些超参数的不同值进行循环,以便一次运行多个实验。如果你的组织使用像 Slurm (像 mine )这样的工作量管理器,那么遵循这种技术也更有意义。
Experiment Logging
我知道有很多令人惊讶的工具专门用来管理这个,比如神圣,但是我更喜欢坚持老派的日志风格。
这些是我每天为了让生活变得更轻松而练习的一些事情。如果你认为这些是次优的,或者你有其他的锦囊妙计,让我知道,我很乐意学习:)
这是我很长一段时间以来的第一篇文章,也是机器学习领域的第一篇文章,我已经为此工作了一段时间。我计划分享我正在学习的和到目前为止学到的东西。反馈将有助于提高未来内容的质量。
曼加甘
教电脑用漫画绘制新的和原创的漫画和动画脸
Manga and anime faces generated with a model trained for 100 epochs
漫画和动画因其复杂的艺术风格和引人入胜的故事而受到全世界的赞赏。这个游戏的粉丝群是如此庞大,以至于有成千上万的艺术家在那里绘制原创漫画和动漫角色,也有成千上万的人想要创造它们。然而,绘画需要大量的时间、努力、技巧和创造力。生成漫画和动画角色可以帮助弥补技能差距,并提供创造自定义角色的机会。我最终想实现我自己的 GAN 来绘制行业标准的漫画和动漫人物,但为了这个项目的目的,我想学习更多关于 GAN 的知识,并挑战自己绘制出我能做到的最佳质量的图像,因为现实中人类会接触到许多折衷的风格。
Real samples, some containing false positives before data cleaning
视频游戏行业是第一个开始认真试验使用人工智能生成原始内容的娱乐领域。除了目前计算机游戏和机器学习之间的重叠,鉴于现代 AAA 视频游戏的 3 亿多美元预算,投资视频游戏开发自动化肯定有巨大的成本激励。
数据准备
用大约 143,000 幅图像的数据集来训练这些图像。众所周知,要生成符合行业标准的图像,高质量的图像数据集即使不是最重要的,也是必不可少的。使用的图像是从 Danbooru 抓取的——一个图像板,可以访问大量足够的图像来训练图像生成模型。这些图像板允许上传风格、领域和质量高度不同的图像,并认为这是真人面部和动漫人物面部之间质量差距的重要部分。图像的质量如此多样化,以至于它们可以是抽象的,所以我希望通过产生具有独特风格的更清晰的数据集来继续这个项目。
抓取图像后,我用[python-animeface](https://github.com/nya3jp/python-animeface)
来裁剪图像。这个图像级联专门用于检测动画和漫画的人脸,也同样适用。这个过程是多线程的,有 12 个池,但下面是每个映像的基本情况:
import animeface
from PIL import Image
img = Image.open('data/anime_image_usagi_tsukino.png')
faces = animeface.detect(img)
x,y,w,h = faces[0].face.pos
img = img.crop((x,y,x+w,y+h))
img.show()
我手动检查误报,因为一些图像。我最终消除了 3%的误报。
使用深度卷积生成对抗网络(DCGAN)的目标
人工智能研究人员到底为什么要构建复杂的系统来生成看起来有点不靠谱的卡通人脸图片?
这件事很酷的一点是,它需要理解这些图片才能生成它们——就像艺术家在画一张脸之前需要理解它需要什么一样。
看这张照片:
An anime face. Specifically, Misty from Pokémon, whose one of my favorite anime characters.
对于那些看动漫的人来说,你会立刻知道这是一张动漫脸的图片——一张源自日本的艺术风格的卡通脸。对计算机来说,这只是一个代表像素颜色的数字网格。它不明白这应该是一张动漫脸,更不用说代表什么概念了。
如果我们向计算机展示数以千计的这些日本风格的卡通面孔,在看到这些图片后,计算机能够绘制原始的动漫面孔——包括不同发型、不同眼睛颜色、不同性别、不同视角的面孔,以至于艺术家可以要求它绘制特定类型的面孔,例如“留着蓝色短发、戴着眼镜、戴着猫耳朵、脸上带着微笑的漫画或动漫女孩。”
如果计算机能够用相应的面部特征绘制这些脸,这意味着它们知道如何在没有任何明确指示的情况下绘制新的角色(至少在儿童水平上)。
作为一名开发人员和艺术家,看到研究人员追求这一点是令人兴奋的。这些生成模型让计算机以一种可以转化为前所未见的概念的方式理解数据,而无需理解该概念的含义。我们仍然处于基于机器学习的生成模型的早期,它们的实际用途目前还很有限,但它们非常有趣。看看人工智能是否能为艺术或娱乐业做出贡献,这将是一件有趣的事情。
“我从认知系统中寻找的不仅仅是另一种形式的计算,而是在我们的生活中创造一种存在,并通过这种存在来激励我们。”
—IBM 沃森副总裁兼首席技术官罗布·海
模型是如何工作的?
DCGAN 由两个神经网络组成:一个生成器和一个鉴别器。这是一场看谁能胜过对方的战斗,结果是两个网络都变得更强大。
让我们假设第一个神经网络是一个首席动画师,他正在审查一部新动画的创意。为了防止诉讼,它被训练来识别在以前的展览或书籍中见过的图画。它的工作是观察面孔,看看是否有适合他们节目的新面孔。
一个卷积神经网络在这种情况下起作用,因为我们需要做的只是拆开一幅图像,将它分成几层并处理每一层,识别图像中的复杂特征,并输出一个值来指示图像中是否有真实的动漫脸。第一个网络是鉴别器:
Discriminator Network
接下来,让我们假设第二个网络是一个全新的动画师,他刚刚学会如何绘制新鲜的动画面孔,这样就不会有人因侵犯版权而被起诉。这位动画师将向一家大型动画公司的首席动画师推销一个新的创意。在第二个网络中,这些层被反转为正常的 ConvNet。这个网络不是像第一个网络那样拍一张照片输出一个值,而是取一个值的列表输出一张照片。
第二个网络是发生器:
Generator Network
现在,我们有了一个寻找重复使用的面孔的主动画师(T6 鉴别师),和一个绘制新面孔的新动画师(T8 生成器)。决斗的时候到了!
第一回合
生成器将绘制一个…有趣的动漫脸副本,它不像一个新的行业质量的脸,因为它不知道动漫脸看起来像什么:
The Generator makes the first (…interesting) manga/anime face
但是现在鉴别器在识别图画的工作上同样糟糕,所以它不会知道区别:
The Discriminator think’s it’s a fresh, industry quality face. Maybe for a YouTube show
现在我们必须告诉鉴别者,这实际上是一张不符合我们标准的脸。然后我们给它看一张真实完整的动漫脸,问它和假的有什么不同。鉴别器寻找新的细节来帮助它区分真假。
例如,鉴别者可能会注意到一张完整的动漫脸有一定的比例。利用这些知识,鉴别者学会了如何辨别真伪。它的工作变得更好了:
The Discriminator levels up! It now can spot very bad fake faces
第二轮
我们告诉生成器,它的动画和漫画图像突然被拒绝为假的,所以它需要加强它的游戏。我们还告诉它,鉴别器现在正在寻找人脸上的特定比例,因此混淆鉴别器的最佳方法是在人脸上绘制这些特征:
The Generator produces a slightly better drawn manga/anime face
假面又被认为是有效的了!现在鉴别者不得不再次看真实的脸,并找到一种新的方法来区分它和假的脸。
生成器和鉴别器之间的这种来回博弈会持续数千次,直到两个网络都成为专家。最终,发生器产生了新的、近乎完美的面孔,鉴别器变成了一个动漫鉴赏家和评论家,寻找最细微的错误。
当两个网络都经过足够的训练,使得人类对假图像印象深刻时,我们就可以将假图像用于任何目的。
结果
我在 100 个时代训练了我的网络,并设法绘制了一些具有独特风格的新面孔。我继续致力于我的实现,并计划用 DRAGAN 和不同的数据集进行实验,以提高生成的质量。
观察前四个时期,发生器的输出接近纯噪声。随着发电机学会做得更好,新面孔慢慢开始成形:
随着训练的深入,生成器会给每个角色画出更均匀的比例。下面是使用 IPython 和经过训练的模型生成的一些结果:
Image interpolation by changing the latent z vector
因为这些图片都有自己的标签,所以在运行网络时记住特定的属性会很有趣。我用不同的头发颜色作为参数再次运行了网络。这一次,鉴别器使用头发颜色来区分人脸,生成器在重新绘制人脸时会考虑到这一点:
Characters with green hair
Characters with blue hair
Characters with blonde hair
结论
这是一个有趣的项目,到目前为止,我学到了很多关于训练甘以及如何优化他们。如果你想了解更多关于 GANs 以及如何训练它们,我强烈推荐你访问这篇文章来了解未来的技巧,因为它们对学习过程非常有帮助。训练 GANs 时,回流训练数据肯定是可能发生的事情。通过使用大量的训练数据集和较短的训练时间,有可能减少这种情况发生的几率。这是一个棘手的问题,对它的研究仍在继续,但希望这能成为建立干净数据集以产生高质量结果的动力。
这个项目绝不是提议取代努力工作的动画师和艺术家——这是一门非凡的艺术,这是为了纪念那些献身于掌握这门艺术的人。这是为了找到计算机不仅可以理解如此复杂的概念的方法,并希望激发所有层次的人欣赏艺术并为艺术做出贡献。我希望这个项目刺激更多关于漫画和动画风格图像的生成模型的研究,并最终帮助业余爱好者和专业人士设计和创造艺术,让尽可能多的人享受。
宣言:人类学习的时间到了
Alan Turing
半兽半机……美在哪里?
野兽是一种生物机器。那么有什么区别呢?
是什么让机器意识到自己?
是什么让我们成为人类?不是与其他动物相比,而是真正的人?
我们如何成为人类?人性是遗传的还是习得的?
人性能像童贞一样失去或像经验一样获得吗?
你觉得这些问题很蠢是因为我们默认是人类吗?
那些在奥斯威辛、布痕瓦尔德和达豪集中营烧死了数百万人的人类呢?
作为人类到底意味着什么?
似乎我们都知道答案,但是我们不能把这些知识用语言表达出来。
这是一种隐性知识,不是吗?
精神在哪里?灵魂是什么?
也许,做人终究是一种精神体验?
我们不能确定是否有任何东西存在于我们感觉的膜之外。然而,我们可以操纵我们的感觉,认为我们控制着自然法则或我们周围的神秘力量,或者两者兼而有之。
那么,人性就是傲慢和骄傲吗?我们在动物和机器中都找不到它们。
我们相信人性的意义不止于此。
也许,人性是从母亲抱着婴儿开始讲故事开始的。一个童话。婴儿感受到她温柔的触摸,听到她亲切关怀的声音……在睡眠和现实的边缘,婴儿的大脑开始在母亲大脑神经元跟随母亲说话的节奏放电的相同区域放电。人性的神奇火花闪现…
我们能量化人性吗?我们能评价它吗?
文明人比野蛮人更有人性吗?
一个连环杀手和一个无辜的孩子呢?
反社会者是人吗?
人性可以简化为自然法则吗?
如果我的脚后跟发痒,我可以选择挠它或者忽略它。我可以用我思想的纯粹力量来控制我身体的生物机器。据我所知,我的身体按照自然法则工作。因此,通过挠我的脚后跟,我用我思想的纯粹力量让自然法则服从我。
寻找人性的源泉就像追逐地平线:你走得越快,它跑得越快。
我们到底为什么要抓它?
如果我们相信人类不仅仅是智能生物机器,这是有原因的。
因为现在从自动驾驶汽车到智能城市等各种各样的例子中发展的人工智能不会自动变成人类。如果不知道是什么让我们成为人类,我们就有可能创造出一个超级聪明的反社会者。或者一群超级聪明,超级强大的反社会者。人工智能不需要一般才会变得危险。
我们也感觉到,我们周围越来越多的人正把他们的人性交给他们的兽性或机器起源。我们不知道是否有不寻常的事情正在发生,或者这只是一个正常的过程,但我们对它的反应也是正常的。我们希望让这些人变得更有人情味。我们希望能尽快完成,以免为时过晚。
我们挖掘人性第一原则的方式是通过在我们暂时称之为人性发展的领域中开发产品。
我们相信,神经科学家已经发现了一些最实用和有效的方法,通过这些方法,人类的记忆和检索在人脑中进行,并在它们之间转移。
我们也相信人工智能领域的科学家已经在机器学习算法中成功地重现了这些手段。
这些方法可能看起来太简单,甚至很原始,但科学证明它们确实有效。这些手段都是故事。问题是:哪些故事最适合学习人性?怎么才能挑对呢?
对童话和神话的比较系统发育研究,通过追溯从我们的时代到人们刚刚发现语言的时代的相同故事,为我们提供了上述问题的答案。
三条研究路线(神经科学+故事,人工智能+故事,系统发生学+故事)到目前为止基本上是平行的,现在是融合的时候了。作为一门学科,人性学习可能会出现。
自 2016 年 10 月以来,我们一直在秘密开发我们的项目。
是时候让我们走出来,开始建立一个由人工智能科学家、神经科学家、语言学家、游戏开发者、文学史家、电影制片人、作家、企业家组成的社区了——所有这些人都因为发现人类第一原则的热情而团结起来——此外,还因为真正希望为人类和机器提供令人信服的、高效的学习和重新学习人类的工具。
叶卡捷琳娜·马特斯克维奇
谢尔盖·奥尔洛夫斯基
伊万·苏希
流形学习:背后的理论
流形学习已经成为几何,尤其是微分几何在机器学习中的一个令人兴奋的应用。但是,我觉得算法背后有很多被忽略的理论,理解它将有助于更有效地应用算法( 见此 )。
我们将从什么是流形学习以及它在机器学习中的应用开始这个相当长的论述。流形学习仅仅是使用高维数据的几何属性来实现以下事情:
- 聚类:找到相似点的组。给定{X1,…,Xn},构造一个函数 f : X 到{1,…,k}。两个“接近”的点应该在同一个簇中。
- 降维:在低维空间中投影点,同时保留结构。给定 R^D 的{X1,…,Xn},构造一个函数 f : R^D 到 R^D,其中 d
- 半监督、监督:给定标记点和未标记点,建立一个标记函数。给定{(X1,Y1),…,(Xn,Yn)},建立 f : X 到 y。两个“接近”的点应该有相同的标签。
其中“接近”的概念使用数据的分布被进一步细化。有几个框架可以实现这一点:
- 概率观点:密度缩短了距离
- 聚类视点:连通区域中的点共享相同的属性
- 流形观点:距离应该“沿着”数据流形测量
- 混合版本:两个“接近的”点是那些通过穿过高密度区域的短路径连接的点
我们要讨论的第一个概念是拉普拉斯正则化,它可以在监督和半监督学习中用作正则化器,并通过投影到拉普拉斯的最后一个特征向量来进行降维。
让我们理解拉普拉斯在这个上下文中的意思。拉普拉斯仅仅是度矩阵(这是对每个顶点上有多少条边的度量)减去邻接矩阵(这是对各个顶点如何相互连接的度量)。现在我们已经准备好开始理解第一种方法:拉普拉斯正则化
拉普拉斯正则化
正则化在减少过度拟合和确保模型不会变得太复杂方面非常有用。使用拉普拉斯算子来正则化扩展了首先在吉洪诺夫正则化中使用的思想,吉洪诺夫正则化应用于再生核希尔伯特空间(RKHS)。
我们不需要深入 RKHS 的细微差别,但我们肯定需要了解的主要结果是,在 RKHS,对于函数空间 X 中的每个函数 X,在核中存在唯一的元素 K_x,它允许我们为每个函数定义一个范数||f||表示 RKHS 中函数的复杂性(机器学习情况下的学习映射函数),我们可以使用它来正则化算法。所以问题会变成
这种正则化叫做外在正则化。现在拉普拉斯正则化增加了另一个称为内在正则化的正则化,它考虑了流形的内在几何并使用它来正则化算法。如何定义正则化子有几种选择,但大多数定义都围绕着流形上的梯度。我们希望正则化器惩罚那些不必要的复杂函数(当数据密集时)。换句话说,我们希望函数在数据密集时是光滑的,这也意味着当数据的边际概率密度较大时,函数在流形上的梯度必须较小。这被形式化为
如果我们可以直接计算这个积分,那将是非常棒的,但与大多数机器学习概念一样,实现它需要使用可用数据进行某种形式的估计。在这种情况下,我们需要将数据点视为图上的点,并基于某种距离概念将它们连接起来。这通常是通过实现某个函数并施加一个条件来实现的,如果距离(使用该函数导出)小于某个特定值,则这两个点用一条边连接。一个这样的函数是标准高斯函数:
现在我们需要一个估计积分的方法。进行完整的推导会使这篇文章太长,所以我将概述涉及的主要思想:使用斯托克斯定理和拉普拉斯近似拉普拉斯-贝尔特拉米算子的事实,我们可以推导出大量数据点的积分的近似。因此,正则化可以估计为
其中 f 是数据处的函数的向量值,n 是数据点的数量(标记的和未标记的)。所以现在要解决的最后一个问题变成了
与其他核方法一样,主要缺点是希尔伯特空间可能是无限维的,如果正则化不能显式地找到,就不可能在空间中搜索解。因此,对正则化(严格单调递增的实值函数)施加某些条件,并使用著名的表示定理,我们可以将期望的函数分解成权重为α的有限维空间,使得
现在我们只需要在有限维空间中搜索α的值来求解我们想要的函数。
与 L1 或 L2 正则化相比,这是一种更复杂的正则化,但它与数据的几何关系非常密切,这似乎有助于确保模型不会过度拟合。
拉普拉斯特征映射
拉普拉斯特征映射使用与上述正则化类似的推理,只是它应用于维数减少而不是正则化。我们首先生成一个图,图中的顶点是数据点,并且连接了相距特定距离(准确地说是欧几里得距离)且距离较小的点。然后添加权重,通常是根据热核。最后,计算特征值和特征向量,并且使用最小的特征向量将数据空间嵌入到 m 维空间。形式上,
解决这个特征向量问题
现在,我们可以将数据投影到前 m 个特征向量 f1…fm 上,从而有效地降低数据的维数。
结论
概括地说,我们介绍了什么是流形学习,其中利用数据的几何来使算法更有效(通过减少过拟合或维数)。接下来,我们特别讨论了两个过程,拉普拉斯正则化和拉普拉斯特征映射。它们都基于图论和微分几何,理解它们背后的理论将有助于了解何时部署哪个过程以及某些数据结构如何影响这些过程的效率。
带 TensorFlow 的手动回推:解耦递归神经网络,从 Google Brain 修改 NN,用交互代码实现。
Photo from Pixel Bay
我喜欢 Tensorflow 及其执行自动微分的能力,但这并不意味着我们不能执行手动反向传播,即使在 Tensorflow 中。对我来说,建立一个神经网络也是一种艺术形式,我想掌握它的每一个部分。所以今天,我将在 TensorFlow 中使用手动反向传播实现简单分类任务的解耦 RNN。并与自动微分模型进行了性能比较。
解耦神经网络最初是在本文中介绍的使用合成梯度解耦神经接口请阅读。我还在解耦的 RNN 上实现了 Numpy 版本的。
最后,请注意这篇文章,我将更加关注 Tensorflow 的实现与 Numpy 的实现有何不同。并说明我喜欢 Tensorflow 实现的原因。
网络架构/前馈/反馈传播
如上所述,网络架构与 RNN 的 Numpy 版本以及前馈/反馈传播操作完全相同。所以我就不深入了。
数据准备\超参数声明
同样,我们将仅对 0 和 1 图像执行简单的分类任务。没什么特别的,但是请看屏幕截图的最后一行,我们正在创建我们的默认图,以便首先制作网络图和训练。(绿色方框区域)
原因一:数学方程实现
Numpy 版本和 TF 版本之间的一个关键区别是每个等式是如何实现的。例如,下面是我如何在 Numpy 中实现 Tanh()的导数。
def d_tanh(x):
return 1 - np.tanh(x) ** 2
然而,在 Tensorflow 中,我会像下面这样实现它。
def d_tf_tanh(x):
return tf.subtract(tf.constant(1.0),tf.square(tf.tanh(x)))
乍一看,这可能有点奇怪,但我个人更喜欢张量流的数学符号,主要原因是它让你在实现每个方程之前真正思考。
原因 2:迫使你思考独立的组件是如何组合在一起的。
Hyper Parameter Declaration Part
以上只是声明权重和学习率的部分,仅此而已。张量流迫使你专注于每个部分。
Network Architecture
以上部分迫使我思考网络架构,它让我专注于每一层。并让我思考我添加到网络中的每一层的效果。比如这一层会有怎样的整体效果?如何执行反向传播??这是这层的最佳选择吗?
最后,以上是培训部分,在这一部分,我可以专注于培训我的网络。我被迫只考虑我的训练的批量大小以及许多其他事情,只与训练有关。
原因 3:自动微分之间的切换和比较
如上所述,在声明成本函数的同时,我也可以声明优化方法。所以现在我可以自由地使用自动微分或手动反向传播。
我可以只注释掉输出的一部分,而不注释另一部分。
训练与结果:人工反向传播。
左图是每个训练循环的成本,右图是 20 个测试集图像的结果。现在让我们看看自动微分的结果。
训练和结果:自动分化。
我用的是学习率为 0.1 的随机梯度下降。就速度而言,它快得惊人。我认为代码首先被编译,也许这就是原因。然而,我很监督,它没有做好测试图像。
交互代码
我转移到 Google Colab 获取交互代码!所以你需要一个谷歌帐户来查看代码,你也不能在谷歌实验室运行只读脚本,所以在你的操场上做一个副本。最后,我永远不会请求允许访问你在 Google Drive 上的文件,仅供参考。编码快乐!
要访问交互代码,请点击此链接。
遗言
尽管我很喜欢 tensorflow 的自动微分功能,但我认为仅仅依靠框架来训练模型并不是一个好主意。对我来说,建立神经网络是一种艺术形式,我想掌握它的每一个部分。
如果发现任何错误,请发电子邮件到 jae.duk.seo@gmail.com 找我。
与此同时,请在我的 twitter 这里关注我,并访问我的网站,或我的 Youtube 频道了解更多内容。如果你感兴趣,我也在这里做了解耦神经网络的比较。
参考文献
- 贾德伯格,m .,Czarnecki,W. M .,奥辛德罗,s .,维尼亚尔斯,o .,格雷夫斯,a .,& Kavukcuoglu,K. (2016)。使用合成梯度的去耦神经接口。 arXiv 预印本 arXiv:1608.05343 。
- Seo,J. D. (2018 年 02 月 03 日)。Only Numpy:解耦递归神经网络,修改自 Google Brain 的 NN,实现用…2018 年 2 月 05 日检索自https://medium . com/swlh/only-Numpy-Decoupled-Recurrent-Neural-Network-modified-NN-from-Google-Brain-Implementation-with-7f 328 e 7899 e 6
- 阿洛尼博士(未注明)。丹·阿洛尼的博客。检索于 2018 年 2 月 5 日,来自 http://blog.aloni.org/posts/backprop-with-tensorflow/
多种语言的多种模型
寻找最佳日常数据科学工具之旅。
Be fast, avoid the pitfalls I found! Or try them out anyway.
在过去的几年里,我一直在研究数据科学方法,试图学习机器学习以及如何有效地自动化自己。到目前为止,我在最后一点上还是非常失败,因为你变得越有效率,给你的工作就越多。但是,我没有把这些知识藏起来,而是分享一些,希望它能帮助你或世界上的其他人。
我仍在纠结的一件事是,我的任务应该使用哪种编程语言?也许你面临着同样的挣扎,或者也许你已经想出了你最喜欢的语言?就我个人而言,在这个星球上的学术生涯中,我是伴随着 c/c++和 Matlab 长大的,但我得到的印象是,你不再属于拥有这种特殊技能的“酷人”了。此外,我在工作中接触到许多语言,所以现在是时候提高我的知识了。
实验装置
在偶然发现了多模型范式,也被称为拆分-应用-组合之后,我意识到这就是我每天在工作中所做的事情。因此,我已经开始确定哪种语言最适合这个特定的任务。
首先,用半随机生成的数据创建一个数据集,这可能类似于我每天处理的数据。数据集足够大,以至于当你做错的时候会明显地减慢计算速度。我已经把数据和结果放到了一个 github repo 中。我不会深入建模细节,但本质上我只是想要计算数据中许多组的多元回归的残差。
这相当复杂,所以让我们来看看我的代码需求:
- 应该是快!计算时间很少,不允许喝咖啡。
- 应该是容易写!节省你,人类,大量的时间。
- 理想情况下,它看起来优雅易读。这完全是一个有待讨论的问题。
接下来,我将比较这些语言中的多种实现:
- Matlab (我的专长,但专有)
- Python (全才)
- R (数据科学爱好者)
- 朱丽娅(新来的,承诺速度!)
另外,我也在比较不同的概念:
- 使用现成的建模包 vs. 手写的线性代数。
- 自动分割应用方法(在数据帧上)与手动编写循环(在数组上)。
搜索解空间
The timing results of all the various solutions I tried so far.
各种尝试之间的执行时间存在巨大差异。特别是在 Matlab 中,你可能会失败得很惨,这经常发生在没有经验的用户身上,进一步增加了它糟糕的声誉。然而,通过一些好的选择,你可以在 Matlab 中做得很好。
这篇文章的灵感,Hadley Wickam 的 tidyverse 解决方案,在他的书 R for Data Science 中详述,也做得不太好。我是 tidyverse 哲学的忠实粉丝,尤其是用于可视化的 ggplot,但显然不应该因为它的计算效率而选择它。
非常有效的方法是自己写出模型的线性代数,以及一个允许你自动进行分割应用的包。最终,data.table 包和一个矩阵 QR 求解器一起胜出。然而,正如一位同事急切指出的,这本质上是对核心 c/c++代码的包装。因此,也许并不是真正的 R 语言赢了。
我还想回到 Julia,它保证了开发的速度和简易性。它还没有打败 data.table,但是我只需要两次简单的尝试就可以让它表现出色!
最后,还有 Python。我最不喜欢这种语言,这可能解释了为什么我不能让它像其他语言一样在 1 秒内运行。如果你知道谁愿意帮助我,我将不胜感激!
最后,现成的 dataframe 方法通常优于跨阵列的初始 for 循环。如果付出额外的努力,后一种方法可以达到类似甚至更好的性能,但几乎没有回报。另一方面,编写自己的模型显然有助于缩短执行时间,因为上图中所有缓慢的解决方案都使用了通用的建模包。除非速度不成问题,否则我建议定制型号。
诗歌
Comparing the results of my favorite attempts in each language
在编写所有这些脚本和函数的时候,我想用另一种语言一遍又一遍地写同一首诗。每种语言的语法可能看起来不同,但总体概念是完全相同的。在这里,我想向您展示我最喜欢的解决方案的美妙之处。
在定义了残差计算函数之后,一切都在名为*df*
*、*的数据帧(或表格)上运行,该数据帧包含两个组索引、两个预测器*A*
和*B*
以及一个估计器*Z*
。对你们中的一些人来说,下面显示的片段是微不足道的,对其他人来说,它们可能看起来像黑色的魔法咒语。
我不会在所有语言中展示建模函数,但正如下面 R 中的代码示例所示,这几乎不比通过residuals(lm(Z ~ poly(A,B,degree=3))
调用一般的线性建模函数lm
更费力,但速度却快了 10 倍:
calc_poly_residuals <- function(A,B,Z) {
# construct the model matrix
M <- cbind(A*0+1, A, B, A*B, A^2, A^2*B, B^2, A*B^2, A^3, B^3)
# calculate residuals after solving M*c = Z
resid <- Z - M %*% solve(qr(M, LAPACK = TRUE), Z)
}
稀有
下面是 R data.table 解决方案。简短、抽象、快速:
df[,resid:=calc_poly_residuals(A,B,Z), by=.(num_group,cat_group)]
朱莉娅
Julia 解决方案只需要多一点代码:
by(df,[:num_group,:cat_group],df -> DataFrame(resid = calc_poly_residuals(df)))
计算机编程语言
显然,Python 更喜欢面向对象的语法:
df_grouped = df.groupby(['cat_group', 'num_group'])
resid = df_grouped.apply(calc_poly_residuals)
矩阵实验室
Matlab 喜欢在函数调用中使用单独的数组:
G = findgroups(df.num_group,df.cat_group);
resid = splitapply(@calc_poly_residuals,df.A,df.B,df.Z,G);
结论
首先,尝试所有这些语言和概念对我的学习很有帮助。虽然我仍然不知道我更喜欢用哪种语言来执行这些模型,但是现在我已经可以使用它们了。当我与我的雇主的其他数据科学团队互动时,这很方便,他们都有自己喜欢的。
相当惊人的是,手工制作自己的模型或算法回报显著!另一方面,您可以将数据处理留给外部包。这很符合我自己的喜好;忽略数据管理,深入思考算法和见解。
将太阳系映射到你附近的某个地方——这是一个 NatGeo 的火星启发的闪亮网络应用程序
我最近晋升为父亲。这就是为什么我目前正在休 5 个月的育儿假(感谢出色的团队@ store2be 的配合!).每天早上 5 点左右,我和儿子一起离开卧室去厨房,这样他的妈妈就可以睡上两个小时。正是在这些清晨时分,我最近在网飞观看了国家地理研究所的火星,这启发了我一个小的“数据科学”项目。
沙漠中真实比例的太阳系
在《火星救援》第一季的前几集里,年轻的本·索耶(Ben Sawyer)——注定要去火星的宇航员之一——和他的父亲一起走进沙漠,把弹珠放在棍子上,这样弹珠的大小就会和我们太阳系中行星的大小相匹配,它们之间的距离就会和相同比例的行星之间的距离相匹配。
The Earth the size of a marble. Source: National Geographic (2016).
这启发我开始了一个项目,用 R 构建一个闪亮的 web 应用程序,让我将太阳系映射到给定位置周围的真实世界。也许有一天,我会和我的儿子一起讲述本·索耶和他父亲的故事(如果他对这种事情感兴趣的话)。
表面上看,这很容易做到。只要“获得太阳系的鸟瞰图”并缩小距离和尺寸。但是等等——行星在移动。太阳系的鸟瞰图到底会是什么样子?
我最初的计划是:
- 在某个坐标系中找到一个行星的 x-y 坐标数据集,该坐标系确实以这种方式存在,并且
- 将这些 x-y 坐标转换成纬度和经度测量值,以将行星的坐标映射到地球上的某个区域。
空间坐标系统
在谷歌搜索了一番后,我偶然发现了美国国家航空航天局的数据。它提供了从 1959 年到 2019 年我们太阳系中行星的位置。这取决于你选择的坐标系:
- 太阳黄道
- 日光惯性
- 太阳黄道图和日光图
当然可以。里面没有 x 或 y。只是一些介于 0 和 360 之间的纬度/经度变量。也许这和半径上的度数有关?所以我去试着理解这些坐标系到底是什么。这里没有速赢。
(太阳)黄道坐标系
A visualisation of the Earth ecliptic coordinate system.
多亏了维基百科,我了解到黄道坐标系可以有它的*“原点[……]可以是太阳或地球的中心,它的主要方向是朝向春分点(北分点),它有一个右手惯例。”*对于包括我在内的我们这些不知道“春分(北)点”是什么意思的人来说,春分是指人们可以想象的穿过地球赤道的平面在春天穿过太阳中心的时刻(记住,地球的轴是向着太阳倾斜的)。这种情况在九月再次发生,然后被称为南分日。这张来自维基百科的图片让我明白了一些事情:
日光惯性坐标系
这是一个坐标系统,基本上就像我们在地球上的经纬度系统,但映射到太阳上。如果你对阅读更多感兴趣,你可以从 NASA 这里或者这里找到信息。我很快放弃了使用它(因为我不能足够快地理解它),但也可以随意探索它。
月亮太阳 R 包
在读入任何数据之前,我决定至少快速检查一下是否有任何 R 包可用于行星绘图。幸运的是,原来有一个,Lukasz Komsta 的叫做 moonsun 。答对了。
在最初走进一条死胡同之后(见摘录),它证明允许我做我想做的事情,为我提供所有太阳系行星在地球黄道坐标中的经度数据,并基于给定的日期,以及行星的距离。因为计划是将行星映射到一个平坦的球面上,所以我忽略了行星黄道坐标中的纬度。
这样,我就拥有了绘制所有八大行星,加上冥王星和太阳的位置所需的一切。
#Getting ecliptic latitude and longitude coordinates from a call to the planets() function in the moonsun package and its outputplanets_today <- data.frame(
as.ecc(planets(show.moon = FALSE)),
dist = planets(show.moon = FALSE)$dist
)planets_today#Output:
# long lat dist
# 2018-11-24-Sun 241* 41' 2'' 0* 0' 0'' 0.99
# 2018-11-24-Mercury 247* 55' 57'' -1* 54' 26'' 0.69
# 2018-11-24-Venus 205* 59' 15'' 0* 12' 2'' 0.37
# 2018-11-24-Mars 333* 46' 13'' -2* 35' 33'' 0.97
# 2018-11-24-Jupiter 242* 51' 16'' 0* 39' 57'' 6.35
# 2018-11-24-Saturn 276* 35' 28'' 0* 32' 55'' 10.87
# 2018-11-24-Uranus 29* 49' 35'' -1* 27' 12'' 19.05
# 2018-11-24-Neptune 342* 42' 11'' -1* 1' 54'' 29.77
# 2018-11-24-Pluto 280* 46' 14'' 2* 28' 57'' 33.38
将行星的坐标映射到地球表面
现在,基于角度方向和距离测量,目标是找到行星在地球上的位置坐标,给定某种比例因子。为了做到这一点,我偶然发现了 geosphere 包,其中就包含了这样一个功能。
destpoint()函数将起始位置、以北纬 0 度为参考的方向角和以米为单位的距离作为输入,并返回您将到达的坐标。瞧啊。
#Pick the location of Earth as a starting point, e.g. the Mojave desert
startingLocationLng <- -115.7863069
startingLocationLat <- 35.0992539#Get angles between Earth and the planets as seen from a top-down-view from the ecliptic north to south pole
planetsAngles <- (-1) * (as.numeric(as.ecc(planets(show.moon = FALSE))$lat) - 360)#Get the distances (in AU and converted to 1 AU = 1,000 m)
planetsDistances <- planets(show.moon = FALSE)$dist * 1000newCoords <- **destPoint**(c(startingLocationLng, startingLocationLat), planetsAngles, planetsDistances)
太阳系绘图应用程序
有了可用的核心组件,所有需要做的就是使用 R 和 RStudio 将这些东西编织在一个基本的闪亮的 web 应用程序中。最终应用的截图可以在下面看到。
The Solar System Mapper web application, built with R & Shiny.
该应用程序提供以下功能:
- 设置观察的日期
- 选择地球的位置
- 选择将天体距离转换为地球距离的比例
基于这些输入,它将计算天体在地图上的位置。它还将为您提供“原始”数据(如坐标和行星大小,单位为厘米),您需要这些数据才能像本·索耶和他的父亲一样真正走进这个世界。
*有趣的补充说明:*根据本·索耶和他爸爸在电视上的模型中使用的地球和土星的大小,我的应用程序告诉我,他们需要从地球开车大约 2 公里到土星,并应用 1 AU = 0.18 公里的比例。这是基于假设他们的地球直径约为 1.53 厘米,土星直径约为 14.50 厘米。作为日期,我选择了 2016 年 11 月 21 日,这一集在 2016 年首次播出。
【https://pdwarf.shinyapps.io/solar-system-mapper/】自己动手试试这个应用吧
此处 代码可通过 GitHub 获得。
剪辑
由于这个项目对我来说首先是一次学习之旅,我认为看着包括一些我走过的非常死胡同的实际过程是很有趣的。在这个项目的过程中,我总共经历了两次真正错误的转弯:
转错#1:曲解水平坐标系
在月亮太阳 R 包的文档中,我看到它可以让你将坐标转换成水平坐标。我(也)简单地阅读了一下,认为我已经找到了我所需要的。这一次,维基百科不是我最好的来源。我完全误读了你在下面看到的图像。对我来说,那时候,图像看起来就像黄道坐标系后来变成的样子。我想我把图像中的地平线误认为地球的赤道。
我想我可以只使用方位角和距离,并且可以用我后来使用黄道经度变量的方式。所以我开始编写一个函数,将方位角和距离转换成平面上的 x-y 坐标。这个函数是这样工作的:
AzimuthToXY <- function(azimuth, distance) {
if(azimuth > 0 && azimuth < 90) {
Y = sin(NISTdegTOradian(azimuth)) * distance
X = cos(NISTdegTOradian(azimuth)) * distance
}
else if(azimuth == 90) {
Y = distance
X = 0
}
else if(azimuth > 90 && azimuth < 180) {
Y = sin(NISTdegTOradian(azimuth - 90)) * distance
X = -1 * cos(NISTdegTOradian(azimuth - 90)) * distance
}
else if(azimuth == 180) {
Y = 0
X = distance
}
else if(azimuth > 180 && azimuth < 270) {
Y = -1 * sin(NISTdegTOradian(azimuth - 180)) * distance
X = -1 * cos(NISTdegTOradian(azimuth - 180)) * distance
}
else if(azimuth == 270) {
Y = -1 * distance
X = 0
}
else if(azimuth > 270 && azimuth < 360) {
Y = -1* sin(NISTdegTOradian(-1 * azimuth + 360)) * distance
X = cos(NISTdegTOradian(-1 * azimuth + 360)) * distance
}
else if(azimuth == 360 | azimuth == 0) {
Y = 0
X = distance
}
return(data.frame(X, Y))
}
但是当我绘制输出时(见下文),我感觉不太对劲,于是我又读了一些。最后,下面的图片,虽然没有维基百科上的漂亮,但更清晰,帮助我理清了事情。
The Horizontal coordinate system explained. Source: Swinburne University (2018).
如果你想知道在某个时间点从哪里观察天空来定位某个天体,水平坐标系是很有用的。它总是基于观测者在地球上的位置,而黄道坐标系是基于地球本身的。
错误转折#2:假设世界是平的
我在上面简要暗示了这个错误。基本上,我想我会在一个平面上得到一些 x-y 坐标,相对于地球所在的 0/0 点,然后把这个平面叠加到地图上。请参见下面的代码和示例输出:
coords <- map2_df(azimuth, distance, AzimuthToXY)plot(coords)
text(x = coords$X, y = coords$Y, labels = planetNames, pos = 1)
My first idea of plotting the planets to a flat Earth.
所以,在谷歌了如何从我的 azimuthytoxy()hustle 中获得目的地坐标之后,我偶然发现了这个 Stackoverflow 线程,标题为“*我如何才能从另一个纬度或经度中找到一个距离 X 的纬度或经度?”。*它以两种方式让我大开眼界:
- 世界不是平的,它是球形的!🤦
- 有一个叫做 geosphere 的包,它包含了一个函数,这个函数将使我在 AzimuthToXY()函数上的努力变得毫无用处。
正如你在上面的帖子中看到的,这就是我如何走上正轨的。多么有趣的项目——我确实学到了很多。也许这个应用在将来的某个时候会对我有用!
PS:这个项目也是约翰·霍普斯金大学 Coursera 上的在线课程 “开发数据产品”的一部分。我即将完成的是数据科学专业的 9/10 课程。一旦我 10 对 10,我将分享我的经历。
测绘挑战赛获胜解决方案
了解如何以惊人的精度在卫星图像上检测建筑物。开源实现的 DIY。由 neptune.ml 为您带来,与 deepsense.ai 一起赢得挑战并获得最佳社区贡献者奖🏆。
No cherry picked predictions. 1st column is input image; 2nd column is model’s prediction; 3rd column is model’s prediction superimposed on the input image; 4th column is ground truth superimposed on the input image. Each row is one example.
序言
卫星图像的深度学习越来越成为数据科学家的热门话题。卫星数据展示了在商业和研究领域的一些可能的应用。用例的范围从分类和本地化,到语义或实例分割。最后一个——实例分割——就是检测图像上的一个对象类,然后分割该对象的每个实例(想想:选择图像上的所有猫)。
这篇文章是关于实例分段挑战的获胜解决方案,称为映射挑战🌐在 crowdAI 和 Humanity & Inclusion 的主持下。在这里,我将分享我们的过程,工作方式,解决方案的内部和最终结果。关于技术栈也不会说太多😉
Project dashboard — we were rather busy with our experiments 😃
为什么重要?
卫星图像提供了高质量的地球表面概览。这些数据可以用于公共利益。一个例子是研究项目:“ 结合卫星图像和机器学习预测贫困 ”。来自斯坦福大学和美国国家经济研究局的研究人员使用深度学习方法(特别是迁移学习技术和 VGG 网络架构)来估计发展中国家一些国家的家庭消费和资产。
另一个例子是支持应对人道主义危机或自然灾害。地图挑战赛如何为这一目标做出贡献?
我们正处于一个人道主义危机在规模和数量上都日益增加的时期(……)。通常,准确的地图要么不存在,要么因灾难或冲突而过时。*
尽管它们很重要,但新地图是手工绘制的,因此迫切需要自动化方法来帮助生成准确的实时地图。因此,竞赛的意义可以简单概括如下:
世界上许多地方还没有绘制成地图;尤其是(……)那些最容易遭受自然灾害的人。获得这些潜在危机区域的地图极大地提高了应急(……)行动者的反应能力。*
数据科学家可以实现这一挑战的实际目标是:
(…)探索机器学习如何为自动分析卫星图像以生成(…)地图铺平道路。*
( 2018-09-12 从* 比赛页面 )检索的所有报价
关于比赛的几句话
Example input images
如果你想参加围绕开放数据组织的机器学习挑战,只需前往crowdAI.org并挑选你最喜欢的。前段时间,2018 年 4 月初,我们被贴图挑战赛所吸引。我们专注于基于图像的机器学习,在此之前,我们参加了数据科学碗 2018 ,在那里我们主要与 U-Net 和 Mask R-CNN 架构合作。在 DSB 2018 期间,我们开发了高度可参数化的 U-Net 的干净实现。这个比赛也是关于分割的,但是在这里,我们使用卫星图像,而不是显微镜图像。出于以下几个原因,我们决定参加地图挑战赛:
- 探索机器学习竞赛的新平台。我们都很了解卡格尔,但是克劳代和 T21 有不同的形象。
- 为更广泛的公众利益贡献我们的一份力量(参见:为什么重要?)。
- 通过定制编码器、多路输出和其他修改,进一步改进 U-Net 实施。
- 扩展我们的开放数据科学项目组合。
团队—数据科学四重奏
数据科学四重奏参加了比赛,分别是:雅各布·查孔、卡米尔·卡什马雷克、安杰伊·皮斯基尔、彼得·塔拉谢维奇(字母顺序)。由于这是整个团队的工作,因此,为了简单起见,我将把进一步的成就提到整个团队,而不是任何特定的人。在这里, neptune.ml 我们坚信,没有强大的团队合作,这一成功是不可能的。我们的 4 人团队,就像四人组(GoF——这四位作者因他们的设计模式书而出名),由热衷于机器学习的爱好者组成。我们来自两家公司:Jakub 和 Kamil 来自 neptune.ml ,Andrzej 和 Piotr 来自 deepsense.ai —机器学习和 ai 咨询公司。
我们是如何工作的?我们是如何设计流程的?
我们有定期的每周计划会议(报告进展和讨论未来的方向),每天的站立会议(让每个人都知道最新的工作),松散的沟通渠道,用于特别的对话和直接在代码中请求评论(当然还有代码审查)😄).
在参加挑战之前,我们有一些原则,我们渴望在我们追求的任何项目中实现。
干净代码 —我们认为单项比赛只是迈向更大目标的一步。因此,我们不会为了在竞争中立于不败之地而牺牲工程质量。具有良好接口的设计良好的实现将在未来的竞争和商业数据科学项目中获得回报。
️team 工作 —根据定义,数据科学项目是团队工作。不断重复新想法(有些效果很好,有些则不太好)的顺利进展是我们在此次竞赛中获得第一名的关键因素之一。任何人都可以提出想法,选择她最喜欢的任务,并思考他们对项目的贡献。这种开放的环境对我们的成功至关重要。
快速实验 —多亏了清洁解决方案开发流程,我们能够顺利地重复想法。从第一天开始,所有实验都在我们的数据科学项目平台 neptune.ml 上运行。与实验相关的所有工件都放在一个地方:结果、输出、保存的模型、代码、图表、超参数——非常方便,并且创建了一个比较结果和查看彼此工作的公共场所。这变得很方便,因为实验的数量很快就超过了 100 次(到目前为止,我们已经进行了超过 1000 次实验,这些实验都是公开的😎).
Single experiment with three interactive charts displayed.
公开分享 — neptune.ml 团队有远见地公开并展示与数据科学项目相关的整个过程。这就是为什么 code base 从第一天起就是开源的。每个人都可以观察它是如何增长的,何时开发新的模型,以及我们如何建立例程来有效地处理竞争数据。这是一个相当大的挑战,因为图像的数量:训练中有 280741 张,验证中有 60317 张,测试集中有 60697 张。此外,每个人都可以观察我们在海王星上运行的实验,浏览图表和结果。最后,我们让每个人都复制我们的结果,因为我们共享完整的信息和指导。我们将我们的想法命名为开放解决方案。
从事数据科学项目的实用建议
在这里,我们从团队的角度分享了哪些工作做得很好,以及我们在当前挑战 ( 查看“成功解决方案描述”部分)中继续做的事情:
- 选择所有实验工件的单一平台(保存的模型、代码、结果、超参数)。当事情变得复杂时,这会节省你大量的时间😉).
neptune.ml dashboard, where we keep all experiments. Notice competition metrics, Precision and Recall in the middle (two green columns).
- 安排每周计划会议以报告进展并讨论两个主题:接下来做什么(接下来 7 天的行动)和想法。我们的 deepsense.ai 团队成员带来了许多关于损失功能和架构设计的技巧,这是讨论它们的合适场所。
- 为每日同步安排固定时间——15 分钟。这将让每个人都知道现在正在处理什么。
- 把所有的任务和问题放在同一个地方比如 GitHub issues 和 boards 或者 trello boards 和 cards。这应该由团队领导策划,由团队中的每个人维护。
- 每个团队成员都在 git 分支工作。一旦完成任务,她就向发布开发分支发布拉请求。一旦增量解决方案完成,发布开发分支将被合并到主开发分支。千万不要碰 master,除非是发布开发分公司的 PR。这确保您在 master 上对您的问题有增量解决方案。它还允许您跟踪项目历史。
- 实施对等代码审查。团队得到了关于软件工程的一般教育,特别是关于彼此的工作风格。
技术堆栈
硬件
在硬件层面,我们在普通笔记本电脑上开发代码,或者在云中训练模型( neptune.ml 处理与谷歌云平台的通信。用户可以选择她最喜欢的 GCP 机器,配备英伟达 K80 或 P100 GPU)或本地的英伟达 GeForce GTX 1070 GPU。在后一种情况下,我们使用 neptune.ml 来监控我们在本地计算的实验(参见下面的章节*“Neptune . ml”*了解更多细节)。
软件
我们使用 Python 3.5,这是我们技术堆栈中最基本的部分。我们可以区分几个逻辑层,这将在下一节中描述。
Python 包(有些是特定于项目的)
在顶部,我们有一些 Python 包,我们每天使用它们来简化数据科学中的常见任务。下面列出了最重要的,并简单说明了为什么它们很重要😉。
- py torch(v 0 . 3 . 1)。我们发现在 PyTorch 中开发深度模型既简单又直观。我们知道有很多博客文章和会议讨论比较了 Keras 和 PyTorch 。我们选择 PyTorch 是因为用户可以直观地开发定制架构。
- ImgAug —用于图像增强,因为它提供了简单的 API 和大量的增强。看看我们对 ImgAug 的使用: augmentation.py 。
- 具体来说,在这次挑战中,我们与 pycocotools 合作,计算竞争指标。
- scikit_image、opencv_python 和 imageio,用于对图像进行操作。
(所有需求都在我们的资源库中requirements . txt)
Steppy 和 steppy-toolkit
Final solution pipeline developed using steppy.
在赢得地图挑战赛之前,我们的团队参加了比赛和商业项目。当时很明显,需要一些简单和干净的接口来构建复杂的机器学习管道。 Steppy 是一个轻量级的 Python 库,支持干净的机器学习流水线设计。它是海王星平台的补充,但在技术上是 100%独立的。 Steppy-toolkit 反过来是一套精心策划的变形金刚,让你的 Steppy 工作更快更有效。
它是一个社区友好的平台,支持数据科学家创建和共享机器学习模型。Neptune 促进团队合作、基础设施管理、模型比较和可重复性。我们在 neptune.ml 上运行所有的实验,以确保我们能够重现它们,并在以后进行比较。Neptune 独立于上面提到的所有层,它只适用于任意的 Python 代码。
Mapping Challenge — neptune screen with project description, similar to GitHub README.md.
获奖解决方案描述
以上是联合 neptune.ml 和 deepsense.ai 对PyData Europe 2018(euro python 2018 的一部分)的贡献的标题,在这里我提出了我们的最佳实验实践。我们将地图挑战的解决方案作为一个用例,因为我们相信我们的想法值得传播(就像 TED 大会😉).值得注意的是,我们是在宣布获奖者之前做的,包括竞赛和社区贡献者两个类别😊。在这张海报中,我们从技术的角度全面概述了哪些方法行之有效。
Click on the poster for full size pdf file.
获胜网络是 U-Net 的兴奋剂*
*我第一次观察到这个术语是在 ods.ai 的 帖子里,他们在那里解释了他们对 DSB 18 的第一名解。
Unet 使用 Resnet34、Resnet101 和 Resnet152 作为编码器,其中 Resnet101 为我们提供了最佳结果。这种方法在 TernausNetV2 论文中有解释(我们的代码💻).也看看我们的可参数化的 U-Net 的实现(代码💻).
1st columns is input image; 2nd column is output from U-Net; 3rd column is prediction superimposed on the input image; 4th column is ground truth superimposed on input image.
损失函数
- 距离加权交叉熵在著名的 U-Net 论文(我们的代码中解释💻).强烈推荐阅读这篇论文😃
- 使用软骰子和距离加权交叉熵的线性组合(代码💻).
- 将由建筑物大小加权的分量(较小的建筑物具有较大的权重)添加到加权交叉熵,该加权交叉熵对属于小对象的像素的错误分类进行惩罚(代码💻).
实践中的损失函数——可视化
前面提到的三点产生了某种复杂的损失函数,因此可能很难理解它在实践中是如何工作的。下面是重量的可视化图,具体如下:
- 距离权重:高值对应于建筑物之间的像素。
- 尺寸权重:高值表示小建筑物(建筑物越小,颜色越深)。请注意,没有建筑物固定为黑色。
(对于两种重量:颜色越深表示数值越高)
1st column is input image, 2nd column is mask, 3rd column visualizes distances between buildings (darker color is higher value), 4th column visualizes weight assigned to the roof (smaller roofs are assigned higher values, background is fixed to black).
培养方案
当我们开始使用预训练的模型时,我们获得了最好的结果(平均精度和平均召回率)(这并不奇怪)。训练计划是这样进行的:
- 用预先训练的权重初始化模型。
- 使用
learning rate=1e-4
和dice weight=0.5
在数据集的 50k 个样本上进行训练。 - 用
learning rate=1e-4
和dice weight=0.5
在全数据集上训练。 - 用较小的
learning rate=1e-5
和dice weight=0.5
训练。 - 使用增加的
dice weight=5.0
进行训练,以使结果更加平稳。
为了方便起见,我们将所有的训练超参数放在一个配置文件中: neptune.yaml 。由于这种方法,我们总是有一个单一的位置,在那里我们可以立即对培训有一个高层次的概述。
资源
我收集了一些有用的链接,你可以在那里寻找进一步的信息。
- 实验连同输出文件、结果、图表和超参数。
- GitHub 上的代码
- PyData Europe 2018(euro python 2018 赛道)上展示的海报。
- 再现它! —也就是说明如何重现我们的结果,也就是训练模型,使您达到:
0.943 Average Precision
和0.954 Average Recall
。 - crowdAI 上的地图挑战赛页面。
承认
我们要感谢 crowdAI 平台和 Humanity & Inclusion 非营利组织的维护者组织和举办了这次挑战。特别感谢来自 crowdAI 的 Sharada Mohanty 在整个比赛过程中给予的大力支持👏。
我们感谢人工智能咨询公司 deepsense.ai 在整个比赛过程中给予的大力支持和建议。
我们要感谢欧洲数据科学协会( EuADS )对顶级社区贡献者奖的赞助。
最后,我们与每一个挑战竞争对手的地图击掌。因为你们,我们真的玩得很开心😄
摘要
映射挑战是一个图像分割挑战,参与者被挑战*“使用机器学习构建缺失的地图”。 neptune.ml 与 deepsense.ai 一起开发了获胜的解决方案,该解决方案从比赛的第一天就开始开源。这种开放性让我们获得了最佳社区贡献者奖*。我们的主要愿景是开放整个数据科学项目,即代码、任务、规划、实验结果以及机器学习项目中常见的所有内容。
现在怎么办?
测绘挑战还没有结束。我们将在🇮🇹.都灵举行的 IEEE 数据科学和高级分析国际会议上展示我们的解决方案除此之外,我们继续按照上面列出的原则参加机器学习竞赛(参见:一节:我们是如何工作的?我们是如何设计流程的?)。最近的一项活动是盐鉴定挑战,在那里我们进一步提高了我们的深度学习技能。
快乐训练🚀
请随时在评论中给出反馈或提出您的问题。