在學(xué)習(xí)各種優(yōu)化方法之前朵诫,我們需要先從簡(jiǎn)單的一維優(yōu)化問(wèn)題開(kāi)始哼审,即只有單一變量的優(yōu)化問(wèn)題禁谦,解決這類問(wèn)題的方法可稱為一維搜索技術(shù)绝编,亦可稱為線性所搜(Line Search)僻澎。一維搜索技術(shù)既可以獨(dú)立的應(yīng)用于求解單變量的優(yōu)化問(wèn)題,同時(shí)又是求解多變量?jī)?yōu)化問(wèn)題的常用手段十饥。
在大多數(shù)多變量函數(shù)的最優(yōu)化中窟勃,迭代格式為:
其中最為關(guān)鍵的就是往哪走的搜索方向和走多少的步長(zhǎng)因子
,如果確定了搜索方向,那么求解步長(zhǎng)因子
的問(wèn)題就是一維優(yōu)化問(wèn)題逗堵,不妨設(shè):
這樣凡從出發(fā)秉氧,沿搜索方向
,確定步長(zhǎng)因子
,使得
(該系列文章涉及的優(yōu)化方法以及步驟均默認(rèn)為求極小值)的問(wèn)題就是關(guān)于步長(zhǎng)因子
的一維搜索問(wèn)題。其主要結(jié)構(gòu)可作如下概括:首先確定包含問(wèn)題最優(yōu)解的搜索區(qū)間蜒秤,然后采用某種分割技術(shù)或者插值方法縮小這個(gè)區(qū)間汁咏,進(jìn)行搜索求解。
一維搜索方法可以分為兩大類作媚,即精確搜索和非精確搜索攘滩。精確搜索,顧名思義就是求的極小值纸泡,此時(shí)得到的
稱為最優(yōu)步長(zhǎng)因子漂问。如果選取的
使得
在可接受的范圍內(nèi),這種情況就稱為非精確的搜索女揭。由于實(shí)際計(jì)算中蚤假,一般做不到精確的一維搜索,實(shí)際上也沒(méi)有必要做到這一點(diǎn)田绑,因?yàn)榫_的一維搜索需要付出較高的代價(jià)勤哗,對(duì)加速收斂作用不大,因此花費(fèi)計(jì)算量較少的不精確的一維搜索技術(shù)方法受到更為廣泛的重視和歡迎掩驱。 但了解精確的一維搜索技術(shù)對(duì)于非精確的技術(shù)有幫助芒划,所以本系列最開(kāi)始依然先從精確的一維搜索技術(shù)展開(kāi)。
精確的一維搜索技術(shù)
通常根據(jù)算法中有無(wú)使用導(dǎo)數(shù)欧穴,將精確的一維搜索技術(shù)分為兩類民逼,即無(wú)導(dǎo)數(shù)信息的試探法,包括二分法涮帘、黃金分割法拼苍、Fibonacci法、進(jìn)退法等;有導(dǎo)數(shù)信息的插值法疮鲫,包含二次插值法吆你、牛頓法等。
高低高(單峰)區(qū)間定位(initially bracketing a minmum)
對(duì)于求根問(wèn)題俊犯,通過(guò)兩點(diǎn)相乘為負(fù)即可確定一個(gè)區(qū)間(連續(xù)函數(shù))妇多。那么對(duì)于求解一維函數(shù)的局部極小值得問(wèn)題,可以通過(guò)三點(diǎn)信息獲得(a triplet of points)燕侠,即如果
者祖,使得
均小于
和
,且函數(shù)連續(xù)绢彤,那
之間就存在一個(gè)局部極小值七问,如下圖所示:
高低高區(qū)間的確定,最為常見(jiàn)的方法是進(jìn)退法茫舶。
進(jìn)退法的思想是先試探械巡、再判斷是進(jìn)還是退,直到得到饶氏,且
均小于
和
情況坟比,則可確定區(qū)間。
Algorithm 1 進(jìn)退法
function [a,b,c] = bracketAdvanceBack(func,x0,h0,plotFlag)
if nargin < 4
plotFlag = 0;
end
if nargin <3
h0 = 0.01;
end
if nargin <2
x0 = 0;
end
if plotFlag == 1
figH = figure();
k = 0;
end
x1 = x0;
h = h0;
x2 = x1 + h;
fx1 = func(x1);
fx2 = func(x2);
%試探
if fx2>=fx1 %說(shuō)明極小點(diǎn)位于x1的左方嚷往,后退搜索,即將步長(zhǎng)設(shè)定 為負(fù)葛账,x1和x2交換
h = -h0;
swap(x1,x2);
swap(fx1,fx2);
end
at = x0;
bt = x2;
iterNum = 1000;
while(iterNum)
h = 2*h;
x3 = x2 + h;
fx3 = func(x3);
ct = x3;
if plotFlag == 1
% pause(1);
plot(x0-300*h0:h0:x0+300*h0,func(x0-300*h0:h0:x0+300*h0),'-b',x1...
,func(x1),'or',x2,func(x2),'og',x3,func(x3),'ob');
print(figH,'-dpng',strcat('plotIm_',num2str(k)));
k = k+1;
end
if fx3>fx2
at = x1;
bt = x2;
ct = x3;
break;
else
x1 = x2;
x2 = x3;
fx2 = fx3;
end
iterNum = iterNum - 1;
end
a = min(at,ct);
b = bt;
c = max(at,ct);
end
function [x,y]=swap(x,y)
t = x;
x = y;
y = t;
end
注:本系列相關(guān)matlab代碼,對(duì)輸入的部分異常情況沒(méi)有進(jìn)行處理
Numerical recipes 10.1節(jié)中提供一種利用三點(diǎn)構(gòu)建的拋物線極小點(diǎn)進(jìn)行高低高區(qū)間的搜索皮仁,這種方法相比傳統(tǒng)的進(jìn)退法在同樣的初始條件下籍琳,能更快的找到高低高區(qū)間,算法如下:
Algorithm 2 拋物線法
function [a,b,c] = bracket(func,a,b,plotFlag,step,steplimit)
if nargin < 6
steplimit = 10;
end
if nargin < 5
step = 1.618034;
end
if nargin < 4
plotFlag = 0;
end
if nargin <3
b= 1;
end
if nargin <2
a = 0;
end
if abs(a-b) > 1
warning('the initial interval is too lager and the result may be unsatisfactory!')
end
if a>b
[a,b]=swap(a,b);
end
abInt = (b-a)/10;
abInt = min(abInt,0.1);
GOLD = step;
GLIMIT = steplimit;
ax = a;
bx = b;
fax = func(ax);
fbx = func(bx);
if fbx>fax
[fbx,fax]=swap(fbx,fax);
[bx,ax]=swap(bx,ax);
abInt = -abInt;
end
cx = bx + GOLD*(bx-ax);
fcx = func(cx);
if plotFlag == 1
figure, plot(ax:abInt:cx,func(ax:abInt:cx),'-b',ax,func(ax),'or',bx,func(bx),'og',cx,func(cx),'ob');
end
while fbx>fcx
r = (bx-ax)*(fbx-fcx);
q = (bx-cx)*(fbx-fax);
ux = bx -((bx-cx)*q-(bx-ax)*r)/(2.0*MySignFunc(max(abs(q-r),eps),q-r));%三點(diǎn)構(gòu)建拋物線的極值點(diǎn);
uxlim = bx + GLIMIT*(cx-bx);
if (bx-ux)*(ux-cx) > 0 %如果u在bx和cx之間
fux = func(ux);
if fux<fcx %我們就得到了一個(gè)高低高區(qū)間 在 bx ux cx
ax = bx;
bx = ux;
%cx = cx;
break;
else if fux>fbx %我們就得到一個(gè)高低高區(qū)間 在 ax bx ux
%ax = ax;
%bx = bx;
cx = ux;
break;
end
end
ux = cx + GOLD*(cx-bx); %如果上面兩個(gè)情況都不滿足贷祈,就在cx的基礎(chǔ)上擴(kuò)大 ux
elseif (cx-ux)*(ux-uxlim)>0 %如果ux在cx和uxlim之間
fux = func(ux);
if fux<fcx %fux是小于fcx的趋急,說(shuō)明 這個(gè)時(shí)候還有擴(kuò)大的空間 ax cx ux
bx = cx;
cx = ux;
ux = ux + GOLD*(ux-bx);%ux-cx
end
elseif (ux-uxlim)*(uxlim-cx)>=0.0 %如果uxlim在ux 和 cx 之間
ux = uxlim;
else
ux = ux + GOLD*(cx-bx);
end
ax = bx;
bx = cx;
cx = ux;
fax = func(ax);
fbx = func(bx);
fcx = func(cx);
if plotFlag == 1
pause(1);
plot(ax:abInt:cx,func(ax:abInt:cx),'-b',ax,func(ax),'or',bx,func(bx),'og',cx,func(cx),'ob');
end
end
abc = sort([ax,bx,cx]);
a = abc(1);
b = abc(2);
c = abc(3);
end
function [x,y]=swap(x,y)
t = x;
x = y;
y = t;
end
function a = MySignFunc(a,x)
a = abs(a);
if x<0
a = -a;
end
end
二分法
嚴(yán)苛點(diǎn),假設(shè)函數(shù)在區(qū)間存在極小值势誊,且
(1)若呜达,則
,說(shuō)明極小值在
;
(2)若,則
,說(shuō)明極小值在
;
則稱為在
區(qū)間上是單谷函數(shù)粟耻。在搜索區(qū)間時(shí)查近,我們找到的高低高區(qū)間往往是單谷函數(shù),確保單谷函數(shù)后挤忙,就有一系列的分割式的方法進(jìn)行精確的一維搜索極值的方法霜威,其中最簡(jiǎn)單就是二分法,類似求函數(shù)過(guò)零點(diǎn)的方法册烈,具體如下:
Algorithm 3 二分法
function x_min = BiSection(func,a,b,c,toll,plotFlag)
if nargin < 6
plotFlag = 0;
end
if nargin < 5
toll = 10^(-8);
end
if (a-b)*(b-c)<=0
x_min = 0;
disp('a<b<c or a>b>c is needed!');
return ;
end
if (a>c)
t=a;
a=c;
c=t;
end
x_mid = (a+c)/2;
if plotFlag == 1
figH = figure();
acInt = (c-a)/100;
plot(a:acInt:c,func(a:acInt:c),'-b',x_mid,func(x_mid),'-ro',a,func(a),'-*r',b,...
func(b),'-*g',c,func(c),'-*b');
hold on;
end
while abs(a-c)>2*toll
if x_mid == b
x_mid = (a+b)/2;
end
if x_mid>b
if func(x_mid) > func(b) %極小值在b的右端
c = x_mid;
else %極小值在x_mid的左端
a = b;
b = x_mid;
end
else
if func(x_mid) > func(b) %極小值在b的右端
a = x_mid;
else %極小值在x_mid的左端
c = b;
b = x_mid;
end
end
x_mid = (a+c)/2;
if plotFlag == 1
pause(0.15);
plot(x_mid,func(x_mid),'-ro');
end
end
hold off;
x_min = (b+x_mid)/2;
二分法是一種最簡(jiǎn)單的分割方法戈泼,每次迭代都將搜索區(qū)間縮短一半,故二分法的收斂速度是 線性的,收斂比是0.5大猛,收斂速度較慢扭倾。其優(yōu)勢(shì)是每一步迭代的計(jì)算量相對(duì)較少,邏輯簡(jiǎn)單挽绩,而且總能收斂到一個(gè)局部極小點(diǎn)吆录。
Fibonacci 分?jǐn)?shù)法
兔子生兔子問(wèn)題大家很熟悉,其就是典型的Fibonacci數(shù)列琼牧,數(shù)學(xué)定義為:
數(shù)列稱為斐波那契(Fibonacci)數(shù)列,
稱為第n個(gè)Fibonacci數(shù)哀卫,相鄰兩個(gè)Fibonacci數(shù)之比稱為Fibonacci分?jǐn)?shù)巨坊。從二分法中,可以得出下面的結(jié)論:
只要在區(qū)間
內(nèi)任取兩個(gè)不同點(diǎn)此改,并算出他們的函數(shù)值加以比較趾撵,就可以把搜索區(qū)間縮小為
或
,因?yàn)榭s小后的區(qū)間仍包含極小點(diǎn)。要進(jìn)一步縮小搜索區(qū)間共啃,只需在縮小后的區(qū)間內(nèi)再取一點(diǎn)占调,并與
或
比較函數(shù)值大小。按照這樣的步驟迭代進(jìn)行移剪,隨著計(jì)算函數(shù)值次數(shù)的 增加究珊,區(qū)間越來(lái)越小,從而越接近極小點(diǎn)纵苛。
這是分割類方法的通用思想剿涮,即通過(guò)不斷的縮小區(qū)間達(dá)到極值點(diǎn)。Fibonacci 分?jǐn)?shù)法是利用這一思想攻人,只是搜索區(qū)間的長(zhǎng)度不再是二分法的0.5取试,而是采用Fibonacci數(shù)列。
Algorithm 4 Fibonacci 分?jǐn)?shù)法
function x_min = FibonacciSection(func,a,b,toll,plotFlag)
%確保[a,b]為單峰區(qū)間
if nargin < 5
plotFlag = 0;
end
if nargin < 4
toll = 10^(-8);
end
if (a>b)
[a,b]=swap(a,b);
end
%step 1 初始化數(shù)據(jù)
Ln = (b-a)^2/toll;
F(1) = 1;
F(2) = 1;
n = 2;
%step 2 求Fibonacci數(shù)列
while F(n)<Ln
n = n+1;
F(n) = F(n-1) + F(n-2);
end
%step 3 初始化x1 x2怀吻,即k = 1
k = 1;
x1 = a+F(n-2)/F(n)*(b-a);
x2 = a+F(n-1)/F(n)*(b-a);
fx1 = func(x1);
fx2 = func(x2);
if plotFlag == 1
figH = figure();
abInt = (b-a)/100;
plot(a:abInt:b,func(a:abInt:b),'-b',a,func(a),'-*r',b,func(b),'-*g');
hold on;
end
%step 4 ,迭代縮短區(qū)間
while k<n-2
if fx1<fx2 %如果fx1<fx2瞬浓,則說(shuō)明極小點(diǎn)在a x2區(qū)間內(nèi)
b = x2;
x2 = x1;
fx2 = fx1;
x1 = a + F(n-k-2)/F(n-k)*(b-a);
fx1 = func(x1);
else %反之,則說(shuō)明極小點(diǎn)在x1 b之間
a = x1;
x1 = x2;
fx1 = fx2;
x2 = a + F(n-k-1)/F(n-k)*(b-a);
fx2 = func(x2);
end
k = k+1;
if plotFlag == 1
pause(0.15);
plot(a,func(a),'-*r',b,func(b),'-*g');
end
end
%step 5 k = n -2 時(shí),再此比較fx1 和 fx2
%區(qū)間固定在a b之間蓬坡,且包含 x2
if fx1<fx2
b = x2;
x2 = x1;
fx2 = fx1;
else
a = x1;
end
%step 6 計(jì)算x1 和 fx1 ,通過(guò)判斷得極小點(diǎn)
x1 = x2 - toll*(b-a);
fx1 = func(x1);
if plotFlag == 1
pause(0.15);
plot(x1,fx1,'-ro',x2,fx2,'-ob',a,func(a),'-*r',b,func(b),'-*g');
hold off;
end
if fx1<fx2
x_min = (a+x2)/2.0;
elseif fx1 == fx2
x_min = (x1+x2)/2.0;
else
x_min = (x1+b)/2;
end
end
function [a,b]=swap(a,b)
t=a;
a=b;
b=t;
end
Fibonacci分?jǐn)?shù)法可以證明是最優(yōu)策略猿棉。相對(duì)二分法Fibonacci分?jǐn)?shù)法收斂快,然而開(kāi)始需要確定迭代次數(shù)屑咳,計(jì)算Fibonacci數(shù)列铺根,每步取點(diǎn)繁瑣,各步縮短率不同乔宿。為此位迂,引入黃金分割法。
黃金分割法
黃金分割法內(nèi)分點(diǎn)的原則是:對(duì)稱且每次區(qū)間縮短率相等。對(duì)稱性來(lái)自Fibonacci分?jǐn)?shù)法掂林,固定縮短率也是改進(jìn)Fibonacci分?jǐn)?shù)發(fā)的不足臣缀,可見(jiàn)黃金分割法和Fibonacci分?jǐn)?shù)法是有聯(lián)系。的確泻帮,可以證明Fibonacci的縮短率在極限情況下就是黃金分割法的縮短率精置,0.618。有興趣的讀者可以查找相關(guān)資料锣杂。
在搜索區(qū)間內(nèi)適當(dāng)插入兩點(diǎn),
,且在區(qū)間內(nèi)對(duì)稱位置脂倦,計(jì)算其函數(shù)值
,
(1)若,則極小點(diǎn)必在區(qū)間
內(nèi)元莫,令
赖阻,新區(qū)間為
;
(2)若,則極小點(diǎn)必在區(qū)間
內(nèi),令
踱蠢,新區(qū)間為
火欧。
經(jīng)過(guò)函數(shù)值比較 ,區(qū)間縮短一次茎截。新區(qū)間只保留中的一個(gè)苇侵。
設(shè)原區(qū)間長(zhǎng)度為,保留區(qū)間長(zhǎng)度為
企锌,區(qū)間縮短率為
榆浓。進(jìn)行第二次縮短時(shí),新點(diǎn)
,設(shè)
撕攒,則新區(qū)間為
哀军。設(shè)區(qū)間縮短率為
。為了保持相同的區(qū)間縮短率打却,應(yīng)有:
由此可得:割法又稱為0.618法杉适。黃金分割法是一種等比例縮短區(qū)間的直接搜索方法,適用于[a,b]區(qū)間上的任何單谷函數(shù)求解極小值問(wèn)題柳击。對(duì)函數(shù)除要求單谷外不作其他任何要求猿推,甚至可以不連續(xù),因此適應(yīng)面廣捌肴。
Algorithm 5 黃金分割法
function x_min = GoldSection(func,a,b,toll,plotFlag)
%確保[a,b]為單峰區(qū)間
if nargin < 5
plotFlag = 0;
end
if nargin < 4
toll = 10^(-8);
end
if (a>b)
[a,b]=swap(a,b);
end
GOLD = (sqrt(5)-1)/2;
%step 1 初始化x1 x2
x1 = a+(1-GOLD)*(b-a);
x2 = a+GOLD*(b-a);
fx1 = func(x1);
fx2 = func(x2);
if plotFlag == 1
figH = figure();
abInt = (b-a)/100;
xx = a:abInt:b;
for i = 1:1:length(xx)
yy(i) = func(xx(i));
end
plot(xx,yy,'-b',a,func(a),'-*r',b,func(b),'-*g');
hold on;
end
%step 2 ,迭代縮短區(qū)間
while abs(a-b)>toll
if fx1<fx2 %如果fx1<fx2蹬叭,則說(shuō)明極小點(diǎn)在a x2區(qū)間內(nèi)
b = x2;
x2 = x1;
fx2 = fx1;
x1 = a + (1-GOLD)*(b-a);
fx1 = func(x1);
elseif fx1 == fx2
a = x1;
b = x2;
x1 = a+(1-GOLD)*(b-a);
x2 = a+GOLD*(b-a);
fx1 = func(x1);
fx2 = func(x2);
else%反之,則說(shuō)明極小點(diǎn)在x1 b之間
a = x1;
x1 = x2;
fx1 = fx2;
x2 = a + GOLD*(b-a);
fx2 = func(x2);
end
if plotFlag == 1
pause(0.15);
plot(a,func(a),'-*r',b,func(b),'-*g');
end
end
x_min = (a+b)/2;
end
function [a,b]=swap(a,b)
t=a;
a=b;
b=t;
end
黃金分割法和Fibonacci分?jǐn)?shù)法也是線性收斂状知,收斂比率約0.618
二次插值法
二分法秽五、Fibonacci分?jǐn)?shù)法以及黃金分割法都屬于試探法,即試驗(yàn)點(diǎn)的位置是由某種給定的規(guī)則確定的饥悴,并沒(méi)有考慮數(shù)值的分布坦喘,僅僅利用試驗(yàn)點(diǎn)函數(shù)值進(jìn)行大小的比較盲再;插值法試驗(yàn)點(diǎn)的位置是按照函數(shù)近似分布的極小點(diǎn)確定的,即插值法需要利用函數(shù)值本身或其導(dǎo)數(shù)信息瓣铣,所以當(dāng)函數(shù)具有較好的解析性質(zhì)時(shí)答朋,插值法比試探法效果更好。
利用原目標(biāo)函數(shù)上的三個(gè)插值點(diǎn)棠笑,構(gòu)成一個(gè)二次插值多項(xiàng)式梦碗,用該多項(xiàng)式的最優(yōu)解作為原函數(shù)最優(yōu)解的近似解,逐步逼近原目標(biāo)函數(shù)的極小點(diǎn)蓖救,稱為二次插值方法或近似拋物線法洪规。簡(jiǎn)單流程如下圖所示:
Algorithm 6 二次插值法
function x_min = ParabolicInterpolationSection(func,a,b,toll,plotFlag)
%確保[a,b]為單峰區(qū)間,且連續(xù)
if nargin < 5
plotFlag = 0;
end
if nargin < 4
toll = 10^(-8);
end
if (a>b)
[a,b]=swap(a,b);
end
if plotFlag == 1
figH = figure();
abInt = (b-a)/100;
plot(a:abInt:b,func(a:abInt:b),'-b',a,func(a),'-*r',b,func(b),'-*g');
hold on;
end
%step 1 初始化
x1 = (a+b)/2;
%step 2 迭代縮短區(qū)間
while abs(a-b) > toll
fa = func(a);
fx1 = func(x1);
fb = func(b);
r = (x1-a)*(fx1-fb);
q = (x1-b)*(fx1-fa);
C1 = (x1-a)*r-(x1-b)*q;
C2 = r-q;
if C2 == 0 %說(shuō)明三點(diǎn)共線,對(duì)于單峰情況循捺,三點(diǎn)共點(diǎn)了斩例,退出
break;
end
x2 = x1 - 1/2*C1/C2; %計(jì)算拋物線的極值點(diǎn)
if (x2-a)*(b-x2)<=0 %極值點(diǎn)不在區(qū)間內(nèi)(兩點(diǎn)共點(diǎn))
break;
end
fx2 = func(x2);
if x2>x1
if fx1<fx2 %如果x2在x1的右邊,fx1<fx2巨柒,則說(shuō)明極小值在a x2區(qū)間內(nèi)
b = x2;
fb = fx2;
else %如果x2在x1的右邊,fx1>=fx2柠衍,則說(shuō)明極小值在x1 b區(qū)間內(nèi)
a = x1;
fa = fx1;
x1 = x2;
fx1 = fx2;
end
else
if fx1<fx2%如果x2在x1的左邊洋满,fx1<fx2,則說(shuō)明極小值在x2 b區(qū)間內(nèi)
a = x2;
fa = fx2;
else %如果x2在x1的左邊珍坊,fx1>=fx2牺勾,則說(shuō)明極小值在a x1區(qū)間內(nèi)
b = x1;
fb = fx1;
x1 = x2;
fx1 = fx2;
end
end
if plotFlag == 1
pause(0.15);
plot(a,fa,'-*r',b,fb,'-*g');
end
end
if plotFlag == 1
hold off;
end
x_min = (a+b)/2;
end
function [a,b]=swap(a,b)
t=a;
a=b;
b=t;
end
三點(diǎn)二次插值法并沒(méi)有直接用到函數(shù)的導(dǎo)數(shù)信息,且相同迭代次數(shù)下阵漏,可以得到更精確的結(jié)果驻民,其收斂比率為1.3,在有解析表達(dá)式履怯,函數(shù)連續(xù)情況下回还,是很實(shí)用的。但拋物線法也有不收斂的情況[1]叹洲,為此Brent做了改進(jìn)柠硕,見(jiàn)后文Brent's Method。
插值法還有很多运提,比如兩點(diǎn)二次插值蝗柔,三次插值,牛頓法民泵,有理插值法等癣丧,這些方法需要用到導(dǎo)數(shù)信息。下面我們介紹牛頓法栈妆,即一點(diǎn)二次插值法胁编。其他方法如果讀者有興趣了解厢钧,可自行從網(wǎng)上檢索相關(guān)算法。
牛頓法
當(dāng)原函數(shù)存在一階二階連續(xù)可導(dǎo)時(shí)掏呼,可以采用牛頓法進(jìn)行一維搜索坏快,收斂速度快,具有局部二階收斂速度憎夷。牛頓法的思想是用二次函數(shù)逐點(diǎn)近似原目標(biāo)函數(shù)莽鸿,以二次函數(shù)的極小點(diǎn)來(lái)近似原目標(biāo)函數(shù)的極小點(diǎn),用切線代替狐仙逐漸逼近導(dǎo)數(shù)函數(shù)的根拾给∠榈茫可以理解為當(dāng)目標(biāo)函數(shù)有一階連續(xù)導(dǎo)數(shù),且二階導(dǎo)數(shù)大于零時(shí)蒋得,函數(shù)的極小值點(diǎn)應(yīng)該滿足極值點(diǎn)存在的必要條件级及,即導(dǎo)數(shù)為0,所以求函數(shù)的極小值點(diǎn)也就是求解函數(shù)一階導(dǎo)數(shù)為0的根额衙。
過(guò)點(diǎn)的切線方程為:
與軸的交點(diǎn)
為:
推廣到k步得到迭代公式:
此外迭代公式也可以由Taylor公式展開(kāi)得到:
在附近用二次函數(shù)來(lái)逼近原目標(biāo)函數(shù)饮焦,故在
點(diǎn)用Taylor公式展開(kāi),保留到二次項(xiàng):
令,也可以得到上面的迭代公式窍侧。
Algorithm 7 牛頓法(一維線性搜索)
function x_min = NewtonLinSrch(func,dfunc,ddfunc,a,b,toll,plotFlag)
%func 一階二階連續(xù)可導(dǎo)县踢,且二階導(dǎo)數(shù)大于0
if nargin < 7
plotFlag = 0;
end
if nargin < 6
toll = 10^(-8);
end
if (a>b)
[a,b]=swap(a,b);
end
x1 = (a+b)/2;
if plotFlag == 1
figH = figure();
abInt = (b-a)/100;
plot(a:abInt:b,func(a:abInt:b),x1,func(x1),'-ro');
hold on;
end
while abs(dfunc(x1))>toll&&ddfunc(x1)>0
x1 = x1 - dfunc(x1)/ddfunc(x1);
if (x1-a)*(b-x1)<=0
break; %如果x1超界,說(shuō)明一階導(dǎo)數(shù)或者二階導(dǎo)數(shù)不滿足使用牛頓法的條件
end
if plotFlag == 1
pause(0.15);
plot(x1,func(x1),'-ro');
end
end
x_min = x1;
end
function [a,b]=swap(a,b)
t=a;
a=b;
b=t;
end
Brent's Method
以上精確的一維搜索方法各有優(yōu)缺點(diǎn)伟件,Brent為了在所有特殊情況下都能較好的適用硼啤,提出了Brent's Method[1]。該方法也被收錄在Matlab的優(yōu)化庫(kù)中斧账,即fminbnd函數(shù)谴返。該方法結(jié)合了二次插值方法和黃金分割法,它在任何特殊的情況中咧织,都保持6個(gè)函數(shù)點(diǎn)嗓袱,即。其中最小值在
和
之間习绢,
是迭代一次找的最小值對(duì)應(yīng)的函數(shù)點(diǎn)索抓,
是次小點(diǎn),
是
前一次迭代點(diǎn)毯炮,
是當(dāng)前迭代的函數(shù)點(diǎn)逼肯。可以通過(guò)閱讀小面的matlab代碼來(lái)理清Brent's Method的邏輯桃煎。其核心思想是大區(qū)間下采用二次插值法篮幢,小區(qū)間的時(shí)候采用黃金分割法,來(lái)避免二次插值法在小區(qū)間陷入循環(huán)的弊病为迈。幾點(diǎn)需要注意[1]:
1三椿、二次插值使用
三點(diǎn)缺菌;
2、插值出來(lái)的拋物線極值點(diǎn)一定在區(qū)間內(nèi)搜锰;
3伴郁、的移動(dòng)步長(zhǎng)不大于上一次的一半([1]中說(shuō)這樣做可以使得插值計(jì)算的這一步收斂在比較好的點(diǎn)上,避免nonconvergent limit circle)
Algorithm 8 Brent's Method
function x_min = BrentMethod(func,a,b,c,tol,iterNum,plotFlag)
%Brent's Method fminbnd
if nargin < 7
plotFlag = 0;
end
if nargin < 6
iterNum = 100;
end
if nargin < 5
tol = 10^(-8);
end
if (a-b)*(b-c)<=0
x_min = 0;
disp('a<b<c or a>b>c is needed!');
return ;
end
if (a>c)
b = a;
a = c;
else
b = c;
end
if plotFlag == 1
figH = figure();
abInt = (b-a)/100;
plot(a:abInt:b,func(a:abInt:b));
hold on;
end
GOLD = 1 - (sqrt(5)-1)/2.0;
x = b;
w = b;
v = b;
fw = func(w);
fx = fw;
fv = fw;
e = 0;
d = 0;
for i=1:1:iterNum
xm = (a+b)/2.0;
tol1 = tol*abs(x)+eps;
tol2 = 2*tol1;
if plotFlag == 1
pause(0.15);
plot(x,fx,'-ro');
end
if abs(x-xm) <= (tol2-0.5*(b-a))
x_min = x;
return;
end
if abs(e)>tol1 %這種情況下是用二次插值法
r = (x-w)*(fx-fv);
q = (x-v)*(fx-fw);
p = (x-v)*q - (x-w)*r;
q = 2.0*(q-r);
if q>0
p = -p;
end
q = abs(q);
etemp = e;
e = d;
if abs(p) >= abs(0.5*q*etemp)||p<=q*(a-x)||p>=q*(b-x)
%采取黃金分割法得到更大的兩段
if x>=xm %從a蛋叼,x焊傅,b區(qū)間段中 找最大的一段,乘以GOLD作為下一次的步長(zhǎng)
e = a-x;
else
e = b-x;
end
d = GOLD*e;%二次插值法不被接受狈涮,采用golden section
else
d = p/q;
u = x + d; %采用二次插值法
if u-a<tol2||b-u<tol2 %如果u值很接近a或者b狐胎,將步長(zhǎng)設(shè)為xm和x的長(zhǎng)度
d = MySignFunc(tol1,xm-x);
end
end
else %采用黃金分割
if x>=xm
e = a-x;
else
e = b-x;
end
d = GOLD*e;%二次插值法不被接受,采用golden section
end
if abs(d) >= tol1 %步長(zhǎng)選擇tol1和d中較小的一個(gè)
u = x+d;
else
u = x+MySignFunc(tol1,d);
end
fu = func(u);
if fu<=fx %如果fu小于fx,說(shuō)明下次迭代為區(qū)間不是在[a,x]歌馍,就是在[x,b]
if u>=x %如果u>=x握巢,則在[x,b],反之在[a,x]
a = x;
else
b = x;
end
v = w;w = x;x = u;
fv = fw;fw = fx;fx = fu;
else%反之松却,說(shuō)明下次迭代區(qū)間不是[a,u],就是[u,b]
if u<x
a = u;
else
b = u;
end
if fu<=fw || w==x
v = w; w = u;
fv = fw; fw = fu;
else if fu<=fv||v==x||v==w
v=u;
fv=fu;
end
end
end
end
end
function a = MySignFunc(a,x)
a = abs(a);
if x<0
a = -a;
end
end
參考文獻(xiàn)
[1] Numerical Recipes, William H. Press