一群鸟在随机搜索食物,在这个区域里只有一块食物。所有的鸟都不知道食物在那里。但是它们知道当前的位置离食物还有多远。那么,找到食物的最简单有效的方法就是搜寻离食物最近的鸟的周围区域。如果将鸟抽象为没有体积和质量的“粒子”,相当于问题的一个解,鸟群就相当于一个解集,离食物最近的鸟相当于解群中的最优粒子,食物的位置相当于全局最优解。
粒子群算法是由 Kennedy 和 Eberhart 等通过模拟鸟群的觅食行为而提出的一种基于群体协作的随机搜索算法。标准粒子群算法搜索寻优的基本框架如图 所示:
每个粒子具有两个属性:
粒子位置 x
粒子速度 v
假设在一个 D 维的目标搜索空间中,有 N 个粒子组成一个群落。则:
第 i 粒子的位置为一个 D 维向量,表示为:
整个粒子群迄今为止搜索到的最优位置为全局极值,表示为:
每个粒子追随当前的最优粒子在解空间中运动,并根据如下公式来更新自己的速度和位置:
速度变换公式:
位置变换公式为:
其中,w 为惯性权值;c1 和 c2 为学习因子,分别反映粒子的自我学习能力和向群体 最 优 粒 子学 习 的 能 力 ; r1 和 r2 为 [0,1] 的 均 匀 随 机数 ;vi为 粒 子 速 度,vi属于[-vmax,vmax],vmax是用户设定的一个常量,用来限制粒子的速度。
公式中,第一部分是粒子先前的速度与惯性权值的积,用来保证算法的全局
收敛性,第二部分是粒子自身的学习能力,第三部分是粒子的社会学习能力,表示粒子之间的信息共享与相互协作,第二、三部分是引起粒子速度变化的社会因素,使其在最优解附近具有局部搜索的能力。
基于上述流程,标准粒子群算法的具体步骤可描述如下:
步骤 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:根据公式(2-1),(2-2)更新粒子的速度 vi 和位置 xi ;
步骤 6:判断是否达到停止准则,如果达到设置的搜索精度或达到最大迭代次
数则退出,否则返回步骤 2。
# coding: utf-8
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
##输出
#程序
my_pso = PSO(pN=30, dim=1, max_iter=100)
my_pso.init_Population()
fitness = my_pso.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=3)
plt.show()