簡介
上次在自話遺傳算法中提到后期會寫兩篇關於粒子群算法和蟻群算法的博文,所以這次給大家帶來的是我對粒子群的一些理解,並附帶一個相當簡單的實例去描述這個算法,我會盡力通俗易懂的把整個算法描述一遍,其實粒子群算法的思想也挺簡單的,希望我不要反而寫復雜了,下面同樣引用百度百科的摘要結束簡介部分。
粒子群優化算法(PSO)是一種進化計算技術(evolutionary computation),1995 年由Eberhart 博士和kennedy 博士提出,源於對鳥群捕食的行為研究 。該算法最初是受到飛鳥集群活動的規律性啟發,進而利用群體智能建立的一個簡化模型。粒子群算法在對動物集群活動行為觀察基礎上,利用群體中的個體對信息的共享使整個群體的運動在問題求解空間中產生從無序到有序的演化過程,從而獲得最優解。
基本思想
正如簡介所描述的那樣,粒子群算法是模擬群體智能所建立起來的一種優化算法,像后面我向大家介紹的蟻群算法也屬於這類算法,粒子群算法可以用鳥類在一個空間內隨機覓食為例,所有的鳥都不知道食物具體在哪里,但是他們知道大概距離多遠,最簡單有效的方法就是搜尋目前離食物最近的鳥的周圍區域。
所以,粒子群算法就是把鳥看成一個個粒子,並且他們擁有位置和速度這兩個屬性,然后根據自身已經找到的離食物最近的解和參考整個共享於整個集群中找到的最近的解去改變自己的飛行方向,最后我們會發現,整個集群大致向同一個地方聚集。而這個地方是離食物最近的區域,條件好的話就會找到食物。這就是粒子群算法,很好理解。
算法描述
所以,我們需要一個pbest來記錄個體搜索到的最優解,用gbest來記錄整個群體在一次迭代中搜索到的最優解。速度和粒子位置的更新公式如下:
v[i] = w * v[i] + c1 * rand() * (pbest[i] - present[i]) + c2 * rand() * (gbest - present[i])
present[i] = present[i] + v[i]
其中v[i]代表第i個粒子的速度,w代表慣性權值,c1和c2表示學習參數,rand()表示在0-1之間的隨機數,pbest[i]代表第i個粒子搜索到的最優值,gbest代表整個集群搜索到的最優值,present[i]代表第i個粒子的當前位置。
我這里打了一個求解y=-x*(x-1) 在[-2,2]上最大值的粒子群算法,選用這個簡單的例子主要是能讓大家清楚的看到效果和粒子的運動方向,也方便理解我想說的一些觀點。代碼如下:

1 /*** 2 * 計算y=-x(x-1)的最大值 3 * 取值范圍x--[-2,2] 4 * @author BreezeDust 5 * 6 */ 7 public class PSOTest { 8 int n=2; //粒子個數,這里為了方便演示,我們只取兩個,觀察其運動方向 9 double[] y; 10 double[] x; 11 double[] v; 12 double c1=2; 13 double c2=2; 14 double pbest[]; 15 double gbest; 16 double vmax=0.1; 17 public void fitnessFunction(){//適應函數 18 for(int i=0;i<n;i++){ 19 y[i]=-1*x[i]*(x[i]-2); 20 } 21 } 22 public void init(){ //初始化 23 x=new double[n]; 24 v=new double[n]; 25 y=new double[n]; 26 pbest=new double[n]; 27 /*** 28 * 本來是應該隨機產生的,為了方便演示,我這里手動隨機落兩個點,分別落在最大值兩邊 29 */ 30 x[0]=-0.5; 31 x[1]=2.6; 32 v[0]=0.01; 33 v[1]=0.02; 34 fitnessFunction(); 35 //初始化當前個體極值,並找到群體極值 36 for(int i=0;i<n;i++){ 37 pbest[i]=y[i]; 38 if(y[i]>gbest) gbest=y[i]; 39 } 40 System.out.println("start gbest:"+gbest); 41 } 42 public double getMAX(double a,double b){ 43 return a>b?a:b; 44 } 45 //粒子群算法 46 public void PSO(int max){ 47 for(int i=0;i<max;i++){ 48 double w=0.4; 49 for(int j=0;j<n;j++){ 50 //更新位置和速度 51 v[j]=w*v[j]+c1*Math.random()*(pbest[j]-x[j])+c2*Math.random()*(gbest-x[j]); 52 if(v[j]>vmax) v[j]=vmax; 53 x[j]+=v[j]; 54 //越界判斷 55 if(x[j]>2) x[j]=2; 56 if(x[j]<-2) x[j]=-2; 57 58 } 59 fitnessFunction(); 60 //更新個體極值和群體極值 61 for(int j=0;j<n;j++){ 62 pbest[j]=getMAX(y[j],pbest[j]); 63 if(pbest[j]>gbest) gbest=pbest[j]; 64 System.out.println(x[j]+" "+v[j]); 65 } 66 System.out.println("======"+(i+1)+"======gbest:"+gbest); 67 } 68 69 70 } 71 public static void main(String[] args){ 72 PSOTest ts=new PSOTest(); 73 ts.init(); 74 ts.PSO(100); 75 } 76 77 78 79 }
輸出結果如下:

1 start gbest:0.0
2 -0.4 0.1
3 0.0 -10.751668729351186
4 ======1======gbest:0.0
5 -0.6822365786740794 -0.2822365786740793
6 0.0 -5.375834364675593
7 ======2======gbest:0.0
8 -0.5822365786740794 0.1
9 0.0 -2.6879171823377965
10 ======3======gbest:0.0
11 -0.48223657867407943 0.1
12 -1.3439585911688983 -1.3439585911688983
13 ======4======gbest:0.0
14 -0.38223657867407945 0.1
15 -1.2439585911688982 0.1
16 ======5======gbest:0.0
17 -0.47659030560462123 -0.09435372693054181
18 -1.143958591168898 0.1
19 ======6======gbest:0.0
20 -0.37659030560462126 0.1
21 -1.043958591168898 0.1
22 ======7======gbest:0.0
23 -0.2765903056046213 0.1
24 -0.943958591168898 0.1
25 ======8======gbest:0.0
26 -0.27903394174424034 -0.0024436361396190653
27 -0.843958591168898 0.1
28 ======9======gbest:0.0
29 -0.38899022876058803 -0.10995628701634769
30 -0.7439585911688981 0.1
31 ======10======gbest:0.0
32 -0.35250959144436234 0.03648063731622572
33 -0.6439585911688981 0.1
34 ======11======gbest:0.0
35 ........ 36 ........ 37 ........ 38 ........ 39 0.9999990975760489 -1.556071309835406E-6
40 ======98======gbest:1.0
41 1.0000000029937202 4.411275849326098E-9
42 1.0000001827158205 1.085139771533034E-6
43 ======99======gbest:1.0
44 0.9999999993730952 -3.6206249540206964E-9
45 1.0000001197322141 -6.298360633295484E-8
46 ======100======gbest:1.0
我們可以從打印的數據看出來,剛開始x[0]和x[1]分散在最大值兩邊,然后x[0]和x[1]逐漸聚集到1的周圍,這里,我們已經收斂到x=1這個地方了,這正是我們要求的最大值,其最大值為1,下面是圖解過程。
1.初始狀態
2.第二次x[1]向左邊移動了
3.最后,兩點聚集在1上,上面多個圈是他們聚集的過程,可以看出來,聚集過程是個越來越密集的過程。
最后
粒子群算法,相對於我上次提到的遺傳算法而言編碼要簡單很多,同樣屬於進化算法,但是粒子群算法並沒有像遺傳算法那樣有選擇交叉變異這樣的過程,而更多的是體現在追蹤單個粒子和共享集體最優信息來實現向最優空間搜索的形式,但是正由於它不同於遺傳算法那樣去忽略個體的一些內在聯系,所以往往會陷入局部最優,所以,在粒子群算法中加入像遺傳算法中的變異或者模擬退火等,可以跳過這個局部最優解。
而慣性權值對於函數收斂速度和是否收斂有很大的決定作用,兩個學習參數c1,c2的制定也同等重要,但是即使這樣,它也沒有遺傳算法中會有多個參數去維護,所以整個算法就那一個公式就行了,相當的清晰。在遺傳算法中的信息的共享是染色體互相之間通過交叉共享,所以在搜索移動過程顯得平均緩慢,而粒子群算法是根據gbest來決定整個集群的單向移動,所以相對遺傳算法,它更快的收斂。
這不由得讓我想到了熵這個概念,在諸如我們社會甚至宇宙這樣復雜的系統,我們都處於一個無序的狀態,屬於熵增狀態,像粒子群,遺傳算法,對群體的研究,體現的智能不就是在這個無序的系統提供有序的能量,然后它就逐漸有序了。對於智能,我想我有更深的體會了。這段話屬於發神經,不作參考。
注:本博文版權屬BreezeDust所有
歡迎轉載,轉載請注明:http://www.cnblogs.com/BreezeDust/p/3354769.html
本文的最新修改和意見請點擊:http://breezedust.com/2013/10/06/zi-hua-li-zi-qun-suan-fa-chao-jian-dan-shi-li/