Optimization
程度★ 難度★★
Optimization
「最佳化」就是找到函數的最大值或者最小值。定義很簡單。
什麼時候需要最佳化?
電腦是計算機,只會計算數字。要讓電腦代替人腦處理真實世界的問題,首先要將人腦的抽象想法,一一對應到電腦的實際數值。
人腦考慮的「效果最好」與「效果最差」,放到了電腦就被設定成「數字最大」與「數字最小」。人腦考慮的「問題」與「各種可能性」,放到了電腦就被設定成「函數」與「各種輸出入」。
於是乎,人腦考慮的「最好結果」與「最差結果」,放到了電腦就是「最佳化」!
函數的極值
一維函數和二維函數容易作圖,三維函數就只能用空氣濃度來呈現函數值了,四維以上只能用幻想的。
以人類視覺感官來說,只要放眼一望就能看到最高點,可是電腦卻辦不到,只能一個一個位置判斷高度。
於是,每一種最佳化演算法除了必須找到極值,另外還有一個重要的共同議題得解決:如何避免卡在區域極值。於是各種奇妙的最佳化演算法就紛至沓來了。
最佳化演算法
百家爭鳴、各有所長。耍嘴皮子的成分居多。
儘管這些演算法不保證答案正確,然而在沒有其他更好的選擇之下,不失為一種解決方案。
http://en.wikipedia.org/wiki/Mathematical_optimization#Optimization_algorithms
http://en.wikipedia.org/wiki/Metaheuristic#Main_contributions
地面勘查類型
程度★ 難度★★
概論
選一個起點,一步一腳印,走向極值。
適用於函數值如同地表般連續起伏的時候。
Hill Climbing(登山法)
沿著函數圖形的表面前進。嘗試隨便跨出一步,確定是往上,就直直走;確定是往下,就不走,並轉向。最後成功登頂。
Simulated Annealing(模擬退火法)
登山法加強版。允許往下走,留個退路,避免走錯山頭。
嘗試隨便跨出一步,確定是往上,就走;確定是往下,以機率exp(-Δt/T)決定走或不走,其中Δt是前後高度差,T是時間。大致上來說,往下越陡就越不想走,年紀越大就越不想走。
註:原論文是找山谷而非找山峰。
Tabu Search(禁忌搜尋)
把剛剛經過的地方用記憶體記下來,避免鬼打牆。
實作時,記住前k步,以queue紀錄。
Gradient Descent(梯度下降法)
計算當前位置的傾斜程度,沿著最陡的方向前進。
求得傾斜程度的方式,是對函數進行一次微分,代入當前位置就得到斜率。因此這個方法只能用在可微函數。
註:原論文是找山谷而非找山峰。
Newton's Method(牛頓法)
計算當前位置的傾斜程度,沿著最陡的方向前進。
求得傾斜程度的方式,是對函數進行二次微分,換句話說就是計算Hessians Matrix。因此這個方法只能用在可微函數。
使用二次微分,可以避免卡在鞍點。
空中勘查類型
程度★ 難度★★
概論
像偵察機一樣飛來飛去,不會被高山峽谷阻擋。
Particle Swarm Optimization(粒子演算法)
一、散佈N個粒子。一個粒子代表一個可行解。可行解D維。 positions[N][D]; 二、以個人過去最佳解、團體過去最佳解,決定粒子的速度。 然後移動粒子,讓粒子飛往最佳解。 velocitys[i][j] = 2.0 * rand(0 ~ 1) * (best_positions[i][j] - positions[i][j]) + 2.0 * rand(0 ~ 1) * (best_positions[best_particle_index][j] - positions[i][j]); 三、更新個人最佳解、團體最佳解。 四、重複二三,直到解夠好。
Bee Colony Optimization(蜜蜂演算法)
一、散佈N個食物。一個食物代表一個可行解。可行解D維。 positions[N][D]; 二、N隻蜜蜂分頭前往N個食物並返回,但是腦中記得的位置會有偏差。 positions[i][j] += rand(-1 ~ +1) * positions[rand(1 ~ N expect i)][j]; 三、每隻蜜蜂皆從N個食物中挑一個去,機率由解的好壞決定。 probability[i] = solution[i] / ( solution[1] + ... + solution[N] ) 返回時腦中記得的位置一樣會有偏差。公式同二。 四、如果某個食物連續K個回合沒去,食物自動消滅。 隨機散佈食物,補足食物直到N個。 五、重複二三四,直到解夠好。
劃分區域類型
程度★ 難度★★
概論
像包圍網一樣把範圍逐漸縮小。
Branch and Bound(分支定界法)
先把一段數據區間分成幾段較小的區間。如果有一段區間,我們當下看不出它是不是正確區間,就把該區間分得更細,並遞迴下去,釐清細節;如果能看出,就停止遞迴。
branch是指當一段區間不確定界限,就分割區間,並遞迴下去。bound是指當一段區間確定了界限,並停止遞迴。
Linear Programming(線性規劃)
線性規劃用於線性函數,並且有許多限制條件時。可以寫成聯立線性不等式。
多半用於圖論問題,效果相當好。針對不同問題,有著各種加速技巧。
由於內容繁雜,此處省略之,各位讀者可自行蒐集資料閱讀。
UVa 10498
排列組合類型
程度★ 難度★★
概論
已經沒有地圖的概念。拼湊函數輸入,盡量讓輸出函數值是極值。
Genetic Algorithm(基因演算法)
這是一個隨機亂湊答案的方法,靈感來自於染色體減數分裂的過程,優良的基因會不斷遺傳下去,逐代演化出更適應環境的基因。基因演算法把答案比擬成染色體,把好的答案不斷分裂再結合,成為更好的答案。
1. [初始化] 一開始先隨便弄幾組答案。 1010101010 1011001011 1110101011 0010101000 2. [fitness function] 根據問題特性,定義答案的好壞程度。 f(1010101010) = 678 3. [selection] 隨便找個位置切一刀,各組答案都被分成兩段。 1010101 010 1011001 011 1110101 011 0010101 000 4. [crossover] 隨便找兩組你覺得夠優良的答案,交叉相接變成新答案。不優良的答案就不交叉相接。 重複一直做到答案數目跟原先一樣多。 1010101 \/ 010 -> 1010101 -- 011 1011001 /\ 011 1011001 -- 010 1010101011 1011001010 1110101010 1010101000 5. [mutation] 每組答案都隨便找一個地方把數字改掉,也可以不改。 1010111011 1011001000 1110101010 1010101001 6. 重複3. 4. 5.,直到裡面有一組答案是你滿意的。
1. 隨機產生N組答案。 2. 計算fitness function。 3. 重複以下步驟,直到有一組答案讓人滿意。 甲、selection。 乙、crossover。 丙、mutation。(如果一開始的答案種類足夠豐富,則可以省略不做) 丁、計算fitness function。
演算法的大致過程就是如此,細部的實作方式、參數的調校方式則是隨人話虎爛。只要一開始的答案種類足夠豐富,多演化幾次,就可以得到不錯的結果。
一開始的答案種類足夠豐富,則可以避免進入區域極值。mutation可以增加答案豐富性,跳脫區域極值。
範例:0/1 Knapsack Problem
有N個物品。 [初始化] 答案設計成N個二進位數字, 0代表對應的物品不在背包內, 1代表對應的物品在背包內。 [fitness function] 是背包內物品總價值,數值越大越好。
當「特定組合」具有深邃的影響力,造成最佳解、次佳解們都包含著同一(幾)套「特定組合」,此時就適合使用基因演算法。以0/1背包問題為例,一套好的物品組合方式可以有效節省背包空間,只要依賴幾套好的物品組合方式,就留有足夠的背包空間,能夠隨心所欲的放入其他物品;所有接近最佳解的答案,答案的其中一小段,都會是那幾套固定的物品組合方式──這種情況就非常適合使用基因演算法。
UVa 10715
範例:Minimum Spanning Tree
有E條邊。 [初始化] 答案設計成E個二進位數字, 0代表對應的邊不是MST。 1代表對應的邊是MST。 [fitness function] 是MST的權重,數值越大越好。
用人眼觀察,很直覺的就能在小區域找出最佳的子樹,那便是一套「特定組合」。
範例:Travelling Salesman Problem
有N個城市。 [初始化] 答案被迫設計成0到N-1的數字,代表一條路徑。 [fitness function] 是路徑的權重,數值越小越好。 [crossover] 哈哈哈,很難搞。 [mutation] 可以有好幾種方式: 1. 隨便交換兩個數字。 2. 隨便找一段數字,顛倒前後順序。 3. 隨便拿出一個數字,隨便插入到其他地方。
旅行推銷員問題也具有「特定組合」的性質,只不過它的答案並不適合分裂再結合,最好不要堅持使用基因演算法,自尋煩惱。
Ant Colony Optimization(螞蟻演算法)
這是一個隨機亂湊答案的方法,靈感來自於螞蟻覓食的過程,螞蟻發現食物後會沿途留下強烈的費洛蒙,驅使其他螞蟻沿著路線前進,不斷留下更多費洛蒙,吸引更多螞蟻;也有螞蟻會另闢新路,而找到更簡潔的路線。螞蟻演算法把答案比擬成螞蟻覓食的路徑,把好的答案不斷做局部調整,成為更好的答案。
螞蟻演算法有各式各樣的版本,這裡介紹其中一個經典版本Ant Colony System,主要是計算一條最短的覓食路徑。附帶一提,這與螞蟻的真實行為有很大出入。
1. [初始化] 一開始先建立一個地圖,地圖上有P個地點。 有一些地點是食物,有一個地點是蟻窩。 地點與地點間皆有道路, 所有道路的費洛蒙都預設為1.0。 2. [state transition rule] 一隻螞蟻從蟻窩出發。 每次踏上一個地點,螞蟻有兩種選擇, ◎探索:隨便走一條路。機率為q。 ◎追蹤:走費洛蒙最強的道路。機率為1-q。 q是螞蟻選擇探索的機率,自行設定在0到1之間。 為了不讓螞蟻打轉繞圈,所以會讓螞蟻避開去過的地點。 在探索和追蹤前,要先過濾掉去過的地點。 所有食物都找到後就直接回蟻窩, 沒找到所有食物就不准回蟻窩。 總之就是要刻意弄出一條「嘗遍天下美食」的路線。 3. [local updating rule] 螞蟻回巢之後, 剛剛走過的每一條道路,費洛蒙都會加強, 道路的費洛蒙會變成下列兩者相加後的數值, ◎自然蒸發,餘下:原本費洛蒙值,乘上1-ρ。 ◎螞蟻路過,添加:道路起點所連接的道路當中,最大的那個費洛蒙值,乘上p。 ρ是費洛蒙蒸發的程度,自行設定在0到1之間。 通常會把參數設的很好,讓相加之後,費洛蒙會比原本增加一些,而不是變更少。 4. 有N隻螞蟻,依序做2. 3.這件事。 5. [global updating rule] N隻螞蟻回巢之後, 地圖上所有道路的費洛蒙都會蒸發一定比例。 ◎自然蒸發,餘下:原本費洛蒙值,乘上1-α。 而目前的最佳路線,在蒸發之後,竟會神奇地額外增加一些費洛蒙。 ◎最佳路線,添加:目前最佳解的數值,倒數後,再乘上α。 α是費洛蒙蒸發的程度,自行設定在0到1之間。 6. 2. 3. 4. 5.,重複執行R次。 途中不斷紀錄最好的路線。
1. 初始化地圖與費洛蒙。 2. 以下動作執行R次: 1. N隻螞蟻依序找路線,不是同時找路線: 1. state transition rule,一隻螞蟻找一條路線。 此路線是由蟻窩出發,經過所有食物各一次,然後回到蟻窩。 2. 記錄目前最佳路線。 3. local updating rule,更新路線費洛蒙。 2. global updating rule,更新所有道路費洛蒙。
螞蟻數量足夠豐富,則可以避免進入區域極值。隨機探索可以增加答案豐富性,跳脫區域極值。
Flash小遊戲:http://www.newgrounds.com/portal/view/378646。這個遊戲的螞蟻演算法會讓螞蟻不斷繞圈,各位可以利用這項弱點來攻略遊戲。
範例:Travelling Salesman Problem
有N個城市。 [初始化] 答案設計成0到N-1的數字,代表一條路徑。 地圖上每個地點都有食物。 地圖上可以任意挑一地點作為蟻窩。
當答案具有「特定排列」的性質,就適合採用螞蟻演算法。