在求取有约束条件的优化问题时,拉格朗日乘子法(Lagrange Multiplier) 和KKT条件是非常重要的两个求取方法,对于等式约束的优化问题,可以应用拉格朗日乘子法去求取最优值;如果含有不等式约束,可以应用KKT条件去求取。当然,这两个方法求得的结果只是必要条件,只有当是凸函数的情况下,才能保证是充分必要条件。
KKT条件是拉格朗日乘子法的泛化。之前学习的时候,只知道直接应用两个方法,但是却不知道为什么拉格朗日乘子法(Lagrange Multiplier) 和KKT条件能够起作用,为什么要这样去求取最优值呢?
本文将首先把什么是拉格朗日乘子法(Lagrange Multiplier) 和KKT条件叙述一下;然后开始分别谈谈为什么要这样求最优值。
一、拉格朗日乘子法(Lagrange Multiplier) 和KKT条件
通常我们需要求解的最优化问题有如下几类:
(i) 无约束优化问题,可以写为:
min f(x);
(ii) 有等式约束的优化问题,可以写为:
min f(x),
s.t. h_i(x) = 0; i =1, ..., n
(iii) 有不等式约束的优化问题,可以写为:
min f(x),
s.t. g_i(x) <= 0; i =1, ..., n
h_j(x) = 0; j =1, ..., m
对于第(i)类的优化问题,常常使用的方法就是Fermat定理,即使用求取函数f(x)的导数,然后令其为零,可以求得候选最优值,再在这些候选值中验证;如果是凸函数,可以保证是最优解。
对于第(ii)类的优化问题,常常使用的方法就是拉格朗日乘子法(Lagrange Multiplier) ,即把等式约束h_i(x)用一个系数与f(x)写为一个式子,称为拉格朗日函数,而系数称为拉格朗日乘子。通过拉格朗日函数对各个变量求导,令其为零,可以求得候选值集合,然后验证求得最优值。
对于第(iii)类的优化问题,常常使用的方法就是KKT条件。同样地,我们把所有的等式、不等式约束与f(x)写为一个式子,也叫拉格朗日函数,系数也称拉格朗日乘子,通过一些条件,可以求出最优值的必要条件,这个条件称为KKT条件。
(a) 拉格朗日乘子法(Lagrange Multiplier)
对于等式约束,我们可以通过一个拉格朗日系数a 把等式约束和目标函数组合成为一个式子:
L(a, x) = f(x) + a*h(x),
这里把a和h(x)视为向量形式,a是横向量,h(x)为列向量,之所以这么写,完全是因为csdn很难写数学公式,只能将就了.....。然后求取最优值,可以通过对L(a,x)的各个参数求导取零,联立等式进行求取,这个在高等数学里面有讲,但是没有讲为什么这么做就可以,在后面,将简要介绍其思想。
(b) KKT条件
对于含有不等式约束的优化问题,如何求取最优值呢?常用的方法是KKT条件,同样地,把所有的不等式约束、等式约束和目标函数全部写为一个式子
L(a, b, x)= f(x) + a*g(x)+b*h(x),
KKT条件是说最优值必须满足以下条件:
1. L(a, b, x)对x求导为零;
2. h(x) =0;
3. a*g(x) = 0;
求取这三个等式之后就能得到候选最优值。其中第三个式子非常有趣,因为g(x)<=0,如果要满足这个等式,必须a=0或者g(x)=0. 这是SVM的很多重要性质的来源,如支持向量的概念。
二. 为什么拉格朗日乘子法(Lagrange Multiplier) 和KKT条件能够得到最优值?
为什么要这么求能得到最优值?
先说拉格朗日乘子法,设想我们的目标函数z = f(x),x是向量, z取不同的值,相当于可以投影在x构成的平面(曲面)上,即成为等高线。
如下图,目标函数是f(x, y),这里x是标量,虚线是等高线,现在假设我们的约束g(x)=0,x是向量,在x构成的平面或者曲面上是一条曲线,假设g(x)与等高线相交,交点就是同时满足等式约束条件和目标函数的可行域的值,但肯定不是最优值,因为相交意味着肯定还存在其它的等高线在该条等高线的内部或者外部,使得新的等高线与目标函数的交点的值更大或者更小,只有到等高线与目标函数的曲线相切的时候,可能取得最优值。
如下图所示,即等高线和目标函数的曲线在该点的法向量必须有相同方向,所以最优值必须满足:
f(x)的梯度 = a* g(x)的梯度,a是常数,表示左右两边同向。
这个等式就是L(a,x)对参数求导的结果。(上述描述,我不知道描述清楚没,如果与我物理位置很近的话,直接找我,我当面讲好理解一些,注:下图来自wiki)。
KKT条件是满足强对偶条件的优化问题的必要条件,可以这样理解:我们要求min f(x),
L(a, b, x) = f(x) + a*g(x) + b*h(x),a>=0,
我们可以把f(x)写为:max_{a,b} L(a,b,x),为什么呢?因为h(x)=0, g(x)<=0,现在是取L(a,b,x)的最大值,a*g(x)是<=0,所以L(a,b,x)只有在a*g(x) = 0的情况下才能取得最大值,否则,就不满足约束条件,因此max_{a,b} L(a,b,x)在满足约束条件的情况下就是f(x),因此我们的目标函数可以写为 min_x max_{a,b} L(a,b,x)。如果用对偶表达式: max_{a,b} min_x L(a,b,x),由于我们的优化是满足强对偶的(强对偶就是说对偶式子的最优值是等于原问题的最优值的),所以在取得最优值x0的条件下,它满足 f(x0) = max_{a,b} min_x L(a,b,x) = min_x max_{a,b} L(a,b,x) =f(x0),我们来看看中间两个式子发生了什么事情:
f(x0) = max_{a,b} min_x L(a,b,x) = max_{a,b} min_x f(x) + a*g(x) + b*h(x) = max_{a,b} f(x0)+a*g(x0)+b*h(x0) = f(x0)
可以看到上述加黑的地方本质上是说 min_x f(x) + a*g(x) + b*h(x) 在x0取得了最小值,用fermat定理,即是说对于函数 f(x) + a*g(x) + b*h(x),求取导数要等于零,即
f(x)的梯度+a*g(x)的梯度+ b*h(x)的梯度 = 0
这就是KKT条件中第一个条件:L(a, b, x)对x求导为零。
而之前说明过,a*g(x) = 0,这时KKT条件的第3个条件,当然已知的条件h(x)=0必须被满足,所有上述说明,满足强对偶条件的优化问题的最优值都必须满足KKT条件,即上述说明的三个条件。可以把KKT条件视为是拉格朗日乘子法的泛化。
以上证明了关于“违反对”拉格朗日乘子选择问题,其实问题还没有结束,因为剩下如何计算G[ ]和G_bar[ ]两个数组,以及每次迭代拉格朗日乘子问题并没有解决,只是解决了关于乘子的选择问题。(http://blog.csdn.net/zhuyue3938199/article/details/7469868)。
乘子选择问题变成以下优化问题:
优化问题进一步推导可得到如下变形:
可求得取得极值点是:
为了推导方便将进行如下定义:
并且由于将(3)式代入:
那么我们就可以得到迭代后的拉格朗日的值了。
接下来对两种情况进行讨论:
(1)如果则根据(3)和(6)可得
在Libsvm中,在后面的源码解释可以看到:
(2)如果,则根据(3)和(6)可得
同理,因此可以得到:
在这里基本已经推导出了Libsvm中每一次拉格朗日乘子的迭代过程。但还有一些细节没有完全解决。如果记得优化问题的对偶问题的限制条件中有,
为了保证这个约束条件的成立,因此还要进行进一步的深入讨论。其实有两种情况的,(1)(2)我们这里就只讨论这种情况。
对偶问题中的另一个约束条件是我们每次只取里面两个乘子来进行优化,因此有:
注意:这里的这里的constant’和constant并不一样哦!!!
由上述(12)和(11)可得, 的取值并不是任意,必须满足约束条件:
在Libsvm的技术文档中,给出了这样一幅图:
在上图中,的取值只能上述四个区域,而不可能取到右下角和左上角的值。证明如下:
(1)位于左上角,那么有:
明显可以看出(13)与(14)式子是矛盾的,因此不可能取到上述的取值。同理
(2)位于左上角,那么有:
也可以看出(15)与(13)式子是矛盾的。因此不可能位于NA区域。因此必然位于上述四个区域之一或在四方形的内部。如果位于四方形的内部,则不需进行进一步的讨论,如果是位于四个区域之一,则必须对的取值进行纠正,保证满足式子(11)。
(1)在局域1有:
满足 为了满足约束条件(11),将数值调整为:
(2)在局域2有:
满足 为了满足约束条件(11),将数值调整为:
(3)在区域3有:
满足 为了满足约束条件(11),将数值调整为:
(4)在区域4有:
满足 为了满足约束条件(11),将数值调整为:
至此,我们已经讨论了时,拉格朗日乘子迭代的全过程。同样道理,的情况也是类似的。这里就不再详细讨论了。接下来就看下Solve函数源代码。
if(y[i]!=y[j]) //
{
double quad_coef = QD[i] + QD[j] + 2*Q_i[j]; //这里计算上述的(4)中的
if (quad_coef<= 0)
quad_coef = TAU; //如果,则用很小的正数代替
double delta = (-G[i]-G[j]) / quad_coef; //计算delta
double diff = alpha[i] -alpha[j]; //计算
alpha[i] += delta; //迭代计算
alpha[j] += delta; //迭代计算
if(diff > 0)
{
if(alpha[j] < 0) //在区域3,按(18)进行更新
{
alpha[j] = 0;
alpha[i] =diff;
}
}
else
{
if(alpha[i] < 0) //在区域4,按(19)进行更新
{
alpha[i] = 0;
alpha[j] = -diff;
}
}
if(diff >C_i - C_j)
{
if(alpha[i] >C_i) //在区域1,按(16)进行更新
{
alpha[i] =C_i;
alpha[j] =C_i - diff;
}
}
else
{
if(alpha[j] >C_j) //在区域2,按(17)进行更新。
{
alpha[j] =C_j;
alpha[i] =C_j + diff;
}
}
}
else
{
double quad_coef = QD[i] + QD[j] - 2*Q_i[j];
if (quad_coef<= 0)
quad_coef = TAU;
double delta = (G[i]-G[j]) / quad_coef;
double sum = alpha[i] + alpha[j];
alpha[i] -= delta;
alpha[j] += delta;
if(sum > C_i)
{
if(alpha[i] > C_i)
{
alpha[i] = C_i;
alpha[j] = sum - C_i;
}
}
else
{
if(alpha[j] < 0)
{
alpha[j] = 0;
alpha[i] = sum;
}
}
if(sum > C_j)
{
if(alpha[j] > C_j)
{
alpha[j] = C_j;
alpha[i] = sum - C_j;
}
}
else
{
if(alpha[i] < 0)
{
alpha[i] = 0;
alpha[j] =sum;
}
}
}