进化策略求解最值问题详解,通俗易懂(附python代码)

进化策略

问题:求 y = x sin 10 x + x cos 2 x y=x\sin{10x}+x\cos{2x} [ 0 , 5 ] [0, 5] 上的最大值。
解题步骤:
1、随机生成种群 p o p pop ,假设种群中含 100 100 条染色体以及每条染色体的变异概率。因为函数自变量只有一个,故每条染色体上只有一个基因。
2、从 p o p pop 中随机选出两条染色体(以及它们的变异概率)来产生一条子染色体。设这两条染色体为 p 1 p_{1} p 2 p_{2}
3、设由这两条父染色体产生的子染色体及其变异概率分别为 k v kv k s ks ,将 p 1 p_{1} p 2 p_{2} 50 50% 的概率复制给 k v kv k s ks
4、子染色体(及其变异概率)发生变异。
5、设一代中产生50条子染色体,则将以上过程重复进行50次。
6、将产生的50条子染色体与100条原始父染色体放在一起,计算它们的适应度(即 y y 值)。
7、按适应度对150条染色体进行排序,选取适应度最大的前100条染色体,将它们作为新的父代染色体重复以上过程,直到所有染色体都被最优染色体取代或达到迭代次数。
p y t h o n python 代码如下:

import numpy as np
DNA_SIZE = 1             # DNA (real number)
DNA_BOUND = [0, 5]       # solution upper and lower bounds
N_GENERATIONS = 200
POP_SIZE = 100           # population size
N_KID = 50             # n kids per generation
def F(x): return np.sin(10*x)*x + np.cos(2*x)*x     # to find the maximum of this function
# find non-zero fitness for selection
def get_fitness(pred): return pred.flatten()
def make_kid(pop, n_kid):
    # generate empty kid holder
    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']):
        # crossover (roughly half p1 and half p2)
        p1, p2 = np.random.choice(np.arange(POP_SIZE), size=2, replace=False)
        cp = np.random.randint(0, 2, DNA_SIZE, dtype=np.bool)  # crossover points
        kv[cp] = pop['DNA'][p1, cp]  # 若 cp 为 True,则将 pop['DNA'][p1] 的值赋给 kv,否则不变。
        kv[~cp] = pop['DNA'][p2, ~cp]  # 若 cp 为 False,则将 pop['DNA'][p2] 的值赋给 kv,否则不变。
        ks[cp] = pop['mut_strength'][p1, cp]
        ks[~cp] = pop['mut_strength'][p2, ~cp]

        # mutate (change DNA based on normal distribution)
        ks[:] = np.maximum(ks + (np.random.rand(*ks.shape)-0.5), 0.)    # must > 0
        kv += ks * np.random.randn(*kv.shape)
        # clip这个函数将将数组中的元素限制在a_min, a_max之间,大于a_max的就使它等于 a_max,小于a_min的就使它等于a_min。
        kv[:] = np.clip(kv, *DNA_BOUND)
    return kids
def kill_bad(pop, kids):
    # put pop and kids together
    for key in ['DNA', 'mut_strength']:
        pop[key] = np.vstack((pop[key], kids[key]))  # 将新产生的染色体(包括变异程度)与父代染色体放到一起作比较

    fitness = get_fitness(F(pop['DNA']))            # calculate global fitness
    idx = np.arange(pop['DNA'].shape[0])
    # argsort函数返回的是数组值从小到大的索引值
    # [-POP_SIZE:] 指从后往前取 POP_SIZE 个,保持种群中染色体数量不变
    good_idx = idx[fitness.argsort()][-POP_SIZE:]
    for key in ['DNA', 'mut_strength']:
        pop[key] = pop[key][good_idx]
    return pop
pop = dict(DNA=5 * np.random.rand(1, DNA_SIZE).repeat(POP_SIZE, axis=0),   # initialize the pop DNA values
           mut_strength=np.random.rand(POP_SIZE, DNA_SIZE))                # initialize the pop mutation strength values
for _ in range(N_GENERATIONS):

    # ES part
    kids = make_kid(pop, N_KID)
    pop = kill_bad(pop, kids)   # keep some good parent for elitism
	print(F(pop['DNA'][0])  # 最优解
发布了36 篇原创文章 · 获赞 1 · 访问量 568

猜你喜欢

转载自blog.csdn.net/qq_36758914/article/details/103331096