粒子群算法

1、 粒子群算法概述

  粒子群算法(Particle Swarm Optimization,PSO)由Kennedy和Eberhart于1995年提出。该算法的思想来源于对鸟类捕食行为的研究,鸟之间通过集体的协作使得群体能够找到最多的食物,PSO便是通过模拟鸟群飞行觅食的行为,来寻找最优解的算法,这是一种基于群体智能(Swarm Intelligence)的优化方法。在粒子群算法中,我们将鸟群抽象成粒子群,用一个粒子来代表一只鸟。PSO目标就是:通过一群粒子在解空间中进行搜索,找到使得适应度函数(fitness function)取得最大值(或最小值)的解。

2、算法介绍

  在正式介绍算法前,先约定好一些符号。假设粒子在 d 维空间中进行搜索,种群大小为N(一共有N个粒子),适应度函数为f(⋅)。
   xi(k) ∈ Rd 表示第 i 个粒子在迭代 k 次后的位置
   vi(k) ∈ Rd 表示第 i 个粒子的在迭代 k 次后的速度
   pbesti ∈ Rd 表示第 i 个粒子所经过的历史最优位置
   gbest ∈ Rd 表示整个种群所找到的历史最优位置

则第 i 个粒子位置更新公式为:
在这里插入图片描述
其中
   w 是惯性系数,w 越大说明粒子更倾向于保持原来的运动状态
   c1 是自我认知系数,c1 越大说明粒子更倾向于相信自己的经验(认知)
   c2 是全局认知系数,c2 越大说明粒子更倾向于相信整个群体的经验(认知)
   r1, r2 是随机数,通常是 [0,1] 上均匀产生的随机数

从更新公式可以看出,粒子下一时刻的运动速度收到三个因素的影响:当前时刻的速度、当前自己找到的最优解的位置以及当前全局最优解的位置。可以用一个图表示粒子位置的更新过程:
在这里插入图片描述

3、算法步骤

基本算法描述如下:

   1、首先,人为设置粒子的种群大小 N ,适应度函数f(⋅),惯性系数 ω ,以及 c1, c2
   2、随机初始化每个粒子的位置 xi(0),初始速度vi(0) ;然后记录当前每个粒子的历史最优解和全局最优解。
   3、不断循环迭代,每循环一次就更新种群中每个粒子的状态,直至达到算法的停止条件。最后,输出所找到的最优解。

算法的停止条件:

   1、最简单的就是直接设置一个最大迭代上限,超出最大迭代次数后直接退出。
   2、设置一个计数器,并设置一个阈值 C 。如果,PSO在搜索过程中,连续 C 次循环所找到的全局最优解都没有发生变化,就停止。
   3、设置一个阈值 T ,如果PSO所找到的全局最优的解满足 f(gbest) ≥ T ,那么停止算法。

4、实例: 用PSO算法搜索ackley函数的最小值

   ackley函数是一个具有非常多个局部极小值的函数,具体表达式如下:
在这里插入图片描述
通常取 a=20,b=0.2,c=2π 。其中 d 表示空间的维数,即 x∈Rd。该函数具有全局最小值 f(x) = 0, x=0 。函数图像如下(三维空间):

在这里插入图片描述
.

完整代码

import numpy as np


# v(k+1) = w*v(k) + c1*r1*(gbest-x) + c2*r2*(pbest-x)
# x(k+1) = x(k) + v(k+1)


class Particle:
    """
    st_x:位置约束,粒子每个维度上的坐标范围必须处于[st_x[0], st_x[1]]之间
    st_v:速度约束,粒子每个维度上的速度范围必须处于[st_v[0], st_v[1]]之间
    position:粒子的当前位置
    velocity:粒子的当前速度
    pbest:粒子自身历史记录的最佳位置
    pvalue:粒子自身历史记录的最佳值
    """
    st_x = None
    st_v = None

    def __init__(self, x, v, pbest, pvalue):
        self.position = x
        self.velocity = v
        self.pbest = pbest
        self.pvalue = pvalue

    def update_velocity(self, v):
        v[v < self.st_v[0]] = self.st_v[0]
        v[v > self.st_v[1]] = self.st_v[1]
        self.velocity = v

    def update_position(self, func):
        # 更新粒子自身的位置,以及判断是否要更新pbest
        self.position += self.velocity
        self.position[self.position < self.st_x[0]] = self.st_x[0]
        self.position[self.position > self.st_x[1]] = self.st_x[1]
        if self.pvalue > func(self.position):
            self.pvalue = func(self.position)
            self.pbest = self.position.copy()


class PSO:
    """
    gbest:粒子群历史记录的最佳位置
    gvalue:粒子群历史记录的最佳值
    """
    gbest = None
    gvalue = np.inf

    def __init__(self, n_dims, n_particles, st_x, st_v, w, c1, c2, num_iter, func):
        # 初始化空间维度
        self.n_dims = n_dims
        # 初始化粒子群数目
        self.n_particles = n_particles
        # 目标函数
        self.func = func
        # 粒子惯性权重
        self.w = w
        # 全局部分学习率
        self.c1 = c1
        # 自我认知部分学习率
        self.c2 = c2
        # 迭代次数
        self.num_iter = num_iter
        # 存放粒子群的列表(容器)
        self.particles = []
        # 初始化粒子的位置和速度约束
        Particle.st_x = st_x
        Particle.st_v = st_v
        # 初始化粒子群
        for _ in range(n_particles):
            # 初始化粒子的随机位置在 st_x[0]~st_x[1] 
            x = (st_x[1] - st_x[0]) * np.random.rand(n_dims) + st_x[0]
            # 计算当前评估值
            pvalue = func(x)
            # 初始化一个粒子
            self.particles.append(
                Particle(
                    x=x,
                    v=(st_v[1] - st_v[0]) * np.random.rand(n_dims) + st_v[0],
                    pbest=x.copy(),
                    pvalue=pvalue
                )
            )

            if self.gvalue > pvalue:
                self.gvalue = pvalue
                self.gbest = x.copy()

    def solve(self):
        # 开始迭代
        for index in range(1, self.num_iter + 1):
            for particle in self.particles:
                v = self.w * particle.velocity + self.c1 * np.random.rand() * (self.gbest - particle.position) + \
                    self.c2 * np.random.rand() * (particle.pbest - particle.position)
                particle.update_velocity(v)
                particle.update_position(self.func)
            for particle in self.particles:
                if particle.pvalue < self.gvalue:
                    self.gvalue = particle.pvalue
                    self.gbest = particle.pbest.copy()
        return self.gbest, self.gvalue


def ackley(x):
    return - 20 * np.exp(-0.2 * np.sqrt((x * x).mean())) - np.exp(np.cos(2 * np.pi * x).mean()) + 20 + np.exp(1)


if __name__ == "__main__":
    # 测试不同迭代次数搜索出来的最优解情况
    for i in range(11):
        pso = PSO(
            n_dims=10,
            n_particles=100,
            st_x=(-20, 20),
            st_v=(-1, 1),
            w=0.8,
            c1=2,
            c2=2,
            num_iter=50 * i,
            func=ackley
        )
        gbest, gvalue = pso.solve()
        print("number of interations:%d\tgvalue:%f" % (50 * i, gvalue))

粒子群算法PSO入门代码火经典案例求Ackley函数附-PSO.zip 本帖最后由 当当的花生 于 2016-7-30 20:09 编辑 回帖获得更多 粒子群算法 遗传算法前面有人讲了,我来讲讲PSO。 1)先看看百度百科解释: 粒子群算法,也称粒子群优化算法(Particle Swarm Optimization),缩写为 PSO, 是近年来由J. Kennedy和R. C. Eberhart等[1] 开发的一种新的进化算法。PSO 算法属于进化算法的一种,和模拟退火算法相似,它也是从随机解出发,通过迭代寻找最优解,它也是通过适应度来评价解的品质,但它比遗传算法规则更为简单,它没有遗传算法的“交叉” 和“变异” 操作,它通过追随当前搜索到的最优值来寻找全局最优。这种算法以其实现容易、精度高、收敛快等优点引起了学术界的重视,并且在解决实际问题中展示了其优越性。粒子群算法是一种并行算法。 2) 什么? 看不懂? 我来通俗解释: 粒子群算法是生物学家研究鸟类捕食创造的,把一只鸟比作成一个粒子,设想一个有20只秃鹫(粒子)的群体吧,秃鹫相互独立具有个体特征但又相互协助体现群体特征,现在我就是这20只中的一只好了(人丑),我现在和小伙伴去 觅食(找非洲野牛的尸体),假设我是一只老婆在家里孵蛋所以我得很认真找食物的秃鹫,每时每刻我都在记录我周围中最可能有猎物的地方,并以这个依据(设为依据一)在下一刻立即调整速度矢量(有大小方向)来趋向我上一时刻发现的最有可能有尸肉的地方。 假如我飞了一小时,上面说到我每时每刻都在记录最有当刻最有可能有肉的地方,那么在这一个小时的记录中肯定有一个最可能有肉的地方,这个地方就是依据二了,我有种往这个移动的趋势。 前面都是我的个鸟行为,我是一只善于观察和沟通并成功让酋长漂亮女儿当我老婆的鸟,所以群里其他秃鹫找到了一个小尸体就会立即告诉我,那我就看谁发现的小尸肉最有分量了,并有一个往这个地方移动的趋势,这是依据三。 再加一些假设以尽可能地模仿一个群体,1)每时每刻有随机从3只傻鸟中抽出一只鸟让他分心,在下一刻瞎移动位置,假设其他秃鹫和我一样机智并且有才华(不太可能),好了有了这些,经过2个小时的觅食,我们这十只鸟最终飞到了同一地点:一头最大野牛尸体旁边。这就是粒子群算法啦,显然是一个找大尸肉的优化算法。 3)来举个经典栗子,求Ackley函数的最小值。 什么很好求?可不是,这个函数的局部最小值太多了,一不小心就掉坑了,函数是这样的: ackley函数.png MATLAB画图如下: 图像.png 画图代码: %经典函数 Ackley clear,clc,close all; x1=-5:0.01:5; x2=-5:0.01:5; for i=1:1001     for j=1:1001         %目标函数         z=-20*exp^2 x2^2)/2))-exp)) cos))/2 20 2.71289;     end end [x,y]=meshgrid; figure mesh xlabel ylabel zlabel复制代码 这么多局部最小值,那么怎么用PSO求最小值呢? 少说废话,先上MATLAB代码: 1)定义函数: function y = fun y=-20*exp^2 x^2)/2))-exp)) cos))/2 20 2.71289;   复制代码 2)PSO求解: 要先定义函数哦 clear,clc,close all; %参数初始化 %粒子群算法中的俩个参数 c1 = 0.1; %惯量因子 c2 = 0.1; maxg=400; %进化次数 移动400回啊 sizepop=20; %总群规模 20只鸟啊 %初始速度和总群上下边界值 Vmax=1; Vmin=-1; %速度范围 上帝让我飞这么快啊 popmax=5; popmin=-5; %粒子范围 我不能飞到老王的领地啊 %%产生初始粒子和速度,上帝说要有鸟,就有了鸟 for i= 1:sizepop pop=popmax*rands ; %初始种群 V=rand; %初始速度 fitness=fun); %染色体的适应度 end %%找最好的染色体,最大的小肉块啊 [bestfitness,bestindex]=min; zbest=pop; %全局最佳 gbest=pop; %个体最佳 fitnessgbest=fitness; %个体最佳适应度 fitnesszbest=bestfitness; %全局最佳适应度 %%迭代寻优,我要找俩百回啊,老婆在家孵蛋啊 for i=1:maxg for j = 1:sizepop %速度更新,要找最好吃的肉啊 V = V c1*rand*-pop) c2*rand*); V>popmax))=popmax; V0.99 k=ceil; pop=rand; end %适应度值,函数最小的点(鸟) fitness=fun); %个体最优更新,我找到最好吃的肉要实时追踪啊 if fitness < fitnessgbest gebest = pop; fitnessgbest = fitness; end %群体最优更新,我是一只善于观察和沟通并成功让酋长漂亮女儿当我老婆的鸟 if fitness < fitnesszbest zbest = pop; fitnesszbest = fitness; end end yy = fitnesszbest; end %结果分析,20个鸟到了同一个地方,来啊互相伤害啊 plot% title]); grid on xlabel; ylabel; %结果输出 zbest %最佳个体,(点的位置) fitnesszbest %最优值(函数最小值)复制代码 说明:且把一个点(x,y)当成我这只鸟的位置,把这个点代到Ackley函数里得到一个值并记录下来。第一,我移动十次以后十次里有一个位置函数值最小(函数最小就是我们要的尸肉啊),那么我总有种往这个位置移动的趋势,第二,20个点带到函数我是不是得有个最小的,那我就又有种往这个点移动的趋势。 V = V c1*rand*-pop) c2*rand*); 而上面的速度更新公式巧妙的结合了上面俩点啊,精彩绝伦啊 c1,c2是个巧妙的常数,选大了搜索范围广,选小了局部搜索强啊 砖家现在在研究动态调整这俩个惯性因子啊 3)运行结果: 适应度.png 这里的适应度其实就是 把20个点带进函数的那个最小值的变化呀 最小值最后是接近真实最小值0啊,好吃的肉啊 结果: 360反馈意见截图16751106316927.png 每次运行结果都不是相同的哦,pso最终得到函数在(0.1070,0.0199)得到最小值0.0694.成功避开所有菊部最优值十分接近真实的在(0,0),最小值0 的结果。 啊我是一只神奇的秃鹫。第一次认真的回答啊,来啊点赞啊,来啊智能算法有什么: 算法.png ----Mr.Dang 转载注明出处,侵删 回复 支持 获得更多 M文件如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值