【MATLAB】混合粒子羣算法原理、代碼及詳解

1.算法

1.1.原理

\qquad建議沒接觸過粒子羣算法的朋友先看較爲基礎的全局粒子羣算法原理及介紹,以下博文鏈接有詳細的講解、代碼及其應用舉例:
【Simulink】粒子羣算法(PSO)整定PID參數(附代碼和講解)
\qquad這裏就介紹一下全局粒子羣算法和混合粒子羣算法的區別。全局粒子羣算法(General PSO)將粒子速度矢量影響因子分爲了三類:慣性因子、自身最優因子、社會因子。每個粒子的初速度定爲0,即v0=0v_0=0,第jj個粒子(1jm1≤j≤m)的下一次迭代的速度v(j)v^{(j)}由以下三部分組成:
v(j)=wv0+c1rand(P(j)X(j))+c2rand(PGX(j))v^{(j)}=w\cdot v_0+c_1\cdot rand\cdot (P^{(j)}-X^{(j)})+c_2\cdot rand\cdot(P_G-X^{(j)})
注:rand是(0,1)的隨機數,v0v_0代表上一次粒子的速度。
第一部分爲自身慣性因子,因爲下一次的迭代次數保留了上一次的速度信息;
第二個部分爲自身最優因子,P(j)\color{blue}{P^{(j)}}爲第jj個因子在之前所有迭代次數中自適應度最高的位置,可以理解爲歷史上自身離最優解最近的位置。
第三部分爲社會因子,PG\color{blue}{P_G}爲種羣在之前所有迭代次數中自適應度最高的位置,可以理解爲歷史上所有粒子離最優解最近的位置中的最近的一個。
\qquad而混合粒子羣算法(Hybrid PSO)與全局粒子羣算法唯一的區別就是將社會因子分解爲了兩部分——局部社會因子和全局社會因子。即v(j)=wv0+c1rand(P(j)X(j))+c2[qrand(PGX(j))+(1q)rand(PL(j)X(j))]v^{(j)}=w\cdot v_0+c_1\cdot rand\cdot (P^{(j)}-X^{(j)})+c_2[q\cdot rand\cdot(P_G-X^{(j)})+(1-q)\cdot rand\cdot(P_L^{(j)}-X^{(j)})]
一般0<q<1,即兩部分社會因子都爲正。與上面不同的是PL(j)P_L^{(j)}是第jj個粒子的局部最優解的座標。
\qquad全局社會因子使得粒子的速度矢量有向(目前的)全局最優解趨向的趨勢,而局部社會因子則使速度矢量包含向粒子的(目前的)局部最優解趨向的趨勢。全局最優解好理解,局部最優解就是該粒子一定範圍內粒子中的最優解,一般這個範圍是固定的,而包含的粒子數量(如果爲1,則是粒子本身)不確定。
\qquad全局粒子羣算法收斂速度快,但是對於多極值問題容易收斂到一個局部最優解;混合粒子羣算法由於要計算局部最優解的原因,收斂速度慢,但可以很好地解決全局粒子羣算法收斂到局部最優解的問題。

1.2.性能比較

\qquad對粒子羣算法感興趣的朋友可以讀一下面這兩部分解釋。

1.爲什麼全局粒子羣算法容易收斂到局部最優解呢?
\qquad我們不妨假設僅有3個粒子,目前有2個極小值點A和B,假設第一次迭代(位置隨機,初速度爲0),一個粒子a恰好就位於其中一個極小值點A附近,另2個粒子b和c彼此較近,但離B較遠,函數值f(A)<f(C)<f(B)f(A)<f(C)<f(B)。初速度爲0,慣性因子爲0。又因爲a就是當前全局最優點,自身最優因子也是本身(因爲迭代次數爲1),所以後兩項都是0,a不會動。粒子b和c的歷史最優因子就是它現在的位置,而社會因子使它向粒子a移動,並且每移動一次,它的自身最優因子都比上次的好,即不會對它的目前的速度造成任何影響。

\qquad最終兩個粒子都會收斂到極值點A。即使極值點B的目標函數值更小一些,但由於極值點A先被粒子羣“找到”,因此就像一個極小值點黑洞一樣,把所有的粒子都“吸”了過去。所以簡單地來說,全局最優解就像一個吸引其他粒子的“黑洞”,如果在找到第二個“黑洞”之前所有粒子都被吸引到了第一個“黑洞”的周圍,那就只能找到第一個局部最優解了。

1 2 3
在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述

2.那爲什麼混合粒子羣算法就可以避免這個問題呢?
\qquad我們不妨假設一個和上文一樣的場景。目標函數只有2個極小值點A和B,第一次迭代,粒子a就位於A的附近,粒子b和c不位於B的附近,但彼此離得較近,離A較遠。而且目標函數值都比a要大。初速度爲0,因此三者的慣性因子爲0。a的自身最優因子就是它本身,同時也是全局最優解,因此a不會動。而b、c的自身最優因子也是本身,然而全局社會最優因子是a,即二者都有向a偏移的趨勢。

\qquad現在考慮局部社會最優因子,b和c距離較小,會受到局部社會因子的影響;而二者都離a較遠,不會受到a的影響(同樣a也不會受到b和c的影響)。假設c的函數值比b小,因此b是c的局部最優解(同時也是它自身的)。在局部社會因子的作用下,b有向c移動的趨勢;c和a均不受影響(c和a的局部最優解都是本身)。假設局部最優因子的權重合適,b應該向極小值B移動,c向a點移動。因爲b有慣性因子,很可能在第二次迭代的過程中,離極小值B的距離會比c要短,滿足f(B)<f(C)<f(A)f(B)<f(C)<f(A)。那麼在接下來的幾步迭代中,三者就會順利收斂到極小值B附近,而不是更大的一個極小值A,進而找到全局最優解。

1 2 3 4
在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述

1.3.步驟

\qquad步驟和全局粒子羣算法基本一致,下面將不一樣的步驟標紅,看過全局粒子羣算法那篇博文的讀者可以重點關注一下。
【step0】確定參數維度N\color{blue}{N}、參數範圍(即每隻鳥的初始位置),確定慣性系數c1,c2,wc_1,c_2,w,確定種羣規模m,迭代次數n以及局部因子作用半徑RR

每個粒子的初始位置是隨機的,設輸入向量x=(x1,x2,...,xN)Tx=(x_1,x_2,...,x_N)^T必須滿足參數範圍限制爲:
{xmin(1)<x1<xmax(1)xmin(2)<x2<xmax(2)...xmin(N)<x1<xmax(N)\begin{cases}x_{min}^{(1)}<x_1<x_{max}^{(1)} \\x_{min}^{(2)}<x_2<x_{max}^{(2)} \\... \\x_{min}^{(N)}<x_1<x_{max}^{(N)} \end{cases}
Xmin=(xmin(1),xmin(2),...xmin(N)),Xmax=(xmax(1),xmax(2),...xmax(N))\color{blue}X_{min}=(x_{min}^{(1)},x_{min}^{(2)},...x_{min}^{(N)}),X_{max}=(x_{max}^{(1)},x_{max}^{(2)},...x_{max}^{(N)})
則輸入向量xx應滿足Xmin<x<XmaxX_{min}<x<X_{max}
【step1】計算每個粒子的速度
每個粒子的初速度定爲0,即v0=0v_0=0,第jj個粒子(1jm1≤j≤m)的下一次迭代的速度v(j)v^{(j)}由三部分組成:
v(j)=wv0+c1rand(P(j)X(j))+c2[qrand(PGX(j))+(1q)rand(PL(j)X(j))]v^{(j)}=w\cdot v_0+c_1\cdot rand\cdot (P^{(j)}-X^{(j)})+c_2[q\cdot rand\cdot(P_G-X^{(j)})+(1-q)\cdot rand\cdot(P_L^{(j)}-X^{(j)})]

注:rand是(0,1)的隨機數,v0v_0代表上一次粒子的速度。
第一部分爲自身慣性因子,因爲下一次的迭代次數保留了上一次的速度信息;
第二個部分爲自身最優因子,P(j)\color{blue}{P^{(j)}}爲第jj個因子在之前所有迭代次數中自適應度最高的位置,可以理解爲歷史上自身離食物最近的位置。
第三部分爲社會因子,由全局社會因子和局部社會因子組成。

PG\color{blue}{P_G}爲全局最優解,是種羣在之前所有迭代次數中自適應度最高的位置,可以理解爲歷史上所有粒子離食物最近的位置中的最近的一個。
一般情況下,取w=1,c1=c2=2w=1,c_1=c_2=2,當種羣規模較大時,可以讓ww的值隨迭代次數減小以增加收斂速度。
PL(j)\color{blue}{P_L^{(j)}}爲局部最優解,每個粒子都有各自的局部最優解,可以理解爲以該粒子爲中心,R\color{blue}{R}爲半徑的超球體內包含的所有粒子中自適應度最高的粒子的位置。q是全局社會因子的佔比,比例越高局部社會因子所佔的權重越小。R\color{blue}{R}稱爲局部因子作用半徑,和粒子分佈平均密度有關。

【step2】按照step1的速度公式計算下一次的速度,並計算下一次的粒子位置。對於第jj個粒子,第k+1k+1次迭代(第k+1k+1代)的位置Xk+1(j)\color{blue}{X_{k+1}^{(j)}}與第kk次迭代的位置XK(j)\color{blue}{X_K^{(j)}}與速度vk(k+1)\color{blue}{v_k^{(k+1)}}關係爲:
Xk+1(j)=Xk(j)+vk(j+1)dtX^{(j)}_{k+1}=X^{(j)}_{k}+v_k^{(j+1)}\cdot dt
其中dt\color{blue}{dt}是仿真間隔,一般情況下可以取1,如果希望仿真得慢一點,搜索平滑一點,可以適當減小dt\color{blue}{dt}
【step3】計算每個粒子的自適應度Fk+1(j)\color{blue}{F^{(j)}_{k+1}},爲了計算出step1公式中的P(j)PG\color{blue}{P^{(j)}、P_G}PL(j)\color{red}{P_L^{(j)}}。爲了方便起見,我們記前k次計算得到了的PGP_GPG(k)P_G^{(k)},則第k+1次迭代中我們將適應度最高的粒子位置記爲PG(k+1)P_G^{(k+1)},則最終的PGP_G爲:
PG={PG(k)F(PG(k))>F(PG(k+1))PG(k+1)F(PG(k))<F(PG(k+1))P_G=\begin{cases}P_G^{(k)},\qquad F(P_G^{(k)})>F(P_G^{(k+1)}) \\[2ex]P_G^{(k+1)},\quad F(P_G^{(k)})<F(P_G^{(k+1)}) \end{cases}
同樣,我們記前k次計算得到的第jj個粒子的位置爲Pk(j)P^{(j)}_{k},第k+1次計算得到的第jj個粒子的位置爲Pk+1(j)P^{(j)}_{k+1},則最終的P(j)P^{(j)}爲:
P(j)={Pk(j)F(Pk(j))>F(Pk+1(j))Pk+1(j)F(Pk(j))<F(Pk+1(j))P^{(j)}=\begin{cases}P_{k}^{(j)},\quad F(P_{k}^{(j)})>F(P_{k+1}^{(j)}) \\[2ex]P_{k+1}^{(j)},\quad F(P_{k}^{(j)})<F(P_{k+1}^{(j)}) \end{cases}
我們計第k次迭代的PL(j)P_L^{(j)}PLk(j)P_{L_k}^{(j)},第kk次迭代的第ii粒子的位置爲Pk(i)P_k^{(i)}
PLk+1(j)=avg[min(F(Pk(i)))],Pk(i)Pk(j)RP_{L_{k+1}}^{(j)}=avg[min(F(P_k^{(i)}))],||P_k^{(i)}-P_k^{(j)}||≤R
即所有距離第jj個粒子不超過R的粒子中函數值最小的那個。
\qquad注意PL(j)P_L^{(j)}不需要保存爲數組,也不需要和上次的值比較,它的值依賴於每次迭代粒子的位置,也會跟着來粒子位置分佈的變化爲變化。

【step4】更新每個粒子的信息。
由於我們在step2的位置迭代中已經更新過粒子的位置信息,在step1中的速度迭代中已經更新過粒子的速度信息,而在step3中又更新了每個粒子的歷史最優位置P(j)P^{(j)}及種羣最優位置PGP_G,因此實際上如果僅需要知道最優解的情況下我們不需要做這一步。
但如果需要作出參數隨迭代次數的改變的圖的話,每次迭代產生最優解PG(k)P_G^{(k)}及最優適應度F(PG(k))F(P_G^{(k)})需要用數組保存下來。

2.代碼

2.1.源碼及註釋

\qquad混合粒子羣算法與全局粒子羣算法的唯一區別就在一多出一個局部社會因子,計算局部社會因子就需要計算每個粒子爲中心,R爲半徑的“局部”內自適應度最高的粒子。因此判斷粒子與粒子間的距離成爲了一大難題。將這部分代碼寫成並行形式,可以大大降低算法時間複雜度和空間複雜度。
\qquad我們定義一個鄰接矩陣
D=[d11d12...d1nd21d22...d2ndn1dn2...dnn]D=\begin{bmatrix} d_{11} & d_{12} & ... & d_{1n}\\ d_{21} & d_{22} & ... & d_{2n}\\ \vdots & \vdots & \ddots & \vdots\\ d_{n1} & d_{n2} & ... & d_{nn} \end{bmatrix}
其中dijd_{ij}代表第ii個粒子距離第jj個粒子的距離,dii=0d_{ii}=0
每次迭代過程中都計算鄰接矩陣DD,計算第jj粒子的局部社會因子時即參考DD矩陣的第jj行(或列)的數據即可。
計算鄰接矩陣DD的函數書寫如下:(Distance_Matrix.m)

function DM=Distance_Matrix(X)
m=size(X,2);%維數
n=size(X,1);%樣本數
DM=zeros(n,n);%距離矩陣
for t=1:m
    Dif=ones(n,1)*X(t,:)-X;%座標差矩陣
    Dis=sum(Dif.^2,2);%第t個樣本距離其他所有樣本的距離(矩陣)
    DM(t,:)=Dis;
end

注意,這裏X是樣本矩陣,樣本是以行向量的形式組成矩陣的。

主程序代碼如下所示:(Hybrid_POS.m)

function [Pg,fmin]=Hybrid_PSO(f,dimension,n,m,xmax,xmin,vmax,vmin,R,p)
%混合粒子羣算法,f爲目標函數,dimension爲維度,n爲代數,m爲種羣規模
%位置限幅爲[xmin,xmax],速度限幅爲[vmin,vmax]
%R爲局部粒子羣算法作用範圍
%p爲局部粒子羣佔的比重(Max=1% 以下四行爲位置限幅和速度限幅,對應的四個參數均爲行向量
    Xmax=ones(m,1)*xmax;
    Xmin=ones(m,1)*xmin;
    Vmax=ones(m,1)*vmax;
    Vmin=ones(m,1)*vmin;
    Savef=zeros(n+1,1);%記錄自適應度F的數組
%   SaveData=zeros(m,dimension,10);%記錄11代種羣的位置,只需結果時不需要此數組
    w=1;c1=2;c2=2;%速度慣性系數
    dt=0.3;%位移仿真間隔
    v=zeros(m,dimension);%初始速度爲0
    X=(Xmax-Xmin).*rand(m,dimension)+Xmin;%初始位置滿足(-xmax,xmax)內均勻分佈
    P=X;%P爲每個粒子每代的最優位置
    DM=Distance_Matrix(X);%距離矩陣
    Local_Pg=zeros(m,dimension);%局部最優解矩陣
    last_f=f(X);
    [fmin,min_i]=min(last_f);%Pg爲所有代中的最優位置 
    Pg=X(min_i,:);%獲取這個最優位置的座標
    Savef(1)=fmin;
    for i=1:m
        XR_i=find(DM(i,:)<R);
        [~,min_i]=min(last_f(XR_i));%按行篩選小於R的點
        Local_Pg(i,:)=X(XR_i(min_i),:);%局部最優解的座標
    end
    N=0;
    for i=1:n
        v=w*v+c1*rand*(P-X)+c2*rand*((1-p)*(ones(m,1)*Pg-X)+p*(Local_Pg-X));
        v=(v>Vmax).*Vmax+(v>=Vmin & v<=Vmax).*v+(v<Vmin).*Vmin;
        X=X+v*dt;
        X=(X>Xmax).*Xmax+(X>=Xmin & X<=Xmax).*X+(X<Xmin).*Xmin;
        new_f=f(X);%新的目標函數值
        update_j=find(new_f<last_f);
        P(update_j,:)=X(update_j,:);%修正每個粒子的歷史最優值
        [new_fmin,min_i]=min(new_f);
        new_Pg=X(min_i,:);
        Pg=(new_fmin<fmin)*new_Pg+(new_fmin>=fmin)*Pg;
        last_f=new_f;%保存當前的函數值
        fmin=min(new_fmin,fmin);%更新函數最小值
         Savef(i)=fmin;
         if mod(i,floor(n/10))==0%10代記錄一次種羣參數
             N=N+1;
         %   SaveData(:,:,N)=X;
         end
        w=w-i/n*0.8*w;
    end
%     for j=1:10
%         figure(j)
%         plot(SaveData(:,1,j),SaveData(:,2,j),'o');
%         xlim([xmin(1),xmax(1)])
%         ylim([xmin(2),xmax(2)])
%         axis tight
%     end
    figure
    plot(Savef','b-')
    title('混合粒子羣優化')
    disp(Pg)
    disp(fmin)
end

注:代碼註釋部分是繪製數次迭代粒子分佈位置,要解除需要一起解除(Ctlr+T),否則會報錯!

2.2.執行與效果

\qquad我們首先來嘗試使用RosenBrock函數(香蕉函數)對其進行試驗。香蕉函數的極小值點爲(1,1),極小值爲0。書寫爲匿名函數如下:

>> f=@(x)((1-x(:,1)).^2+100*(x(:,2)-x(:,1).^2).^2);

注:這裏的冒號不可以省略,因爲是樣本爲多維行向量組成的矩陣,所以函數也應返回同維向量而不是一個值。

我們設定一個稍大的範圍,速度限幅設置爲位置限幅約1/3的大小,局部社會因子取0.15,局部社會因子影響半徑R取位置限幅的1/6。仿真命令及結果如下:

>> [Pg,fmin]=Hybrid_PSO(f,2,25,200,[10,10],[-10,-10],[3,3],[-3,-3],3,0.15)
    0.9731    0.9480

   8.2839e-04


Pg =

    0.9731    0.9480


fmin =

   8.2839e-04

目標函數的下降趨勢如下:
在這裏插入圖片描述
粒子羣的變化趨勢如下圖:

在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述
在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述

可以發現粒子羣算法順利收斂到了(1,1)附近。

2.3.理解與進階

\qquad反問讀者一個問題,如何提高混合粒子羣算法(Hybrid PSO)的精度。肯定有人會說增加迭代次數n或者擴大種羣規模m,除此之外,還有一個簡單易行的方法,即在第一次結果的基礎上進行第二次仿真,並把範圍設置在第一次結果的附近,大大減小位置限幅和速度限幅的數值,仿真精度自然會提高。
\qquad重新設置位置限幅爲[0,2],速度限幅爲[-0.3,0.3],R=0.3,再次仿真:

>> [Pg,fmin]=Hybrid_PSO(f,2,25,200,[2,2],[0,0],[0.3,0.3],[-0.3,-0.3],0.3,0.15)
    1.0009    1.0014

   9.9527e-06


Pg =

    1.0009    1.0014


fmin =

   9.9527e-06

在這裏插入圖片描述
\qquad可以發現二次仿真後最優解更加接近於(1,1),極小值也大大縮小(縮小2個數量級)。讀者可以思考如何修改代碼以實現一次仿真就能代替二次仿真的效果。
\qquad混合粒子羣算法在單極值的,或者極值不密集的解析函數上仿真與全局粒子羣算法效果相差無幾,將其參數ρ\rho設爲0,即爲全局粒子羣算法(但別以爲這樣可以提高運算速度)。我看看仿真結果的對比:

混合粒子羣 全局粒子羣
ρ=0.15\rho=0.15 ρ=0\rho=0
[xmin,xmax]=[10,10][x_{min},x_{max}]=[-10,10] [xmin,xmax]=[10,10][x_{min},x_{max}]=[-10,10]
[vmin,vmax]=[3,3][v_{min},v_{max}]=[-3,3] [xmin,xmax]=[10,10][x_{min},x_{max}]=[-10,10]
R=3 /
在這裏插入圖片描述 在這裏插入圖片描述
x=(1.0809,1.1701)x^*=(1.0809 ,1.1701) x=(1.1044,1.2174)x^*=(1.1044 ,1.2174)
fmin=0.0069f_{min}=0.0069 fmin=0.0115f_{min}=0.0115

\qquad但在優化類似神經網絡、simulink函數等無解析式複雜函數時,混合粒子羣求得更小極值的可能性更大(注意,粒子羣每次仿真結果不一樣,求得最優解只是一個概率收斂問題)。

希望本文對您有幫助,謝謝閱讀!

發佈了27 篇原創文章 · 獲贊 149 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章