目錄
-
基本概念
粒子羣優化算法(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日 郵箱:[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();
}
-
源文件下載地址
各位閱讀文章的朋友覺得文章不錯可以給個好評或者點贊,覺得有問題可以指出來或者發郵箱[email protected]聯繫我!如需要轉載請附上鍊接,謝謝各位朋友!
(更新於2020.05.05)