一群鸟在随机搜索食物,在该区域内只有一块食物。所有的鸟都不知道食物在哪里。但是它们知道当前的位置距离食物还有多远。那么,找到食物最简单有效的方法——就是搜寻离食物最近的鸟的周围区域。如果将鸟抽象为没有体积和质量的“粒子”,相当于问题的一个解,鸟群就相当于一个解集,距离食物最近的鸟相当于解集中的最优粒子,食物的位置相当于全局最优解。
基本原理
PSO是由Kennedy和Eberhart等通过模拟鸟群的觅食行为而提出的一种基于群体协作的随机搜索算法。
标准粒子群算法搜索寻优过程如图1所示:
图1 标准粒子群算法搜索寻优过程
每个粒子有2个属性:粒子位置x,例子速度v。假设在一个D维的目标空间中,有N个粒子组成一个群落。则有:
第i个粒子的位置为一个D维向量:
第i个粒子的飞行速度为一个D维向量:
第i个粒子至目前为止搜索到的最优位置为个体极值:
整个粒子群至目前为止搜索到的最优位置为全局极值:
每个粒子追随当前的最优粒子在解空间中运动,并根据如下公式更新自己的位置和速度:
速度变换:
位置变换:
其中,w为惯性权值;c1和c2为学习因子,分别反映粒子的自我学习能力和向群体最优粒子学习的能力;r1和r2为[0,1]的均匀随机数;vi为粒子速度,vi属于[-vmax,vmax],vmax是用户设定的一个常量,用来限制粒子的速度。
公式中,(1)是粒子先前的速度与惯性权值的积,用来保证算法的全局收敛性,(2)是粒子自身的学习能力,(3)是粒子的社会学习能力,表示粒子之间的信息共享与相互协作。(2)和(3)是引起粒子速度变化的社会因素,使其在最优解附近具有局部搜索的能力。
算法步骤
标准粒子群算法的具体步骤如下:
(1)在可行域中随机初始化一群粒子,包括粒子的规模N、位置xi和速度vi;
(2)根据目标函数计算每个粒子的适应度值Fit[i];
(3)比较每个粒子的适应度值Fit[i]与个体极值Pbest[i]
若Fit[i]>Pbest[i],则用Fit[i]替换Pbest[i];
(4)比较每个粒子的适应度值[i]itF与当前的全局极值gbest[i],
若Fit[i]>gbest[i],则用Fit[i]替换gbest[i];
(5)根据公式更新粒子的速度vi和位置xi;
(6)判断是否达到停止准则,如果达到设置的搜索精度或达到最大迭代次数则退出,否则返回(2)。
代码实现
import numpy as np
import random
import matplotlib.pyplot as plt
class PSO():
# PSO参数设置
def __init__(self, pN, dim, max_iter):
self.w = 0.8
self.c1 = 2
self.c2 = 2
self.r1 = 0.6
self.r2 = 0.3
self.pN = pN # 粒子数量
self.dim = dim # 搜索维度
self.max_iter = max_iter # 迭代次数
self.X = np.zeros((self.pN, self.dim)) # 所有粒子的位置和速度
self.V = np.zeros((self.pN, self.dim))
self.pbest = np.zeros((self.pN, self.dim)) # 个体经历的最佳位置和全局最佳位置
self.gbest = np.zeros((1, self.dim))
self.p_fit = np.zeros(self.pN) # 每个个体的历史最佳适应值
self.fit = 1e10 # 全局最佳适应值
#目标函数:Sphere函数
def function(self, X):
return X**4-2*X+3
#初始化种群
def init_Population(self):
for i in range(self.pN): #因为要随机生成pN个数据,所以需要循环pN次
for j in range(self.dim): #每一个维度都需要生成速度和位置,故循环dim次
self.X[i][j] = random.uniform(0, 1)
self.V[i][j] = random.uniform(0, 1)
self.pbest[i] = self.X[i] #初始化self.pbest值
tmp = self.function(self.X[i]) #得到现在最优
self.p_fit[i] = tmp 这个个体历史最佳的位置
if tmp < self.fit: #得到现在最优和历史最优比较,如果现在最优大于历史最优,则更新历史最优
self.fit = tmp
self.gbest = self.X[i]
# 更新粒子位置
def iterator(self):
fitness = []
for t in range(self.max_iter): #迭代次数,不是越多越好
for i in range(self.pN): # 更新gbest\pbest
temp = self.function(self.X[i])
if temp < self.p_fit[i]: # 更新个体最优
self.p_fit[i] = temp
self.pbest[i] = self.X[i]
if self.p_fit[i] < self.fit: # 更新全局最优
self.gbest = self.X[i]
self.fit = self.p_fit[i]
for i in range(self.pN):
self.V[i] = self.w * self.V[i] + self.c1 * self.r1 * (self.pbest[i] - self.X[i]) + \
self.c2 * self.r2 * (self.gbest - self.X[i])
self.X[i] = self.X[i] + self.V[i]
fitness.append(self.fit)
print(self.X[0], end=" ")
print(self.fit) # 输出最优值
return fitness
testpso = PSO(pN=30, dim=1, max_iter=100)
testpso.init_Population()
fitness = testpso.iterator()
# 画图
plt.figure(1)
plt.title("Figure1")
plt.xlabel("iterators", size=14)
plt.ylabel("fitness", size=14)
t = np.array([t for t in range(0, 100)])
fitness = np.array(fitness)
plt.plot(t, fitness, color='b', linewidth=1)
plt.show()