粒子群优化算法(Particle Swarm Optimization),是一种经典的智能算法,也是较为基础的算法。粒子群的含义为多个随机量组成的群体,通过对这些群体的挑选和更新,最终选出最为接近解的一个随机量来作为结果。其本质并不复杂,仅仅是用随机生成的数去参与计算,多个随机数的计算结果相互比较,选出能产生最优解的那个随机数作为最终结果。
产生随机数的过程是随机而不可控的,要想在多个随机量中取到最好的数,仅靠随机产生是不能得到很好的结果的。因此,产生随机数的过程需要能够处于可控状态,使得其产生的随机数处于所期望的范围内。PSO里优化的含义便是如此,即产生可控的随机粒子群。
粒子群如何才能显示可控又能随机的特性呢?这里就再引入一个速度和维度的概念,速度即为从当前粒子转移到下一个粒子的速度,其本质含义就是偏移量。维度的本质其实就是粒子群的复制品,即给当前粒子群多个偏移量进行多次计算。在这里需要指出的是:PSO产生多个粒子,粒子的位置随机,每一个粒子具有可控的多个不同的随机偏移量。
偏移量的随机性还需要受到当前粒子本身位置的限制,使得随机产生的偏移量不会超过设定范围。在大多数解释中,多以生涩难懂的所谓学习因子(acceleration constant)、惯性(inertia)、认知(cognition)、社会(social)这种名词作称,而其本质是利用极其简单的原理而来的。此部分会在PSO算法原理示例中做出详细解释。
在计算过程中,首先需要计算每个粒子的解,选出极值(个体极值)作为这一个粒子系统的最优解;然后在每个粒子都具有自身最优解后比较所有粒子的值,选出其中的极值(全局极值)作为整个粒子系统的最优解。最后,进行多次迭代,在每个粒子中加入偏移量,并再次计算得出最优解。在多次迭代产生的多个最优解中做最后一次挑选,挑选出的粒子即为PSO最优解。
我们以一个简单函数f(x)为例,来详细解释原理中的内容,以便于深入理解。假设该函数为左减右增的二次函数,我们需要求该函数的最小值,显然此最小值存在并且只有一个,假设该最小值为x0。
上述内容即是PSO算法的整个计算过程,可以发现,总共需要计算的粒子数为N*D*M个,当粒子数量越多时,能得到的适应值越多,在理论上能更好地得出最优解。
根据前面的算法原理和示例,设计如下算法。
算法需要完成的内容:
% xm: particle result
% fv: function result
% fitness: fitness function
% N: numbers of group/particle
% c1,c2: acceleration constant 1&2
% w: inertia/momentum weight, react habit of particle
% M: max interation time
% D: dimention of search space
% a: The minimum of original particle value
% b: The maximum of original particle value
% PSO main function
function [pg,fv,Pbest] = PSO(fitness,N,c1,c2,w,M,D,a,b)
% Initialize numbers of particle
format long;
for i = 1:N
for j = 1:D
% Initialize random position, range [a,b]
x(i,j) = a+(b-a)*rand;
% Initialize random velocity, range [a,b]
v(i,j) = a+(b-a)*rand;
end
end
% Calculate fitness value of each particle, Initialize Pi & Pg
% Pi: Individual extremum
% Pg: Global extremum
for i = 1:N
p(i) = fitness(x(i,:));
% xb is backup of x
xb(i,:) = x(i,:);
end
pg = x(N,:);
% Choose the global best value
for i = 1:(N-1)
if fitness(x(i,:)) < fitness(pg)
pg = x(i,:);
end
end
% Main loop, interative computations until satisfied precision
% Calculate the minimum of function by PSO
for t = 1:M
for i = 1:N
v(i,:) = w*v(i,:)+c1*rand*(xb(i,:)-x(i,:))+c2*rand*(pg-x(i,:));
x(i,:) = x(i,:)+v(i,:);
if fitness(x(i,:)) < p(i)
p(i) = fitness(x(i,:));
xb(i,:) = x(i,:);
end
if p(i) < fitness(pg)
pg = xb(i,:);
end
end
% Save fitness function value in every interative computations
Pbest(t) = fitness(pg);
end
% Final solution
fv = fitness(pg);
% Output results
disp('=============================================================');
disp('Global Extremum of x in Every Dimention:');
disp(pg);
disp('=============================================================');
disp('Fitness Function Value in Every Interative Computations:');
disp(Pbest);
disp('=============================================================');
disp('Final Solution:');
disp(fv);
上述代码可以分成以下几个部分来看:
在代码的测试中,使用3种类型的函数进行计算以检查算法,观察算法的特性。由于代码中所求的是函数极小值,因此在这里的测试中,主要测试与极小值数量相关的函数。
所选取的函数类型包括:
(一)无极值的函数:
无极值的函数最为典型和最容易观察的就是单调函数了,这里选择f(x)=-2x+4。
构建函数:
function F = fitness(x)
F = 0;
for i = 1:30
F = -2*x(i)+4;
end
用PSO算法运行函数,其中粒子数N=50,学习因子c1=1.5,c2=2.5,惯性权重w=0.5,最大迭代次数M=100,维度D=30,初始粒子生成区域[-3,3]:
>> [xm,fv,Pbest]=PSO(@fitness,50,1.5,2.5,0.5,100,30,-3,3);
输出结果:
=============================================================
Global Extremum of x in Every Dimention:
1.0e+308 *
Columns 1 through 7
0.841051353022593 -0.815362634098202 -0.971560424001742 0.058536740953437 0.278278526311938 0.549501785505087 0.684021101629322
Columns 8 through 14
-0.277279492571157 -0.670375777743297 0.072034145220756 -1.029020776175725 -0.110958264760359 0.554608597715386 1.601070166415694
Columns 15 through 21
-0.154873876453593 -0.837816763464718 -0.156977033537677 0.563598469594560 1.206370914151192 -Inf -0.899268116457533
Columns 22 through 28
-0.638042720497759 -0.482391940153852 -0.588300635971660 0.806486136307647 -0.688514030378603 -0.567399109429627 1.471028424563621
Columns 29 through 30
0.208156245066552 1.512900553405087
=============================================================
Fitness Function Value in Every Interative Computations:
1.0e+302 *
Columns 1 through 7
-0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000
Columns 8 through 14
-0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000
Columns 15 through 21
-0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000
Columns 22 through 28
-0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000
Columns 29 through 35
-0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000
Columns 36 through 42
-0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000 -0.000000000000000
Columns 43 through 49
-0.000000000012021 -0.000006850419996 -1.128491406854554 -Inf -Inf -Inf -Inf
Columns 50 through 56
-Inf -Inf -Inf -Inf -Inf -Inf -Inf
Columns 57 through 63
-Inf -Inf -Inf -Inf -Inf -Inf -Inf
Columns 64 through 70
-Inf -Inf -Inf -Inf -Inf -Inf -Inf
Columns 71 through 77
-Inf -Inf -Inf -Inf -Inf -Inf -Inf
Columns 78 through 84
-Inf -Inf -Inf -Inf -Inf -Inf -Inf
Columns 85 through 91
-Inf -Inf -Inf -Inf -Inf -Inf -Inf
Columns 92 through 98
-Inf -Inf -Inf -Inf -Inf -Inf -Inf
Columns 99 through 100
-Inf -Inf
=============================================================
Final Solution:
-Inf
从输出结果可以看出在这次计算中从第46次迭代开始,所有迭代的结果全部变成-Inf,即负无穷大。最终结果也为-Inf。
将每个维度上的全局极值xm提取出来绘制在函数上:
可以明显看出的是PSO算法对无极值函数的计算是完全无效的,它无法判断出函数是否含有极值,只能找到更小值,所以无论粒子数如何增加,无论迭代次数如何,最终结果也必定错误。 但是,这也说明算法的偏移量有着很大的效果,当更小值离计算值越远时,偏移量会越大从而使得粒子值更快地偏向更小值。
(二)计算范围内有且只有一个极小值的函数:
有且只有一个极小值的函数选取开口向上的二次函数来作为测试示例,这里选择f(x)=πx^2+4.2165x-6。
构建函数:
function F=fitness(x)
for i = 1:30
F = pi*x(i)^2+4.2165*x(i)-6;
end
用PSO算法运行函数,其中粒子数N=50,学习因子c1=1.5,c2=2.5,惯性权重w=0.5,最大迭代次数M=100,维度D=30,初始粒子生成区域[-3,3]:
>> [xm,fv,Pbest]=PSO(@fitness,50,1.5,2.5,0.5,100,30,-3,3);
输出结果:
=============================================================
Global Extremum of x in Every Dimention:
Columns 1 through 7
-2.753074798081740 -1.169369707046688 1.062521777824847 -3.436944003027899 -3.453434421008966 -3.346728544512620 0.224254329525503
Columns 8 through 14
-1.513282523759711 1.392535003860485 0.137742338762548 1.028461706556775 -0.847233750607663 -0.068847770729289 -1.656558968000103
Columns 15 through 21
-2.634257617648518 0.540436047009250 0.964646167036658 0.960257208261315 0.872886226318105 -1.571326026494238 -2.865833163441617
Columns 22 through 28
1.737692482372997 1.102928175297616 -0.104774526333868 0.144557995844851 0.361837419787455 3.540180471928583 -1.798800458695054
Columns 29 through 30
-0.558942764851097 -0.671076816832947
=============================================================
Fitness Function Value in Every Interative Computations:
Columns 1 through 7
-7.414590713624410 -7.414787937084041 -7.414787937084041 -7.414787937084041 -7.414796355999133 -7.414796355999133 -7.414796355999133
Columns 8 through 14
-7.414796355999133 -7.414796355999133 -7.414796355999133 -7.414796355999133 -7.414797454548400 -7.414797454548400 -7.414797454548400
Columns 15 through 21
-7.414797454548400 -7.414797685474882 -7.414797685474882 -7.414797685474882 -7.414797685474882 -7.414797685474882 -7.414797685474882
Columns 22 through 28
-7.414797693652570 -7.414797693652570 -7.414797693652570 -7.414797693652570 -7.414797700523192 -7.414797700523192 -7.414797700523192
Columns 29 through 35
-7.414797700523192 -7.414797700523192 -7.414797700523192 -7.414797700523192 -7.414797700551938 -7.414797700551938 -7.414797700591263
Columns 36 through 42
-7.414797700591263 -7.414797700592745 -7.414797700592745 -7.414797700592745 -7.414797700592745 -7.414797700592745 -7.414797700592745
Columns 43 through 49
-7.414797700593347 -7.414797700593347 -7.414797700593413 -7.414797700593413 -7.414797700593413 -7.414797700593413 -7.414797700593413
Columns 50 through 56
-7.414797700593413 -7.414797700593413 -7.414797700593413 -7.414797700593413 -7.414797700593413 -7.414797700593413 -7.414797700593413
Columns 57 through 63
-7.414797700593413 -7.414797700593413 -7.414797700593413 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414
Columns 64 through 70
-7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414
Columns 71 through 77
-7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414
Columns 78 through 84
-7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414
Columns 85 through 91
-7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414
Columns 92 through 98
-7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414 -7.414797700593414
Columns 99 through 100
-7.414797700593414 -7.414797700593414
=============================================================
Final Solution:
-7.414797700593414
可以看出,在这次计算中,从第60次迭代开始,PSO算法能找出精确解,这是偏移量的逐步逼近带来的效果。在本例中所选取的初始粒子区域即已包含了极值点。
同样,将每个维度的全局极值粒子点xm放在函数图像中:
可以明显发现的是,即便选择的初始值取值范围是[-3,3],也仍然有几个维度的全局极值点取在了区域外,这是偏移量带来的空间搜索的效果,这样的方式十分类似于二分法求值。
如果重复算法过程,粒子值的取点会有不同,这是取点随机导致的。但要值得注意的是,由于示例中选取的是简单函数,只要粒子数量和迭代次数足够多,是必定能找到极值点的。而实际情况下拟合的函数不一定能找到,这点在后面的PSO算法的优化和优劣中会举例提出。
(三)计算范围内有多个极小值的函数:
在一定计算范围内含有多个极小值的函数比较典型的就是三角函数了,这里选择f(x)=-5.376sin(x)+3.451cos(x)+4.185*pi。
构建函数:
function F=fitness(x)
for i = 1:30
F = -5.376*sin(x(i))+3.451*cos(x(i))+4.185*pi;
end
用PSO算法运行函数,其中粒子数N=50,学习因子c1=1.5,c2=2.5,惯性权重w=0.5,最大迭代次数M=100,维度D=30,初始粒子生成区域[-3,3]:
>> [xm,fv,Pbest]=PSO(@fitness,50,1.5,2.5,0.5,100,30,-3,3);
输出结果:
=============================================================
Global Extremum of x in Every Dimention:
Columns 1 through 9
2.222057300314215 1.584744215718849 -1.389305175684149 -0.304993030488773 -1.464753293568250 -1.516629684758275 -0.662122473376967 -1.513272679334709 1.891019898435771
Columns 10 through 18
-2.603622266554929 0.437498697619477 1.612369390707586 -0.790965052178944 -1.681190439449502 -0.198410281213692 0.943858412398637 0.719017608309307 -2.085287787030176
Columns 19 through 27
0.257022898439140 -1.742402906920305 1.655809760060000 0.077001794816666 0.411142717679348 -1.241325957370525 -2.053804056041739 -0.650803902299574 -0.686559182782667
Columns 28 through 30
-1.439189287201725 0.618429057811882 2.141475428275006
=============================================================
Fitness Function Value in Every Interative Computations:
Columns 1 through 9
6.759258157138222 6.759258157138222 6.759258157138222 6.759258157138222 6.759258157138222 6.759258157138222 6.759258157138222 6.759258157138222 6.759258157138222
Columns 10 through 18
6.759240086482973 6.759234151527503 6.759234151527503 6.759234151527503 6.759234151527503 6.759234151527503 6.759234151527503 6.759234151527503 6.759234151527503
Columns 19 through 27
6.759234151527503 6.759234151527503 6.759234038544016 6.759234038544016 6.759234038544016 6.759234026863794 6.759234026863794 6.759233942811053 6.759233942811053
Columns 28 through 36
6.759233942811053 6.759233939747472 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157
Columns 37 through 45
6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157 6.759233939507157
Columns 46 through 54
6.759233939507157 6.759233939507103 6.759233939507103 6.759233939507103 6.759233939507103 6.759233939507103 6.759233939507103 6.759233939507103 6.759233939507103
Columns 55 through 63
6.759233939507103 6.759233939507103 6.759233939507103 6.759233939507071 6.759233939507019 6.759233939507015 6.759233939507015 6.759233939507015 6.759233939507015
Columns 64 through 72
6.759233939507015 6.759233939507015 6.759233939507015 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014
Columns 73 through 81
6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014
Columns 82 through 90
6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507014 6.759233939507013
Columns 91 through 99
6.759233939507013 6.759233939507013 6.759233939507013 6.759233939507013 6.759233939507013 6.759233939507013 6.759233939507013 6.759233939507013 6.759233939507013
Column 100
6.759233939507013
=============================================================
Final Solution:
6.759233939507013
从输出结果上看,在这次计算中直到第90次迭代开始才得到函数的精确解。这是因为函数类型更加复杂,通过类似二分法的PSO算法求解更加困难。在本例中所选取的初始粒子区域即已包含了一个极小值点。
同样,将每个维度的全局极值xm放在函数上观察点的位置:
可以发现,在[-3,3]的区域范围内,存在一个极大值和一个极小值。由于函数较前两个复杂,因此耗费了大量的时间计算了无意义的极大值周围区域。很明显,算法需要先寻找到极小值区域再寻找极小值。在本例中,选择的迭代次数为100,完成精确解的迭代次数为90,可以看出,如果迭代次数不够,粒子数量不够时,可能会不容易找到精确解(即实际上最终解的位置是浮动的、存在不确定性的)。并且使用PSO算法求精确解明显不是一个正确的解决办法。
另外,将初始粒子的计算区域扩大到[-9,9]计算:
>> [xm,fv,Pbest]=PSO(@fitness,50,1.5,2.5,0.5,100,30,-9,9);
得到的最终结果是:
=============================================================
Final Solution:
6.759233939507020
观察xm在函数上的位置:
可以非常明显的发现,仅仅是扩大了初始粒子的生成区域,结果却发生了极大的变化,随机点的取值散乱且不能发现明显规律。这是因为该函数在[-9,9]区域内包含了多个极大值和多个极小值,导致算法的偏移量出现问题。而最终结果很显然与前一次计算结果不同,随机点没有取到最小值。因此,在计算区域内存在多个极值的函数用PSO算法计算显然是存在不确定性的,很容易获得错误的结果。
PSO算法的优化大多与参数的设定相关,对于不同类型的函数,参数大小的选择决定了粒子位置的准确性,这与学习因子和惯性权重参数控制下的偏移量的选择有关。另外,粒子的数量和迭代的次数虽然能提供更多的计算量,但粒子数量越多的情况下也可能会出现越多的无意义粒子(该粒子位置下的小区域范围内可能已经被计算过,或者计算了无意义的区域,或者即便是更多的粒子也无法找到极值) ,因此粒子的数量和迭代次数的大小需要根据实际需求进行选择。
比如求解以下函数的最小值:
function F=fitness(x)
F = 0;
for i = 1:30
F = F+x(i)^2+2*x(i)-3;
end
用PSO算法运行函数,其中学习因子c1=1.5,c2=2.5,惯性权重w=0.5,维度D=30,初始粒子生成区域[-3,3]:
(1)当粒子数N=50,迭代次数M=100时:
>> [xm,fv,Pbest]=PSO(@fitness,50,1.5,2.5,0.5,100,30,-3,3);
最终结果为:
=============================================================
Final Solution:
-1.127480058326967e+02
(2)当粒子数N=50,迭代次数M=1000时:
>> [xm,fv,Pbest]=PSO(@fitness,50,1.5,2.5,0.5,1000,30,-3,3);
最终结果为:
=============================================================
Final Solution:
-1.155305812181920e+02
(3)当粒子数N=50,迭代次数M=10000时:
>> [xm,fv,Pbest]=PSO(@fitness,50,1.5,2.5,0.5,10000,30,-3,3);
最终结果为:
=============================================================
Final Solution:
-1.123345006760462e+02
(4)当粒子数N=100,迭代次数M=1000时:
>> [xm,fv,Pbest]=PSO(@fitness,100,1.5,2.5,0.5,1000,30,-3,3);
最终结果为:
=============================================================
Final Solution:
-1.187908858314188e+02
(5)当粒子数N=500,迭代次数M=1000时:
>> [xm,fv,Pbest]=PSO(@fitness,500,1.5,2.5,0.5,1000,30,-3,3);
最终结果为:
=============================================================
Final Solution:
-1.199956804469871e+02
然而,尽管在参数选择上选取了最优参数,粒子数量足够,也无法避免算法中粒子位置的随机性所带来的结果不稳定的情况。无论参数或粒子数量如何选取,最终得到的结果永远是处于在一定范围内变动的不精确的值。为了避免因为随机带来的不确定性,也有必要添加一定的误差判定以压缩最终结果的范围,误差大小也需要与选择的参数大小相关以避免因参数的选择导致误差判定失效。因此,PSO算法只适用于计算在一定误差内的趋近某个值的解,而不适用于精确解。在适应函数较为复杂或者函数求解并不需求很高的精度时,可以用来进行趋近计算得到取值范围或者在一定误差内计算近似解。
当然,从PSO算法原理和给出的示例上可以看出,对于在计算范围内具有多个极值的函数以及无极值的函数而言,该算法的适用性会大大减弱甚至毫无作用。 这是由于算法是进行的简单函数值的比较,而对于自变量的取值是需要用户进行控制的。如果某个具有多极值的函数在计算区域内并不明晰它的极值区域或极值数,使用PSO算法则可能得到错误的结果,而如果该函数在计算区域内是无极值的,那么是一定无法得到正确结果的。
比较特别的是,在上述的算法中没有对加入偏移量后粒子的位置做出严格限制,对于无极值或多极值的函数会出现粒子偏移失常,产生超出区域的值。
综上所述,可以总结以下几点:
1、PSO算法的优化是与函数的选择、算法参数的设定、计算的区域有极大相关的;
2、PSO算法由于其粒子的随机性,无法得到精确值而只能得到在一定区域内浮动的近似值;
3、PSO算法不能使用在计算区域内具有多个极值或者无极值的函数上,因为这会得到错误的结果;
4、PSO算法自身无法保证粒子计算是否有意义,粒子量越多,无意义的粒子也越多;
5、PSO算法能快速提供大量的区域可控粒子参与计算,计算效率高。
PSO算法作为经典智能算法的基础之一,其算法的设计思想是具有很好的意义的,在PSO算法基础上进行改进、优化等可以有助于快速找到极值范围,也可以快速求取近似值。虽然其具有相当多的局限性,但它提出了用多种方式去有效控制值的范围并生成大量随机值的方法,而很多的智能算法也正是利用了这样的方法去寻找最终的解。
智能算法的用途看似非常微妙,其本质仍然仅是在探求对函数求解的适合计算机计算的方式。在很多情况下,智能算法最终的困难点在于寻找到适合的函数去模拟或者近似于实际情况,而算法则是用来求解这个函数的。 俗话说万事开头难,寻找合适的函数去匹配实际情况需要很多经验以及数学分析思维。
当然,寻找适合的函数也需要培养算法思维,了解并熟悉其计算过程也是一个非常重要的点,否则设计函数却无法求解也同样是无法解决实际问题的。PSO算法也仅仅是智能算法中的冰山一角,还有更多的经典算法需要去了解和学习。
–注:本文为原创,未经允许,禁止转载!–