您的位置:首页 > 其它

进化策略

2018-03-21 15:22 190 查看
一、什么是进化策略

进化策略和遗传算法都使用到了遗传信息,比较DNA,然后繁衍变异,从而获取上一代没有的东西。然后通过适者生存不适者淘汰的这一套理论不断进化。

那下面来看下进化策略与遗传算法的不同。

就遗传算法来说,遗传算法使用的DNA是二进制编码的,爸妈的DNA交叉配对组成宝宝的DNA,宝宝也会再进行一定的变异获得新的属性,但是一般的进化策略却略有不同。



进化策略中,爸妈的DNA不再用01这种形式了,直接用实数来代替,这样就不会涉及二进制的转换问题了,从而能够解决实际生活中的很多由实数组成的真实问题,比如我有一个关于x的公式,而这个公式找那个其他参数都可以用DNA的实数来代替,然后进化我的DNA,也就是优化这个公式。那这个时候宝宝要如何变异呢?

进化策略中有一个因素可以帮我们进行宝宝变异,那就是变异强度,简单来说,我们将爸妈的遗传信息看成是正态分布的平均值,再在这个平均值上附加一个标准差,我们就能用正态分布产生一个相近的数,如下图:



比如途中8.8位置上的变异强度是1,我们就按照1的标准差和8.8的均值产生一个离8.8比较近的数,比如8.7,然后对宝宝每一位上的值进行同样的操作,就能产生稍微不同的宝宝DNA了,所以,变异强度也可以当成一组遗传信息从爸妈的DNA中遗传下来,甚至遗传为宝宝的变异强度基因也能变异。



所以,在进化策略中,可以将两种遗传信息传递给后代,一种是可以代表遗传信息所在位置的均值,另一种是记录这个均值的变异强度,有了这两组信息我们就可以自由的在实数区间进行变异繁衍啦。

二、代码实现进化策略

整个程序基本就是生孩子丢掉坏孩子的过程,每次就是生孩子然后将父母和孩子放在一起去计算他们的fitness,然后排序取前面一段作为新的population

import numpy as np
import matplotlib.pyplot as plt

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]
kv[~cp] = pop['DNA'][p2, ~cp]
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)
kv[:] = np.clip(kv, *DNA_BOUND)    # clip the mutated value
return kids   将数据都控制在DNA范围内

#丢掉坏宝宝
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])
good_idx = idx[fitness.argsort()][-POP_SIZE:]   # selected by fitness ranking (not value)
for key in ['DNA', 'mut_strength']:
pop[key] = pop[key][good_idx]
return pop

#生成population,在这里我们不仅要生成DNA还要生成mutation strength变异强度
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

plt.ion()       # something about plotting
x = np.linspace(*DNA_BOUND, 200)
plt.plot(x, F(x))

for _ in range(N_GENERATIONS):
# something about plotting
if 'sca' in globals(): sca.remove()
sca = plt.scatter(pop['DNA'], F(pop['DNA']), s=200, lw=0, c='red', alpha=0.5); plt.pause(0.05)

# ES part  整个进化的循环其实就是不断的生小孩和丢掉坏小孩的过程
kids = make_kid(pop, N_KID)
pop = kill_bad(pop, kids)   # keep some good parent for elitism

plt.ioff(); plt.show()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: