1. 基本思想
粒子群优化算法(PSO)是一种进化计算技术,由Eberhart博士和kennedy博士于1995年提出。源于对鸟群捕食的行为研究。
基本思想:
一个由多个个体组成的群体对多维搜索空间进行搜索,每个个体在搜索时,考虑到了自己搜索到的历史最好点和群体内(或邻域内)其他个体的历史最好点,在此基础上进行位置(状态,也就是解)的变化.
2.标准PSO
2. 算法构成要素
• 群体大小: m
m是个整型参数。当m很小的时候,陷入局优的可能性很大。然而,群体过大将导致计算时间的大幅增加。并且当群体数目增长至一定水平时,再增长将不再有显著的作用。当m =1的时候, PSO算法变为基于个体搜索的技术,一旦陷入局优,将不可能跳出。当m很大时, PSO的优化能力很好,可是收敛的速度将非常慢。
• 学习因子: c1和c2
学习因子使粒子具有自我总结和向群体中优秀个体学习的能力,从而向群体内或邻域内最优点靠近。 c1和c2通常等于2,不过在文献中也有其他的取值。但是一般c1等于c2,并且范围在0和4之间。
• 最大速度: Vmax 一般设定为变量范围
• 惯性权重
智能优化方法的运行是否成功, 探索能力(全局搜索) 和开发能力(局部搜索)的平衡是非常关键的。对于粒子群优化算法来说,这两种能力的平衡就是靠惯性权重来实现.
3.代码(求解多项式的最大值,最小值问题)
# -*- coding: utf-8 -*-
"""
Created on Sat Aug 11 18:19:18 2018
@author: jj
"""
import numpy as np
import matplotlib.pyplot as plt
import random
'''
* ━━━━━━神兽出没━━━━━━
* ┏┓ ┏┓
* ┏┛┻━━━┛┻┓
* ┃ ┃
* ┃ ━ ┃
* ┃ ┳┛ ┗┳ ┃
* ┃ ┃
* ┃ ┻ ┃
* ┃ ┃
* ┗━┓ ┏━┛Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*
* ━━━━━━感觉萌萌哒━━━━━━
'''
# 定义“粒子”类
class parti(object):
def __init__(self, v, x):
self.v = v # 粒子当前速度
self.x = x # 粒子当前位置
self.pbest = x # 粒子历史最优位置
class PSO(object):
def __init__(self, interval, tab, partisNum=10, iterMax=1000, w=1, c1=2, c2=2):
self.interval = interval # 给定状态空间 - 即待求解空间
self.tab = tab # 求解最大值还是最小值的标签: 'min' - 最小值;'max' - 最大值
self.iterMax = iterMax # 最大迭代求解次数
self.w = w # 惯性因子
self.c1, self.c2 = c1, c2 # 学习因子
self.v_max = (interval[1] - interval[0]) * 0.1 # 设置最大迁移速度
self.partis_list, self.gbest = self.initPartis(partisNum) # 完成粒子群的初始化,并提取群体历史最优位置
self.x_seeds = np.array(list(parti_.x for parti_ in self.partis_list)) # 提取粒子群的种子状态
self.solve() # 完成主体的求解过程
self.display() # 数据可视化展示
def initPartis(self, partisNum):
partis_list = list()
for i in range(partisNum):
v_seed = random.uniform(-self.v_max, self.v_max)
x_seed = random.uniform(*self.interval)
partis_list.append(parti(v_seed, x_seed)) #确定目标找最大值还是最小值
temp = 'find_' + self.tab
if hasattr(self, temp):
gbest = getattr(self, temp)(partis_list)
else:
exit('>>>tab标签传参有误:"min"|"max"<<<')
return partis_list, gbest
def solve(self):
for i in range(self.iterMax):
for parti_c in self.partis_list:
f1 = self.func(parti_c.x)
# 更新粒子速度,并限制在最大迁移速度之内
parti_c.v = self.w * parti_c.v + self.c1 * random.random() * (parti_c.pbest - parti_c.x) + self.c2 * random.random() * (self.gbest - parti_c.x)
if parti_c.v > self.v_max:
parti_c.v = self.v_max
elif parti_c.v < -self.v_max:
parti_c.v = -self.v_max
# 更新粒子位置,并限制在待解空间之内
if self.interval[0] <= parti_c.x + parti_c.v <=self.interval[1]:
parti_c.x = parti_c.x + parti_c.v
else:
parti_c.x = parti_c.x - parti_c.v
f2 = self.func(parti_c.x)
getattr(self, 'deal_'+self.tab)(f1, f2, parti_c) # 更新粒子历史最优位置与群体历史最优位置
def func(self, x): # 状态产生函数 - 即待求解函数
value = np.sin(x**2) * (x**2 - 5*x)
return value
def find_min(self, partis_list): # 按状态函数最小值找到粒子群初始化的历史最优位置
parti = min(partis_list, key=lambda parti: self.func(parti.pbest))
return parti.pbest
def find_max(self, partis_list):
parti = max(partis_list, key=lambda parti: self.func(parti.pbest)) # 按状态函数最大值找到粒子群初始化的历史最优位置
return parti.pbest
def deal_min(self, f1, f2, parti_):
if f2 < f1: # 更新粒子历史最优位置
parti_.pbest = parti_.x
if f2 < self.func(self.gbest):
self.gbest = parti_.x # 更新群体历史最优位置
def deal_max(self, f1, f2, parti_):
if f2 > f1: # 更新粒子历史最优位置
parti_.pbest = parti_.x
if f2 > self.func(self.gbest):
self.gbest = parti_.x # 更新群体历史最优位置
def display(self):
print('solution: {}'.format(self.gbest))
plt.figure(figsize=(8, 4))
x = np.linspace(self.interval[0], self.interval[1], 300)
y = self.func(x)
plt.plot(x, y, 'g-', label='function')
plt.plot(self.x_seeds, self.func(self.x_seeds), 'b.', label='seeds')
plt.plot(self.gbest, self.func(self.gbest), 'r*', label='solution')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('solution = {}'.format(self.gbest))
plt.legend()
plt.savefig('PSO.png', dpi=500)
plt.show()
plt.close()
if __name__ == '__main__':
PSO([-9, 5],'max')#此处选择模式和求解空间