近似算法


近似算法

 

我們的問題是,給定一個亂七八糟的函數,求它在某個區域內的最大值(最小值)。

模擬退火算法

爬山

爬山算法是純粹的貪心算法。給定一個起始點,我們能爬到一個極大值。

while(1)
{
    if(f(x+0.001) - f(x-0.001) > eps)  x+=0.001;         
    //如果向右走有利,則向右走
    else if(f(x+0.001) - f(x-0.001) < -eps) x+=0.001;
    //如果向左走有利,則向左走

    else goto finish;       //已經爬到極大值
}

爬山的缺陷在於,它會陷入局部最優解,而難以爬到全局最優解。例如下圖。 爬山

我們把上面的x+0.001之類的操作稱作“移動”。

經典模擬退火

模擬退火的思想在於,如果一個移動會使答案變得更優,我們就接受這個移動;否則我們以一定的概率接受這個移動。

聽起來很玄學。根據物理的那套理論,我們定義兩個東西:
- 溫度$(T)$。它隨着時間推移而逐漸降低。
- 增量$(E)$。它描述一次移動獲得的好處。從$x$移動到$x'$的增量定義為$f(x')-f(x)$,增量越大,往$x'$移動的優勢越大。

在模擬退火中,如果增量大於$0$,則直接接受這次移動;否則按下面的概率接受移動:

$$P = \exp(\frac{E}{T})$$

聽起來十分的玄學。然而它竟然可以得出精度比較好的解。偽代碼如下:

T=100.0;               //初始溫度

for(int i=0;i<100;i++)      //控制迭代次數
{
    tar=getPos();           //在x的周圍選一個點
    E=f(tar)-f(x);

    if(E > eps) x=tar;      //直接移動
    else if(exp(E/T) > random(0,1)) x=tar;     //接受移動

    T=T*0.99;               //降溫
}

遺傳算法

不妨假設有一大群兔子,它們均勻地分布在各種地方。
由於一些黑惡勢力的影響,每年只有位置最高的那100只兔子能活下來。

位置最高的那些兔子們繁衍生息,它們的后代有些比它們站得高,於是這些后代活了下來;其他后代被黑惡勢力搞死了。每年都只有站得最高的100只兔子能活下來。

在無盡的歲月后,這100只兔子想必都站在了世界上最高的山峰。

這個算法聽起來比模擬退火靠譜。現在它的實現過程如下:

  1. 先隨機產生100個點,均勻地分布在所求區間上。
  2. 取每兩個點的中位數,這樣我們共獲得了10000個點。
  3. 取出最高的100個點,然后開始新一輪迭代。

但是這會引發一個問題。例如下圖:

問題

這樣的話,無論我們迭代多少次,總是找不到最高點(因為是取中位數)。這搞屁。

所以我們引入變異。每個數都有二進制表示,我們產生一個數之后,對它進行變異操作:二進制的每一位都以$p$的概率翻轉。

這樣的話,由於變異的存在,迭代若干次之后,最高點是找得到的。

那么問題來了。$p$到底取多少?

恭喜您打開了黑暗世界的大門——玄學調參數。由於我們很難給出一個很妙的$p$,遺傳算法變得比模擬退火還不靠譜。

如何玄學調參數呢?我們造一些區間比較小的數據,暴力求出答案,然后根據這些數據來調整$p$。猜很多個$p$的值,看哪個最好。我們只需要考慮$p<0.5$的情況,因為以p的概率翻轉,和以p的概率不翻轉是本質相同的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM