为什么 Deep Learning 最先在语音识别应用领域和图像处理领域取得突破

&p&本文纯属搞笑!!&/p&Topic Model (主题模型)这个东西如果从99年Hofmann的pLSA开始算起,得火了有近20年了。这20年里出现了很多东西,这篇文章不准备对这些东西做细致的介绍,而是谈谈个人对这些模型的一些看法。首先,我先阐明观点,就是这些东西虽然看起来很不一样,但是在某一层面的本质上看差不太多。&p&因为我是做推荐系统的,我就从推荐系统这个角度去说吧。2009年参加Netflix Prize的时候,当时解决的是一个评分预测的问题。也就是每个用户给电影打了1~5分,然后让你去预测一个用户对一个电影会打多少分。这个时候就遇到一个矩阵,叫做user-item矩阵。这个矩阵中大量的元素都是missing的,而不missing的哪些pair都有一个1~5分的分数。整个比赛的目的就是去预测那些missing的pair如果不missing会是多少分。&/p&&p&在Netflix Prize之前,这个问题都是这么解决的,首先把missing的值都填上3分(也有其他策略,但这不是本文的重点),然后把user-item矩阵做SVD分解,选取最大的K个特征值对应的特征向量组成的矩阵,然后再乘起来。这个时候,那些missing的pair都变成了其他的分数,这个分数就是预估值。在Netflix Prize这个方法能work的原因是当时只有一个MovieLens数据集,那个数据集只有几百个用户和物品,这么做还是OK的。但到了Netflix Prize,数据集顿时到了几十万维的矩阵,群众们傻眼了,因为SVD分解是个O(n^3)的复杂度。&/p&&p&这个时候有个哥们忽然在Blog上发了一篇文章(他的那篇博客可能是学术论文引用最多的博客文章),说你们不用管那些missing的pair。你们就直接在不missing的pair上用梯度下降法学习user和item的latent factor的表示吧。于是有了那个著名的伪SVD算法:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&r(u, i) = &p(u), q(i)&
&/code&&/pre&&/div&&p&于是整个Netflix Prize中涌现了一大堆带SVD的算法,比如RSVD,NSVD,SVD++等等。我也发明了几个SVD算法,因为照着这个思路太容易发散了。&/p&&p&但是,我一直觉得Netflix Prize其实误导了整个推荐系统的发展。当然应该说是更早的MovieLens就误导了,只是Netflix Prize没有纠正过来。这个误导就是,评分预测其实不是重要的问题,反而是一个很次要的问题。因为,当人民群众拿着Netflix Prize的算法准备用在自己的系统里时,顿时傻眼了,因为没有评分数据。他们有的只是观看数据,点击数据,购买数据等等。这些数据有一个特点,就是user-item矩阵中所有的非missing值,都是1。而不是Netflix Prize里面的评分。而且人们意识到,评分这件事有2个步骤:&/p&&ol&&li&看电影&/li&&li&评分&/li&&/ol&&p&也就是说,如果用户连电影都不看,他是不会去评分的。于是,预测用户会看什么电影,并把这些电影推荐给他,显然比知道这个用户会看这个电影后,预测他看完会给多少分更重要。&/p&&p&但预测用户会看什么电影时,我们遇到了一个问题,就是如何对一个非missing值都是1的矩阵进行分解。这也是2012年KDD Cup的Track 2提出的问题。&/p&&p&这个时候,人们忽然发现,在NLP领域,做Topic Model时,遇到的doc-word矩阵,和我们遇到的这种user-item矩阵一样,都是非missing值都是1的矩阵(有人会说doc-word矩阵的值是tfidf,但本质上其实就是1)。而那个领域已经提出了2个算法来解决这个问题,就是著名的pLSA和LDA。这两个算法的训练复杂读都只取决于非0元素的个数,和0元素的个数都没有关系。于是很多人开始把这两个算法应用于推荐系统领域(其实之前在Netflix Prize就有人用了,但后来因为那个SVD算法太NB,大家都纷纷搞SVD去了)。&/p&&p&但是在2012年KDD Cup的时候。我们想,我们为什么不在0,1上训练SVD的模型呢?那是因为0太多了(这里0就是missing value)。既然0太多,我们采样吧。比如我们每遇到一个1,就随机采样出N个0,然后用SVD训练。那么我们怎么采样0呢?当时有两种候选:&/p&&ol&&li&纯随机的选择,也就是说如果一个用户看过K个item,我们就从所有item中随机选择 NK个他没看过的item作为负样本。&/li&&li&按照item的热门度去选,也就是说如果一个用户看过K个item,我们就从所有item中按照item的热门度随机选择 NK个他没看过的item作为负样本。&/li&&/ol&&p&第2种更合理。这是因为,对于missing值来说,一个人没有看过一个电影,有两种可能:&/p&&ol&&li&他不知道有这个电影&/li&&li&他知道,但不喜欢&/li&&/ol&&p&而对于热门的电影来说,是2个概率更高(当然这里还存在一种可能,就是他在其他平台上看过了,但这个在整体用户的统计意义上不高)。而我们的模型学习的就是兴趣,所以越可能是原因2的item,越应该作为负样本。这个算法就是Negative Sampling。&/p&&p&到这个时候为止,对于0-1矩阵的分解,我们有了2个武器,一个是贝叶斯学派的LDA,一个是频率学派的矩阵分解。我们知道,贝叶斯学派和频率学派有着各种各样的区别,如果从优化的角度去看,MCMC是贝叶斯学派的模型常用的优化方法,而梯度下降是频率学派常用的。&/p&&p&故事发展到这个阶段时,群众的目光忽然转向了。Topic Model的发展忽然转向了“我们需要更多的Topic”。之前,大家弄个几百个topic就非常高兴了,这个时候忽然有人说,我们要几百万个Topic。据说是因为google有个系统能学50万topic,非常NB。另外大家希望,topic多了就能学习出更多小的topic,表达更小众的语义。于是群众们开始干了。一开始大家是拿LDA开刀的。于是乎,LDA从12年开始,经历了SparseLDA, AliasLDA, LightLDA, WarpLDA的发展道路,到了15年底,已经能非常快的学100万topic了,而且这个快是靠直接降低理论的时间复杂度实现的,代码写的更好只是起了辅助作用。&/p&&ol&&li&SparseLDA利用了如果topic很多,那么当模型快收敛时,一个word其实只会属于很少的topic,然后利用稀疏性来加速了算法。但这个算法有个致命的缺陷,就是初始化时,模型并不稀疏,因此迭代的前几轮会非常慢。当然充满智慧的群众发明了一堆奇技淫巧部分解决了这个问题。&/li&&li&AliasLDA是优化了Gibbs Sampling采样的时间复杂度,利用Alias Table让对K个topic采样的时间复杂度从O(K)降低到O(1)&/li&&li&LightLDA修改了采用的分布,把原来基于一个word doc在topic上联合分布的采样过程,改成了2个交替进行的独立采样过程,一个只依赖word,另一个只依赖doc。&/li&&li&WarpLDA做了更多的工程级别的优化,让LightLDA更快。&/li&&/ol&&p&但后来,LDA一直没有大规模的火起来。这是因为不幸的又遇到了深度学习这股风,google在2013年提出了word2vec。word2vec本身不是一个很深的模型,他其实就是一个一层的模型。但这个模型的nb之处在于,他是频率学派的,支持梯度法优化,因此这一层可以插入到DL的网络中作为一层,和其他层一起做end-to-end的优化,LDA就没法这么搞。这样,大量的有监督的问题,用上word2vec后,效果顿时就超过LDA了。&/p&&p&word2vec刚出来时,我发现他在优化时用了霍夫曼编码来实现了层次化的SoftMax(HS)。当时我觉得他这么做有2个目的:&/p&&ol&&li&减少运算复杂度,如果是普通的SoftMax,其实就相当于在0-1矩阵的所有值上做矩阵分解,没有能利用到矩阵的稀疏性。&/li&&li&倾向于选择热门的item做负样本,因为霍夫曼编码是按照热门度对item编码的,越热门的item离根节点越近。&/li&&/ol&&p&所以,HS真是太巧妙了。果然不出所料,2014年的时候,有群众提出,那我们直接用Negative Sampling吧。这样程序写起来简单。大家一试,发现效果还不错,并不比HS差,而且代码确实很容易写。&/p&&p&故事发展到这个阶段时,我们总觉得少了点啥。这个word2vec忽然跳出来就抢了LDA的饭碗,那么LDA最后搞的那些把topic提升到100万个的工作,貌似word2vec还没搞啊?我去google了一下,发现群众的智慧是无限的,果不其然,有人发现这个遗留问题了。Facebook的研究人员在一个标题为&a href=&/?target=http%3A//www.machinelearning.ru/wiki/images/d/db/MikolovWord2vecSlides.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&What's next, word2vec&i class=&icon-external&&&/i&&/a&的演讲中明确提出,稀疏表达是word2vec下一个要解决的问题。其实稀疏表达的前提就是topic要多。只有多了,才有可能学习出非常小的topic。&/p&&p&好吧,后面就让我们拭目以待吧。&/p&&p&读后思考:为什么Netflix Prize的评分问题可以只在不missing的value上训练,而不用管missing value?&/p&&p&------------------------------&/p&&p&欢迎关注 [ ResysChina ] 微信公众号。&/p&
本文纯属搞笑!!Topic Model (主题模型)这个东西如果从99年Hofmann的pLSA开始算起,得火了有近20年了。这20年里出现了很多东西,这篇文章不准备对这些东西做细致的介绍,而是谈谈个人对这些模型的一些看法。首先,我先阐明观点,就是这些东西虽然看起来很…
更新&/p&&p&社招;其实里面漏了一个重要我原本打算去的机会,但我临时还是决定去大厂,今天这公司总监给我打了个电话,谈到由业务驱动转向技术驱动,也说了一些挽留话,我真蛮感动的;之前hr的积极更进以及最后我的临时变卦,其实我都蛮惭愧;我一直觉得自己这些面试碰到的公司碰到的人都很好,我跟总监说自己是被高看了,是心里话;大家如果对组合数学或者强化学习有兴趣有研究可以私信我帮忙推荐;&/p&&p&关于国内公司薪资问题可以私信我;&/p&&p&#
更新&/p&&p&一些面试的建议:&/p&&p&1:bat三家都喜欢问大量的计算机基础知识,考察工程能力,b都喜欢问数据结构和leetcode,t问的比较随意但是很考察思维能力;(当然还是得看面试官)&/p&&p&2:对于像我这种非计算机班科出身的(数学统计),面机器学习算法的公司比较容易,面工程的公司比较难;&/p&&p&3:深度学习入门门槛很低,但是精通门槛很高,仍然很多东西都是黑盒子,因此如果真的没有这方面经验,不建议写进简历,很容易被问倒;面试官如果自身不精通,他压根不会问深度学习,如果问了,那他基本上还是比较懂行的;(个人经验,不一定准)&/p&&p&4:面试有些问题不确定,就说自己知道的,知道多少说多少,反正不能什么都不说;&/p&&p&&br&&/p&&p&我最近换工作,基本上轮了一圈大的互联网公司,下面是我的面经,希望对nlp或者机器学习深度学习感兴趣的朋友准备面试有点帮助,有些问题我答得不准希望不吝赐教;&/p&&p&&br&&/p&&p&--- 某新闻app ---&/p&&p&round1:&/p&&p&1:cnn做卷积的运算时间复杂度;&/p&&p&2;Random forest和GBT描述;&/p&&p&3:(看到kaggle项目经历)为什么xgboost效果好?&/p&&p&4:leetcode;&/p&&p&&br&&/p&&p&round2:&/p&&p&1:工程背景;&/p&&p&2: python熟悉程度;&/p&&p&3:leetcode;&/p&&p&&br&&/p&&p&round3:&/p&&p&1:项目介绍&/p&&p&2:项目最难的是什么&/p&&p&3:项目做的最有成就感的是什么&/p&&p&4:生活做的最有成就感的是什么&/p&&p&5:一天刷多少次我们的app&/p&&p&&br&&/p&&p&不评论;&/p&&p&&br&&/p&&p&&br&&/p&&p&--- 打车公司 ---&/p&&p&1: LSTM结构推导,为什么比RNN好?&/p&&p&需要说明一下LSTM的结构,input forget gate, cell information hidden information这些,之前我答的是防止梯度消失爆炸,知友指正,不能防止爆炸,很有道理,感谢;&/p&&p&&br&&/p&&p&2:梯度消失爆炸为什么?&/p&&p& 答案:略&/p&&p&&br&&/p&&p&3:为什么你用的autoencoder比LSTM好?&/p&&p& 答案:我说主要还是随机化word embedding的问题,autoencoder的句子表示方法是词袋方法,虽然丢失顺序但是保留物理意义;(?)&/p&&p&&br&&/p&&p&4: overfitting怎么解决:&/p&&p& 答案:dropout, regularization, batch normalizatin;&/p&&p&&br&&/p&&p&5:dropout为什么解决overfitting,L1和L2 regularization原理,为什么L1 regularization可以使参数优化到0, batch normalizatin为什么可以防止梯度消失爆炸;&/p&&p& 答案:略&/p&&p&6: 模型欠拟合的解决方法:&/p&&p& 答案:我就说到了curriculum learning里面的sample reweight和增加模型复杂度;还有一些特征工程;然后问了常用的特征工程的方法;&/p&&p&&br&&/p&&p&7:(简历里面写了VAE和GAN还有RL,牛逼吹大了)VAE和GAN的共同点是什么,解释一下GAN或者强化学习如何引用到你工作里面的;&/p&&p& 答案:略&/p&&p&&br&&/p&&p&传统机器学习&/p&&p&1:SVM的dual problem推导;&/p&&p&2:random forest的算法描述+bias和variance的分解公式;&/p&&p&3:HMM和CRF的本质区别;&/p&&p&4:频率学派和贝叶斯派的本质区别;&/p&&p&5:常用的优化方法;&/p&&p&6: 矩阵行列式的物理意义(行列式就是矩阵对应的线性变换对空间的拉伸程度的度量,或者说物体经过变换前后的体积比)&/p&&p&7: 动态预测每个区域的用车需求量;&/p&&p&&br&&/p&&p&对于打车公司,我的感觉很好,hr态度和面试官态度都很好,包括最后跟老大打完电话约去公司聊一下确定一下;全程hr都是有问必答;&/p&&p&有一次为了去前面那个新闻app,而改了打车公司面试时间,hr态度都很好;&/p&&p&最后我已经决定了去深圳,不能去打车公司也有点遗憾了;&/p&&p&而且打车公司问的问题很专业,全程下来都是ML算法,不考脑残的leetcode;我根本没时间也不想再去刷leetcode就为了个面试;&/p&&p&&br&&/p&&p&--- 手机公司 ---&/p&&p&round1:&/p&&p&1:LSTM相关的问题;&/p&&p&2:python写k-means;&/p&&p&3:想不起来了&/p&&p&&br&&/p&&p&round2:&/p&&p&1:业务相关的问题&/p&&p&2:记不起来了&/p&&p&&br&&/p&&p&round3:&/p&&p&1:记不起来了&/p&&p&&br&&/p&&p&手机公司最近在搞发布会,面试过了一个星期再通知我去复面,我果断拒绝;&/p&&p&全程深度学习的东西基本上不问,问了一两个看来他们基本不用,然后就是leetcode;&/p&&p&手机公司做智能家居蛮有前途的;面试官态度很好;&/p&&p&&br&&/p&&p&&br&&/p&&p&--- 搜索公司 ---&/p&&p&三轮&/p&&p&1:怎么样识别文本垃圾信息;&/p&&p&2:(数据结构)树合并;&/p&&p&3:工作涉及到的业务知识;&/p&&p&4: python如何把16位进制的数转换成2进制的数;&/p&&p&5:MySQL的键的一个问题;&/p&&p&6: linux下如何把两个文件按照列合并&/p&&p&7:map-reduce的原理(问的基础,因为我简历没有mapreduce);&/p&&p&8:NLP方面的想法;&/p&&p&9:职业规划,专家型还是领导型;&/p&&p&10:如果给offer是不是直接来此公司;&/p&&p&&br&&/p&&p&说实话,搜索公司最耿直,一下午面玩完全没有任何磨磨唧唧就给了口头offer;&/p&&p&如果留在北京,首选肯定是它了;&/p&&p&后面问我在面其他哪些公司,如果给了offer去哪家,我说就这家,那时候也没想到后面的两家深圳公司也过了,感觉蛮愧疚的,就冲这个态度也应该去此公司的;&/p&&p&真的不像网上流传的那些;而且此公司最后面的manager是我见过态度很好而且感觉可以依靠人;&/p&&p&&br&&/p&&p&&br&&/p&&p&&br&&/p&&p&-- 大厂 ---&/p&&p&1: 链表逆转&/p&&p&2:1亿的文本如何放在100台机器上两两做相似度计算&/p&&p&3:40亿数据如何用2G内存排序&/p&&p&4;遍历树&/p&&p&5:HMM原理&/p&&p&&br&&/p&&p&大厂来面我的人级别很高,全程碾压我,最后我说话都不利索了,完全想不到会过的;&/p&&p&感觉大厂效率很高,hr也很专业;其实就面了两轮就谈薪资了;&/p&&p&&br&&/p&&p&总体来说,面试还是很顺利,基本上投的公司都给了offer;因为要去深圳,有两个很好的北京的机会不能去,真心遗憾;&/p&&p&&br&&/p&&p&有兴趣关注一下我的机器人,公众号是cross_entropy,可以联系到我;&/p&
更新社招;其实里面漏了一个重要我原本打算去的机会,但我临时还是决定去大厂,今天这公司总监给我打了个电话,谈到由业务驱动转向技术驱动,也说了一些挽留话,我真蛮感动的;之前hr的积极更进以及最后我的临时变卦,其实我都蛮惭愧;我一直…
&p&随着DeepMind公司开发的AlphaGo升级版master战胜围棋世界冠军,其背后应用的强化学习思想受到了广泛关注,也吸引了我想一探究竟为什么强化学习的威力这么大。早在2015年,DeepMind就在youtube上发布了围棋程序master的主要作者David Silver主讲的一套强化学习视频公开课,较为系统、全面地介绍了强化学习的各种思想、实现算法。其一套公开课一共分为十讲,每讲平均为100分钟。其中既包括扎实的理论推导,也有很多有趣的小例子帮助理解,对于理解强化学习来说是一套非常好的教程。我在跟随这套教程学习的过程中一边听讲、一边笔记,最后编写代码实践,终于算是对强化学习的概念终于有了初步的认识,算是入门了吧。为了巩固加深自己的理解,同时也能为后来的学习者提供一些较为系统的中文学习资料,我萌生了把整个公开课系统整理出来的想法。&/p&&p&本学习笔记力求尽可能还原David Silver的视频演讲,力求用通俗的语言、丰富的示例讲解来深入浅出的解释强化学习中的各种概念算法。对于其中重要概念的英文词汇的翻译,力求能尽可能符合其实际含义,同时保留英文原文。限于水平,其中难免有理解偏颇甚至错误的地方,希望同行能够不吝指出,在此先表谢意。&/p&&p&&br&&/p&&p&David Silver的这套视频公开课可以在youtube上找到,其链接地址如下:&a href=&/?target=https%3A///watch%3Fv%3D2pWv7GOvuf0%26list%3DPL7-jPKtc4r78-wCZcQn5IqyuWhBZ8fOxT& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&/watch?v=2pWv7GOvuf0&list=PL7-jPKtc4r78-wCZcQn5IqyuWhBZ8fOxT&i class=&icon-external&&&/i&&/a& 。不知道国内的视频网站有没有原版视频。同时David也公开了它视频里所使用的讲义pdf,讲义内容与视频内容在某些地方有细微差别,应该是讲义更新些。我把这些转到百度网盘,地址是:&a href=&/?target=https%3A///s/1nvqP7dB& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/s/1nvqP7d&/span&&span class=&invisible&&B&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&。 同样在这个地址还有David在公开课第一讲里推荐阅读的两篇关于强化学习的教材。&/p&&p&目前用于强化学习编程实践的常用手段是使用OpenAI推出的gym库,该库支持python语言。其官方网站在这里: &a href=&/?target=https%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&OpenAI Gym: A toolkit for developing and comparing reinforcement learning algorithms&i class=&icon-external&&&/i&&/a&。 正如其描述的一样,它是一个开发、比较各种强化学习算法的工具库,提供了不少内置的环境,是学习强化学习不错的一个平台,gym库的一个很大的特点是可以可视化,把强化学习算法的人机交互用动画的形式呈现出来,这比仅依靠数据来分析算法有意思多了。我自己也设计了与gym兼容的、针对讲义内容中提到的格子世界环境类和其它一些有意思的类。&/p&&p&这里还介绍一个网站给大家:&a href=&/?target=http%3A//cs.stanford.edu/people/karpathy/reinforcejs/index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Gridworld with Dynamic Programming&i class=&icon-external&&&/i&&/a&。它是人工智能领域的青年专家Karpathy用javascript结合d3可视化的几个强化学习的Demo,非常有趣,我也借鉴了不少他的ReinforceJS库中的代码。不过Python将会是我结合公开课进行编码的主要编程语言。在早期,我将在尽可能不适用任何库的情况下实践一些简单的算法思想,在后期,由于涉及到一些函数的近似,需要使用一些深度学习的算法,会使用到Tensorflow或Pytorch。&/p&&p&总体来说,学习强化学习、理解其算法不需要特别深的数学和编程知识,但一定的微积分、矩阵、概率统计知识还是需要的。对于编程来说,Python已经使得编程变得非常容易。相信跟随这套笔记,任何想了解强化学习的人都能对其有比较深刻的理解。&/p&&p&序言就写到这里吧,敬请期待David Silver的《强化学习》第一讲 简介。&/p&
随着DeepMind公司开发的AlphaGo升级版master战胜围棋世界冠军,其背后应用的强化学习思想受到了广泛关注,也吸引了我想一探究竟为什么强化学习的威力这么大。早在2015年,DeepMind就在youtube上发布了围棋程序master的主要作者David Silver主讲的一套强化学…
&img src=&/v2-ab72d922_b.png& data-rawwidth=&1240& data-rawheight=&620& class=&origin_image zh-lightbox-thumb& width=&1240& data-original=&/v2-ab72d922_r.png&&&blockquote&&b&张瑞&/b&,研究生毕业于北京邮电大学,毕业后一直从事搜索引擎及自然语言处理方向的研发工作。曾就职于百度及豌豆荚。现任知乎机器学习团队负责人。&/blockquote&&p&&b&特约记者丨杨润琦(南京大学),刘冲(北京邮电大学)&/b&&/p&&p&&b&杨润琦:&/b&能否和我们介绍一下知乎的机器学习团队?目前主要负责哪些方面的工作和任务呢?&/p&&p&&b&张瑞:&/b&我们团队是一个横向的功能团队,也就是说整个知乎平台上用到的机器学习场景都会交给我们团队负责,也包括建设一套完整的机器学习栈。我们将所有的应用场景分为两大模块,六大方向。两大模块分别是基础数据和基础技术,另一个是和业务相关的,用于改善内容流通和产品体验。&/p&&img src=&/v2-f185ae207db1_b.png& data-rawwidth=&1080& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1080& data-original=&/v2-f185ae207db1_r.png&&&p&基础数据和基础技术主要包含用户画像和内容分析两部分工作。首先用户画像我们会根据用户的交互行为、回答问题、自身资料等数据挖掘其社会学属性、兴趣爱好等等,也会根据其问答行为对其在某个领域的权威度进行分析。其次内容分析部分主要是针对知乎上面所有的内容(包括文本、图像、音视频等)建立一套完善的内容分析流水线。 &/p&&p&一般所有发送到知乎上面的内容都会在发布的第一瞬间通过该实时计算框架,结合自然语言处理、图片识别、或者音视频降噪等技术进行一个基础但是很重要的分析工作。比如说文本类内容,会进行实体抽取、词语切分、topic 建模、分类等。另一个模块就是与业务密切相关的,主要是用于改进用户体验,提升内容在知乎平台上的流通效率,根据业务场景可以划分为推荐、排序、商业化、社区管理四个方面。 &/p&&p&首先我们会有一个统一的推荐引擎负责公司所有的推荐场景,进行千人千面的推荐。这里会结合上面提到的用户画像技术和一些比较先进的比如深度学习等方法提升推荐效果。 &/p&&p&其次,排序相对而言更横向一点,会用在推荐、首页信息流、搜索等其他模块之中,会针对性的根据各个业务不同情况收集不同数据,提取特征,再训练排序的模型。 &/p&&p&第三个是商业化,主要包括广告和机构号,这里会在推荐和排序的基础上做一些更有特点的工作,比如针对广告主做竞价、流量预估、物料推荐等等。 &/p&&p&最后一个就是社区管理,这部分工作与内容分析和用户画像的对接比较紧密,会做一些最基本的工作,比如色情图片检测等,以及根据用户画像和内容分析得到的一些数据,结合社区管理层面的业务需求做一些更上层的事情。 &/p&&p&以我们正在做的“潜在权威创作用户挖掘”举例,在知乎平台上有很多优秀的答题者,他们在自己的专业领域积累了一定知识,具备很强的能力,所以我们需要在第一时间发现他,并邀请他创作高质量的内容,从而提升用户产生优质答案的生产效率。所以整个来讲,我们机器学习团队的工作主要分为两个大的模块,六个方向。&/p&&p&&b&杨润琦:&/b&您觉得从技术层面上来讲,团队成立以来解决过的最大的一个困难是什么?&/p&&p&&b&张瑞:&/b&从我个人的角度上来讲,目前我们所遇到的问题、正在做的事情大都还是能够想得很清楚,很少遇到从一开始就不知道该怎么做的情况。而且有些我们在做的东西我感觉还是不错的,甚至还超出了我们的预期效果。就像爬山一样,在爬之前可能会觉得很难爬甚至爬不上去,但是等你过去了之后你就会觉得其实一步一步走上来也没有那么艰难。 &/p&&p&以我们首页的产品举例,过去半年首页的转化率提升了将近 70%,同时首页的停留时长也增加了 40% 多。也就是说配合上用户留存率的提升,用户在首页的内容消费大概翻了一番。 &/p&&p&但是在我们做这个工作之前,我们想的只是一步一步踏实的推进,一步一步地把能想到的特征提取出来,比如说用户的兴趣、实时兴趣、答案本身质量好坏、用户兴趣与答案所属领域交叉、用户本身的社交关系、与发布答案者的社交关系交叉等等,这些都是一点一点添加到模型中的,欣慰的是在做的过程中发现提取的这些特征都能够转化成比较好的效果,每一次都有比较好的提升,经过半年的迭代,最终收获了比较不错的效果。&/p&&p&&b&刘冲:&/b&前面提到的两大模块六个任务,是如何进行分配和组织的呢?整个工作耗费了多长时间?&/p&&p&&b&张瑞:&/b&我们在去年年初的时候刚刚建立团队,目前团队已经接近 20 个人规模,初期团队主要是把精力集中在基础数据和基础技术的工作上,比如用户流量场景优化、知识的商业化、社区管理等工作也会有所涉及。到今年,我们结合了一些深度学习领域的研究成果,搭建了完善的推荐系统。 &/p&&p&目前来讲六个方向上都会安排人去做,大家齐头并进,具体到某一个方向还是会根据具体的工作场景决定工作的方法。其实我们还有很多项目想要开展,也一直在招募工作伙伴中。 &/p&&p&&b&杨润琦:&/b&刚才说到在推荐系统中会用到深度学习相关的技术,可以具体的聊一下吗? &/p&&p&&b&张瑞:&/b&其实深度学习用在推荐也好、排序也好、搜索也好,本质上说解决的是用户信息需求和信息之间的匹配关系。在拥有足够数据量的情况下,深度学习可以更好的解决这些问题。 &/p&&p&比如说推荐,之前可能先把内容划分到一个具体的领域,体育、商业等,然后再看用户喜欢哪个领域的内容,将很多交叉特征去组合起来做推荐。这样的缺点是,首先领域信息是人工设计的,可能和用户真实需求有一定差距,比如说用户喜欢体育,但并不代表所有体育的东西都会喜欢,可能只喜欢乒乓球、篮球,不喜欢足球,另外一个就是特征会比较稀疏,很难找到其关联性,比如一个人喜欢商业,那大概率也会喜欢金融,这就需要一个非常复杂的规则或者补充模型来解决。 &/p&&p&所以说浅层学习,比如 LR 这种模型,当你用到一定程度之后就会考虑向深度学习上转移,使用深度学习来解决信息需求和信息本身之间的匹配程度问题。这里用户的信息需求可能表现成其历史行为中体现出来的兴趣,用户的资料也会体现他喜欢的东西,把这些东西全部拿过来当做用户信息需求表征的一部分,通过这种上下文信息以及海量的用户行为来预测用户会看什么内容,今天看了什么,明天会看什么等等。 &/p&&p&目前我们使用了四层的神经网络,融合了 CNN、word embedding、userembedding 等预训练的嵌入式表示,使用这样的网络去做匹配。那么通过这个网络推荐出来的东西,相对来讲可以搞定传统机器学习解决不了的问题。所以我们开始用深度学习来解决推荐推荐、排序等问题,比如说搜索下面我们会做 query 和内容文本之间的匹配。&/p&&p&&b&刘冲:&/b&我记得之前谷歌发过一篇用深度学习做视频推荐的文章,那么您在做这个方向的时候会参考他们的论文,使用他们的模型还是自己会尝试修改?另外就是当从传统机器学习转型到深度学习时,你们专门招一些深度学习的人才还是让技术人员进行转型去学习这方面的东西呢?&/p&&p&&b&张瑞:&/b&第一个问题的话,我们肯定会参考业界最先进的技术,比如说谷歌的两个 DNN 网络做视频推荐这种,不过我们最后用到的东西并不会完全按照他们提出的模型进行部署,但实际上讲,大家用到的技术从本质上讲都是差不多的,思路也是一样的。 &/p&&p&我们会参考他们论文里提出的先进的经验,比如说 wide and deep 网络结构,wide 负责 memory,deep 负责推理和泛化;YouTube 使用多个神经网络进行推荐,将用户和内容进行 embedding 的思想我们都会进行借鉴和参考,把一些好的特征加入到我们的网络中,所以说最后在技术层面上来讲是融合各家之长。 &/p&&p&第二个问题,我觉得传统的机器学习和深度学习之间并没有很深的鸿沟,其实是可以跨越的。像我们现在在做推荐系统的很多同学,他们之前是使用 GBDT、LR 等传统机器学习方法去做,但大家学习、接触深度学习的知识还是挺快的,因为本身来讲,深度学习和传统机器学习之间的优化思想、理论基础还是比较类似的。&/p&&p&&b&刘冲:&/b&那你们会不会找一些这方面的大牛来带着做还是就靠自己去学习?&/p&&p&&b&张瑞:&/b&知乎有很多比较有经验的工程师,也会有一些刚入门的同学,他们之间肯定会存在技术上的差距,所以经常会举办一些技术分享、新人与老人之间的传帮带等等,大家会经常坐在一起分享和讨论。比如说我刚才说到的那些深度学习方面的项目,都是我们在技术分享周会上面参考了很多同学的调研结果,然后大家一起讨论,总结出一个适用于知乎的一个架构出来。&/p&&p&至于说会不会找这方面的大牛,可以透露一点就是我们会有比较新的或者前沿的产品探索去做,涉及到自然语言处理和智能问答方向,这块我们想找一个资深科学家去做前沿的探索,这也是对我们团队本身技术能力、人员梯队的一种补充。&/p&&p&&b&杨润琦:&/b&能不能跟我们分享一下知乎机器学习挑战赛的相关内容,为什么想要办这样一个比赛?&/p&&p&&b&张瑞:&/b&知乎机器学习挑战赛的初衷是想激发一下大家对于自然语言理解这个领域的兴趣。这个题目其实当时我们也是考虑了很久,然后比较慎重地去选择的。首先我们觉得它比较能够体现知乎的特色,这个题目跟知乎的产品结合得还是比较紧密的。 &/p&&p&另外我们在设计这个题目的时候也考虑了它的难易度和区分度,一方面对于刚入门的同学来说,想要借助这个题目去尝试、去实践一些很传统的方法,甚至很简单的一些方法也是 OK 的;另一方面它不是一个可以非常容易就被很好地解决的问题,做到一定阶段之后如果想要提高,可能就需要设计一些创新的点或者引入一些更前沿的技术,所以题目也会存在一个区分度。 &/p&&p&比如我们提供的数据里面,包含标签之间的结构信息和标签本身的意义的信息,这个对应的是现在多标签分类里面的比较前沿的方向,就是包含结构信息的标签的多分类问题。我们希望比较优秀的队伍能够把这些信息利用起来,去做一些不错的创新。&/p&&p&&b&刘冲:&/b&那您觉得现在比赛的进度可以达到你们的预期吗?&/p&&p&&b&杨润琦:&/b&以及您怎么评价那些排名靠前的团队目前达到的程度?&/p&&p&&b&张瑞:&/b&我们记得当初我们做这个规划的时候,是说我们大概会有七八百支队伍这个样子。现在比赛进程大概到一半,已经有快九百支队伍参加,所以从进程上来讲还是不错的。&/p&&p&从选手提交的结果上看——其实我们有定期的周报收集,收集一些已经做出来比较优秀的结果的队伍的代码和说明文档。我看了一下,其实里面还是有一些比较闪光的点。整体上来讲,大家在把一些最前沿的技术运用进来,或者说是在比较复杂的模型上面去调整模型的效果,在这方面的能力其实还是非常棒的。&/p&&p&如果要说还有什么缺憾的话,我觉得可能是目前虽然看到了很多小的闪光点或者创新点,但是还没有一个比较大的跨越式创新出现。不过归根结底创新本来就也不是一个很容易出现的事情,所以其实到现在为止,我觉得整个比赛的进度,包括大家的结果,从我自己来看,还是比较超出预期的。&/p&&p&&b&刘冲:&/b&您觉得最后预计最后得分能做到多少?&/p&&p&&b&杨润琦(坏笑):&/b&会超过当前线上模型的表现吗?&/p&&p&&b&张瑞:&/b&从得分公式的设计上来看,最后如果你能做到 100% 的准确的话,满分是 0.8 多一点,但是数据本身存在一定的噪声或者说缺失,因为我们的产品有个限制,对问题打的标签不能超过一定的个数,而一个问题可能和十几个标签都相关。刨除掉这个因素,我们预计最理想的结果可能可以到 0.5 往上一点。 &/p&&p&目前提交上来前三的同学在测试数据上的表现已经做到相当不错的程度(注:截至采访时间 A 榜最高分数在 0.42 左右),当然和我们的线上还是有一定的差距,但是这个对比本身可能有一定的不公平性,因为我们线上拿到的数据可能会更多,而且都是明文(注:指比赛数据经过了隐私保护和脱敏处理),所以直接这样去对比还是不公平的。&/p&&p&&b&刘冲:&/b&在做算法的时候,准确度和计算效率目前你们会更看重哪一点?&/p&&p&&b&张瑞:&/b&在绝大部分场景下,我们追求的是准确度,然后计算效率。&/p&&p&&b&刘冲:&/b&是因为实时性的要求并不高吗?&/p&&p&&b&张瑞:&/b&并不是这样,其实是说计算资源相对于准确性来讲还是比较容易去解决的。比如说我们做深度学习的模型,四层网络的预测,基本上在 CPU 机器上面对一个 batch 的数据,例如 50 条进行预测,耗时是两毫秒左右,换用 GPU 的话还会更快。互联网工业界有一个比较流行的说法,就是说你能够通过升级机器或者加机器来解决,就不要去改动模型和算法,因为机器总是比人要便宜很多的。所以在绝大部分时候,我们确实是更追求准确度,也就是说最后线上产品的效果。 &/p&&p&我觉得你这个问题可能可以升级一下,就是说算法的效果和算法的整体架构哪个会更重要一点。比如说你是希望一个比较清晰的架构,它的效果稍微差一点;还是拼凑了很多乱七八糟的东西,最后产生的效果比较好,但是你也很难去修改它? &/p&&p&这个时候,从一般的实践上来讲,我们会更倾向于那种优秀的架构,因为它往往能够带来迭代效率的提高。可能从第一版来看,它的算法的效果确实不如其他的堆起来来得那么快,但是一般来说算法不是一版就可以来完成,一个比较优秀清晰的架构为算法的迭代带来便利是比较大的。如果可以做到两天三天就完成一个迭代,那么就可以把效果一点一点提升起来。所以这种情况下来讲,算法的架构上的清晰和优美到最后仍然还是为了这种算法的准确度去服务的。&/p&&p&&b&杨润琦:&/b&所以可能它最终还是保持了一个良好的架构,但是准确度已经超过了之前的那种七拼八凑的?&/p&&p&&b&张瑞:&/b&对。&/p&&p&&b&杨润琦:&/b&这让我想到了一个很有意思的问题,我某个师兄去某互联网公司做算法的时候遇到了一些麻烦,就是他引入了一个比较新的技术范式,这个范式做成以后以前做的一些模块就显得比较累赘了,从算法效率来看应该去掉,但最后却保留在了系统里,因为其他工程师会觉得那是他们做了几年的东西,如果整个去掉就是否定了他们的工作成果,对于这个现象您怎么看?&/p&&p&&b&张瑞:&/b&就是说技术更新换代,可能会……&/p&&p&&b&杨润琦:&/b&遇到这种非技术的阻力。&/p&&p&&b&张瑞:&/b&知乎基本不存在这个问题。其实不光是我们团队内,也包括我们这个团队和其他技术团队之间的沟通,或者说我们这个技术团队和业务团队之间的沟通,大家在做事情的时候其实还是会以最后的效果为目标,很少遇到这种非技术的、或者纯粹从这种抢事儿或者划地盘这种方面来的阻力。 &/p&&p&我觉得做数据的同学,最后都会有一个比较强的 sense,就是数据驱动。如果最后拿不出明确的数据来支持你的观点的话,那这种吵架,或者说抬杠,其实都没有意义。在知乎我们还是比较倾向于用这种方式去做沟通和交流的,以最后客观的标准去看哪种技术,或者说哪种方案会更好一点。&/p&&p&&b&杨润琦:&/b&在最后能不能给年轻人一些建议,尤其是对未来想要应聘机器学习岗位的博士生或者硕士生?&/p&&p&&b&张瑞:&/b&我觉得对于一个机器学习工程师来讲,工程能力和对机器学习理论的理解能力,这两个方面其实是不可偏废的。工程能力,或者说架构能力,可以使你的做事效率有一个质的提升。比如说做机器学习的工程师,肯定是会遇到很多实验的,需要收集数据、采集各种各样的特征,这个时候,你的工程能力,包括我刚才提到的架构决定了你迭代的快慢,或者说你把你自己的想法去实现出来这样一个快慢。这是工程能力提升了之后能够给你带来好处。 &/p&&p&另外一个是在机器学习理论方面的能力。现在我们开源的库或者包其实都很多了,很多同学会觉得,我能够在数据上面跑出来结果那就 OK 了,我不需要关注它里面是什么样的,这其实是一个误区。如果你对它的理论基础没有一个清晰的认识的话,你是不知道怎么去对它做优化的。 &/p&&p&比如说举一个最简单的一个例子:线性模型和非线性模型的选择。这个时候你需要知道 LR 是一个广义线性模型的然后 GBDT 是一个 tree based 的非线性模型,它能够对特征进行非线性划分。在不同的场景下面,特征对最后的目标的贡献,可能是线性的,也可能是非线性的,如果你不知道这个的话,对于模型的效果就没法去做提升了。这个是对知识和技术层面的一个考量。 &/p&&p&对于在校的同学,其实还是建议大家能够多去做一些实践,包括利用自己的寒暑假或者是闲暇的时间去实习,或者说去参加一些竞赛,比如说我们的知乎机器学习挑战赛。现在来讲,工业界用的数据和很多实验室的数据还是有挺大的不同的,公司做事情的方式和在实验室做事情方式也很不一样。如果能有一些实践的经验,这对你今后的帮助是很大的,它可以让你很快地去适应这种公司的节奏或者是方式。&/p&&p&&b&杨润琦:&/b&实践上您刚才提到了可以通过实习或者比赛来证明,那么在求职应聘的时候,应该怎么样凸现自己理论方面的能力?&/p&&p&&b&张瑞:&/b&一般来讲最好是你的简历能够引导你的面试官去问你一些你比较擅长的问题,或者说是能够展现你的亮点的问题。这个一方面是你过去做的一些事情,包括你的实践经历,另一方面可能还会有你的 GitHub,你之前整理的一些技术博客或者文档,这些东西都能很好地体现你过去所做的事情和掌握的知识。其实我接到简历里面,很多同学都会有自己的 GitHub 地址,有的同学确实也实现出来很漂亮的代码,我每次筛简历遇到都会很认真地去看。 &/p&&p&另外如果想要展示你知识的扎实,那么对于所有你做过的东西里面涉及到的基础知识是需要有一个很好的掌握的。举一个例子,比如说做文本相关性的,多多少少的都会接触到 word embedding,很多人只是说我拿 word embedding 来简单地用一下,但如果你对它有一个比较扎实深入的了解的话,其实是能够为面试官带来很多不一样的感受。&/p&&p&&b&关于PaperWeekly&/b& &/p&&p&PaperWeekly是一个推荐、解读、讨论、报道人工智能前沿论文成果的学术平台。如果你研究或从事AI领域,欢迎在公众号后台点击&b&「交流群」&/b&,小助手将把你带入PaperWeekly的交流群里。&/p&&p&&b&微信公众号:PaperWeekly&/b&&/p&&p&&b&新浪微博:@PaperWeekly&/b&&/p&
张瑞,研究生毕业于北京邮电大学,毕业后一直从事搜索引擎及自然语言处理方向的研发工作。曾就职于百度及豌豆荚。现任知乎机器学习团队负责人。特约记者丨杨润琦(南京大学),刘冲(北京邮电大学)杨润琦:能否和我们介绍一下知乎的机器学习团队?目前主要…
&blockquote&近日,Dishashree Gupta 在 Analyticsvidhya 上发表了一篇题为《Architecture of Convolutional Neural Networks (CNNs) demystified》的文章,对用于图像识别和分类的卷积神经网络架构作了深度揭秘;作者在文中还作了通盘演示,期望对 CNN 的工作机制有一个深入的剖析。机器之心对本文进行了编译,&a href=&///?target=https%3A///blog/2017/06/architecture-of-convolutional-neural-networks-simplified-demystified/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原文链接在此&i class=&icon-external&&&/i&&/a&,希望对你有帮助。&/blockquote&&h2&&a href=&///?target=https%3A//mp./s%3F__biz%3DMzA3MzI4MjgzMw%3D%3D%26mid%3D%26idx%3D1%26sn%3D61e9cbc505eb464escene%3D0%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&机器视角:长文揭秘图像处理和卷积神经网络架构&i class=&icon-external&&&/i&&/a&&/h2&&p&&br&&/p&&h2&&b&引言&/b&&/h2&&p&先坦白地说,有一段时间我无法真正理解深度学习。我查看相关研究论文和文章,感觉深度学习异常复杂。我尝试去理解神经网络及其变体,但依然感到困难。&/p&&p&&br&&/p&&p&接着有一天,我决定一步一步,从基础开始。我把技术操作的步骤分解开来,并手动执行这些步骤(和计算),直到我理解它们如何工作。这相当费时,且令人紧张,但是结果非凡。&/p&&p&&br&&/p&&p&现在,我不仅对深度学习有了全面的理解,还在此基础上有了好想法,因为我的基础很扎实。随意地应用神经网络是一回事,理解它是什么以及背后的发生机制是另外一回事。&/p&&p&&br&&/p&&p&今天,我将与你共享我的心得,展示我如何上手卷积神经网络并最终弄明白了它。我将做一个通盘的展示,从而使你对 CNN 的工作机制有一个深入的了解。&/p&&p&&br&&/p&&p&在本文中,我将会讨论 CNN 背后的架构,其设计初衷在于解决图像识别和分类问题。同时我也会假设你对神经网络已经有了初步了解。&/p&&p&&br&&/p&&h2&&b&目录&/b&&/h2&&p&1.机器如何看图?&/p&&p&2.如何帮助神经网络识别图像?&/p&&p&3.定义卷积神经网络&/p&&ul&&li&卷积层&/li&&li&池化层&/li&&li&输出层&/li&&/ul&&p&4.小结&/p&&p&5.使用 CNN 分类图像&/p&&p&&br&&/p&&h2&&b&1. 机器如何看图?&/b&&/h2&&p&人类大脑是一非常强大的机器,每秒内能看(捕捉)多张图,并在意识不到的情况下就完成了对这些图的处理。但机器并非如此。机器处理图像的第一步是理解,理解如何表达一张图像,进而读取图片。&/p&&p&&br&&/p&&p&简单来说,每个图像都是一系列特定排序的图点(像素)。如果你改变像素的顺序或颜色,图像也随之改变。举个例子,存储并读取一张上面写着数字 4 的图像。&/p&&p&&br&&/p&&p&基本上,机器会把图像打碎成像素矩阵,存储每个表示位置像素的颜色码。在下图的表示中,数值 1 是白色,256 是最深的绿色(为了简化,我们示例限制到了一种颜色)。&/p&&p&&br&&/p&&img src=&/v2-cef0c90b60ba_b.png& data-rawwidth=&387& data-rawheight=&380& class=&content_image& width=&387&&&p&&br&&/p&&p&一旦你以这种格式存储完图像信息,下一步就是让神经网络理解这种排序与模式。&/p&&p&&br&&/p&&h2&&b&2. 如何帮助神经网络识别图像?&/b&&/h2&&p&表征像素的数值是以特定的方式排序的。&/p&&img src=&/v2-d6efa_b.png& data-rawwidth=&848& data-rawheight=&808& class=&origin_image zh-lightbox-thumb& width=&848& data-original=&/v2-d6efa_r.png&&&p&假设我们尝试使用全连接网络识别图像,该如何做?&/p&&p&&br&&/p&&p&全连接网络可以通过平化它,把图像当作一个数组,并把像素值当作预测图像中数值的特征。明确地说,让网络理解理解下面图中发生了什么,非常的艰难。&/p&&img src=&/v2-25be163bbf174bc95613a21_b.png& data-rawwidth=&1340& data-rawheight=&140& class=&origin_image zh-lightbox-thumb& width=&1340& data-original=&/v2-25be163bbf174bc95613a21_r.png&&&p&即使人类也很难理解上图中表达的含义是数字 4。我们完全丢失了像素的空间排列。&/p&&p&我们能做什么呢?可以尝试从原图像中提取特征,从而保留空间排列。&/p&&p&&br&&/p&&h2&&b&案例 1&/b&&/h2&&p&这里我们使用一个权重乘以初始像素值。&/p&&img src=&/v2-f2bb2b737c_b.png& data-rawwidth=&1326& data-rawheight=&604& class=&origin_image zh-lightbox-thumb& width=&1326& data-original=&/v2-f2bb2b737c_r.png&&&p&现在裸眼识别出这是「4」就变得更简单了。但把它交给全连接网络之前,还需要平整化(flatten) 它,要让我们能够保留图像的空间排列。&/p&&img src=&/v2-ecb23f7cce51ed444ceefa1d35bd4240_b.png& data-rawwidth=&1354& data-rawheight=&106& class=&origin_image zh-lightbox-thumb& width=&1354& data-original=&/v2-ecb23f7cce51ed444ceefa1d35bd4240_r.png&&&p&&br&&/p&&h2&&b&案例 2&/b&&/h2&&p&现在我们可以看到,把图像平整化完全破坏了它的排列。我们需要想出一种方式在没有平整化的情况下把图片馈送给网络,并且还要保留空间排列特征,也就是需要馈送像素值的 2D/3D 排列。&/p&&p&我们可以尝试一次采用图像的两个像素值,而非一个。这能给网络很好的洞见,观察邻近像素的特征。既然一次采用两个像素,那也就需要一次采用两个权重值了&/p&&img src=&/v2-5aae57fcba2b5_b.jpg& data-rawwidth=&994& data-rawheight=&383& class=&origin_image zh-lightbox-thumb& width=&994& data-original=&/v2-5aae57fcba2b5_r.jpg&&&p&&br&&/p&&p&希望你能注意到图像从之前的 4 列数值变成了 3 列。因为我们现在一次移用两个像素(在每次移动中像素被共享),图像变的更小了。虽然图像变小了,我们仍能在很大程度上理解这是「4」。而且,要意识到的一个重点是,我们采用的是两个连贯的水平像素,因此只会考虑水平的排列。&/p&&p&&br&&/p&&p&这是我们从图像中提取特征的一种方式。我们可以看到左边和中间部分,但右边部分看起来不那么清楚。主要是因为两个问题:&/p&&p&&br&&/p&&p&1. 图片角落左边和右边是权重相乘一次得到的。&/p&&p&2. 左边仍旧保留,因为权重值高;右边因为略低的权重,有些丢失。&/p&&p&&br&&/p&&p&现在我们有两个问题,需要两个解决方案。&/p&&p&&br&&/p&&h2&&b&案例 3&/b&&/h2&&p&遇到的问题是图像左右两角只被权重通过一次。我们需要做的是让网络像考虑其他像素一样考虑角落。我们有一个简单的方法解决这一问题:把零放在权重运动的两边。&/p&&img src=&/v2-b87ae12947cffa0f429d5f1_b.jpg& data-rawwidth=&1225& data-rawheight=&389& class=&origin_image zh-lightbox-thumb& width=&1225& data-original=&/v2-b87ae12947cffa0f429d5f1_r.jpg&&&p&&br&&/p&&p&你可以看到通过添加零,来自角落的信息被再训练。图像也变得更大。这可被用于我们不想要缩小图像的情况下。&/p&&p&&br&&/p&&h2&&b&案例 4&/b&&/h2&&p&这里我们试图解决的问题是右侧角落更小的权重值正在降低像素值,因此使其难以被我们识别。我们所能做的是采取多个权重值并将其结合起来。&/p&&p&&br&&/p&&p&(1,0.3) 的权重值给了我们一个输出表格&/p&&img src=&/v2-ca6e6b4afb696bccdcbda_b.png& data-rawwidth=&333& data-rawheight=&376& class=&content_image& width=&333&&&p&&br&&/p&&p&同时表格 (0.1,5) 的权重值也将给我们一个输出表格。&/p&&img src=&/v2-cf8ff64d38ce55d2c1de2_b.png& data-rawwidth=&331& data-rawheight=&396& class=&content_image& width=&331&&&p&两张图像的结合版本将会给我们一个清晰的图片。因此,我们所做的是简单地使用多个权重而不是一个,从而再训练图像的更多信息。最终结果将是上述两张图像的一个结合版本。&/p&&p&&br&&/p&&h2&&b&案例 5&/b&&/h2&&p&我们到现在通过使用权重,试图把水平像素(horizontal pixel)结合起来。但是大多数情况下我们需要在水平和垂直方向上保持空间布局。我们采取 2D 矩阵权重,把像素在水平和垂直方向上结合起来。同样,记住已经有了水平和垂直方向的权重运动,输出会在水平和垂直方向上低一个像素。&/p&&p&&br&&/p&&img src=&/v2-fdebef4ea66_b.jpg& data-rawwidth=&1002& data-rawheight=&363& class=&origin_image zh-lightbox-thumb& width=&1002& data-original=&/v2-fdebef4ea66_r.jpg&&&p&&br&&/p&&p&特别感谢 Jeremy Howard 启发我创作了这些图像。&/p&&p&&br&&/p&&h2&&b&因此我们做了什么?&/b&&/h2&&p&上面我们所做的事是试图通过使用图像的空间的安排从图像中提取特征。为了理解图像,理解像素如何安排对于一个网络极其重要。上面我们所做的也恰恰是一个卷积网络所做的。我们可以采用输入图像,定义权重矩阵,并且输入被卷积以从图像中提取特殊特征而无需损失其有关空间安排的信息。&/p&&p&&br&&/p&&p&这个方法的另一个重大好处是它可以减少图像的参数数量。正如所见,卷积图像相比于原始图像有更少的像素。&/p&&p&&br&&/p&&h2&&b&3.定义一个卷积神经网络&/b&&/h2&&p&我们需要三个基本的元素来定义一个基本的卷积网络&/p&&p&&br&&/p&&p&1. 卷积层&/p&&p&2. 池化层(可选)&/p&&p&3. 输出层&/p&&p&&br&&/p&&h2&&b&卷积层&/b&&/h2&&p&在这一层中,实际所发生的就像我们在上述案例 5 中见到的一样。假设我们有一个 6*6 的图像。我们定义一个权值矩阵,用来从图像中提取一定的特征。&/p&&img src=&/v2-1e95f13c1f0d650e826e813c0e1f493a_b.png& data-rawwidth=&425& data-rawheight=&159& class=&origin_image zh-lightbox-thumb& width=&425& data-original=&/v2-1e95f13c1f0d650e826e813c0e1f493a_r.png&&&p&我们把权值初始化成一个 3*3 的矩阵。这个权值现在应该与图像结合,所有的像素都被覆盖至少一次,从而来产生一个卷积化的输出。上述的 429,是通过计算权值矩阵和输入图像的 3*3 高亮部分以元素方式进行的乘积的值而得到的。&/p&&p&&br&&/p&&img src=&/v2-f9dabe62c1e5c63e418f1_b.jpg& data-rawwidth=&487& data-rawheight=&168& class=&origin_image zh-lightbox-thumb& width=&487& data-original=&/v2-f9dabe62c1e5c63e418f1_r.jpg&&&p&&br&&/p&&p&现在 6*6 的图像转换成了 4*4 的图像。想象一下权值矩阵就像用来刷墙的刷子。首先在水平方向上用这个刷子进行刷墙,然后再向下移,对下一行进行水平粉刷。当权值矩阵沿着图像移动的时候,像素值再一次被使用。实际上,这样可以使参数在卷积神经网络中被共享。&/p&&p&&br&&/p&&p&下面我们以一个真实图像为例。&/p&&img src=&/v2-56acff17e4c36aba47234_b.png& data-rawwidth=&640& data-rawheight=&249& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-56acff17e4c36aba47234_r.png&&&p&权值矩阵在图像里表现的像一个从原始图像矩阵中提取特定信息的过滤器。一个权值组合可能用来提取边缘(edge)信息,另一个可能是用来提取一个特定颜色,下一个就可能就是对不需要的噪点进行模糊化。&/p&&p&先对权值进行学习,然后损失函数可以被最小化,类似于多层感知机(MLP)。因此需要通过对参数进行学习来从原始图像中提取信息,从而来帮助网络进行正确的预测。当我们有多个卷积层的时候,初始层往往提取较多的一般特征,随着网络结构变得更深,权值矩阵提取的特征越来越复杂,并且越来越适用于眼前的问题。&/p&&p&&br&&/p&&h2&&b&步长(stride)和边界(padding)的概念&/b&&/h2&&p&像我们在上面看到的一样,过滤器或者说权值矩阵,在整个图像范围内一次移动一个像素。我们可以把它定义成一个超参数(hyperparameter),从而来表示我们想让权值矩阵在图像内如何移动。如果权值矩阵一次移动一个像素,我们称其步长为 1。下面我们看一下步长为 2 时的情况。&/p&&p&&br&&/p&&img src=&/v2-2d5ce7b1af041dab1bb71b_b.jpg& data-rawwidth=&421& data-rawheight=&150& class=&origin_image zh-lightbox-thumb& width=&421& data-original=&/v2-2d5ce7b1af041dab1bb71b_r.jpg&&&p&&br&&/p&&p&你可以看见当我们增加步长值的时候,图像的规格持续变小。在输入图像四周填充 0 边界可以解决这个问题。我们也可以在高步长值的情况下在图像四周填加不只一层的 0 边界。&/p&&img src=&/v2-67c54ac5b709f0d13ce78e9e17c8991f_b.png& data-rawwidth=&246& data-rawheight=&188& class=&content_image& width=&246&&&p&我们可以看见在我们给图像填加一层 0 边界后,图像的原始形状是如何被保持的。由于输出图像和输入图像是大小相同的,所以这被称为 same padding。&/p&&p&&br&&/p&&img src=&/v2-19f50c5cb8e1_b.jpg& data-rawwidth=&419& data-rawheight=&189& class=&content_image& width=&419&&&p&&br&&/p&&p&这就是 same padding(意味着我们仅考虑输入图像的有效像素)。中间的 4*4 像素是相同的。这里我们已经利用边界保留了更多信息,并且也已经保留了图像的原大小。&/p&&p&&br&&/p&&p&&b&多过滤与激活图&/b&&/p&&p&需要记住的是权值的纵深维度(depth dimension)和输入图像的纵深维度是相同的。权值会延伸到输入图像的整个深度。因此,和一个单一权值矩阵进行卷积会产生一个单一纵深维度的卷积化输出。大多数情况下都不使用单一过滤器(权值矩阵),而是应用维度相同的多个过滤器。&/p&&p&&br&&/p&&p&每一个过滤器的输出被堆叠在一起,形成卷积图像的纵深维度。假设我们有一个 32*32*3 的输入。我们使用 5*5*3,带有 valid padding 的 10 个过滤器。输出的维度将会是 28*28*10。&/p&&p&&br&&/p&&p&如下图所示:&/p&&img src=&/v2-defbc123f52a27bdddf8_b.png& data-rawwidth=&640& data-rawheight=&220& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-defbc123f52a27bdddf8_r.png&&&p&&br&&/p&&p&激活图是卷积层的输出。&/p&&p&&br&&/p&&h2&&b&池化层&/b&&/h2&&p&有时图像太大,我们需要减少训练参数的数量,它被要求在随后的卷积层之间周期性地引进池化层。池化的唯一目的是减少图像的空间大小。池化在每一个纵深维度上独自完成,因此图像的纵深保持不变。池化层的最常见形式是最大池化。&/p&&p&&br&&/p&&img src=&/v2-cae74f156d80e8e12ec6_b.png& data-rawwidth=&259& data-rawheight=&110& class=&content_image& width=&259&&&p&在这里,我们把步幅定为 2,池化尺寸也为 2。最大化执行也应用在每个卷机输出的深度尺寸中。正如你所看到的,最大池化操作后,4*4 卷积的输出变成了 2*2。&/p&&p&让我们看看最大池化在真实图片中的效果如何。&/p&&p&&br&&/p&&img src=&/v2-e62be992ba35c0f79a2f54191da1defb_b.png& data-rawwidth=&640& data-rawheight=&246& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-e62be992ba35c0f79a2f54191da1defb_r.png&&&p&&br&&/p&&p&正如你看到的,我们卷积了图像,并最大池化了它。最大池化图像仍然保留了汽车在街上的信息。如果你仔细观察的话,你会发现图像的尺寸已经减半。这可以很大程度上减少参数。&/p&&p&&br&&/p&&p&同样,其他形式的池化也可以在系统中应用,如平均池化和 L2 规范池化。&/p&&p&&br&&/p&&h2&&b&输出维度&/b&&/h2&&p&理解每个卷积层输入和输出的尺寸可能会有点难度。以下三点或许可以让你了解输出尺寸的问题。有三个超参数可以控制输出卷的大小。&/p&&p&&br&&/p&&p&1. 过滤器数量-输出卷的深度与过滤器的数量成正比。请记住该如何堆叠每个过滤器的输出以形成激活映射。激活图的深度等于过滤器的数量。&/p&&p&2. 步幅(Stride)-如果步幅是 1,那么我们处理图片的精细度就进入单像素级别了。更高的步幅意味着同时处理更多的像素,从而产生较小的输出量。&/p&&p&3. 零填充(zero padding)-这有助于我们保留输入图像的尺寸。如果添加了单零填充,则单步幅过滤器的运动会保持在原图尺寸。&/p&&p&&br&&/p&&p&我们可以应用一个简单的公式来计算输出尺寸。输出图像的空间尺寸可以计算为([W-F + 2P] / S)+1。在这里,W 是输入尺寸,F 是过滤器的尺寸,P 是填充数量,S 是步幅数字。假如我们有一张 32*32*3 的输入图像,我们使用 10 个尺寸为 3*3*3 的过滤器,单步幅和零填充。&/p&&p&&br&&/p&&p&那么 W=32,F=3,P=0,S=1。输出深度等于应用的滤波器的数量,即 10,输出尺寸大小为 ([32-3+0]/1)+1 = 30。因此输出尺寸是 30*30*10。&/p&&p&&br&&/p&&h2&&b&输出层&/b&&/h2&&p&在多层卷积和填充后,我们需要以类的形式输出。卷积和池化层只会提取特征,并减少原始图像带来的参数。然而,为了生成最终的输出,我们需要应用全连接层来生成一个等于我们需要的类的数量的输出。仅仅依靠卷积层是难以达到这个要求的。卷积层可以生成 3D 激活图,而我们只需要图像是否属于一个特定的类这样的内容。输出层具有类似分类交叉熵的损失函数,用于计算预测误差。一旦前向传播完成,反向传播就会开始更新权重与偏差,以减少误差和损失。&/p&&p&&br&&/p&&h2&&b&4. 小结&/b&&/h2&&p&正如你所看到的,CNN 由不同的卷积层和池化层组成。让我们看看整个网络是什么样子:&/p&&p&&br&&/p&&img src=&/v2-a182bd59d24_b.png& data-rawwidth=&640& data-rawheight=&188& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-a182bd59d24_r.png&&&p&&br&&/p&&ul&&li&我们将输入图像传递到第一个卷积层中,卷积后以激活图形式输出。图片在卷积层中过滤后的特征会被输出,并传递下去。&br&&/li&&li&每个过滤器都会给出不同的特征,以帮助进行正确的类预测。因为我们需要保证图像大小的一致,所以我们使用同样的填充(零填充),否则填充会被使用,因为它可以帮助减少特征的数量。&br&&/li&&li&随后加入池化层进一步减少参数的数量。&br&&/li&&li&在预测最终提出前,数据会经过多个卷积和池化层的处理。卷积层会帮助提取特征,越深的卷积神经网络会提取越具体的特征,越浅的网络提取越浅显的特征。&br&&/li&&li&如前所述,CNN 中的输出层是全连接层,其中来自其他层的输入在这里被平化和发送,以便将输出转换为网络所需的参数。&br&&/li&&li&随后输出层会产生输出,这些信息会互相比较排除错误。损失函数是全连接输出层计算的均方根损失。随后我们会计算梯度错误。&br&&/li&&li&错误会进行反向传播,以不断改进过滤器(权重)和偏差值。&br&&/li&&li&一个训练周期由单次正向和反向传递完成。&br&&/li&&/ul&&p&&b&5. 在 KERAS 中使用 CNN 对图像进行分类&/b&&/p&&p&让我们尝试一下,输入猫和狗的图片,让计算机识别它们。这是图像识别和分类的经典问题,机器在这里需要做的是看到图像,并理解猫与狗的不同外形特征。这些特征可以是外形轮廓,也可以是猫的胡须之类,卷积层会攫取这些特征。让我们把数据集拿来试验一下吧。&/p&&p&&br&&/p&&p&以下这些图片均来自数据集。&/p&&img src=&/v2-298e3e184cabf4e7102afbd2_b.png& data-rawwidth=&640& data-rawheight=&254& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-298e3e184cabf4e7102afbd2_r.png&&&p&&br&&/p&&p&我们首先需要调整这些图像的大小,让它们形状相同。这是处理图像之前通常需要做的,因为在拍照时,让照下的图像都大小相同几乎不可能。&/p&&p&&br&&/p&&p&为了简化理解,我们在这里只用一个卷积层和一个池化层。注意:在 CNN 的应用阶段,这种简单的情况是不会发生的。&/p&&div class=&highlight&&&pre&&code class=&language-text&&#import various packagesimport osimport numpy as npimport pandas as pdimport scipyimport sklearnimport kerasfrom keras.models import Sequentialimport cv2from skimage import io
%matplotlib inline
#Defining the File Path
cat=os.listdir(&/mnt/hdd/datasets/dogs_cats/train/cat&)
dog=os.listdir(&/mnt/hdd/datasets/dogs_cats/train/dog&)
filepath=&/mnt/hdd/datasets/dogs_cats/train/cat/&filepath2=&/mnt/hdd/datasets/dogs_cats/train/dog/&#Loading the Images
label = []for i in cat:
image = scipy.misc.imread(filepath+i)
images.append(image)
label.append(0) #for cat imagesfor i in dog:
image = scipy.misc.imread(filepath2+i)
images.append(image)
label.append(1) #for dog images
#resizing all the imagesfor i in range(0,23000):
images[i]=cv2.resize(images[i],(300,300))
#converting images to arrays
images=np.array(images)
label=np.array(label)
# Defining the hyperparameters
filters=10filtersize=(5,5)
epochs =5batchsize=128input_shape=(300,300,3)
#Converting the target variable to the required sizefrom keras.utils.np_utils import to_categorical
label = to_categorical(label)
#Defining the model
model = Sequential()
model.add(keras.layers.InputLayer(input_shape=input_shape))
model.add(keras.layers.convolutional.Conv2D(filters, filtersize, strides=(1, 1), padding='valid', data_format=&channels_last&, activation='relu'))
model.add(keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(units=2, input_dim=50,activation='softmax'))
pile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(images, label, epochs=epochs, batch_size=batchsize,validation_split=0.3)
model.summary()
&/code&&/pre&&/div&&p&&br&&/p&&p&在这一模型中,我只使用了单一卷积和池化层,可训练参数是 219,801。很好奇如果我在这种情况使用了 MLP 会有多少参数。通过增加更多的卷积和池化层,你可以进一步降低参数的数量。我们添加的卷积层越多,被提取的特征就会更具体和复杂。&/p&&p&&br&&/p&&p&在该模型中,我只使用了一个卷积层和池化层,可训练参数量为 219,801。如果想知道使用 MLP 在这种情况下会得到多少,你可以通过加入更多卷积和池化层来减少参数的数量。越多的卷积层意味着提取出来的特征更加具体,更加复杂。&/p&&p&&br&&/p&&h2&&b&结语&/b&&/h2&&p&希望本文能够让你认识卷积神经网络,这篇文章没有深入 CNN 的复杂数学原理。如果希望增进了解,你可以尝试构建自己的卷积神经网络,借此来了解它运行和预测的原理。&/p&&p&&br&&/p&&p&本文首发于微信公众号:机器之心(almosthuman2014),如需转载,请私信联系,感谢。&/p&
近日,Dishashree Gupta 在 Analyticsvidhya 上发表了一篇题为《Architecture of Convolutional Neural Networks (CNNs) demystified》的文章,对用于图像识别和分类的卷积神经网络架构作了深度揭秘;作者在文中还作了通盘演示,期望对 CNN 的工作机制有一…
&p&.&/p&&p&  这个月花了将近一整个月的时间,调整了一个循环神经网络(RNN)的超参数,经历了各种挫折,最终取得了成功。在我最迷茫的时候,我曾经试图在网上搜索有针对性的调参经验,但一无所获。为了给后来人排雷,我就把我的调参经历记录在这里。&/p&&p&  要读懂这篇文章,你需要了解 RNN、LSTM、CTC,最好有过训练 CTC 网络的体验。&/p&&h2&零、任务描述&/h2&&p&  任务背景其实并不重要。如果你不想详细看,可以只看这一句:&b&我用随机梯度下降法(SGD)训练了一个使用 CTC 输出层的 RNN,可调的超参数包括梯度裁剪阈值和初始学习率。&/b&&/p&&p&  我训练的 RNN 是一个语音识别任务的声学模型。它的输入是 40 维的滤波器组特征序列,输出是音素序列。网络并不负责把音素序列进一步转换成单词序列,所以它只是一个声学模型,并不是一个完整的语音识别器。&/p&&p&  训练使用的数据为 &a href=&/?target=http%3A//www.openslr.org/resources/7/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&TEDLIUM v1&i class=&icon-external&&&/i&&/a&,其内容为 TED 讲座。其中训练数据有 206 小时,开发数据有 1.7 小时,测试数据有 3.1 小时。由于种种原因,实际中我使用了 95% 的训练数据进行训练,5% 的训练数据进行交叉验证,开发集和测试集没有用到。&/p&&p&  我一共训练了两个版本的网络。第一个版本与 &a href=&/?target=https%3A///srvk/eesen/tree/master/asr_egs/tedlium/v1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&EESEN 中的示例&i class=&icon-external&&&/i&&/a& 相同。它含有 5 个双向 LSTM 隐藏层,每层每个方向有 320 个神经元;CTC 输出层含有 40 个神经元(39 个音素 + 1 个空白),放在一个 softmax 组中。训练时的目标函数为平均每帧的 negative log-likelihood。训练算法为随机梯度下降(SGD),每个 batch 含有 2 万帧,每个 epoch(即扫描完一趟所有训练数据)约为 2,000 个 batch。使用的超参数为:梯度裁剪至 &img src=&/equation?tex=10%5E%7B-4%7D& alt=&10^{-4}& eeimg=&1&&;初始学习率为 3,在前 12 个 epoch 保持恒定,之后每个 epoch 折半,直到 24 个 epoch;训练使用了 Nesterov momentum,系数为 0.9。解码时采用朴素的 best-path decoding 得到输出音素序列,网络性能用音素错误率(PER)衡量。这个网络的训练没打什么麻烦,1 个 epoch 过后,训练集上的错误率就降到了 28.8%,交叉验证集为 30.2%;用 6 天时间跑完全部 24 个 epoch 后,最终的性能为:训练集 4.8%,交叉验证集 15.4%。&/p&&p&  我真正想训练的是第二个版本 ——「弱监督」版本。在这个版本中,对于每一条训练语音,我不再告诉网络它对应的音素串是什么,而只告诉它&b&每个音素出现了几次&/b&。网络的隐藏层结构都不变,但输出层现在只有 39 个神经元,均使用 sigmoid 激活函数。这可以看成是使用了 39 个平行的 CTC 输出层,每个输出层只负责识别一个音素;在计算目标函数时,每个 CTC 层的目标序列就是它所负责的音素重复指定的次数。训练方法、解码方法、性能指标均与「强监督」版本相同。为了控制超参数空间的规模,我只调整&b&梯度裁剪阈值&/b&和&b&初始学习率&/b&这两个超参数。我的预期是这个网络仍能进行音素识别,但学习过程可能会慢一些,性能也会比「强监督」版本差一些。&/p&&h2&一、出师不利&/h2&&p&  首先,我把「强监督」版本的超参数(梯度裁剪阈值 &img src=&/equation?tex=10%5E%7B-4%7D& alt=&10^{-4}& eeimg=&1&&、初始学习率 3)直接应用到了「弱监督」网络上。结果,经过了好几个 epoch,网络都没有输出任何音素,两个数据集上的错误率都是 100%。对比「强监督」版本在 1 个 epoch 后就达到了 30% 左右的错误率,「弱监督」版本显然出问题了。&/p&&h2&二、误入歧途&/h2&&p&  我猜想,「弱监督」网络之所以学不到东西,是因为它的目标函数跟「强监督」版本不同,造成最优超参数发生了偏移。但我并不确定应该把超参数调大还是调小。于是,我对梯度裁剪阈值 limit、初始学习率 lr 两个参数进行了 grid search,limit 在每个数量级内取一个值,lr 在每个数量级内取两个值。由于训练比较费时间(1 个 epoch 需要 8 个小时),对每组超参数,我只训练了 50 个 batch(相当于 1/40 个 epoch),并观察此时在交叉验证集中某 10 条语音上的错误率。如果训练正常,这个错误率应该小于 100%;如果训练异常,这个错误率可能等于 100%,也可能发生梯度爆炸导致程序崩溃。&/p&&p&  Grid search 的结果如下图所示:&/p&&img src=&/v2-88f640c13ee93e50468a2_b.png& data-rawwidth=&809& data-rawheight=&452& class=&origin_image zh-lightbox-thumb& width=&809& data-original=&/v2-88f640c13ee93e50468a2_r.png&&&p&&i&(图 1:初次 grid search 的结果)&/i&&/p&&p&  这个图需要好好消化一下。图的纵轴是梯度裁剪阈值,横轴是初始学习率。首先注意到,最低的错误率(蓝色)分布在对角线上。这很容易理解:当梯度真的被裁剪到了的时候,裁剪阈值缩小一个数量级,就需要学习率放大一个数量级,才会让网络参数发生相同的变化。注意到上图正中的那个 89.3,它以及周围的一些数字向右下方向延伸时毫无变化,这说明梯度裁剪已经非常「狠」了,梯度中绝大多数的分量都被裁剪得只剩下符号。这并不是我想要的。而向左上方延伸时,数值稍有不同,这说明左上这片区域中,梯度裁剪的力度适中,梯度的有些分量被裁剪了,有些则没有。&/p&&p&  当超参数的组合偏离对角线时,错误率就开始增大了。在对角线左侧,学习率太小,所以学得慢;在对角线右侧,学习率太大,容易造成梯度爆炸(鲜红色)。左下角和右上角的两片区域我并没有尝试,因为这两片区域中显然不会出现更低的错误率。&/p&&p&  整张图中最低的错误率是左上角的 88.3 和 88.5,它们对应的 limit 分别为 &img src=&/equation?tex=10%5E%7B-3%7D& alt=&10^{-3}& eeimg=&1&& 和 &img src=&/equation?tex=10%5E%7B-4%7D& alt=&10^{-4}& eeimg=&1&&,接近我最初尝试的值(&img src=&/equation?tex=10%5E%7B-4%7D& alt=&10^{-4}& eeimg=&1&&);而 lr 则是 0.01 和 0.03,比我最初尝试的值(3)小了两个数量级。于是我觉得,&b&第一节中网络没有输出的原因是学习率太大了&/b&,网络可能陷入了一个「什么也不输出」的局部最优解,出不来了。&/p&&p&  我用刚刚找到的最优超参数以及它附近的几组超参数重新训练网络,结果发现,若在每个 epoch 后测量错误率,仍然全都是 100%。实际上,对于 (limit = &img src=&/equation?tex=10%5E%7B-3%7D& alt=&10^{-3}& eeimg=&1&&,lr = 0.01) 这组超参数,「50 个 batch 之后」恰恰是错误率最低的时机。此后,错误率会逐渐回升,并在 1 个 epoch 以内回升到 100% 并保持。难道说用弱监督真的什么也学不到?我不甘心。&/p&&h2&三、曲径通幽&/h2&&p&  为了弄清楚网络到底在干什么,我决定画出在某一条语音上网络各层的输出,看看能否观察出端倪。&/p&&img src=&/v2-16d97bd76f90cf78e142ca9e_b.png& data-rawwidth=&1123& data-rawheight=&563& class=&origin_image zh-lightbox-thumb& width=&1123& data-original=&/v2-16d97bd76f90cf78e142ca9e_r.png&&&p&&i&(图 2:弱监督网络训练 50 个 batch 后各层的输出)&/i&&/p&&p&  上图是「弱监督」网络使用最初的超参数(limit = &img src=&/equation?tex=10%5E%7B-4%7D& alt=&10^{-4}& eeimg=&1&&,lr = 3)训练 50 个 batch 后,在交叉验证集里一条语音上各层的输出。这条语音共有 85 帧。图中从左到右、从上到下依次是输入的滤波器组特征、5 个隐藏层的输出,以及最后预测的每个音素的概率。由于每个隐藏层有 640 个神经元,图中画不下,所以我只画了向前方向的 40 个神经元的输出。可以看出,&b&各层的输出越来越「糊」&/b&,即在时间方向上的变化越来越不明显,到了第 3 个隐藏层,输出就基本是常数了。当然,在最开头的几帧,输出还是略有不同的。我觉得,这表示 &b&RNN 陷入了某种「死循环」&/b&,除了开头的几帧,RNN 就陷入了「不管输入是什么,输出都不变」的死亡状态了。上面的图中画的是训练 50 个 batch 之后的情景,但哪怕训练到 100 个 batch,结果都是类似的。&/p&&p&  我试图分析网络参数(包括权重和偏置)的变化,以及 LSTM 各个门的开闭情况,都没能得出明确的结论。于是,我准备也画出「强监督」网络在同一条语音上各层的输出,与「弱监督」网络对比。&/p&&img src=&/v2-ea6a677b8d_b.png& data-rawwidth=&1114& data-rawheight=&564& class=&origin_image zh-lightbox-thumb& width=&1114& data-original=&/v2-ea6a677b8d_r.png&&&p&&i&(图 3:强监督网络训练 10 个 batch 后各层的输出)&/i&&/p&&p&  上图是「强监督」网络在训练 10 个 batch 后各层的输出。我们同样看到,从第 4 个隐藏层开始,输出也「糊」掉了。但!是!随着训练的进行,这种「糊」掉的现象得以改善。比如,在训练 200 个 batch 之后,各层的输出是下面这样的。可以看到,所有隐藏层的输出都开始随着时间有变化,而且变化与输入特征中的突变基本同步。网络开始学到东西了!&/p&&img src=&/v2-e61f837d361fec_b.png& data-rawwidth=&1120& data-rawheight=&562& class=&origin_image zh-lightbox-thumb& width=&1120& data-original=&/v2-e61f837d361fec_r.png&&&p&&i&(图 4:强监督网络训练 200 个 batch 后各层的输出)&/i&&/p&&p&&b&   对「强监督」网络的观察推翻了我对于「弱监督」网络陷入「死循环」的猜想。&/b&原来,网络并不是「死了」、已经学不到东西了,而是还没有开始「活」。我想起了 CTC 网络在训练的初始阶段,会有一个「热身」(warm-up)的过程,此时「空白」符号的概率占绝对优势,网络什么也不会输出。而在「热身」阶段之前,其实还会有一个「预热身」阶段,在此阶段,「空白符号的概率占绝对优势」这一秩序尚未建立,网络可能会输出一些随机的符号(音素)。观察图 2 的最后一个子图,可以看到有 3 个音素具有较高的概率,网络会把它们输出出来。如果正好某一个音素也出现在标准答案中,PER 就会小于 100% 了。如果观察 PER 在 CTC 训练过程中的变化,会是这个样子:&/p&&img src=&/v2-bd2ad231ae8f33fc6041e_b.png& data-rawwidth=&641& data-rawheight=&417& class=&origin_image zh-lightbox-thumb& width=&641& data-original=&/v2-bd2ad231ae8f33fc6041e_r.png&&&p&&i&(图 5:CTC 训练过程中各个阶段错误率的变化)&/i&&/p&&p&  原来,图 1 中所有小于 100% 的错误率,其实都对应着「预热身阶段」。它们在一段时间后回升到 100%,不代表着网络的死亡,而是代表进入了「热身阶段」。为了促使网络尽快脱离热身阶段、进入学习阶段(下文称为「启动」),&b&不应该把学习率调低,反而应该调高&/b&。在第二节,我们调参的方向正好反了。&/p&&p&  当然,如果只调高学习率,不调整梯度裁剪阈值,就会导致梯度爆炸;所以需要相应地调低梯度裁剪阈值。如果放在图 1 中来看,就是说,最优参数很可能不位于图 1 的左上方,而是位于右下方。咦?等等,在图 1 的右下方,只要保持 limit * lr 恒定,错误率都一样呀?其实并不是这样 ——「错误率都一样」只是预热身阶段的现象。随着训练的进行,梯度的绝对值会越来越小,等到梯度裁剪不起作用的时候,就只剩下学习率决定训练进展的速度了。这说明我们应当&b&调高学习率,同时调低梯度裁剪阈值&/b&。另外,最优参数不一定位于图 1 中错误率最低的对角线上,因为预热身阶段的错误率并不能说明学习阶段的表现。我们需要在图 1 右下方区域内重新进行 grid search,这次要观察的不是一定时间后的错误率,而是需要多久网络才能「启动」。&/p&&h2&四、昂首阔步&/h2&&p&  第二次 grid search 的结果如下图。我选择的超参数都位于图 1 中对角线偏右侧的区域,因为我观察到,只有这片区域内的超参数才能使网络在 100 个 batch 之内脱离预热身阶段,而我的目的正是寻找让网络训练进展更快的超参数。对于每组超参数,我训练了 10,000 个 batch,相当于 5 个 epoch,用时接近 2 天。每过 200 个 batch,我测量了交叉验证集中 10 条语音上的错误率,图中记录的是网络「启动」的时间和发生梯度爆炸的时间。&/p&&img src=&/v2-93aa137fe9ab21a5213f4_b.png& data-rawwidth=&1004& data-rawheight=&286& class=&origin_image zh-lightbox-thumb& width=&1004& data-original=&/v2-93aa137fe9ab21a5213f4_r.png&&&p&&i&(图 6:第二次 grid search 的结果)&/i&&/p&&p&  训练 10,000 个 batch 后,我们看到了与图 1 不一样的风景。原来,当我们「昂首阔步」地把学习率调高好几个数量级之后,网络还是可以在合理的时间内启动的。使网络启动最快的超参数出现在 limit = &img src=&/equation?tex=10%5E%7B-8%7D& alt=&10^{-8}& eeimg=&1&&,lr = &img src=&/equation?tex=10%5E4& alt=&10^4& eeimg=&1&&,它只需要 1,200 个 batch 就能启动。到 5 个 epoch 时,在随机选择的 10 条交叉验证语音上的错误率已经达到了 55.6%,网络果然学到东西了!&/p&&h2&五、宁静致远&/h2&&p&  于是,我用 limit = &img src=&/equation?tex=10%5E%7B-8%7D& alt=&10^{-8}& eeimg=&1&&,lr = &img src=&/equation?tex=10%5E4& alt=&10^4& eeimg=&1&& 这组参数进行了正式的实验,每个 epoch 后在整个交叉验证集上测量错误率。令我惊喜的是,在 5 个 epoch 后,整个验证集上的错误率实际上已经降到了 44.3%。但是,到第 8 个 epoch 时,发生了梯度爆炸,训练崩溃了。&/p&&p&  看来,上一节中使用的学习率还是「步子太大,扯到蛋了」。虽然启动很快,但当梯度小到裁剪不起作用的时候,学习率太大的坏处就体现出来了。这意味着学习率不应该调得这么大,走得慢一点,才能走得远。当然,还有一种解决方案是在第 8 个 epoch 之前开始降低学习率,不过如果去试验这一点,就意味着把学习率的 schedule(包括在什么时候开始衰减、衰减多快)也纳入待调整的超参数,超参数空间一下子又升了两维,这并不是我想要的。于是,我在图 6 中试验过的超参数的左侧又进行了第三次 grid search。这次 grid search 是正式的 —— 我跑完了全部 24 个 epoch,并在每个 epoch 后在整个交叉验证集上测量错误率。下图展示了结果。绿色背景的单元格表示成功跑完 24 个 epoch 的超参数,其中的数值是最终交叉验证集上的错误率;橙色背景的单元格表示发生梯度爆炸的超参数,其中记录了发生爆炸的 epoch 数,以及前一个 epoch 的错误率。如果 6 个 epoch 后网络仍未启动,我则没有让它们继续跑下去,相应的单元格涂成红色。&/p&&img src=&/v2-1ce37f4d9f32f34b96f543a_b.png& data-rawwidth=&954& data-rawheight=&210& class=&origin_image zh-lightbox-thumb& width=&954& data-original=&/v2-1ce37f4d9f32f34b96f543a_r.png&&&p&&i&(图 7:第三次 grid search 的结果)&/i&&/p&&p&  最终得到的最优超参数为 limit = &img src=&/equation?tex=10%5E%7B-6%7D& alt=&10^{-6}& eeimg=&1&&,lr = 100。在 24 个 epoch 之后,它在训练集和交叉验证集上的错误率分别为 30.1% 和 34.5%,高于「强监督」网络的 4.8% 和 15.4%。这说明在「弱监督」下网络仍能学到东西,但不如在「强监督」下学得那么快、那么好,完美验证了我的预期。&/p&&h2&六、经验总结&/h2&&ol&&li&CTC 在训练过程中会经历预热身阶段、热身阶段、学习阶段。在热身阶段,网络没有任何输出,错误率会是 100%;在预热身阶段,网络会有少量随机输出,错误率略低于 100%。如果只观察错误率,容易把预热身阶段误当成学习阶段。&/li&&li&如果观察到 RNN 中各隐藏层的输出不随时间变化,并不意味着网络已经陷入了「死循环」,往往只是网络还没有开始学习。此时应加大学习率,促使网络尽快进入学习阶段。&/li&&li&在对 CTC 网络的超参数进行 grid search 时,如果为了省时间而只跑较少的 batch 数,往往欲速则不达:你可能只观察到了预热身阶段;也有可能在学习阶段的初期学得很快的超参数会导致后期梯度爆炸。最终的最优超参数还是要跑完整个训练过程才能确定。&/li&&/ol&
. 这个月花了将近一整个月的时间,调整了一个循环神经网络(RNN)的超参数,经历了各种挫折,最终取得了成功。在我最迷茫的时候,我曾经试图在网上搜索有针对性的调参经验,但一无所获。为了给后来人排雷,我就把我的调参经历记录在这里。 要读懂这篇文章,…
各类范数从机器学习的角度会比较好理解一些,所以我从这个角度说一下,本人为初学者,如有错误,还请不吝指正。&/p&&p&
我们从最简单的最小二乘线性模型开始。最开始,最小二乘的loss(需优化的目标函数)如下:&/p&&br&&img src=&/v2-4b3fd5d3eda1_b.png& data-rawwidth=&540& data-rawheight=&122& class=&origin_image zh-lightbox-thumb& width=&540& data-original=&/v2-4b3fd5d3eda1_r.png&&&p&式中,tn是目标变量,xn是观测量(自变量),\phi 是基函数(后期推导与核化相关),是w是参数。此式有闭式解,解为:&/p&&br&&img src=&/v2-f95d69fe69ebe9b_b.png& data-rawwidth=&345& data-rawheight=&73& class=&content_image& width=&345&&&p&但是我们都知道,矩阵求逆是一个病态问题,即矩阵并不是在所有情况下都有逆矩阵。所以上述式子在实际使用时会遇到问题。为了解决这个问题,可以求其近似解。可以用SGD(梯度下降法)求一个近似解,或者加入正则项(2范数)。加入正则项是我们这里要说的。加入2范数的正则项可以解决这个病态问题,并且也可以得到闭式解,在实际使用时要比用SGD快,并且加入正则化后的好处并不仅仅是这些。加入正则项(2范数)的loss如下:&/p&&br&&img src=&/v2-a5ce14f05f34d73eab9d502_b.png& data-rawwidth=&485& data-rawheight=&117& class=&origin_image zh-lightbox-thumb& width=&485& data-original=&/v2-a5ce14f05f34d73eab9d502_r.png&&&p&其闭式解为:&/p&&br&&img src=&/v2-4fb2fc7c5ed0c51e649e3dbe20f20c4a_b.png& data-rawwidth=&387& data-rawheight=&88& class=&content_image& width=&387&&&p&此式在 \lambda 不为零时,总是有解的,所以是一个非病态的问题,这在实际使用时很好。除了这一点,2范数的正则项还有其他好处,比如控制方差和偏差的关系,得到一个好的拟合,这里就不赘述了,毕竟这里讲的是范数,有兴趣可以参阅相关资料。&/p&&p&
加入正则项后一般情况下的loss为:&/p&&br&&img src=&/v2-d88f739d9e6b50cd9eae84_b.png& data-rawwidth=&542& data-rawheight=&118& class=&origin_image zh-lightbox-thumb& width=&542& data-original=&/v2-d88f739d9e6b50cd9eae84_r.png&&&p&
好了,我们终于可以专注于范数了。不同范数对应的曲线如下图:&/p&&br&&img src=&/v2-49dcdffaf72c0fcd0ecdadd18e310a63_b.png& data-rawwidth=&1583& data-rawheight=&509& class=&origin_image zh-lightbox-thumb& width=&1583& data-original=&/v2-49dcdffaf72c0fcd0ecdadd18e310a63_r.png&&&p&
(图来源于参考书PRML)&/p&&p&上图中,可以明显看到一个趋势,即q越小,曲线越贴近坐标轴,q越大,曲线越远离坐标轴,并且棱角越明显。那么 q=0 和 q=oo 时极限情况如何呢?猜猜看。&/p&&br&&br&&br&&br&&br&&img src=&/v2-dcd50a1df9aa71a9b53cdb8_b.png& data-rawwidth=&253& data-rawheight=&251& class=&content_image& width=&253&&&p&bingio, 你猜对了,答案就是十字架和正方形。除了图形上的直观形象,在数学公式的推导中,q=0 和 q=oo 时两种极限的行为可以简记为非零元的个数和最大项。即0范数对应向量或矩阵中非零元的个数,无穷范数对应向量或矩阵中最大的元素。具体推导可以参考维基百科。至此为止,那么他们用在机器学习里有什么区别呢?&/p&&p&以1范数和2范数为例:&/p&&br&&img src=&/v2-b2a

我要回帖

更多关于 图像处理和语音识别 的文章

 

随机推荐