神奇动物和在哪里可以找到它们(在推特上)
Newt Scamander
从 1997 年第一本书发行到 2018 年最新的《神奇动物》电影,巫师世界一直是一个长期持续的趋势,吸引了许多千禧一代。这是过去二十年中最具影响力的现象之一,并吸引了大批追随者。然而,自从第二部《神奇动物》电影上映后,人们对这部电影的抵触情绪似乎比以往任何时候都多。这甚至导致粉丝群体中的一些人形成了反粉丝心态(加纳,2018 年),这意味着粉丝会因为不喜欢某个特定部分而与该部分脱离关系。
《神奇动物:格林德沃的罪行》并不是大规模系列电影中第一部受到强烈反对的电影,两年前《星球大战:最后的绝地武士》等其他著名电影也发生过这种情况。这被许多粉丝视为失败,这部电影在网上受到了来自评论家和粉丝的大量仇恨(福布斯,2018 & 快报,2018 ),然而当莫顿贝(2018) 在推特上进行的一项研究显示,只有 21.9%的评论是负面的。因此,问题来了,这是否会是《神奇动物》的相同场景,因为大多数人都与魔法世界系列有着密切的关系,我们想给我们的读者一个影迷对新电影的看法的总体概述(带有一些魔法视觉)。这篇文章是写给对世界上最大的球队和球迷之一感兴趣的普通读者的,也是写给球迷自己的。
这些年来,魔法世界的曝光率一直很高,可以说是一种持续的趋势。通过展示谷歌趋势,可以洞察到新系列与哈利波特系列相比有多受欢迎。尽管《神奇动物》也不差,但不用多久我们就会发现《哈利·波特》仍然比《神奇动物》更受欢迎。
Google Trends
值得一提的是,哈利波特自 1997 年以来一直在确立自己的地位,而《神奇动物》只是在 2016 年才上映,然而第一部电影上映时,第一部哈利波特电影就获得了大量的粉丝和金钱。所以,当宣布粉丝们将得到一部前传时,许多粉丝都很兴奋,因为这被视为他们对魔法世界的“延伸”,这也在票房报告中看到。
BOX Office Results Bar Chart
BOX Office Results Pie Chart
《神奇动物在哪里》比《阿兹卡班的囚徒》更受欢迎,这表明它肯定不是系列电影中收入最低的。然而,随着第二部电影在影院上映两个月,它的名声越来越差,收入也明显减少。这些新电影成为了评论家们的热门话题,比如《每日电讯报》(2016 年)、《T2》(2016 年)、《Buzzfeed》(2016 年)和《T4》(2016 年)、《福布斯》(2016 年),《福布斯》(2016 年),自从约翰尼·德普在 2016 年电影的结尾以格林德沃的身份意外亮相以来。关于约翰尼·德普的更多见解将在本文后面给出。
Tweet 1: Popular Negative Opinions
由于这些粉丝对《神奇动物》系列电影有着非常不同的看法,所以研究人员对这些粉丝喜欢或不喜欢这部电影的原因进行了描述。为了这项研究,我们求助于人人都爱过度分享的平台:Twitter。从第一批预告发布到电影停止在影院上映,每部电影有 250 条推文被分析。因此,导致《神奇动物在哪里》从 2016 年 6 月 1 日到 2017 年 4 月 30 日,以及《神奇动物:格林德沃的罪行》从 2018 年 11 月 1 日到 2019 年 1 月 7 日。
通过滚动这些推文,已经可以注意到负面评论围绕着电影中的演员和清晰的情节漏洞等主题,但是稍后我们将详细阐述这些主题,看看人们不喜欢第二部电影是否有特定的原因。
为了理清混乱(由 500 条推文组成),这些帖子被多次分成不同的类别,以简要概述 Twitter 上存在的积极和消极情绪。第一个主要类别由负面、正面或营销相关推文的数量决定,这导致了以下发现:
Fantastic Beasts 1 and Fantastic Beasts 2 Divide of Comments
在 500 条推文中,超过一半是营销相关的,准确地说是 251 条,这表明用于电影的标签高度商业化。其余的推文似乎对两部电影都非常积极,对第一部电影的负面评论很少(105 条评论中只有 2 条),对《格林德沃的罪行》电影的总评论中约有三分之一是负面的(144 条中有 35 条)。
然而,这些主要类别仍然没有给我们更多的信息为什么《格林德沃的罪行》被描述为“玷污了哈利波特遗产的电影”(2018 年福布斯)
所以,在看了一下非营销相关的推文后,可以看出 Twitter 上的粉丝似乎对电影的角色以及演员有很大的兴趣(无论是积极还是消极),并通过他们的语言,粉丝艺术和粉丝小说来表现这一点。一些剩余的推文还包括用户提到他们计划去看电影或只是看了电影,没有表达实际意见。这些推文被标记为电影体验,在做更多研究时没有被考虑在内。
Histogram Discussed Topics
Bar Chart Characters FB 1 & 2
我们将从推特上粉丝们最喜欢的角色开始。如上面的视频所示,粉丝们为《神奇动物在哪里》中的纽特·斯卡曼神魂颠倒。虽然,这并不令人惊讶,因为他是电影中的主要主角,他是第一个更有爱心和温柔的男性角色,加上他是赫奇帕奇的事实(而且,每个人都喜欢赫奇帕奇)。Twitter 上其他受欢迎的角色包括邓布利多(或者更确切地说是电影中没有他)和克雷登斯。所有这些男性角色也收到了相当多的粉丝艺术。
Tweet 2: Fan showing love towards Newt Scamander
在《格林德沃的罪行》中,聚光灯从纽特身上移开,影迷的新欢似乎已经转向电影的对手;格林德沃。这既是因为他成为了第二部电影的主角,也是格林德尔多夫妇中的一员,这也解释了为什么年轻的邓布利多(#Dumbledamn)经常在评论中被提及。尽管粉丝们仍然明显对两人之间缺乏浪漫感到失望(《卫报》,2018 )。
Tweet 3: Complaints about lack of Grindeldore
Tweet 4 : Support for Grindeldore
Pie Chart Characters FB 1 & 2
Twitter 上另一个激烈辩论的话题是电影的演员,尤其是因为围绕他们有很多问题。当看《神奇动物》系列第一部电影的推文时,只有两个演员和一个女演员被真正谈论过;雷德梅恩(纽特),德普(格林德沃)和苏多尔(奎尼)。在这些推文中值得注意的是,所有用户对电影明星都有积极的反应。
Actors mentioned in Tweets FB 1
Tweet 5: Fan showing love towards actors
然而,在第二部电影中,提到了更多的演员。这一次,扮演邓布利多的裘德洛和扮演克雷登斯的埃兹拉·米勒得到了他们应得的赞赏。
Actors mentioned in Tweets FB 2
除了约翰尼·德普,所有的演员都因为他们在电影中的表现而得到了赞扬。在提到他的 28 个帖子中,有 5 个是负面的。这些帖子都提到了他虐待前妻的指控,尽管其余 23 个正面帖子都为他辩护,或者只是说他们不关心他的个人生活,但确实喜欢他的表演。
Tweet 6 about the Johnny Depp situation
为了真正找出电影中令人喜爱或讨厌的地方,还根据对情节的评论对推文进行了分析。对于《神奇动物在哪里》,我们发现所有的评论都是正面的。然而,许多评论并没有提到他们为什么喜欢这部电影,只有 5 条评论具体说明了他们喜欢实际情节的什么,这些都与故事情节有着更黑暗的基调和只是“好”或者时间设置和使用的惊人视觉效果有关。
Infographic Plot FB 1
Tweet 7: Positive opinion about plot FB 1
对于《神奇动物:格林德沃的罪行》,意见似乎有所不同,仍然有对这部电影的喜爱(66%的评论仍然是积极的),然而粉丝们几乎没有表明他们为什么喜欢它。不喜欢这个情节的人(幸运的是)提到了原因,大多数评论都提到了故事情节不完整或不正确,这使得电影很难理解。这些结果已经表明了粉丝心态的分歧,以及基于他们是否喜欢《神奇动物》系列的问题,似乎出现了不同的亚文化。
Infographic Plot FB 2
Tweet 8: Negative opinion about plot FB 2
粉丝在 Twitter 上表达自己的另一种方式是发布粉丝艺术、粉丝理论和粉丝小说。《神奇动物在哪里》的 105 篇帖子中有 21 篇是粉丝创作的。帖子主要围绕格林德尔多夫妇(格林德尔沃德和邓布利多),纽特本人和纽特娜(纽特和蒂娜),在所有的粉丝艺术中,值得注意的是这对夫妇受到了全世界粉丝的喜爱,因为有些帖子甚至用泰语、俄语和日语发布。
Tweet 9 & 10: Japanese fan-art about Newtina and other Fantastic Beasts Characters
围绕第二部电影的推文包含了更多粉丝的创作,在 144 条帖子中,有 41 条包含了粉丝艺术和粉丝小说。几乎所有这些帖子都围绕着同一对夫妇和纽特·斯卡曼个人。
不同粉丝艺术的创作清楚地展示了粉丝们对特定角色组合的投入,这与魔法世界粉丝们多年来所做的事情非常吻合;如果他们不能获得足够的东西,他们会自己创造更多。
Tweet 11 & 12: Containing fan-art of the Grindeldore couple
Pie Chart Marketing Comments FB 1 & FB 2
在分析了 Twitter 之后,很明显,为电影制作的标签也被大量用于营销目的。既然魔法世界系列已经赚了数十亿美元,商业空间的出现也就不足为奇了。随着 500 条推文中有 251 条与营销相关,很明显越来越多的公司意识到这种神奇的特许经营是他们可以赚钱的东西。此外,还有官方粉丝网站,如 Pottermore 和 MuggleNet,它们主要由粉丝驱动,但仍然被视为中立和商业网站,因为它们为电影做了大量宣传。公司试图对这个市场产生重大影响,他们要么通过在推特上发布关于电影赠品或促销的消息,比如发布更多事实、演员活动、商品或票务网站链接。
Tweet 13: Give-away by popular account OriginalFunko
Tweet 14: Promotional post by the original Fantastic Beasts account
人们对神奇动物系列电影的最大问题之一是约翰尼·德普的选角,他是也是一个有争议的人物,因为他被前妻指控虐待,这受到了各种媒体的广泛批评(综艺,2018 & 卫报,2018 )。在续集中,约翰尼·德普出现得更多,在格林德沃的罪行被公布的时候,对话(或指控)再次被点燃。推特和媒体上对此的看法非常明显,许多粉丝对演员和 J.K .罗琳的选角感到愤怒。
Bar Chart #boycottjohnnydepp & #johnnydeppisinnocent
通过查看 Twitter 上最常用的标签来显示对这位演员的支持(# JohnnyDeppIsInnocent)或仇恨(#BoycottJohnnyDepp),我们看到平台上有一些非常直言不讳的用户。特别是在韩国,这位演员并不受欢迎,有单独的韩国标签被创建来批评他。然而,平台上对约翰尼·德普的支持仍然占大多数,大约三分之二的评论是积极的,许多人仍然表达了他们对他的爱。
Tweet 15: Negative Johnny Depp Opinion
Word-clouds on researched Hashtags
由于推特用户对这样的话题直言不讳,这导致了另一种现象在巫师界发生:在最初的崇拜者圈子里出现了多种崇拜者亚文化。大多数粉丝都直言不讳地表达了他们的观点,这在粉丝群体之间造成了隔阂。一些反粉丝强烈批评那些喜欢约翰尼·德普或神奇动物系列的粉丝。
Tweet 16 & 17: Criticising other fans
Fantastic Beasts vs Harry Potter
通过收集所有的结果,我们可以清楚地看到巫师世界不再是一个大社区,而是多个小社区。所有这些社区对新的神奇动物电影和其中的演员都有非常不同的观点。
著名的《活着的男孩》已经让粉丝着迷了二十多年,而让人们着迷于整个现象的东西(比如房子和令人难以置信的情节)似乎被 J.K .罗琳推到了一边。由于新电影不是基于书籍,也不是围绕哈利·波特、赫敏·格兰杰或罗恩·韦斯莱,它引起了粉丝们的兴趣,因为它带走了哈利·波特的魔力。所以,在新系列播出后,问题来了,罗琳试图在她的魔法世界里放入这么多的系列,是否真的是在摧毁她的魔法。
这可以通过今天的一些研究来回答;是的,她可能正在摧毁她的世界的某些部分,但粉丝已经变得如此之大,无论她发布什么,都会有很大一部分人支持她。
目前的情况与上一部绝地电影有关,在网上看起来这部电影受到了大量的反对,但当它被放在一个角度看时,实际上网上的仇恨相对较少。在粉丝发布的 249 条推文中,有 14.8%是关于神奇动物系列的负面推文。虽然这并不能掩盖《最后的绝地》和《神奇动物》都达到了让粉丝非常困惑和失望的目的。
我们完全建议你做的是自己决定你对新系列的看法,特别是因为有这么多不同的意见,而这只是总共 5 部电影的续集。因此,等到下一部电影来寻找答案也不是一个坏选择。众所周知,J.K .罗琳是创造宏伟故事情节的大师,所以现在,我们所能做的就是对她(以及她背后的整个营销团队)多一点信心,并希望她能利用她的魔法将神奇动物变成粉丝应得的特许经营权。
毫无疑问,即将上映的《神奇动物》系列电影将重新点燃新一代人或老一辈人对魔法的热爱。也许这不会是自 1997 年以来哈利波特教给我们的对魔法的热爱,但纽特·斯卡曼肯定有更多神奇的动物让我们去爱。
由 Imme van Oudheusden 和 Kim Jansen 创作。
APA 参考:
m .贝(2018)。《仇恨者的武器化:最后的绝地和通过社交媒体操纵的流行文化的战略政治化》。洛杉矶:南加州大学安娜堡传播与新闻学院。
Bennett,A. (2016 年 11 月 2 日)。哈利·波特迷对约翰尼·德普在《神奇动物》中的角色感到愤怒。检索自 BuzzFeed:https://www . BuzzFeed . com/alannabennett/Johnny-Depp-fantastic-beasts
丘巴,K. (2018 年 10 月 10 日)。艾梅柏·希尔德在#MeToo 周年纪念活动上阅读关于约翰尼·德普虐待指控的信。检索自综艺:https://Variety . com/2018/scene/news/amber-heard-Johnny-Depp-open-letter-me-too-1202975127/
加纳河(2018)。媒体粉丝和粉丝研究指南。《不是我的命根子:自我民族志、情感波动和流行音乐反狂热》(第 6 章)。约翰·威利父子公司。
霍克斯河(2016 年 11 月 9 日)。约翰尼·德普确认出演《神奇动物》中的格林德沃——但并不是每个人都高兴。从电讯报检索:https://www . Telegraph . co . uk/films/2016/11/09/Johnny-Depp-confirmed-as-grindelwald-in-fantastic-beasts-but-n/
Kyriazis,S. (2018 年 7 月 10 日)。《星球大战:最后的绝地反击》和影迷抵制:导演警告后果自负。检索自 Express:https://www . Express . co . uk/entertainment/films/986642/Star-Wars-Last-Jedi-backlash-fan-boycit-Han-Solo-flop-Kathleen-Kennedy-Rian-Johnson
Mendelson,S. (2016 年 11 月 2 日)。为什么约翰尼·德普不帮助《神奇动物在哪里》。检索自福布斯:https://www . Forbes . com/sites/Scott Mendel son/2016/11/02/why-Johnny-Depp-donts-help-fantastic-beasts-and-where-to-find-them/# 19e 400442 e44
Mendelson,S. (2018 年 11 月 14 日)。回顾:《神奇动物 2》是一场系列杀人灾难。检索自福布斯:https://www . Forbes . com/sites/Scott Mendel son/2018/11/14/review-fantastic-beasts-the-crimes-of-grindelwald-franchise-killing-disaster-JK-Rowling-Johnny-Depp/# ad 50 ACF 31803
Mendelson,S. (2018 年 6 月 26 日)。《星球大战 9》的大问题不会是《最后的绝地武士》的反弹或者《单飞》的失败。检索自福布斯:https://www . Forbes . com/sites/Scott Mendel son/2018/06/26/star-wars-9-last-Jedi-网飞-solo-force-awakens-wonder-woman-1984-frozen-2-juman Ji-James-bond-box-office/# 4014 AE 3c 3d 17
普尔弗,A. (2018 年 10 月 4 日)。艾梅柏·希尔德的法律团队谴责约翰尼德普虐待否认。从《卫报》检索:https://www . The Guardian . com/film/2018/oct/04/amber-heards-legal-team-谴责-Johnny-Depp-虐待-否认
纽特·斯卡曼图片检索自:https://t1 . dau mcdn . net/movie/0161 e 246399349 CBA 68d 8 f1 f 9 C5 c 15 c 41540263032405
神奇动物大战哈利波特图片检索自:http://ovicio . com . br/WP-content/uploads/eg2tsrg 5 bvaybfnqc0ql . jpg
纽特·斯卡曼与 Bowtruckle Gif 检索自:https://68 . media . Tumblr . com/715 c 11d 0 CEB 1812 c 878 AFD 81 f 20 c8 e 83/Tumblr _ oh 069 mpdcq 1 vpj 1 fho 1 _ 500 . Gif
恶作剧托管图片检索自:https://just stitchers . in/WP-content/uploads/2017/01/恶作剧托管. png
所有推文:
推文 1:由用户 @ JennyENicholson 于 2018 年 7 月 20 日发布
检索自:https://Twitter . com/jennye Nicholson/status/1020406911676502016
推文 2:由用户@prettymessygurl 于 2018 年 12 月 1 日发布
检索自:https://Twitter . com/prettymessygurl/status/1068947380379230209
推文 3:由用户@deppheadgang 于 2018 年 11 月 23 日发布
检索自:https://twitter.com/deppheadgang/status/1065945167058935809
推文 4:由用户@deppheadgang 于 2019 年 2 月 1 日发布
检索自:https://twitter.com/deppheadgang/status/1080454573192548352
Tweet 5:由用户@ magicalGicques 于 2018 年 9 月 12 日发布
检索自:https://Twitter . com/magialgicques/status/1071788822264930305
推文 6:由用户@cindispy00 于 2018 年 3 月 12 日发布
检索自:https://twitter.com/Cindispy00/status/1080966882553942016
推文 7:由用户@wyattyhalpert 于 2018 年 11 月 20 日发布
检索自:https://twitter.com/wyattyhalpert/status/800275977871863808
推文 8:由用户@ryanmeft 于 2018 年 11 月 16 日发布
检索自:https://twitter.com/RyanmEft/status/1063672113293377536
推文 9:由用户@ tapioccat 于 2018 年 11 月 27 日发布
检索自:https://twitter.com/tapioccat/status/1078439397618380800
推文 10:由用户@osatou_tw 于 2018 年 3 月 1 日发布
检索自:https://twitter.com/osatou_tw/status/1081087335159087104
推文 11:由用户@decembristsson 于 2018 年 4 月 1 日发布
检索自:https://Twitter . com/decembristsson/status/1081190992567549952
推文 12:由用户@dichi71 于 2018 年 5 月 1 日发布
检索自:【https://twitter.com/DiChi71/status/1081659007750807552】T4
推文 13:由用户@originalfunko 于 2018 年 12 月 22 日发布
检索自:https://Twitter . com/original funko/status/1063976339114471424
推文 14:由用户@fantasticbeasts 于 2018 年 11 月 30 日发布
检索自:https://Twitter . com/fantastic beasts/status/1068671018628079617
推文 15:由用户@ sukuraai 于 2018 年 9 月 26 日发布
检索自:https://twitter.com/SakuraAi/status/1044586020572778498
推文 16:由用户@mathewkearney 于 2018 年 11 月 16 日发布
检索自:https://Twitter . com/mathewkearney/status/1063553558556155904
推文 17:由用户@kyloporg 于 2018 年 8 月 25 日发布
检索自:https://twitter.com/kyloporg/status/1044616526681329664
常见问题聊天机器人 MVP
使用 Python、Flask、Docker 和谷歌云服务
https://willtscott.github.io/inquire-boulder-chatbot/
这是一个快速的过程和工具的纲要,我研究并使用它来为博尔德市建立一个聊天机器人,CO 的常见问题页面。将来我会写一些关于技术方面的更详细的帖子。
github:【https://github.com/willtscott/inquire-boulder-chatbot
**结果:**现在,这个例子是一个最小可行的产品。我之所以分享这个过程,是因为它可以很容易地转移到其他 FAQ 网站,并且可以通过其他功能进行扩展。我遵循的路线也受到我希望获得标准行业实践经验的影响,因此是简单和复杂选项的平衡。
数据采集
将 FAQ 页面转换成数据集在理论上非常简单,第一步是将网页转换成逗号分隔值的文件。根据你的出发点,这可能是琐碎的,也可能是乏味的。
我开始使用科罗拉多州博尔德市的内容,所以当我看到他们的查询博尔德 FAQ 页面的第一反应是震惊!页面是动态生成的,这使得下载或抓取变得更加困难。因此,我最初的选择是点击 250 多个主题中的每一个,并手动将它们的信息复制粘贴到一个文件中。 Yowch!(值得注意的是,虽然这可能需要几个小时令人麻木的点击,但弄清楚如何抓取动态页面可能需要更长的时间。)
幸运的是,我有了一个更好的主意,这个主意给我带来了回报,也让我少了很多烦闷。在博尔德开放数据页面上,我找到了 FAQ 相关数据集维护负责人的联系信息。仅仅发了几封邮件之后,她就从网站管理员那里给我发来了一个文件,里面包含了每个 FAQ 页面的内容,按类别、部门和主题进行了分类。
在项目的早期阶段,这种资产是纯金的,并继续得到回报,因为我的联系人提供了进一步的帮助,建议类似的数据集、相关的项目,以及向博尔德数据团队展示我的 ChatBot 并在他们的数据展示页面上托管它的可能性。所以非常感谢,尼科利亚!
**经验教训:**在你花大量时间去完成一项琐碎的任务之前,花几分钟四处看看,看看你是否能直接找到问题的根源。许多市政府发布公共数据集,必须有人负责处理所有这些数据。礼貌地提问,你永远不知道你会得到什么样的数据。此外,社会关系可能会更有回报。
数据清理
得到这个文件是一个巨大的推动,但它还没有结束。在将文件从 Excel 转换为 CSV 格式后,我仍然需要清理数据并使其达到最终状态:一列问题和一列相应的答案。
我将每个条目转换成 unicode 文本,移除工件,并利用 spaCy 库的特性来分隔条目中的每个句子。虽然这不是一个完美的修复,但它让我在处理干净数据方面有了一个巨大的开端,足以让我能够继续尝试 NLP 和 ML 技术。
后来,我重新开始清理这些条目,并手工编辑了一些由地址、不标准的语法、奇怪的标点和样式造成的错误。
对于pie ce de resistance我编写了一个复杂的正则表达式,从一组文本中分离出问答对,然后将它们放入两个独立的列中。
**跳到最后:**根据你自己的需要,你可以在这里停下来,把你整洁的 q-n-a 电子表格带到聊天机器人平台,如微软 QnA Maker 或谷歌 Dialogflow ,它会把你的数据插入一个预建的界面,包括聊天回复和开箱即用的机器学习。在默认设置的这两个选项中,QnA Maker 给我的结果稍好一些。价格会有所不同,所以在你承诺之前做好你的功课。在这篇博客的最后,我从我的经历中提供了一些建议。
自然语言处理
经过预处理和手工清理后,我的 NLP 管道是删除标点符号和停用词,将所有内容都小写,然后对剩余的词进行词条整理。我发现变元化比单纯的词干化要有效得多。将单词简化为最基本的形式有助于更广泛的相似性匹配,这有助于聊天机器人在响应查询时的准确率。NLTK 库有一些简单的选项可以提供帮助。
下一步是将文档转换成 ML 模型能够理解的数字向量。首先,我使用单词包,这是一个大型的稀疏矩阵,用二进制值来表示语料库中的每个单词是否存在于文档中。从这里开始,BOW 向量被转换成术语频率——逆文档频率向量,它基于每个单词在文档中的频率及其在整个文档集合中的频率来表示每个单词对语料库的重要性。
因此,对于我的数据集,单词“Boulder”具有相对较低的 TF-IDF 值,这是因为它在整个文档中非常普遍。对于一个关于不同城市的常见问题,你会认为“博尔德”更有分量。(无双关之意?)
**行业工具:**单词袋和 TF-IDF 矢量化是任何 NLP 项目的标准,为更复杂的操作提供了坚实的基础。下面的大多数匹配策略涉及对 TF-IDF 向量应用各种函数。
相似性匹配
为了将用户问题与数据集中的答案进行匹配,我尝试了几种不同的方法:
- 语义相似度 通过预先训练的模型被包括在 NLP 库空间中,该模型认为如果单词在相似的上下文中使用,则它们是相似的。根据我的经验,“中型”空间模型在分配相似性方面几乎和“大型”模型一样好,而且加载速度明显更快。该库的实现既快速又简单(甚至 spaCy 中包括了矢量化),但是直接的结果并不特别令人印象深刻,并且大型模型可能会在部署时损害您的钱包。
- 余弦相似度 是两个向量之间夹角的余弦度量。这里的应用程序是计算用户查询向量和数据集中每个向量之间的夹角余弦。最接近 1 的余弦是用户查询的最佳匹配。我从 numpy 和 scikit-learn 的现有部分构建了这个比较,它足够简单,并且不需要庞大的模型。我发现结果相当不错,并最终在我的 MVP 机器人中使用了这种精益方法。
- KD 树 是 scikit-learn 中表示的一种数据结构,对存储 K 近邻关系很有用。这种静态存储使您不必在每次比较向量时重新计算距离。scikit-learn 版本中的距离度量不支持余弦相似性,余弦相似性将是该策略的理想扩展,但一些包含的度量(欧几里德、l2、闵可夫斯基和 p)在我的测试案例中工作得一样好。
- Gensim的 Doc2Vec 是 Word2Vec 方法的扩展,它使用神经网络来学习整个文档的嵌入,而不仅仅是单个单词。我发现这种方法的设置比以前的方法要复杂得多,并且结果不如基本余弦相似度和 KDTree。然而,如果你对神经网络很熟悉,并且愿意钻研细节,那么这是一个很有前途的角度。需要注意的是:大多数 FAQ 不会包含足够的文本来获得强大的训练,并且没有太多对预训练 Doc2Vec 模型的支持,但是这里有一个开始。
保持简单和愚蠢:相似性匹配有许多不同的方法。同样,遵循阻力最小的途径,寻找一个为您想要使用的策略提供内置功能的库。没有必要重新发明轮子。当你准备好部署你的机器人时,你可以回来重新检查你的选项以提高准确性。
我的建议是将你的管道构建成独立的模块,这样你就可以很容易地交换新的选项,而不用重写整个程序。这种模块化还将帮助您测试和比较结果,以便您知道您正在做出关于选择哪个函数的明智决策。
Web 服务和部署
随着您的管道能够返回相关的响应,下一步是让机器人上线,这样人们就可以实际使用它。
Flask 是一个 Python 微框架,它可以通过在本地 URL 上托管一个基本的 HTML 页面,并将用户查询作为 POST 请求提交给 Flask route 函数,后者返回来自相似性匹配算法的响应,并将其呈现在页面上,从而使聊天机器人的 web 服务变得异常简单。
**分享就是关怀:**网络服务的真正力量在于把你的机器人放到互联网上,让公众和其他程序都能访问。只要有当地的 Flask 服务,你就已经成功了一半。
在网上提供你的机器人的另一半是让它可以被公众访问。像 [ngrok](http://ngrok - secure introspectable tunnels to localhost https://ngrok.com/) 这样的工具在技术上可以做到这一点,但是规模很小,需要你自己的电脑来托管。更有用的是谷歌、亚马逊、微软等提供的现代云服务。这将为您处理托管(当然是收费的。)
我与谷歌云服务合作托管我的 Flask 应用程序,将它包装在 Docker 容器中,并在负载平衡的 Kubernetes 集群上运行,以允许扩展。([谷歌应用引擎](http://App Engine - Build Scalable Web & Mobile Backends in Any … https://cloud.google.com/appengine/)是一个替代方案,在某些情况下可能会更容易。)这一步最后给了 bot 一个公共 URL。分享给你的朋友吧!
连接
如果你想建立你自己的网页界面,这是一个好地方。
我在这里采用了一种混合方法,并将我的 q-n-a 数据集上传到 Google Dialogflow,作为知识库意图。然后,我通过使用应用程序的公共 URL 作为一个 webhook ,将知识意图连接到我在 GCP 的 web 服务。
现在,每当用户向 Dialogflow 代理查询知识库中的主题时,代理都会在后台向我的 web 服务应用程序发送 webhook 请求,并接收由我的自定义相似性匹配确定的响应。
我的混合方法的好处是,用户可以与 Dialogflow 接口进行交互(包括闲聊响应),如果我的自定义 bot 服务器出现故障,Google 的知识意图机器学习可以作为后备响应。
**自豪的家长:**我应该在这里指出——尽管我的相似性算法很基本,但它仍然胜过我测试的大规模技术公司服务中的任何开箱即用的 ML 平台。
关于成本的一些话:
**谷歌云产品:**300 美元的注册信用旨在帮助你在掌握事物的过程中吸收成本,但仍然需要小心你在服务上投入的重量,这样你就可以避免成本飙升的经典恐怖故事。我使用的服务需要启用计费。在测试 Docker、clusters 和 swarms 时,我在几周内花掉了大约 15 美元。一天自己占了 10 美元左右,跟踪钱的去向可能会很棘手,所以要小心!最后,一个用户基数小的聊天机器人运行起来应该相当便宜。稍后我会提供一个更新,提供更多关于信用持续时间的细节。
更新: 经过几周的持续运营,我有了一些关于成本的初步数据。一开始我的服务大概吃了***【3 美元/天*** 。仅使用 webhooks 使我能够消除 Dialogflow API 库,并缩减到仅 1 个集群,而不是 3 个,成本降至~【2 美元/天】。
Dialogflow: 标准版免费,企业版有按使用付费要求。这里有一张对比图,但即使是标准版配额也应该足以让你入门。这个平台有很多小功能,包括语音支持以及与脸书和 Slack 等其他消息应用的集成。
微软 QnA Maker: 如果你只是上传一个包含两列的 Excel 文件:问题和答案,微软 Azure 平台上的这个 web 服务开箱即用就能很好地工作。对于我的小测试集,ML 响应比 Dialogflow 的内置 ML 更准确,尽管界面不是那么用户友好。我用 200 美元的免费注册信用连续运行了整整一个月(流量很少),但我建议在你设置的时候想办法禁用这项服务,以便进一步扩展你的信用。这是这项服务的定价页面。
下一集…
在我的下一篇文章中,我将进一步深入细节,并提供一个指南,通过 Docker 跟踪将这个简单的 Flask 应用程序部署到 GCP Kubernetes 集群的路径。我计划解决一些其他教程中似乎没有的空白,所以如果你对这个话题感兴趣,请继续关注。如果你有任何问题或者只是想聊聊机器人,请告诉我!
AI 能阻止犯罪吗?使用计算机视觉的逃票检测
逃票是纽约市交通管理局面临的一个日益严重的问题。去年的报告显示:
- 据估计,2018 年因逃票造成的收入损失为 2.15 亿美元
- 地铁 9600 万美元,公交车 1.19 亿美元
- 预计未收收入将比 2015 年增加 1.1 亿美元
Fare Evasion in New York. (Source)
在 2018 年 12 月举行的 MTA 委员会特别会议上,纽约市交通总裁安迪·拜福德表示,甚至机构高管也可能被部署来阻止逃票者。他说:“我们将让总部的人组成团队,随机去乘坐公共汽车或站在大门前,提供一个物理屏障,以确保你在进入车站或乘坐公共汽车前有票。”。“当然,我们会有(额外的 MTA)团队或警察来支持我们。”
正如这里的所提到的,逃票还有其他的社会含义。“当我是警察局长时,我们开始关注逃票,”布拉顿在 2014 年说。“我们发现了什么?七分之一的人被通缉。每 21 个人中就有一个携带武器,从美工刀到简自豪冲锋枪。因此,如果你愿意的话,纽约奇迹始于 25 年前对地铁逃票行为的执法。”
用于估计逃票的当前数据收集过程远非完美,并且依赖于人工生成的数据和采样技术。
MTA fare evasion data collection (source)
我相信,通过利用计算机视觉的技术进步,利用安全摄像机镜头测量(而不是估计)地铁逃票的成本有效的自动化系统是可能的。大多数十字转门都被安全摄像头覆盖,这些镜头被记录并保存在中央服务器上。有可能设计一个软件管道来消耗来自这些服务器的视频数据,并使用计算机视觉来检测十字转门跳线,并将该信息记录在数据库中。这种自动化将有以下好处:
- 无需安装边缘设备或现场硬件,这意味着实施成本最低。
- 逃票数据将具有精确的时间粒度,而不是采样。
- 逃票数据将具有精细的空间粒度(车站入口级别),不同于当前方法的全系统估计。
- 将其转化为实时信息系统的潜力
- 准确的估算将使 MTA 能够更好地进行成本效益分析,并以数据驱动的方式决定下一步行动。
- 数据的时空特性将使高效的人员调度成为可能,以防止逃票。
- 它将削减人工数据收集的成本
计算机视觉营救
我们将用计算机视觉可以解决的方式来重新表述这个问题。目标是识别视频中发生逃票的帧。当一个人跳过十字转门而不是走过它时,就会发生逃票。因此,如果你能在给定的画面中区分一个行走的人和一个跳跃的人,你就能在此基础上检测逃票行为。
许多基于卷积神经网络的不同架构都有可能解决这个问题。但是从头开始训练这些模型需要大量的数据,而我们并不具备解决这个特定问题的能力(除非你在 MTA 有亲戚)。但是在计算机视觉的现代,你很少需要从头开始。网络上有大量或预先训练好的模型可供使用,可以用来初始化模型的部分或完整状态,也可以用来提取可以用来训练浅层分类的特征。这被称为迁移学习。
姿态估计系统似乎是用于特征提取的完美候选,因为姿态特征应该能够从行走的人识别跳跃的人。姿态估计系统使用卷积神经网络从图像中估计人体上选定关键点的位置。因此,该解决方案分为两个模块:
**姿态特征提取:**该模块将检测帧中的所有人,并通过检测关键身体点来估计他们的姿态。 Open Pose 是一个开源的人体姿态估计系统,我用它来提取姿态特征。
姿势分类:基于人走过或跳过十字转门的姿势会有明显不同的直觉。姿态分类将基于姿态特征将姿态分类为跳跃或行走。
概念验证解决方案
为了测试提议方法的可行性,我开发了一个概念验证解决方案。准备了来自 google 图像搜索的大约 200 个图像的小数据集。一半的图片是站着的人,另一半是在空中跳跃的人。开放姿态用于从图像中提取姿态特征,这给你身体的 18 个关键点的位置。随后在 18 维特征空间上训练一个小的随机森林来解决双向分类问题。
分类器给出了 91%的精确度和 85%的召回率,即使训练/测试分裂为 50/50,这表明它是一个简单的分类问题。从如此小的数据集获得良好结果的原因是,在 14 维特征空间中,跳跃姿态和行走姿态是容易分离的。
Example predictions on unseen data
现在,我们将尝试通过模型运行一个视频,看看它是否可以识别包含跳跃的人的帧。确实如此。
Me walking through a poorly simulated turnstile.
Me jumping over a poorly simulated turnstile.
结果是有希望的,似乎有可能使用计算机视觉设计一个自动逃票检测系统。
我们相信,通过根据标记的 MTA 监测数据重新训练/微调整个模型管道,可以提高性能。这是因为每个系统都生成具有某些特征属性的数据分布。例如,对于 MTA 监测数据来说,遮挡模式、捕捉角度和照明条件将是独特的。在训练中使用类似的数据应该能够提高性能。
github 上有代码。你可以随意摆弄它,如果你喜欢它,可以留下一颗星星。
通过在 GitHub 上创建一个帐户,为 muaz-urwa/逃票检测-使用计算机视觉的发展做出贡献。
github.com](https://github.com/muaz-urwa/Fare-Evasion-Detection-using-Computer-Vision)
基于整体嵌套边缘检测的卫星图像农场分割
想象一下,如果我们丢弃了整个印度的卫星图像,可以检测出农场边界,不仅可以映射到单个农民,还可以映射到离相应农场最近的银行、铁路、公路和市场。
Farm Segmentation Layer after 12 epochs of training on top of a random area in Rajasthan
我最近一直在做一份问题声明,这将有助于检测印度所有的农场。这是一项相当具有挑战性的任务,因为我们将使用废弃的谷歌地球卫星图像来实现这一目标,而农场的边界通常很难区分,因此很难检测到。我决定采用的模型是一种基于深度学习的 ConvNeuralNet 模型,称为整体嵌套边缘检测,它给定一幅图像,在每一层后输出一个预测,并将其与地面真实二进制图像(包含相应图像的真实边缘图)进行比较,以在每一层生成一个边损失,然后将其相加,以给出融合损失。在每个损失级别生成权重,然后反向传播以给出优化值。
现在我们已经对管道有了一个简要的概述,不再赘述,让我们开始吧。
预训练模型预测
适用于 HED 的预训练模型已经在著名的 BSDS 数据集上进行了训练,但对我们没有太大用处,因为作为数据集一部分的图像类型是普通图像,而不是卫星图像。我决定将预训练的模型用于一个小图像,并测试它是否足够令人满意,以便通过一些后期处理来缩放它。
Original Image in juxtaposition with its edge map produced from the pre-trained model
正如您在边缘地图中看到的,结果没有按比例进行切割,给出了一个健壮的农场边界检测模型。可怕的…数据生成和图像标记!
数据生成
由于预训练模型未能为我们提供一个稳健的模型,我必须想出一种方法来生成一个数据集及其相应的地面实况,该数据集与 BSDS 数据集一样大,以确保模型不会过度拟合,并以最小的验证损失提供良好的整体准确性。
幸运的是,我从第一天开始就可以访问废弃的谷歌地球卫星图像数据,因此计算出从哪个确切的区域开始分割相对容易得多。在花了几个小时寻找能够包围最大农场并具有清晰边缘以进行地面校正的区域后,Ganganagar tehsil 被选中来获取标记数据。BSDS 数据集包含大约 30,000 个用于训练算法的标记图像(大约 480 X 480),因此要获得与该数据集接近的精度,大约需要 30,000 个标记图像。废弃的谷歌地球图片每张大约是 1000 X 1000,这样我们就有 480 X 480 的图片可以贴标签了。为了获得与 BSDS 一样大的数据集,需要标注 1,20,000 幅影像。疯狂!
数据增强拯救世界。
增大
图像增强是指当你没有足够的数据来训练深度学习模型时,通过对现有数据进行形态学转换来增加数据集的大小。在这种情况下,我确实有足够的数据,但扩充的想法是对相对较小的数据进行基础处理,然后将其扩充到大约 30,000。通过这种方式,人工地面实况调查将减少到标记 1225 幅图像(在将大约 16,1000 X 1000 幅图像裁剪成 480X480 之后),并且这些图像将增加 24 倍,使得数据集的大小大约为 29,400。我实现了以下基本的扩充技术来增加数据集,这将在下一篇文章中详细介绍。https://medium . com/nano nets/how-to-use-deep-learning-when-you-has-limited-data-part-2-data-augmentation-c 26971 DC 8 ced
1.缩放比例
对于这个特殊的问题陈述,我将数据集缩放到 1.5 和 0.5,使放大因子为 3 倍。进一步应用于变换的技术将针对每个标度,使它们进一步乘以因子 3。
Original Scale Image →0.5 →1.5
Scaling in OpenCV
2.轻弹
下一个转换是水平翻转图像,然后针对每个比例垂直翻转。因此,对于每个比例,您会得到两张图像,这意味着放大系数是 3 倍。
Original Image → Horizontally flipped → Vertically flipped
Flipping in OpenCV
3.轮流
实现的另一种形态变换是旋转。旋转时唯一需要注意的是,旋转后的图像尺寸可能不一样。将正方形图像旋转 90 度,将矩形图像旋转 180 度,可以保留图像的尺寸。在我的例子中,图像是正方形的,所以可以把它旋转 90 度。放大系数 2 倍。
Original Image → Rotated 90 degrees
Rotation in OpenCV
4.高斯噪声
高斯噪声扭曲了高频(出现最多且特别无用的)特征,这通常是过拟合的原因。高斯噪声也会扭曲低频特征(实际数据),但网络可以学会忽略它。为数据添加少量 apt 可以增强学习能力。我在整个数据集中添加了随机的粉红色像素来引入高斯噪声。放大系数 2 倍。
Original Image → With Gaussian Noise
Adding Gaussian noise
在这些技术的帮助下,我们终于能够创建一个非常接近 30,000 大关的数据集。现在是劳动密集型的部分…图像标注!
标记
使用了一个基于网络的工具,它将上传一个图像,使用鼠标指针,可以在图像的顶部绘制线条,突出农场的边界。在图像上画线后,提取二值图像,其中白色像素代表农场边缘,黑色像素代表非边缘。这是相应的 RGB 卫星图像的地面实况边缘图。
Manual Labeling of Edges using RGB satellite images
Extracted Binary image after completing labeling
整体嵌套边缘检测
该算法基于由 5 个卷积层组成的卷积神经网络架构。在输入图像通过之后,每一层对其输入进行非线性操作,并生成边缘图,该边缘图与输入图像的地面真实图像进行比较,以生成边损。每个侧输出层与产生侧损失的具有相应权重的分类器相关联。在这种图像到图像的训练中,在训练图像中的所有像素上计算损失函数。
Side-output error for each layer. weights are denoted as w = (w(1) , . . . , w(M) ). where l(side) denotes the image-level loss function for side outputs
对于标准卫星图像,边缘/非边缘像素的分布严重倾斜。估计 85–90%的图像是非边缘的,这就是使用成本敏感函数来正确捕捉误差的原因。该算法在每个像素项的基础上引入类平衡权重β。索引 j 在图像 x 的图像空间维度上。然后,我们使用这个类平衡权重作为一种简单的方法来抵消边缘和非边缘之间的这种不平衡。具体地,我们定义了等式(1)中使用的以下类别平衡的交叉熵损失函数
l(side) denotes the image-level loss function for side outputs
其中,β= | Y |/| Y |和 1β= | Y+|/| Y |。| Y |和|Y+|分别表示边缘和非边缘基础真值标签集。pr(yj = 1 | X;w,w(m) ) = σ(a (m) j ) ∈ [0,1]使用 sigmoid 函数σ(.在每个侧输出层,我们然后获得边缘图预测 yˇ(m)side =σ(aˇ(m)side),其中 aˇ(m)side≡{ a(m)j,j = 1,.。。,|Y |}是层 m 的侧面输出的激活
为了直接利用侧输出预测,该算法在网络中增加了一个加权融合层,同时在训练过程中学习融合权重。
loss function at the fusion layer L(fuse)
其中 Y fuse ≡ σ(求和(m=1-M)(hmA(m)侧))其中 h = (h1,.。。,hM)为融合权重。Dist(,)是融合预测和地面真实标签图之间的距离,我们将其设置为交叉熵损失。将一切放在一起,我们通过标准(反向传播)随机梯度下降最小化以下目标函数:
The final objective function used for backpropagation
Network Architecture for HED highlighting the error backpropagation paths. Side-output layers are inserted after each convolutional layer. Supervision is imposed at each side-output layer, guiding the side-outputs towards edge predictions with the characteristics we desire. The outputs of HED are multi-scale and multi-level, with the side-output-plane size becoming smaller and the receptive field size becoming larger. One weighted-fusion layer is added to automatically learn how to combine outputs from multiple scales. The entire network is trained with multiple error propagation paths (dashed lines).
https://arxiv.org/pdf/1504.06375.pdf
轮廓检测、绘图和后处理
原始预测图像的边缘可能完整,也可能不完整,一旦我们从该图像中提取轮廓,我们希望轮廓是一个闭合的多边形,因为农场也是闭合的。为了处理不完整的边缘,引入了扩张,这将加宽边缘,使得缺失的链接将被完成,并且在扩张后的图像上进行骨架化,以从宽边缘提取单像素线,从而给出最终的完整轮廓。
Satellite Image with prediction after dilation and skeletonization. Hanging edges still remain.
此外,如果两条边之间的距离对于膨胀处理来说很大,则在黑色图像上绘制每个轮廓(从已经生成的轮廓中获取),进行填充,然后从中提取新的轮廓,这将自动移除多边形中可能存在的不完整的边。
Satellite image with contours after post-processing. Most of the hanging edges are removed.
结论
在基于深度学习架构的模型的帮助下,我能够正确地检测拉贾斯坦邦的农田,准确率为 80–85%。这有助于构建进一步的模型,包括:一种测量农场等级的新方法(农场指南),一种连接矩阵,其中农场被映射到最近的铁路、水路、银行、mandi、土壤的各个方面,基于不同的指数和盐度。
(注意:整体嵌套边缘检测的 Keras 实现借用了https://github.com/lc82111/Keras_HED
使用神经网络的时尚产品图像分类|从零开始的机器学习(第六部分)
通过在 Python 中从头构建神经网络,了解如何处理图像数据和对时尚产品进行分类
TL;DR 从头开始用 Python 构建神经网络。使用该模型将时尚产品的图片分为 10 类中的 1 类。
我们生活在 Instagram、YouTube 和 Twitter 的时代。图像和视频(一系列图像)主导了千禧一代和其他怪人消费信息的方式。
让模特了解图像显示的内容,对于了解你的情绪状态(是的,你可能会在 Instagram 上发布分手自拍后立即收到个性化的可乐广告)、位置、兴趣和社交团体至关重要。
主要地,理解实践中使用的图像数据的模型是(深度)神经网络。在这里,我们将从头开始用 Python 实现一个神经网络图像分类器。
合作笔记本
drive.google.com](https://drive.google.com/file/d/1S59KWV8KmZTI-A6OpXge3yG87HXyIcUz/view?usp=sharing)
图像数据
希望你不会对计算机不能像我们一样看到图像感到惊讶。设备上的每个图像都以矩阵的形式表示/存储,其中每个像素都是一个或多个数字。
读取时尚产品数据
时尚-MNIST 是 Zalando 文章图片的数据集——由 60,000 个示例的训练集和 10,000 个示例的测试集组成。每个示例都是 28x28 灰度图像,与 10 classes 中的标签相关联。我们打算将时尚 MNIST 作为原始 MNIST 数据集的直接替代,用于机器学习算法的基准测试。它共享训练和测试分割的相同图像大小和结构。
以下是这些图片的示例:
你可能熟悉原始的手写数字 MNIST 数据集,并想知道为什么我们不使用它?嗯,在做预测可能太容易了。当然,时尚更酷,对吗?
探索
产品图像是灰度的,28x28 像素,看起来像这样:
以下是图像像素矩阵的前 3 行:
请注意,这些值在 0–255 范围内(灰度)。
我们有 10 类可能的时尚产品:
让我们来看看使用 t-SNE 的一些产品的低维表示。我们将使用来自 scikit-learn 的实现将数据转换成二维数据:
您可以观察到一些类之间有明显的分隔,而其他类之间有明显的重叠。让我们建立一个可以尝试区分不同时尚产品的神经网络!
神经网络
神经网络(NNs),特别是深度神经网络,在过去几年里在机器学习领域风靡一时。这并不奇怪,因为大多数关于各种机器学习问题的最新成果(SOTA) 都是通过神经网络获得的。
人工神经元
模拟我们的生物神经元的目标导致了人工神经元的发明。这是你大脑中单个神经元的样子:
source: CS231n
另一方面,我们有一个大大简化的数学模型,它在实践中非常有用(神经网络的成功证明了这一点):
source: CS231n
人工神经元的想法很简单——你有来自某处的数据向量 X ,参数向量 W 和偏置向量 b 。神经元的输出由下式给出:
其中 f 是控制神经元输出信号强度的激活函数。
构建神经网络
您可以使用单个神经元作为分类器,但有趣的部分开始于您将它们分组到层中。具体来说,神经元连接成一个无环图,数据在各层之间流动:
source: CS231n
这个简单的神经网络包含:
- 输入层-3 个神经元,应该与输入数据的大小相匹配
- 隐藏层-您的模型在训练期间应该学习的权重为 W 的 4 个神经元
- 输出层-提供模型预测的 2 个神经元
想建立深度神经网络?只需添加至少一个隐藏层:
source: CS231n
乙状结肠的
sigmoid 函数是相当常用的激活函数,至少直到最近是这样。它具有明显的 S 形,对于 00 到 11 之间的任何实输入值和输出值,它都是一个可微的实函数。此外,它在每一点都有一个正导数。更重要的是,我们将使用它作为模型隐藏层的激活函数。
下面是它的定义:
下面是我们实现它的方法:
它的一阶导数(我们将在训练算法的反向传播步骤中使用)具有以下公式:
我们的实现重用了 sigmoid 实现本身:
Softmax
softmax 函数很容易区分,它是纯函数(输出仅取决于输入),结果向量的元素和为 1。这是:
以下是 Python 实现:
在概率论中,softmax 函数的输出有时用作分类分布的表示。让我们来看一个示例结果:
输出的大部分权重对应于输入 8。softmax 函数突出显示最大值并抑制较小值。
反向传播
当使用神经网络时,反向传播几乎是我们所做的任何事情的支柱。该算法由 3 个子任务组成:
- 向前传球
- 计算误差
- 进行反向传递(反向传播)
在第一步中,backprop 使用数据和网络的权重来计算预测。接下来,基于预测和提供的标签计算误差。最后一步是从最后一层开始,通过网络传播错误。因此,权重基于误差一点一点地更新。
让我们对算法实际上在做什么建立更多的直觉:
求解异或
我们将尝试创建一个能够正确预测 XOR 函数值的神经网络。下面是它的真值表:
这是一个直观的表示:
让我们从定义一些参数开始:
epochs 参数控制我们的算法在训练期间“看到”数据的次数。然后,我们设置输入层、隐藏层和输出层中神经元的数量——我们有 2 个数字作为输入,1 个数字作为输出大小。学习率参数控制我们的神经网络从新数据中学习并忘记已经知道的东西的速度。
我们的训练数据(来自表格)如下所示:
我们的神经网络中的 W 向量需要有一些初始值。我们将采样一个均匀分布,用适当的大小初始化:
最后,反向投影算法的实现:
那个误差好像在减少!耶!而且实现也没那么吓人吧?
在forward
步骤中,我们取数据 X 和 W_hidden 的点积,并应用我们的激活函数来获得我们的隐藏层的输出。我们通过获取隐藏层输出和 W_output 的点积来获得预测。
为了获得error
,我们计算真实值和预测值之间的差异。请注意,这是一个非常粗略的度量,但是对于我们的示例来说,它很好。
最后,我们使用计算出的误差来调整权重。注意,我们需要来自正向传递act_hidden
的结果来计算 W_output,并使用sigmoid_prime
计算一阶导数来更新 W_hidden。
为了进行推断(预测),我们将只进行前一步(因为我们不会根据结果调整 W ):
我们的魔法似乎起作用了!预测是正确的!
图像分类
构建神经网络
我们的神经网络将只有一个隐藏层。我们将实现上面显示的训练算法的一个更加复杂的版本,以及一些方便的方法。
初始化权重
我们将对一个均匀分布进行采样,初始权重的值在-1 和 1 之间。下面是实现过程:
培训
我们来看看训练方法:
对于每个时期,我们应用反向投影算法,评估相对于权重的误差和梯度。然后,我们使用学习率和梯度来更新权重。
做一个反向投影步骤比我们的 XOR 例子要复杂一点。我们在返回梯度之前做了一个额外的步骤——应用 L1 和 L2 正则化。正则化通过惩罚参数 W 的大值来引导我们的训练朝向更简单的方法。
我们的forward
和backward
步骤与上一个例子中的非常相似,误差如何?
测量误差
我们将使用交叉熵损失(称为对数损失)函数来评估误差。该函数测量分类模型的性能,其输出是概率。它惩罚(严厉地)错误和自信的预测。定义如下:
其中 C 是类的数量, y 是二进制指示符,如果类标签是观察的正确分类, p 是 o 属于类 c 的预测概率
Python 中的实现如下所示:
现在我们有了损失函数,我们终于可以定义模型的误差了:
在计算交叉熵损失之后,我们添加正则化项并计算平均误差。以下是 L1 和 L2 正则化的实现:
做预测
现在我们的模型可以从数据中学习,是时候对它以前没有见过的数据进行预测了。我们将实现两种预测方法— predict
和predict_proba
:
回想一下,神经网络中的预测(通常)包括对数据应用向前的一步。但它的结果是一个值的向量,表示每个类对数据的信任程度。我们将使用最大似然估计(MLE) 来获得我们的最终预测:
MLE 的工作方式是选取最高值,并将其作为输入的预测类返回。
方法predict_proba
返回所有类别的概率分布,代表每个类别正确的可能性。注意,我们通过将softmax
函数应用于forward
步骤的结果来获得它。
估价
是时候测试我们的神经网络模型了。我们可以这样训练它:
培训可能需要一些时间,所以请耐心等待。让我们来预测一下:
首先,我们来看看训练错误:
这里看起来有些可疑,似乎我们的模型不能继续减少 150 个历元左右的误差。让我们来看一个单一的预测:
那个好像是对的!让我们再看几个:
不太好。培训和测试的准确性如何:
嗯,那些看起来不太好。虽然随机分类器将返回约 10%的准确度,但在测试数据集上约 50%的准确度也不会成为实用的分类器。
提高准确性
训练误差图上的“锯齿状”线显示了我们的模型无法收敛。回想一下,我们使用反向传播算法来训练我们的模型。数据标准化后,训练神经网络收敛速度更快。
我们将使用 scikit-learn 的标度来标准化我们的数据。该文件指出:
以平均值为中心,以单位方差为分量标度。
这是新的训练方法:
让我们来看看错误:
误差似乎稳定得多,稳定在一个较低的点——约 200 对约 400。让我们来看看一些预测:
那些看起来也好多了!最后,准确性:
训练集上的约 87%(对约 50%)比未缩放的方法有了巨大的改进。最后,你的努力得到了回报!
结论
多好的旅程啊!我希望你也能从头开始开发你的第一个神经网络!
你学会了如何处理图像数据,转换它,并用它来训练你的神经网络。我们使用了一些方便的技巧(缩放)来极大地提高分类器的性能。
合作笔记本
drive.google.com](https://drive.google.com/file/d/1S59KWV8KmZTI-A6OpXge3yG87HXyIcUz/view?usp=sharing)
最初发表于【https://www.curiousily.com】。
喜欢你读的吗?你想了解更多关于机器学习的知识吗?提升你对 ML 的理解:
“我不能创造的,我不理解”——理查德·费曼这本书将引导你走向更深的…
leanpub.com](https://leanpub.com/hmls)
时尚科学进行季节性色彩分析
结果是数据中找不到“季节”
穿对颜色的衣服,更有魅力!
这就是季节性色彩分析的魅力所在。通过恰当地将你置于四季之一——春、夏、秋、冬——每一季都有适合你的调色板。
本文运用时尚科学来探索一个简单的概念——人们真的会被分成四个部分来映射传统的季节分配吗?对我来说,时尚科学包括图像处理、机器学习和数据分析,但也包括传统的艺术和心理学概念。
使用从我们当前的 iPhone 应用程序收集的超过 100,000 张“肖像自拍”(所有人都关注色调),我们将每张自拍分成关键的身体部位——皮肤、头发、眼睛和嘴唇。(我说的‘肖像自拍’明确指的是高分辨率的肖像——我们需要虹膜上有很多像素!)然后,我们应用聚类分析技术,根据自拍者身体部位颜色的相似性,将自拍者分组在一起。虽然两个集群和四个集群显然很好,但这些与季节描述完全不相关。
有了新的、基于科学的细分,就有了一个坚实的基础来更好地看待时装设计、营销和零售市场细分的数据方法。进一步的工作也将带我们重新审视个人色彩分析——基于个人色彩调和的个性化调色板的创建。
背景
季节性色彩分析(SCA)基于和谐的色彩会增强个体的自然美这一概念。季节方面涉及到把所有人放入四个部分中的一个,以季节命名。有用户自我识别的指导,尽管历史上用户已经被专业的从业者放入他们的季节。有趣的是,这些从业者经常不同意将图像放在哪个季节,尤其是在边缘情况下。
鉴于带摄像头的智能手机的普及,这难道不是自动识别一个人的季节的自然领域吗?
因此,我们一群人研究、设计并部署了一个 iOS 应用程序,它就能做到这一点,即自拍肖像并识别那个人的季节。此外,我们向那个人展示了他们的季节性调色板,还为他们提供了增强现实功能——例如来自他们相机手机的实时视频流,显示了好的和不好的颜色。这在诸如服装店的场所是有用的。
Augmented Reality in a Clothing Store for an Autumn
这个版本的应用程序存在一些挑战,最重要的是,由于光照和人像自拍构图的变化,季节性分配缺乏可重复性。我们已经在下面的分析中解决了这个问题,并计划在不久的将来发布一个更有效的应用程序。
通过使用我们的应用程序,我们有超过 10 万张人类的自拍照。这个集合并不代表人类在年龄、性别、地理和种族上的分布。一种有用的方式是把这些肖像想象成“对 iPhone 感兴趣的时尚人士”。这些肖像自拍只是为了分析而收集的。用户在提供他们的自拍肖像之前同意这一条款,这些在个人层面上是不可用或不显示的。
给定这组人像自拍的数据集,我们能学到什么?让我们测试一下假设,在我们的数据中确实有季节来对个体进行分类。
对肖像进行分类
评价一幅肖像的本质在于把肖像图像分解成身体部位——皮肤、头发、眼睛、嘴唇。每一个身体部位的颜色都代表了这个人,并引导我们找到他们的颜色。这是一个至关重要的假设——季节性颜色分配是基于关键的身体部位颜色。
简而言之,这个过程是一个简单的管道:
- 过滤掉糟糕的图像——那些过度亮/暗的图像,那些阴影很深的图像,戴着眼镜/帽子的图像,等等。
- 自动白平衡图像——通过对机器学习网络的广泛训练,我们在显示“真实”人类方面取得了良好的效果。作为一个练习,浏览一组脸书的自拍照,看看明显的人类肤色的广泛变化!
Before / After — Automatically adjusting White Balance for good skin tones
- 识别身体部位-使用图像处理和额外的机器学习来识别皮肤、头发、眼睛(虹膜)、眼睛(巩膜-白色)和嘴唇。
Sample body part images — hair, skin, iris, sclera, lips — from various models
- 对这些身体部位的颜色进行分类——包括平均颜色和代表颜色的等级,以便抓住更微妙的次要颜色的丰富性。
就这样——我们现在有了自拍肖像的数字表示,可以进行分析了。
聚类分析
聚类分析意味着对肖像进行分组,以便相似的肖像在聚类中。这是数据分析中的常见任务。有许多方法和算法可用于聚类分析。我们聚类分析的输入是一组身体部位的一组颜色。输出是一组聚类和每个肖像对其聚类的标识。
以下结果使用了三个身体部位-皮肤、头发和虹膜。这些是根据它们在 Lab 颜色空间中的平均颜色而不是 RGB 进行聚类的。正如维基百科所说,Lab“被设计成在人类色觉方面是一致的,这意味着这些值的相同数量的数字变化对应于大约相同数量的视觉感知变化。”也就是说,我们已经用多个身体部位和各种颜色空间进行了评估,以获得类似的结果。
识别聚类的第一种方法被称为肘方法。从 1 到 30 的聚类被评估它们的聚类程度。聚类数量的最佳表示是在图中有一个弯头的地方。
Elbow method to determine optimal clustering — using Skin, Hair, Iris in Lab colorspace
季节色彩分析会让我们相信,应该有两个——温暖/凉爽——和四个——季节的清晰和明显的集群。在此图中,并没有突出显示“肘部”在哪里,是 2 个、3 个、4 个还是 5 个集群?
另一种方法是层次聚类。这可以根据每个模型的身体部位颜色之间的距离来识别聚类。输出显示为树状图——一种树形结构。在图表中,Y 轴代表肖像之间的亲密程度。解释该图表以识别聚类的方法是找出聚类一致的大 Y 长度。
Dendrogram — using Skin, Hair, Iris in Lab colorspace
使用这种方法,人们可以清楚地看到两个簇接着四个簇的解释。这符合当季色彩的诠释。
季节性颜色分析中的一个概念是对两个部分的聚类可以/应该基于皮肤的暖色/冷色。在色轮上,暖色通常与色轮的顶部相关——红色到黄色——而冷色是另一侧——或者蓝色到紫色。传统上,“温暖”包括春季和秋季,而“凉爽”包括夏季和冬季。
在我们的一组代表性数据中,肤色似乎都是暖色,即(惊喜!)肉色,随着色调的变化,集群似乎均匀分散。换句话说,双聚类模型对肤色/色调没有帮助。尽管注意到这种温度与色调的关联通常被认为是心理上的而不是物理上的,指的是确定温度的“底色”。这种基调没有出现在数据中。
Skin Hues in the two cluster classification
四个星团——它们是季节吗?大考
如果我们从之前的树状图聚类图中提取四个聚类模型,我们可以测试它们是否映射到季节。四个聚类中每个聚类的实际平均颜色在该图表的底部以图形方式显示。
为了测试我们的聚类,我们将我们的聚类任务与一位流行的季节性色彩专家的任务进行了对比。因为我们不知道季节如何映射到这些新发现的聚类,所以我们需要尝试所有的组合,例如,尝试将聚类 1 作为春天,然后将聚类 1 作为夏天,等等。总而言之,对于可能的季节,我们的星团有 24 种可能的组合。完美的映射是 100%,而完全随机的映射是 25%。从经验来看,我希望有 80%-90%的映射能够成功。
对于我们的聚类到专家季节分类的最佳映射,有 36%的匹配百分比。这不是一张可信的地图。
忽略总映射(每个季节映射到一个集群,但一次只关注一个季节),最佳映射是冬季到集群二,顺便说一下,这看起来有些合适。其次是夏想的集群三。然而,尽管完美的映射将再次是 100%,但是冬季到聚类 2 的映射百分比仍然只有 47%,而夏季到聚类 3 的映射百分比仍然是 45%——这仍然是一个很差的、不可信的结果。
总结
我们已经表明,在我们超过 10 万张自拍肖像和季节性色彩分析模型之间,充其量只有微弱的联系——我们看到每类随机分配 25%,但远远没有达到预期的 80–90%。这通过各种聚类技术、暖/冷评估的应用以及季节性颜色的专家分配的应用来显示。可以有多种方式来反对我们的解释,从自拍肖像的颜色提取不良到我们的数据集与他人的问题。我们尊重所有的挑战,但保留这项调查正在开始的警告——但根据时尚科学的规则——这是在可能的情况下对基于事实的分析的强烈偏好。
这项工作包含了对时装业的强烈暗示。根据颜色对细分市场进行更加精确和真实的识别,可以更好地调整设计、营销甚至零售。
我们正在以各种方式继续这项工作。作为这项工作的一个分支,一个有趣的方法是创建动态调色板——或个性化调色板,而不是季节或集群。这进一步提供了将调色板调整到特定身体部位着色的优点,例如染发剂、唇彩等。以及变化的照明条件,例如阳光、舞厅、办公室等。
请继续关注我们的研究,分享数据集和代码!
(Preliminary) Creation of Personalized Palette based on Color Harmonies
Fast.ai 库:第一印象
最近尝试了一下 fast.ai 深度学习库,想分享一下经验。
首先,我的背景——不是为了展示我有多酷/多坏,而是因为它主要与像我一样思考和编码的人相关,而与其他人不太相关。
我从来没有学过软件工程,所有的事情都是自学的。从 **C++和 matlab 开始,**在我参与的 caffe 工作了 3 年,然后转到 python 和 pytorch 。大多数情况下,我写脏代码,并不关心它是否是次优的和不可伸缩的,除非它成为瓶颈。我很少在尝试做某件事之前阅读文档。
也就是说,我可以设计并实现干净、可扩展且高效的软件——就像我曾经在一家名为“先拍照后购买”的时尚初创公司担任首席技术官一样。但这需要时间,而且不适合深度学习研究的快速原型制作,所以大多数情况下我不愿意这么做。我也是 Jupyter 笔记本的粉丝。
先从 fast.ai 的好东西说起,然后描述一下我经历过的挑战。
fast.ai 里的牛逼东西
- 微数据集。我无法表达微数据集对于快速调试、可再现性、健全性检查和学习有多酷。
https://github.com/fastai/fastai/blob/master/examples/vision.ipynb
2.学习率+wd+动量和增量的默认参数。这可能看起来是小事,但关系重大。当你试图让工作变得疯狂时,一切都可能出错。数据,采样,缩放,一切。从等式中去掉两个主要的东西是一件解放大脑的大事
https://docs.fast.ai/vision.transform.html#Data-augmentation-details
- lr_find() ,一个周期策略和 concat 池。Lr_find 是非常强大而简单的方法,来自 Leslie N. Smith 的“训练神经网络的循环学习率”,该论文值得 NIPS/ICML 的最佳论文,但可能会被忽视。fast.ai 保存并提升。想法很简单——用不同的 lr 做一个小批量 SGD,重新编码,选择最好的一个。
https://docs.fast.ai/basic_train.html#lr_find
它工作得很好:当我们为硬网络论文写代码并做实验的时候,我们花了大约 1 周的时间去发现并相信 lr = 10 是好的。使用 lr_find 和 one_cycle,我可以从 2 次尝试中恢复几乎相同的性能。
ConcatPool 是简单的[avg,max]池。根据我的经验,这是仅次于宝石池的第二好选择。
太棒了,但是只有当你摸它们的时候
- 。复试。** 这是最重要的事情**,这可能在 fast.ai 课程中已经提到很多了,但对于外行人来说一点也不明显,尤其是当你只是谷歌那些不起作用的东西,而不是仔细阅读文档的时候。
我如何尝试新事物?在 vim 中打开 train.py,把一些代码放在不同的地方,通常利用全局可见的变量(也有风险,但谁在乎呢)。因为我是那种“宁愿花一周时间在谷歌上搜索一些东西,也不愿占用别人的时间寻求帮助”的人 Radek Osmulski ,我花了两天时间(虽然不是全职)试图找出如何在 fast.ai 中做同样的事情
我几乎要放弃了,但后来找到了回调,并意识到它们是我所需要的。我只是不知道该找什么。Fast.ai 开发者标记了“插入你代码的地方”,你可以通过写回调来访问它们。您还可以全面访问所有变量。
My explanation of what fast.ai callbacks are — just marked places to put your code.
对我没用的东西
它们大多是测试时的东西,不在“单一输入—单一类输出”的范例中。例如,我的网络有 5 个独立的头(OK,4 个独立的和 1 个相关的),并输出 2 个列表:一个列表具有来自 5 个分类器的预测,另一个具有 4 个 512d 特征。这足以打破许多现成的功能。
所有故障实例都可以从这里重现:https://github . com/ducha-aiki/whale-identificati on-2018/blob/master/reproduct _ problems . ipynb
- learn.predict()摘自推理教程:
2.好的,我可能应该使用函数 get_preds(),它根据教程给出了原始输出,对吗?不对。
********
Things which work with tutorial (left), do not work for me.
3.最后一次尝试,测试时间增加
Again, when output is list, not tensor, nothing works out of the box
不要误会我的意思,这些都不是严重的问题:我很容易就构建了工作区,尽管不是以 fast.ai 的方式
Not nice, but works
对于测试时的增强,我只是切换了转换。另一个问题:我还没有找到如何使火车装载机是非洗牌,所以在肮脏的方式:
Poor-man TTA
4.fp16 从来没有为我工作过,结果是失败。我现在已经尝试了 fast.ai 的最新版本,但是不知何故其他东西被改变了,以前工作的代码现在不工作了。我已经经历过几次了,所以:
****5. fast.ai 真的很快,这很好,但也有它自己的缺点:你不能只是更新版本,然后希望什么都不会坏。特别简单的改名都很烦。
我也有一些其他问题,但现在认为它们不值得一提——它们更像是我的错,而不是图书馆的错。
总之,我很高兴我已经尝试了 fast.ai,并且可能也会在我的研究项目中使用它。
快速简便地将开放的街道地图数据动态导入到 Google 工作表文件中
问题概述
你在一家管理意大利大城市地铁运输的公司担任业务分析师,你需要向营销和传播部门提供该地区酒吧和咖啡馆的列表,并向他们分发可以贴在窗户上或房间内的地图。此外,销售部门将联系离车站最近的酒吧和咖啡馆,提议加入贵公司提供的交通服务的售票计划。
这是一个每月发生的定期请求。
数据源
这类地理相关问题的主要数据源之一是公开的街道地图。
有几种方法可以访问开放的街道地图数据库,但是最流行的方法之一是使用天桥 API。在本文中,我们将看到如何使用这些 API 在 Google Sheet 中生成一个动态列表,该列表由参数化查询生成,并由最终业务用户设置值。通过这种方式,其他同事可以自己获取数据,并可以复制、编辑或保存列表以供将来操作,例如将每个酒吧或咖啡馆分配给一个将联系该结构的重要客户经理。
通过天桥 API 的查询可以使用两种语言:天桥 XML 或天桥 QL。
这次我们将使用天桥 QL,,一种用 C 风格语法编写的命令式编程语言。学习这门语言的主要“入门”指南可在本页找到。
数据析取
让我们总结一下我们需要提取的内容:
- 文本输出,我们将使用标准的 CSV 格式,标题在第一行,用逗号作为列分隔符,Google Sheet 会喜欢这个选择的!
- 指定区域的酒吧和咖啡馆列表;
- 经营场所必须在地铁站入口 X 米半径范围内。
要提取的属性的细节变化很大,并且不是每个场所的所有信息都被完全编辑,与其他国家(首先是德国)相比,可能有许多细节字段仍然不完整(例如电话号码或营业时间)。
超时将在 20 秒后修复。商业用户将不能轻易改变这个值。增加它是不合适的,因为我们想要提取的数据并不大,并且以下规则适用:
"如果查询运行时间超过此时间,服务器可能会超时中止查询。第二个影响是,这个较高的值,服务器可能会在执行查询之前拒绝它。
让我们来设置查询!
正如预期的那样,我们希望提取特定区域的酒吧和咖啡馆列表。这些元素在 OSM 数据库中用以下标签分类:
- 舒适=酒吧
- 舒适=咖啡馆
当我们必须使用天桥 API 时,要遵循的一个好规则是查阅与我们想要提取的标签相关的 TagInfo 页面:
- 【https://taginfo.openstreetmap.org/tags/?key=amenity 价值=咖啡馆#概述
- https://taginfo.openstreetmap.org/tags/?key=amenity&值=条形#概述
在这里,我们可以找到各种有用的信息。在“ combination ”选项卡中,我们找到了与该标签相关的特性列表,这是制作我们想要提取的列列表的良好起点,稍后我们将在项目中指定这些列。
**在“概述”选项卡中,我们可以看到这个地方在数据库中是如何编码的。在这种情况下,我们很容易看到,酒吧和咖啡馆可以是节点,方式或关系。**出于我们的目的,该信息是基本的,因为在查询中我们将指定在所有这些实体中进行搜索,并且因为我们知道该信息可以存储为点(节点)或更大的区域(方式)。在这个项目中,我们显然希望只提取一次与酒吧/咖啡馆相关的信息,因此我们希望获得的纬度和经度坐标是线所包围区域的中心坐标。
让我们举一个例子,在一个方形条的情况下,在 OSM 数据库中有四个 way 元素,但是我们希望在表中所有这些都在一行中表示,考虑到条总是相同的(相同的名字,相同的电话号码,…)。这一目的将通过指示立交桥仅提取该区域的中心来实现。
查询中要考虑的最后一个元素是我们要提取的区域。我们选择使用每个自治市的边界提取数据,这些数据将在表格的用户填写的输入单元格中显示,记住一些地铁站位于不同的自治市。
从这张有用的表中,我们可以了解到,意大利直辖市的行政边界在 OSM 数据库中用 8 级表示。
至此,我们已经拥有了构建查询的所有元素:
我们考虑了酒吧/咖啡馆和车站入口之间的固定距离值(50 米)的查询,以及固定的自治市(ISTAT 代码 015146 对应于米兰市),因此我们必须修改查询,使其可用于 Google sheet。
如何在电子表格中使用查询
我们需要遵循以下步骤:
- 在 内包含查询 IMPORTDATA 公式(阅读 Google Sheet 官方指南);
- 用嵌套双引号替换单单双引号;
- 将距离值替换为*&B5&*;
- 用*&B4&*替换市 ISTAT 代码的值。
我们最后得出以下结论:
通过链接到隐藏表的数据验证和获得 ISTAT 代码的 VLOOKUP 公式 ,我们可以制作一个用户友好的下拉菜单,用户可以从中选择自治市的名称和要考虑的距离值。
每次单元 B3 或单元 B4 发生变化时,服务地址列表的值都会更新。
使用 Nvidia DALI 在 PyTorch 中快速增强数据
原帖:https://www . basic ml . com/performance/2019/04/16/py torch-data-augmentation-with-NVIDIA-Dali
在我工作的新项目中,我必须为多标签多类别分类任务处理一组足够大的图像数据。尽管 GPU 利用率接近 100%,但运行超过 200 万张图像的单个训练时段需要近 3.5 小时。如果您正在进行基线实验,并且想要快速得到结果,这是一个大问题。我首先想到的是,由于我在处理原始大小的图像,每个图像至少有几兆字节,所以瓶颈是磁盘 I/O。我使用 Imagemagick mogrify 来调整所有 200 万张图像的大小,这花了很长时间。令我惊讶的是,调整图片大小根本没有减少训练时间!嗯,不明显。因此,我仔细检查了代码,发现主要的瓶颈是 PyTorch 中的图像增强操作。
在偶然发现 Github 的时候,我发现在 Nvidia 工作的人最近发布了一个库——DALI,据说就是为了解决这个问题。该库仍在积极开发中,并支持所有主要 ML 开发库的快速数据扩充— PyTorch , Tensorflow , MXNet 。
Fig 1: A typical data augmentation pipeline
使用 Nvidia DALI,可以通过将适当的操作移到 GPU 来优化上述数据流水线。使用 DALI 后,管道看起来像这样-
Fig 2: Fig 2: An Nvidia DALI pipeline
有关 DALI 功能的更多细节,请参见这篇由 Nvidia 开发人员撰写的初学者友好帖子,标题为使用 NVIDIA DALI 进行快速 AI 数据预处理。在这篇文章的剩余部分,我将展示如何将 Nvidia DALI 合并到 PyTorch 代码中。欢迎读者对下面的代码提供可能的改进。
我们从安装所需的依赖项开始。
到目前为止,您已经完成了“nvidia-dali”的安装,我们现在将把它集成到我们的 PyTorch 代码中。为了创建虚拟数据集,我们下载了由 Udacity 提供的花卉分类数据。数据集包含两个文件夹——“训练”和“有效”。我们使用“train”文件夹中的图像,并展平目录,该目录组织为一个分层文件夹,包含按标签排列的图像,每个标签有一个子文件夹。我们不使用提供的标签,而是生成虚拟标签进行演示。
接下来,我们创建一个空格分隔的文件,它符合 Nvidia DALI 官方文档页面上给出的示例。
接下来,我们创建一个“ExternalInputIterator ”,它对我们的数据进行批处理,并由 DALI 管道用来输入数据,并将其馈送给相应的设备进行处理。下面的代码改编自官方代码这里为多个标签工作。感谢悉达多甘居指向官方教程。
接下来,我们实例化该迭代器,并将其作为输入提供给‘externalsourcepipeline ’,该‘externalsourcepipeline’扩展了‘pipeline’类,并将数据提供给相应的设备用于增强操作。
我们差不多完成了,现在我们实例化一个“DALIGenericIterator ”,它帮助我们迭代数据集,就像我们在 PyTorch 中通常做的那样。
谷歌 Colab: 笔记本
我还没有在我的代码中对 DALI 进行基准测试,一旦有了结果,我会更新这篇文章。
保持优雅。
链接:
-达利 Github 回购
-大理官方博客文章
快速傅里叶变换
Photo by Fré Sonneveld on Unsplash
如何从零开始用 Python 实现快速傅立叶变换算法?
如果你有电气工程的背景,你很可能听说过傅立叶变换。通俗地说,傅立叶变换是一种将信号的域(x 轴)从时间改变到频率的数学运算。后者对于分解由多个纯频率组成的信号特别有用。更多细节请看下面的视频。
傅立叶变换的应用不限于数字信号处理。事实上,傅立叶变换可以加速卷积神经网络的训练过程。回想一下卷积层如何在图像的一部分上覆盖内核,并对该位置的所有值执行逐位乘法。然后,内核被转移到图像的另一部分,并且重复该过程,直到它遍历了整个图像。
傅立叶变换可以通过利用以下特性来加速卷积。
上面的等式表明,两个信号的卷积等价于它们的傅立叶变换的乘法。因此,通过将输入变换到频率空间,卷积变成单个元素的乘法。换句话说,卷积层和内核的输入可以使用傅立叶变换转换成频率,乘以一次,然后使用傅立叶逆变换转换回来。存在与将输入变换到傅立叶域和傅立叶逆变换以将响应返回到空间域相关联的开销。然而,这被从执行单次乘法而不是将图像的不同部分与内核相乘获得的速度所抵消。
离散傅里叶变换
离散傅立叶变换(DTF)可以写成如下形式。
为了确定离散信号x[n]
(其中N
是其域的大小),我们将它的每个值乘以n
的某个函数的e
。然后我们对给定的n
的结果求和。如果我们使用计算机来计算信号的离散傅立叶变换,它需要执行 N(乘法)x N(加法)= O(N)次运算。
顾名思义,快速傅立叶变换(FFT)是一种确定输入的离散傅立叶变换的算法,比直接计算要快得多。用计算机科学的行话来说,FFT 将大小为N
的问题所需的计算次数从O(N^2)
减少到O(NlogN)
。
表面上看,这似乎没什么大不了的。然而,当 N 足够大时,它可以产生一个不同的世界。请看下表。
假设执行一次操作需要 1 纳秒。对于大小为N = 10
⁹.的问题,快速傅立叶变换算法需要大约 30 秒来计算离散傅立叶变换相比之下,常规算法需要几十年的时间。
快速傅立叶变换算法
假设,我们将傅立叶变换分成偶数和奇数索引子序列。
在做了一点代数运算后,我们得到了两项的和。这种方法的优点在于可以同时计算偶数和奇数索引子序列。
假设,N = 8
,为了可视化数据随时间的流动,我们可以利用一个蝴蝶图。我们同时计算偶数和奇数项的离散傅立叶变换。然后,我们使用上面的公式计算x[k]
。
我们可以用大 O 符号来表示增益,如下所示。第一项来自于我们两次计算离散傅立叶变换的事实。我们将后者乘以在一半原始输入上计算离散傅立叶变换所花费的时间。在最后一步,需要N
步来累加特定k
的傅立叶变换。我们通过在最终产品中添加N
来说明这一点。
请注意,我们是如何将傅里叶变换的计算时间缩短了 1/2 的。我们可以通过应用分治法来进一步改进算法,每次将计算成本减半。换句话说,我们可以继续分割问题大小,直到我们剩下两个一组,然后直接计算每一对的离散傅立叶变换。
只要N
是 2 的幂,你可以分成两等份的最大次数由p = log(N)
给出。
如果我们使用问题大小为N = 8
的快速傅立叶变换算法,结果会是这样。请注意我们是如何划分p = log(8) = 3
阶段的。
Python 代码
让我们看看如何使用 Python 从头开始实现快速傅立叶变换算法。首先,我们导入numpy
库。
import numpy as np
接下来,我们定义一个函数来直接计算离散傅立叶变换。
def dft(x):
x = np.asarray(x, dtype=float)
N = x.shape[0]
n = np.arange(N)
k = n.reshape((N, 1))
M = np.exp(-2j * np.pi * k * n / N)
return np.dot(M, x)
通过将结果与从 numpy 的fft
函数获得的结果进行比较,我们可以确保我们的实现是正确的。
x = np.random.random(1024)
np.allclose(dft(x), np.fft.fft(x))
我们可以清楚地看到,离散傅里叶变换函数比快速傅里叶变换算法慢几个数量级。
%timeit dft(x)
%timeit np.fft.fft(x)
就像我们之前看到的,快速傅立叶变换的工作原理是计算整个问题的小子集的离散傅立叶变换,然后组合结果。后者可以使用递归在代码中轻松完成。
def fft(x):
x = np.asarray(x, dtype=float)
N = x.shape[0]
if N % 2 > 0:
raise ValueError("must be a power of 2")
elif N <= 2:
return dft(x)
else:
X_even = fft(x[::2])
X_odd = fft(x[1::2])
terms = np.exp(-2j * np.pi * np.arange(N) / N)
return np.concatenate([X_even + terms[:int(N/2)] * X_odd,
X_even + terms[int(N/2):] * X_odd])
同样,我们可以通过比较从 numpy 获得的结果来验证我们的实现是否正确。
x = np.random.random(1024)
np.allclose(fft(x), np.fft.fft(x))
FFT 算法比直接实现要快得多。然而,它仍然比 numpy 实现落后很多。其中一个原因是 numpy 实现使用矩阵运算来同时计算傅立叶变换。
%timeit dft(x)
%timeit fft(x)
%timeit np.fft.fft(x)
我们定义另一个函数来计算傅立叶变换。只是这一次,我们利用了向量运算而不是递归。
def fft_v(x):
x = np.asarray(x, dtype=float)
N = x.shape[0]
if np.log2(N) % 1 > 0:
raise ValueError("must be a power of 2")
N_min = min(N, 2)
n = np.arange(N_min)
k = n[:, None]
M = np.exp(-2j * np.pi * n * k / N_min)
X = np.dot(M, x.reshape((N_min, -1)))while X.shape[0] < N:
X_even = X[:, :int(X.shape[1] / 2)]
X_odd = X[:, int(X.shape[1] / 2):]
terms = np.exp(-1j * np.pi * np.arange(X.shape[0])
/ X.shape[0])[:, None]
X = np.vstack([X_even + terms * X_odd,
X_even - terms * X_odd])return X.ravel()
同样,通过与 numpy 库中的结果进行比较,我们可以确保获得正确的结果。
x = np.random.random(1024)
np.allclose(fft_v(x), np.fft.fft(x))
正如我们所看到的,使用向量运算的 FFT 实现比我们以前获得的要快得多。我们仍然没有接近 numpy 库计算傅立叶变换的速度。这是因为 numpy 的fft
背后的 FFTPACK 算法是一个 Fortran 实现,经过了多年的调整和优化。如果您有兴趣了解更多,我建议您看看源代码。
%timeit fft(x)
%timeit fft_v(x)
%timeit np.fft.fft(x)
Ray Tune:一个 Python 库,可以在任意比例下快速调整超参数
在不改变代码的情况下,将您的搜索从笔记本电脑扩展到数百台机器。 验出雷调 。
如果你曾经试图调整机器学习模型的超参数,你就会知道这可能是一个非常痛苦的过程。简单的方法很快变得耗时。
现在,您比以往任何时候都更需要尖端的超参数调整工具来跟上最先进的技术。
模型的进步越来越依赖于更新更好的超参数调整算法,如基于人口的训练 ( PBT )、HyperBand 和 ASHA。
Population-based Training improves DeepMind’s state-of-the-art algorithms on many domains by significant margins. Source: https://deepmind.com/blog/population-based-training-neural-networks/
这些算法提供了两个关键优势:
- 他们将模型性能最大化:例如,DeepMind 使用 PBT在星际争霸上实现超人性能;Waymo 使用 PBT 来启用自动驾驶汽车。
- 他们最大限度地降低培训成本 : HyperBand 和 ASHA 收敛到高质量配置所需时间是以前方法的一半;基于人口的数据增强算法将成本削减了几个数量级。
事实是,绝大多数研究人员和团队没有利用这样的算法。大多数现有的超参数搜索框架没有这些更新的优化算法。一旦达到一定规模,大多数现有的并行超参数搜索解决方案可能会很难使用——您需要为每次运行配置每台机器,并且通常需要管理单独的数据库。
实际上,实现和维护这些算法需要大量的时间和工程。
但是不需要这样。没有理由为什么您不能轻松地将超参数调整集成到您的机器学习项目中,在您的集群中的 8 个 GPU 上无缝地运行并行异步网格搜索,并在云上大规模利用基于群体的训练或任何贝叶斯优化算法。
在这篇博文中,我们将介绍 RayTune,这是一个强大的超参数优化库,旨在消除缩放实验执行和超参数搜索之间的摩擦。
Tune scales your training from a single machine to a large distributed cluster without changing your code.
RayTune 是一个强大的库,可以加速超参数优化。以下是一些核心功能:
- RayTune 提供了现成的分布式异步优化。
- RayTune 提供最先进的算法,包括(但不限于)【ASHA】【BOHB】基于群体的训练。
- 您可以将 RayTune 超参数搜索从单台机器扩展到大型分布式集群,而无需更改您的代码。
- RayTune 集成了许多优化库,如 Ax/Botorch 、 HyperOpt 和贝叶斯优化,使您能够透明地扩展它们。
- RayTune 支持任何机器学习框架,包括 PyTorch、TensorFlow、XGBoost、LightGBM、scikit-learn 和 Keras。
除了 RayTune 的核心特性之外,研究人员和开发人员更喜欢 RayTune 而不是其他现有超参数调优框架的两个主要原因是:规模和灵活性。
Note for Search Algorithms: as of 8/12/2019, HpBandSter supports HyperBand, Random Search, and BOHB. KerasTuner supports Random Search, HyperBand, and Bayesian Optimization. Optuna supports Median (Percentile) Stopping, ASHA, Random Search, and Bayesian Optimization (TPE). HyperOpt supports Bayesian Optimization and Random Search. Tune supports PBT, BOHB, ASHA, HyperBand, Median Stopping, Random Search, Bayesian Optimization (TPE, etc), and numerous others due to library integrations.
调整简化了缩放。
通过添加不到 10 行 Python 代码,利用机器上的所有内核和 GPU 来执行并行异步超参数调优。
If you run into an ImportError, try installing from a snapshot wheel: https://ray.readthedocs.io/en/latest/installation.html#trying-snapshots-from-master
https://twitter.com/MarcCoru/status/1080596327006945281
使用另一个配置文件和 4 行代码,在云上启动大规模分布式超参数搜索,并自动关闭机器(我们将在下面向您展示如何做到这一点)。
借助 Tune 的内置容错、试验迁移和集群自动扩展,您可以安全地利用 spot(可抢占)实例,并将云成本降低高达 90%。
调谐是灵活的。
Tune 与实验管理工具无缝集成,如 MLFlow 和 TensorBoard 。
Tune 为优化算法提供了一个灵活的接口,允许您轻松实现和扩展新的优化算法。
您可以使用 Tune 来利用和扩展许多最先进的搜索算法和库,如 HyperOpt (如下)和 Ax ,而无需修改任何模型训练代码。
使用 Tune 很简单!
现在让我们深入一个具体的例子,展示如何利用最先进的早期停止算法(ASHA)。我们将首先在您工作站上的所有内核上运行 Tune。然后,我们将用大约 10 行代码在云上扩展相同的实验。
我们将在这个例子中使用 PyTorch,但是我们也有可用的 Tensorflow 和 Keras 的例子。
Tune 作为射线的一部分安装。要运行这个示例,您需要安装以下软件:pip install ray torch torchvision.
你可以在这个博客这里下载完整版的博客。
我们首先运行一些导入:
header of tune_script.py
让我们用 PyTorch 写一个神经网络:
要开始使用 Tune,在 PyTorch training below 函数中添加一个简单的日志记录语句。
def train_mnist(config):
model = ConvNet()
train_loader, test_loader = get_data_loaders()
optimizer = optim.SGD(
model.parameters(),
lr=config["lr"],
momentum=config["momentum"])
for i in range(10):
train(model, optimizer, train_loader, torch.device("cpu"))
acc = test(model, test_loader, torch.device("cpu"))
**tune.track.log(mean_accuracy=acc)**
if i % 5 == 0:
# This saves the model to the trial directory
torch.save(model, "./model.pth")
注意,在上面的训练脚本中有几个助手函数;你可以在这里看到它们的定义。
运行曲调
让我们运行 1 次试验,从一个均匀分布中随机抽样,以获得学习率和动量。
现在,你已经完成了你的第一次跑调!您可以通过指定 GPU 资源来轻松启用 GPU 使用— 参见文档了解更多详细信息。然后我们可以画出这次试验的表现。
并行执行和提前停止
Early stopping with ASHA.
让我们集成 ASHA,一个可扩展的提前停止算法(博文和论文)。ASHA 终止了不太有希望的试验,并将更多的时间和资源分配给更有希望的试验。
使用num_samples
在机器上的所有可用内核中并行搜索(额外的尝试将被排队)。
您可以使用与上例相同的数据帧绘图。运行后,如果安装了 Tensorboard,还可以使用 Tensorboard 可视化结果:tensorboard --logdir ~/ray_results
走向分布式
建立一个分布式超参数搜索通常工作量很大。Tune 和 Ray 让这一切变得天衣无缝。
使用简单的配置文件启动云
Launch a cluster and distribute hyperparameter search without changing your code
首先,我们将创建一个配置光线簇的 YAML 文件。作为射线的一部分,Tune 与射线簇发射器之间的交互非常干净。下面显示的相同命令将在 GCP、AWS 和本地私有集群上工作。除了一个头节点之外,我们还将使用 3 个工作节点,因此集群上总共应该有 32 个 vCPUs,这使我们能够并行评估 32 个超参数配置。
tune-default.yaml
把东西放在一起
要在光线簇中分布超参数搜索,需要将它附加到脚本的顶部:
考虑到计算的大幅增长,我们应该能够增加搜索空间和搜索空间中的样本数量:
你可以在这个博客(作为tune_script.py
)下载完整版的剧本。
启动你的实验
要启动您的实验,您可以运行(假设到目前为止您的代码在一个文件tune_script.py
中):
$ ray submit tune-default.yaml tune_script.py --start \
--args=”localhost:6379”
这将在 AWS 上启动您的集群,将tune_script.py
上传到 head 节点上,并运行python tune_script localhost:6379
,这是 Ray 为支持分布式执行而打开的一个端口。
脚本的所有输出都会显示在您的控制台上。请注意,集群将在设置任何工作节点之前首先设置头节点,因此最初您可能只看到 4 个可用的 CPU。一段时间后,您可以看到 24 个试验被并行执行,其他试验将排队等候,一旦一个试验空闲,就立即执行。
要关闭集群,您可以运行:
$ ray down tune-default.yaml
你完了🎉!
了解更多信息:
Tune 还有许多其他特性,使研究人员和从业人员能够加速他们的开发。这篇博客文章中没有涉及的其他调整功能包括:
- 运行分布式容错实验的简单 API
- 通过的分布式超参数搜索为 PyTorch 进行分布式数据并行训练
- 基于人口的培训
对于能够访问云的用户,Tune 和 Ray 提供了许多实用程序,可以实现在笔记本电脑上开发和在云上执行之间的无缝过渡。文档包括:
- 在后台会话中运行实验
- 向现有实验提交试验
- 在 TensorBoard 中可视化分布式实验的所有结果。
Tune 旨在轻松扩展实验执行和超参数搜索。如果您有任何意见或建议,或者对 Tune 有兴趣,您可以联系我或 ray-dev 邮件列表。
代码:https://github . com/ray-project/ray/tree/master/python/ray/tune
文档:http://ray.readthedocs.io/en/latest/tune.html
关于超参数调整的其他阅读材料,请查看 Neptune.ai 关于 Optuna vs HyperOpt 的博文!
感谢彭于晏、埃里克·梁、乔伊·冈萨雷斯、扬·斯托伊察、尤金·维尼斯基、丽莎·邓拉普、菲利普·莫里茨、、阿尔文·万、丹尼尔·罗斯柴尔德、布里詹·塔南杰扬、阿洛克·辛格(也许还有其他人?)来通读这篇博文的各种版本!
用于目标检测的快速 R-CNN
技术论文摘要
在试图理解使用深度学习的对象检测的关键概念和里程碑时,之前关于使用 CNN【1】的区域的文章强调了有史以来第一个具有深度学习主干的检测器网络中每个阶段的功能和训练细节。这篇文章深入挖掘了它的热门继任者 Fast R-CNN 的细节。[2]
随着 2014 年 R-CNN 论文发表以来我们看到的技术进步和计算能力的增加,我们现在很容易看到作者当时发现的 R-CNN 的明显缺陷:
- **多阶段、昂贵的训练:**网络所有阶段所需的独立训练过程——在对象提议上微调 CNN,学习 SVM 以对来自 CNN 的每个提议的特征向量进行分类,以及学习边界框回归器以微调对象提议(更多细节请参考区域和 CNN)在时间、计算和资源方面被证明是一种负担。例如,为了训练 SVM,我们需要将前一阶段的数千个可能的区域提议的特征写入磁盘。
- **慢测试时间:**给定这种多级流水线,使用简单的 VGG 网络作为主干的检测 CNN 需要 47 秒/图像。
2015 年发表的另一篇论文 SPP-Nets 或“空间金字塔池网络”[3]解决了问题的一部分。它的主要贡献是 a)使用多尺度图像特征池来提高分类和检测的网络性能,以及 b)使用任意大小的输入图像来训练 CNN,尽管使用了全连接(FC)层。在其检测管道中,它引入了一个重要的概念——从整个图像中仅提取一次单个特征图,并从该单个特征图中汇集该图像的任意大小的“区域提议”的特征。这使得他们的网络运行速度比 R-CNN 快几个数量级。他们没有像 R-CNN 那样对 2000 个地区的提案运行 CNN,而是只有一个转发通道,可以从中汇集所有 2000 个候选提案的特征。
快速 R-CNN 流水线
架构细节:
为了更好地理解快速 R-CNN 如何以及为什么提高 R-CNN 和 SPP 网络的效率和性能,让我们首先来看看它的架构。
- 快速 R-CNN 由 CNN(通常在 ImageNet 分类任务上预先训练)组成,其最终池层由“ROI 池”层代替,其最终 FC 层由两个分支代替——一个(K + 1)类别 softmax 层分支和一个类别特定的边界框回归分支。
Figure 1: The Fast R-CNN pipeline
Figure 2: The ROI pooling layer as a special case of SPP layer
- 整个图像被馈送到主干 CNN,并且从最后的卷积层获得特征。取决于所使用的主干 CNN,输出的特征地图比原始图像尺寸小得多。这取决于中枢 CNN 的步幅,在 VGG 中枢的情况下通常是 16。
- 同时,对象提议窗口从类似选择性搜索的区域提议算法中获得[4]。正如在带 CNN 的区域中所解释的,物体提议是图像上的矩形区域,表示物体的存在。
- 然后,属于该窗口的主干特征图的部分被馈入 ROI 汇集层。
- ROI 池图层是只有一个金字塔等级的空间金字塔池(SPP)图层的特例。该层基本上将来自所选建议窗口(来自区域建议算法)的特征划分成大小为 h/H 乘 w/W 的子窗口,并在这些子窗口的每一个中执行汇集操作。这产生了大小为(H x W)的固定大小输出特征,而与输入大小无关。选择 h 和 W,使输出与网络的第一个全连接层兼容。在 Fast R-CNN 论文中 H 和 W 的选择值是 7。像常规池一样,ROI 池在每个渠道中单独进行。
- ROI 池层(N x 7 x 7 x 512,其中 N 是建议数量)的输出特征随后被送入后续 FC 层,以及 softmax 和 BB-regression 分支。softmax 分类分支产生属于 K 个类别和一个总括背景类别的每个 ROI 的概率值。BB 回归分支输出用于使来自区域提议算法的边界框更加精确。
损失:
softmax 层的分类分支给出了(K +1)个类别上每个 ROI 的概率 p = p₀,… pₖ.分类损失 L 𝒸ₗₛ (p,u) 由-log(pᵤ给出)是真实 u 类的对数损失
Equation 1: smooth L1 loss for BB regression
Equation 2: Joint loss for multi-task training
回归分支产生 4 个边界框回归偏移 tᵏᵢ,其中 *i = x,y,w,*和 h. (x,y) 代表左上角, w 和 h 表示边界框的高度和宽度。类别 u 的真实边界框回归目标由 v ᵢ表示,其中当 u≥1 *时 *i = x,y,w,*和 h 。*忽略 u=0 的情况,因为背景类没有背景事实框。使用的回归损失是等式 1 中给出的平滑 L1 损失。每个 ROI 的联合多任务损失由两个损失的组合给出,如等式 2 所示。请注意,这里的快速 R-CNN 有一个组合学习方案,可以微调主干 CNN,并对边界框进行分类和回归。
培训:
- 在训练期间,每个小批量由 N=2 个图像构成。小批量由来自每个图像的 64 个 ROI 组成。
- 像 R-CNN 一样,25%的 ROI 是具有至少 0.5 IoU 的对象提议,具有前景类的地面真实边界框。对于特定的类,这些将是正的,并且将被标上适当的 u=1…K。
- 其余感兴趣区域从 IoU 的基础边界框在[0.1,0.5]之间的提案中取样。这些 ROI 被标记为属于类别 u = 0(背景类别)。
- 直到 ROI 合并层之前,整个图像都要通过 CNN。这样,来自同一图像的所有 ROI 在向前和向后通过 CNN 时共享计算和内存(在 ROI 合并层之前)。
- 与 SPP 网络不同,采样策略(从非常少的图像中批量采样所有 ROI)允许整个模块(特征生成、分类和回归)一起训练。在 SPP 网络中,大多数输入 ROI 来自不同的图像,因此用于检测的训练过程仅在特征生成之后微调完全连接的层,因为在 SPP 层之前更新权重是不可行的(一些 ROI 在原始图像上可能具有非常大的感受野)。实际特征仍然来自为分类而训练的预训练网络。这限制了 SPP 网络的准确性。
- 请注意,在 ROI 合并层之前,CNN 网络的批次大小非常小(批次大小= 2),但在接下来的 softmax 和回归层中,网络的批次大小要大得多(批次大小= 128)。
其他注意事项:
- **通过 ROI pooling 层反向传播:**对于每个小批量 ROI *r,*让 ROI pooling 输出单元 yᵣⱼ 作为其子窗口 R(r,j)中最大池的输出。然后,如果该位置是为 yᵣⱼ.选择的 argmax,则在 R(r,j) 中的输入单元( xᵢ )中累积梯度
- 在快速 R-CNN 的多尺度流水线中,输入图像在训练时被调整为随机采样的尺寸,以引入尺度不变性。在测试时,每个图像以多个固定的比例被馈送到网络。对于每个 ROI,仅从这些尺度之一汇集特征,选择这些尺度使得缩放的候选窗口具有最接近 224×224 的像素数。然而,作者发现单尺度流水线的性能几乎一样好,而计算时间成本低得多。在单尺度方法中,训练和测试时的所有图像都被调整为 600(最短边),最长边的上限为 1000。
- 可以用截短的 SVD 来压缩大的全连接层,以使网络更有效。这里,由 w 作为其权重矩阵参数化的层可以被因式分解,以通过将它分成两层(具有偏差的σₜvᵀ和 u)来减少参数计数,而它们之间没有非线性,其中 w ~ u σₜvᵀ.
结果
- Fast R-CNN 在发布 VOC12、VOC10(含额外数据)和 VOC07 时实现了最先进的性能。
- 快速 R-CNN 在测试时处理图像的速度比 R-CNN 快 45 倍,在训练时快 9 倍。它的训练速度比 SPP-Net 快 2.7 倍,运行测试映像的速度比 SPP-Net 快 7 倍。在进一步使用截断 SVD 时,网络的检测时间减少了 30%以上,mAP 仅下降 0.3。
- 该论文的其他贡献表明,对于更大的网络,微调 conv 层(而不仅仅是 SPPnets 等 FC 层)对于实现更好的 mAP 非常重要。对于较小的网络,这种改进可能不会很大。
- 多任务训练不仅更容易,而且还能提高表现,因为训练时任务会相互影响。因此,训练网络的不同阶段一起提高了它的共享代表力量(骨干 CNN)
这就是 Fast R-CNN 论文的技术总结。希望你喜欢(理解)!欢迎在下面的评论中讨论或更正。
阅读快速 R-CNN 的继任者和最先进的物体探测网络——更快 R-CNN 这里。
参考资料:
[1] Girshick,Ross 等人,“用于精确对象检测和语义分割的丰富特征层次。”2014 年 IEEE 计算机视觉与模式识别会议(2014)
【2】Girshick,Ross。"快速 R-CNN "2015 年 IEEE 计算机视觉国际会议(ICCV)(2015)
【3】何,等,“用于视觉识别的深度卷积网络中的空间金字塔池”计算机科学讲义(2014)
[4] Uijlings,J. R. R .等,“物体识别的选择性搜索”国际计算机视觉杂志 104.2 (2013)
用 Turf.js 和命令行构建的快速静态 D3 地图
将 Mike Bostock 的命令行制图教程与 Node.js 的灵活性结合起来
Estimated percent of undocumented residents in U.S. metro areas. Source: Pew Research Center
最近,我需要制作一些美国各州的泡沫地图,嵌入到《圣安东尼奥快报新闻》的报道中。我想使用 D3,但担心缓慢的资产加载和地图渲染,特别是因为 CMS 的限制,我需要单独iframe
每个地图。
为了找到导出 D3 生成的 SVG 的方法,我进行了一些谷歌搜索。
这家伙做了个出口按钮,挺酷的。纽约时报有 SVG Crowbar ,提供类似的功能。然而,我发现的最令人兴奋的结果是这篇由四部分组成的文章,Mike Bostock 的。
我强烈推荐 Bostock 的文章,本教程的大部分内容都来源于此。我对他的方法的唯一问题是,对我来说,在命令行上编写 d3 代码会变得复杂和混乱。这里有一个片段:
**(topo2geo tracts=- \
< ca-topo.json \
| ndjson-map -r d3 -r d3=d3-scale-chromatic 'z = d3.scaleThreshold().domain([1, 10, 50, 200, 500, 1000, 2000, 4000]).range(d3.schemeOrRd[9]), d.features.forEach(f => f.properties.fill = z(f.properties.density)), d' \
| ndjson-split 'd.features'; \
topo2geo counties=- \
< ca-topo.json \
| ndjson-map 'd.properties = {"stroke": "#000", "stroke-opacity": 0.3}, d')\
| geo2svg -n --stroke none -p 1 -w 960 -h 960 \
> ca.svg**
我想找到一个利用 Node.js 的解决方案,允许我仍然从命令行使用 Bostock 的 d3-geo-projection ,但是将大部分制图操作和地图渲染的处理交给 JavaScript。这就是 Turf.js 的用武之地——一个用于编写和操作 GeoJSON 的令人惊叹的开源地理空间分析工具。
本教程一步一步地介绍如何使用 node 和命令行生成静态地图。我们将以 SVG 格式构建上述地图,该地图显示了美国 100 个最大的大都市区中无证居民比例最高的 50 个大都市区。
第一步:加载你的数据
地图需要的文件有:
- 2017 年皮尤研究中心研究的未记录居民数据。
- 定义美国城市区域位置的 shapefile。
- 定义美国各州轮廓的 shapefile。
启动命令行并创建一个工作目录:
**mkdir undocumented-residents-map
cd undocumented-residents-map**
创建一个 bash 文件,我们将使用它作为我们的主要构建脚本:
touch buildmap.sh
原始皮尤数据在处可用。我将其简化为两列,并将其存储在 data.world 上。shapefiles 由人口普查局提供。我们可以通过浏览器下载所有这些文件,但以编程方式进行更有趣。
在您最喜欢的文本编辑器中打开buildmap.sh
,写下如下内容:
上面有条件地下载并解压所有三个文件到我们的项目文件夹的根目录。
现在我们有了我们的资产,我们可以开始构建我们的地图。
第二步:将 Shapefiles 转换为 GeoJSON
我们将使用 NPM 包来实现这一点,所以现在是设置package.json
的好时机。
运行npm init
并按照提示生成 JSON。接下来,您需要将以下内容添加到生成的package.json
中:
**"scripts": { "buildmap": "sh buildmap.sh" }**
这将允许我们在当前 NPM 一揽子计划的背景下管理buildmap.sh
。
安装 Mike Bostock 的流 shapefile 解析器(npm i shapefile -D)
,并在buildmap.sh
的底部添加以下代码行,将我们的 shape file 转换为 GeoJSON:
这两个 GeoJSON 文件用于以下目的:
metroareas.geojson
:我们将使用地理数据将未记录的常驻 CSV 数据绑定到地图上。states.geojson
:我们将用来绘制地图背景的美国州轮廓。
最终,这两个文件将与 CSV 文件合并成一个主 GeoJSON 文件,我们将把它转换成 SVG。但是首先…
第三步:将位置数据添加到我们未记录的居民数据点
在这一步中,我们将使用 Node 将 CSV 中的数据(美国大都市区未登记居民的百分比)转换为 GeoJSON 文件中以各自大都市区为中心的缩放圆。
如果你是 GeoJSON 新手,我推荐你从维基百科页面开始。
我们输出的 GeoJSON 将包括 CSV 中每个大都市区域的单个要素-一个点。这些特征的坐标将从metroarea.geojson
中获得,每个点的“属性”对象将包括一个pointRadius
属性,用于相对于在该城市区域中发现的无证居民的相应百分比来缩放点的大小。
下面是我们将在 JS 文件中采取的步骤的概述:
- 将
metroareas.geojson
和metro-area-percent-undocumented.csv
转换为 JS 对象 - 过滤
metroareas.geojson
,只包括我们的 CSV 中也存在的城市区域 - 使用 Turf.js 找到每个都会区多边形的中心,并将我们的点固定到中心的坐标上。
- 在每个特性的“properties”对象中为我们的点添加样式(颜色等),包括我们的
pointRadius
属性,它是使用 d3 缩放的。 - 将要素集导出为新的 GeoJSON 文件。
首先,创建文件:
**touch mapMetroPathsToCircles.js**
打开mapMetroPathsToCircles.js
并编写以下代码,完成上述 5 个步骤,并在注释中详细说明每个步骤:
在将它添加到 bash 文件之前,我们需要安装所需的依赖项:
**npm i @turf/turf d3 csv-parse@3.1.3 -D**
然后,在buildmap.sh
中我们可以添加:
**node mapMetroPathsToCircles.js # Create circles.geojson**
第四步:将州轮廓添加到我们的城市区域 GeoJSON 中
现在我们有了圆形的地理图,但是没有背景图。因此,我们将合并到美国的州大纲中。
在命令行上:
**touch mapAndMergeStates.js**
用以下内容填充文件(注释中的详细信息):
最后把这个加到buildmap.sh
:
**node mapAndMergeStates.js # merge in states, output topo.geojson**
步骤五: 将 GeoJSON 转换为 SVG
我们现在有了主 GeoJSON 文件(topo.geojson
),可以将其转换为 SVG。
然而,我们应该首先对我们的数据应用地理投影,这样 SVG 就可以按比例生成。为此,我们将使用 Bostock 的地质项目。
我们还希望分割 GeoJSON,以便每个要素都在一行上。因此,当我们将 GeoJSON 转换为 SVG 时,每个要素将在 XML 中占据一个新行。当我们在本教程末尾使用命令行拼接图例时,这将非常有用。
安装:
**npm i d3-geo-projection ndjson-cli -D**
在buildmap.sh
的顶部,将您需要的投影(在我们的例子中是美国艾伯斯)和 SVG 输出的高度和宽度放入 bash 变量:
**# USA albers
PROJECTION='d3.geoAlbersUsa()'# Display height and width
WIDTH=960
HEIGHT=600**
然后在buildmap.sh
底部添加:
注意第 7 行,我们运行 sed 命令从 SVG 中提取最后一行:因为我们使用了ndjson-split
将 GeoJSON 转换为换行符分隔的 JSON 文件,所以我们的 SVG XML 也是换行符分隔的。因此,使用 sed 命令,我们去掉了 SVG 的右括号。当我们构建我们的 legend SVG 时,我们也将去掉它的左括号,并将两者连接到我们的最终输出中。
你可以在这里了解更多关于换行符分隔的 JSON 及其用法。
第六步:给我们的地图添加一个图例
我们快完成了。最后一步是使用 node 和 D3 生成 SVG 格式的图例,然后将所述图例合并到我们的地图中。
我们将使用 Brad Oyler 的 D3 节点库在 D3 手写我们的图例(并导出 SVG)。我们还将使用标志传入我们的 SVG 高度和宽度变量,并用minimit库解析所述标志。
安装:
**npm i d3-node minimist -D**
在命令行上创建我们的 JS 文件:
**touch buildLegend.js**
然后写下以下内容(细节再次在评论中):
现在,在buildmap.sh
中,我们可以添加:
上面运行buildLegend.js
,传入我们的 SVG 宽度和高度。然后,它使用tail
将图例和地图连接到我们的最终输出topo.svg
。
最后两行只是清理目录,删除不必要的文件。
我们完事了。!!在命令行上运行:
**npm run buildmap**
如果一切顺利,这应该会生成topo.svg
,看起来有点像这个。
作为参考,这里有一个回购包括所有这些文件的最终形式和一个直接链接到所述回购中的buildmap.sh
。
Fastai 与🤗变形金刚(伯特、罗伯塔、XLNet、XLM、迪沃伯特)
使用 Fastai 实现最先进的 NLP 模型进行情感分析的教程
在【2018 年初,杰瑞米·霍华德(fast . ai 的联合创始人)和塞巴斯蒂安·鲁德推出了通用语言模型微调文本分类 (ULMFiT)方法。ULMFiT 是第一个应用于 NLP 的迁移学习方法。因此,除了显著优于许多最先进的任务之外,它还允许在只有 100 个标记示例的情况下,匹配相当于基于 100 倍以上数据训练的模型的性能。
ULMFiT requires less data than previous approaches. (Howard and Ruder, ACL 2018)
我第一次听说 ULMFiT 是在杰瑞米·霍华德的一次 fast.ai 课程中。他演示了如何通过几行代码轻松实现完整的 ULMFiT 方法——多亏了fastai
库。在他的演示中,他使用了在 Wikitext-103 上预先训练的 AWD-LSTM 神经网络,并迅速获得了最先进的结果。他还解释了关键技术——也在 ULMFiT 中演示过——来微调模型,如区分学习率、逐步解冻或倾斜三角形学习率。
自从 ULMFiT 的引入,迁移学习在 NLP 中变得非常流行,然而谷歌(BERT,Transformer-XL,XLNet),脸书(RoBERTa,XLM)甚至 OpenAI (GPT,GPT-2)都开始在非常大的语料库上预先训练他们自己的模型。这一次,他们没有使用 AWD-LSTM 神经网络,而是使用了基于变压器的更强大的架构(参见注意力是你所需要的全部)。
虽然这些模型很强大,但是fastai
并没有将它们全部集成。幸好抱紧脸🤗创建了众所周知的[transformers](https://github.com/huggingface/transformers)
库。这个库以前被称为pytorch-transformers
或pytorch-pretrained-bert
,它汇集了超过 40 个最先进的预训练 NLP 模型(伯特、GPT-2、罗伯塔、CTRL……)。该实现提供了有趣的附加工具,如 tokenizer、optimizer 或 scheduler。
用于 TensorFlow 2.0 和 PyTorch 的最先进的自然语言处理🤗变形金刚(以前称为…
github.com](https://github.com/huggingface/transformers)
transformers
库可以是自给自足的,但是将它并入fastai
库提供了与强大的fastai
工具兼容的更简单的实现,如区分学习速率、逐步解冻或倾斜三角形学习速率。这里的要点是允许任何人——专家或非专家——轻松获得最先进的结果,并“让 NLP 再次变得不酷”。
值得注意的是,在fastai
中集成拥抱脸transformers
库已经在:
- Keita Kurita 的文章用快速 AI 微调 BERT 的教程,使
pytorch_pretrained_bert
库兼容fastai
。 - Dev Sharma 的文章将 RoBERTa 与 Fastai 一起用于 NLP ,这使得
pytorch_transformers
库与fastai
兼容。
虽然这些文章质量很高,但是它们的演示的某些部分不再与transformers
的最新版本兼容。
🛠集成变压器和 fastai 进行多类分类
在开始实现之前,请注意可以通过多种方式将transformers
集成到fastai
中。为此,我带来了——我认为是——最通用、最灵活的解决方案。更准确地说,我试图对两个库进行最小的修改,同时使它们与最大数量的 transformer 架构兼容。但是,如果你找到一个聪明的方法来实现这个,请在评论区告诉我们!
本教程的 Jupiter 笔记本版本可以在这个 Kaggle 内核上获得。
库安装
首先,您需要安装fastai
和transformers
库。为此,只需遵循此处和此处和的说明。
在这个演示中,我使用了已经安装了fastai
库的 Kaggle。所以我只是用命令安装了transformers
:
pip install transformers
用于本演示的库的版本是fastai 1.0.58
和transformers 2.1.1
。
🎬示例任务
选择的任务是对电影评论进行多类文本分类。
下载数千个项目的开放数据集+在一个平台上共享项目。探索热门话题,如政府…
www.kaggle.com](https://www.kaggle.com/c/sentiment-analysis-on-movie-reviews/data)
对于每个文本电影评论,模型必须预测情感的标签。我们根据分类精度评估模型的输出。情感标签是:
0→负
1→有点负
2→空档
3→有点正
4→正
使用pandas
将数据加载到DataFrame
中。
主变压器等级
在transformers
中,每个模型架构都与 3 种主要类型的类相关联:
- 一个模型类,用于加载/存储特定的预训练模型。
- 一个记号赋予器类,用于预处理数据并使其与特定模型兼容。
- 一个配置类,用于加载/存储特定型号的配置。
例如,如果您想使用 BERT 架构进行文本分类,您可以使用[BertForSequenceClassification](https://huggingface.co/transformers/model_doc/bert.html#bertforsequenceclassification)
作为模型类,使用[BertTokenizer](https://huggingface.co/transformers/model_doc/bert.html#berttokenizer)
作为标记器类,使用[BertConfig](https://huggingface.co/transformers/model_doc/bert.html#bertconfig)
作为配置类。
稍后,您将看到那些类共享一个公共的类方法from_pretrained(pretrained_model_name, ...)
。在我们的例子中,参数pretrained_model_name
是一个字符串,带有要加载的预训练模型/标记器/配置的快捷方式名称,例如bert-base-uncased
。我们可以在transformers
文档这里找到所有的快捷方式名称。
为了在类之间轻松切换——每个类都与一个特定的模型类型相关——我创建了一个字典,它允许通过指定正确的模型类型名来加载正确的类。
值得注意的是,在这种情况下,我们只对一个多类文本分类任务使用transformers
库。出于这个原因,本教程只集成了实现了序列分类模型的 transformer 架构。这些模型类型是:
- 伯特(来自谷歌)
- XLNet(来自谷歌/CMU)
- XLM(来自脸书)
- 罗伯塔(来自脸书)
- 蒸馏啤酒(来自拥抱脸)
然而,如果你想更进一步——通过实现另一种类型的模型或 NLP 任务——本教程仍然是一个很好的开端。
数据预处理
为了匹配预训练,我们必须以特定的格式格式化模型输入序列。
为此,您必须首先对进行标记,然后对文本进行正确的数字化。
这里的困难在于,我们将微调的每个预训练模型需要完全相同的特定预处理,即记号化 & 数值化,而不是在预训练部分使用的预处理。
幸运的是,来自transformers
的记号赋予器类提供了正确的预处理工具,对应于每个预训练的模型。
在fastai
库中,数据预处理是在DataBunch
创建期间自动完成的。
正如您将在DataBunch
实现部分看到的那样,记号赋予器和数值化器在处理器参数中以如下格式传递:
processor = [TokenizeProcessor(tokenizer=tokenizer,…), NumericalizeProcessor(vocab=vocab,…)]
让我们首先分析如何将transformers
记号赋予器集成到TokenizeProcessor
函数中。
自定义标记器
这一部分可能有点混乱,因为许多类被包装在一起,并且具有相似的名称。
继续,如果我们仔细观察fastai
的实现,我们会注意到:
[TokenizeProcessor](https://docs.fast.ai/text.data.html#TokenizeProcessor)
对象将Tokenizer
对象作为tokenizer
参数。[Tokenizer](https://docs.fast.ai/text.transform.html#Tokenizer)
对象将一个BaseTokenizer
对象作为tok_func
参数。[BaseTokenizer](https://docs.fast.ai/text.transform.html#BaseTokenizer)
对象实现函数tokenizer(t:str) → List[str]
,该函数获取文本t
并返回其令牌列表。
因此,我们可以简单地创建一个继承自BaseTokenizer
的新类TransformersBaseTokenizer
,并重写一个新的tokenizer
函数。
在这个实现中,要注意三件事:
- 由于我们没有使用 RNN,我们必须将序列长度限制为模型输入大小。
- 大多数模型需要在序列的开头和结尾放置特殊的标记。
- 像 RoBERTa 这样的一些模型需要一个空格来开始输入字符串。对于那些模型,应该在
add_prefix_space
设置为True
的情况下调用编码方法。
下面,您可以找到本教程中使用的 5 种模型类型的每个预处理要求的简历。您也可以在每个模型部分的拥抱脸文档中找到该信息。
伯特:[CLS] +代币+ [SEP] +填充
蒸馏瓶:[CLS] +代币+ [SEP] +填充
罗伯塔:[CLS] +前缀空格+记号+ [SEP] +填充
XLM: [CLS] +代币+ [SEP] +填充
XLNet:填充+令牌+ [SEP] + [CLS]
值得注意的是,在这部分实现中,我们不添加填充。
我们将在后面看到,fastai
会在DataBunch
创建期间自动管理它。
自定义数值化器
在fastai
中,[NumericalizeProcessor](https://docs.fast.ai/text.data.html#NumericalizeProcessor)
对象将一个[Vocab](https://docs.fast.ai/text.transform.html#Vocab)
对象作为vocab
参数。
通过这种分析,我建议采用两种方法来适应fastai
数控化器:
- 你可以像在 Dev Sharma 的文章中描述的那样(第 1 节。设置记号赋予器,检索记号列表并创建一个
Vocab
对象。 - 创建一个继承自
Vocab
的新类TransformersVocab
,并覆盖numericalize
和textify
函数。
即使第一个解决方案看起来更简单,Transformers
也没有为所有模型提供一个直接的方法来检索他的令牌列表。
因此,我实现了第二个解决方案,它针对每个模型类型运行。
包括分别使用numericalize
和textify
中的convert_tokens_to_ids
和convert_ids_to_tokens
功能。
注意:函数__gestate__
和__setstate__
允许函数导出和 load_learner 与TranformersVocab
一起正确工作。
定制处理器
既然我们已经有了自定义的记号赋予器和数值化器,我们就可以创建自定义的处理器。注意我们正在传递include_bos = False
和include_eos = False
选项。这是因为默认情况下fastai
添加了自己的特殊标记,这会干扰我们的自定义标记器添加的[CLS]
和[SEP]
标记。
设置数据发送
对于 DataBunch 创建,您必须注意将参数processor
设置为我们新的定制处理器transformer_processor
,并正确管理填充。
正如拥抱脸文档中提到的,伯特、罗伯塔、XLM 和迪尔伯特是具有绝对位置嵌入的模型,所以通常建议在右侧填充输入,而不是在左侧。关于 XLNET,它是一个具有相对位置嵌入的模型,因此,您可以在右侧或左侧填充输入。
定制模型
正如这里提到的和一样,每个模型的 forward 方法总是输出一个tuple
,其中包含各种元素,具体取决于模型和配置参数。在我们的例子中,我们只对访问逻辑感兴趣。
访问它们的一种方法是创建自定义模型。
为了使我们的转换器适应多类分类,在加载预训练模型之前,我们需要精确标签的数量。为此,您可以修改 config 实例,或者像 Keita Kurita 的文章中那样修改num_labels
参数。
学员:自定义优化器/自定义指标
在pytorch-transformers
中,拥抱脸实现了两个特定的优化器——BertAdam 和 OpenAIAdam——它们已经被一个 AdamW 优化器所取代。
这个优化器匹配 Pytorch Adam 优化器 Api,因此,将它集成到fastai
中变得很简单。
注意,为了重现贝塔姆的特定行为,你必须设置correct_bias = False
。
有区别的微调和逐步解冻
为了使用区别学习率和 G 随机解冻 ,fastai
提供了一个工具,允许将结构模型“分割”成组。fastai 文档中描述了执行“分割”的指令,此处为。
不幸的是,模型架构差异太大,无法创建一个独特的通用函数,以方便的方式“拆分”所有的模型类型。因此,您将不得不为每个不同的模型架构实现一个定制的“分割”。
例如,如果我们使用 DistilBERT 模型,我们通过制作print(learner.model)
来观察他的架构。我们可以决定将模型分成 8 块:
- 1 嵌入
- 6 变压器
- 1 个分类器
在这种情况下,我们可以这样分割我们的模型:
请注意,我没有发现任何文件研究了区别学习率和逐步解冻甚至倾斜三角形学习率对变压器架构的影响。因此,使用这些工具并不能保证更好的结果。如果你发现了任何有趣的文档,请在评论中告诉我们。
火车
现在我们终于可以使用所有的fastai
内置特性来训练我们的模型了。像 ULMFiT 方法一样,我们将使用倾斜三角学习率、区分学习率和逐渐解冻模型。
因此,我们首先冻结除分类器之外的所有组,使用:
learner.freeze_to(-1)
对于倾斜三角形学习率,您必须使用函数fit_one_cycle
。更多信息,请查看 fastai 文档这里。
为了使用我们的fit_one_cycle
,我们需要一个最佳的学习速率。我们可以用一个学习率查找器来找到这个学习率,这个学习率查找器可以用[lr_find](https://docs.fast.ai/callbacks.lr_finder.html#callbacks.lr_finder)
来调用。我们的图表看起来像这样:
我们将选择一个比最小值稍早的值,此时损失仍会增加。这里 2x 10–3 似乎是一个不错的值。
learner.fit_one_cycle(1,max_lr=2e-03,moms=(0.8,0.7))
损失图看起来像这样:
然后,我们解冻第二个组,并重复这些操作,直到所有组都解冻。如果您想使用区别学习率,您可以如下使用slice
:
要解冻所有组,使用learner.unfreeze()
。
创建预测
既然我们已经训练了模型,我们想要从测试数据集生成预测。
如 Keita Kurita 的文章中所述,由于函数get_preds
默认情况下不按顺序返回元素,因此您必须将元素按正确的顺序重新排序。
在 Kaggle 示例中,在没有过多使用参数的情况下,我们获得了 0.70059 的公开分数,这使我们在排行榜上排名第 5!
📋结论
在本文中,我解释了如何将transformers
库与心爱的fastai
库结合起来。它的目的是让你明白在哪里寻找和修改这两个库,使它们一起工作。很可能,它允许你使用倾斜三角形学习率、区别学习率和甚至逐步解冻。因此,甚至无需调整参数,您就可以快速获得最先进的结果。
今年,变形金刚成了 NLP 的必备工具。正因为如此,我认为预先训练的变形金刚架构将很快被整合到fastai
的未来版本中。同时,本教程是一个很好的开端。
我希望您喜欢这第一篇文章,并发现它很有用。
感谢您的阅读,不要犹豫,请留下问题或建议。
我会继续在 NLP 上写文章,敬请期待!
📑参考
[1]拥抱脸,变形金刚 GitHub(2019 年 11 月),https://github.com/huggingface/transformers
[2] Fast.ai,Fastai 文档(2019 年 11 月),https://docs.fast.ai/text.html
[3]https://arxiv.org/abs/1801.06146杰瑞米·霍华德&塞巴斯蒂安·鲁德,文本分类通用语言模型微调(2018 年 5 月)
[4] Keita Kurita,用快速人工智能微调 BERT 的教程(2019 年 5 月)
[5] Dev Sharma ,使用 RoBERTa 和 Fastai 进行 NLP(2019 年 9 月)
更快的 A/B 测试🚀—用数字表示
除了传统假设检验(也称为 frequentist)方法之外的其他方法正变得越来越普遍——我发现贝叶斯方法是一个有意义的改进。
传统的方法🎓
典型的 A/B 测试意味着假设测试——这意味着我们想要“证明 A & B 是显著不同的”。我们可以将我们的测试结果插入到现有的 A/B 测试评估器中,例如来自 Evan Miller 的评估器,并得到结果。
在大多数这些工具中,部分结果是“p”值。通常,如果小于 5%,结果被认为是显著的。有趣的是,许多人不知道“p”值的实际含义,并且经常被误解。这是问题的一部分,因为如果你不能解读测试结果,就很难得出合理的结论。
“p”值代表 A 和 B 来自同一分布的可能性
为什么要改变?😱
在我看来,常规方法有两个重大问题:
- 由于理解“p”值很难,人们经常得出错误的结论
- 传统的方法需要非常大的样本量:用典型的参数来显示 1%成功率的转换漏斗上 10%的提升,你必须让 320 000 个用户看到你的测试!
贝氏救援队。⛑
为了评估其他工具,我构建了一个模拟环境来测试各种框架及其参数。下面我将分享我的高级发现,并推荐一些你可以使用的参数,我发现这些参数非常健壮。
**场景:**假设你计划在接下来的几周内一个接一个地运行 10 个 A/B 测试,如果一个测试被接受,你将为所有未来的用户推出这个特性。不是所有的 A/B 测试都是肯定的,有时你不知道用户在寻找什么——我假设你测试的是更好或更差的版本。
在每个模拟中,我综合了每个测试的改进——因此,如果 10 个测试中有 3 个测试获得了+3%、+7%、+2%的改进,我会计算:
(1.03 * 1.07 * 1.02)-1 = 0.124.. = 12.4%
我重复了 1000 次以上的模拟,然后平均出复合结果:
正如你所看到的,所有的框架都接受积极的测试,并允许你向所有用户推出改进。但是你也可以看到, Bayes(完整持续时间)版本产生了最大的提升(给定相同的精确 A/B 测试结果)。这怎么可能呢?贝叶斯伊恩方法接受小结果的负担也较低——因为来自多个测试的小结果可以合成大结果,所以贝叶斯伊恩方法胜出。您还可以看到,如果您运行 A/B 测试的时间较短,那么框架将无法做出如同拥有所有数据一样好的决策。
但是贝叶斯方法有什么缺点吗?不幸的是,这一点经常被忽略,但是要回答这个问题,我们不应该看平均模拟结果,而应该看复合结果的分布。
百分位数显示,在一小部分模拟中(~1%)测试框架的错误决策会导致整体性能下降。虽然在我们的模拟中我们可以看到这一事实,但在现实世界中,您不会注意到您正在损害您的业务!相比之下,你可以看到非常保守的传统(Frequentist)方法没有这个问题。
好吧,那么哪个更好呢?🤔
总的来说,我更喜欢贝叶斯伊恩方法——只要你不是超级倒霉,你就可以期待用这种方法得到更好的结果,但在这种情况下,你也不会比传统方法失去太多。
您还必须考虑时间方面——为您的决策框架提供更少的时间(和数据)将会导致更糟糕的决策……
除了:如果更短的测试持续时间可以让你运行更多的测试,这是一个值得的权衡。
比方说,如果你在三分之一的时间内运行你的测试,它允许你在相同的时间内运行两倍的测试。这对结果有什么影响?
正如你所看到的,在 Frequentist 方法中用更短的测试持续时间运行更多的测试并没有太大的帮助,但是在 Bayes ian 的情况下,我们减少了可能的负面影响并显著提高了正面影响。
让我们在 0 时间内运行无限量的测试🦁
我的模拟显示,在 Bayes ian 框架中,只要运行同等数量的测试,就有可能将测试时间越来越短(例如,将时间减少 10 倍,运行 10 倍的测试)。实际上,这有几个问题:
- 如果您正在运行的测试的质量因为频率的增加而下降——所有的赌注都将被取消
- 通常你不能运行尽可能多的测试,因为有人需要构建它们——在这种情况下,为测试分配尽可能多的时间以做出最好的决策是有意义的
- 一般来说,你应该运行你的测试至少一个星期——用户在周末的行为可能与工作日有很大的不同,你的测试应该能够考虑这些情况!
让我们用贝叶斯分析一些测试🐳
我建议你使用以下参数来保护你的缺点:
- 获胜的可能性应该大于 66%
- 利润应大于 1%
我将在下面提供 python 代码,但是您也可以在大多数其他编程语言中这样做!该代码只是近似的,运行速度相当快。
*# to install dependencies: pip install numpy scipy* **import** numpy **as** _numpy
**from** scipy.stats.distributions **import** beta **as** _beta **def** get_likelihood_of_win(test_result, margin=0.01):
success = 0
total = 0 ref_pos = test_result[**'A'**][**'success_cnt'**]
ref_neg = test_result[**'A'**][**'fail_cnt'**]
test_pos = test_result[**'B'**][**'success_cnt'**]
test_neg = test_result[**'B'**][**'fail_cnt'**] conv_rate_base = max(
(ref_pos/ ref_pos + ref_neg),
(test_pos/ test_pos + test_neg)
) **for** x **in** _numpy.linspace(0, min(conv_rate_base * 2, 1), 100):
prob = _beta.pdf(x=x, a=ref_pos, b=ref_neg)
prob_test_wins = 1 - _beta.cdf(
x=x * (1 + margin),
a=test_pos, b=test_neg
)
success += prob_test_wins * prob
total += prob **return** success / total **if** __name__ == **'__main__'**:
test_result = {
**'A'**: {
**'success_cnt'**: 10,
**'fail_cnt'**: 100,
},
**'B'**: {
**'success_cnt'**: 18,
**'fail_cnt'**: 100,
}
}
likelihood_of_win = get_likelihood_of_win(
test_result=test_result, margin=0.01
)
accepted = likelihood_of_win > 0.66
print(accepted, round(likelihood_of_win, 2))
更快的 ALS 推荐与特征提取(和布偶!)
在最近的另一篇文章中,我讲述了我是如何为非漫画读者创建一个漫画推荐系统到漫画。我回顾了我是如何做到这一点的一些步骤,包括创建一个交替最小二乘法(ALS)模型,该模型将用户和项目分解成他们自己的矩阵,可以这样可视化:
当我们将这两个值分开后,可以将它们相乘,得到稀疏矩阵中原始值的最接近的组合,但也可以填入我们没有的值。现在,每个用户和物品都有自己独特的功能,这些功能以数字矩阵值的形式表现出来,我们用这些值来实现这些功能。
🐸十.🧀
我的推荐系统使用大量的项目和用户,所以为了帮助说明这一点,我将看一下我自己想象的一个非常简化的版本。我在怪异的例子中学得最好,所以它们会在我的大脑中停留更长的时间。所以,为了你的享受,让我们想象布偶需要一个奶酪的推荐系统。你把他们中的一些人聚集在一起,得到他们从 1 到 5 的分数,然后创建一个数据框,看起来像这样:
使用 ALS,我们可以将评级矩阵分解为代表用户和项目的矩阵,每个矩阵都通过潜在特征来表达。假设我们决定布偶奶酪推荐器有十个潜在特征,我们将得到两个特征矩阵,如下所示:
使用矩阵乘法,当我们重新组合这些矩阵时,我们会得到一个新的矩阵,如下所示:
你现在可以看到的一件大事是,这个过程已经填充了任何原本缺少评级的单元格。我们使用用户和项目的潜在特征来估计他们对项目的评价。如果我们向 Gonzo 推荐一种奶酪,知道他已经对 Swiss & Roquefort 进行了评级,我们可以看到 Gouda 是他没有吃过的项目中评级最高的,这是一个可靠的选择!
特征提取的魔力
我们做到了,我们可以向布偶推荐奶酪。但是…我们如何向牙齿医生推荐一种奶酪呢?滑板车?老鼠里索!?我们怎么会忘记他呢!我们需要帮助获得更多的布偶和最适合它们的奶酪。
一位新用户向我们提出了所谓的冷启动问题。我们必须弄清楚如何向没有信息的用户推荐(或者如果我们想添加新的奶酪,我们会遇到类似的问题)。我们可以只推荐评价最高的,也许是评价最高的,有许多不同的方法来尝试和解决这个问题。回到我最初的漫画推荐用例,我决定从他们那里获得一些用户评级,并从那里开始预测,但是我如何使用新的评级呢?
正如您在 ALS 中看到的,要有效地获得推荐,您需要有完整的矩阵,创建模型,然后找到最佳匹配。这样做的问题很简单:计算量很大,速度很慢。如果每次需要推荐时都需要重新创建模型,那么效率会非常低。
为了在不建立新模型的情况下快速获得结果,我们可以使用从项目中提取的特征以及新用户的一些推荐,并简单地进行矩阵乘法来获得分数。这听起来可能很直接,但让我详细介绍一下这个概念:
在 Python 中,让我展示一下可能的样子。首先,让我们假设牙齿博士决定加入这个布偶奶酪聚会,并将高达奶酪和切达奶酪都评为 5 分(他是一个相当快乐的家伙)。我们把他的分数放在他们自己的 numpy 数组中:
dr_teeth = np.array([[5],[5]])
dr_teeth.shape # (2, 1)
接下来,我们获取 gouda 和 cheddar 的项目特征,并将它们放在一个单独的数组中。它们是上图中要素数据框中的前两个项目,因此看起来会像这样:
select_cheese = items.iloc[0:2, 2:12].to_numpy()
select_cheese.shape # (2, 10)
接下来,我们将使用最小二乘法的线性代数解来求解牙齿博士的用户特征:
dr_teeth_features = np.linalg.lstsq(select_cheese, dr_teeth, rcond=None)
dr_teeth_features = dr_teeth_features[0].reshape((10,))
dr_teeth_features
###
array([1.94412615, 0\. , 0\. , 1.49873073, 0.20873594,
0\. , 0\. , 0.42289857, 0.36965752, 0.19383103])
我们做到了!现在,我们有了用户功能,就像所有其他现有用户一样。然后,我们可以使用这些和所有项目的矩阵乘法来返回牙齿医生的全套分数:
dr_teeth_scores = [np.dot(dr_teeth_features, row) for row in items.iloc[:, 2:12].to_numpy()]for row in zip(items['cheese'], dr_teeth_scores):
print(row)###
('gouda', 4.9999999999999964)
('cheddar', 5.000000000000001)
('brie', 4.270218133363084)
('swiss', 2.505755675697055)
('roquefort', 3.5066194383500755)
看起来对他来说下一个最好的奶酪是布里干酪。我们现在有一种快速的方法来近似新用户的结果,而不必创建一个全新的模型。
解开这一想法最重要的部分是知道你可以将特征提取应用到许多涉及数据科学的操作中。特别是当你开始使用大型预训练模型进行图像分类时,我们可以类似地使用它们的特征,而不需要运行大规模的神经网络来在更短的时间内获得结果的近似。
更快的数据科学
商业领袖经常问如何加速数据科学项目。众所周知,数据科学家花费 80%的时间在数据争论上。缩短这一时间可以加快数据科学项目的周转,并让数据科学家将更多的时间花在其他人无法完成的高价值活动上。随着数据科学团队规模的扩大,经济效益和工作效率会快速增长。这篇文章为数据工程的适度投资提供了一个案例,通过满足对较小的代表性数据集的需求,大大减少了花费在交互式数据探索上的时间。
减少分析查询的周转时间
减少花费在数据探索和代码开发上的时间的关键是最大限度地减少获得关于数据的基本问题的答案所花费的时间。当分析查询的典型运行时间从几个小时到一个小时到 10 分钟到不到一分钟到不到 10 秒钟时,开发过程的动态会发生巨大的变化。一旦查询响应时间达到几秒钟的范围,就可以提出许多问题来测试不同的假设,并最终在更短的时间内获得更好的结果。
大数据太大了
在研究项目和数据管道的开发过程中,数据科学家必须多次运行他们的查询,对它们进行提炼和改进,以便以他们想要的格式获得他们需要的数据。然而,处理大数据非常耗时,因为无论您使用的是 Hadoop 还是现代分布式数据仓库(如 Snowflake、Redshift 或 Vertica ),处理大型数据集都需要很长时间。使用共享计算资源的模式常常会加剧这个问题,在这种模式下,交互式查询会与较大的批处理进程竞争。
数据科学家对推进研究所需的时间感到沮丧,他们发明了避免长时间等待的捷径,但往往牺牲了分析结果的准确性或适用性。例如,处理一个小时的日志数据使查询时间变得可以忍受,从而可以取得进展。然而,这些结果不能用来得出关于整个数据集的结论。
数据工程师可以通过采用几种简单的方法来减少查询时间,只需要少量的工作和很少的额外成本,从而减轻数据争论的痛苦。这些方法旨在将数据的大小和范围缩减到与所提问题相关的子集,下面将对此进行详细介绍。
使用列式数据存储
数据的存储方式对数据的分析访问有很大的影响。列数据格式,如 Parquet ,被广泛使用并提供了许多好处。除了将数据扫描限制在查询中出现的列并允许更好的压缩之外,这些格式还以二进制格式而不是文本格式存储数据。即使在一个高效的 CSV 阅读器中,将文本解析为二进制数据类型也会消耗将数据加载到计算机内存所需时间的 80%。此外,正确解析文本字段本身也是一个挑战。一次预处理和以二进制格式存储数据避免了每次访问数据时的额外计算。数据仓库通常提供现成的二进制列数据存储。
创建始终在线的采样数据集
许多数据问题可以通过使用代表性的数据样本来回答。采样数据集比一小段时间的数据好得多,因为它们代表整个数据集,足以回答各种问题。尽管提取和更新样本是乏味的,但每个数据科学家迟早都会被诱惑这样做,仅仅是为了缩短他们查询的周转时间。一个更有效且成本不高的解决方案是定期提供自动生成的数据样本。理想情况下,采样数据的生成应依赖于产生完整数据集的流水线。
在数据代表一些事件(例如,广告印象、购买交易、网站访问等)的典型情况下。)与一些实体(例如,在线用户、公司等)相关。),用不同类型的采样创建数据集是有益的。一个显而易见的方法是对事件进行采样,随机选择一定百分比的事件包含在数据集中。另一种抽样策略,对数据科学家或分析师来说,可能更有价值,也更难实现,就是覆盖与实体样本相关的所有记录。例如,我们可能希望包含 5%的站点用户的所有购买。这样的样本允许人们有效地执行基于用户的分析。采样策略,包括自适应采样,是另一篇文章的主题。
提取较小的相关数据集
当感兴趣的事件很少时,取样可能不是一个选项。例如,在数字广告设置中,人们可能对在有限的时间范围内提取特定广告活动的所有可用数据感兴趣。这样的数据集虽然包含所有必需的字段,但只是所有数据的一个小子集。与这些数据进行交互的分析师和数据科学家在处理一个项目时可能会发出数百个查询。如果数据工程团队构建工具,允许数据科学家为初始提取创建一个查询,并由另一个查询负责定期更新,则提取这样一个数据集并使其保持最新的过程可以自动化。项目完成后,不再需要这些数据,可以将其存档或删除。
将较小的数据集放在高效的 SQL 存储中
SQL 无疑是数据分析最常用的语言。因此,使用 SQL 使数据集可用于查询扩大了可以与数据交互的人数。抛开数据的民主化不谈,在高效的分析 SQL 查询引擎中提供更小的数据集可以进一步减少查询时间,从而减少数据科学家和分析师浪费的时间。根据数据的大小和对基础设施的要求,这种查询引擎的范围很广,从 MySQL 和 PostgreSQL 到 Snowflake 和 Redshift,再到完全托管的服务,如亚马逊的 Athena 和谷歌的 BigQuery。
提供专用的计算资源
数据探索中最大的挫折之一是不得不在一个共享队列中等待一个查询的结果,这个查询最终运行不到一分钟。在共享集群上为交互式查询提供单独的高优先级资源池(可能限制在工作时间内),对于改善整体查询周转时间大有帮助。此外,为数据科学和分析团队提供具有足够 CPU 和内存容量的专用计算资源,可以将较小的数据集加载到他们选择的工具中,以执行开发和深入分析。
投资是值得的!
人类的时间比计算机时间和数据存储成本要贵一个数量级。通过比较数据科学家的有效时薪和一台强大计算机的时薪,人们可以很容易地观察到这一点。此外,人力时间为公司创造了新的净价值。因此,将典型的分析查询完成时间缩短到不到一分钟可能是加速数据科学和分析项目的最有效的技术投资。
Kelly sik kema 和 Glen Noble 在 Unsplash 上拍摄的照片由 Sergei Izrailev 合成
这篇文章最初出现在生活数据博客上。
具有并行处理的更快的熊猫:cuDF 与 Modin
Photo by Lindsay Henwood on Unsplash
对于 Pandas,默认情况下我们一次只能使用一个 CPU 内核。这对于小数据集来说没问题,但是当处理较大的文件时,这可能会造成瓶颈。
通过使用并行处理来加快速度是可能的,但是如果你从未编写过多线程程序,不要担心:你不需要学习如何去做。一些新的图书馆可以为我们做到这一点。今天我们就来对比一下其中的两位: cuDF 和摩丁。它们都使用类似 pandas 的 API,所以我们可以通过修改 import 语句来开始使用它们。
cuDF
cuDF 是一个 GPU 数据帧库,它提供了一个类似熊猫的 API ,允许我们加速我们的工作流,而无需进入 CUDA 编程的细节。lib 是 RAPIDS 的一部分,RAPIDS 是一套开源库,使用 GPU 加速,与流行的数据科学库和工作流集成,以加速机器学习。
The RAPIDS suite
该 API 与 pandas 非常相似,因此在大多数情况下,我们只需更改一行代码就可以开始使用它:
**import cudf as pd**s = pd**.Series(**[1,2,3,None,4]**)**df = pd**.DataFrame**([('a', list(range(20))),
('b', list(reversed(range(20)))),
('c', list(range(20)))]**)**df.**head**(2)df.**sort_values**(by='b')
df['a']
df.**loc**[2:5, ['a', 'b']]s = pd.Series([1,2,3,None,4])s.fillna(999)df = pd.**read_csv(**'example_output/foo.csv'**)** df.**to_csv(**'example_output/foo.csv', index=False**)**
cuDF 是一个单 GPU 库。对于多 GPU,他们使用 Dask 和 dask-cudf 包,该包能够在单台机器上的多个 GPU 之间扩展 cudf,或者在一个集群中的许多机器上扩展多个 GPU[cuDF 文档 ]。
摩丁
Modin 还提供了一个 pandas-like API 使用 Ray 或 Dask 实现一个高性能的分布式执行框架。有了 Modin,你可以使用你机器上的所有 CPU 内核。它在 4 个物理内核的笔记本电脑上提供了高达 4 倍的速度提升[ 摩丁文档 ]。
环境
我们将使用 Maingear VYBE PRO 数据科学 PC ,我正在使用 Jupyter 运行脚本。以下是技术规格:
Maingear VYBE PRO 数据科学电脑
- 125gb 内存
- i9–7980 xe,36 个内核
- 2x 泰坦 RTX 24GB
用于基准的数据集是巴西 2018 年高等教育普查。
基准 1:读取一个 CSV 文件
让我们使用 Pandas、cuDF 和 Modin 读取一个 3gb 的 CSV 文件。我们将运行它 30 次并得到平均值。
Reading a CSV file
摩丁以平均不到 4s 胜出。它会自动在系统的所有可用 CPU 内核中分配计算,我们有 36 个内核,这可能就是原因🤔?
基准 2:缺失值
在这个基准测试中,我们将填充数据帧的 NaN 值。
Filling missing values
摩丁也是这个基准的赢家。cuDF 是平均运行时间更长的库。
基准 3:分组依据
让我们将行分组,看看每个库的行为。
Grouping rows
这里 cuDF 是赢家,摩丁表现最差。
酷,那么我应该使用哪个库呢?
https://twitter.com/swyx/status/1202202923385536513
要回答这个问题,我想我们必须考虑一下我们在工作流程中最常用的方法。在今天的基准测试中,使用 Modin 读取文件要快得多,但是我们需要在 ETL 中使用多少次read_csv()
方法呢?相比之下,理论上,我们会更频繁地使用groupby()
方法,在这种情况下,cuDF 库的性能最好。
Modin 很容易安装(我们只需要使用 pip),cuDF 比较难(你需要更新 NVIDIA 驱动,安装 CUDA,然后使用 conda 安装 cuDF)。或者你可以跳过所有这些步骤,得到一台数据科学电脑,因为它配备了所有 RAPIDS 库和完全安装的软件。
此外,摩丁和 cuDF 仍处于早期阶段,他们还没有完整覆盖整个熊猫 API。
入门指南
如果你想深入研究 cuDF,10 分钟到 cuDF 和 Dask-cuDF 是一个很好的起点。
关于摩丁的更多信息,这篇博文解释了更多关于用射线并行化熊猫的信息。如果你想更深入地了解,还有关于用 Modin 透明地扩展交互式数据科学的技术报告,它很好地解释了 Modin 的技术架构。
用于目标检测的快速 R-CNN
技术论文摘要
R-CNN 家族中使用最广泛的最先进版本——更快的 R-CNN 于 2015 年首次发布。本文是了解当今物体探测基础的系列文章的第三篇,也是最后一篇,阐述了更快的 R-CNN 探测管道的技术细节。回顾它的前辈,看看这些总结:地区与 CNN (R-CNN) 和快速 R-CNN 。
在 R-CNN 系列论文中,版本之间的演变通常是在计算效率(整合不同的训练阶段)、减少测试时间和提高性能(mAP)方面。这些网络通常包括——A)生成“边界框”或图像中可能对象的位置的区域提议算法;b)通常使用 CNN 获得这些对象的特征的特征生成阶段;c)分类层,用于预测该对象属于哪个类别;以及 d)回归层,用于使对象边界框的坐标更加精确。
快速 R-CNN 网络中剩下的唯一独立部分是区域提议算法。R-CNN 和快速 R-CNN 都使用基于 CPU 的区域提议算法,例如,选择性搜索算法,每幅图像大约需要 2 秒钟,在 CPU 上运行。更快的 R-CNN [3]论文通过使用另一个卷积网络(RPN)来产生区域提议,解决了这个问题。这不仅将每个图像的区域提议时间从 2s 降低到 10ms,而且允许区域提议阶段与随后的检测阶段共享层,导致特征表示的整体改进。在本文的其余部分,“更快的 R-CNN”通常指的是一种检测管道,它使用 RPN 作为区域提议算法,使用快速 R-CNN 作为检测器网络。
区域提案网络
Figure 1: The architecture of the region proposal network or RPN
体系结构
- 区域建议网络(RPN)从输入图像被馈送到骨干卷积神经网络开始。首先调整输入图像的大小,使其最短边为 600 像素,最长边不超过 1000 像素。
- 主干网络的输出特征(由 H x W 表示)通常比输入图像小得多,这取决于主干网络的跨度。对于本文中使用的两种可能的主干网(VGG、ZF 网络),网络跨距为 16。这意味着主干输出特征中的两个连续像素对应于输入图像中相距 16 个像素的两个点。
- 对于输出特征图中的每个点,网络必须了解输入图像中相应位置是否存在对象,并估计其大小。这是通过在主干网络的输出要素地图上的每个位置的输入图像上放置一组“锚点”来实现的。这些锚表示在该位置的各种尺寸和长宽比的可能物体。下图显示了 9 个可能的锚点,它们以 3 种不同的纵横比和 3 种不同的大小放置在输入图像上,用于输出特征地图上的点 A。对于帕斯卡挑战,所使用的锚具有 128、256、512 和 1:1、1:2 和 2:1 的 3 种比例的盒子面积。
Figure 2: The possible anchors in the input image in a location corresponding to point A in the feature map.
- 当网络移动通过输出特征图中的每个像素时,它必须检查跨越输入图像的这些 k 对应锚点是否实际包含对象,并细化这些锚点的坐标以给出作为“对象提议”或感兴趣区域的边界框。
- 首先,具有 512 个单元的 3×3 卷积被应用于主干特征图,如图 1 所示,以给出每个位置的 512-d 特征图。接下来是两个兄弟层:1 x 1 卷积层,18 个单元用于对象分类,1 x 1 卷积层,36 个单元用于边界框回归。
- 分类分支中的 18 个单元给出大小为(H,W,18)的输出。该输出用于给出主干特征图(尺寸:H×W)中的每个点在该点的所有 9 个锚点中是否包含对象的概率。
- 回归分支中的 36 个单元给出大小为(H,W,36)的输出。该输出用于给出主干特征图(大小:H×W)中每个点的 9 个锚的 4 个回归系数。这些回归系数用于改善包含对象的锚点的坐标。
训练和损失函数
- 输出的特征图由大约 40×60 个位置组成,总共对应 40609 ~ 20k 个锚点。在列车运行时,所有跨越边界的锚都被忽略,因此它们不会造成损失。这使得每个图像大约有 6k 个锚。
- 如果一个锚满足以下两个条件中的任何一个,则该锚被认为是“正”样本——a)该锚具有最高的 IoU(交集/并集,一种重叠的度量);b)锚具有大于 0.7 的 IoU 和任何地面实况框。同一个 groundtruth 框可以导致多个锚点被分配阳性标签。
- 如果一个锚点的 IoU 与所有 groundtruth 框小于 0.3,则该锚点被标记为“负”。剩余的锚(既不是正面的也不是负面的)在 RPN 训练中被忽略。
- 用于训练 RPN 的每个小批量来自单个图像。从该图像中采样所有锚会使学习过程偏向负样本,因此随机选择 128 个正样本和 128 个负样本来形成该批,如果正样本数量不足,则用额外的负样本填充。
- RPN 的训练损失也是多任务损失,由下式给出:
- 这里 i 是主播在 mini-batch 中的索引。分类损失 L𝒸ₗₛ(pᵢ,pᵢ)* 是两类(对象对非对象)的对数损失。 pᵢ 是主播 i 的分类分支的输出分数, pᵢ* 是地面实况标签(1 或 0)。
- 回归损失 Lᵣₑ(tᵢ,tᵢ)* 仅在锚点实际包含一个对象时被激活,即基础事实 pᵢ* 为 1。术语 tᵢ 是回归层的输出预测,由 4 个变量组成【tₓ,tᵧ,t w ,tₕ].回归目标 tᵢ*计算如下—
- 这里 x,y,w,h 对应于盒子中心的 (x,y) 坐标和盒子的高度 h 和宽度 w 。xₐ,x*代表锚定框的坐标及其对应的地面真实边界框。
- 请记住,锚盒的所有 k ( = 9)都有不同的回归量,它们不共享权重。因此,锚 i 的回归损失应用于其相应的回归量(如果是正样本)。
- 在测试时,所学习的回归输出 tᵢ可以被应用于其相应的锚框(被预测为正的),并且用于预测的对象提议边界框的 x,y,w,h 参数可以从下式反算
测试时间详细信息
在测试时,来自每个图像的 20k 个锚经过一系列后处理步骤,发送到对象提议边界框中。
- 回归系数被应用于锚点以进行精确定位。这给出了精确的边界框。
- 所有的盒子都按照它们的 cls 分数排列。然后,应用阈值为 0.7 的非最大抑制(NMS)。从上到下,所有与另一个边界框的 IoU 大于 0.7 的边界框都被丢弃。因此,最高得分的边界框被保留用于一组重叠的框。
- 这给出了每个图像大约 2k 个建议。
- 跨界边界框被保留并被剪切到图像边界。
- 当使用这些对象建议来训练快速 R-CNN 检测流水线时,使用来自 RPN 的所有 2k 个建议。在用于快速 R-CNN 检测的测试时间,仅选择来自 RPN 的前 N 个提议。
对象检测:更快的 R-CNN (RPN +快速 R-CNN)
Figure 3: The RPN for region proposals and Fast R-CNN as a detector in the Faster R-CNN detection pipeline
更快的 R-CNN 架构包括作为区域提议算法的 RPN 和作为检测器网络的快速 R-CNN。
快速 R-CNN 作为快速 R-CNN 的检测器
快速 R-CNN 检测器还包括一个 CNN 主干、一个 ROI 池层和完全连接的层,后面是两个用于分类和边界框回归的兄弟分支,如图 3 所示。
- 输入图像首先通过主干 CNN 得到特征图(特征大小:60,40,512)。除了测试时间效率,使用 RPN 作为建议生成器的另一个关键原因是 RPN 主干和快速 R-CNN 检测器主干之间重量共享的优势。
- 接下来,来自 RPN 的边界框提议被用于汇集来自主干特征地图的特征。这是由 ROI pooling 层完成的。ROI 汇集层本质上是通过以下方式工作的:a)从主干特征地图中提取与提议相对应的区域;b)将该区域分成固定数量的子窗口;c)在这些子窗口上执行最大汇集以给出固定大小的输出。要了解投资回报池层的细节及其优势,请阅读 Fast R-CNN 。
- ROI 池层的输出大小为(N,7,7,512 ),其中 N 是区域建议算法的建议数。在通过两个完全连接的图层后,这些要素将被送入兄弟分类和回归分支。
- 注意,这些分类和检测分支与 RPN 的不同。这里,分类层对于检测任务中的每个类(包括一个包罗万象的背景类)都有 C 个单元。这些特征通过 softmax 层得到分类分数,即一个建议属于每个类别的概率。回归层系数用于改进预测的边界框。这里的回归量是大小不可知的,(不同于 RPN),但特定于每个类。也就是说,所有类都有单独的回归变量,每个变量有 4 个参数,对应于回归层中的 C*4 个输出单元。
- 关于更快的 R-CNN 如何被训练和它的损失函数的更多细节参考快速 R-CNN 。
4 步交替训练
为了迫使网络在 RPN 和检测器之间共享 CNN 主干的权重,作者使用了 4 步训练方法:
a)如上所述,独立训练 RPN。该任务的中枢 CNN 用来自为 ImageNet 分类任务训练的网络的权重初始化,然后为区域提议任务进行微调。
b)快速 R-CNN 检测器网络也是独立训练的。该任务的中枢 CNN 用来自为 ImageNet 分类任务训练的网络的权重初始化,然后为对象检测任务进行微调。RPN 权重是固定的,并且来自 RPN 的建议被用于训练更快的 R-CNN。
c)RPN 现在使用来自这个更快的 R-CNN 的权重进行初始化,并且针对区域提议任务进行微调。这一次,RPN 和检测器之间的公共层中的权重保持固定,只有 RPN 特有的层被微调。这是最终的 RPN。
d)再次使用新的 RPN,快速 R-CNN 检测器被微调。同样,只有检测器网络特有的层被微调,而公共层权重是固定的。
这给出了共享卷积层的更快的 R-CNN 检测框架。
Figure 4: Results of the Faster R-CNN detection framework with a VGG backbone
结果
- 在 PASCAL 数据集上的所有实验中,选择快速 R-CNN 作为检测器。使用 RPN+ZF 主干作为建议网络(不与检测器共享权重)与使用“选择性搜索”(SS)作为区域建议算法的性能相当。这已经给了我们相当的结果,大大减少了检测时间。RPN+VGG 主干网仅作为一个具有非共享权重的提案网络,其表现略好于 SS 地区提案基线。当检测器使用共享权重时,RPN 中的 ZF 和 VGG 主干的性能都超过了 SS 基线。这与大量其他实验一起验证了 RPN 作为区域提议方法的使用。
- 与选择性搜索的 1.8 秒相比,VGG RPN 的检测需要 198 毫秒。
- 执行的其他实验验证了 NMS 的使用,以及单独的分类和回归分支的使用。用于根据分数对提议进行排序的分类分支似乎是保持合理的高召回率与 IoU 重叠率的重要因素,即使当对象提议的数量减少时。
- 在观察锚箱比例和长宽比的重要性的消融研究中,作者发现使用 3 个比例和一个长宽比几乎与 3 个比例和 3 个长宽比一样有效。根据任务和数据集,可以修改这些比率和比例。在每个位置使用单个锚点会导致地图显著下降。
这就结束了更快的 R-CNN 论文的技术总结。希望你喜欢(理解)!欢迎在下面的评论中讨论或更正。
参考资料:
[1]任,何,罗斯吉斯克,更快的 R-CNN:用区域提议网络实现实时目标检测,NIPS’15 会议录
【2】http://www . telesens . co/2018/03/11/Object-Detection-and-classification-using-R-CNNs/
【3】https://Leonardo araujosantos . git books . io/artificial-intelligence/