粒子群算法也称粒子群优化算法PSO(Particle Swarm Optimization),属于进化算法EA(Evolutionary Algorithm)的一种,实现容易、精度高、收敛快,是一种并行算法。它是从随机解出发,通过迭代寻找最优解,也是通过适应度来评价解的品质,它通过追随当前搜索到的最优值来寻找全局最优。
算法原理
设x为粒子起始位置,v为粒子飞行速度,p为搜索到的粒子的最优位置。
PSO初始化为一群随机粒子,然后通过迭代找到最优解。在每一次迭代中,粒子通过跟踪两个极值来更新自己:第一个就是粒子本身所找到的最优解,这个解称为个体极值pbest;另一个极值是整个种群目前找到的最优解,这个极值是全局极值gbest。粒子始终跟随这两个极值并在每一次迭代中更新自己的位置和速度,直到找到最优解。
具体如下:
假设在一个D维的目标搜索空间中,有N个粒子组成一个群落,其中第i个粒子为一个D维向量:
第i个粒子的飞行速度也是一个D维向量:
第i个粒子迄今为止搜索到的最优位置,即个体极值Pbest:
整个粒子群迄今为止搜索到的最优位置,即全局极值Gbest:
在找到这两个最优值时,粒子根据如下公式来更新自己的速度和位置:
其中,c1、c2为学习因子,也称加速常数(acceleration constant);r1、r2为[0,1]范围内的均匀随机数。
第一个公式右侧包括三部分,
-
第1部分为惯性inertia或动量momentum,代表了粒子有维持自己先前速度的趋势;
-
第2部分为认知cognition,反映了粒子对自己历史经验的记忆或回忆,代表粒子有向自身历史最佳位置逼近的趋势;
-
第3部分为社会social,反映了粒子间协同合作与知识共享的群体历史经验,代表粒子有向群体或邻近历史最佳位置逼近的趋势。
算法流程
- 初始化粒子群,包括群体规模N、每个粒子的位置xi和速度vi计算每个粒子的适应度值Fit[i]
- 对每个粒子,用它的适应度值Fit[i]和个体极值pbest(i)比较,如果Fit[i]>pbest(i),则用Fit[i]替换掉 pbest(i)
- 对每个粒子,用其适应度Fit[i]和全局极值gbest(i)比较,如果Fit[i]>gbest(i),则用Fit[i]替换掉gbest(i)
- 根据公式更新粒子的位置xi和速度vi
- 如果满足结束条件,误差足够好或达到最大循环次数,退出,否则返回2
代码实现
import numpy as npimport matplotlib.pyplot as plt'''******************************目标函数***********************************'''# 目标函数 , 同时也将他设定为 适应度函数 (一维)def get_fitness(x):y = -x**2 - 8*x -1return y'''******************************初始化***********************************'''# ************************初始化简单参数*************************************w = 0.8 #惯性因子c1 = 2 #自身认知因子c2 = 2 #社会认知因子r1 = 0.6 #自身认知学习率r2 = 0.3 #社会认知学习率pN = 100 #粒子数量dim = 1 #搜索维度max_iter = 1000 #最大迭代次数X = np.zeros((pN, dim)) #初始粒子的位置V = np.zeros((pN, dim)) #初始粒子的速度p_best = np.zeros((pN, dim), dtype = float) #单个粒子的历史最佳位置g_best = np.zeros((1, dim), dtype = float) #全局最佳位置p_bestfit = np.zeros(pN) #单个粒子的历史最佳适应值g_bestfit = -1e15 #全局最佳适应值# *********************初始化个体和全局的最优解********************************for i in range(pN):#初始化每一个粒子的位置和速度X[i] = np.random.uniform(0,5,[1, dim])V[i] = np.random.uniform(0,5,[1, dim])# 得到初始时的每一个粒子的历史最佳位置(暂且将第一次给的值定为最佳位置)p_best[i] = X[i]p_bestfit[i] = get_fitness(X[i]) #得到对应的fit值# 得到初始时的全局最佳位置和相应的适应度值(每遍历一个粒子就更新一次)# (这里不直接用max函数求最大值是因为不一定下一个粒子比前一个粒子更优,从而导致冗余计算。下面的那个for循环同理)g_bestfit = max(p_bestfit)g_best = max(p_best) #得到全局最佳位置'''***************************迭代***********************************#'''fitness = [] #记录每次迭代的最优解,画图时用for _ in range(max_iter):# 更新每个粒子的位置和速度for i in range(pN):# 更新g_best 和 p_besttemp = get_fitness(X[i]) #获得当前位置的适应值if temp > p_bestfit[i]: #先更新个体最优p_bestfit[i] = tempp_best[i] = X[i]if p_bestfit[i] > g_bestfit: #再更新全局最优 (注意:这里不直接用max函数求最大值是因为最外面还有一层max_iter迭代循环,从而更容易导致冗余计算;而初始化时的那重循环外面再无循环层,所以即使使用max函数也不会造成什么冗余。)g_best = X[i]g_bestfit = p_bestfit[i]V[i] = w*V[i] + c1*r1*(p_best[i] - X[i]) + c2*r2*(g_best - X[i])X[i] = X[i] + V[i]'''# 这样写没错,可以代替上面的那层if语句,但不能这样写,因为最外面还有一重max_iter循环,如果下一次迭代不比当前最优解还好的话,就造成了max函数计算冗余g_bestfit = max(p_bestfit)g_best = max(p_best)'''fitness.append(g_bestfit) # 记录每次迭代后找到的全局最优解print(g_best, g_bestfit)'''***************************画图***********************************#'''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, max_iter)])fitness = np.array(fitness)plt.plot(t, fitness, color='b', linewidth=3)plt.show()import numpy as np import matplotlib.pyplot as plt ''' ******************************目标函数*********************************** ''' # 目标函数 , 同时也将他设定为 适应度函数 (一维) def get_fitness(x): y = -x**2 - 8*x -1 return y ''' ******************************初始化*********************************** ''' # ************************初始化简单参数************************************* w = 0.8 #惯性因子 c1 = 2 #自身认知因子 c2 = 2 #社会认知因子 r1 = 0.6 #自身认知学习率 r2 = 0.3 #社会认知学习率 pN = 100 #粒子数量 dim = 1 #搜索维度 max_iter = 1000 #最大迭代次数 X = np.zeros((pN, dim)) #初始粒子的位置 V = np.zeros((pN, dim)) #初始粒子的速度 p_best = np.zeros((pN, dim), dtype = float) #单个粒子的历史最佳位置 g_best = np.zeros((1, dim), dtype = float) #全局最佳位置 p_bestfit = np.zeros(pN) #单个粒子的历史最佳适应值 g_bestfit = -1e15 #全局最佳适应值 # *********************初始化个体和全局的最优解******************************** for i in range(pN): #初始化每一个粒子的位置和速度 X[i] = np.random.uniform(0,5,[1, dim]) V[i] = np.random.uniform(0,5,[1, dim]) # 得到初始时的每一个粒子的历史最佳位置(暂且将第一次给的值定为最佳位置) p_best[i] = X[i] p_bestfit[i] = get_fitness(X[i]) #得到对应的fit值 # 得到初始时的全局最佳位置和相应的适应度值(每遍历一个粒子就更新一次) # (这里不直接用max函数求最大值是因为不一定下一个粒子比前一个粒子更优,从而导致冗余计算。下面的那个for循环同理) g_bestfit = max(p_bestfit) g_best = max(p_best) #得到全局最佳位置 ''' ***************************迭代***********************************# ''' fitness = [] #记录每次迭代的最优解,画图时用 for _ in range(max_iter): # 更新每个粒子的位置和速度 for i in range(pN): # 更新g_best 和 p_best temp = get_fitness(X[i]) #获得当前位置的适应值 if temp > p_bestfit[i]: #先更新个体最优 p_bestfit[i] = temp p_best[i] = X[i] if p_bestfit[i] > g_bestfit: #再更新全局最优 (注意:这里不直接用max函数求最大值是因为最外面还有一层max_iter迭代循环,从而更容易导致冗余计算;而初始化时的那重循环外面再无循环层,所以即使使用max函数也不会造成什么冗余。) g_best = X[i] g_bestfit = p_bestfit[i] V[i] = w*V[i] + c1*r1*(p_best[i] - X[i]) + c2*r2*(g_best - X[i]) X[i] = X[i] + V[i] ''' # 这样写没错,可以代替上面的那层if语句,但不能这样写,因为最外面还有一重max_iter循环,如果下一次迭代不比当前最优解还好的话,就造成了max函数计算冗余 g_bestfit = max(p_bestfit) g_best = max(p_best) ''' fitness.append(g_bestfit) # 记录每次迭代后找到的全局最优解 print(g_best, g_bestfit) ''' ***************************画图***********************************# ''' 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, max_iter)]) fitness = np.array(fitness) plt.plot(t, fitness, color='b', linewidth=3) plt.show()import numpy as np import matplotlib.pyplot as plt ''' ******************************目标函数*********************************** ''' # 目标函数 , 同时也将他设定为 适应度函数 (一维) def get_fitness(x): y = -x**2 - 8*x -1 return y ''' ******************************初始化*********************************** ''' # ************************初始化简单参数************************************* w = 0.8 #惯性因子 c1 = 2 #自身认知因子 c2 = 2 #社会认知因子 r1 = 0.6 #自身认知学习率 r2 = 0.3 #社会认知学习率 pN = 100 #粒子数量 dim = 1 #搜索维度 max_iter = 1000 #最大迭代次数 X = np.zeros((pN, dim)) #初始粒子的位置 V = np.zeros((pN, dim)) #初始粒子的速度 p_best = np.zeros((pN, dim), dtype = float) #单个粒子的历史最佳位置 g_best = np.zeros((1, dim), dtype = float) #全局最佳位置 p_bestfit = np.zeros(pN) #单个粒子的历史最佳适应值 g_bestfit = -1e15 #全局最佳适应值 # *********************初始化个体和全局的最优解******************************** for i in range(pN): #初始化每一个粒子的位置和速度 X[i] = np.random.uniform(0,5,[1, dim]) V[i] = np.random.uniform(0,5,[1, dim]) # 得到初始时的每一个粒子的历史最佳位置(暂且将第一次给的值定为最佳位置) p_best[i] = X[i] p_bestfit[i] = get_fitness(X[i]) #得到对应的fit值 # 得到初始时的全局最佳位置和相应的适应度值(每遍历一个粒子就更新一次) # (这里不直接用max函数求最大值是因为不一定下一个粒子比前一个粒子更优,从而导致冗余计算。下面的那个for循环同理) g_bestfit = max(p_bestfit) g_best = max(p_best) #得到全局最佳位置 ''' ***************************迭代***********************************# ''' fitness = [] #记录每次迭代的最优解,画图时用 for _ in range(max_iter): # 更新每个粒子的位置和速度 for i in range(pN): # 更新g_best 和 p_best temp = get_fitness(X[i]) #获得当前位置的适应值 if temp > p_bestfit[i]: #先更新个体最优 p_bestfit[i] = temp p_best[i] = X[i] if p_bestfit[i] > g_bestfit: #再更新全局最优 (注意:这里不直接用max函数求最大值是因为最外面还有一层max_iter迭代循环,从而更容易导致冗余计算;而初始化时的那重循环外面再无循环层,所以即使使用max函数也不会造成什么冗余。) g_best = X[i] g_bestfit = p_bestfit[i] V[i] = w*V[i] + c1*r1*(p_best[i] - X[i]) + c2*r2*(g_best - X[i]) X[i] = X[i] + V[i] ''' # 这样写没错,可以代替上面的那层if语句,但不能这样写,因为最外面还有一重max_iter循环,如果下一次迭代不比当前最优解还好的话,就造成了max函数计算冗余 g_bestfit = max(p_bestfit) g_best = max(p_best) ''' fitness.append(g_bestfit) # 记录每次迭代后找到的全局最优解 print(g_best, g_bestfit) ''' ***************************画图***********************************# ''' 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, max_iter)]) fitness = np.array(fitness) plt.plot(t, fitness, color='b', linewidth=3) plt.show()
运行结果
很明显对于函数y = -x**2 - 8*x -1
,当x=-4
时取最大值y=15