目录
-
基本概念
粒子群优化算法(particle swarm optimization,PSO)属于进化算法的一种,它源于鸟群捕食的行为研究。基本思想是通过群体中个体之间的协作和信息共享来寻找最优解。在PSO中,每个优化问题的潜在解都是搜索空间中的一只鸟,抽象为粒子,每个粒子都有一个由目标函数决定的适应值(fitness value),以及决定它们飞行的方向和距离。 PSO具有实现容易、精度高、收敛快等优点。
-
算法实现
在我编写的程序里可以这样理解,我们需要定义基本粒子类和粒子群类,每个粒子含有固有的属性,比如速度、位置以及储存更新的变量,粒子群类似,含有个体极值、全局极值以及计算函数。
假设在一个D维的目标搜索空间中,有N个粒子组成一个群落,其中第i个粒子表示为一个D维的向量,简单来说每个粒子都会对应优化问题相应的优化变量:
(1)
第i个粒子的飞行速度也是一个D维的向量:
(2)
第i个粒子迄今为止搜索到的最优位置称为个体极值:
(3)
整个粒子群迄今为止搜索到的最优位置为全局极值:
(4)
个体极值与全局极值寻优时,粒子根据下式更新位置和速度:
(5)
(6)
式中:w为惯性权重,非负数,调节对解空间的搜索范围,c1、c2为学习因子,也称为加速常数,r1、r2增加随机搜索性。
式(5)由三部分组成:
第一部分:惯性部分,反映了粒子的运动习惯,代表粒子有维持自己先前速度的趋势;
第二部分:自我认知,反映了粒子对自身历史经验的记忆,代表粒子有向自身最佳位置逼近的趋势;
第三部分:社会认知,反映了粒子间协同与知识共享的群体历史经验,代表粒子有向群体或领域历史最佳位置逼近的趋势。
算法实现流程图如下:
-
粒子群算法的构成要素分析
1.种群大小N
N过小,陷入局优的可能性很大; N过大,优化能力很好,但计算时间大幅提高,收敛速度慢。N一般取20-60,较难的问题取100-200。
2. 最大速度
作用在于维护算法的探索能力与开发能力的平衡, 较大时,增强了全局搜素能力,但粒子容易飞过目标区域,导致局部搜索能力下降。较小时,开发能力增强,但会极大地增加全局搜索的时间,容易陷入局部最优。速度取值一般为优化变量范围的10-30%。
3.权重因子w
w较大,有利于跳出局部极小点,增强粒子的勘探能力(全局搜索能力)。w较小,利于粒子的开发能力(局部搜索能力)。线性递减权重法:
(7)
式中:表示权重最大值,表示权重最小值,t表示当前迭代步数,表示最大迭代步数。
4.学习因子c1、c2
c1=0,“只有社会,没有自我”迅速丧失群体多样性,易陷入局优而无法跳出。c2=0,“只有自我,没有社会”完全没有信息的社会共享,导致算法收敛速度缓慢 。一般、都不为0,更容易保持收敛速度和搜索效果的均衡,是较好的选择。
-
C++程序测试Sphere函数
通过程序计算,迭代400步,用origin整理如下:
我们可以看出粒子群优化算法收敛速度非常快,在迭代100步左右就以及寻找到最优值,用时也非常少,下图为种群为20的粒子子寻优走向图。
-
总结
PSO算法的优点:
- 算法通用性强,不依赖于问题信息。
- 群体搜索,并具有记忆功能,保留局部个体和全局种群的最优信息,无需梯度信息。
- 原理结构简单,设置参数少,容易实现。
- 协同搜索,同时利用个体局部信息和群体全局信息指导搜索,收敛速度快。
PSO算法的缺点:
- 算法局部搜索能力较差,搜索精度不够高。
- 算法不能够绝对保证搜索到全局最优解,容易陷入局部极小解。
- 算法搜索性能对参数具有一定的依赖性。
-
visual studio2017c++源代码
pch.h头文件:
// Particle_swarm.cpp : 粒子群算法实现过程。
//开发人员:陈帅 开发日期:2019年8月4日-29日 邮箱:chenshuai0614@hrbeu.edu.cn
#ifndef PCH_H
#define PCH_H
#include <iostream>
# include <fstream>
#include <iomanip>
#include <math.h>
#include <vector>
#include<random>
#include<ctime>
//定义粒子的各种性质
using namespace std;
//产生随机小数或整数
class RandomNumber {
public:
RandomNumber() {
srand(time(0)); //析构函数,在对象创建时数据成员执行初始化操作
}
int integer(int begin, int end)
{
return rand() % (end - begin + 1) + begin;
}
double decimal(double a, double b)
{
return double(rand() % 10000) / 10000 * (b - a) + a;
}
};
//定义粒子群
class pso
{
private:
double c1_particle = 2.0; //c1学习因子1,自我认知
double c2_particle = 2.0; //c2学习因子2,社会认知
double w_max = 0.9; //最大惯性权重因子,影响着全局搜索
double w_min = 0.6; //最小惯性权重因子,局部深度搜索能力
int M_particle = 400; //最大迭代次数,
int D_particle = 2; //搜索空间的维数也叫变量个数
int N_particle = 20; //初始化群体的个体,N很小容易陷入局部优化,N很大优化能力很好,优化的寻优精度和运行时间
public:
vector <vector <double>>x_i; //粒子群位置
vector<vector <double>>v_i; //粒子群速度
vector<vector<double>>xp_best; //个体最优位置
vector<double> xg_best; //全局最优位置
vector<double>fp_best; //个体最优值
double fg_best; //全局最优值
double w_particle; //权重更新
vector<double>x_low = { -100 }; //优化变量下限值
vector<double>x_high = { 100 }; //优化变量上限值
vector<double>v_low = { -5 }; //飞行速度下限值
vector<double>v_high = { 5 }; //飞行速度上限值
double r1, r2; //r1、r2为增加随机搜索性
void Initialize_fit_extremum(); //给定初始化粒子群速度和位置,计算粒子群适应度,初始化个体极值和全局极值
void Optimization_iteration();//寻优迭代
};
double function(vector<double> x); //目标函数
#endif //PCH_H
Particle_swarm.cpp主函数
#include "pch.h"
RandomNumber r; //随机数
int main()
{ clock_t startTime, endTime; //定义程序开始运行时间和结束时间
startTime = clock(); //计时开始
pso PSO; //定义PSO相关参数和函数
//给定初始化粒子群速度和位置,计算粒子群适应度,初始化个体极值和全局极值
PSO.Initialize_fit_extremum();
//进入主要循环,按照公式依次迭代,直到满足精度要求
PSO.Optimization_iteration();
endTime = clock();//计时结束
cout << "run time:" << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
}
pso_function.cpp源文件:
#include "pch.h"
double function(vector<double> x)
{
double fx = 0;
int n = size(x);
//============================测试函数=============================
//1.Sphere函数 变量[-100,100]
for (int i = 0; i < n; i++)
{
fx = fx + pow(x[i], 2);
}
return fx;
}
void pso::Initialize_fit_extremum()
{
//===================给定初始化粒子群速度和位置==========
extern RandomNumber r; //定义全局随机数
xp_best.resize(N_particle, vector<double>(D_particle));
xg_best.resize(D_particle);
fp_best.resize(N_particle);
x_i.resize(N_particle, vector<double>(D_particle));
v_i.resize(N_particle, vector<double>(D_particle));
for (int i = 0; i < N_particle; i++)
{
for (int j = 0; j < D_particle; j++)
{
x_i[i][j] = r.decimal(x_low[0], x_high[0]); //随机初始化位置
v_i[i][j] = r.decimal(v_low[0] , v_high[0] ); //随机初始化速度
}
}
//================计算粒子群适应度,初始化个体极值和全局极值=========
for (int j = 0; j < N_particle; j++)
{
fp_best[j] = function(x_i[j]); //先计算各个粒子的适应度
xp_best[j] = x_i[j];
}
xg_best =x_i[0];
fg_best = function(xg_best);
for (int j = 1; j < N_particle ; j++)
{
if (function(x_i[j]) < fg_best)
{
xg_best = x_i[j]; //更新最优值对应的优化变量
fg_best = function(x_i[j]);
} //找到全局最优变量
}
}
//**************************************
//粒子群寻优迭代
//*************************************
void pso::Optimization_iteration()
{
extern RandomNumber r; //定义全局随机数
ofstream out1("粒子最优值走向.txt");
ofstream out("粒子群算法优化结果.txt");
double f;
for (int k = 0; k <M_particle; k++)
{
w_particle = w_max - k * (w_max - w_min) / M_particle; //更新权重
for (int j = 0; j < N_particle; j++)
{
r1 = r.decimal(0, 1.0), r2 = r.decimal(0, 1.0); //r1、r2产生随机数
for (int i = 0; i < D_particle; i++)
{
v_i[j][i] = w_particle * v_i[j][i] + c1_particle * r1*(xp_best[j][i]- x_i[j][i]) + c2_particle * r2*(xg_best[i] - x_i[j][i]); //更新位置
//速度越界处理,取边界值
if (v_i[j][i] < v_low[0])
{
v_i[j][i] = v_low[0];//越界更新为边界值
}
if (v_i[j][i] > v_high[0])
{
v_i[j][i] =v_high[0];//越界更新为边界值
}
x_i[j][i] = x_i[j][i] + v_i[j][i]; //更新速度
//位置越界处理,取边界值
if (x_i[j][i]< x_low[0] )
{
x_i[j][i] = x_low[0];//越界更新为最优值
}
if ( x_i[j][i] >x_high[0])
{
x_i[j][i] = x_high[0];//越界更新为边界值
}
}
f = function(x_i[j]);
if ( f< fp_best[j]) //个体选优
{
fp_best[j] = f;
xp_best[j] = x_i[j];
}
if (fp_best[j] < fg_best) //全局选优
{
xg_best = xp_best[j];
fg_best = fp_best[j];
}
for (int i = 0; i < D_particle; i++)
{
out1 << fixed << setw(12) << setprecision(5) << x_i[j][i];
}
fg_best = function(xg_best);
}
out1 << endl;
fg_best = function(xg_best);
out << k << fixed << setw(12) << setprecision(5) << fg_best << endl;
}
out << "最优变量:" << endl;
for (int i = 0; i < D_particle; i++)
{
out << "x" << i << "=" << fixed << setw(12) << setprecision(5) << xg_best[i] << endl;//输出最优变量
}
out << "最优值=" << fixed << setw(12) << setprecision(5) << fg_best << endl;
out.close();
out1.close();
}
-
源文件下载地址
各位阅读文章的朋友觉得文章不错可以给个好评或者点赞,觉得有问题可以指出来或者发邮箱chenshuai0614@hrbeu.edu.cn联系我!如需要转载请附上链接,谢谢各位朋友!
(更新于2020.05.05)