乌鸦搜索算法(Python)

乌鸦搜索算法

摘要

这篇论文提出了一个新颖的元启发式优化器,基于乌鸦的智能行为命名为乌鸦搜索算法(CSA)。CSA是一种基于群体的技术,它的工作原理是乌鸦把多余的食物储存在隐蔽的地方,需要食物时再取出来。CSA被应用于对目标函数、约束条件和决策变量性质不同的六种不同的受约束工程设计问题进行优化。将CSA所获得的结果与各种算法的结果进行比较。仿真结果显示使用CSA或许会比其他算法更可能找到有希望的结果。

1. 介绍

工程设计的定义是构建满足特定需求的产品的决策过程。常见的工程设计问题具有复杂的目标函数和大量的决策变量。可行解是所有设计的集合,其特征是在所有可能的设计参数(决策变量)。一种优化技术是尝试从所有可行解中找到最佳解。

传统搜索方法一直以来被应用到去解决工程设计问题。尽管这些方法在许多实际问题中找到了希望的结果,但是在许多复杂的设计问题中可能会失败。在实际设计问题中,决策变量的数量可能非常的大并且它们在目标函数中的影响可能非常复杂。目标函数或许会有许多局部最优解,而设计师更感兴趣的是全局最优解。这些问题不能被只能找到局部最优解的传统方法来处理。在这些情况下,有效的优化方法是被需要的。
元启发式算法对于解决许多现实世界的非常非线性和多峰优化问题可以显示很好的性能。所有元启发式算法都使用随机化和局部搜索的一定权衡。这些算法可以为困难的优化问题找到最佳解决方案,但是并不能保证是最优解。希望这些算法大部分时间都能工作,但不是一直工作。元启发式算法可以适用于全局优化。基于Glover's公约,所有现代自然启发方法被称为元启发式。

目前的趋向是利用自然启发元启发式算法去解决困难的问题,它已经显示出元启发式是令人惊讶的有效。元启发式的文献在过去20年中得到了巨大的扩展。 一些著名的元启发式算法如下:基于自然选择的遗传算法(GA) ,基于鸟群和鱼类教育的社会行为的粒子群优化(PSO),基于音乐即兴创作过程的和谐搜索(HS), 基于布谷鸟寄生的布谷鸟搜索算法,基于微型蝙蝠回声定位行为的蝙蝠算法(BA),基于动物搜索行为的群搜索优化器(GSO),基于热带萤火虫闪烁光模式的萤火虫算法(FA)等。到目前为止,研究人员只使用了受自然启发的非常有限的特性,并且有更多算法的发展空间。 本文的主要动机之一是开发一种方便用户的(简单的概念和易于实现)元启发式技术,通过它我们可以在解决优化问题时获得有希望的结果。
乌鸦是广泛分布的鸟类属,现在被认为是世界上最聪明的动物之一。作为一个群体,乌鸦表现出非凡的智力例子,在智力测试中往往得分很高。它们可以记住面容,使用工具,使用复杂的方法去交流和在不同的季节隐藏与取回食物。

在乌鸦群中,有一种行为和优化过程有许多相似之处。根据这个行为,乌鸦隐藏它们过量的食物在环境的某些位置(隐藏地),并且在需要时取回储存的食物。乌鸦是贪婪的鸟,因为它们跟随彼此为了获得更好的食物来源。找到被乌鸦隐藏的食物来源不是件容易的事,因为乌鸦发现有另一个跟随他,乌鸦会尝试通过另一个环境的位置去愚弄乌鸦。从优化的角度来看,乌鸦是搜索者,环境是搜索空间,环境的每个位置是一个可行的解决方案,食物来源的质量是目的(适应度)函数,环境的最佳食物来源是问题的全局解决方案。基于这些相似点,CSA试图模拟乌鸦的智能行为,去找到优化问题的解决方案。

2. 乌鸦搜索算法

乌鸦(乌鸦科或科)被认为是最聪明的鸟类。它们所含的大脑相对于他们的体型最大。根据脑体比,他们的大脑比人脑略低。乌鸦聪明的证据很多。他们在镜像测试中展示了自我意识,并具有工具制作能力。当一个不友好的人走近时,乌鸦可以记住面孔并互相警告。而且,它们可以使用工具,以复杂的方式交流,并在几个月后回忆起他们食物的隐藏地。
已知乌鸦观察其他鸟,观察其他鸟把食物藏在哪里,一旦主人离开,就把它偷走。如果乌鸦犯了偷窃罪,它将采取额外的预防措施,如移动隐藏地,以避免成为未来的受害者。事实上,他们利用自己的小偷经验来预测小偷的行为,并能确定最安全的路线,以保护他们的缓存不被窃取。

在这篇论文中,基于上述智能行为,开发了一种基于种群的元启发式算法CSA。 CSA的原则如下:

  • 乌鸦以群居的形式生活。
  • 乌鸦会记住它们隐藏地的位置。
  • 乌鸦们互相跟随为了偷窃。
  • 乌鸦保护他们的缓存不被偷的概率。

假设有一个d维环境,包括一些乌鸦。乌鸦的数量(群大小)是 N ,乌鸦i在时间(迭代) item 在搜索空间中由向量 $x^{i,iter}(i=1,2,...,N;iter=1,2,...,iter_{max})$ 指定,其中 $x{i,iter}=[x_1,x_2{i,iter},...,x_d]$ ,$iter_{max}$是最大迭代次数。每只乌鸦都会记住它们的隐藏地的位置。在每次迭代$iter$中,乌鸦i的隐藏地为$m^{i,iter}$.这是乌鸦i目前为止获得的最好的位置。事实上,在每只乌鸦的记忆中,它的位置都被最好的经历记住了。乌鸦在环境中移动,寻找更好的食物来源(隐藏的地方)。

假设在迭代$iter$中,乌鸦j想去他的隐藏地$m^{j,iter}$。在这个迭代中,乌鸦i决定跟随乌鸦j接近乌鸦j的隐藏地。在这种情况下,可能会发生两种情况:

  • 情况1:乌鸦j不知道乌鸦i在跟踪它。因此乌鸦i将接近乌鸦j的隐藏地。 在这种情况下,得到乌鸦i的新位置如下:
    $x^{i,iter+1} = x^{i,iter} + r_i \times fl^{i,iter} \times (m^{j,iter} - x^{i,iter}) \tag{1}$

    其中$r_i$是一个在0到1之间均匀分布的随机数,$fl^{i,iter}$表示乌鸦i在迭代迭代时的飞行长度。

图1给出了这种状态的原理图和$fl$对搜索能力的影响。小的$fl$数值导致局部搜索(接近$x{i,iter}$),大的$fl$数值导致全局搜索(远离$x$)。在图1(a)显示,如果$fl$的值小于1, 乌鸦i的下一个位置在$x{i,iter}$和$m$之间的虚线上。图1(b)显示,如果$fl$的值大于1,乌鸦i的下一个位置在可能超过$m^{i,iter}$的虚线上

  • 情况2:乌鸦j知道乌鸦i在跟踪它。 因此,为了保护其缓存不被窃取,乌鸦j将通过前往搜索空间的另一个位置来欺骗乌鸦i。

状态1和状态2可以表示如下:

$$f(n) = \begin{cases}
x^{i,iter+1} = x^{i,iter} + r_i \times fl^{i,iter} \times (m^{j,iter} - x^{i,iter}) & r_j \geq AP^{j,iter} \
\text{a random position} & \text{otherwise}
\end{cases}
\tag{2}$$

其中$r_j$是一个在0到1之间均匀分布的随机数吗,$AP^{j,iter}$表示乌鸦j在迭代迭代时的感知概率。

元启发式算法应在多样化和集约化之间提供良好的平衡。在乌鸦搜索算法中,集约化和多样化主要受感知概率($AP$)参数的控制。通过降低感知概率值,CSA倾向于在该区域找到当前良好解决方案的局部区域进行搜索。因此,使用较小的($AP$)值,会增加集约化。另一方面,随着感知概率值的增加,搜索当前良好解附近的概率降低,CSA倾向于在全局尺度上探索搜索空间(随机化)。 因此,使用较大的($AP$)值,会增加多样化

图1. CSA情况1流程图,乌鸦i可以去到虚线上的任意一个位置

3. 对CSA实现进行优化

CSA的伪码如图(2)所示。本节给出了实现CSA的逐步程序。

  • 步骤1:初始化问题和可调参数

    定义优化问题,决策变量和约束条件。设置CSA(群落大小$N$)、最大迭代次数($iter_{max}$)、飞行长度($fl$)和感知概率($AP$)的可调参数。

  • 步骤2:初始化乌鸦的位置和记忆

    N只乌鸦被随机定位在d维搜索空间中作为群成员。每个乌鸦表示问题的可行解,d表示决策变量的个数。

    $$ Crows =
    \begin{bmatrix}
    x_1^1 & x_2^1 & \cdots & x_d^1 \
    x_1^2 & x_2^2 & \cdots & x_d^2 \
    \vdots & \vdots & \vdots & \vdots \
    x_1^N & x_2^N & \cdots & x_d^N \
    \end{bmatrix} \tag{3}$$

    初始化每个乌鸦的内存。 由于在最初的迭代中,乌鸦没有经验,所以假设它们把食物隐藏在它们的初始位置。
    $$ Memory =
    \begin{bmatrix}
    m_1^1 & m_2^1 & \cdots & m_d^1 \
    m_1^2 & m_2^2 & \cdots & m_d^2 \
    \vdots & \vdots & \vdots & \vdots \
    m_1^N & m_2^N & \cdots & m_d^N \
    \end{bmatrix} \tag{4}$$

  • 步骤3:评估适应度(目标)功能

    对于每个乌鸦,通过将决策变量值插入目标函数来计算其位置的质量。

  • 步骤4:生成新位置

    乌鸦在搜索空间中生成新的位置如下:假设乌鸦i想生成一个新的位置。 为此目的,这只乌鸦随机选择一只乌鸦(例如乌鸦j),并跟随它来发现这只乌鸦隐藏地($m^j$)。 用方程(2)得到了乌鸦i的新位置。 对于所有的乌鸦来说,这个过程是重复的。

  • 步骤5:检查新位置的可行性

    检查各乌鸦新位置的可行性。 如果乌鸦的新位置是可行的,乌鸦就会更新它的位置。 否则,乌鸦停留在当前位置,不会移动到生成的新位置。

  • 步骤6:评估新位置的适应度功能

    计算每个乌鸦新位置的适应度值$f(\cdot)$。

  • 步骤7:更新记忆

    乌鸦更新记忆如下:
    $$ m^{i,iter+1} = \begin{cases}
    x^{i,iter+1} & f(x^{i,iter+1})\text{ is better than }f(m^{i,iter})\
    m^{i,iter} & Otherwise
    \end{cases} \tag{5}$$
    其中$f(\cdot)$表示目标函数值。

    可见,如果乌鸦的新位置的适应度函数值优于记忆位置的适应度函数值,乌鸦就会通过新位置更新它的记忆。

  • 步骤8:检查终止标准

    步骤4-7被重复,直到到达$iter_{max}$。 当满足终止准则时,存储器在目标函数值方面的最佳位置作为优化问题的解决方案。

乌鸦搜索算法伪码

图(2):乌鸦搜索算法伪码

乌鸦搜索算法流程图

图(3):乌鸦搜索算法流程图

4. CSA与GA、PSO和HS的比较

与其他著名的算法(如GA、PSO和HS)一样,CSA利用一群寻求者来探索搜索空间。通过使用种群,找到一个好的解决方案并从局部最优逃逸的概率增加。优化算法除了种群大小和最大迭代次数(代)外,还有一些其他参数需要调整。参数设置是优化算法的缺点之一,因为它是一项耗时的工作。调整参数较少的算法更容易实现。在CSA中,可以调整的有飞行长度和感知概率(2个参数)。在PSO算法中,可调参数为惯性权重,速度最大值,个体学习因子和社会学习因子(4个参数)。HS可调参数为和谐记忆的价值考虑率,俯仰调节率和产生带宽(3个参数)。在GA中,应确定选择方法,交叉方法,交叉概率,变异方法,变异概率和替换方法(6个参数)。

与GA和PSO一样,CSA不是一个贪婪的算法,因为如果乌鸦产生一个不比其当前位置更好的新位置,它将移动到新位置。 非贪婪算法可以增加生成的解的多样性。 在HS中,如果它的适应度值优于记忆最差和谐的适应度,则接受一种新的解决方案。
像HS和PSO一样,CSA包括记忆,在记忆中记住好的解决方案。 在粒子群算法中,每个粒子都被吸引到自己找到的最佳位置和该组找到的最佳位置。 因此,在每次迭代时,都直接使用到目前为止找到的最佳解决方案。 在CSA的每一次迭代中,每只乌鸦随机选择一只乌鸦(它可能是它自己),并向其隐藏的地方移动(乌鸦找到的最佳解决方案)。 这意味着在CSA的每一次迭代中,到目前为止发现的最佳位置被直接用于寻找更好的位置。

5. 数值例子

事实证明,在一定的假设下,没有一种单一的搜索算法是所有问题的平均最佳搜索算法。换句话说,一个算法可能比其他算法更好地解决一些问题和一些问题。 为了在没有偏差结论的情况下评估所提出的CSA的优化功率,考虑并解决了六个工程设计问题,包括三杆桁架、压力容器、拉伸/压缩弹簧、焊接梁、齿轮传动和蝶形弹簧。所有考虑的问题都具有目标函数、约束和决策变量的不同性质。 CSA已经在MATLAB环境中使用奔腾4CPU2.1G2GB RAM在PC上执行。图(3)显示CSA实现的流程图。表(1)显示了CSA用于解决这些问题的参数设置。 值得提及的是,没有尝试优化CSA的参数设置。

本文对每个问题直接处理约束。 这意味着不能完全满足约束条件的每个解决方案都将被认为是不可行的和废弃的。 然而,拒绝不可行的解决方案可能对包括许多设计变量的问题和(或)其设计空间严重受约束的问题有严重的缺点,因为在这些问题中生成可行的设计可能需要大量的连续试验。 约束优化问题的约束处理方法之一是使用惩罚函数。 利用罚函数,将约束优化问题转化为无约束优化问题。 由于CSA的结果与文献报道的结果进行了比较,并且大多数方法都使用了直接控制约束,因此这里没有使用惩罚方法。

5.1 工程优化问题

5.1.1 三杆桁架设计问题

5.1.2 压力容器设计问题

5.1.3 张力/压缩弹簧设计问题

5.1.4 焊接梁设计问题

5.1.5 齿轮传动设计问题

5.1.6 蝶形弹簧设计问题

5.2 基准函数

虽然工程问题的结果证明了CSA与文献中现有的方法具有竞争力,但在较大的问题中,CSA的性能仍然存在一个问题。为了评估CSA在大规模优化问题上的性能,在10个维度中求解了表(16)所示的五个著名的基准函数。在CSA中,与以前一样,AP和fl值分别设置为0.1和2。 在PSO中,速度被控制,学习因素(个体和社会)被设置为2。

此外,在迭代过程中,惯性权重从0.9线性下降到0.4。 在GA中,采用凸交叉(系数为0.25和0.75)、均匀变异和锦标赛选择。 交叉概率和突变概率分别设置为0.9和0.005。 在CSA、PSO和GA中,种群大小设置为20,最大迭代次数选择2000次。 因此,在调查中,健康评估的数量为40,000。

表(17)显示了CSA获得的结果与PSO和GA在30次独立运行中发现的结果相比。 在所有函数上,CSA在最佳指数方面都优于其他算法。 在此表中,显示了运行的平均时间。 结果表明,在相同的适应度评价中,CSA比PSO和GA消耗的计算时间更少。

作为另一项研究,研究了不同参数设置对CSA性能的影响。 表(18)和表(19)显示了不同AP和fl值对Sphere function ($f_1$)Rosenbrock function ($f_2$)Griewank function ($f_3$)的结果的影响。从表18可以看出,AP=0导致CSA的性能弱,因为算法的多样化能力已经被消除。考虑到最佳指标,从所研究的参数设置来看,$f_1$、$f_2$和$f_3$的最佳指标分别是($AP$=0.05和$fl$=1.5),($AP$=0.05和$fl$=2.5)和($AP$=0.2和$fl$=2)。考虑平均指数,从所研究的参数设置来看,$f_1$、$f_2$和$f_3$的最佳参数设置分别是($AP$=0.05和$fl$=2)、($AP$=0.05和$fl$=2.5)和($AP$=0.3和$fl$=2)。在测试函数中,f1和f2是单峰的,而f3是多峰的。对于单峰函数,$AP$的小值导致更好的结果,而对于多模态函数,最好使用较大的$AP$值来逃避局部最优。如果使用$AP$的固定值($AP$=0.05),并且$fl$的值从1.5增加到2.5,则CSA在$f_1$、$f_2$和$f_3$上的性能平均有所提高。如果$AP$的值设置为0.2,$fl$的值从1.5增加到2.5,平均而言,CSA在$f_1$上的性能没有改善,而在$f_3$上,CSA的性能有所改善。因此,与其他优化技术一样,CSA的细化是一个需要通过试验来解决的问题

6. 结论

基于乌鸦的智能行为,提出了一种新的元启发式算法CSA。CSA是一种基于种群的优化算法,它非常简单,仅有两个可调参数(飞行长度和感知概率),这反过来又使其在不同工程领域的应用非常有吸引力。在CSA中,感知概率参数直接用于控制算法的多样性。 与GA、PSO和HS相比,CSA的参数调整较少,因此更容易实现。通过求解具有不同性质的目标函数、约束和决策变量的不同工程设计问题来评价CSA的有用性。仿真结果表明,与其他算法相比,该算法具有较好的性能,具有较好的竞争效果。在一组基准函数上,虽然PSO是基于种群的算法中的一种快速技术,但它的性能优于CSA。结果表明,CSA的收敛速度较好,该算法在1s左右找到了所研究问题的解。

7. 代码示例

7.1 问题说明

计算(-100 : 100)范围内10个维度(变量)的平方和最小

7.2 仿真显示

  • 从i到n随机生成跟踪乌鸦序号

    从i到n跟踪仿真图

  • 从0到n随机生成跟踪乌鸦序号

从0到n跟踪仿真图

7.3 代码展示(Python)

import random
import numpy
import math
from matplotlib import pyplot as plt

# 初始化变量值(乌鸦搜索算法)
n = 20  # 乌鸦数量
iter_max = 500  # 迭代次数
fl = 2  # 飞行长度
ap = 0.1  # 感知概率
# l-u范围内d维求平方最小值
d = 10
l = -100
u = 100


# init(n, d, l, u)
# 初始化d维范围矩阵中乌鸦的位置,返回矩阵x
def init(n, d, l, u):
    x = []
    for i in range(n):  # 生成n个乌鸦
        x.append([])
        for j in range(d):
            x[i].append(l - ((l - u) * random.random()))
    return x


# fitness(x,d)
# 评估该位置适合度,并返回列表fit
# 该程序适合度为将d个变量分别平方相加即为该问题适合度,值越小适合度越高
def fitness(x, d):
    fit = []
    for i in range(len(x)):  # 遍历每只乌鸦
        fit.append(0)  # 初始化适合度为0
        for j in range(d):
            fit[i] = fit[i] + pow(x[(i, j)], 2)
    return fit


# random_follow_num(n)
# 生成n个随机编号,编号范围为0 : (n-1),返回列表rfn
def random_follow_num(n):
    rfn = []
    for i in range(n):
        rfn.append(int(math.ceil(n * random.random()) - 1))  # math.ceil() 向上取整
    return rfn


x = numpy.matrix(init(n, d, l, u))
mem_x = x.copy()  # 储存记忆位置
fit = numpy.array(fitness(x, d))
mem_fit = fit.copy()  # 储存记忆位置适合度
new_fit = numpy.array([0])  # 初始化新适合度
ffit_iter = numpy.array([])  # 每次迭代中的最小适合度

# print(x)
# print(fit)
# print(new_fit)

# 文献中说为从i到n随机选择乌鸦,该次方法为随机生成未有判断

# 开始迭代
for iter in range(iter_max):
    # rfn = numpy.array(random_follow_num(n))  # 生成随机跟踪乌鸦下标
    new_x = numpy.empty((n, d))  # 随机生成各乌鸦新位置
    for i in range(n):  # 遍历每个乌鸦
        rfn_num = int(math.ceil(n - (n - i) * random.random()) - 1)
        if random.random() > ap:  # 乌鸦跟踪未被发现
            for j in range(d):  # 公式1,num[i]为跟踪的乌鸦编号
                new_x[(i, j)] = x[(i, j)] + (random.random() * fl * (mem_x[(rfn_num, j)] - x[(i, j)]))
                # new_x[(i, j)] = x[(i, j)] + (random.random() * fl * (mem_x[(rfn[i], j)] - x[(i, j)]))
        else:
            for j in range(d):  # 被发现,生成随机位置
                new_x[(i, j)] = l - ((l - u) * random.random())
    fit = numpy.array(fitness(new_x, d))

    #     print(new_x)
    #     print(ft)
    #     print()

    # 更新位置信息以及记忆
    for i in range(n):
        ctd = 0
        if l < new_x.all() < u:  # 判断生成位置是否在范围内
            ctd = ctd + 1
            x[i] = new_x[i].copy()  # 更新乌鸦的位置
            if fit[i] < mem_fit[i]:  # 若有更小的适合度
                mem_x[i] = new_x[i].copy()  # 更新记忆位置
                mem_fit[i] = fit[i]  # 更新记忆适合度
    print(mem_x)
    print(mem_fit)
    print()
    ffit_iter = numpy.append(ffit_iter, numpy.amin(mem_fit))  # 从给定数组中的元素沿指定轴返回最小值
d_ffit = numpy.amin(mem_fit)  # 从给定数组中的元素沿指定轴返回最小值

print("ffit_iter: ")
print(ffit_iter[-100:]) # 每次迭代下的最小适合度
print()

print("d_ffit: " + str(d_ffit)) # 迭代完毕后的最小适合度
print()

# 绘图
x = numpy.arange(0, iter_max)
y = ffit_iter[x]
plt.title("Crow Search Algorithm \n" + "d: {0} n: {1} fl: {2} ap: {3} l: {4} u: {5}"
          .format(d, n, fl, ap, l, u))
plt.ylabel("y axis fitness ")
plt.xlabel("x axis iteration")
plt.plot(x, y)
plt.show()

posted @ 2021-06-18 13:24  MO_OF  阅读(2246)  评论(0编辑  收藏  举报