粒子群优化算法

一、概述

粒子群优化算法(Particle Swarm Optimization,PSO)的思想来源于对鸟捕食行为的模仿,最初,Reynolds.Heppner 等科学家研究的是鸟类飞行的美学和那些能使鸟群同时突然改变方向,分散,聚集的定律上,这些都依赖于鸟的努力来维持群体中个体间最佳距离来实现同步。而社会生物学家 E.O.Wilson 参考鱼群的社会行为认为从理论上说,在搜寻食物的过程中,尽管食物的分配不可知,群中的个体可以从群中其它个体的发现以及以往的经验中获益

粒子群从这种模型中得到启发并用于解决优化问题。如果我们把一个优化问题看作是在空中觅食的鸟群,那么粒子群中每个优化问题的潜在解都是搜索空间的一只鸟,称之为“粒子”(Particle),“食物”就是优化问题的最优解。每个粒子都有一个由优化问题决定的适应度用来评价粒子的“好坏”程度,每个粒子还有一个速度决定它们飞翔的方向和距离,它根据自己的飞行经验和同伴的飞行经验来调整自己的飞行。粒子群初始化为一群随机粒子(随机解),然后通过迭代的方式寻找最优解,在每一次的迭代中,粒子通过跟踪两个“极值”来更新自己,第一个是粒子本身所经历过的最好位置,称为个体极值即python导入粒子群算法库 python粒子群优化算法_算法;另一个是整个群体经历过的最好位置称为全局极值python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_02。每个粒子通过上述的两个极值不断更新自己,从而产生新一代的群体。

二、粒子群算法

算法的描述如下:

假设搜索空间是python导入粒子群算法库 python粒子群优化算法_开发语言_03维,并且群体中有python导入粒子群算法库 python粒子群优化算法_python_04个粒子。那么群体中的第python导入粒子群算法库 python粒子群优化算法_开发语言_05个粒子可以表示为一个python导入粒子群算法库 python粒子群优化算法_开发语言_03维的向量,python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_07,即第python导入粒子群算法库 python粒子群优化算法_开发语言_05个粒子在python导入粒子群算法库 python粒子群优化算法_开发语言_03维的搜索空间的位置是python导入粒子群算法库 python粒子群优化算法_算法_10,它所经历的“最好”位置记作python导入粒子群算法库 python粒子群优化算法_python_11。粒子的每个位置代表要求的一个潜在解,把它代入目标函数就可以得到它的适应度值,用来评判粒子的“好坏”程度。整个群体迄今为止搜索到的最优位置记作python导入粒子群算法库 python粒子群优化算法_优化问题_12python导入粒子群算法库 python粒子群优化算法_python_13是最优粒子位置的索引。

python导入粒子群算法库 python粒子群优化算法_开发语言_14

python导入粒子群算法库 python粒子群优化算法_python_15

python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_16为惯性权重(inertia weight),python导入粒子群算法库 python粒子群优化算法_开发语言_17为第python导入粒子群算法库 python粒子群优化算法_开发语言_05个粒子到第python导入粒子群算法库 python粒子群优化算法_算法_19代为止搜索到的历史最优解,python导入粒子群算法库 python粒子群优化算法_开发语言_20为整个粒子群到目前为止搜索到的最优解,python导入粒子群算法库 python粒子群优化算法_优化问题_21python导入粒子群算法库 python粒子群优化算法_优化问题_22分别是第python导入粒子群算法库 python粒子群优化算法_开发语言_05个粒子当前的位置和飞行速度,python导入粒子群算法库 python粒子群优化算法_优化问题_24为非负的常数,称为加速度因子,python导入粒子群算法库 python粒子群优化算法_开发语言_25python导入粒子群算法库 python粒子群优化算法_优化问题_26之间的随机数。

公式由三部分组成,第一部分是粒子当前的速度,表明了粒子当前的状态;第二部分是认知部分(Cognition Modal),表示粒子本身的思考(python导入粒子群算法库 python粒子群优化算法_优化问题_27也称为自身认知系数);第三部分是社会认知部分(Social Modal),表示粒子间的信息共享(python导入粒子群算法库 python粒子群优化算法_python_28为社会认知系数)。

参数的选择

粒子数目一般取30~50,参数python导入粒子群算法库 python粒子群优化算法_优化问题_24一般取2。适应度函数、粒子的维数和取值范围要视具体问题而定。问题解的编码方式通常可以采用实数编码。

算法的主要步骤如下

第一步:对粒子群的随机位置和速度进行初始设定,同时设定迭代次数。

第二步:计算每个粒子的适应度值。

第三步:对每个粒子,将其适应度值与所经历的最好位置python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_30的适应度值进行比较,若较好,则将其作为当前的个体最优位置。

第四步:对每个粒子,将其适应度值与全局所经历的最好位置python导入粒子群算法库 python粒子群优化算法_优化问题_31的适应度值进行比较,若较好,则将其作为当前的全局最优位置。

第五步:根据公式(1),(2)对粒子的速度和位置进行优化,从而更新粒子位置。

第六步:如未达到结束条件(通常为最大循环数或最小误差要求),则返回第二步。

三、基于粒子群算法的非线性函数寻优

本案例寻优的非线性函数为

python导入粒子群算法库 python粒子群优化算法_算法_32

python导入粒子群算法库 python粒子群优化算法_算法_33python导入粒子群算法库 python粒子群优化算法_算法_34时,该函数为Ackley函数,函数图形如图1所示。

python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_35

从函数图形可以看出,该函数有很多局部极小值,在python导入粒子群算法库 python粒子群优化算法_python_36处取到全局最小值0。

本案例群体的粒子数为20,每个粒子的维数为2,算法迭代进化次数为100。加速度因子python导入粒子群算法库 python粒子群优化算法_python_37python导入粒子群算法库 python粒子群优化算法_python_38,惯性权重python导入粒子群算法库 python粒子群优化算法_优化问题_39

引入的模块如下:

import numpy as np
import matplotlib.pyplot as plt

# 解决中文乱码和负号问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

适应度函数代码如下:

# 函数用于计算粒子适应度值
def funAckley(x):
    c = 20
    y = -1.0 * c * np.exp(-0.2 * np.sqrt((x[0] ** 2 + x[1] ** 2) / 2)) \
        - np.exp((np.cos(2 * np.pi * x[0]) + np.cos(2 * np.pi * x[1])) / 2) \
        + c + np.exp(1)
    return y

PSO算法代码如下:

c1, c2 = 1.4, 1.5  # 加速度因子
maxgen = 100  # 进化次数
sizepop = 20  # 群体规模
w = 0.1  # 惯性权重
Vmax, Vmin = 1, -1  # 速度最大值,最小值
popmax, popmin = 5, -5  # 个体最大值,最小值
pop = np.zeros([sizepop, 2])  # 种群
V = np.zeros([sizepop, 2])  # 速度
fitness = np.zeros(sizepop)  # 适应度
trace = np.zeros(maxgen)  # 结果

# 随机产生一个群体,初始粒子和速度
for i in range(sizepop):
    pop[i] = 5 * ((-2 * np.random.rand(1, 2) + 1))
    V[i] = (-2 * np.random.rand(1, 2) + 1)
    fitness[i] = funAckley(pop[i])

# 个体极值和群体极值
bestfitness = np.min(fitness)
bestindex = np.argmin(fitness)
Gbest = pop[bestindex]  # 全局最佳
fitnessGbest = bestfitness  # 全局最佳适应度值
Pbest = pop.copy()  # 个体最佳
fitnessPbest = fitness.copy()  # 个体最佳适应度值

# 迭代寻优
for i in range(maxgen):
    for j in range(sizepop):
        V[j] = w * V[j] + c1 * (-2 * np.random.rand(1, 2) + 1) * (Pbest[j] - pop[j]) \
               + c2 * (-2 * np.random.rand(1, 2) + 1) * (Gbest - pop[j])  # 速度更新
        V[j, V[j] > Vmax] = Vmax
        V[j, V[j] < Vmin] = Vmin
        pop[j] = pop[j] + V[j]  # 群体更新
        pop[j, pop[j] > popmax] = popmax
        pop[j, pop[j] < popmin] = popmin
        fitness[j] = funAckley(pop[j])  # 适应度值

        if fitness[j] < fitnessPbest[j]:
            Pbest[j] = pop[j].copy()
            fitnessPbest[j] = fitness[j]
        if fitness[j] < fitnessGbest:
            Gbest = pop[j].copy()
            fitnessGbest = fitness[j]

    trace[i] = fitnessGbest
    print(Gbest, fitnessGbest)

# 结果分析
plt.plot(trace)
plt.title("最优个体适应度")
plt.xlabel("进化代数")
plt.ylabel("适应度")
plt.show()

算法结果如下:

python导入粒子群算法库 python粒子群优化算法_优化问题_40

最终得到的个体适应度值为python导入粒子群算法库 python粒子群优化算法_算法_41,对应的粒子位置为python导入粒子群算法库 python粒子群优化算法_开发语言_42,PSO算法寻优得到最优值接近函数实际最优值,说明PSO算法具有较强的函数极值寻优能力。

四、基于自适应变异粒子群算法的非线性函数寻优

本案例寻优的非线性函数(Shubert函数)为

python导入粒子群算法库 python粒子群优化算法_开发语言_43

该函数图形如图3所示:

python导入粒子群算法库 python粒子群优化算法_优化问题_44

从函数图形可以看出,该函数有很多局部极小值,很难用传统的梯度下降方法进行全局寻优。

自适应变异是借鉴遗传算法中的变异思想,在PSO算法中引入变异操作,即对某些变量以一定的概率重新初始化。变异操作拓展了在迭代中不断缩小的种群搜索空间,使粒子能够跳出先前搜索到的最优值位置,在更大的空间中开展搜索,同时保持了种群多样性,提高算法寻找更优值的可能性。因此,在普通粒子群算法的基础上引入简单变异算子,在粒子每次更新之后,以一定概率重新初始化粒子。

本案例群体的粒子数为50,每个粒子的维数为2,算法迭代进化次数为1000。加速度因子python导入粒子群算法库 python粒子群优化算法_python_37python导入粒子群算法库 python粒子群优化算法_python_38,惯性权重python导入粒子群算法库 python粒子群优化算法_算法_47

适应度函数代码如下:

def funShubert(x):
    h1 = 0
    h2 = 0
    for i in range(1, 6):
        h1 += i * np.cos((i + 1) * x[0] + i)
        h2 += i * np.cos((i + 1) * x[1] + i)
    return h1 * h2

自适应变异PSO算法代码如下:

c1, c2 = 1.4, 1.5  # 加速度因子
maxgen = 1000  # 进化次数
sizepop = 50  # 群体规模
w = 0.8  # 惯性权重
Vmax, Vmin = 5, -5  # 速度最大值,最小值
popmax, popmin = 10, -10  # 个体最大值,最小值
pop = np.zeros([sizepop, 2])  # 种群
V = np.zeros([sizepop, 2])  # 速度
fitness = np.zeros(sizepop)  # 适应度
trace = np.zeros(maxgen)  # 结果

# 随机产生一个群体,初始粒子和速度
for i in range(sizepop):
    pop[i] = 10 * (-2 * np.random.rand(1, 2) + 1)
    V[i] = 5 * (-2 * np.random.rand(1, 2) + 1)
    fitness[i] = funShubert(pop[i])

# 个体极值和群体极值
bestfitness = np.min(fitness)
bestindex = np.argmin(fitness)
Gbest = pop[bestindex]  # 全局最佳
fitnessGbest = bestfitness  # 全局最佳适应度值
Pbest = pop.copy()  # 个体最佳
fitnessPbest = fitness.copy()  # 个体最佳适应度值

# 迭代寻优
for i in range(maxgen):
    for j in range(sizepop):
        V[j] = w * V[j] + c1 * (-2 * np.random.rand(1, 2) + 1) * (Pbest[j] - pop[j]) \
               + c2 * (-2 * np.random.rand(1, 2) + 1) * (Gbest - pop[j])  # 速度更新
        V[j, V[j] > Vmax] = Vmax
        V[j, V[j] < Vmin] = Vmin
        pop[j] = pop[j] + V[j]  # 群体更新
        pop[j, pop[j] > popmax] = popmax
        pop[j, pop[j] < popmin] = popmin
        if np.random.rand() > 0.9: # 自适应变异
            pop[j] = 10 * (-2 * np.random.rand(1, 2) + 1)
        fitness[j] = funShubert(pop[j])  # 适应度值
        
        if fitness[j] < fitnessPbest[j]:
            Pbest[j] = pop[j].copy()
            fitnessPbest[j] = fitness[j]
        if fitness[j] < fitnessGbest:
            Gbest = pop[j].copy()
            fitnessGbest = fitness[j]

    trace[i] = fitnessGbest
    print(Gbest, fitnessGbest)

# 结果分析
plt.plot(trace)
plt.title("最优个体适应度")
plt.xlabel("进化代数")
plt.ylabel("适应度")
plt.show()

算法结果如下:

python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_48

最终得到的个体适应度值为-186.6831831611777,对应的例子位置为python导入粒子群算法库 python粒子群优化算法_优化问题_49,自适应变异PSO算法寻优得到最优值接近函数实际最优值,说明该算法具有较强的函数极值寻优能力。

五、补充

惯性权重python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_16体现的是粒子当前速度多大程度上继承先前的速度,Shi.Y最先将惯性权重python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_16引入到PSO算法中,并分析指出一个较大的惯性权值有利于全局搜索,而一个较小的惯性权值则更有利于局部搜索。为了更好地平衡算法的全局搜索与局部搜索能力,其提出了线性递减惯性权重(Linear Decreasing Inertia Weight,LDIW),即

python导入粒子群算法库 python粒子群优化算法_python_52

式中,python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_53为初始惯性权重,python导入粒子群算法库 python粒子群优化算法_算法_54为迭代至最大次数时的惯性权重,python导入粒子群算法库 python粒子群优化算法_算法_19为当前迭代次数,python导入粒子群算法库 python粒子群优化算法_开发语言_56为最大迭代次数。

一般来说,惯性权重取值为python导入粒子群算法库 python粒子群优化算法_算法_57python导入粒子群算法库 python粒子群优化算法_优化问题_58时算法性能最好。这样,随着迭代的进行,惯性权重由0.9线性递减至0.4,迭代初期较大的惯性权重使算法保持了较强的全局搜索能力,而迭代后期较小的惯性权值有利于算法进行更精确的局部搜索。

线性惯性权重只是一种经验做法,常用的惯性权重的选择还包括以下几种:

python导入粒子群算法库 python粒子群优化算法_优化问题_59

python导入粒子群算法库 python粒子群优化算法_算法_60

六、练习

求测试函数的最小值,以及最小值点。

1. Rastrigin function:

python导入粒子群算法库 python粒子群优化算法_python_61

python导入粒子群算法库 python粒子群优化算法_算法_62时,如下图所示:

python导入粒子群算法库 python粒子群优化算法_优化问题_63

2. Sphere function:

python导入粒子群算法库 python粒子群优化算法_算法_64

python导入粒子群算法库 python粒子群优化算法_算法_34时,如下图所示:

python导入粒子群算法库 python粒子群优化算法_优化问题_66

3. Beale function:

python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_67

python导入粒子群算法库 python粒子群优化算法_python_68

4. Booth function:

python导入粒子群算法库 python粒子群优化算法_算法_69

python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_70

5. Bukin function

python导入粒子群算法库 python粒子群优化算法_优化问题_71

python导入粒子群算法库 python粒子群优化算法_算法_72

6. three-hump camel function

python导入粒子群算法库 python粒子群优化算法_python_73

python导入粒子群算法库 python粒子群优化算法_python导入粒子群算法库_74

7. Hölder table function

python导入粒子群算法库 python粒子群优化算法_开发语言_75

python导入粒子群算法库 python粒子群优化算法_python_76