A. php的memcached分布式hash演算法,如何解決分布不均crc32這個演算法沒辦法把key值均勻的分布出去
memcached的總結和分布式一致性hash
當前很多大型的web系統為了減輕資料庫伺服器負載,會採用memchached作為緩存系統以提高響應速度。
目錄: (http://hounwang.com/lesson.html)
memchached簡介
hash
取模
一致性hash
虛擬節點
源碼解析
參考資料
1. memchached簡介
memcached是一個開源的高性能分布式內存對象緩存系統。
其實思想還是比較簡單的,實現包括server端(memcached開源項目一般只單指server端)和client端兩部分:
server端本質是一個in-memory key-value store,通過在內存中維護一個大的hashmap用來存儲小塊的任意數據,對外通過統一的簡單介面(memcached protocol)來提供操作。
client端是一個library,負責處理memcached protocol的網路通信細節,與memcached server通信,針對各種語言的不同實現分裝了易用的API實現了與不同語言平台的集成。
web系統則通過client庫來使用memcached進行對象緩存。
2. hash
memcached的分布式主要體現在client端,對於server端,僅僅是部署多個memcached server組成集群,每個server獨自維護自己的數據(互相之間沒有任何通信),通過daemon監聽埠等待client端的請求。
而在client端,通過一致的hash演算法,將要存儲的數據分布到某個特定的server上進行存儲,後續讀取查詢使用同樣的hash演算法即可定位。
client端可以採用各種hash演算法來定位server:
取模
最簡單的hash演算法
targetServer = serverList[hash(key) % serverList.size]
直接用key的hash值(計算key的hash值的方法可以自由選擇,比如演算法CRC32、MD5,甚至本地hash系統,如java的hashcode)模上server總數來定位目標server。這種演算法不僅簡單,而且具有不錯的隨機分布特性。
但是問題也很明顯,server總數不能輕易變化。因為如果增加/減少memcached server的數量,對原先存儲的所有key的後續查詢都將定位到別的server上,導致所有的cache都不能被命中而失效。
一致性hash
為了解決這個問題,需要採用一致性hash演算法(consistent hash)
相對於取模的演算法,一致性hash演算法除了計算key的hash值外,還會計算每個server對應的hash值,然後將這些hash值映射到一個有限的值域上(比如0~2^32)。通過尋找hash值大於hash(key)的最小server作為存儲該key數據的目標server。如果找不到,則直接把具有最小hash值的server作為目標server。
為了方便理解,可以把這個有限值域理解成一個環,值順時針遞增。
如上圖所示,集群中一共有5個memcached server,已通過server的hash值分布到環中。
如果現在有一個寫入cache的請求,首先計算x=hash(key),映射到環中,然後從x順時針查找,把找到的第一個server作為目標server來存儲cache,如果超過了2^32仍然找不到,則命中第一個server。比如x的值介於A~B之間,那麼命中的server節點應該是B節點
可以看到,通過這種演算法,對於同一個key,存儲和後續的查詢都會定位到同一個memcached server上。
那麼它是怎麼解決增/刪server導致的cache不能命中的問題呢?
假設,現在增加一個server F,如下圖
此時,cache不能命中的問題仍然存在,但是只存在於B~F之間的位置(由C變成了F),其他位置(包括F~C)的cache的命中不受影響(刪除server的情況類似)。盡管仍然有cache不能命中的存在,但是相對於取模的方式已經大幅減少了不能命中的cache數量。
虛擬節點
但是,這種演算法相對於取模方式也有一個缺陷:當server數量很少時,很可能他們在環中的分布不是特別均勻,進而導致cache不能均勻分布到所有的server上。
如圖,一共有3台server – 1,2,4。命中4的幾率遠遠高於1和2。
為解決這個問題,需要使用虛擬節點的思想:為每個物理節點(server)在環上分配100~200個點,這樣環上的節點較多,就能抑制分布不均勻。
當為cache定位目標server時,如果定位到虛擬節點上,就表示cache真正的存儲位置是在該虛擬節點代表的實際物理server上。
另外,如果每個實際server的負載能力不同,可以賦予不同的權重,根據權重分配不同數量的虛擬節點。
// 採用有序map來模擬環
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//用MD5來計算key和server的hash值
// 計算總權重
if ( this.totalWeight for ( int i = 0; i < this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 為每個server分配虛擬節點
for ( int i = 0; i < servers.length; i++ ) {
// 計算當前server的權重
int thisWeight = 1;
if ( this.weights != null && this.weights[i] != null )
thisWeight = this.weights[i];
// factor用來控制每個server分配的虛擬節點數量
// 權重都相同時,factor=40
// 權重不同時,factor=40*server總數*該server權重所佔的百分比
// 總的來說,權重越大,factor越大,可以分配越多的虛擬節點
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j < factor; j++ ) {
// 每個server有factor個hash值
// 使用server的域名或IP加上編號來計算hash值
// 比如server - "172.45.155.25:11111"就有factor個數據用來生成hash值:
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// 每個hash值生成4個虛擬節點
for ( int h = 0 ; h < 4; h++ ) {
Long k =
((long)(d[3+h*4]&0xFF) << 24)
| ((long)(d[2+h*4]&0xFF) << 16)
| ((long)(d[1+h*4]&0xFF) << 8 )
| ((long)(d[0+h*4]&0xFF));
// 在環上保存節點
consistentBuckets.put( k, servers[i] );
}
}
// 每個server一共分配4*factor個虛擬節點
}
// 採用有序map來模擬環
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//用MD5來計算key和server的hash值
// 計算總權重
if ( this.totalWeight for ( int i = 0; i < this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 為每個server分配虛擬節點
for ( int i = 0; i < servers.length; i++ ) {
// 計算當前server的權重
int thisWeight = 1;
if ( this.weights != null && this.weights[i] != null )
thisWeight = this.weights[i];
// factor用來控制每個server分配的虛擬節點數量
// 權重都相同時,factor=40
// 權重不同時,factor=40*server總數*該server權重所佔的百分比
// 總的來說,權重越大,factor越大,可以分配越多的虛擬節點
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j < factor; j++ ) {
// 每個server有factor個hash值
// 使用server的域名或IP加上編號來計算hash值
// 比如server - "172.45.155.25:11111"就有factor個數據用來生成hash值:
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// 每個hash值生成4個虛擬節點
for ( int h = 0 ; h < 4; h++ ) {
Long k =
((long)(d[3+h*4]&0xFF) << 24)
| ((long)(d[2+h*4]&0xFF) << 16)
| ((long)(d[1+h*4]&0xFF) << 8 )
| ((long)(d[0+h*4]&0xFF));
// 在環上保存節點
consistentBuckets.put( k, servers[i] );
}
}
// 每個server一共分配4*factor個虛擬節點
}
// 用MD5來計算key的hash值
MessageDigest md5 = MD5.get();
md5.reset();
md5.update( key.getBytes() );
byte[] bKey = md5.digest();
// 取MD5值的低32位作為key的hash值
long hv = ((long)(bKey[3]&0xFF) << 24) | ((long)(bKey[2]&0xFF) << 16) | ((long)(bKey[1]&0xFF) << 8 ) | (long)(bKey[0]&0xFF);
// hv的tailMap的第一個虛擬節點對應的即是目標server
SortedMap tmap = this.consistentBuckets.tailMap( hv );
return ( tmap.isEmpty() ) ? this.consistentBuckets.firstKey() : tmap.firstKey();
更多問題到問題求助專區(http://bbs.hounwang.com/)
B. 優化演算法筆記(六)遺傳演算法
遺傳演算法(Genetic Algorithms,GA)是一種模擬自然中生物的遺傳、進化以適應環境的智能演算法。由於其演算法流程簡單,參數較少優化速度較快,效果較好,在圖像處理、函數優化、信號處理、模式識別等領域有著廣泛的應用。
在遺傳演算法(GA)中,每一個待求問題的候選解被抽象成為種群中一個個體的基因。種群中個體基因的好壞由表示個體基因的候選解在待求問題中的所的得值來評判。種群中的個體通過與其他個體交叉產生下一代,每一代中個體均只進行一次交叉。兩個進行交叉的個體有一定幾率交換一個或者多個對應位的基因來產生新的後代。每個後代都有一定的概率發生變異。發生變異的個體的某一位或某幾位基因會變異成其他值。最終將以個體的適應度值為概率選取個體保留至下一代。
遺傳演算法啟發於生物的繁殖與dna的重組,本次的主角選什麼呢?還是根據大家熟悉的孟德爾遺傳規律選豌豆吧,選動物的話又會有人疑車,還是植物比較好,本次的主角就是它了。
遺傳演算法包含三個操作(運算元):交叉,變異和選擇操作。下面我們將詳細介紹這三個操作。
大多數生物的遺傳信息都儲存在DNA,一種雙螺旋結構的復雜有機化合物。其含氮鹼基為腺嘌呤、鳥嘌呤、胞嘧啶及胸腺嘧啶。
表格中表示了一個有10個基因的個體,它們每一個基因的值為0或者1。
生物的有性生殖一般伴隨著基因的重組。遺傳演算法中父輩和母輩個體產生子代個體的過程稱為交叉。
表中給出了兩個豌豆的基因,它們均有10個等位基因(即編號相同的基因)。
遺傳演算法的交叉過程會在兩個個體中隨機選擇1位或者n位基因進行交叉,即這兩個個體交換等位基因。
如,A豌豆和B豌豆在第6位基因上進行交叉,則其結果如下
當兩個個體交叉的等位基因相同時,交叉過程也有可能沒有產生新的個體,如交叉A豌豆和B豌豆的第2位基因時,交叉操作並沒有產生新的基因。
一般的會給群體設定一個交叉率,crossRate,表示會在群體中選取一定比例的個體進行交叉,交叉率相對較大,一般取值為0.8。
基因的變異是生物進化的一個主要因素。
遺傳演算法中變異操作相對簡單,只需要將一個隨機位基因的值修改就行了,因為其值只為0或1,那麼當基因為0時,變異操作會將其值設為1,當基因值為1時,變異操作會將其值設為0。
上圖表示了A豌豆第3位基因變異後的基因編碼。
與交叉率相似,變異操作也有變異率,alterRate,但是變異率會遠低於交叉率,否則會產生大量的隨機基因。一般變異率為0.05。
選擇操作是遺傳演算法中的一個關鍵操作,它的主要作用就是根據一定的策略隨機選擇個體保留至下一代。適應度越優的個體被保留至下一代的概率越大。
實現上,我們經常使用「輪盤賭」來隨機選擇保留下哪個個體。
假設有4個豌豆A、B、C、D,它們的適應度值如下:
適應度值越大越好,則它們組成的輪盤如下圖:
但由於輪盤賭選擇是一個隨機選擇過程,A、B、C、D進行輪盤賭選擇後產生的下一代也有可能出現A、A、A、A的情況,即雖然有些個體的適應度值不好,但是運氣不錯,也被選擇留到了下一代。
遺產演算法的三個主要操作介紹完了,下面我們來看看遺傳演算法的總體流程:
前面我們說了遺傳演算法的流程及各個操作,那麼對於實際的問題我們應該如何將其編碼為基因呢?
對於計算機來所所有的數據都使用二進制數據進行存放,如float類型和double類型的數據。
float類型的數據將保存為32位的二進制數據:1bit(符號位) 8bits(指數位) 23bits(尾數位)
如-1.234567f,表示為二進制位
Double類型的數據將保存為64位的二進制數據:1bit(符號位) 11bits(指數位) 53bits(尾數位)
如-1.234567d,表示為二進制為
可以看出同樣的數值不同的精度在計算機中存儲的內容也不相同。之前的適應度函數 ,由於有兩個double類型的參數,故其進行遺傳演算法基因編碼時,將有128位基因。
雖然基因數較多,但好在每個基因都是0或者1,交叉及變異操作非常簡單。
相比二進制編碼,十進制編碼的基因長度更短,適應度函數 有兩個輸入參數,那麼一個個體就有2個基因,但其交叉、變異操作相對復雜。
交叉操作
方案1:將一個基因作為一個整體,交換兩個個體的等位基因。
交換前
交換第1位基因後
方案2:將兩個個體的等位基因作為一個整體,使其和不變,但是值隨機
交換前
交換第1位基因後
假設A、B豌豆的第一位基因的和為40,即 ,第一位基因的取值范圍為0-30,那麼A、B豌豆的第一位基因的取值范圍為[10,30],即 為[0,30]的隨機數, 。
變異操作,將隨機的一位基因設置為該基因取值范圍內的隨機數即可。
這個過程說起來簡單但其實現並不容易。
我們要將它們的值映射到一個軸上才能進行隨機選擇,畢竟我們無法去繪制一個輪盤來模擬這個過程
如圖,將ABCD根據其值按順序排列,取[0,10]內的隨機數r,若r在[0,1]內則選擇A,在(1,3]內則選擇B,在(3,6]內則選擇C,在(6,10]則選擇D。
當然這仍然會有問題,即當D>>A、B、C時,假如它們的值分布如下
那麼顯然,選D的概率明顯大於其他,根據輪盤賭的選擇,下一代極有可能全是D的後代有沒有辦法均衡一下呢?
首先我想到了一個函數,
不要問我為什麼我不知道什麼是神經什麼網路的,什麼softmax、cnn統統沒聽說過。
這樣一來,它們之間的差距沒有之前那麼大了,只要個體適應度值在均值以上那麼它被保留至下一代的概率會相對較大,當然這樣縮小了個體之間的差距,對真正優秀的個體來說不太公平,相對應,我們可以在每次選擇過程中保留當前的最優個體到下一代,不用參與輪盤賭這個殘酷的淘汰過程。
最令人高興的環節到了,又可以愉快的湊字數了。
由於遺傳演算法的收斂速度實在是太慢,區區50代,幾乎得不到好的結果,so我們把它的最大迭代次數放寬到200代。
使用二進制編碼來進行求解
參數如下:
求解過程如上圖,可以看出基因收斂的很快,在接近20代時就圖中就只剩一個點了,之後的點大概是根據變異操作產生。看一下最後的結果。
可以看出最好的結果已經得到了最優解,但是10次實驗的最差值和平均值都差的令人發指。為什麼會這樣呢?
問題出在二進制編碼上,由於double類型的編碼有11位指數位和52位小數位,這會導致交叉、變異操作選到指數位和小數位的概率不均衡,在小數位上的修改對結果的影響太小而對指數為的修改對結果的影響太大,
如-1.234567d,表示為二進制為
對指數為第5位進行變異操作後的結果為-2.8744502924382686E-10,而對小數位第5為進行變異操作後的結果為-1.218942。可以看出這兩部分對數值結果的影響太不均衡,得出較好的結果時大概率是指數位與解非常相近,否則很難得出好的結果,就像上面的最差值和均值一樣。
所以使用上面的二進制編碼不是一個好的基因編碼方式,因此在下面的實驗中,將使用十進制來進行試驗。
使用:十進制編碼來進行求解
參數如下:
我們可以看到直到40代時,所有的個體才收束到一點,但隨後仍不斷的新的個體出現。我們發現再後面的新粒子總是在同一水平線或者豎直線上,因為交叉操作直接交換了兩個個體的基因,那麼他們會相互交換x坐標或者y坐標,導致新個體看起來像在一條直線上。
我們來看看這次的結果。
這次最優值沒有得到最優解,但是最差值沒有二進制那麼差,雖然也不容樂觀。使用交換基因的方式來進行交叉操作的搜索能力不足,加之輪盤賭的選擇會有很大概率選擇最優個體,個體總出現在矩形的邊上。
下面我們先改變輪盤賭的選擇策略,使用上面的sigmod函數方案,並且保留最優個體至下一代。
使用:十進制編碼來進行求解
參數如下:
看圖好像跟之前的沒什麼區別,讓我們們看看最終的結果:
可以看出,最優值沒有什麼變化,但是最差值和平均值有了較大的提升,說明該輪盤賭方案使演算法的魯棒性有了較大的提升。在每次保留最優個體的情況下,對於其他的個體的選擇概率相對平均,sigmod函數使得即使適應度函數值相差不太大的個體被選到的概率相近,增加了基因的多樣性。
使用:十進制編碼來進行求解,改變交叉方案,保持兩個個體等位基因和不變的情況下隨機賦值。
參數如下:
上圖可以看出該方案與之前有明顯的不同,在整個過程中,個體始終遍布整個搜索空間,雖然新產生的個體大多還是集中在一個十字架型的位置上,但其他位置的個體比之前的方案要多。
看看結果,
這次的結果明顯好於之前的所有方案,但仍可以看出,十進制的遺傳演算法的精度不高,只能找到最優解的附近,也有可能是演算法的收斂速度實在太慢,還沒有收斂到最優解。
遺傳演算法的探究到此也告一段落,在研究遺傳演算法時總有一種力不從心的感覺,問題可能在於遺傳演算法只提出了一個大致的核心思想,其他的實現細節都需要自己去思考,而每個人的思維都不一樣,一萬個人能寫出一萬種遺傳演算法,其實不僅是遺傳演算法,後面的很多演算法都是如此。
為什麼沒有對遺傳演算法的參數進行調優,因為遺傳演算法的參數過於簡單,對結果的影響的可解釋性較強,意義明顯,實驗的意義不大。
遺傳演算法由於是模仿了生物的進化過程,因此我感覺它的求解速度非常的慢,而且進化出來的結果不一定是最適應環境的,就像人的闌尾、視網膜結構等,雖然不是最佳的選擇但是也被保留到了今天。生物的進化的隨機性較大,要不是恐龍的滅絕,也不會有人類的統治,要不是人類有兩只手,每隻手有5根手指,也不會產生10進制。
以下指標純屬個人yy,僅供參考
目錄
上一篇 優化演算法筆記(五)粒子群演算法(3)
下一篇 優化演算法筆記(七)差分進化演算法
優化演算法matlab實現(六)遺傳演算法matlab實現
C. 線性方程組的解有哪些規律
D1就是把D中的第1列的數, 換成方程組等號右邊的數。
D2就是把D中的第2列的數, 換成方程組等號右邊的數。
克萊姆法則:是將方程組等式右側的向量,替換到系數矩陣的第幾行,得到新的行列式。
假若有n個未知數,n個方程組成的方程組: 克萊姆法則
a11X1+a12X2+...+a1nXn = b1
a21X1+a22X2+...+a2nXn = b2
an1X1+an2X2+...+annXn = bn
(3)解演算法的分布度擴展閱讀:
一般來說,用克萊姆法則求線性方程組的解時,計算量是比較大的。使用克萊姆法則求線性方程組的解的演算法時間復雜度依賴於矩陣行列式的演算法復雜度O(f(n)),其復雜度為O(n·f(n)),一般沒有計算價值,復雜度太高。. 對具體的數字線性方程組,當未知數較多時往往可用計算機來求解。用計算機求解線性方程組目前已經有了一整套成熟的方法。
D. 優化演算法筆記(二)優化演算法的分類
(以下描述,均不是學術用語,僅供大家快樂的閱讀)
在分類之前,我們先列舉一下常見的優化演算法(不然我們拿什麼分類呢?)。
1遺傳演算法Genetic algorithm
2粒子群優化演算法Particle Swarm Optimization
3差分進化演算法Differential Evolution
4人工蜂群演算法Artificial Bee Colony
5蟻群演算法Ant Colony Optimization
6人工魚群演算法Artificial Fish Swarm Algorithm
7杜鵑搜索演算法Cuckoo Search
8螢火蟲演算法Firefly Algorithm
9灰狼演算法Grey Wolf Optimizer
10鯨魚演算法Whale Optimization Algorithm
11群搜索演算法Group search optimizer
12混合蛙跳演算法Shuffled Frog Leaping Algorithm
13煙花演算法fireworks algorithm
14菌群優化演算法Bacterial Foraging Optimization
以上優化演算法是我所接觸過的演算法,沒接觸過的演算法不能隨便下結論,知之為知之,不知為不知。其實到目前為止優化演算法可能已經有幾百種了,我們不可能也不需要全面的了解所有的演算法,而且優化演算法之間也有較大的共性,深入研究幾個之後再看其他優化演算法上手速度會灰常的快。
優化演算法從提出到現在不過50-60年(遺傳演算法1975年提出),雖種類繁多但大多較為相似,不過這也很正常,比較香蕉和人的基因相似度也有50%-60%。當然演算法之間的相似度要比香蕉和人的相似度更大,畢竟人家都是優化演算法,有著相同的目標,只是實現方式不同。就像條條大路通羅馬,我們可以走去,可以坐汽車去,可以坐火車去,也可以坐飛機去,不管使用何種方式,我們都在去往羅馬的路上,也不會說坐飛機去要比走去更好,交通工具只是一個工具,最終的方案還是要看我們的選擇。
上面列舉了一些常見的演算法,即使你一個都沒見過也沒關系,後面會對它們進行詳細的介紹,但是對後面的分類可能會有些許影響,不過問題不大,就先當總結看了。
再對優化演算法分類之前,先介紹一下演算法的模型,在筆記(一)中繪制了優化演算法的流程,不過那是個較為簡單的模型,此處的模型會更加復雜。上面說了優化演算法有較大的相似性,這些相似性主要體現在演算法的運行流程中。
優化演算法的求解過程可以看做是一個群體的生存過程。
有一群原始人,他們要在野外中尋找食物,一個原始人是這個群體中的最小單元,他們的最終目標是尋找這個環境中最容易獲取食物的位置,即最易存活下來的位置。每個原始人都去獨自尋找食物,他們每個人每天獲取食物的策略只有採集果實、製作陷阱或者守株待兔,即在一天之中他們不會改變他們的位置。在下一天他們會根據自己的策略變更自己的位置。到了某一天他們又聚在了一起,選擇了他們到過的最容易獲取食物的位置定居。
一群原始人=優化演算法中的種群、群體;
一個原始人=優化演算法中的個體;
一個原始人的位置=優化演算法中個體的位置、基因等屬性;
原始人變更位置=優化演算法中總群的更新操作;
該位置獲取食物的難易程度=優化演算法中的適應度函數;
一天=優化演算法中的一個迭代;
這群原始人最終的定居位置=優化演算法所得的解。
優化演算法的流程圖如下:
對優化演算法分類得有個標准,按照不同的標准分類也會得到不一樣的結果。首先說一下我所使用的分類標准(動態更新,有了新的感悟再加):
按由來分類比較好理解,就是該演算法受何種現象啟發而發明,本質是對現象分類。
可以看出演算法根據由來可以大致分為有人類的理論創造而來,向生物學習而來,受物理現象啟發。其中向生物學習而來的演算法最多,其他類別由於舉例有偏差,不是很准確,而且物理現象也經過人類總結,有些與人類現象相交叉,但仍將其獨立出來。
類別分好了,那麼為什麼要這么分類呢?
當然是因為要湊字數啦,啊呸,當然是為了更好的理解學習這些演算法的原理及特點。
向動物生存學習而來的演算法一定是一種行之有效的方法,能夠保證演算法的效率和准確性,因為,如果使用該策略的動物無法存活到我們可以對其進行研究,我們也無法得知其生存策略。(而這也是一種倖存者偏差,我們只能看到行之有效的策略,但並不是我們沒看到的策略都是垃圾,畢竟也發生過小行星撞地球這種小概率毀滅性事件。講個冷笑話開cou心一shu下:一隻小恐龍對他的小夥伴說,好開心,我最喜歡的那顆星星越來越亮了(完)。)但是由於生物的局限性,人們所創造出的演算法也會有局限性:我們所熟知的生物都生存在三維空間,在這些環境中,影響生物生存的條件比較有限,反應到演算法中就是這些演算法在解決較低維度的問題時效果很好,當遇到超高維(維度>500)問題時,結果可能不容樂觀,沒做過實驗,我也不敢亂說。
按更新過程分類相對復雜一點,主要是根據優化演算法流程中更新位置操作的方式來進行分類。更新位置的操作按我的理解可大致分為兩類:1.跟隨最優解;2.不跟隨最優解。
還是上面原始人的例子,每天他有一次去往其他位置狩獵的機會,他們採用何種方式來決定今天自己應該去哪裡呢?
如果他們的策略是「跟隨最優解」,那麼他們選取位置的方式就是按一定的策略向群體已知的最佳狩獵位置(歷史最佳)或者是當前群體中的最佳狩獵位置(今天最佳)靠近,至於是直線跑過去還是蛇皮走位繞過去,這個要看他們群體的策略。當然,他們的目的不是在最佳狩獵位置集合,他們的目的是在過去的途中看是否能發現更加好的狩獵位置,去往已經到過的狩獵地點再次狩獵是沒有意義的,因為每個位置獲取食物的難易程度是固定的。有了目標,大家都會朝著目標前進,總有一日,大家會在謀個位置附近相聚,相聚雖好但不利於後續的覓食容易陷入局部最優。
什麼是局部最優呢?假設在當前環境中有一「桃花源」,擁有上帝視角的我們知道這個地方就是最適合原始人們生存的,但是此地入口隱蔽「山有小口,彷彿若有光」、「初極狹,才通人。」,是一個難以發現的地方。如果沒有任何一個原始人到達了這里,大家向著已知的最優位置靠近時,也難以發現這個「桃源之地」,而當大家越聚越攏之後,「桃源」被發現的可能性越來越低。雖然原始人們得到了他們的解,但這並不是我們所求的「桃源」,他們聚集之後失去了尋求「桃源」的可能,這群原始人便陷入了局部最優。
如果他們的策略是「不跟隨最優解」,那麼他們的策略是什麼呢?我也不知道,這個應該他們自己決定。畢竟「是什麼」比「不是什麼」的范圍要小的多。總之不跟隨最優解時,演算法會有自己特定的步驟來更新個體的位置,有可能是隨機在自己附近找,也有可能是隨機向別人學習。不跟隨最優解時,原始人們應該不會快速聚集到某一處,這樣一來他們的選擇更具多樣性。
按照更新過程對上面的演算法分類結果如下
可以看出上面不跟隨最優解的演算法只有遺傳演算法和差分進化演算法,他們的更新策略是與進化和基因的重組有關。因此這些不跟隨最優解的演算法,他們大多依據進化理論更新位置(基因)我把他們叫做進化演算法,而那些跟隨群體最優解的演算法,他們則大多依賴群體的配合協作,我把這些演算法叫做群智能演算法。
目前我只總結了這兩種,分類方法,如果你有更加優秀的分類方法,我們可以交流一下:
目錄
上一篇 優化演算法筆記(一)優化演算法的介紹
下一篇 優化演算法筆記(三)粒子群演算法(1)