训练一个模型时大家都需要面对一个问题:参数优化。通常,我们做参数优化时都会先导出一个cost function,然后通过调整参数值来最大化或最小化这个cost function。这个过程听起来很简单,但真的做起来是个剧恶心的体力活!
比方说你要用梯度方法做优化,得求一阶导二阶导吧,求得半死不活之后还得自己用代码实现,敲完代码然后调用一遍梯度下降方法,结果跑到一半,程序挂了,一大波数值异常排着队的往外蹦,啥矩阵不正定啦,根号里对数里分母上数字太接近0啦,想想就心塞。
那我们不用梯度方法呗,改用蒙特卡洛采样吧,又是一堆破事,采样分布咋取,proposal distribution咋设,收敛性如何,而且实现细节上非常主观,采样程序跑的还慢,真过分!
更恶心的情况是,模型可能没有一个显式的表达式,或者这个模型不是自己写的,完全不知道里面是如何实现的,这种情况下做参数优化简直是强人所难。。。诶,宝宝心里苦,但宝宝不说。
但是,今天我们要说的一个参数优化的方法可以让你轻松学习出一个健壮的模型,完全不用担心前面吐槽的种种问题。这个方法叫做贝叶斯优化,英文是Bayesian Optimization。
贝叶斯优化是专门优化不知道表达式的函数的,也就是说这个函数写不出y=ax+b的样子。你可能会问,都写不出来表达式那咋表示这个函数呢? 别着急,虽然他写不出表达式,但每给出一个输入x,他可以算出一个输出y。当我们有了很多采样到的(x,y)数据对时,我们大致可以知道函数的形态,然后找到函数的最值。
但是,优化一个不知道表达式的函数和优化一个已知表达式的函数有着很大上的区别,他的目标不仅仅是找到函数最值,而是要达到两个目标:
1 学习这个函数的形态
2 找到学习出的函数的最值
这里目标一也是完成最优化的一个环节,因为不知道函数形态,那还咋找最值。。。但这个目标一和目标二是相互矛盾的。
我们举个栗子来说明下这两个目标之间的矛盾性。假使我刚来到一个新的城市,现在想要找到这个城市里最喜爱的餐厅。那么这个城市餐厅被我喜欢的程度就是一个没有表达式的函数,那怎么去优化他呢?当然是一家一家去吃咯!当我把这个城市所有餐厅全部吃一遍,就知道最爱哪家餐厅了,但这么一家一家吃过来是要花很多时间和软妹币的。我们肯定希望尽可能的减少尝试的次数。
那么问题来了,我现在是要尝试一家我从来没去过的餐厅呢(目标一)还是要在吃过的几家里选一家再细细品味对比呢(目标二)?如果是去没去过的餐厅,我可能会遇到一家灰常好吃的餐厅,但也可能会悲剧。如果我选择已经在我比较喜欢的名单上且还没去过的餐厅,的确能更精确的更新我自己的最佳餐厅的排名,但可能和这个城市中真正的最爱餐厅失之交臂(这就是传说中的局部最优解)。
啊,好纠结!为什么要做这么艰难的决定。别烦恼,有了贝叶斯优化,麻麻再也不用担心选不到餐厅。贝叶斯优化能在这两个相互矛盾的目标中自动权衡利弊,时而选择目标一,时而选择目标二,最终找到函数的最值。简单的说,贝叶斯优化告诉我们,在刚来到新城市时要多去尝试新的餐厅,等我们对餐厅的整体情况有一定了解后,就多去自己可能喜欢的餐厅,偶尔尝试下未知的餐厅,这样就能较大概率的找到最爱的餐厅。
具体来说,贝叶斯优化是根据下面的公式选择下一次采样的位置:
这里我们考虑最大化函数值的情况,首先使用已有的观测值来构建一个高斯过程(Gaussian process)的回归模型,并预测出未知输入位置上的均值和标准差。我们选择均值和标准差的加和最大的输入位置来作为下一个取样的点。这个加和公式被称做acqusition function。他里面有个权重参数,这里我们就不展开讨论这个权重参数的设置了,因为会引出一堆的关于收敛性的证明,有兴趣的话,大家可以去看这篇文献Gaussian Process Optimization in the Bandit Setting: No Regret and Experimental Design。
回到acqusition function的公式,如果标准差大,表示我们对该点的了解甚少,多去采样这些点会帮助我们更好的了解这个函数形态,也就是实现目标一。如果均值大,表示该点可能是最大值的位置,去采样这些点会帮助我们尽快锁定最大值,也就是实现目标二。一开始,我们的采样数据非常少,算法会采样标准差大的点,也就是刚到新城市,多去尝试新餐厅。等采样了一定数目的点后,标准差的值会下降很多,这时候采样点的选择就更多的受到均值的影响,采样点就会更大概率的出现在真正最大值附近,也就是去自己觉得可能最喜欢的餐厅。
我们来检验下贝叶斯优化的效果吧,为了评估算法的性能,我们使用已知表达式的函数,然后假装不知道这个表达式来进行贝叶斯优化。首先我们选最简单的一维函数:
我们把输入离散化成100份,然后做20次采样,左上角是实际函数的样子,右上角是标准差变换后的值,叫做熵(entropy)。左下角是均值,右下角是acqusition function,每次我们取这个acqusition function值最大的位置作为下一个采样点,这里上部很多的红线是已经采样的数据,绿线是下一次的采样位置,左下角的单个红线是当前认为的最大值。
再看下在二维时的情况,我们使用做优化问题常用的一个benchmark函数,叫做branin函数。同样,红色叉叉是已经采样的数据,绿点是当前采样位置,红点是当前认为的最大值位置。你会发现两个峰值的位置会聚集很多的采样点,而在其他位置只有零星的采样点。这就是贝叶斯优化权衡两个目标后产生的采样分布。
我们再对branin函数取反,这样就是找最小值了。
我们把算法稍微改进下,在锁定最优值区域后,加大搜索精度。
我们再换一个变态的函数,有n多个峰值,一般的优化方法很容易止步在局部最优,但是贝叶斯优化并不会!
接下来,我演示一个实际问题上的最优化案例,因为我并不知道这个函数的真实形态,所以左上角的函数走势就空着了。
你会发现,在取样的后期,acqusition function左边的值会慢慢的增大,然后被采样,这就类似我们在选择很喜欢的餐厅的时候,偶尔还会去尝试未知的餐厅。