Differential Evolution: A Survey of the State-of-the-Art

@

Das S, Suganthan P N. Differential Evolution: A Survey of the State-of-the-Art[J]. IEEE Transactions on Evolutionary Computation, 2011, 15(1): 4-31.

@article{das2011differential,
title={Differential Evolution: A Survey of the State-of-the-Art},
author={Das, Swagatam and Suganthan, P N},
journal={IEEE Transactions on Evolutionary Computation},
volume={15},
number={1},
pages={4--31},
year={2011}}

这是一篇关于Differential Evolution (DE) 的综述, 由于对这类方法并不熟悉, 只能简单地做个记录.

主要内容

考虑如下问题,

minf(X),

其中X=(x1,,xD).

我所知的, 如梯度下降方法, 贝叶斯优化可以用来处理这类问题, 但是还有诸如 evolutionary algorithm (EA), evolutionary programming (EP), evolution strategies(ESs), genetic algorithm (GA), 以及本文介绍的 DE (后面的基本都不了解).

DE/rand/1/bin

先给出最初的形式, 称之为DE/rand/1/bin:

Input: scale factor F, crossover rate Cr, population size NP.
1:G=0, 并随机初始化PG={X1,G,,XNP,G}.
2: While the stopping criterion is not satisfied Do:

  • For i=1,,NP do:
  1. Mutation step:

Vi,G=Xr1i,G+F(Xr2i,GXr3i,G).

  1. Crossover step: 按照如下方式生成Ui,G=(u1,i,G,,uD,i,G)

uj,i,G={vj,i,Gifrand[0,1]Crorj=jrandxj,i,Gotherwise.

  1. Selection step:

Xi,G={Ui,Giff(Ui,G)f(Xi,G)Xi,Gotherwise.

  • End For.
  • G=G+1.
    End While.

其中Xi,G=(xj,i,G,,xD,i,G), jrand是预先随机生成的一个属于[1,D]的整数, 以保证U相对于X至少有些许变化产生, Xr1i,G,Xr2i,G,Xr3i,G是从PG中随机抽取且互异的.

在接下来我们可以发现很多变种, 而这些变种往往是Mutation step 和 Crossover step的变体.

DE/?/?/?

DE/rand/1/exp

这是crossover step步的的一个变种:

随机从[1,D]中抽取整数nL, 然后

uj,i,G={vj,i,Gifnjn+L1xj,i,Gotherwise.

L可以通过下面的步骤生成

  • L=0
  • while rand[0,1]Cr and LD:

L=L+1.

DE/best/1

Vi,G=Xbest,G+F(Xr1i,GXr2i,G),

其中Xbest,GPG中的最优的点.

DE/best/2

Vi,G=Xbest,G+F(Xr1i,GXr2i,G)+F(Xr3i,GXr4i,G).

DE/rand/2

Vi,G=Xr1i,G+F(Xr2i,GXr3i,G)+F(Xr4i,GXr5i,G),

超参数的选择

真的没有细看, 文中粗略地介绍了几处, 还有很多需要查原文.

F的选择

有的推荐[0.4,1](最佳0.5), 有的推荐0.6, 有的推荐[0.4,0.95](最佳0.9).

还有一些自适应的选择, 如

F={max{lmin,1|fmaxfmin|}if:|fmaxfmin|<1max{lmin,1|fmaxfmin|}otherwise,

我比较疑惑的是难道|fmaxfmin|不是大于等于1吗?

Fi,G+1={rand[Fl,Fu]withprobabilityτFi,Gelse,

其中Fl, Fu分别为F取值的下界和上界.

NP的选择

有的推荐[5D,10D], 有的推荐[3D,8D].

Cr的选择

有的推荐[0.3,0.9].

还有

Cri,G+1={rand[0,1]withprobabilityτCri,Gelse,

一些连续变体

A

p=f(Xr1)+f(Xr2)+f(Xr3)p1=f(Xr1)/pp2=f(Xr2)/pp3=f(Xr1)/p.

如果rand[0,1]<Γ(Γ是给定的):

Vi,G+1=(Xr1+Xr2+Xr3)/3+(p2p1)(Xr1Xr2)+(p3p2)(Xr2Xr3)+(p1p3)(Xr3Xr1),

否则

Vi,G+1=Xr1+F(Xr2Xr3).

B

Ui,G=Xi,G+ki(Xr1,GXi,G)+F(Xr2,GXr3,G),

其中ki给定, F=kiF.

C

在这里插入图片描述

D

即在考虑x的时候, 还需要考虑其反a+bx, 假定x[a,b], [a,b]为我们给定范围, X的反类似的构造.

E

在这里插入图片描述
其中Xnbest,G表示在Xi,Gn的近邻中的最优点, p,q[ik,i+k].
在这里插入图片描述
其中Xgbest,GPG中的最优点.

Vi,G=wgi,G+(1w)Li,G.

G

在这里插入图片描述

剩下的在复杂环境下的应用就不记录了(只是单纯讲了该怎么做).

一些缺点

  1. 高维问题不易处理;
  2. 容易被一些问题欺骗, 而现如局部最优解;
  3. 对不能分解的函数效果不是很好;
  4. 路径往往不会太大(即探索不充分);
  5. 缺少收敛性的理论的保证.

代码

f(x,y)=x2+50y2.
在这里插入图片描述

{
  "dim": 2,
  "F": 0.5,
  "NP": 5,
  "Cr": 0.35
}


"""
de.py
"""

import numpy as np
from scipy import stats
import random




class Parameter:

    def __init__(self, dim, xmin, xmax):
        self.dim = dim
        self.xmin = xmin
        self.xmax = xmax
        self.initial()


    def initial(self):
        self.para = stats.uniform.rvs(
            self.xmin, self.xmax - self.xmin
        )

    @property
    def data(self):
        return self.para

    def __getitem__(self, item):
        return self.para[item]

    def __setitem__(self, key, value):
        self.para[key] = value

    def __len__(self):
        return len(self.para)

    def __add__(self, other):
        return self.para + other

    def __mul__(self, other):
        return self.para * other

    def __pow__(self, power):
        return self.para ** power

    def __neg__(self):
        return -self.para

    def __sub__(self, other):
        return self.para - other

    def __truediv__(self, other):
        return self.para / other


class DE:

    def __init__(self, func, dim ,F=0.5, NP=50,
                 Cr=0.35, xmin=-10, xmax=10,
                 require_history=True):
        self.func = func
        self.dim = dim
        self.F = F
        self.NP = NP
        self.Cr = Cr
        self.xmin = np.array(xmin)
        self.xmax = np.array(xmax)
        assert all(self.xmin <= self.xmax), "Invalid xmin or xmax"
        self.require_history = require_history
        self.init_x()
        if self.require_history:
            self.build_history()


    def init_x(self):
        self.paras = [Parameter(self.dim, self.xmin, self.xmax)
                      for i in range(self.NP)]

    @property
    def data(self):
        return [para.data for para in self.paras]

    def build_history(self):
        self.paras_history = [self.data]

    def add_history(self):
        self.paras_history.append(self.data)

    def choose(self, size=3):
        return random.sample(self.paras, k=size)

    def mutation(self):
        x1, x2, x3 = self.choose(3)
        return x1 + self.F * (x2 - x3)

    def crossover(self, v, x):
        u = np.zeros_like(v)
        for i, _ in enumerate(v):
            jrand = random.randint(0, self.dim)
            if np.random.rand() < self.Cr or i is jrand:
                u[i] = v[i]
            else:
                u[i] = x[i]
            u[i] = v[i] if np.random.rand() < self.Cr else x[i]
        return u

    def selection(self, u, x):
        if self.func(u) < self.func(x):
            x.para = u
        else:
            pass

    def step(self):
        donors = [self.mutation()
                  for i in range(self.NP)]

        for i, donor in enumerate(donors):
            x = self.paras[i]
            u = self.crossover(donor, x)
            self.selection(u, x)
        if self.require_history:
            self.add_history()

    def multi_steps(self, times):
        for i in range(times):
            self.step()





class DEbest1(DE):

    def bestone(self):
        y = np.array([self.func(para)
             for para in self.paras])
        return self.paras[np.argmax(y)]

    def mutation(self, bestone):
        x1, x2 = self.choose(2)
        return bestone + self.F * (x1 - x2)

    def step(self):
        bestone = self.bestone()
        donors = [self.mutation(bestone)
                  for i in range(self.NP)]

        for i, donor in enumerate(donors):
            x = self.paras[i]
            u = self.crossover(donor, x)
            self.selection(u, x)
        if self.require_history:
            self.add_history()

class DEbest2(DEbest1):

    def mutation(self, bestone):
        x1, x2, x3, x4 = self.choose(4)
        return bestone + self.F * (x1 - x2) \
                + self.F * (x3 - x4)

class DErand2(DE):

    def mutation(self):
        x1, x2, x3, x4, x5 = self.choose(5)
        return x1 + self.F * (x2 - x3) \
                + self.F * (x4 - x5)


class DErandTM(DE):

    def mutation(self):
        x = self.choose(3)
        y = np.array(list(map(self.func, x)))
        p = y / y.sum()
        part1 = (x[0] + x[1] + x[2]) / 3
        part2 = (p[1] - p[0]) * (x[0] - x[1])
        part3 = (p[2] - p[1]) * (x[2] - x[1])
        part4 = (p[0] - p[2]) * (x[2] - x[0])
        return part1 + part2 + part3 + part4

posted @   馒头and花卷  阅读(544)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示