【AI】Python 实现粒子群算法

news2024/12/24 10:19:25

粒子群算法

1. 题目介绍

粒子群算法,其全称为粒子群优化算法 (Particle Swarm Optimization, PSO) 。它是通过模拟鸟群觅食行为而发展起来的一种基于群体协作的搜索算法。粒子群算法属于启发式算法也叫智能优化算法,其基本思想在于通过群体中个体之间的协作和信息共享来寻找最优解。

我们的目标是寻找一个函数的全局最小值或最大值,这个函数可以是二维或三维的,也可以是多维的。为了方便理解,下面通过一张图来直观地理解这个算法(也是本实验的结果):

在这里插入图片描述
可以看到,一开始图中有很多点,它们随机地分布在三维图像中,随着算法的进行,这些点会逐渐往全局最小值的方向靠拢,这个过程就像鸟类觅食一样,找到食物的鸟会带着其它鸟往食物靠拢。有的点移动得快,到达全局最小值后就不怎么动了;有些点移动得慢,会在局部来回震荡,始终也无法到达目标位置。但是不管怎样,只要有一个点到达了最优位置,就可以认为算法已经成功找到了最优解。

上图中这个三维函数的定义为:
f ( x , y ) = { 30 x − y ; x < m , y < m 30 y − x ; x < m , y ≥ m x 2 − y / 2 ; x ≥ m , y ≤ m 20 y 2 − 500 x ; x ≥ m , y ≥ m f(x, y) =\begin{cases} 30x-y; & x<m, y<m \\ 30y-x; & x<m,y≥m \\ x^2-y/2; & x≥m,y≤m \\ 20y^2-500x; & x≥m, y≥m \end{cases} f(x,y)=30xy;30yx;x2y/2;20y2500x;x<m,y<mx<m,ymxm,ymxm,ym
在本实验中,设置参数为 m = 30 , 0 < x , y < 60 m=30,0<x,y<60 m=30,0<x,y<60,参数也可以选择其它的值。
在三维空间中随机选取 s s s 个粒子,每个粒子的坐标满足: x , y ∈ ( 0 , 60 ) , z = f ( x , y ) x, y ∈ (0, 60), z=f(x,y) x,y(0,60),z=f(x,y) 。假设随机选取 30 30 30 个粒子,在初始状态下,这些粒子的位置分布如下图所示:
在这里插入图片描述
在后续的迭代过程中,每个粒子会不断向更优的位置靠拢。对于第 i i i 个粒子,这个过程可以很容易地表示成: x i k + 1 = x i k + o f f s e t x_{i}^{k+1}=x_i^k+offset xik+1=xik+offset。其中, k + 1 k+1 k+1 表示当前轮次, k k k表示上一轮。

从上述表达式可以看出,要不断优化迭代方向,最重要的操作就是在每一轮中都找一个最合适的 o f f s e t offset offset 值。聪明的计算机科学家们在穷举了无数条件后,最终想到了 o f f s e t offset offset 主要受三个值的影响:粒子上一轮移动所产生的惯性 v i k v_i^{k} vik;粒子搜索过程中局部最优值与当前位置的差 p i − x i k p_i-x_i^k pixik;所有粒子当前的全局最优值与当前位置的差 p g − x i k p_g-x_i^k pgxik

想象一下,你是一只鸟儿,和别的鸟儿在一片很大的森林中找一个食物最多的位置,根据可靠消息,食物最多的位置,周围那一片的食物也非常多。你每到一个位置都会记录一下这个地方有多少食物,现在已经找过了 20 个地方,其中 15 号位置的食物是最多的,有 10 斤虫子!但是根据别的鸟儿提供的信息,位置 243 的食物是最多的,足足有 100 斤虫子!一方面,你很想往 243 号位置飞,另一方面,你又不能轻易放弃之前的努力,所以你也不能偏离 15 号位置太远,同时,你因为一直在飞,最好不要突然掉头,所以你还受到惯性方向的影响!所以,最终你做出了一个艰难的决策:你会将 15 号位置的方向、243 号位置的方向、你本身飞行的方向做一个矢量叠加,最终得出了你下一步要飞行的方向。

因此, o f f s e t offset offset 的值实际上就可以用 v v v 来表示,它可以理解为 “速度”,因为每个点位置更新是使用矢量的加和来表示的,“速度” 一词非常恰当地形容了这层意思。不失一般性,下面的公式给出了粒子群位置坐标的更新公式:

v i k + 1 = w ⋅ v i k + c 1 ⋅ r a n d ( ) ⋅ ( p i − x i k ) + c 2 ⋅ r a n d ( ) ⋅ ( p g − x i k ) x i k + 1 = x i k + v i k + 1 v_{i}^{k+1}=w·v_{i}^{k}+c_1·rand()·(p_{i}-x_{i}^k)+c_2·rand()·(p_{g}-x_i^k) \\ x_i^{k+1}=x_i^k+v_i^{k+1} vik+1=wvik+c1rand()(pixik)+c2rand()(pgxik)xik+1=xik+vik+1

2. 代码实现

2.1 粒子的表示

每一个粒子需要记录当前点的坐标和前进速度,以及历史走过的最优位置。表示为:

class Particle:
    def __init__(self):
        # 当前点的坐标
        self.x = np.random.uniform(x_min, x_max)
        self.y = np.random.uniform(y_min, y_max)
        # 记录局部最优点和最优值
        self.x_local_best = self.x
        self.y_local_best = self.y
        self.f_local_best = function(self.x, self.y)
        # 当前点的前进速度
        self.vx = np.random.uniform(v_min, v_max)
        self.vy = np.random.uniform(v_min, v_max)

2.2 粒子群的表示

粒子群需要记录每一个点的信息,以及所有点经过的全局最优位置。同时它还要提供粒子群更新的方法,我们将它划分为两个部分的更新:速度 v v v 的更新和坐标 ( x , y ) (x, y) (x,y) 的更新,然后再用一个总的更新函数将这两个部分连接起来。代码如下:

class PSO:
    def __init__(self, iter_num, size):
        # size个点
        self.particles = [Particle() for _ in range(size)]
        # 记录全局最优点和最优值
        self.x_global_best = 20
        self.y_global_best = 20
        self.f_global_best = function(self.x_global_best, self.y_global_best)
        # 迭代轮数
        self.iter_num = iter_num
		# 用来作图
        self.f_global_best_records = []

    def update_v(self, particle):
        vx_new = w * particle.vx + \
                 c1 * np.random.rand() * (particle.x_local_best - particle.x) + \
                 c2 * np.random.rand() * (self.x_global_best - particle.x)
        vy_new = w * particle.vy + \
                 c1 * np.random.rand() * (particle.y_local_best - particle.y) + \
                 c2 * np.random.rand() * (self.y_global_best - particle.y)
        particle.vx = max(min(vx_new, v_max), v_min)
        particle.vy = max(min(vy_new, v_max), v_min)

    def update_xy(self, particle):
        x_new, y_new = particle.x + particle.vx, particle.y + particle.vy
        x_new, y_new = max(min(x_new, x_max), x_min), max(min(y_new, y_max), y_min)
        f_new = function(x_new, y_new)
        particle.x, particle.y = x_new, y_new

        if f_new < particle.f_local_best:
            particle.x_local_best = particle.x
            particle.y_local_best = particle.y
            particle.f_local_best = f_new
        if f_new < self.f_global_best:
            self.x_global_best = particle.x
            self.y_global_best = particle.y
            self.f_global_best = f_new

    def update(self):
        for _ in range(self.iter_num):
            x, y, f = [], [], []
            for particle in self.particles:
                self.update_v(particle)
                self.update_xy(particle)
                x.append(particle.x)
                y.append(particle.y)
                f.append(function(particle.x, particle.y))
            yield x, y, f
            self.f_global_best_records.append(self.f_global_best)

2.3 函数定义

函数的定义如下,它接受一个坐标 ( x , y ) (x, y) (x,y) 并返回函数值 z z z

def function(x, y):
    m = 30
    if x < m and y < m:
        return 30 * x - y
    elif x < m <= y:
        return 30 * y - x
    elif x >= m > y:
        return x ** 2 - y / 2
    elif x >= m and y >= m:
        return 20 * (y ** 2) - 500 * x

2.4 参数设置

总的来说,参数的设置如下:

iter_num, size = 100, 30
x_min, y_min, x_max, y_max = 0, 0, 60, 60
v_min, v_max = -1, 1
w, c1, c2 = 0.4, 0.2, 3

其中需要注意的是,速度范围 ( v m i n , v m a x ) (v_{min}, v_{max}) (vmin,vmax) 必须互为相反数,而且不能过大;如果不互为相反数,例如为 ( − 1 , 2 ) (-1, 2) (1,2),那么速度更容易为正数,粒子前进方向更容易往 > 0 > 0 >0 的趋势走;反之若为 ( − 2 , 1 ) (-2, 1) (2,1),粒子前进方向更容易往 < 0 < 0 <0 的趋势走。如果速度上下限过大,粒子容易发生跳跃,突然前进一大步到达定义域边界,反复震荡,最终导致粒子不往最优方向收敛。

参数 c 1 c_1 c1 控制粒子往局部最优值靠拢的趋势, c 2 c_2 c2 控制粒子往全局最优值靠拢的趋势。我们希望粒子往全局最优值靠一些,所以最好把 c 2 c_2 c2 设置得比 c 1 c_1 c1 大一些。

其它参数可以自行更改。

2.5 作图演示

为了直观地演示粒子的收敛过程,在每一轮迭代过程中都在三维函数中绘制一遍散点图,下面的代码展示了这个逻辑,这种流程对于其它需求也是很有借鉴意义的:

pso = PSO(iter_num, size)
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
for x, y, f in pso.update():
    ax.clear()
    ax.plot_surface(X, Y, Z, cmap='rainbow', alpha=0.4, rstride=1, cstride=1)
    ax.scatter(x, y, f, s=10, c='r', label='顺序点')
    plt.ion()
    plt.pause(0.1)
    plt.ioff()
print('result coordinate: ', pso.x_global_best, ' ', pso.y_global_best, ' ', pso.f_global_best)
plt.show()
plt.plot(range(len(pso.f_global_best_records)), pso.f_global_best_records, alpha=1)
plt.show()

2.6 完整代码

import numpy as np
import matplotlib.pyplot as plt
import time


def function(x, y):
    m = 30
    if x < m and y < m:
        return 30 * x - y
    elif x < m <= y:
        return 30 * y - x
    elif x >= m > y:
        return x ** 2 - y / 2
    elif x >= m and y >= m:
        return 20 * (y ** 2) - 500 * x


x_min, y_min, x_max, y_max = 0, 0, 60, 60
# 速度上下限必须互为相反数,保证方向的随机性
v_min, v_max = -1, 1
# c2越大越容易收敛
w, c1, c2 = 0.4, 0.2, 3
t = np.arange(x_min, x_max, 0.5)
X, Y = np.meshgrid(t, t)
Z = np.zeros(shape=X.shape)
for i in range(len(t)):
    for j in range(len(t)):
        Z[i][j] = function(X[i][j], Y[i][j])


class Particle:
    def __init__(self):
        # 当前点的坐标
        self.x = np.random.uniform(x_min, x_max)
        self.y = np.random.uniform(y_min, y_max)
        # 记录局部最优点和最优值
        self.x_local_best = self.x
        self.y_local_best = self.y
        self.f_local_best = function(self.x, self.y)
        # 当前点的前进速度
        self.vx = np.random.uniform(v_min, v_max)
        self.vy = np.random.uniform(v_min, v_max)


class PSO:
    def __init__(self, iter_num, size):
        # size个点
        self.particles = [Particle() for _ in range(size)]
        # 记录全局最优点和最优值
        self.x_global_best = 20
        self.y_global_best = 20
        self.f_global_best = function(self.x_global_best, self.y_global_best)
        # 迭代轮数
        self.iter_num = iter_num
        # 用来作图
        self.f_global_best_records = []

    def update_v(self, particle):
        vx_new = w * particle.vx + \
                 c1 * np.random.rand() * (particle.x_local_best - particle.x) + \
                 c2 * np.random.rand() * (self.x_global_best - particle.x)
        vy_new = w * particle.vy + \
                 c1 * np.random.rand() * (particle.y_local_best - particle.y) + \
                 c2 * np.random.rand() * (self.y_global_best - particle.y)
        particle.vx = max(min(vx_new, v_max), v_min)
        particle.vy = max(min(vy_new, v_max), v_min)

    def update_xy(self, particle):
        x_new, y_new = particle.x + particle.vx, particle.y + particle.vy
        x_new, y_new = max(min(x_new, x_max), x_min), max(min(y_new, y_max), y_min)
        f_new = function(x_new, y_new)
        particle.x, particle.y = x_new, y_new

        if f_new < particle.f_local_best:
            particle.x_local_best = particle.x
            particle.y_local_best = particle.y
            particle.f_local_best = f_new
        if f_new < self.f_global_best:
            self.x_global_best = particle.x
            self.y_global_best = particle.y
            self.f_global_best = f_new

    def update(self):
        for _ in range(self.iter_num):
            x, y, f = [], [], []
            for particle in self.particles:
                self.update_v(particle)
                self.update_xy(particle)
                x.append(particle.x)
                y.append(particle.y)
                f.append(function(particle.x, particle.y))
            yield x, y, f
            self.f_global_best_records.append(self.f_global_best)


def main():
    iter_num, size = 100, 30
    pso = PSO(iter_num, size)
    fig = plt.figure(figsize=(8, 6))
    ax = fig.add_subplot(111, projection='3d')
    for x, y, f in pso.update():
        ax.clear()
        ax.plot_surface(X, Y, Z, cmap='rainbow', alpha=0.4, rstride=1, cstride=1)
        ax.scatter(x, y, f, s=10, c='r', label='顺序点')
        plt.ion()
        plt.pause(0.1)
        plt.ioff()
    print('result coordinate: ', pso.x_global_best, ' ', pso.y_global_best, ' ', pso.f_global_best)
    plt.show()
    plt.plot(range(len(pso.f_global_best_records)), pso.f_global_best_records, alpha=1)
    plt.show()


if __name__ == '__main__':
    main()

3. 结果演示

运行上面给出的完整代码,程序结果为:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

可以看出,在迭代 60 60 60 轮时 f f f 就开始收敛了,这说明有粒子已经找到了近似的全局最优值,之后的所有操作都是为了进一步逼近这个最优值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/64358.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零入门容器云网络-6:基于veth pair、namespace以及路由技术,实现跨主机命名空间之间的通信测试案例

已发表的技术专栏&#xff08;订阅即可观看所有专栏&#xff09; 0  grpc-go、protobuf、multus-cni 技术专栏 总入口 1  grpc-go 源码剖析与实战  文章目录 2  Protobuf介绍与实战 图文专栏  文章目录 3  multus-cni   文章目录(k8s多网络实现方案) 4  gr…

ROS系列:第六章 机器人建模

文章目录六、机器人系统仿真1.概述仿真优势:仿真缺陷:2. URDF集成Rviz基本流程1.创建功能包&#xff0c;导入依赖2.编写 URDF 文件3.在 launch 文件中集成 URDF 与 Rviz4.在 Rviz 中显示机器人模型5.优化 rviz 启动3. URDF语法详解3.1 URDF语法详解01_robotrobot1.属性2.子标签…

Promethus实操部署ARM架构 麒麟系统

由于有个地市局的等保测评要求安装监控软件&#xff0c;实操安装普罗米修斯和Zabbix&#xff0c;原本想安装Zabbix在本地安装非常顺利&#xff0c;但是服务器是华为鹏鲲的、ARM架构&#xff0c;Zabbix的有些东西找不到ARM的&#xff0c;所以两个都尝试了下。本篇讲解下Promethu…

协同过滤推荐算法

协同过滤&#xff1a;利用集体智慧&#xff0c;借鉴相关人群的观点进行推荐。 过去兴趣相似的用户在未来的兴趣也会相似&#xff1b;相似的用户会产生相似的历史行为数据。 根据历史行为&#xff0c;产生相似用户&#xff0c;分析出推荐结果。 用一句大白话说&#xff0c;其实也…

Android请求应用权限

文章目录前言参考一、请求应用权限基本原则二、请求权限的流程&#xff08;官网摘抄&#xff09;三、请求权限编码1.允许系统管理权限请求代码2.自行管理权限请求代码总结前言 学习Android为什么需要动态申请危险权限 学会Android应用危险权限申请的方式 参考 Android官方文档…

8 种 Python 定时任务的解决方案

在日常工作中&#xff0c;我们常常会用到需要周期性执行的任务&#xff0c;一种方式是采用 Linux 系统自带的 crond 结合命令行实现&#xff0c;另外一种方式是直接使用Python。 最近我整理了一下 Python 定时任务的实现方式&#xff0c;内容较长&#xff0c;建议收藏后学习&a…

uni-app云开发(我直接访问后端)

uniCloud 是 DCloud 联合阿里云、腾讯云&#xff0c;为开发者提供的基于 serverless 模式和 js 编程的云开发平台。 熟悉的js的程序员&#xff0c;轻松搞定前后台整体业务。实现了前端完成前后端工作的可能 用法&#xff1a; 第一步新建uniCloud项目 点击文件 ——>新建—…

Hue编译安装使用

简介 由于大数据框架很多&#xff0c;为了解决某个问题&#xff0c;一般来说会用到多个框架&#xff0c;但是每个框架又都有自己的web UI监控界面&#xff0c;对应着不同的端口号。比如HDFS(9870)、YARN(8088)、MapReduce(19888)等。这个时候有一个统一的web UI界面去管理各个大…

高斯混合模型下的变分推断

大概从下面几个部分学习&#xff1a; 1.EM算法 人人都懂EM算法 - 知乎 (zhihu.com) 18分钟理解EM算法 - 知乎 (zhihu.com) 变分贝叶斯深度学习综述 - 知乎 (zhihu.com) 【未看完】 EM算法存在的意义是什么&#xff1f; - 知乎 (zhihu.com)【八种境界】 EM 算法具备收敛性…

java计算机毕业设计ssm体育赛事管理系统App2qrcr(附源码、数据库)

java计算机毕业设计ssm体育赛事管理系统App2qrcr&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#x…

[附源码]Python计算机毕业设计Django酒店物联网平台系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

小目标检测文章阅读

无人机上目标检测的特点&#xff1a; 1、图像特点 在多数情况下&#xff0c;无人机的拍摄视野很大&#xff0c;包含丰富的视觉内容&#xff0c;虽然它提供了更全面的场景信息。 缺点&#xff1a; 1&#xff09;但是待检测的目标对象通常在图像中占比较小&#xff0c;且没有足…

法国巴黎索邦大学博士后—实验物理学

【国外博士后招聘-法国博士后】法国巴黎索邦大学博士后—实验物理学 索邦大学&#xff08;法文&#xff1a;Sorbonne Universit&#xff1b;英文&#xff1a;Sorbonne University&#xff09;简称“索邦”&#xff08;Sorbonne&#xff09;&#xff0c;是一所位于法国巴黎拉丁区…

多线程环境下的单例模式

✨✨hello&#xff0c;愿意点进来的小伙伴们&#xff0c;你们好呐&#xff01; &#x1f43b;&#x1f43b;系列专栏&#xff1a;【JavaEE初阶】 &#x1f432;&#x1f432;本篇内容&#xff1a;基于多线程的单例模式 &#x1f42f;&#x1f42f;作者简介:一名现大二的三非编程…

Linux虚拟化网络之路由配置

一、Linux路由配置 如果要在不同网段直接通讯&#xff0c;需要添加路由&#xff0c;Linux添加路由命令如下&#xff1a; route [add|del] [-net|-host] target [netmask Nm] [gw Gw] [[dev] If] add : 添加一条路由规则&#xff1b;del : 删除一条路由规则&#xff1b;-net …

Win11如何开启移动中心页面的操作方法教学

Win11如何开启移动中心页面的操作方法教学分享。有用户不知道怎么去打开移动中心&#xff0c;开启这个页面我们可以去进行屏幕亮度调整、声音调整、笔记本电池状态、外接显示器/投影仪、以及幻灯片显示模式等功能集中到一个面板上进行管理设置。如何开启这个页面&#xff0c;来…

【教程】超详细通过Shizuku转生支付宝集成XQ_Crystal来自动收能量

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.blog.csdn.net] 通过Shizuku是比应用转生更好更稳定的方法&#xff01; 可以先看这篇&#xff1a;免Root使用Xposed插件并开启蚂蚁森林自动偷能量,比应用转生好 还不会的&#xff0c;继续往下。看完还不会&#xff…

手机银行APP评测系列:天津银行持续优化手机银行用户体验,但仍需加强细节提升

易观分析&#xff1a;作为银行金融服务线上场景渗透的有效抓手&#xff0c;当前手机银行APP已经成为其触达用户的重要渠道。随着银行发力场景服务平台成为发展趋势&#xff0c;5G技术问世对金融服务场景端提出新要求&#xff0c;用户体验反馈成为银行线上场景化运营的重要一环。…

JavaScript—分支结构和循环结构整理

目录 一、流程控制 二、分支结构 1. if语句 2. if…else语句 3. if…else if语句 4. switch语句 5. 条件表达式构成的选择结构 三、循环结构 1.while循环 2. do-while循环 3. for循环 3.1 for循环转换为while循环 3.2 断点调试 4. 循环嵌套 JavaScript 是一种解释…

微服务框架 SpringCloud微服务架构 16 SpringAMQP 16.6 FanoutExchange

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构16 SpringAMQP16.6 FanoutExchange16.6.1 发布订阅 - Fanout Exchange16.6…