粒子群(PSO)算法的理解与应用

article/2025/10/1 10:44:45

最近在学习粒子群算法,看了很多资料都有点摸不清头脑,直到看了一篇博客中超级简洁的粒子群C++实现代码,才明白粒子群算法的原理,真心感谢博主,在此贴出博主的博客地址:

http://blog.sina.com.cn/s/blog_4ed027020100c9lx.html

在前面的文章中,我们提到的梯度下降法、牛顿法、高斯-牛顿法,以及LM算法等都属于最优化算法,这些最优化算法的共同点是优化一组可能的解,使该解尽可能接近真实解。粒子群算法(也称为PSO算法)也属于最优化算法,但该算法与上述提到算法的主要区别在于,该算法同时优化多组可能的解,最后在多组可能的解中选择最接近真实解的一组作为最终解。每一组可能的解就是一个粒子,因此多组可能解组成了粒子群,这就是该算法名称的由来。下面将讲解我对粒子群算法的理解,并将该算法应用于一个简单例子的最优化求解。

1. 粒子群算法的核心思路

粒子群算法被提出的灵感来源于鸟群觅食。如下图,鸟群觅食过程中,每只鸟沿着各个方向飞行去寻找食物,每只鸟儿都能记住到目前为止自己在飞行过程中最接近食物的位置,同时每只鸟儿之间也有信息共享,它们会比较到目前为止各自与食物之间的最近距离,从各自的最近距离中,选择并记忆整体的一个最近距离位置。由于每只鸟儿都是随机往各个方向飞行的,各自的最近距离位置与整体最近距离位置不断被更新,也即它们记忆中的最近位置越来越接近食物,当它们飞行到达的位置足够多之后,它们记忆的整体最近位置也就达到了食物的位置。

抽象成数学模型,每只鸟儿就是一个粒子,食物的位置也就是问题的最优解,鸟儿与食物的距离也即当前粒子的目标函数值。比如要求z=x*x+y*y的最优解,设置粒子数为6个,如下图所示,相当于各个粒子在曲面上滚动,每个粒子i(0≤i≤5)记住自己滚动过程中(迭代)的最低位置(位置越低z值越小)Zi(0≤i≤5),同时不同粒子之间也有交流,它们会比较Z0~Z5,从中取得一个最小值作为当前的全局最低位置。

2. 粒子群算法的实现

假设目标函数有n个输入参数:f(x1, x2, ..., xn)。

对于每个粒子,它包含的元素

(1) 当前时刻位置:(x1, x2, ..., xn)

(2) 当前时刻的目标函数值(也称为适应度):f(x1, x2, ..., xn)

(3) 该粒子的历史最优位置:(x1_pbest, x2_pbest, ..., xn_pbest)

(4) 该粒子的历史最优目标函数值:f_pbest = f(x1_pbest, x2_pbest, ..., xn_pbest)

对于全部粒子,它们共有的元素:

(1) 粒子总数:num

(2) 迭代总次数:cnt。粒子群算法也是一个迭代的过程,需要多次迭代才能获取到理想的最优解。

(3) 全局最优位置:(x1_gbest, x2_gbest, ..., xn_gbest)

(4) 全局最优目标函数值:f_gbest = f(x1_gbest, x2_gbest, ..., xn_gbest)

(5) 位置随机化的上下限:xmin,xmax。迭代开始的时候以及迭代的过程中,均需要对粒子的位置进行随机分布,需要设置随机分布的上下限,不然随机分布偏离得太远,会严重影响优化结果。

(6) 速度的上下限:Vmin,Vmax。迭代过程中,速度也具有一定的随机性,需要限制速度的大小在一定范围内,不然如果速度值太大也会严重影响优化结果。

(7) 速度计算参数:c1、c2。通常取1.0~1.8的值。

粒子位置的更新公式:

参考上述提到的博客,对于每一个粒子的每一个位置参数xi,其位置更新公式如下,其中randf为0~1的随机数,c1与c2通常取1.0~1.8之间的固定值。

为了加快收敛速度,根据速度具有惯性的原理,后来人们提出了在速度计算中增加惯性,也即加上上一轮迭代时该位置参数的速度。如下式,其中w为0~1的参数,通常随着迭代次数的增加,逐渐减小w,因为越到后面可能解就越接近真实解,迭代收敛就越慢,所以需要减小w来放慢速度,否则容易错过最优解。

C++代码实现(本代码参考了上述提到的博客的代码):

定义全局参数:

#define DATA_SIZE 500
const int NUM = 300;  //粒子总数
const float c1 = 1.65;  //速度计算参数1
const float c2 = 1.65;  //速度计算参数2
const float xmin = -150;   //位置下限
const float xmax = 150;    //位置上限const float vmin = -250.5;   //速度下限
const float vmax = 250.5;    //速度上线

定义粒子结构体:

struct particle
{float x[DATA_SIZE];   //该粒子的当前时刻位置float bestx[DATA_SIZE];//该粒子的历史最优位置float f;       //该粒子的当前适应度float bestf;   //该粒子的历史最优适应度
}swarm[NUM];   //总共有num个粒子

获取0~1的随机数:

#define randf ((rand()%10000+rand()%10000*10000)/100000000.0) //产生0-1随机浮点数

目标函数,显然目标函数的真实解为(0, 1, 2,..., dim-1):

float f1(float x[], int dim)
{float z = 0;for (int i = 0; i < dim; i++){z += (i+20)*(x[i] - i)*(x[i] - i);}return z;
}

迭代优化过程:

/*
best为全局最优位置
DIM为目标函数的输入参数总个数,也即每个粒子的位置参数总个数
*/
void PSO(float *best, int DIM)
{for (int i = 0; i < DIM; i++)//初始化全局最优{best[i] = randf*(xmax - xmin) + xmin; //随机生成xmin~xmax的随机数}//初始化全局最优目标函数值为一个非常大的值double gbestf = 100000000000000.0;  for (int i = 0; i < NUM; i++)  //初始化粒子群{particle* p1 = &swarm[i];   //获取每一个粒子结构体的地址for (int j = 0; j < DIM; j++){//随机生成xmin~xmax的随机数作为该粒子的位置参数p1->x[j] = randf*(xmax - xmin) + xmin;}p1->f = f1(p1->x, DIM);   //计算当前时刻的目标函数值p1->bestf = 100000000000000.0;  //初始化每个粒子的历史最优目标函数值为一个非常大的值}float *V = (float *)calloc(DIM, sizeof(float));const int cnt = 2000;   //总共2000次迭代float w = 0.0025/(cnt-1);  //设置w初值,后面逐渐减小for (int t = 0; t < cnt; t++)   //cnt次迭代{for (int i = 0; i < NUM; i++)  //NUM个粒子{particle* p1 = &swarm[i];for (int j = 0; j < DIM; j++)   //计算速度,并更新位置{//w*(cnt-1-t)随着t的增加逐渐减小V[j] = w*(cnt-1-t)*V[j] + c1*randf*(p1->bestx[j] - p1->x[j]) + c2*randf*(best[j] - p1->x[j]);//V[j] = c1*randf*(p1->bestx[j] - p1->x[j]) + c2*randf*(best[j] - p1->x[j]);//限制速度的上下限V[j] = (V[j] < vmin) ? vmin : ((V[j] > vmax) ? vmax : V[j]);p1->x[j] = p1->x[j] + V[j];  //更新位置参数}p1->f = f1(p1->x, DIM);   //计算当前粒子的当前时刻目标函数值//如果当前粒子的当前时刻目标函数值小于其历史最优值,则替换该粒子的历史最优if (p1->f < p1->bestf)   {for (int j = 0; j < DIM; j++){p1->bestx[j] = p1->x[j];}p1->bestf = p1->f;}//如果当前粒子的历史最优值小于全局最优值,则替换全局最优值if (p1->bestf < gbestf)   {for (int j = 0; j < DIM; j++){best[j] = p1->bestx[j];}//这里有点不理解,为什么替换全局最优值之后要重新随机分布该粒子的位置参数?//如果没有这部分代码,整体优化效果就会很差for (int j = 0; j < DIM; j++) {p1->x[j] = randf*(xmax - xmin) + xmin;}gbestf = p1->bestf;printf("t = %d, gbestf = %lf\n", t, gbestf);}}}free(V);
}

主函数:

void main(void)
{int DIM = 400;//维数float gbestx[DATA_SIZE];//全局最优位置PSO(gbestx, DIM);printf("全局最优位置:\n");for(int i = 0; i < DIM; i++){printf("%f ", gbestx[i]);if (i > 0 && i % 7 == 0)printf("\n");}printf("\n");
}

运行上述代码,得到结果如下,可知获取的最优解还是非常接近真实解的。

计算速度时,分别加入惯性与不加入惯性,记录每轮迭代的全局最优目标函数值,如下图所示,可以看到加入惯性之后全局最优目标函数值减小得更快。


http://chatgpt.dhexx.cn/article/GbyZnRwa.shtml

相关文章

6套粒子群算法(内含matlab代码)

粒子群算法(1)----粒子群算法简介 一、粒子群算法的历史 粒子群算法源于复杂适应系统&#xff08;Complex Adaptive System,CAS&#xff09;。CAS理论于1994年正式提出&#xff0c;CAS中的成员称为主体。比如研究鸟群系统&#xff0c;每个鸟在这个系统中就称为主体。主体有适…

粒子群算法(PSO)详解

1 粒子群PSO算法简介 1.1 维基百科的解释 粒子群算法&#xff08;Particle Swarm Optimization&#xff0c;简称PSO&#xff09;&#xff0c;或称粒子群优化&#xff0c;是属于人工智能算法&#xff0c;公元1995年由肯尼迪&#xff08;Kennedy&#xff09;与埃伯哈特&#xf…

优化算法——粒子群算法(PSO)

一、粒子群算法的概述 粒子群算法(PSO)属于群智能算法的一种&#xff0c;是通过模拟鸟群捕食行为设计的。假设区域里就只有一块食物&#xff08;即通常优化问题中所讲的最优解&#xff09;&#xff0c;鸟群的任务是找到这个食物源。鸟群在整个搜寻的过程中&#xff0c;通过相互…

粒子群算法(PSO) 介绍

算法理解 粒子群算法&#xff0c;又叫鸟群算法&#xff0c;可见是受鸟群捕食行为的启发。它属于遗传算法、群智算法。粒子群算法关注于粒子的两个属性&#xff1a;位置和速度。每个粒子在空间中单独搜寻&#xff0c;它们记得自己找到的过最优解&#xff0c;也知道整个粒子群当…

【优秀作业】粒子群算法

粒子群优化算法 一、概述 粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;的思想来源于对鸟捕食行为的模仿&#xff0c;最初&#xff0c;Reynolds.Heppner 等科学家研究的是鸟类飞行的美学和那些能使鸟群同时突然改变方向&#xff0c;分散…

Dex加固与反编译

编译与反编译 编译 将java代码转换为Dalvik字节码 将res资源文件、AndroidManifest.xml等配置文件编译为二进制文件 反编译 将DEX文件转换为jar包或者Smali文件 将二进制资源文件还原为资源源码文件 编译与反编译是相对的过程&#xff0c;转换过程分别由编译器和反编译器实…

编译与反编译

编译&#xff1a;高级语言转换成计算机认识的低级语言 编译的主要的目的是将便于人编写、阅读、维护的高级语言所写作的源代码程序&#xff0c;翻译为计算机能解读、运行的低级语言的程序&#xff0c;也就是可执行文件。 反编译&#xff1a;Java的反编译&#xff0c;一般是将…

反编译网站

最近帮一个公司反编译了一个他们在用的网站&#xff0c;是一个印照片&#xff0c;然后群(384389229)里面的伙伴们&#xff08;专指&#xff1a;魂牵悲梦&#xff09;&#xff0c;叫我写个反编译的教程出来&#xff0c;由于前面时间很忙&#xff0c;一拖再拖到了现在终于有空就写…

编译/反编译

1.Android APK 1.软件 1.apktool 1.作用&#xff1a;反编译apk或重新打包apk 2.dex2jar 1.作用&#xff1a;将Android的可执行文件.dex转换为.jar 3.jd-gui 1.作用&#xff1a;方便阅读jar文件的代码工具 2.步骤 1.通过apktool将apk软件反编译2.使用dex2jar将classes.dex文件转…

反编译(Decompilers)

工具下载 调试工具反汇编工具反编译工具PE相关工具编译工具编辑工具.NET工具脱壳工具加壳工具补丁工具监视软件代码计算 密码学工具其它 反编译&#xff08;Decompilers&#xff09; VFP程序 UnFoxAll 3.0专业增强版  优点&#xff1a;界面和功能较实用缺点&#xff1a;支持到…

反编译器

转自&#xff1a;https://blog.csdn.net/kongwei521/article/details/54927689 在项目开发过程中&#xff0c;估计也有人和我遇到过同样的经历&#xff1a;运行环境出现了重大Bug亟需解决、或者由于电脑挂了、旧代码覆盖新代码&#xff0c;而在这种情况下&#xff0c;我们不能…

如何构建反汇编代码?

大型的非结构化反汇编指令堆几乎不可能被分析&#xff0c;所以大多数反汇编工具都会以某种简单的分析方法来构造反汇编代码。在本节中&#xff0c;我们将会讨论通过反汇编工具恢复的通用代码和数据结构&#xff0c;以及这些通用代码和数据结构会如何帮助我们进行二进制分析。 …

反编译

反编译 我们都知道&#xff0c;Android程序打完包之后得到的是一个APK文件&#xff0c;这个文件是可以直接安装到任何Android手机上的&#xff0c;我们反编译其实也就是对这个APK文件进行反编译。Android的反编译主要又分为两个部分&#xff0c;一个是对代码的反编译&#xff…

解决openai.error.APIConnectionError: Error communicating with OpenAI

一、问题描述 可以fanqiang&#xff0c;但是使用openai的接口还是报错如下的openai.error.APIConnectionError: Error communicating with OpenAI问题&#xff1a; File "D:\Anaconda3\envs\gms\lib\site-packages\openai\api_resources\abstract\engine_api_resource.py…

【Nginx应用】1.理解正、反向代理和负载均衡

在讲解Nginx之前&#xff0c;我们首先要理解什么是正向代理和反向代理。因为Nginx作为负载均衡的作用时&#xff0c;扮演的就是一个代理的角色&#xff0c;理解了正反向代理&#xff0c;对我们接下来学习Nginx会很有帮助1.正向代理 在我们的日常生活中其实就已经使用到了正向代…

软件安全实验——局域网DDoS攻击

文章目录 实验任务实验过程DoS攻击与DDoS攻击ping命令参数实施DDoS攻击 实验任务 对局域网内IP地址为10.12.186.186的主机&#xff08;已关闭防火墙&#xff09;发起基于网络流量的DDoS攻击。 实验过程 DoS攻击与DDoS攻击 DoS是Denial of Service的简称&#xff0c;即拒绝服务…

kali局域网攻击(一)

前言 很久以前的博客才发现&#xff0c;发布一下。 这个系列以后有时间再做。 arp攻击 arp路由链表,感兴趣的自行百度,我的博客我的笔记. 路由指向 介绍两个东西. echo 0 >/proc/sys/net/ipv4/ip_forward #让经过的数据不留通 echo 1 >/proc/sys/net/ipv4/ip_forward…

嗅探欺骗之Ettercap局域网攻击

嗅探欺骗 ——Ettercap局域网攻击 最近在练习使用ettercap工具&#xff0c;下面来介绍一下用ettercap实施嗅探以及欺骗的实验过程。 嗅探&#xff1a; 首先&#xff0c;我们把虚拟机作为攻击者&#xff0c;物理机作为受害者。①在虚拟机中打开一个终端&#xff0c;输入命令ett…

当代局域网攻击软件到底带来了什么

20世纪00年代晚期21世纪初&#xff0c;计算机网络技术及其安全技术得到了迅速发展&#xff0c;出现了一系列新的局域网攻击工具&#xff0c;如Metasploit&#xff0c;它是一款强大的局域网渗透测试开发框架&#xff1b;NetWox&#xff0c;它可以扫描网络中的漏洞&#xff1b;Wi…

局域网arp攻击_ARP局域网攻防浅析

ARP官方释意&#xff1a;地址解析协议&#xff0c;即ARP(Address Resolution Protocol)&#xff0c;是根据获取的一个。发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机&#xff0c;并接收返回消息&#xff0c;以此确定目标的物理地址(MAC)&#xff1b;收到返回…