进化策略

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014248127/article/details/79143437

进化策略和遗传算法统称为进化算法,二者的思想很类似,但步骤和应用方向有所差别。
对遗传算法感兴趣的可以参考博客:遗传算法讲解

这篇文章主要讲解进化策略,从以下三个方面入手:

  • 进化策略的思想
  • 进化策略与遗传算法的差别
  • 进化策略的两个实例
    (对第一部分和第二部分的理解可以在看完第三部分有一个认识后,在进一步回过头来理解)

一、进化策略的思想:
1,进化策略:
(1)进化策略的认识:进化策略是一种模仿生物进化的一种求解参数优化问题的方法;不过与遗传算法不一样的是,它采用实数值作为基因;它总遵循零均值、某一方差的高斯分布的变化产生新的个体,然后保留好的个体。

(2)进化策略的过程:进化策略的一般算法可以描述如下:

  • 问题为寻找实值n维矢量x,使得函数F(x)取极值。不失一般性,设此程序为极小化过程。(确定问题
  • 初始化:从各维的可行范围内随机选取亲本xi,i=1,…,p的初始值。初始试验的分布一般是均匀分布。(初始化种群
  • 进化:对两个个体进行交叉重组;通过对于x的每个分量增加零均值和预先选定的标准差的高斯随机变量,从每个亲本xi产生子代x’i。(交叉、变异
  • 选择:通过将误差F(xi)和F(x’i),i=1,…,p 进行排序,选择并决定哪些矢量保留。具有最小误差的p个矢量变成下一代的新亲本。(把父亲和儿子放在一起用适应度排序,保留好的)。
  • 重复进化和选择直到达到收敛

2,进化策略的关键步骤:进化策略的关键在于:交叉、变异、变异程度的变化、选择
(1)交叉:和遗传算法一样,交叉就是交换两个个体的基因,主要有三种方式:

  • 离散重组。先随机选择两个父代个体,然后将其分量进行随机交换,构成子代新个体的各个分量,从而得出如下新个体。
  • 中值重组。这种重组方式也是先随机选择两个父代个体,然后将父代个体各分量的平均值作为子代新个体的分量,构成的新个体为。
  • 混杂重组。这种重组方式的特点在于父代个体的选择上。混杂重组时先随机选择一个固定的父代个体,然后针对子代个体每个分量再从父代群体中随机选择第二个父代个体。也就是说,第二个父代个体是经常变化的。至于父代两个个体的组合方式,既可以采用离散方式,也可以来用中值方式,甚至可以把中值重组中的1/2改为[0,1]之间的任一权值。

(2)变异: 变异比较简单,就是在每个分量上面加上零均值、某一方差的高斯分布的变化产生新的个体。这个某一方差就是变异程度。

(3)变异程度:变异程度并不是一直不变化的,算法开始的时候变异程度比较大,当接近收敛后,变异程度会开始减小。

(4)选择:进化策略的选择有两种:(μ+λ)选择是从μ个父代个体及λ个子代新个体中确定性地择优选出μ个个体组成下一代新群体;(μ, λ)选择是从λ个子代新个体中确定性地择优桃选μ个个体(要求λ>μ)组成下一代群体,每个个体只存活一代,随即被新个体顶替。粗略地看,似乎(μ+λ)选择最好,它可以保证最优个体存活,使群体的进化过程呈单调上升趋势。但是(μ+λ)选择保留旧个体,有时是局部最优解,这也带来了很多问题。
(实践也证明,(μ, λ)-ES优于(μ+λ)-ES,前者已成为当前进化策略的主流。

3,进化策略的分类:根据选择方法的不同,进化策略可以分为:(μ+λ)-ES、(μ, λ)-ES。根据具体取值的不同我们常见的有(1+1)-ES,(μ, λ)-ES两种。
(1)(1+1)-ES: 这种进化策略只有一个父亲,每次也只产生一个新的个体,然后从两个中保留好的。

  • 个体:个体由各个实数分量表示。
  • 进化:这类在进化过程中只有变异:就是在每个分量上面加上零均值、某一方差的高斯分布的变化产生新的个体。
  • 变异程度:这里采用1/5关系:还没到收敛的时候(左图), 我们增大 MUT_STRENGTH, 如果已经快到收敛了(右图), 我们就减小 MUT_STRENGTH. 那如何判断是否快到收敛没呢, 就是如果有1/5的变异比原始的 parent 好的话, 就是快收敛了(像右图). 在左图中, 有一半比原始 parent 好, 一半比较差, 所以还没到收敛.
    这里写图片描述
    具体在(1+1)-ES中的变化公式:
    这里写图片描述
  • 选择:就是从两个中选择好的。

(2)(μ, λ)-ES:这种进化策略的种群中有μ个体,每次新产生λ个体,然后从λ个新的个体中选着μ个作为新的种群。

  • 个体:个体有两部分组成,一部分是基因:就是各个分量值,另一部分:每个分量对应的兵役程度。
  • 进化:包括交叉和变异(具体和上面一样)
  • 变异程度: 变异程度也能变异。将变异强度变异以后, 他就能在快收敛的时候很自觉的逐渐减小变异强度, 方便收敛。
  • 选择:从λ个新的个体中选着μ个作为新的种群。

二、进化策略与遗产算法的区别:遗传算法强调染色体的操作,进化策略强调了个体级的行为变化
1,基本的区别是它们的研究方法和领域不同:

  • 进化策略是一种数值优化的方法。它采用的是一个具有自适应步长σ,和倾角θ的特定爬山方法,进化策略被应用于离散型优化问题。
  • 遗传算法从厂义是一种自适应搜索技术,决定着如何分配在高于平均规划的情况下呈指数增长的试验数据,参数优化是它的应用领域之一。

    2,表示个体的方式不同:

  • 进化策略在浮点矢量上运行

  • 遗传算法一般运行在二进制矢量上

3,选择过程不同:进化策略有(μ+λ)、(μ, λ)选择;遗传算法一般采用轮盘悬着的方法。

4,参数变化不同:进化策略中的变异程度是在改变的;遗传算法中的参数一般保持恒定。

三、进化策略算法的实例:
求解函数的最优值:F(x)= sin(10*x)*x + cos(2*x)*x,x的边界:[0,5]
1,(1+1)-ES算法:
实例的完整代码,包括可视化展示:(1+1)-ES
个体:各个分量值

parent = 5*np.random.rand(DNA_SIZE)

进化:

def make_kid(parent):   # 生成孩子
    kid = parent + MUT_STRENGTH*np.random.randn(DNA_SIZE)
    kid = np.clip(kid,*DNA_BOUND)   # 边界化,不能超过边界

    return kid

选择:

def kill_bad(parent, kid):  # 抛弃掉不好的,同时根据结果修改变异强度
    global MUT_STRENGTH
    fp = get_fitness(F(parent))[0]
    fk = get_fitness(F(kid))[0]
    p_target = 1/5

    if fp < fk:
        parent = kid    # 抛弃不好的
        ps = 1
    else:
        ps = 0

    MUT_STRENGTH *= np.exp(1/np.sqrt(DNA_SIZE+1)*(ps-p_target)/(1-p_target))    # 修改变异强度
    return parent

2,(μ+ λ)-ES算法:
实例的完整代码,包括可视化展示:(μ,+λ)-ES

个体:

pop = dict(DNA = 5*np.random.rand(1,DNA_SIZE).repeat(POP_SIZE,axis=0),
               mut_strength=np.random.rand(POP_SIZE,DNA_SIZE))  # 初始化DNA和变异强度

进化:

def make_kid(pop, n_kid):   # 产生孩子的过程
    kids = {'DNA':np.empty((n_kid,DNA_SIZE))}
    kids['mut_strength'] = np.empty_like(kids['DNA'])

    for kv,ks in zip(kids['DNA'],kids['mut_strength']):
        p1,p2 = np.random.choice(np.arange(POP_SIZE),size=2,replace=True)
        cp = np.random.randint(0,2,DNA_SIZE,dtype=np.bool)
        # 交叉过程
        kv[cp] = pop['DNA'][p1,cp]
        kv[~cp] = pop['DNA'][p2,~cp]
        ks[cp] = pop['mut_strength'][p1, cp]
        ks[~cp] = pop['mut_strength'][p2, ~cp]
        # 变异过程
        ks[:] = np.maximum(ks + (np.random.rand(*ks.shape)-0.5),0.) # 变异程度也可以改变,保持大于0
        kv += ks * np.random.rand(*kv.shape)
        kv[:] = np.clip(kv,*DNA_BOUND)

    return kids

选择:

def kill_bad(pop, kids): # 抛弃不好的
    for key in ['DNA','mut_strength']:  # 合并父亲和儿子
        pop[key] = np.vstack((pop[key],kids[key]))

    # 利用适应度选择出好的,排序,选出前面的POP_SIZE
    fitness = get_fitness(F(pop['DNA']))
    idx = np.arange(pop['DNA'].shape[0])
    good_idx = idx[fitness.argsort()][-POP_SIZE:]

    for key in ['DNA','mut_strength']:
        pop[key] = pop[key][good_idx]
    return pop

猜你喜欢

转载自blog.csdn.net/u014248127/article/details/79143437