粒子群(PSO)算法最早是由美国电气工程师Eberhart和社会心理学家Kennedy在1995年基于群鸟觅食提出来的。
群鸟觅食其实是一个最佳决策的过程, 与人类决策的过程相似。Boyd和Re chars on探索了人类的决策过程,并提出了个体学习和文化传递的概念。根据他们的研究成果,人们在决策过程中常常会综合两种重要的信息:第一种是他们自己的经验,即他们根据以前自己的尝试和经历,已经积累了一定的经验,知道怎样的状态会比较好;第二种是其他人的经验,即从周围人的行为获取知识,从中知道哪些选择是正面的,哪些选择是消极的。
同样的道理,群鸟在觅食的过程中,每只鸟的初始状态都处于随机位置,且飞翔的方向也是随机的。每只鸟都不知道食物在哪里,但是随着时间的推移,这些初始处于随机位置的鸟类通过群内相互学习、信息共享和个体不断积累字觅食物的经验,自发组织积聚成一个群落,并逐渐朝唯一的目标-—食物前进。每只鸟能够通过一定经验和信息估计目前所处的位置对于能寻找到食物有多大的价值,即多大的适应值;每只鸟能够记住自己所找到的最好位置,称之为局部最优(p best) 。此外, 还能记住群鸟中所有个体所能找到的最好位置, 称为全局最优(g best) , 整个鸟群的觅食中心都趋向全局最优移动, 这在生物学上称之为“同步效应”。通过鸟群觅食的位置不断移动,即不断迭代,可以使鸟群朝食物步步进逼。
在群鸟觅食模型中,每个个体都可以被看成一个粒子,则鸟群可以被看成一个粒子群。假设在一个D维的目标搜索空间中,有m个粒子组成一个群体,其中第i个粒子(i=1,2,…,m)位置表示为 X i = ( x i 1 , x i 2 , … , x i D ) X_{i}=(x_{i}^{1},x_{i}^{2},…,x_{i}^{D}) Xi=(xi1,xi2,…,xiD),即第i个粒子在D维搜索空间中的位置是 X i X_{i} Xi。换言之,每个粒子的位置就是一个潜在解,将X,代人目标函数就可以计算出其适应值,根据适应值的大小衡量其优劣。粒子个体经历过的最好位置记为 P i = ( P i 1 , P i 2 , … , P i D ) P_{i}=(P_{i}^{1},P_{i}^{2},…,P_{i}^{D}) Pi=(Pi1,Pi2,…,PiD),整个群体所有粒子经历过的最好位置记为 P g = ( p g 1 , p g 2 , … , p g D ) P_{g}=(p_{g}^{1},p_{g}^{2},…,p_{g}^{D}) Pg=(pg1,pg2,…,pgD)。粒子i的速度记为 V i = ( v i 1 , v i 2 , … , v i D ) V_{i}=(v_{i}^{1},v_{i}^{2},…,v_{i}^{D}) Vi=(vi1,vi2,…,viD)。
粒子群算法采用下列公式对粒子所在的位置不断更新(单位时间1):
v i d = ω v i d + c 1 r 1 ( p i d − x i d ) + c 2 r 2 ( p g d − x i d ) ( 8 − 1 ) v_{i}^{d}=\omega v_{i}^{d}+c_{1}r_{1}(p_{i}^{d}-x_{i}^{d})+ c_{2}r_{2}(p_{g}^{d}-x_{i}^{d}) (8-1) vid=ωvid+c1r1(pid−xid)+c2r2(pgd−xid)(8−1)
x i d = x i d + α v i d ( 8 − 2 ) x_{i}^{d}= x_{i}^{d}+\alpha v_{i}^{d} (8-2) xid=xid+αvid(8−2)
其中,i=1,2,…m;d=1,2,…,D;w是非负数、称为惯性因子;加速常数c:和ca是非负常数; r 1 r_{1} r1和 r 2 r_{2} r2是[0,1]范围内变换的随机数;α称为约束因子,目的是控制速度的权重。
此外, v i d ∈ [ − v m a x d , v m a x d ] v_{i}^{d}\in [-v_{max}^{d},v_{max}^{d}] vid∈[−vmaxd,vmaxd] 即粒子i的飞翔速度V, 被一个最大速度 V m a x = ( v m a x 1 , v m a x 2 , … , v m a x D ) V_{max}=(v_{max}^{1},v_{max}^{2},…,v_{max}^{D}) Vmax=(vmax1,vmax2,…,vmaxD)所限制。如果当前时刻粒子在某维的速度 v 1 d v_{1}^{d} v1d更新后超过该维的最大飞翔速度 v m a x d v_{max}^{d} vmaxd则当前时刻该维的速度被限制在 v m a x d v_{max}^{d} vmaxd 。 v m a x v_{max} vmax为常数, 可以根据不同的优化问题设定。
迭代终止条件根据具体问题设定,一般达到预订最大迭代次数或粒子群且前为止搜索到的最优位置满足目标函数的最小允许误差。
近年来, 一些学者将PSO算法推广到约束优化问题,其关键在于如何处理好约束, 即解的可行性。如果约束处理得不好,其优化的结果往往会出现不能收敛和结果是空集的状况。基于PSO算法的约束优化工作主要分为两类:
Parsopoulos等采用罚函数法,利用非固定多段映射函数对约束优化问题进行转
图解Python数据结构与算法-实战篇
PSO算法的搜索性能取决于其全局探索和局部细化的平衡,这在很大程度上依赖于算法的控制参数,包括粒子群初始化、惯性因子w、最大飞翔速度 v m a x v_{max} vmax和加速常数 c 1 c_{1} c1与 c 2 c_{2} c2等。PSO算法具有以下优点:
同时, PSO算法的缺点也是显而易见的:
1)算法局部搜索能力较差,搜索精度不够高。
2)算法不能绝对保证搜索到全局最优解,主要有两方面的原因:
①有时粒子群在俯冲过程中会错失全局最优解。粒子飞翔过程中的俯冲动作使搜索行为不够精细,不容易发现全局最优目标值,所以对粒子的最大飞翔速度进行限制既是为了使粒子不要冲出搜索区域的边界,同时也是为了使搜索行为不至于太粗糙。
②应用PSO算法处理高维复杂问题时,算法可能会早熟收敛,也就是粒子群在没有找到全局最优信息之前就陷入停顿状态,飞翔的动力不够,粒子群丧失了多样性,各粒子之间的抱合力增强,紧紧地聚集在一起,并且它们的飞翔速度几乎为零,虽然此时粒子距离全局最优解并不远,但是几乎为零的飞翔速度使其跳出停滞不前的状态,各个粒子力不从心。这些停滞不前的早熟点未必都是局部最优点,也可能是位于局部最优点邻域内的其他点,这一点与梯度搜索法不同,梯度搜索法如果出现早熟,通常只会陷人局部最优点,而不可能陷人局部最优点邻域内的其他点,这一点与梯度搜索算法不同,梯度搜索算法如果出现早熟,通常只会陷入局部最优点,而·不可能陷入局部最优点领域内的其它点。
3)算法搜索性能对参数具有一定的依赖性。对于特定的优化问题,如果用户经验不足,参数调整的确是个棘手的问题。参数值的大小直接影响到算法是否收敛以及求解结果的精度。
4)PSO算法是一种概率算法,算法理论不完善,缺乏独特性,理论成果偏少。从数学角度严格证明算法结果的正确性和可靠性还比较困难;缺少算法结构设计和参数选取的实用性指导原则,特别是全局收敛研究和大型多约束非线性规划的研究成果非常少。
PSO算法实现的流程图如下图所示:
import numpy as np
import matplotlib.pyplot as plt
class PSO(object):
def __init__(self, population_size, max_steps):
self.w = 0.6 # 惯性权重
self.c1 = self.c2 = 2
self.population_size = population_size # 粒子群数量
self.dim = 2 # 搜索空间的维度
self.max_steps = max_steps # 迭代次数
self.x_bound = [-10, 10] # 解空间范围
self.x = np.random.uniform(self.x_bound[0], self.x_bound[1],
(self.population_size, self.dim)) # 初始化粒子群位置
self.v = np.random.rand(self.population_size, self.dim) # 初始化粒子群速度
fitness = self.calculate_fitness(self.x)
self.p = self.x # 个体的最佳位置
self.pg = self.x[np.argmin(fitness)] # 全局最佳位置
self.individual_best_fitness = fitness # 个体的最优适应度
self.global_best_fitness = np.min(fitness) # 全局最佳适应度
def calculate_fitness(self, x):
return np.sum(np.square(x), axis=1)
def evolve(self):
fig = plt.figure()
for step in range(self.max_steps):
r1 = np.random.rand(self.population_size, self.dim)
r2 = np.random.rand(self.population_size, self.dim)
# 更新速度和权重
self.v = self.w*self.v+self.c1*r1*(self.p-self.x)+self.c2*r2*(self.pg-self.x)
self.x = self.v + self.x
plt.clf()
plt.scatter(self.x[:, 0], self.x[:, 1], s=30, color='k')
plt.xlim(self.x_bound[0], self.x_bound[1])
plt.ylim(self.x_bound[0], self.x_bound[1])
plt.pause(0.01)
fitness = self.calculate_fitness(self.x)
# 需要更新的个体
update_id = np.greater(self.individual_best_fitness, fitness)
self.p[update_id] = self.x[update_id]
self.individual_best_fitness[update_id] = fitness[update_id]
# 新一代出现了更小的fitness,所以更新全局最优fitness和位置
if np.min(fitness) < self.global_best_fitness:
self.pg = self.x[np.argmin(fitness)]
self.global_best_fitness = np.min(fitness)
print('best fitness: %.5f, mean fitness: %.5f' % (self.global_best_fitness, np.mean(fitness)))
pso = PSO(100, 100)
pso.evolve()
plt.show()
《matlab在数学建模中的应用》