粒子群优化算法

粒子群算法,也称粒子群优化算法或鸟群觅食算法(Particle Swarm Optimization),缩写为PSO,是由J. Kennedy和R. C. Eberhart等开发的一种新的进化算法(Evolutionary Algorithm -EA)[1]。PSO算法属于进化算法的一种,和模拟退火算法相似,它也是从随机解出发,通过迭代寻找最优解,它也是通过适应度来评价解的品质,但它比遗传算法规则更为简单,它没有遗传算法的“交叉”(Crossover)和“变异”(Mutation)操作,它通过追随当前搜索到的最优值来寻找全局最优。这种算法以其实现容易、精度高、收敛快等优点引起了学术界的重视,并且在解决实际问题中展示了其优越性。在 PSO 算法中,将鸟群中的个体称为“粒子”,可行域上的一个点代表食物源,即是个体(粒子)位置,也是所要优化问题的一个潜在解。在可行域中创建 N 个粒子,每个粒子的特征用位置、速度和适应度值表示。每个粒子在可行域中运动并计算得到适应度值,根据个体适应度最好值与群体适应度最好值更新个体位置,从而达到优化的目的[2]。该文首先介绍了标准粒子群算法的基本工作原理和算法迭代步骤,然后分别介绍了现今对粒子群算法的不同改进方法和算法在现实生活中的实际应用。在文章的结论中给出了粒子群算法下一步的研究方向。

标准粒子群算法

与其他的基于群体智能的算法相似,粒子群优化算法也是通过群体中不同粒子之间的相互合作和相互竞争来实现在寻优空间中的搜索过程以找到所求问题的最优位置。粒子群算法首先随机的初始化一群均匀分布在给定的寻优空间中的粒子(种群规模一般为30),然后所有的粒子根据两个极值来更新自身的速度:一个是个体极值( $pbest$ );另一个是群体极值($gbest$)。目前广泛使用的标准粒子群算法的数学描述为:设粒子群中粒子的总数为 popsize,粒子的维数为m,算法的终止条件(即最大迭代次数)为maxiter,第i个粒子在t时刻的飞行速度和在搜索空间中的位置分别为 $v_{i}(t)=[v_{i1}(t),v_{i2}(t),\cdots,v_{im}(t)]^T$, $x_{i}(t)=[x_{i1}(t),x_{i2}(t),\cdots,x_{im}(t)]^T$,粒子在t时刻的个体极值和群体极值分别为 $pbest_{i}(t)=[p_{i1}(t),p_{i2}(t),\cdots,p_{im}(t)]^T$, $gbest_{i}(t)=[g_{1},g_{2},\cdots,g_{m}]^T$ 所有的粒子按照如下的更新方式在搜索空间中飞行以找到最优解。
$$
\begin{aligned}
v_{i+1}(t+1)=wv_{i}(t)+c_{1}r_{1}(pbest_{i}(t)-x_{i}(t))+c_{2}r_{2}(gbest-x_{i}(t))
\end{aligned}
$$
$$
\begin{aligned}
x_{i+1}(t+1) = x_{i}(t)+v_{i+1}(t+1)
\end{aligned}
$$
其中,$ω$ 为惯性权重系数,决定了上次迭代速度保留的多少。它是粒子群算法的重要参数之一。在粒子群算法中,可以通过调节它的大小来平衡算法的全局搜索和局部搜索的能力。研究分析表明,在粒子群算法的算法初期,选择较大的惯性权重值可以使得算法有很强的全局搜索能力;而在粒子群算法的算法后期选择较小的惯性权重值可以使得粒子逐渐收敛到全局最优。因此,在很多改进的粒子群算法中,惯性权重采用了线性递减的方式进行更新。 $c1$ , $c2$ 为算法的学习因子,它们分别影响着粒子的“自我学习”能力和“社会学习”能力。一般认为,设置较大的 $c1$ ,会使得所有粒子过多的在局部范围内徘徊,不利于算法的全局搜索;而设置较大的 $c2$ ,则会使得粒子过早的陷入局部极值,降低解的精度。 $r1$ 和 $r2$ 是介于[0,1]之间的随机数。标准粒子群算法的流程可以描述如下。
(1)设置种群规模、变量范围、惯性权重、学习因子等参数,并随机的初始化一群均匀分布在给定的寻优空间中的粒子(包含速度和位置信息)。
(2)计算群体中各个粒子的适应度值(即函数值)。设置第 $i$ 个粒子的适应度值为它的当前个体极值 $pbest_{i}$,所有粒子中的最好粒子设置为群体的全体极值 $gbest$。
(3)根据公式(1)、(2)更新每个粒子的速度和位置。
(4)对所有粒子,将其当前的函数值与它以前 找到过的最好位 置进行比较,如果当前位置较好,则将个体最优位置 $pbest_{i}$ 设置为这个粒子的位置,然后再对群体的全局极值 $gbest$ 更新。
(5)判断给定的终止条件是否满足。若满足终止条件,停止搜索,输出需要的结果;否则,返回(3)继续搜索。

应用研究

从最初求解一些稍微简单的问题到更为复杂的问题,其发展趋势主要表现在:[3]
(1)PSO用于求解有约束的优化问题:2008年,刘伟等人基于参数方程利用粒子群算法求解含有等式约束的优化问题;2007年,曹春红等人利用粒子群算法求解几何约束问题;2008年,王金华等人利用粒子群算法求解约束离散优化问题;同年,魏静菅等基于模糊利用粒子群算法求解约束优化问题。
(2)PSO用于随机优化问题的求解:2006年,赵培忻等人利用粒子群算法求解随机装卸工问题;2007年,王芳等利用粒子群算法求解随机需求车辆路径问题;同年,李红梅等人研究了基于量子行为利用粒子群算法求解随机规划问题;陆琳,谭清美等人进行了利用粒子群算法求解随机需求VRP问题的研究。
(3)PSO用于最优控制问题的求解:孙凯等利用粒子群优化算法求解航天器太阳帆板伸展过程中,航天器姿态运动的最优控制问题;厉虹、张冰运用粒子群算法在线优化对模糊控制器的量化因子,获得平衡控制器参数的最优值;关圣涛等提出一种基于粒子群优化算法的非线性模型预测控制,在滚动优化部分应用粒子群优化算法求解预测控制律,对非线性系统施加优化控,实验效果良好;马昌喜等利用粒子群算法求解城市环路交通协调控制系统,效果良好。
(3)用于多目标优化:莫愿斌等利用粒子群算法求解多目标过程系统优化;贺益君等就补料分批生化反应器的动态多目标优化应用粒子群算法求解;张文明等针对水文模型的参数多目标优化应用粒子群算法求解;彭志平等针对协商僵局的多目标问题利用粒子群算法消解,其僵局解决能力明显比现有的其他方法强。
从以上的分析可以看出,从应用角度看粒子群算法应用于求解越来越复杂的问题,同时对粒子群算法的改进也越来越精细,优化性能也大大加强,但对算法优化性能的改进还没有结束,如何更精细、更简洁地改进算法,提高其性能,用于求解更多更复杂的问题,仍是一个研究的热点。[3]

参考文献

[1]Fukuyama Y. Fundamentals of particle swarm techniques [A]. Lee K Y , El2Sharkawi M A. Modern Heuristic Optimization Techniques With Applications to Power Systems [M]. IEEE Power Engineering Society , 2002. 45~51
[2]陈子廓, 史宪睿. 基于觅食生境选择的改进粒子群算法[J]. 辽宁工业大学学报:自然科学版, 2022, 42(1):3.
[3]莫愿斌,刘贺同,陈德钊,粒子群优化算法的发展趋势 TP 183; TQ 015.9; 06-39:A,1001-4160(2009)04-430-434
[4]杨维, 李歧强. 粒子群优化算法综述[J]. 中国工程科学, 2004, 006(005):87-94.
[5]屈新怀, 单笛, 孟冠军. 基于靠近目标粒子群算法的AGV路径规划[J]. 合肥工业大学学报:自然科学版.
[6]Ali F A , Selvan K T . A study of PSO and its variants in respect of microstrip antenna feed point optimization[J]. IEEE, 2009:1817-1820.


python代码

题目:

'''
粒子群算法实现
作者:LP
时间:2022年4月13日
参考:https://blog.csdn.net/qq_38048756/article/details/108945267
'''
import numpy as np

def fit_fun(x): # 适应函数
return sum(100.0 * (x[0][1:] - x[0][:-1] ** 2.0) ** 2.0 + (1 - x[0][:-1]) ** 2.0)


class Particle:
# 初始化
def __init__(self, x_max, max_vel, dim):
self.__pos = np.random.uniform(-x_max, x_max, (1, dim)) # 粒子的位置
self.__vel = np.random.uniform(-max_vel, max_vel, (1, dim)) # 粒子的速度
self.__bestPos = np.zeros((1, dim)) # 粒子最好的位置
self.__fitnessValue = fit_fun(self.__pos) # 适应度函数值

def set_pos(self, value):
self.__pos = value

def get_pos(self):
return self.__pos

def set_best_pos(self, value):
self.__bestPos = value

def get_best_pos(self):
return self.__bestPos

def set_vel(self, value):
self.__vel = value

def get_vel(self):
return self.__vel

def set_fitness_value(self, value):
self.__fitnessValue = value

def get_fitness_value(self):
return self.__fitnessValue


class PSO:
def __init__(self, dim, size, iter_num, x_max, max_vel, tol, best_fitness_value=float('Inf'), C1=2, C2=2, W=1):
self.C1 = C1
self.C2 = C2
self.W = W
self.dim = dim # 粒子的维度
self.size = size # 粒子个数
self.iter_num = iter_num # 迭代次数
self.x_max = x_max
self.max_vel = max_vel # 粒子最大速度
self.tol = tol # 截至条件
self.best_fitness_value = best_fitness_value
self.best_position = np.zeros((1, dim)) # 种群最优位置
self.fitness_val_list = [] # 每次迭代最优适应值

# 对种群进行初始化
self.Particle_list = [Particle(self.x_max, self.max_vel, self.dim) for i in range(self.size)]

def set_bestFitnessValue(self, value):
self.best_fitness_value = value

def get_bestFitnessValue(self):
return self.best_fitness_value

def set_bestPosition(self, value):
self.best_position = value

def get_bestPosition(self):
return self.best_position

# 更新速度
def update_vel(self, part):
vel_value = self.W * part.get_vel() + self.C1 * np.random.rand() * (part.get_best_pos() - part.get_pos()) + self.C2 * np.random.rand() * (self.get_bestPosition() - part.get_pos())
vel_value[vel_value > self.max_vel] = self.max_vel
vel_value[vel_value < -self.max_vel] = -self.max_vel
part.set_vel(vel_value)

# 更新位置
def update_pos(self, part):
pos_value = part.get_pos() + part.get_vel()
part.set_pos(pos_value)
value = fit_fun(part.get_pos())
if value < part.get_fitness_value():
part.set_fitness_value(value)
part.set_best_pos(pos_value)
if value < self.get_bestFitnessValue():
self.set_bestFitnessValue(value)
self.set_bestPosition(pos_value)

def update_ndim(self):

for i in range(self.iter_num):
for part in self.Particle_list:
self.update_vel(part) # 更新速度
self.update_pos(part) # 更新位置
self.fitness_val_list.append(self.get_bestFitnessValue()) # 每次迭代完把当前的最优适应度存到列表
print('第{}次最佳适应值为{}'.format(i, self.get_bestFitnessValue()))
if self.get_bestFitnessValue() < self.tol:
break

return self.fitness_val_list, self.get_bestPosition()

if __name__ == '__main__':
pso = PSO(4, 5, 10000, 30, 60, 1e-4, C1=2, C2=2, W=1)
fit_var_list, best_pos = pso.update_ndim()
print("最优位置:" + str(best_pos))
print("最优解:" + str(fit_var_list[-1]))

实验结果: