智能優化算法——粒子羣算法原理(附代碼)

目錄

基本概念

算法實現

粒子羣算法的構成要素分析  

C++程序測試Sphere函數

總結

visual studio2017c++源代碼

源文件下載地址


  • 基本概念

           粒子羣優化算法(particle swarm optimization,PSO)屬於進化算法的一種,它源於鳥羣捕食的行爲研究。基本思想是通過羣體中個體之間的協作和信息共享來尋找最優解。在PSO中,每個優化問題的潛在解都是搜索空間中的一隻鳥,抽象爲粒子,每個粒子都有一個由目標函數決定的適應值(fitness value),以及決定它們飛行的方向和距離。 PSO具有實現容易、精度高、收斂快等優點。

  • 算法實現

   在我編寫的程序裏可以這樣理解,我們需要定義基本粒子類粒子羣類,每個粒子含有固有的屬性,比如速度、位置以及儲存更新的變量,粒子羣類似,含有個體極值、全局極值以及計算函數。

   假設在一個D維的目標搜索空間中,有N個粒子組成一個羣落,其中第i個粒子表示爲一個D維的向量,簡單來說每個粒子都會對應優化問題相應的優化變量

           X_{i}=\left ( x_{i1}, x_{i2},\cdots x_{iD}\right ) \qquad i=1,2,\cdots N                           (1)

   第i個粒子的飛行速度也是一個D維的向量:

           VV_{i}=\left ( v_{i1}, v_{i2},\cdots v_{iD}\right ) \qquad i=1,2,\cdots NV_{i}=\left ( v_{i1}, v_{i2},\cdots v_{iD}\right ) \qquad i=1,2,\cdots NX_{i}=\left ( x_{i1}, x_{i2},\cdots x_{iD}\right ) \qquad i=1,2,\cdots NV_{i}=\left ( x_{i1}, x_{i2},\cdots x_{iD}\right ) \qquad i=1,2,\cdots NV_{i}=\left ( v_{i1}, v_{i2},\cdots v_{iD}\right ) \qquad i=1,2,\cdots N                              (2)

           第i個粒子迄今爲止搜索到的最優V位置稱爲個體極值

                                   p_{best}\left ( p_{i1}, p_{i2},\cdots p_{iD}\right ) \qquad i=1,2,\cdots N                               (3)

           整個粒子羣迄今爲止搜索到的最優位置爲全局極值

                                             g_{best}=\left ( p_{g1}, p_{g2},\cdots p_{gD}\right )                                              (4)

          個體極值與全局極值尋優時,粒子根據下式更新位置速度

                      V_{id}^{k}=w*V_{id}^{k-1}+c_{1}r_{1}\left ( p_{id}-x_{id}^{k-1} \right )+c_{2}r_{2}\left ( p_{gd}-x_{id}^{k-1} \right )                   (5)

                                                x_{id}^{k}=x_{id}^{k-1}+V_{id}^{k}                                                      (6)

式中:w爲慣性權重,非負數,調節對解空間的搜索範圍,c1、c2爲學習因子,也稱爲加速常數,r1、r2增加隨機搜索性。

式(5)由三部分組成:

第一部分:慣性部分,反映了粒子的運動習慣,代表粒子有維持自己先前速度的趨勢;

第二部分:自我認知,反映了粒子對自身歷史經驗的記憶,代表粒子有向自身最佳位置逼近的趨勢;

第三部分:社會認知,反映了粒子間協同與知識共享的羣體歷史經驗,代表粒子有向羣體或領域歷史最佳位置逼近的趨勢。

算法實現流程圖如下:

  • 粒子羣算法的構成要素分析  

1.種羣大小N

        N過小,陷入局優的可能性很大; N過大,優化能力很好,但計算時間大幅提高收斂速度慢。N一般取20-60,較難的問題取100-200。

2. 最大速度V_{m}

       作用在於維護算法的探索能力開發能力的平衡, V_{m}較大時,增強了全局搜素能力,但粒子容易飛過目標區域,導致局部搜索能力下降。較小時,開發能力增強,但會極大地增加全局搜索的時間,容易陷入局部最優。速度取值一般爲優化變量範圍的10-30%。

3.權重因子w

      w較大,有利於跳出局部極小點,增強粒子的勘探能力全局搜索能力)。w較小,利於粒子的開發能力局部搜索能力)。線性遞減權重法:

                              w=w_{max}-\frac{t*\left ( w_{max}-w_{min} \right )}{t_{max}}                                                    (7)    

式中:w_{max}表示權重最大值,w_{min}表示權重最小值,t表示當前迭代步數,t_{max}表示最大迭代步數。

4.學習因子c1、c2

     c1=0,“只有社會,沒有自我”迅速喪失羣體多樣性,易陷入局優而無法跳出。c2=0,“只有自我,沒有社會”完全沒有信息的社會共享,導致算法收斂速度緩慢 。一般、都不爲0,更容易保持收斂速度和搜索效果的均衡,是較好的選擇。

  • C++程序測試Sphere函數

                                                    f\left ( x \right )=\sum_{i=1}^{D}x_{i}^{2}

通過程序計算,迭代400步,用origin整理如下:

我們可以看出粒子羣優化算法收斂速度非常快,在迭代100步左右就以及尋找到最優值,用時也非常少,下圖爲種羣爲20的粒子子尋優走向圖。

  • 總結

PSO算法的優點:

  1. 算法通用性強,不依賴於問題信息。
  2. 羣體搜索,並具有記憶功能,保留局部個體和全局種羣的最優信息,無需梯度信息。
  3. 原理結構簡單,設置參數少,容易實現。
  4. 協同搜索,同時利用個體局部信息和羣體全局信息指導搜索,收斂速度快

PSO算法的缺點:

  1. 算法局部搜索能力較差,搜索精度不夠高。
  2. 算法不能夠絕對保證搜索到全局最優解,容易陷入局部極小解
  3. 算法搜索性能對參數具有一定的依賴性。
  • visual studio2017c++源代碼

pch.h頭文件:

// Particle_swarm.cpp : 粒子羣算法實現過程。
//開發人員:陳帥    開發日期:2019年8月4日-29日   郵箱:[email protected]
#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();
}
  • 源文件下載地址

https://download.csdn.net/download/weixin_41788456/11828583

各位閱讀文章的朋友覺得文章不錯可以給個好評或者點贊,覺得有問題可以指出來或者發郵箱[email protected]聯繫我!如需要轉載請附上鍊接,謝謝各位朋友!

(更新於2020.05.05)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章