【学习笔记】我命由天不由我之随机化庇佑 —— 爬山法 和 模拟退火法
以下均假設最優解是在最低點。
爬山法
爬山算法是一種局部擇優的方法,采用啟發式方法,是對深度優先搜索的一種改進,它利用反饋信息幫助生成解的決策。
直白地講,就是當目前無法直接到達最優解,但是可以判斷兩個解哪個更優的時候,根據一些反饋信息生成一個新的可能解。
因此,爬山算法每次在當前找到的最優方案 xxx 附近尋找一個新方案。如果這個新的解 x′x'x′ 更優,那么轉移到 x′x'x′,否則不變。
這種算法對于單峰函數顯然可行。
Q:既然都知道是單峰函數了為什么不三分呢?
A:你說的對!直接三分好了。
B:我要是知道是單峰函數,我還在這里騙分???
爬山算法會引入『溫度參數』 TTT。
類比的說,爬山就是一個醉漢喝得狂醉然后再山上裸奔蹦迪。
他知道該回家了(不然就要跪搓衣板),然后每次會往他認為最低的地方狂奔過去(中途不剎車)。
顯然他可能一次恰好奔到山腳然后下山回家,也有可能奔過了到另一座山頂上去了。
不過沒關系,醉漢奔過頭了還會存在奔回來的可能。
但顯然這個過程很沒用。仿佛醉漢回家全靠天公作美。
所以在暴走過程中,他會經受山頂寒風的摧殘,酒精作用漸漸消減,他變得越發清晰。
他就變得謹慎一點,每次少奔一點以達到山腳最低點位置。
這就要引入『降溫參數』來起到緩緩冷靜的作用。
關于『降溫參數』,一般是 [0.985,0.999][0.985,0.999][0.985,0.999] 中選,這樣才能做到慢慢消減。
顯然如果存在多個”轉折“時,爬山就很容易進入局部最優解,而非全局最優解。
隨著頭腦逐漸清醒,醉漢蹦出局部最優解的期望就會更小,很有可能一直跳不過去某個坡。
模擬退火
為什么會有上面情況的產生呢?
其實是因為爬山法的寫法,只有在新解優于當前解的時候,我們才會接受新解并移動到相應位置。
根據這種情況,我們知道其實偶爾新解不好我們也要去接受,這樣才會存在跳出這個坡的可能。
這就是模擬退火了。
模擬退火相較于爬山就只是多了一個隨機接受非最優解的部分,大大增加了找到全局最優解得可能。
以下是追根溯源,由物理和化學知識遷移到信息學上應用:
我們知道在分子和原子的世界中,能量越大,意味著分子和原子越不穩定,當能量越低時,原子越穩定。
『退火』是物理學術語,指對物體加溫在冷卻的過程。
模擬退火算法來源于晶體冷卻的過程,如果固體不處于最低能量狀態,給固體加熱再冷卻,隨著溫度緩慢下降,固體中的原子按照一定形狀排列,形成高密度、低能量的有規則晶體(即全局最優解)。
而如果溫度下降過快,可能導致原子缺少足夠的時間排列成晶體的結構,結果產生了具有較高能量的非晶體(即局部最優解)。
因此就可以根據退火的過程,給其再增加一點能量,然后再冷卻,如果增加能量,跳出了局部最優解,那么本次退火就是成功的。
模擬退火由兩個部分組成:Metropolis\text{Metropolis}Metropolis 算法和退火過程。
Metropolis\text{Metropolis}Metropolis 算法就是如何在局部最優解的情況下讓其跳出來,是退火的基礎。
Metropolis\text{Metropolis}Metropolis 提出的以概率來接受新狀態的重要性采樣方法,而非使用完全確定的規則,稱為Metropolis\text{Metropolis}Metropolis 準則,計算量較低。
假設我們從 AAA 開始求解。先跳到 BBB,然后發現 BBB 更優,絕對接受。BBB 又跳到 CCC,絕對接受。CCC 跳到 DDD ,哎呀更差了呢!此時我們以一定的概率選擇是否接受;假設接受,DDD 又跳到 EEE 發現比之前跳到的所有位置都優,直接接受,EEE 繼續跳……\dots\dots…… ;不接受,就還停在 CCC 又開始隨機下一個解。
至于這個接受概率是多少呢?已經有前人計算出來了。x:x:x: 當前最優解,x′:x':x′: 產生的新解
P={1E(x′)<E(x)e?E(x′)?E(x)TE(x′)≥E(x)P=\begin{cases}1\quad\quad\quad\quad\quad\quad E(x')<E(x)\\e^{-\frac{E(x')-E(x)}{T}}\quad\quad\ E(x')\ge E(x)\end{cases} P={1E(x′)<E(x)e?TE(x′)?E(x)??E(x′)≥E(x)?
從這個式子我們可以看出,如果新解更優,那么百分之百絕對接受;否則我們會以 PPP 的概率接受。
Metropolis\text{Metropolis}Metropolis 算法雖然說是模擬退火算法的基礎,但直接使用的話可能導致尋找解得速度太慢,以至于無法過題。
為了確保在有限的時間收斂,必須設定控制算法收斂的參數。
在上面的公式中,可以調節的參數就是『溫度參數』TTT。
- TTT 如果過大,就會導致退火太快,迭代次數不夠,最后停留在局部最優值就會結束迭代。
- TTT 如果較小,則計算時間會增加。
實際應用中采用退火溫度表,在退火初期采用較大的 TTT 值,隨著退火的進行,逐步降低:
-
初始的溫度 T0T_0T0? 應選的足夠高,使的所有轉移狀態都被接受。初始溫度越高,獲得高質量的解的概率越大,但耗費的時間也越長。
-
退火速率。
-
指數式下降:Tn=λTn,n=1,2,3,...T_n=\lambda T_n,n=1,2,3,...Tn?=λTn?,n=1,2,3,...。λ\lambdaλ 即是爬山算法里面的『降溫參數』,選取的值同樣遵守 <1<1<1 又逼近 111 原則。
這種方式最常見,且對每一溫度,有足夠的轉移嘗試,但其收斂速度比較慢。
-
其它方式:
- Tn=T0log?(1+t)T_n=\frac{T_0}{\log(1+t)}Tn?=log(1+t)T0??。
- Tn=T01+tT_n=\frac{T_0}{1+t}Tn?=1+tT0??。
-
-
終止溫度。當 T0T_0T0? 迭代到終止溫度時就會結束退火。一般設為 eps=1e-k(k∈Z+k\in \Z^+k∈Z+)。
一般針對數據進行『溫度參數』TTT,『降溫參數』Δ\DeltaΔ 的調參,在本地手造大數據跑,自己抉擇。
對時間和正確性的平衡選取。
有的時候可以用 #include <ctime> 庫里面自帶的 clock() 函數計時,也可以自己定一個跑的次數。
( clock() / (1.0 * CLOCKS_PER_SEC) ) <= TIME //返回的是多少秒 所以TIME是個 <1 的浮點數需要注意是:
- 初始溫度 T0T_0T0? 的選取對算法結果有一定的影響,最好是多次運行對結果進行綜合判斷。
- 在算法運行初期,溫度下降快,避免接受過多的差結果。當運行時間增加,溫度下降減緩,以便于更快穩定結果。
- 當迭代次數增加到一定次數時,結果可能已經達到穩定,但是距離算法結束還有一段時間。在設計程序時應該加入適當的輸出條件,滿足輸出條件即可結束程序。
最后給出流程圖總結:又淘了一張好圖
顯然,模擬退火也不一定是對的,這個概率接受就很概率。但對比爬山得到最優解的概率肯定是大大增加的。
例題
Strange function
hdu2899
TTT 次詢問,每次給定 yyy。
求 f(x)=6x7+8x6+7x3+5x2?yx(0≤x≤100)f(x)=6x^7+8x^6+7x^3+5x^2-yx\quad(0\le x\le 100)f(x)=6x7+8x6+7x3+5x2?yx(0≤x≤100) 的最小值。
#include <bits/stdc++.h> using namespace std; double y; const double eps = 1e-8; //終止溫度 const double delta = 0.997; //溫度變化率 mt19937 wwl(time(0)); uniform_real_distribution < double > range( 0, 100 );double f( double x ) {return 6 * pow(x, 7) + 8 * pow(x, 6) + 7 * pow(x, 3) + 5 * pow(x, 2) - y * x; }double solve() {double T = 100, x = range( wwl ); //初始溫度 以及初始隨機解double now = f(x), ans = now;int Time = 8e5; //防止超時的卡點次數while( T > eps and Time -- ) { //要么降溫完成 要么被卡時double tx = x + (rand() * 2 - RAND_MAX) * T; //隨機擾動產生新解if( 0 <= tx and tx <= 100 ) {double nxt = f(tx);ans = min( ans, nxt );if( nxt < now ) //新狀態更小 直接接受x = tx, now = nxt;else if( rand() < exp( ( now - nxt ) / T ) * RAND_MAX ) //在一定概率內仍接受這個解x = tx, now = nxt;}T *= delta; //降溫}return ans; }int main() {int T;scanf( "%d", &T );while( T -- ) {scanf( "%lf", &y );printf( "%.4f\n", solve() );}return 0; }[JSOI2004]平衡點 / 吊打XXX
洛谷鏈接
#include <bits/stdc++.h> using namespace std; #define delta 0.996 #define maxn 1005 #define eps 1e-15 struct node { int x, y, w; }g[maxn]; int n;double energy( double x, double y ) {double ans = 0, dx, dy;for( int i = 1;i <= n;i ++ ) {dx = x - g[i].x, dy = y - g[i].y;ans += sqrt( dx * dx + dy * dy ) * g[i].w;}return ans; }double ansx, ansy, ans, x, y, now; void Simulate_Anneal() {double T = 5e4;while( T > eps ) {double tx = x + (rand() * 2 - RAND_MAX) * T;double ty = y + (rand() * 2 - RAND_MAX) * T;double tw = energy( tx, ty );if( tw < ans ) ans = tw, ansx = tx, ansy = ty;if( tw < now ) x = tx, y = ty, now = tw;else if( rand() < exp( ( now - tw ) / T ) * RAND_MAX )x = tx, y = ty;T *= delta;} }signed main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d %d %d", &g[i].x, &g[i].y, &g[i].w );for( int i = 1;i <= n;i ++ ) x += g[i].x, y += g[i].y;x /= n, y /= n;ansx = x, ansy = y;now = ans = energy( x, y );Simulate_Anneal();Simulate_Anneal();Simulate_Anneal();Simulate_Anneal();printf( "%.3f %.3f\n", ansx, ansy );return 0; }Haywire
洛谷鏈接
#include <bits/stdc++.h> using namespace std; #define TIME 0.9 #define eps 1e-10 #define delta 0.998 #define maxn 15 int n; int p[maxn]; int f[maxn][5];int energy() {int ans = 0;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= 3;j ++ )ans += fabs( p[i] - p[f[i][j]] );return ans; }int main() {mt19937 wwl(time(NULL));scanf( "%d", &n );uniform_int_distribution < int > id( 1, n );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= 3;j ++ )scanf( "%d", &f[i][j] );iota( p + 1, p + n + 1, 1 );int ans = energy();while( ( clock() / (1.0 * CLOCKS_PER_SEC) ) <= TIME ) {for( int i = 1;i <= n;i ++ ) p[i] = i;double T = 1e5; int x, y;while( T > eps ) {do { x = id( wwl ), y = id( wwl ); }while( x == y );swap( p[x], p[y] );int now = energy();if( now < ans ) ans = now;else if( rand() > exp( ( now - ans ) / T ) * RAND_MAX )swap( p[x], p[y] );T *= delta;}}printf( "%d\n", ans / 2 );return 0; }學習參考博客:
https://www.cnblogs.com/flashhu/p/8884132.html
https://blog.csdn.net/weixin_42398658/article/details/84031235
https://zhuanlan.zhihu.com/p/266874840?utm_source=qq
總結
以上是生活随笔為你收集整理的【学习笔记】我命由天不由我之随机化庇佑 —— 爬山法 和 模拟退火法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何选择一款适合自己电脑的固态硬盘怎么样
- 下一篇: 第八周项目5-定期存款利息计算器