发布时间:2017-03-15
3月3日,中国人工智能学会AIDL第二期【人工智能前沿讲习班】在北京中科院自动化所举行,本期讲习班的主题为【机器学习前沿】。周志华教授担任学术主任,前来授课的嘉宾均为中国机器学习界一流专家、资深科研人员和企业精英,包括:耿新、郭天佑、刘铁岩、王立威、叶杰平、于剑、余扬、张长水、郑宇、朱军
张长水
清华大学自动化系教授、博士生导师,智能技术与系统国家重点实验室学术委员会委员,智能技术与系统国家重点实验室副主任。主要从事机器学习、模式识别、人工智能、计算机视觉等领域的教学和科研工作。
以下是张长水教授的演讲实录:
今天我和大家分享的主题是
“神经网络模型的结构优化”
我大概会讲一下几点:
Part 1: 研究背景
Part 2: 子模函数和超模函数
Part 3: 神经网络结构的优化
Part 4: 实验部分
Part 1: 研究背景
当前,深度神经网络模型的出现给我们带成了很大的影响,这个影响大部分都是积极正面的,但是同时也存在一些不同看法。不管怎么说,深度学习模型在传统的很多机器学习问题和相关问题上,都取得了令人瞩目的突破和进展。
我举几个例子,比如图像识别。图像识别是这样一个问题:有一张图像,需要识别这个图像是猫、是狗、是计算机、是羽毛球拍?在2012年的深度学习网络用于解决问题时,有了很大的突破。
除此之外还有其他的问题,比如图像描述、机器翻译、语音识别。机器翻译我们知道过去几十年发展也很慢,基本上没有办法应用实际,也是因为深度学习方法的应用,使得机器翻译有了一个很大的突破。百度因为这个方面的工作,大概在去年获得了一个国家科技进步二等奖,是王海峰带领他的团队的成果。此外,语音识别,大家都知道,以前也是没有到应用的水平,而现在我们就可以用。比如说大家用微信,就可以用语音输入。目前为止性能还不错的语音识别系统,全部都是用深度学习方法去做的。
除此以外还有很多,比如医疗。还比如大家都知道的下棋。
深度学习方法应用有很多好处,同时也有很多问题。比如说,深度学习网络模型计算量特别大、模型特别复杂。模型复杂导致两个问题,第一是训练上的困难,第二个是测试上的困难。训练上的困难在于它需要大量的时间,而且一个深度学习网络要想在某个问题上达到特别好的实用化性能,需要特别多的数据。而这对于机器计算的要求、对于数据的要求,通常来说不是我们在高校擅长满足的。因此,工业界就显得很有优势,他们有数据、有计算资源。现在深度学习的技术进步了,但是训练模型依然要花费很长时间。像我们实验室动不动训练一个模型就要一两天的时间。另外测试时间也很长,我给一个数据,跑神经网络,最后从末端给出一个结果。这个过程看起来只有一遍过程,但是由于中间计算过于复杂,所以时间仍然很长。比如给一张图像,通常来说如果代码写的不够好,大概需要几秒的时间,如果写的特别糟也可能一分钟的时间。可是我们知道有些应用问题不允许你这样做,它需要你实时地识别图像。还有就是对内存有要求。神经网络模型有大量的参数都要存到计算机里去。如果你用的是服务器,这就没问题,但当你的这个技术走向应用变成产品,这就不一样了。比如说无人驾驶车,我们希望无人驾驶车上装的摄像头能够识别路上的情况、标识一些物体,你如果这么做,就要在无人驾驶车上有一个识别设备。我们知道无人驾驶车是一个那么有限的环境,它不太可能让你放一个服务器或GPU,所以它的计算能力很弱。还有就是它对于电的要求高,我们知道GPU特别费电,车上不太可能放一个几百瓦、上千瓦的供电系统。所以有人对AlphaGo的一个批评就是,你和人去比赛,人靠的是什么,喝一杯牛奶、一片面包、一个鸡蛋就来参加比赛;AlphaGo靠什么,后面有那么大的一个供电系统。还有一个特别理想的状况,既然深度学习做图像识别已经有了很多突破,为什么不用在手机上?可是一旦考虑用在手机上,就发现有一堆的问题:内存太小、计算能力太弱、耗电太厉害,所有这些东西都导致了神经网络现在在应用阶段有非常大的困难。
因此就提出这样的问题,我们怎么样让深度学习网络紧凑、小型化。在实际中,我们做深度学习的时候有一个很重要的问题,就是要调参数。首先,给你一个问题,你有了数据,选择了一个基本模型,但是这个模型结构到底怎么设置,层有多少,每层宽度多少?这样一些参数怎么去定?有很多的因素会影响我们学习的性能。有人做过一项这样的研究,你能够把网络学的好,学习率(learning rate)是最重要的一个因素。学习率就是我们求偏导的时候,会对导数的权重调整的系数,这个系数特别重要,有相当多的研究工作关注在这个地方,这个地方任何一个突破对所有人都是至关重要的,这里“所有人”是指对神经网络使用的那部分研究人员。此外,每层的宽度也是一个重要的参数。我今天的报告主要讲如何选择每层宽度。
神经网络结构优化,有哪些已有的方法?
第一种,贝叶斯方法
权重参数是我们在训练阶段要学习的一个参数,此外我们需要提前确定的参数我们叫超参数。我们在超参数这个问题上怎么去做?这是我们传统的深度学习、机器学习比较关注的问题。我们假设有一个要学习的参数,有的时候我们给这个参数假设一个形式,例如:高斯分布,那这个高斯分布就是你的先验,你再想办法确定这个高斯分布的均值、方差。这就是贝叶斯方法。但是这样的方法里面,你需要先确定先验。
第二种,导数的方法
优化目标函数通常的做法是通过求导完成的。我们往往对神经网络的权重进行求导。既然你的学习率是一个超参数,我们为什么不能够对它进行学习?所以如果你能够建立你要优化的这个损失函数和你现在要学习的超参数之间的函数关系,建立这个函数关系以后,就可以去求梯度、求导。这个方法的优点是很明显的,但是缺点就是,可能需要你把这两者之间的函数关系理清楚。第二个,对于离散的问题,这种办法就不好用。
第三种,网格搜索
超参数还怎么优化?在实际过程中我们还有一些经验上的做法,比如说网格搜索。大家去设想一下,在神经网络之前我们大家学过支持向量机。支持向量机的目标函数有两项:是间隔项和惩罚项。这两项之间会有一个C来平衡大的间隔和错分样本的惩罚。这里 C是需要提前定的。但是实际中我们不知道C是多少。实际做的过程就是,我们通过网格搜索把这C等间隔取值,分别优化SVM,使得我能够得到一个特别好的结果。调好参数很重要,一来你要去发文章的时候,把你的参数调的尽可能好,和其它最好的方法去比较。另一个就是调系统和产品,我们希望自己的系统性能尽可能好,去卖个好价钱。
假如我们要优化一个神经网络,而我只关心这两层的宽度。所谓的网格搜索就是,让每层的宽度取值5、10、15、20、25个节点,然后两层一起考虑,遍历所有的组合。这样做保证不丢掉一些重要的结构。可想而知,这种做法非常慢,而且我们神经网络往往会很多很多层,所以这是一个很头疼的事。
即使采用遍历的方法,网格搜索的方法后来也被认为不太好。在2012年Bengio在 “The Journal of Machine Learning Research”发表的工作告诉我们,假设你要优化的那两个参数,可能有一个很重要而另一个不那么重要,网格搜索就意味着构成一个这样的搜索点的分布,这个分布向两个方向投影,就意味着你搜索了9个点,而在每个方向上都有一些搜索点重复。如果我们采用随机采样的方式,而不是网格搜索的话,就有可能会充分利用这九个点采到这个特别重要的点。他们做了一些理论的和实验的分析,说明随机搜索效果往往会更好。而比较有意思的,随机搜索本身其实是一个很简单的过程,不需要那么多的预备知识和技术,所以是一件挺好的事。
结构优化是一个离散优化问题,所以我们用前边很多的贝叶斯方法、求导方法不能用,所以通常情况下,都是人工做的。如果我们在座的有老师,让你的学生去调参,说你要网格搜索,他可能会拒绝,他说这事我搞不定,这个参数组合太多了,另外,我们机器承受不了,我算一次就要1天、2天,我这样一组合可能要几百次、几万次人工调参数。所以人工调参数费时费力。此外,就是需要特别多的知识,你要有很多的知识和经验才能调好参数,对专家的依赖性很强。更关键的问题是,我好不容易花一个月把参数调好,现在换一个数据集,我还需要再花半个月时间调参。另外是当你的应用场景发生变化的时候,新的客户来了,这个时候你不得不调,非硬着头皮做不可,所以熬夜就成了家常便饭。
第四种,其它优化手段
其一种是低秩近似。我们把神经网络这些权列成一个矩阵,假设这个矩阵是低秩的,加上低秩正则以后,去优化这个网络结构。换句话说,在你优化整个目标函数的时候,同时希望这个秩要低。如果把约束加在全连接层上,效果就比较好。
其二,去掉无用的连接和节点。神经网络每相邻层之间都是连接,我们有的时候会问,所有这些连接都有用吗,是不是有的连接没有用?如果是这样的话,我们是不是可以把没有用的连接去掉。换句话说,看起来那个权重是有,但是其实很小,我们总觉得特别小的权重起的作用很弱,我们就把它去掉。这种想法有人做过,就是我先训练一个网络,训练好以后,我看哪个权重特别小,把它去掉,然后再重新训练。训练稳定了以后,看哪个权重又小,再把它去掉,一点点这么去做。好像2015年NIPS会议上就有这样一个文章发表,大概用的是这样的思路。当然也有人说,我对于你们的权重加一个稀疏的正则,去优化。当然这样从做法上更流畅、更漂亮。后来有人说,除了连接很重要,中间有几十万个节点,每个节点都很重要吗,能不能把某个节点去掉,这个做法就是节点稀疏。
其三,量化权重。现在整个权训练好了,但是因为有很多权,我要存这些权就很麻烦,因此大家想,这个权重不用浮点数,用整数行不行?整数做的一种办法就是,把所有的权重都聚类,在聚集多的地方取值,其它的用近似。还有一种做法就是,把所有的权重量化成几个等级,比如有4个等级。一个极端是两个等级,有和没有,有的话就是1,没有的话就是0。在这种情况下你会发现,整个神经网络计算就变得非常非常的容易,只存在有和没有,就变得非常的简单和快速。
当然,所有这些方法都会带来副作用,就是你的识别率会下降。有的时候我们会说,我们关注这个算法能不能放手机里去,因为通常来说,放到手机里的很多应用程序对识别率没有那么高的影响,认为大众对有些识别问题的要求可能没有那么高。这样识别率降一点也没有特别大的关系。
Part 2: 子模函数和超模函数
子模函数和超模函数是后边的网络结构优化要用到的知识。介绍的时候我先说明,这里面大概有10页左右的PPT是从这个网站上拿过来的(网址:http://www.select.cs.cmu.edu/tutorials/icml08submodularity.html)。在2008年国际机器学习大会有一个特别好的tutorial,就是关于子模函数和超模函数。那个报告给我印象深刻,所以我就把其中的几页拿过来在上面做了一些改动。不管怎么说,谢谢这两个作者。课后大家如果对这个有兴趣,可以去看看他们很完整的PPT。他们对子模函数和超模函数介绍非常详细,很感谢他们。
子模函数和超模函数,是关于集合函数的一些性质。集合函数是指,这个函数是定义在它的子集上的函数,这个函数在每个子集上的取值。通常我们认为空集函数是对应的是0。
什么是子模函数?子模函数是怎么形成的,我们不去管它,可以把它看成一个黑箱(black box),但是我们希望这个函数具有一个这样的性质:对于任给的A、B两个子集, F(A)+F(B) ≥ F(A ∪ B)+F(A ∩ B)。
如果它满足这个条件,就说它是一个子模函数。这样的性质也等价于这个性质:有两个集合,一个是A,一个是B,A集合是B集合的一部分。这种情况下如果在A集合上加上一个元素,这个集合就变大一点,变大了以后,这个函数会比原来A集合函数增加了一部分,在小的集合上增加的量要更大大。换句话说,小集合加上一个元素带来的改进更大,而在大的集合上增加同样的元素以后,它带来的影响会比较小一些。
什么是超模函数?如果F是一个子模函数,前面加一个负号,那就是超模函数。
这件事有点太抽象,我们举一个具体的问题,这样大家就会有很直观理解。假设,现在有一个房间,我们需要在房间里布置一些传感器,布置传感器是为了对整个房间进行数据采样。每个每个传感器会有一个覆盖面积。我们希望放上有限的传感器,覆盖的面积越大越好。在这样一个问题里边,对于任何一个集合,F(A)=A能够覆盖的面积。所谓的A是什么呢?就是你放的传感器,因为每个传感器会放在一个位置上。
这个问题里的F是一个子模函数(我定义F是它覆盖的那个面积)。为什么呢?可以设想,我有两种情况,一种情况是我放2个传感器,还有一种情况是,我放4个传感器,其中包含了刚才的两个传感器。我在2和4个传感器的布局里,分别再加上同一个位置的1个传感器,那么你会发现上面小的集合情况(2个传感器)下带来的面积增加量比较大。而原来4个传感器的集合增加的面积部分比较小。这是一个非常直观的例子。
子模函数有一个很有意思的性质:假如Fi是子模函数,这个λi>0,它的正的线性叠加仍然是子模函数。就是在正的这种线性组合的意义上它是封闭的。
我们怎么去理解子模函数?对子模函数的寻优对应的是一个离散的优化问题,我们可能知道更多的是连续的优化问题。在连续优化问题里边我们比较喜欢的一个问题叫凸问题,就是说白一点,我们只有一个单峰。这种情况下找最大值相对比较容易。我们通过求偏导,原则上一定能找到最优值。但是到离散问题以后,什么是凸我们就不知道了。而子模函数类似于我们在连续问题里的凸函数。下面这个例子会呈现子模函数与凸问题的关系。
假设有一个这样的函数g,它是从整数到实数的一个映射,函数F定义在A集合上,这个子模函数怎么定义呢?它就定义成我这个集合的“大小”,把集合别的因素都去掉,只考虑它的大小。这样如果两个集合a是b的子集,那么 a的大小 < b的大小。这个函数的特点就在于,在小的地方增加一点所带来的增益,和在大的地方同样增加一点所带来的增益,前者要大。所以你也可以认为,子模函数是离散函数的一种凸性质。
当然你会说我们还有别的运算,比如说两个子模函数F1、F2,求最大,那还是子模函数吗?它的最大max(F1,F2)不一定是子模函数。它的最小,就是这两个子模函数取最小,min(F1,F2)一般来说也不一定是子模函数。
(本报告根据速记整理)
CAAI原创 丨 作者张长水教授
未经授权严禁转载及翻译
如需转载合作请向学会或本人申请
转发请注明转自中国人工智能学会