莫烦python:Evolution Strategy Basic 进化策略基础

莫烦python:Evolution Strategy Basic 进化策略基础

莫烦老师网课链接:https://www.bilibili.com/video/av16926245?p=8&spm_id_from=pageDriver
在这里插入图片描述
在这里插入图片描述

解析全在代码里了,可直接copy去看

"""
The Evolution Strategy can be summarized as the following term:
{mu/rho +, lambda}-ES

Here we use following term to find a maximum point.
{n_pop/n_pop + n_kid}-ES

Visit my tutorial website for more: https://mofanpy.com/tutorials/
要我用一句话概括ES: 在程序里生宝宝, 杀死不乖的宝宝, 让乖宝宝继续生宝宝.
"""
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()


# 首先的 make_kid 功能. 我们随机找到一对父母, 然后将父母的 DNA 和 mut_strength 基因都 crossover 给 kid.
# 然后再根据 mut_strength mutate 一下 kid 的 DNA. 也就是用正态分布抽一个 DNA sample.
# 而且 mut_strength 也能变异. 将变异强度变异以后, 他就能在快收敛的时候很自觉的逐渐减小变异强度, 方便收敛.
def make_kid(pop, n_kid):
    # generate empty kid holder
    # 根据正态分布生孩子
    kids = {'DNA': np.empty((n_kid, DNA_SIZE))}     # kids' DNA-->(50, 1)
    kids['mut_strength'] = np.empty_like(kids['DNA'])   # kids' mut_strength-->(50, 1)
    for kv, ks in zip(kids['DNA'], kids['mut_strength']):
        # crossover (roughly half p1 and half p2)
        # parents1 parents2-->随机选择
        p1, p2 = np.random.choice(np.arange(POP_SIZE), size=2, replace=False)
        # replace表示抽样后是否放回,为True表示有放回,则可能会出现相同的索引值,为False则不会
        # crossover points
        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]
        # kids mut_strength
        ks[cp] = pop['mut_strength'][p1, cp]
        ks[~cp] = pop['mut_strength'][p2, ~cp]
        # 以上便是将爸妈的DNA交叉后便合并到一块的结果
        # 怎么合并的?--》比如 爸爸的DNA是[[50], [49],...]
        # kv[cp] = pop['DNA'][p1, cp]-->将50替换掉
        # kv[~cp] = pop['DNA'][p2, ~cp]剩下的全是妈妈的
        # 又因为是随机配对的,所以有可能会把相同的基因又换回去,但是这没关系的

        # mutate (change DNA based on normal distribution)
        # 让变异强度也产生一定幅度的变异
        # rand-->返回shape为(d0, d1, ..., dn)的标准正态分布(均值为0,标准差为1)的数组
        ks[:] = np.maximum(ks + (np.random.rand(*ks.shape)-0.5), 0.)    # must > 0
        # kids value-->每一个的变异强度*正态分布的标准差
        kv += ks * np.random.randn(*kv.shape)
        # 放到0~5的范围内
        kv[:] = np.clip(kv, *DNA_BOUND)    # clip the mutated value
    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]))
        #     vstack是垂直(按照行顺序)的把数组给堆叠起来

    fitness = get_fitness(F(pop['DNA']))            # calculate global fitness
    idx = np.arange(pop['DNA'].shape[0])
    # 选取最大的前100位
    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


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
# 这个点只有一个, 所以我们的 DNA 的长度就只有一个. 我们用一个 python 字典来存这两种 DNA 的信息. 这里 DNA 存的是均值, mut_strength 存的是标准差.
# 传统的 ES DNA 形式分两种, 它有两条 DNA. 一个 DNA 是控制数值的, 第二个 DNA 是控制这个数值的变异强度. 比如一个问题有4个变量.
# 那一个 DNA 中就有4个位置存放这4个变量的值 (这就是我们要得到的答案值). 第二个 DNA 中就存放4个变量的变动幅度值.
# DNA1=1.23, -0.13, 2.35, 112.5 可以理解为4个正态分布的4个平均值.
# DNA2=0.1, 2.44, 5.112, 2.144 可以理解为4个正态分布的4个标准差.
# 所以这两条 DNA 都需要被 crossover 和 mutate.
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()
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值