啓發式算法(Heuristic Algorithm)是一種基於直觀或經驗的構造的算法,對具體的優化問題能在可接受的計算成本(計算時間、佔用空間等)內,給出一個近似最優解,這個近似解與真實最優解的偏離程度通常不能被預計。
因爲 NP 問題通常的經典算法求解效率太低甚至沒法求解,從而促使了啓發式算法的誕生。一個精心設計的啓發式算法,一般能在較短期內獲得問題的近似最優解,對於 NP 問題也能夠在多項式時間內獲得一個較優解。算法
啓發式算法不是一種確切的算法,而是提供了一個尋找最優解的框架。從開頭的定義能夠看出,啓發式算法須要根據實際應用場景,創建一系列切合實際問題的啓發式規則。同時啓發式算法存在如下問題:編程
所以值得注意的是,啓發式算法不能保證獲得最優解,效果相對不穩定,它的效果依賴於實際問題和設計者的經驗。但瑕不掩瑜,面對複雜問題啓發式算法能以相對簡單的方式進行解決,而且它容易設計程序。數組
大部分啓發式算法是經過生物現象或物理現象演變而來,咱們據此將它分爲如下類別:性能優化
接下來挑選以上類別中較爲經典的啓發式算法進行介紹。網絡
在熱力學上,退火(annealing)現象指物體逐漸降溫的物理現象。溫度越低,物體的能量狀態越低;當能量狀態足夠低後,液體開始冷凝與結晶,在結晶狀態時,系統的能量狀態最低,也最穩定。框架
物理退火過程由三部分組成:函數
加溫過程:目的是加強粒子的熱運動,使其偏離平衡位置。性能
等溫過程:對於與周圍環境交換熱量而溫度不變的封閉系統,系統狀態的自發變化老是朝自由能減小的方向進行。優化
冷卻過程:使粒子熱運動減弱,系統能量降低,達到能量最低態。編碼
模擬退火法是一種通用的啓發式算法,咱們把問題搜索空間內每一個解都想象成物體內的分子,對於搜索空間內的每一個解,如同物體分子同樣帶有「能量」,用於表示這個解對問題的合適程度。算法以搜索空間中的一個任意解做爲初始解,每一步隨機產生一個新解,並計算從當前解到達新解的機率。其中,加溫過程對應算法的初始溫度,等溫過程對應算法的 Metropolis 抽樣過程,冷卻過程對應控制參數的降低。
Metropolis 準則是指以必定的機率接受惡化解,從而使算法具備逃脫局部極值和避免過早收斂的全局優化能力。
能量的變化就是目標函數值的變化,能量的最低態就是最優解。其中 Metropolis 準則是 SA 算法收斂於全局最優解的關鍵所在,當搜索到很差的解,Metropolis 準則會以必定機率接受這個很差的解,使算法具有跳出局部最優的能力。假定當前可行解爲 x,迭代更新後的解爲 x_new,那麼對應的「能量差」定義爲:
Δf = f ( x_new ) − f ( x )
以必定機率接受很差的解,則該機率爲:
p (Δf) = exp( -Δf/kT )
溫度 T 是 Metropolis 準則的影響因素之一:在高溫下,可接受與當前狀態能量差較大的新解;在低溫下,只接受與當前狀態能量差較小的新解。
模擬退火算法的具體流程以下圖所示:
模擬退火算法的應用普遍,能夠高效地求解 NP 徹底問題,如旅行商問題、最大截問題、0-1 揹包問題等。可是其參數比較難控制,不能保證一次就收斂到最優值,大部分狀況下仍是會陷入局部最優值,主要受三個關鍵參數影響:
初始溫度值設置
初始溫度值的設置是影響模擬退火算法全局搜索性能的重要因素。初始溫度高,則搜索到全局最優解的可能性大,但所以要花費大量的計算時間;反之,則可節約計算時間,但全局搜索性能可能受到影響。
退火速度問題,即每一個溫度值的迭代次數
模擬退火算法的全局搜索性能也與退火速度密切相關。通常來講,同一溫度下的「充分」搜索是至關必要的,但搜索越「充分」,計算開銷天然越大。
溫度管理問題
溫度管理問題也是影響模擬退火算法全局搜索性能的重要因素。實際應用場景下,由於須要考慮計算開銷問題,常採用溫度衰減的方式進行降溫:
T=α×T.α∈(0,1)
爲了保證較大的搜索空間,α 通常取接近於 1 的值,如 0.9五、0.9。
🌰舉個例子:買菜問題
買菜問題是一個典型的組合優化問題:假設給定一組包含n個蔬菜的集合,其中每一個蔬菜都有自身的體積 w_i 和價格 v_i,買菜阿姨有一個容量爲C的購物籃,買菜阿姨的任務是在不超過購物籃容量的前提下,購買一組價格最高的蔬菜放入籃中。
給定 n 個蔬菜的集合{x_1, x_2, ..., x_n},x_i∈{0, 1},每一個蔬菜 x_i 的具備屬性{(w_i, v_i)},購物籃容量爲正整數 C,即求解以下優化問題:
假設蔬菜的體積集合 size={2,2,3,4},蔬菜的價格集合 value={5,6,7,8},阿姨的購物籃容量爲 7,通常設置初始方案爲 S0 = {0,0,0,0}。既然是最大化蔬菜的總價格,那麼目標函數和限制函數就是:
若阿姨每次蒙着眼睛隨機挑選一個蔬菜 i 則有三種新解產生方式:
1.若是蔬菜 i 不在購物籃中,就直接把它丟進籃子裏;
2.若是蔬菜 i 不在購物籃中,可是籃子滿了,那麼蒙着眼睛從籃子裏取出蔬菜 j,把位置讓給蔬菜 i;
3.若是蔬菜 i 已經在購物籃中,那麼先把蔬菜 i 取出來,而後蒙着眼睛挑一個蔬菜j並放進籃子裏。
根據三種新解產生的狀況,那麼購物籃的價值差、體積差都會出現三種狀況。
購物籃的價值差:
購物籃的體積差:
因爲買菜問題是有約束的最優化問題,因此 Metropolis 準則須要作一些相應的調整:
而後,根據前面所述的計算規則,設置好初始溫度 T、溫度衰減係數 α、每一個溫度的迭代次數 K,會得到一個最優買菜方案:S = {1,1,1,0}。即 Totalsize=7,Totalvalue=18。
遺傳算法借鑑了達爾文的進化論和孟德爾的遺傳學說,將待解決的問題模擬成一個生物進化的過程,經過複製、交叉、突變等操做產生下一代的解,並逐步淘汰掉適應度函數值低的解,增長適應度函數值高的解。這樣進化 N 代後就頗有可能會進化出適應度函數值很高的個體。
先看一些遺傳學的相關生物概念:
種羣:生物的進化以羣體的形式進行,這樣的一個羣體稱爲種羣;
個體:組成種羣的單個生物;
基因:一個遺傳因子;
染色體:包含一組的基因;
生存競爭,適者生存:對環境適應度高的個體參與繁殖的機會比較多,後代就會愈來愈多;適應度低的個體參與繁殖的機會比較少,後代就會愈來愈少;
遺傳與變異:新個體會遺傳父母雙方各一部分的基因,同時有必定的機率發生基因變異。
而對應的遺傳算法也有如下基本組成:
遺傳算法經過某種編碼機制把對象抽象成按必定順序進行排列的字符串,編碼主要分爲如下種類:
最簡單的一種編碼方式是二進制編碼,既是把問題的解,編碼成二進制數組的形式;
互換編碼通常用於解決排序問題:好比 TSP 問題,用一串基因編碼表示遍歷的城市順序;
樹形編碼用於遺傳規劃中的演化編程;
值編碼用於解決複雜的數值問題。
編碼主要遵循三個原則:
1.完備性:問題空間的全部解都能由編碼規則進行表示;
2.健全性:任何一個基因都對應一個可能解;
3.非冗餘性:問題空間和編碼規則造成的表達空間一一對應。
遺傳算法對一個個體(解)的質量評估,是用適應度函數值來度量的,適應度函數的值越大,個體的質量越好。適應度函數是遺傳算法進化過程的驅動力,也是進行天然選擇的惟一標準,須要根據求解的具體問題進行設計。
一般來講,適應度函數與目標函數是正相關的,可對目標函數做一些變形來獲得適應度函數。
遺傳算子包括選擇算子、交叉算子和變異算子。
選擇運算
選擇運算是指對個體進行優勝劣汰操做。適應度高的個體被遺傳到下一代羣體中的機率大;適應度低的個體,被遺傳到下一代羣體中的機率小。
基本遺傳算法(SGA)中選擇算子採用輪盤賭的選擇方法,其基本思想是每一個個體被選中的機率與其適應度函數值大小成正比。
輪盤賭選擇方法的實現步驟以下所示:
🌰舉個例子
假設有染色體 S1 = 3(00011)、S2 = 10(01010)、S3 = 17(10001)、S4 = 22(10110),根據適應度函數 F(S) = S^2 -2 可得出各個染色體的適應度:
F(S1) = 3^2 -2 = 7
F(S2) = 10^2 -2 = 98
F(S3) = 17^2 -2 = 287
F(S4) = 22^2 -2 = 482
假設有 4 個隨機數 r1=0.061,r2=0.242,r3=0.402,r4=0.728;再結合各個染色體的適應度可得出:
交叉運算
交叉運算是指對兩個相互配對的染色體依據交叉機率 Pc 按某種方式相互交換其部分基因,從而造成兩個新的個體。交叉運算是遺傳算法區別於其餘進化算法的重要特徵,它在遺傳算法中起關鍵做用,是產生新個體的主要方法。基本遺傳算法(SGA)中交叉算子採用單點交叉算子,除此以外,還有雙點交叉和基於「與/或」的交叉。
單點交叉(二進制編碼)是指選擇一個交叉點,子代在交叉點前面的基因從一個父代基因中得到,後面的部分從另外一個父代基因得到。
雙點交叉(二進制編碼)是選擇兩個交叉點,子代基因在兩個交叉點之間的部分從一個父代基因中得到,剩下的部分從另一個父代基因中得到。
基於「與/或」的交叉(二進制編碼)則是對兩個父代基因,進行按位「與」/「或」處理,獲得子代基因。
變異運算
變異運算是指依據變異機率 Pm 改變個體編碼串中的某些基因值,從而造成新的個體。變異運算是產生新個體的輔助方法,決定遺傳算法的局部搜索能力,保持種羣多樣性。
交叉運算和變異運算的相互配合,共同完成對搜索空間的全局搜索和局部搜索。基本遺傳算法(SGA)中變異算子採用基本位變異算子。
基本位變異算子是指對個體編碼串隨機指定的一位或者多位基因,進行簡單翻牌操做,即 1 變 0、0 變 1。是否接受變異,由變異機率決定。
運行參數包含種羣規模、交叉率、變異率、最大進化代數等。
種羣規模指的是羣體中個體的個數,比較大的種羣的規模並不能優化遺傳算法的結果,種羣的大小推薦使用 15-30。交叉率通常來講應該比較大,通常使用 85%-95%。變異率通常來講應該比較小,通常使用 0.5%-1%。
如上圖所示,遺傳算法基本流程是:
1.初始化進化代數計數器(t=0),T 是最大進化代數,而後隨機生成 M 個個體做爲初始羣體 P(t);
2.進行個體評價:計算 P(t)中各個個體的適應度值;
3.進行選擇運算:將選擇算子做用於羣體;
4.進行交叉運算:將交叉算子做用於羣體;
5.進行變異運算:將變異算子做用於羣體;
6.經過步驟 2-5,獲得下一代羣體 P(t+1);
7.終止條件判斷進化代數是否達到最大值:若 t≦T,則 t←t+1,轉到步驟2;若 t>T,終止,輸出解。
遺傳算法有兩種性能優化方案:災變與精英主義。
遺傳算法的局部搜索能力較強,但很容易陷入局部最優的陷阱,要跳出局部極值就必須殺死當前的優秀個體,從而讓遠離當前極值的點有充分的進化餘地,這就是災變的思想。當利用交叉和變異產生子代時,極可能在某個中間步驟丟失獲得的最優解,在每次產生子代時,首先把當前最優解複製到子代中,防止進化過程當中產生的最優解被交叉和變異破壞,這就是精英主義的思想。
災變與精英主義,這二者間存在必定程度的矛盾:災變機制是把產生的優秀個體殺掉;精英主義機制則是把優秀個體保留到子代。但其實二者實際上是能夠共存的,在每一代進行交叉運算前,都把最優秀的個體複製到下一代,但當接下去連續 n 代都沒有出現更優秀個體時,多是遺傳算法陷入局部最優,這個時候就能夠採用災變機制,幫助算法跳出局部最優。根據具體場景構建遺傳算法時,能夠有選擇性的採用災變和精英主義。
🌰再回到上文的例子:買菜問題
買菜問題是一個典型的組合優化問題:假設給定一組包含n個蔬菜的集合,其中每一個蔬菜都有自身的體積 w_i 和價格 v_i,買菜阿姨有一個容量爲C的購物籃,買菜阿姨的任務是在不超過購物籃容量的前提下,購買一組價格最高的蔬菜放入籃中。
給定 n 個蔬菜的集合{x_1, x_2, ..., x_n},x_i∈{0, 1},每一個蔬菜 x_i 的具備屬性{(w_i, v_i)},購物籃容量爲正整數 C,即求解以下優化問題:
阿姨買菜問題,自然符合二進制編碼,將待求解的 n 個蔬菜的集合{x_1, x_2, ..., x_n},表示爲長度爲 n 的二進制染色體。
假設蔬菜的體積集合 size={2,2,3,4},蔬菜的價格集合 value={5,6,7,8},阿姨的購物籃容量爲 10,隨機生成以下種羣(n=4,種羣規模爲4): S1 = 0001,S2 = 0101,S3 = 1000,S4 = 1111。
既然是最大化蔬菜的總價格,那麼首先計算個體的總價格,而後計算個體的整體積:
因爲容量上限的限制,那麼適應度的計算須要考慮這個因素,所以加入懲罰項:
其中,參數 α 是懲罰係數,α > 1.0,數值越大,懲罰力度越大。
假設懲罰係數取 10,那麼每一個個體的適應度爲:
S1 = 0001,TotalSize=4,TotalValue=8,Fitness=8;
S2 = 0101,TotalSize=6,TotalValue=14,Fitness=14;
S3 = 1000,TotalSize=2,TotalValue=5,Fitness=5;
S4 = 1111,TotalSize=11,TotalValue=26,Fitness=16。
假設生成 4 個隨機數,r1=0.22,r2=0.57,r3=0.41,r4=0.79。
那麼,下一代的種羣就是 T1 = 0101,T2 = 1000,T3 = 0101,T4 = 1111。接着對通過選擇後的種羣進行隨機配對,而後根據交叉率隨機設置交叉點,採用單點交叉的方式,互換已配對的染色體的部分基因。
假設 T1 和 T4 配對,交叉點是第二位;T2 和 T3 配對,交叉點在第三位,那麼交叉後的新種羣爲:
U1 = 0111,TotalSize=9,TotalValue=21,Fitness=21;
U2 = 1001,TotalSize=6,TotalValue=13,Fitness=13;
U3 = 0100,TotalSize=2,TotalValue=6,Fitness=6;
U4 = 1101,TotalSize=8,TotalValue=19,Fitness=19。
再次假設 U3 在第3、四位上發生了變異,那麼:
U1 = 0111,TotalSize=9,TotalValue=21,Fitness=21;
U2 =1001,TotalSize=6,TotalValue=13,Fitness=13;
U3 = 0111,TotalSize=9,TotalValue=21,Fitness=21;
U4 = 1101,TotalSize=8,TotalValue=19,Fitness=19。
至此,阿姨已經找到了最佳的買菜方案 U1和U3。
🌰再舉一個例子:旅遊問題(若是你懂了,可快速滑過~)
阿姨從家裏出發,遊玩全部祖國的著名城市以後回家。這又是一個經典的組合優化問題,此次的任務是選出一條路線,讓此次旅遊的總行程最短。
如上表所示,給每個城市賦予一個數字編碼,那麼一條路線(即一條染色體)用包含 n 個城市編碼的數組來表示,數組元素的順序表示旅行的順序,並且數組中的元素不會重複,由於一個城市只去玩一次。
假設:S1 = {17, 3, 21, …, 30},表示旅行的順序爲:鄭州 -> 上海 -> 福州 -> … -> 成都。
阿姨的此次旅行總行程越短越好,那麼取一條路線的總行程的倒數,做爲適應度函數。假設東經爲 x,北緯爲 y,那麼一個城市的座標即爲(x, y),那麼一條路線 S_i = {(x_1, y_1), (x_2, y_2), ..., (x_n, y_n)},i∈[0, m],因此:
這裏一樣採用輪盤賭的選擇方法。接着對路線隨機配對,根據交叉率隨機挑選出交叉點。對於路徑序列,不能利用單點交叉法簡單的互換父母染色體的部分基因,由於這樣容易形成子代染色體中出現重複的城市編碼。從父親中得到交叉點的城市編碼,保持這些編碼在父親中是順序並填充到子代的頭部,剩餘的城市編碼從母親中獲取並填滿子代。好比:
父親:{1,2,3,4,5,6,…}母親:{31,2,3,11,1,5,…}
子代:{1,3,4,5,6,…,31,2,11,…}
這裏採用的變異方式是根據變異率隨機挑選一條路線中的某兩個城市編碼,而後交換這兩個編碼的位置。好比 S = {1,3,4,5,6,…,31,2,11,…},那麼,變異後 T = {1,11,4,5,6,…,31,2,3,…}。
至此,阿姨就能夠根據這個遺傳算法尋找總行程最短的旅遊路線啦~
進化策略(Evolution Strategy)是一種求解參數優化問題的方法,模仿生物進化原理,假設不論基因發生何種變化,產生的結果(性狀)總遵循零均值、某一方差的高斯分佈。進化策略特色以下:
進化策略可分紅兩類,(μ+λ)-ES 和 (μ,λ)-ES。
(μ+λ)-ES
每次迭代產生 λ 個新解,經過和父代進行比較,將較好的 μ 個成爲下一次迭代的父代,其餘的直接捨去。
這種方式引入種羣的思想,易於並行化,但容易陷入局部最優陷阱,主要用在多目標優化。
(μ,λ)-ES
每次迭代產生 λ 個新解(λ>μ),其中較好的 μ 個成爲下一次迭代的父代,其餘的直接捨去。這種方式全部解都只存活一代,可較好避免陷入局部最優。
(μ+λ) 選擇能夠保證最優個體存活,使羣體的進化過程呈單調上升趨勢,可是 (μ+λ) 選擇保留舊個體,容易帶來局部最優問題。(μ, λ)-ES 一般優於 (μ+λ)-ES,是當前進化策略使用的主流。
進化策略的 DNA 再也不是用二進制進行表示, 而是用實數來代替,能夠解決不少由實數組成的實際問題。進化策略產生子代的基因交叉,和遺傳算法相似,但是基因變異應該怎麼操做呢?因爲基因是實數,因此沒法像遺傳算法那樣採用簡單的翻牌作法。
進化策略中的基因變異由變異強度來決定,正態分佈在這裏發揮了關鍵做用。
咱們將父代遺傳下來的基因值看作是正態分佈的平均值,接着在這個平均值上附加一個標準差,這個時候便肯定了一個正態分佈,而後使用該正態分佈產生一個數。好比在這個 8.8 位置上的變異強度爲 2.5, 按照 2.5 的標準差和 8.8 的均值肯定一個正太分佈,而後產生一個新的值 8.7。
子代基因每一位上的值都會通過不一樣的狀態分佈進行變異,這樣就會產生全新的子代 DNA。 因此,變異強度也能夠被當成一組遺傳信息從父代的 DNA 中遺傳下來,並且變異強度自己也能進行變異。
進化策略的關鍵步驟在於:交叉、變異、選擇、變異程度的變化。
和遺傳算法同樣,交叉就是交換兩個個體的基因,主要有三種方式:
1.離散重組:先隨機選擇兩個父代個體,而後將其份量進行隨機交換,構成子代新個體的各個份量,從而得出新個體。
2.中值重組:這種重組方式也是先隨機選擇兩個父代個體,而後將父代個體各份量的平均值做爲子代新個體的份量,構成新個體。
3.混雜重組:這種重組方式的特色在於父代個體的選擇上。混雜重組時先隨機選擇一個固定的父代個體,而後針對子代個體每一個份量再從父代羣體中隨機選擇第二個父代個體。也就是說,第二個父代個體是常常變化的。至於父代兩個個體的組合方式,既能夠採用離散方式,也能夠來用中值方式。
變異比較簡單,就是在每一個份量上面加上零均值、某一方差的高斯分佈的變化產生新的個體。這個某一方差就是變異程度,變異程度是會變化的,算法開始的時候變異程度比較大,當接近收斂後,變異程度會開始減少。
接着經過一個比較具體的進化策略案例來了解,以下圖所示是 (1 + 1)-ES 中的變異程度公式。
變異程度的控制這裏採用 1/5 成功規則。在還沒收斂的時候增大變異程度,快要收斂的時候就減少變異程度。斷定是否收斂的條件是,若是隻有 1/5 的變異比原始父代好,那麼就是快收斂了;若是有一半的變異比原始父代好, 那麼就是還沒收斂。