【智慧演算法】粒子群演算法(Particle Swarm Optimization)超詳細解析+入門程式碼例項講解
喜歡的話可以掃碼關注我們的公眾號哦,更多精彩盡在微信公眾號【程式猿聲】

01 演算法起源
粒子群優化演算法(PSO)是一種進化計算技術(evolutionary computation),1995 年由Eberhart 博士和kennedy 博士提出,源於對鳥群捕食的行為研究 。該演算法最初是受到飛鳥叢集活動的規律性啟發,進而利用群體智慧建立的一個簡化模型。粒子群演算法在對動物叢集活動行為觀察基礎上,利用群體中的個體對資訊的共享使整個群體的運動在問題求解空間中產生從無序到有序的演化過程,從而獲得最優解。
02 什麼是粒子群演算法?
2.1 官方定義(參照百科)
粒子群演算法,也稱粒子群優化演算法或鳥群覓食演算法(Particle Swarm Optimization),縮寫為 PSO, 是近年來由J. Kennedy和R. C. Eberhart等開發的一種新的進化演算法(Evolutionary Algorithm - EA)。PSO 演算法屬於進化演算法的一種,和模擬退火演算法相似,它也是從隨機解出發,通過迭代尋找最優解,它也是通過適應度來評價解的品質,但它比遺傳演算法規則更為簡單,它沒有遺傳演算法的“交叉”(Crossover) 和“變異”(Mutation) 操作,它通過追隨當前搜尋到的最優值來尋找全域性最優。這種演算法以其實現容易、精度高、收斂快等優點引起了學術界的重視,並且在解決實際問題中展示了其優越性。粒子群演算法是一種並行演算法。
2.2 通俗點描述
如同前面的描述,PSO模擬的是鳥群的捕食行為。設想這樣一個場景:一群鳥在隨機搜尋食物。在這個區域裡只有一塊食物。所有的鳥都不知道食物在那裡。但是他們知道當前的位置離食物還有多遠。那麼找到食物的最優策略是什麼呢。最簡單有效的就是搜尋目前離食物最近的鳥的周圍區域。
鳥群在整個搜尋的過程中,通過相互傳遞各自的資訊,讓其他的鳥知道自己的位置,通過這樣的協作,來判斷自己找到的是不是最優解,同時也將最優解的資訊傳遞給整個鳥群,最終,整個鳥群都能聚集在食物源周圍,即找到了最優解。
PSO中,每個優化問題的解都是搜尋空間中的一隻鳥。我們稱之為“粒子”。所有的粒子都有一個由被優化的函式決定的適應值(fitness value),每個粒子還有一個速度決定他們飛翔的方向和距離。然後粒子們就追隨當前的最優粒子在解空間中搜索。
PSO 初始化為一群隨機粒子(隨機解)。然後通過迭代找到最優解。在每一次迭代中,粒子通過跟蹤兩個"極值"來更新自己。第一個就是粒子本身所找到的最優解,這個解叫做個體極值pBest。另一個極值是整個種群目前找到的最優解,這個極值是全域性極值gBest。另外也可以不用整個種群而只是用其中一部分作為粒子的鄰居,那麼在所有鄰居中的極值就是區域性極值。
2.3 再再再通俗點的描述
粒子群演算法的基本思想是通過群體中個體之間的協作和資訊共享來尋找最優解。如上的情景。試著想一下一群鳥在尋找食物,在這個區域中只有一隻蟲子,所有的鳥都不知道食物在哪。但是它們知道自己的當前位置距離食物有多遠,同時它們知道離食物最近的鳥的位置。想一下這時候會發生什麼?

同時各只鳥在位置不停變化時候離食物的距離也不斷變化,所以每個鳥一定有過離食物最近的位置,這也是它們的一個參考。

所以,粒子群演算法就是把鳥看成一個個粒子,並且他們擁有位置和速度這兩個屬性,然後根據自身已經找到的離食物最近的解和參考整個共享於整個叢集中找到的最近的解去改變自己的飛行方向,最後我們會發現,整個叢集大致向同一個地方聚集。而這個地方是離食物最近的區域,條件好的話就會找到食物。
03 粒子抽象
3.1 關於速度和位置
粒子群演算法通過設計一種無質量的粒子來模擬鳥群中的鳥,粒子僅具有兩個屬性:速度和位置,速度代表移動的快慢,位置代表移動的方向。
鳥被抽象為沒有質量和體積的微粒(點),並延伸到N維空間,粒子i在N維空間的位置表示為向量Xi=(α1,α2,…,αN),飛行速度表示為向量Vi=(β1,β2,…,βN)。每個粒子都有一個由目標函式決定的適應值(fitness value),並且知道自己到目前為止發現的最好位置(pbest)和現在的位置Xi。這個可以看作是粒子自己的飛行經驗。除此之外,每個粒子還知道到目前為止整個群體中所有粒子發現的最好位置(gbest)(gbest是pbest中的最好值),這個可以看作是粒子同伴的經驗。粒子就是通過自己的經驗和同伴中最好的經驗來決定下一步的運動。
3.2 速度和位置的更新
PSO初始化為一群隨機粒子(隨機解)。然後通過迭代找到最優解。在每一次的迭代中,粒子通過跟蹤兩個“極值”(pbest,gbest)來更新自己。在找到這兩個最優值後,粒子通過下面的公式來更新自己的速度和位置。

對於公式(1):
公式(1)的第①部分稱為【記憶項】,表示上次速度大小和方向的影響;
公式(1)的第②部分稱為【自身認知項】,是從當前點指向粒子自身最好點的一個向量,表示粒子的動作來源於自己經驗的部分;
公式(1)的第③部分稱為【群體認知項】,是一個從當前點指向種群最好點的向量,反映了粒子間的協同合作和知識共享。粒子就是通過自己的經驗和同伴中最好的經驗來決定下一步的運動。
以上面兩個公式為基礎,再來看一個公式:

公式(2)和 公式(3)被視為標準PSO演算法。
04 標準PSO演算法流程
4.1 標準PSO演算法的流程
1)初始化一群微粒(群體規模為N),包括隨機位置和速度;
2)評價每個微粒的適應度;
3)對每個微粒,將其適應值與其經過的最好位置pbest作比較,如果較好,則將其作為當前的最好位置pbest;
4)對每個微粒,將其適應值與其經過的最好位置gbest作比較,如果較好,則將其作為當前的最好位置gbest;
5)根據公式(2)、(3)調整微粒速度和位置;
6)未達到結束條件則轉第2)步。
迭代終止條件根據具體問題一般選為最大迭代次數Gk或(和)微粒群迄今為止搜尋到的最優位置滿足預定最小適應閾值。
4.2 PSO流程圖解

4.3 學習因子c1、c2分析
公式(2)和(3)中pbest和gbest分別表示微粒群的區域性和全域性最優位置。
-
當C1=0時,則粒子沒有了認知能力,變為只有社會的模型(social-only):
稱為全域性PSO演算法。粒子有擴充套件搜尋空間的能力,具有較快的收斂速度,但由於缺少區域性搜尋,對於複雜問題
比標準PSO 更易陷入區域性最優。
-
當C2=0時,則粒子之間沒有社會資訊,模型變為只有認知(cognition-only)模型:
稱為區域性PSO演算法。由於個體之間沒有信息的交流,整個群體相當於多個粒子進行盲目的隨機搜尋,收斂速度慢,因而得到最優解的可能性小。
05 程式碼例項講解
5.1 先來看個簡單的例項
在這個例子中,我們選取了一個求解函式y=-x*(x-1) 在[0,2]上最大值的粒子群演算法。然後通過步步跟蹤演算法輸出結果,來給大家講解粒子運動的過程。
下面先看程式碼和程式碼註釋。
1public class AlgorithmPSO { 2int n=2; //粒子個數,這裡為了方便演示,我們只取兩個,觀察其運動方向 3double[] y; 4double[] x; 5double[] v; 6double c1=2; 7double c2=2; 8double pbest[]; 9double gbest; 10double vmax=0.1; //速度最大值 11//適應度計算函式,每個粒子都有它的適應度 12public void fitnessFunction(){ 13for(int i=0;i<n;i++){ 14y[i]=-1*x[i]*(x[i]-2); 15} 16} 17public void init(){ //初始化 18x=new double[n]; 19v=new double[n]; 20y=new double[n]; 21pbest=new double[n]; 22/*** 23* 本來是應該隨機產生的,為了方便演示,我這裡手動隨機落兩個點,分別落在最大值兩邊 24*/ 25x[0]=0.0; 26x[1]=2.0; 27v[0]=0.01; 28v[1]=0.02; 29fitnessFunction(); 30//初始化當前個體最優位置,並找到群體最優位置 31for(int i=0;i<n;i++){ 32pbest[i]=y[i]; 33if(y[i]>gbest) gbest=y[i]; 34} 35System.out.println("演算法開始,起始最優解:"+gbest); 36System.out.print("\n"); 37} 38public double getMAX(double a,double b){ 39return a>b?a:b; 40} 41//粒子群演算法 42public void PSO(int max){ 43for(int i=0;i<max;i++){ 44double w=0.4; 45for(int j=0;j<n;j++){ 46//更新位置和速度,下面就是我們之前重點講解的兩條公式。 47v[j]=w*v[j]+c1*Math.random()*(pbest[j]-x[j])+c2*Math.random()*(gbest-x[j]); 48if(v[j]>vmax) v[j]=vmax;//控制速度不超過最大值 49x[j]+=v[j]; 50 51//越界判斷,範圍限定在[0, 2] 52if(x[j]>2) x[j]=2; 53if(x[j]<0) x[j]=0; 54 55} 56fitnessFunction(); 57//更新個體極值和群體極值 58for(int j=0;j<n;j++){ 59pbest[j]=getMAX(y[j],pbest[j]); 60if(pbest[j]>gbest) gbest=pbest[j]; 61System.out.println("粒子n"+j+": x = "+x[j]+""+"v = "+v[j]); 62} 63System.out.println("第"+(i+1)+"次迭代,全域性最優解 gbest = "+gbest); 64System.out.print("\n"); 65} 66 67} 68//執行我們的演算法 69public static void main(String[] args){ 70AlgorithmPSO ts=new AlgorithmPSO(); 71ts.init(); 72ts.PSO(10);//為了方便演示,我們暫時迭代10次。 73} 74 75}
輸出結果:
1演算法開始,起始最優解:0.0 2 3粒子n0: x = 0.004v = 0.004 4粒子n1: x = 0.0v = -4.065770842472382 5第1次迭代,全域性最優解 gbest = 0.007984 6 7粒子n0: x = 0.01778510589090629v = 0.013785105890906289 8粒子n1: x = 0.0v = -1.625639647649872 9第2次迭代,全域性最優解 gbest = 0.03525390179026183 10 11粒子n0: x = 0.0610276658084214v = 0.04324255991751511 12粒子n1: x = 0.0v = -0.6035255880722042 13第3次迭代,全域性最優解 gbest = 0.11833095562281844 14 15粒子n0: x = 0.1610276658084214v = 0.1 16粒子n1: x = 0.0v = -0.012719944703824898 17第4次迭代,全域性最優解 gbest = 0.29612542246113416 18 19粒子n0: x = 0.2610276658084214v = 0.1 20粒子n1: x = 0.06231495466940402v = 0.06231495466940402 21第5次迭代,全域性最優解 gbest = 0.4539198892994499 22 23粒子n0: x = 0.3610276658084214v = 0.1 24粒子n1: x = 0.16231495466940402v = 0.1 25第6次迭代,全域性最優解 gbest = 0.5917143561377656 26 27粒子n0: x = 0.46102766580842136v = 0.1 28粒子n1: x = 0.262314954669404v = 0.1 29第7次迭代,全域性最優解 gbest = 0.7095088229760813 30 31粒子n0: x = 0.5610276658084213v = 0.1 32粒子n1: x = 0.362314954669404v = 0.1 33第8次迭代,全域性最優解 gbest = 0.8073032898143969 34 35粒子n0: x = 0.6610276658084213v = 0.1 36粒子n1: x = 0.462314954669404v = 0.1 37第9次迭代,全域性最優解 gbest = 0.8850977566527127 38 39粒子n0: x = 0.7610276658084213v = 0.1 40粒子n1: x = 0.562314954669404v = 0.1 41第10次迭代,全域性最優解 gbest = 0.9428922234910285
現在我們來觀察兩個粒子的位移x在每一次迭代中的變化(離食物的距離)。
1) 初始狀態
粒子n0: x = 0.0 v = 0.01
粒子n1: x = 2.0 v = 0.02

兩個粒子位於區間兩端。
2) 第一次迭代
粒子n0: x = 0.004 v = 0.004
粒子n1: x = 0.0 v = -4.065770842472382

兩個粒子都跑到原點了。
3) 第二、三……十次迭代

可以看到,兩個粒子在不斷靠近最優點。上面多個圈是他們聚集的過程,可以看出來,聚集過程是個越來越密集的過程。這才是10次迭代而已。如果我們加大迭代次數,很容易就找出最優解了。最後放上一個迭代100次的結果:

相信通過這個簡單的例子。大家已經對粒子群演算法有了非常清晰的認識了。
06 PSO和GA比較
6.1 共性
(1)都屬於仿生演算法。
(2) 都屬於全域性優化方法。
(3) 都屬於隨機搜尋演算法。
(4) 都隱含並行性。
(5) 根據個體的適配資訊進行搜尋,因此不受函式 約束條件的限制,如連續性、可導性等。
(6) 對高維複雜問題,往往會遇到早熟收斂和收斂 效能差的缺點,都無法保證收斂到最優點。
6.2 差異
(1) PSO有記憶,好的解的知識所有粒子都保 存,而GA,以前的知識隨著種群的改變被改變。
(2) PSO中的粒子僅僅通過當前搜尋到最優點進行共享資訊,所以很大程度上這是一種單共享項資訊機制。而GA中,染色體之間相互共享資訊,使得整個種群都向最優區域移動。
(3) GA的編碼技術和遺傳操作比較簡單,而PSO 相對於GA,沒有交叉和變異操作,粒子只是通過內部速度進行更新,因此原理更簡單、引數更少、實現更容易。
07 程式碼下載
欲獲取程式碼,請關注我們的微信公眾號【程式猿聲】,在後臺回覆: PSO 。即可下載。

推薦文章: ofollow,noindex" target="_blank">10分鐘教你用Python做個打飛機小遊戲超詳細教程
推薦文章: 10分鐘教你用python下載和拼接微信好友頭像圖片
推薦文章: 10分鐘教你用python一行程式碼搞點大新聞
推薦文章: 10分鐘教你用python打造貪吃蛇超詳細教程