差分进化算法

原理

  最近在学习演化算法(Evolutionary algorithm),粒子群算法和遗传算法已经很熟悉了,而差分进化算法我还没认真研究过,趁着暑期实训的机会打算把差分进化算法做个总结,最后再将这三种算法做个比较。
  差分进化算法是演化算法的一种,它的思想和遗传算法比较像,算法分为以下几个流程:

  • 初始化

      演化算法的初始化一般都是随机初始化,个体一般表示为一个多维向量 [ x 1 , x 2 , . . . , x n ] , x i ∈ [ l i , h i ] [x_1,x_2,...,x_n], x_i\in [l_i,h_i] [x1,x2,...,xn],xi[li,hi] l i l_i li h i h_i hi为第i维变量的范围。一般而言,对第i维而言,可以先产生一个0-1的随机数 r r r,然后 x i = l i + r ∗ ( h i − l i ) x_i=l_i+r*(h_i-l_i) xi=li+r(hili)
  • 评估

      演化算法的个体的好坏是通过适应值函数来决定的,对于最小化问题而言,个体的适应值越小,则越有优势;最大化问题可以转换为最小化问题,毕竟 max ⁡ f ( x ) = − min ⁡ ( − f ( x ) ) \max f(x)=-\min (-f(x)) maxf(x)=min(f(x))
  • 成熟&变异

      差分进化算法的成熟和变异与遗传算法有些不同,对种群中的每一个个体,选出除该个体之外的另外三个个体a,b,c,新个体的产生方式如下:
    m u t a n t = a + m u t ∗ ( b − c ) mutant=a+mut*(b-c) mutant=a+mut(bc) mut为参数,一般取值为0.5-2。
      新产生的个体还需要进行变异操作,对新个体的多维向量的每一维,以一定的概率进行变异得到新的值,变异的新数值一般是取[0,1]内的随机数,然后按照初始化中的操作将其变为范围位于 [ l i , h i ] [l_i,h_i] [li,hi]的值。变异之后,需要将该变异值与原个体值进行比较,取其中适应值更好的一个作为新个体值。再将该新个体值与种群中最优的个体进行比较,更新最优的个体值。
  • 结束

      进化算法的结束一般有两种,其一是设定循环的最大次数,达到最大次数后中止算法;其二是设定阈值,假定相邻的两次循环中最优个体的适应值差在阈值以内,则认为算法收敛并中止算法。最后的最优个体值即是本次算法求得的最优解。

实现

  我利用python实现该算法并进行测试。代码如下:

import numpy as np
import matplotlib.pyplot as plt

def de(fobj, bounds, mut=0.8, crossp=0.7, popsize=20, its=1000):
    dimensions = len(bounds)
    pop = np.random.rand(popsize, dimensions)
    min_b, max_b = np.asarray(bounds).T
    diff = np.fabs(min_b - max_b)
    pop_denorm = min_b + pop * diff
    fitness = np.asarray([fobj(ind) for ind in pop_denorm])
    best_idx = np.argmin(fitness)
    best = pop_denorm[best_idx]
    for i in range(its):
        for j in range(popsize):
            idxs = [idx for idx in range(popsize) if idx != j]
            a, b, c = pop[np.random.choice(idxs, 3, replace = False)]
            mutant = np.clip(a + mut * (b - c), 0, 1)
            cross_points = np.random.rand(dimensions) < crossp
            if not np.any(cross_points):
                cross_points[np.random.randint(0, dimensions)] = True
            trial = np.where(cross_points, mutant, pop[j])
            trial_denorm = min_b + trial * diff
            f = fobj(trial_denorm)
            if f < fitness[j]:
                fitness[j] = f
                pop[j] = trial
                if f < fitness[best_idx]:
                    best_idx = j
                    best = trial_denorm
        yield best, fitness[best_idx]

def fitness(x):
    return np.sum(x**2)/len(x)

bound=[(-100,100)]*20
results=de(fitness,bound)
x,f=zip(*results)
plt.plot(f)
plt.show()

上述代码参考自这位大佬,他的代码写的很简洁,我没有改动就直接拿上来了。
最后的效果如下:
效果图

效果

  一般而言,当问题的维度比较小时,大概几十维的时候,演化算法的效果还是很可以的;当问题的维度变得很大,一般是几百维甚至上千维德时候,演化算法的效果就变得比较差了,需要较多的迭代次数才能得到一个较好的解,这也是"维数灾难"的一种体现。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值