粒子羣優化算法 (PSO)

1、概述

粒子羣優化算法(PSO)是一種進化計算技術(evolutionary computation),1995 年由Eberhart 博士和kennedy 博士提出,源於對鳥羣捕食的行爲研究 。該算法最初是受到飛鳥集羣活動的規律性啓發,進而利用羣體智能建立的一個簡化模型。粒子羣算法在對動物集羣活動行爲觀察基礎上,利用羣體中的個體對信息的共享使整個羣體的運動在問題求解空間中產生從無序到有序的演化過程,從而獲得最優解。

PSO 算法屬於進化算法的一種,和模擬退火算法相似,它也是從隨機解出發,通過迭代尋找最優解,它也是通過適應度來評價解的品質,但它比遺傳算法規則更爲簡單,它沒有遺傳算法的“交叉”(Crossover) 和“變異”(Mutation) 操作,它通過追隨當前搜索到的最優值來尋找全局最優。這種算法以其實現容易、精度高、收斂快等優點引起了學術界的重視,並且在解決實際問題中展示了其優越性。

粒子羣算法通過設計一種無質量的粒子來模擬鳥羣中的鳥,粒子僅具有兩個屬性:速度和位置,速度代表移動的快慢,位置代表移動的方向。

粒子就是通過自己的經驗和同伴中最好的經驗來決定下一步的運動。

理論知識戳這個鏈接:此鏈接含算法的Java復現

2、matlab實現

clc
clear 
close all
E=0.000001;
maxnum=800;%最大迭代次數
narvs=2;%目標函數的自變量個數
particlesize=50;%粒子羣規模
c1=2;%每個粒子的個體學習因子,加速度常數
c2=2;%每個粒子的社會學習因子,加速度常數
w=0.6;%慣性因子
vmax=5;%粒子的最大飛翔速度
v=2*rand(particlesize,narvs);%粒子飛翔速度
x=-300+600*rand(particlesize,narvs);%粒子所在位置
%定義適應度函數
fitness=inline('(x(1)^2+x(2)^2)/10000','x');
for i=1:particlesize
	f(i)=fitness(x(i,:));	
end
personalbest_x=x;
personalbest_faval=f;
[globalbest_faval,i]=min(personalbest_faval);
globalbest_x=personalbest_x(i,:); 
k=1;
while (k<=maxnum)
	for i=1:particlesize
			f(i)=fitness(x(i,:));
		if f(i)<personalbest_faval(i)
			personalbest_faval(i)=f(i);
			personalbest_x(i,:)=x(i,:);
		end
	end
	[globalbest_faval,i]=min(personalbest_faval);
	globalbest_x=personalbest_x(i,:);
	for i=1:particlesize
		v(i,:)=w*v(i,:)+c1*rand*(personalbest_x(i,:)-x(i,:))...
			+c2*rand*(globalbest_x-x(i,:));
		for j=1:narvs
			if v(i,j)>vmax
				v(i,j)=vmax;
			elseif v(i,j)<-vmax
				v(i,j)=-vmax;
            end
		end
		x(i,:)=x(i,:)+v(i,:);
    end
    ff(k)=globalbest_faval;
    if globalbest_faval<E
        break
    end
%       figure(1)
%       for i= 1:particlesize
%       plot(x(i,1),x(i,2),'*')
%       end
	k=k+1;
end
xbest=globalbest_x;
figure(2)
set(gcf,'color','white');
plot(1:length(ff),ff)

3、Python代碼復現(已測試)

理論學習這個鏈接,講的很好!

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import time
%matplotlib inline
 
class PSO(object):
    def __init__(self):
        self.iter=300 #迭代次數
        self.w=1 #慣性權重
        self.lr = (0.49445, 1.49445)  #粒子羣個體和社會的學習因子,即加速常數
        self.sizepop=20 #種羣規模
        self.rangepop=(-2,2) #粒子的位置的範圍限制,x、y方向的限制相同
        self.rangespeed=(-0.5,0.5) #速度限制
        self.px=[]  #當前全局最優解
        self.py=[]
 
    def func(self, x):
        # x輸入粒子位置
        # y 粒子適應度值
        if (x[0] == 0) & (x[1] == 0):
            y = np.exp((np.cos(2 * np.pi * x[0]) + np.cos(2 * np.pi * x[1])) / 2) - 2.71289
        else:
            y = np.sin(np.sqrt(x[0] ** 2 + x[1] ** 2)) / np.sqrt(x[0] ** 2 + x[1] ** 2) + np.exp(
                (np.cos(2 * np.pi * x[0]) + np.cos(2 * np.pi * x[1])) / 2) - 2.71289
        return y
 
    def initpopvfit(self, sizepop):
        pop = np.zeros((sizepop, 2))
        v = np.zeros((sizepop, 2))
        fitness = np.zeros(sizepop)
 
        for i in range(sizepop):
            pop[i] = [(np.random.rand() - 0.5) * self.rangepop[0] * 2, (np.random.rand() - 0.5) * self.rangepop[1] * 2]
            v[i] = [(np.random.rand() - 0.5) * self.rangepop[0] * 2, (np.random.rand() - 0.5) * self.rangepop[1] * 2]
            fitness[i] = self.func(pop[i])
        return pop, v, fitness
 
    def getinitbest(self, fitness, pop):
        # 羣體最優的粒子位置及其適應度值
        gbestpop, gbestfitness = pop[fitness.argmax()].copy(), fitness.max()
        # 個體最優的粒子位置及其適應度值,使用copy()使得對pop的改變不影響pbestpop,pbestfitness類似
 
        pbestpop, pbestfitness = pop.copy(), fitness.copy()
 
        return gbestpop, gbestfitness, pbestpop, pbestfitness
 
    def run(self):
        """
        通過循環迭代,不斷的更新粒子的位置和速度,根據新粒子的適應度值更新個體和羣體的極值
        :return:
        """
        pop, v, fitness = self.initpopvfit(self.sizepop)
        gbestpop, gbestfitness, pbestpop, pbestfitness = self.getinitbest(fitness, pop)
 
        result = np.zeros(self.iter)
        for i in range(self.iter):
            # 速度更新
            for j in range(self.sizepop):
                v[j] = self.w * v[j] + self.lr[0] * np.random.rand() * (pbestpop[j] - pop[j]) + self.lr[
                                                                                                    1] * np.random.rand() * (
                                                                                                    gbestpop - pop[j])
            v[v < self.rangespeed[0]] = self.rangespeed[0]
            v[v > self.rangespeed[1]] = self.rangespeed[1]
 
            # 粒子位置更新
            for j in range(self.sizepop):
                pop[j] += v[j]
            pop[pop < self.rangepop[0]] = self.rangepop[0]
            pop[pop > self.rangepop[1]] = self.rangepop[1]
 
            # 適應度更新
            for j in range(self.sizepop):
                fitness[j] = self.func(pop[j])
 
            for j in range(self.sizepop):
                if fitness[j] > pbestfitness[j]:
                    pbestfitness[j] = fitness[j]
                    pbestpop[j] = pop[j].copy()
 
            if pbestfitness.max() > gbestfitness:
                gbestfitness = pbestfitness.max()
                gbestpop = pop[pbestfitness.argmax()].copy()
 
            result[i] = gbestfitness
            self.px.append(gbestpop[0])
            self.py.append(gbestpop[1])
        return result, self.px, self.py
 
    def drawPaht(self,X, Y, Z, px, py, pz):
        """
        繪圖
        """
        fig = plt.figure()
        ax = Axes3D(fig)
        plt.title("PSO")
        ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color='b', )
        ax.set_xlabel('x label', color='r')
        ax.set_ylabel('y label', color='g')
        ax.set_zlabel('z label', color='b')
        ax.plot(px, py, pz, 'r.')  # 繪點x
        plt.show()
 
 
def f(X, Y):
    return np.sin(np.sqrt(X ** 2 + Y ** 2)) / np.sqrt(X ** 2 + Y ** 2) + np.exp(
        (np.cos(2 * np.pi * X) + np.cos(2 * np.pi * Y)) / 2) - 2.71289
 
 
pso = PSO()
result, px, py = pso.run()
print(max(result), result.argmax())
 
plt.plot(result)
 
X = np.arange(-2, 2, 0.05)
Y = np.arange(-2, 2, 0.05)
X, Y = np.meshgrid(X, Y)
Z = f(X, Y)
pso.drawPaht(X, Y, Z, px, py, f(np.array(px), np.array(py)))
plt.show()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章