赞
踩
我在上个月(3.15,时间过得真快,已经一个月了…)写了两篇关于遗传算法的博文[1]:遗传算法及基于该算法的典型问题的求解实践-CSDN博客 和[2]:基于遗传算法的波束形成优化-仿真实践-CSDN博客,当时关注到该算法时,也一并了解了下与之相似的算法,如蚁群算法、模拟退火算法以及本博文想要探讨的粒子群算法等。各种类似的优化算法太多了,遗憾没有那么多时间和精力一一学习掌握,在之前探讨过的遗传算法基础上,本博文以及后续想要写作的几篇博文选择粒子群算法进行研究,探讨其与遗传算法的对比、以及联合使用。
本文作为粒子群算法的第一篇博文,对该算法做简单介绍,并研究基于该算法解决几个典型问题。网上关于该算法已经有了很多生动且明了的介绍[3][4],本博文将主要侧重于该算法在具体问题的实践上,此外,为充分利用原有遗传算法基础[1][2],在本博文的各类概念介绍和算法理解上,我会恰当地拿出遗传算法的相关知识做对比。
Blog
2024.4.17 博文第一次撰写
四、基于粒子群算法求解 (Griewank测试函数/曲面)的最值点
粒子群优化(Particle Swarm Optimization, PSO),是由J. Kennedy和R. C. Eberhart等于1995年开发的一种演化计算技术,该算法的灵感来源于鸟群觅食行为的规律性,通过模拟鸟群的集体觅食行为来寻找问题的最优解。PSO 算法属于进化算法的一种,它从随机解出发,通过迭代寻找最优解,并通过适应度来评价解的品质,它通过追随当前搜索到的最优值来寻找全局最优。PSO算法中的每个解被视作一个粒子,这些粒子在解空间中以一定的速度飞行,并根据自身经验(个体极值)和群体经验(全局极值)动态调整位置和速度。粒子群算法具有收敛速度快、参数少、算法简单易实现的优点,但同时也存在容易陷入局部最优解的问题,依赖于良好的初始化和参数设计。
PSO算法在工程设计优化、数据挖掘、神经网络训练、控制工程、机器人路径规划、图像处理、调度问题等领域都有广泛的应用。总之,一切可以建模为数学优化问题的各类问题,理论上都可以用这些优化算法(包括粒子群、遗传等)进行优化求解。
理解该算法,首先从与其有关的基本概念入手,在后文的应用实践中我会将这些概念在应用问题的数学建模以及求解流程中一一对应。
1. 粒子和粒子群
求解各类应用问题时,我们首先需要将要解决的问题映射成一个数学问题,也即:数学建模!该数学问题的一个可行解便可被称为一个粒子,粒子群算法中的粒子和遗传算法中的染色体是一个意思。粒子群算法中我们会随机初始化多个粒子(可行解),这些粒子合在一起就是所谓的粒子群。
2. 位置和速度
每个粒子都有两个属性:位置和速度。位置表征的就是粒子对应的多个维度的值:每个粒子(问题的一个可行解)可能有多个维度(比如我们后文想要求解的一元函数最值问题,其解是一维的,而求解二元函数的最值问题,其解是二维的),这些维度下的值就是粒子的位置,我们在遗传算法中称之为染色体的基因。速度表征的是位置的变化,我们在迭代的过程中,是通过速度值来调整粒子的位置以使得粒子往最优解的方向运动。而在遗传算法中,我们是通过交叉、变异等操作让染色体朝着最优解的方向改进。
3. 惯性权重
如前所述,在迭代的过程中,我们是通过速度来调整粒子的位置以使得粒子往最优解的方向运动,但是我们同时引入惯性权重来保持粒子原有的特性,惯性权重使粒子保持运动的惯性和搜索扩展空间的趋势,该值越大,粒子探索新区域的能力越强,利于全局寻优,但是局部寻优能力越弱,所以在粒子群算法中,该值我们一般会设置为随迭代次数的增加而逐渐减小:迭代的前期我们希望尽快找到全局最优的区域,迭代的后期则倾向于精细化的局部寻优。
4. 适应度
和遗传算法中对适应度的定义一样。遗传算法和粒子群算法,其求解问题的本质就是一个在迭代的过程中不断逼近最优解的过程。我们每次迭代都有很多的粒子,我们如何衡量这些粒子的优劣?我们可以通过构造一个适应度函数来给每次迭代中生成的所有粒子“打分”,得到每个粒子的适应度。这个适应度函数就是我们想要用粒子群算法去优化的目标函数(比如在一元函数最大值求解过程中,我们的目标函数就是f(x)表达式:不同的x值(粒子)下有不同的y值,谁的y值越大,便表明其适应度越高)。
5. 学习因子
分个体学习因子和群体学习因子,个体学习因子表征粒子在迭代过程中对自身历史位置中适应度最好位置的学习权重。群体学习因子表征粒子在迭代过程中对群体历史位置中适应度最好位置的学习权重。这两个因子是作为常系数体现在每次迭代时粒子各个维度的新速度值的计算上。
有了前面介绍的几个概念,我们便可以写出粒子群优化算法迭代过程中的核心公式,粒子每次迭代时的速度更新公式:
(1-1)
位置更新公式:
(1-2)
式中,表示第k+1次迭代时第id个粒子的新的速度值(注:该速度的维度数等于粒子解的维度数);w为惯性权重;C1表示个体学习因子;r1和r2是[0 1]之间的随机值,每次迭代时该值可以由rand函数求出,该值的引入是为了增加寻优过程的随机性;C2为群体学习因子;是第k次迭代时第id个粒子的位置值;是第id个粒子在第K+1次迭代前的历次迭代过程中最高适应度值对应的位置值;是全部粒子在第K+1次迭代前的历次迭代过程中最高适应度值对应的位置值。
6. 边界条件以及边界问题处理
优化问题的解必然是有边界的:我们是在限定的范围内去寻找最优解!在遗传算法中,其迭代时的交叉、变异等都是在限定范围内进行的,所以历次迭代后的结果不需要我们去考虑是否越界。但是在粒子群算法中,从公式(1-1)和(1-2)来看,速度值和位置值的求解是不受限的,所以在每次更新完速度和位置后,我们需要判断速度和位置是否越界,并拟定越界时的处理方法。在本博文涉及的几个问题的处理过程中,对于越界的情况,我将越界的速度和位置值设定为界限值。
7. 迭代结束条件
各种基于迭代来求解的方法都有相同问题:迭代何时停止。一般有两种方式来确定迭代何时结束:一是预设迭代次数,在一些实际应用中,可以事先统计出达到较好效果时的进化次数。比如,你通过大量实验发现:不管输入的数据如何变化,算法在进化K次之后就能够得到最优解,那么你就可以将进化的次数设成K。然而,实际情况往往没有那么理想,因为不同的初始输入会导致得到最优解时的迭代次数相差甚远。二是限定精度范围,如果算法要达到全局最优解可能要经过很多很多次进化,这会极大影响系统的性能。那么我们可以在算法的精确度和系统效率之间寻找一个平衡点,我们事先设定一个可以接收的结果范围,当算法进行k次进化后,一旦发现了当前的结果已经在误差范围之内了,就终止算法。不过这种方式下也有缺点:有些情况下可能稍微进化几次就进入了误差允许范围,但有些情况下需要进化很多很多很多很多次才能进入误差允许范围。这种不确定性导致算法的执行效率不可控。在本博文涉及问题求解中,我都是预设迭代次数来控制迭代结束。
前文对粒子群算法可能涉及的各参数及其用途(在算法中的角色)做了说明,将这些概念串起来,便构成了典型的粒子群算法处理流程。
对于各类应用问题,首先需要明确问题并进行数学建模:特别是解的形式、优化目标的确定。然后预设参数:比如我们需要预设多少个粒子、预设多少的迭代次数、惯性权重、学习因子等。随后基于数学建模的结果,针对该应用问题,初始化各个粒子的位置值和速度值、设计适应度函数。接着就可以进入迭代的循环里:计算适应度 ---> 更新速度和位置 ---> 边界处理 ---> 计算适应度 ---> 更新速度和位置 ---> 边界处理… 直至达到预设的迭代次数,或者满足其它预设迭代终止条件。
典型的粒子群算法处理流程如下:
图2.1 典型的粒子群算法处理流程
在前文的基础上,本章探讨基于粒子群算法求解一元函数的最值问题。
现有函数:
(3-1)
x的取值范围在[0 20],求该函数在x区间内的最大值。可以把该函数在[0 20]区间内的曲线画出来看看:
图3.1 函数曲线图
可以看到,在x = 18.3382(与我们设置的x最小间隔有关)处我们可以取得最大值31.9755。该函数有很多的极大值点,所以该函数是一个很好的优化算法测试函数!如果参数设置得不合理,优化算法是很容易陷入局部极大值里的。
该问题其实已经是一个清晰的数学问题了,不需要我们做更多的分析:在限定区间的每个x值都是一个可能解(可作为一个粒子),该问题的优化目标是:使y的值尽可能大,适应度函数可直接取为f(x)的表达式。
本博文所提供代码的仿真参数预设如下:
表3.1 预设参数列表
参数 | 值 |
粒子数量 | 10 |
粒子维度 | 1 (就只有自变量x) |
粒子位置范围 | [0 20] |
粒子速度范围 | [-1 1] |
惯性权重 | 0.8 (本次仿真中,历次迭代下的惯性权重值不变) |
个体学习因子 | 0.5 |
群体学习因子 | 0.5 |
迭代终止条件 | 迭代100次后终止 |
基于第二章中的求解流程以及3.2节的预设参数,进行仿真求解。本章以及后续两个章节的仿真代码我都上传至第八章的代码链接中,读者可下载参考。本节给出几个核心的代码模块的解释。
粒子初始的位置和速度都是在前述预设参数约束下随机生成。
1. 关于速度和位置的更新以及边界约束:
图3.2 速度和位置更新以及边界约束
对于每一个粒子,先更新其速度(基于公式(1-1)),更新速度后判断其是否越界,如果越界则将边界值赋值给该速度。随后,由新求得的速度加上一次迭代得到的位置值得到本次迭代的位置值,同样,如果位置值超过边界值,则将边界值赋值给位置值。
2. 计算适应度,并更新各粒子、以及整个粒子群的最优适应度下的粒子位置值
图3.3 计算适应度并更新最优适应度下的粒子值
适应度Fitness_partical2的计算就是基于函数f(x)的表达式求解。我用变量BestFit_partical装载每个粒子的历史最优适应度和最优适应度对应的粒子位置值:其有2行,粒子数列,第一行装载最优适应度值,第二行装载对应的粒子位置(也就是x的值),每次迭代后,需要更新该变量。
BestFit_global为3行,(迭代次数+1)列,用来装载历次迭代下粒子群整体的历史最优适应度及其对应的粒子位置值,第三行是为后面画图方便,我存储了历次迭代的最优适应度值。当然,其实历史最优是适应度我们只需要保留一个即可(每次迭代完成后,只有一个历史最优适应度值及其对应的粒子位置)。
可以说,粒子群算法最核心的代码就是前面这两部分,后面的两个问题我不再重复介绍,只给出不同于本问题的一些代码模块。
当然,我所提供的代码不是最优的(效率最高的),读者可以参考并自行优化。
图3.4 不同迭代次数下各粒子适应度分布
图3.5 各迭代次数下的最优适应度变化曲线
图3.6 迭代前后粒子位置
从上面几幅图的结果来看,经过迭代后,达到了预期的目标:找到该一元函数的最大值的位置。仿真的结果验证了所编代码的正确性、粒子群算法优化该问题的可行性,且收敛效果还不错:大概经过27次左右迭代后便找到了全局最优解的位置。【当然,这与参数和初始化粒子的位置有关!】
从实践来看,粒子群的代码复杂度(至少是写代码上)其实要优于遗传算法。但是粒子群算法严重依赖于参数的设计!上表3.1中给出的参数是我试过几组后算是比较优的组合,读者可以基于代码试着更改惯性权重、学习因子等参数,看看收敛效果,可能会有一些意外收获…。设置什么样的参数以使得结果快速收敛、且不会陷入局部最优解是粒子群算法研究面临的核心问题。
在前文的基础上,本章探讨基于粒子群算法求解Griewank函数的最值问题。
Griewank函数(格里旺克函数)是用于测试优化程序效率的经典函数之一。此外还有Rastrigin、Ackley等函数。Griewank函数的表达式为:
(4-1)
x可以是多维的,当其是二维时,f(x)在x的取值范围内就是一个曲面,本章讨论x为二维情况下的优化。此时可以理解为:在限定的平面范围内(x∈[a b],y∈[c d],y对应x的第二个维度,每一组[x,y]的值对应函数的一个Z值),找到在该范围下该曲面的最小值点(Z的最小值,及其对应的坐标)。限定x和y的取值范围都是[-10 10],可以看看该曲面的样子:
图4.1 Griewank函数图像
函数有很多的凸起和凹陷,和上一章中的一元函数有诸多的极值点一样,可以测试优化算法是否容易陷入局部最优解处。
注:该函数的最小值点在[x,y] = [0,0]处取得。
同样,该问题其实已经是一个清晰的数学问题了,不需要我们做更多的分析:在限定区间的每个[x,y]的组合都是一个可能解(可作为一个粒子),该问题的优化目标是:使Z的值尽可能小,适应度函数可直接取为f(x)的表达式。
本博文所提供代码的仿真参数预设如下:
表4.1 预设参数列表
参数 | 值 |
粒子数量 | 10 |
粒子维度 | 2 |
粒子位置范围 | [-10 10] (两个维度都是这样) |
粒子速度范围 | [-1 1] (两个维度都是这样) |
惯性权重 – X方向 | 0.6 |
惯性权重 – Y方向 | 0.5 |
个体学习因子 – X方向 | 0.7 |
群体学习因子 – X方向 | 1.4 |
个体学习因子 – Y方向 | 0.6 |
群体学习因子 – Y方向 | 1.5 |
迭代终止条件 | 迭代100次后终止 |
注:本章仿真中对越界的处理方法也是:如果越界则将边界值赋值给该值。
粒子初始的位置和速度都是在前述预设参数约束下随机生成。
关于速度和位置的更新、最优适应度下粒子位置的更新等代码模块和前面一样,这里只是改成了二维的,没有太多不同,本节不再给出。这里贴一下适应度的计算函数(也就是Griewank函数值的计算):
图4.2 Griewank函数(适应度值计算方法)
该函数输入二维坐标(一行两列的向量),输出该坐标下的Z值。计算的方法很简单,直接基于公式(4-1)编辑代码即可。
图4.3 不同迭代次数下各粒子适应度值的分布
图4.4 各迭代次数下的最优适应度变化曲线
上述两张图中的适应度值我直接用Z值表示,Z值越小(适应度值越小)是我们期望看到的。上面的结果(至少从趋势上)验证了算法的正确性。
不过遗憾的是,结果似乎还是陷入了局部最优解:
图4.5 迭代完成前后最优适应度值及其对应的坐标值
前面说过,Griewank函数的最优值在[0,0]处取得,f(0,0) = 0。如何优化参数以获得全局最优解,读者可以基于提供的代码自行优化。
本章使用粒子群算法对Griewank测试函数的最小值点进行了迭代求解,求解的结果验证了算法的可行性,但是本章所给的参数下,算法较容易陷入局部最优解,如何优化参数以使得可以增加算法收敛速度的同时,不会陷入局部最优解,是需要后续研究的问题。(比如可以设置线性减小的惯性权重值。)
在前文的基础上,本章探讨基于粒子群算法求解01背包问题。
有N件物品和一个容量为V的背包。第i件物品的体积是v(i),价值是w(i)。求解将哪些物品放入背包可使物品的体积总和不超过背包的容量,且价值总和最大。
假设N件物品的体积分别为:[V(1),V(2),… V(N)],价值分别为:[w(1),w(2),… w(N)]。每个粒子对应一个可行解,为每个粒子设计一个大小为N维的二进制向量解(为0表示不装,为1表示装),当然,需要保证所装物品的体积加起来小于背包体积V。以所装物品的总价值作为适应度值:
(5-1)
表示编号为id的粒子所装物品的总价值(也即其适应度值),该值越大越好。M表示该粒子对应的解装载了M个物品。
本博文所提供代码的仿真参数预设如下:
表5.1 预设参数列表
参数 | 值 |
预设物品数 | 10 |
预设各物品价值 | 在80内随机生成 |
预设各物品体积 | 在50内随机生成 |
预设背包体积 | 300 |
粒子数量 | 10 |
粒子维度 | 10(等于物品数) |
粒子位置范围 | 二进制:要么为0 要么为1 (为1表示装载该序号对应的物品) |
粒子速度范围 | [-5 5] |
惯性权重 | 从1线性变化到0.4 |
个体学习因子 – X方向 | 0.5 |
群体学习因子 | 1.5 |
迭代终止条件 | 迭代100次后终止 |
本问题和前面两章的问题有两个较大的不同:
1. 粒子的位置只有0和1之分,我们此时不能用第一章中的位置更新公式(1-2)计算本问题的位置值。本代码提供的解决思路是:将粒子每个维度的速度进行“归一化”处理,并设置[0 1]区间内的随机变量,如果归一化后的速度超过该随机变量的值,将该速度维度对应的位置值设置为1,否则设置为0。
图5.1 从新的速度值计算新的位置值的处理方法
Vbuffer为求得的粒子jj的速度值,其大小为1*Num_goods,Num_goods为物品数量,用函数:
(5-2)
来归一化各速度。函数f(x)的曲线如下图所示,在前述设置的速度范围:[-5 5]下:
图5.2 归一化函数图像
该函数在自变量范围内单调递增,且两端分别无限接近于0和1,是一个很好的工具!归一化后,我们对每个归一化后的速度值进行判断,并得到对应的位置值。
2. 用前面的方法解决了粒子位置值的更新问题后,此时我们得到的粒子无法保证其体积一定是小于背包体积的。那么我们重新去更新一次粒子的位置值?(当然可以这样做,但是很繁琐,而且需要设计合理的方法,不然前面基于速度来求解粒子的位置部分毫无意义)。本代码提供的解决思路是:不再更新粒子的位置值以使得粒子对应的总体积小于背包体积,而是:在计算粒子适应度时,对超过背包体积的粒子增加“惩罚”。
图5.3 适应度计算函数
在基于粒子的位置值求得总的价值后,再计算该粒子总的体积,如果该体积超过背包体积,则减小其适应度值,且超过越多,减小的值越大。在本代码中PunishFactor取2。
我试了很多组参数,但是收敛的效果都很差…:
图5.4 各迭代次数下各粒子适应度值的分布
图5.5 各迭代次数下最优适应度值变化曲线
从结果来看,可以说完全没有收敛的意思…,但是方法应该是对的,读者可以基于我所提供的代码,更大胆地设置各参数(比如更多的粒子、更多的迭代次数、以及不同的学习因子等),此外,在粒子位置更新、适应度的求解上可能有更好的方法。
本章使用粒子群算法对01背包问题进行了求解。虽然结果不尽如人意,但是整个问题的求解思路和流程是没有问题的,本章提供的粒子位置更新方法以及适应度的求解方法也都蛮有意思。 不过似乎该问题更适合用遗传算法求解?
本博文对粒子群算法做了系统性&细节性介绍:包括其相关概念、经典的处理流程等。并以一元函数寻优、二元函数寻优、01背包问题作为研究对象,探讨了如何使用粒子群算法解决这三个问题。
粒子群算法在实现上其实要比遗传算法简单,细节也更少,但是该算法的效果严重依赖于参数设置,欠佳的预设参数很容易导致算法陷入局部最优解。在参考资料[5]中给出了两种算法比较全面的对比,读者可以移步查看,这里贴几点:
1. PSO和GA的相同点:
(1)都属于仿生算法。PSO主要模拟鸟类觅食、人类认知等社会行为而提出;GA主要借用生物进化中“适者生存”的规律。
(2)都属于全局优化方法。两种算法都是在解空间随机产生初始种群,因而算法在全局的解空间进行搜索,且将搜索重点集中在性能高的部分。
(3)都属于随机搜索算法。都是通过随机优化方法更新种群和搜索最优点。PSO中认知项和社会项前都加有随机数;而GA的遗传操作均属随机操作。
(4)都隐含并行性。搜索过程是从问题解的一个集合开始的,而不是从单个个体开始,具有隐含并行搜索特性,从而减小了陷入局部极小的可能性。并且由于这种并行性,易在并行计算机上实现,以提高算法性能和效率。
(5)根据个体的适配信息进行搜索,因此不受函数约束条件的限制,如连续性、可导性等。
(6)对高维复杂问题,往往会遇到早熟收敛和收敛性能差的缺点,都无法保证收敛到最优点。
2. PSO和GA不同点
(1)PSO有记忆,好的解的知识所有粒子都保存,而GA没有记忆,以前的知识随着种群的改变被破坏。
(2)在GA算法中,染色体之间相互共享信息,所以整个种群的移动是比较均匀地向最优区域移动。PSO中的粒子仅仅通过当前搜索到最优点进行共享信息,所以很大程度上这是一种单项信息共享机制,整个搜索更新过程是跟随当前最优解的过程。在大多数情况下,所有粒子可能比遗传算法中的进化个体以更快速度收敛于最优解。
(3)GA的编码技术和遗传操作比较简单,而PSO相对于GA,不需要编码,没有交叉和变异操作,粒子只是通过内部速度进行更新,因此原理更简单、参数更少、实现更容易。
(4)在收敛性方面,GA己经有了较成熟的收敛性分析方法,并且可对收敛速度进行估计;而PSO这方面的研究还比较薄弱。尽管已经有简化确定性版本的收敛性分析,但将确定性向随机性的转化尚需进一步研究。
(5)在应用方面,PSO算法主要应用于连续问题,包括神经网络训练和函数优化等,而GA除了连续问题之外,还可应用于离散问题,比如TSP问题、货郎担问题、工作车间调度等。
[1] 遗传算法及基于该算法的典型问题的求解实践-CSDN博客
[3] 粒子群算法(Particle Swarm Optimization)超详细解析-CSDN博客
[4] 粒子群优化算法(Particle Swarm Optimization, PSO)的详细解读 - 知乎 (zhihu.com)
[5] 粒子群综述 - 小艾shea - 博客园 (cnblogs.com)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。