1 拉格朗日乘子法的數(shù)學(xué)背景
當(dāng)使用前面介紹的罰函數(shù)法求解約束問題時,為獲得足夠好的近似解含末,罰參數(shù)需取足夠大的值猜拾,這將導(dǎo)致增廣目標(biāo)函數(shù)的黑森矩陣出現(xiàn)病態(tài),從而導(dǎo)致數(shù)值計算上的困難佣盒。因此提出拉格朗日乘子法挎袜。
學(xué)高數(shù)的時候我們就學(xué)過等式約束條件下的拉格朗日乘子法。延續(xù)前一節(jié)中對約束最優(yōu)化問題的定義沼撕,則拉格朗日函數(shù)為宋雏。局部最優(yōu)解的條件是對x求梯度及對所有
求導(dǎo)均為0。
下面來討論不等式和等式同時約束條件下的拉格朗日乘子法务豺。拉格朗日函數(shù)為磨总。對
的情況需要討論:
- 最優(yōu)解在
內(nèi)部時,
笼沥,約束條件無效蚪燕,有
- 最優(yōu)解在
邊界上時娶牌,
,約束條件有效馆纳。此時對x求梯度設(shè)為0诗良,有
,
指向
內(nèi)部(因為邊界處是最優(yōu)解),
也指向
內(nèi)部(因為邊界處為0鲁驶,
內(nèi)大于0)鉴裹,所以
可見,無論最優(yōu)解在何處钥弯,都有径荔,這個條件被稱為互補松弛條件。
因此針對不等式和等式同時約束條件下的拉格朗日乘子法脆霎,局部最優(yōu)解的條件可以用如下的KKT條件表示:
滿足KKT條件的點被稱為KKT點总处。
2 拉格朗日乘子法的構(gòu)成
2.1 等式約束問題的乘子法
將外點罰函數(shù)法的思想引入拉格朗日函數(shù)的最優(yōu)化問題。設(shè)睛蛛,構(gòu)造輔助函數(shù)
求駐點鹦马,令
根據(jù)KKT條件有
若
則
- 為了使得
收斂向
,有
- 為了使得
忆肾,每一步增加罰因子
(
為放大系數(shù))
由此得到等式約束問題乘子法的步驟:
- 選定初始點
荸频,初始乘子估計
,初始罰因子
难菌,常數(shù)
试溯,
,精度
郊酒,置
- 構(gòu)造增廣目標(biāo)函數(shù)
- 以
為初始點求解無約束問題
遇绞,其解為
- 若
,則得解
燎窘,停止迭代
- 若
成立摹闽,則令
,否則
- 令
褐健,令
付鹿,轉(zhuǎn)步2
2.2 一般約束問題的乘子法
引入松弛變量z將不等式問題化為等價的等式約束問題:
構(gòu)造增廣拉格朗日函數(shù):
配方后可得:
將該式對求偏導(dǎo),令偏導(dǎo)為0蚜迅,有
因此舵匾,代入消去z得
則
根據(jù)KKT條件有
為了使得收斂向
,根據(jù)KKT條件谁不,有
可以得到一般約束條件下的增廣目標(biāo)函數(shù)和的遞推公式:
由此得到一般約束問題乘子法的步驟:
- 選定初始點
坐梯,初始乘子估計
,初始罰因子
刹帕,常數(shù)
吵血,
谎替,精度
,置
- 構(gòu)造增廣目標(biāo)函數(shù)
- 以
為初始點求解無約束問題
蹋辅,其解為
- 若
钱贯,則得解
,停止迭代
- 若
成立侦另,則令
秩命,否則
- 計算
,令
褒傅,轉(zhuǎn)步2
3 實戰(zhàn)測試
對于上節(jié)深入淺出最優(yōu)化(7) 罰函數(shù)法中提出的約束最優(yōu)化問題硫麻,的初值均在
的范圍內(nèi)隨機生成,總共生成100組起點樊卓。統(tǒng)計迭代成功(在1000步內(nèi)得到最優(yōu)解且單次步長搜索迭代次數(shù)不超過1000次)的樣本的平均迭代步數(shù)、平均迭代時間和得到的最優(yōu)解及開銷函數(shù)最小值杠河。
迭代步數(shù) | 迭代時間 | 最優(yōu)解 | 函數(shù)最小值 |
---|---|---|---|
17 | 24.3729s |
代碼實現(xiàn)
本博客所有代碼在https://github.com/HarmoniaLeo/optimization-in-a-nutshell開源碌尔,如果幫助到你,請點個star券敌,謝謝這對我真的很重要唾戚!
你可以在上面的GitHub鏈接或本文集的第一篇文章深入淺出最優(yōu)化(1) 最優(yōu)化問題概念與基本知識中找到Function.py和lagb.py
使用共軛梯度PRP+法的拉格朗日乘子法
import numpy as np
from Function import Function #定義法求導(dǎo)工具
from lagb import * #線性代數(shù)工具庫
from scipy import linalg
n=3 #x的長度
mu=2
lj=np.ones(1) #λj初值,長度等于等式限制條件個數(shù)
li=np.ones(2) #λi初值待诅,長度等于不等式限制條件個數(shù)
def func(x): #目標(biāo)函數(shù)叹坦,x是一個包含所有參數(shù)的列表
return (x[0]-1)**2+(x[0]-x[1])**2+(x[1]-x[2])**2
def hj(x): #構(gòu)造數(shù)組h,第j位是第j+1個等式限制條件計算的值卑雁,x是一個包含所有參數(shù)的列表
return np.array([x[0]*(1+x[1]**2)+x[2]**4-4-3*np.sqrt(2)])
def gi(x): #構(gòu)造數(shù)組g募书,第i位是第i+1個不等式限制條件計算的值,x是一個包含所有參數(shù)的列表
return np.array([x[0]+10,-x[0]+10])
def myFunc(x):
return func(x)+\
1/(2*mu)*np.sum(np.power(np.where(li-mu*gi(x)>0,li-mu*gi(x),0),2)-np.power(li,2))-\
np.sum(lj*hj(x))+0.5*mu*np.sum(np.power(hj(x),2))
def cdt(x):
return np.sqrt(np.sum(np.power(hj(x),2)))+np.sqrt(np.sum(np.power(np.where(gi(x)>0,0,gi(x)),2)))
sigma2=1.5 #放大因子
e2=0.001
beta=0.5
x=np.array([2.0,2.0,2.0]) #初值點
k1=0
while cdt(x)>=e2:
e=0.001
beta1=1
sigma=0.4
rho=0.55
tar=Function(myFunc)
k=0
d=-tar.grad(x)
x1=x
while tar.norm(x)>e:
a=1
if not (tar.value(x+a*d)<=tar.value(x)+rho*a*dot(turn(tar.grad(x)),d) and \
np.abs(dot(turn(tar.grad(x+a*d)),d))>=sigma*dot(turn(tar.grad(x)),d)):
a=beta1
while tar.value(x+a*d)>tar.value(x)+rho*a*dot(turn(tar.grad(x)),d):
a*=rho
while np.abs(dot(turn(tar.grad(x+a*d)),d))<sigma*dot(turn(tar.grad(x)),d):
a1=a/rho
da=a1-a
while tar.value(x+(a+da)*d)>tar.value(x)+rho*(a+da)*dot(turn(tar.grad(x)),d):
da*=rho
a+=da
lx=x
x=x+a*d
beta=np.max((dot(turn(tar.grad(x)),tar.grad(x)-tar.grad(lx))/(tar.norm(lx)**2),0)) #PRP+
d=-tar.grad(x)+beta*d
k+=1
print(k1,k)
if cdt(x)/cdt(x1)>beta:
mu*=sigma2
k1+=1
print(x)