Python 进化算法的简单介绍和实现

总起

文章中的源码可以在 GitHub - anguangzhihen/PythonTest 中的EvoGATest.py找到。

进化算法(EA)是从达尔文的自然选择理论和现代分子遗传学获得灵感而发展出来的算法。

使用进化算法的动机之一是它能提供一套具有鲁棒问题求解的算法,它已在大学课程编排、卫星天线吊杆设计、银行贷款建模、股票的交易模型取得一定的成果。

所有进化算法都基于同一基本理念:由个体组成的种群在有限资源环境中,对资源的竞争导致自然选择现象的产生。

特点:

1.基于种群运行的;

2.多数进化算法采用重组操作算子;

3.进化算法是随机的。

组成:

1.问题表示;

2.评估函数;

3.种群;

4.父代选择机制;

5.变异操作算子,包括重组和突变;

6.生存选择机制。

进化算法的主要种类:

1.遗传算法(GA),应用最为广泛,被视为一种函数优化方法,SGA是进化算法的果蝇:采用二进制进行表示、适应度比例机制的选择操作算子、较低概率的突变操作算子、强调以生物遗传机制启发机理的重组操作算子;

2.进化策略(ES),采用实数进行表示,选择压力通常会非常高,最新的CMA算法是优化复杂实值函数的主要流行算法之一;

3.进化规划(EP),无重组操作,经典的EP算法采用状态机表示个体,现在多使用实数;

4.遗传规划(GP),以树为染色体,可定位为通过自然选择进行计算机编程,低或零突变概率;

5.学习分类器系统(LCS),通过基于规则集方式对知识表征;

6.差分进化(DE),对进化算法中常见的复制操作算子进行了“扭曲”,即得到所谓的差分突变;

7.粒子群优化(PSO),使用向量加法进行定义的突变操作算子;

8.分布估计算法(EDA),通过3步过程采用“标准”变异操作替代新子代创建。

在游戏内容的生成上,这类基于搜索方法(进化算法是其中最重要的算法之一)具有广泛的适用性,缺点是速度非常慢,然后在设计具体的搜索算法、表示以及评估函数的时候,各个成功的方法需要依靠明智的设计选择。

遗传算法实现

在上一节中,我们大概介绍了一下进化算法,本节我们将实现一下进化算法中一个简单的遗传算法。

首先我们描述一下问题:有函数y = x^2,从5位二进制编码中寻找使y最大。当然我们一眼就能看出来问题的答案是 x = 0b11111,即31,通过这个简单问题,我们能大概理解进化算法的原理。

接着我们来看一下整个算法的基本循环:

# 初始化种群,从[0, MAX_X]中随机选出
pop = np.random.randint(1, size = POP_SIZE)
for i in range(N_GENERATIONS):
    # 获取适应度
    fitness = getFitness(pop)
    # 父代选择
    pop = select(pop, fitness)
    popCopy = pop.copy()
    for popIndex in range(len(pop)):
        parent = pop[popIndex]
        # 重组,使用单点交叉
        child = crossover(parent, popCopy)
        # 突变,使用位翻转
        child = mutate(child)
        # 生存选择,使用基于年龄的替代策略,但父代和子代数量相同,所以将所有子代替换成父代
        pop[popIndex] = child

 
最后实现具体的函数即可:

# 获取适应度
def getFitness(pred):
    return pred + 1e-3

# 选择父代,使用适合比例选择(FPS)机制
def select(pop, fitness):
    return np.random.choice(pop, size = POP_SIZE, replace = True, p = fitness / fitness.sum())

# 重组
def crossover(parent, pop):
    # 选择一个交叉的个体
    other = np.random.choice(pop)
    # 选择交叉点
    point = np.random.randint(1, DNA_SIZE - 1)
    cross = [fillBits(point), fillBits(point) ^ MAX_X]
    np.random.shuffle(cross)
    return (parent & cross[0]) + (other & cross[1])

# 突变(本问题中可以使用格雷码以保证连续整数在二进制变化中的汉明距离也为1)
def mutate(child):
    for i in range(DNA_SIZE):
        # 获得突变位置
        point = 1 << i
        if np.random.rand() < MUTATION_RATE:
            child = child ^ point
    return child

运行看一下效果:

Python 进化算法的简单介绍和实现_第1张图片

虽然选到了最高的点,不过整个算法看起来像是在随机运行。

这里存在两个问题:

1.突变概率太大造成了对优良解的破坏;

2.选择父代时,使用FPS机制导致个体合适度彼此接近时几乎没有选择压力;

处理方式:

1.我们可以将突变概率设置为1%(原为10%);

2.我们在计算适应度时可以减去当前最小的适应度扩大选择压力;

最终效果:

Python 进化算法的简单介绍和实现_第2张图片

参考

【莫烦Python】进化算法 Evolutionary Algorithms_哔哩哔哩_bilibili

《进化计算导论》

《人工智能与游戏》

你可能感兴趣的:(游戏AI,算法,python,进化算法,AI,人工智能)