主页
  • 主页
  • 分类
  • 热文
  • 教程
  • 面试
  • 标签
Python 人工智能

Python 人工智能 教程

Python 人工智能 入门概念
Python 人工智能 开始使用
Python 人工智能 机器学习
Python 人工智能 数据准备
Python 人工智能 监督学习:分类
Python 人工智能 监督学习:回归
Python 人工智能 逻辑编程
Python 人工智能 无监督学习:聚类
Python 人工智能 自然语言处理 (NLP)
Python 人工智能 NLTK(自然语言工具包)
Python 人工智能 分析时间序列数据
Python 人工智能 语音识别
Python 人工智能 启发式搜索
Python 人工智能 游戏
Python 人工智能 神经网络
Python 人工智能 强化学习
Python 人工智能 遗传算法
Python 人工智能 计算机视觉
Python 人工智能 深度学习

教程

Python 人工智能 入门概念
Python 人工智能 开始使用
Python 人工智能 机器学习
Python 人工智能 数据准备
Python 人工智能 监督学习:分类
Python 人工智能 监督学习:回归
Python 人工智能 逻辑编程
Python 人工智能 无监督学习:聚类
Python 人工智能 自然语言处理 (NLP)
Python 人工智能 NLTK(自然语言工具包)
Python 人工智能 分析时间序列数据
Python 人工智能 语音识别
Python 人工智能 启发式搜索
Python 人工智能 游戏
Python 人工智能 神经网络
Python 人工智能 强化学习
Python 人工智能 遗传算法
Python 人工智能 计算机视觉
Python 人工智能 深度学习

Python 人工智能 遗传算法


上一章 下一章

什么是遗传算法?

遗传算法(GAs)是一类基于自然选择和遗传学概念的搜索算法。GA 是更大分支——进化计算的一部分。

遗传算法是由密歇根大学的 John Holland 及其学生和同事发展起来的,其中最著名的是 David E. Goldberg。自那时起,它已被成功应用于各种优化问题。

在 GA 中,我们有一个可能解决方案的池。这些解决方案随后经历了重组和变异(就像自然遗传那样),产生了新的后代,并且这一过程在多代中重复。每个个体(或候选解)都会被分配一个适应值(基于其目标函数值),并且适应性更高的个体有更多的机会繁殖并产生适应性更强的后代。这符合达尔文的适者生存理论。

因此,它会在世代中不断演化出更好的个体或解决方案,直到达到停止准则。

遗传算法本质上是足够随机化的,但它们的表现优于随机局部搜索(即我们只是尝试随机解,并记录目前为止最好的解),因为它们还利用了历史信息。

如何使用遗传算法解决优化问题?

优化是指使设计、情况、资源和系统尽可能有效的行为。下面的框图展示了优化过程:

Optimization Problems

优化问题

优化过程中的遗传算法机制阶段

当用于解决问题的优化时,GA 机制的步骤序列如下:

  1. 随机生成初始种群。
  2. 选择具有最佳适应值的初始解。
  3. 使用变异和交叉算子重新组合所选解。
  4. 将后代插入种群中。
  5. 如果满足停止条件,则返回具有最佳适应值的解;否则返回第二步。

安装必要的包

为了使用遗传算法在 Python 中解决问题,我们将使用一个强大的 GA 包叫做 DEAP。这是一个新式进化计算框架的库,用于快速原型设计和测试想法。我们可以在命令提示符下使用以下命令来安装这个包:

pip install deap

如果你使用的是 Anaconda 环境,可以使用以下命令来安装 deap:

conda install -c conda-forge deap

使用遗传算法实现解决方案

本节解释了如何使用遗传算法实现解决方案。

生成比特模式

下面的例子展示了如何生成一个比特字符串,该字符串包含 15 个 1,基于 One Max 问题。

导入必要的包

import random
from deap import base, creator, tools

定义评估函数

这是创建遗传算法的第一步。

def eval_func(individual):
   target_sum = 15
   return len(individual) - abs(sum(individual) - target_sum),

创建带有正确参数的工具箱

def create_toolbox(num_bits):
   creator.create("FitnessMax", base.Fitness, weights=(1.0,))
   creator.create("Individual", list, fitness=creator.FitnessMax)

   toolbox = base.Toolbox()
   toolbox.register("attr_bool", random.randint, 0, 1)
   toolbox.register("individual", tools.initRepeat, creator.Individual,
   toolbox.attr_bool, num_bits)
   toolbox.register("population", tools.initRepeat, list, toolbox.individual)

   toolbox.register("evaluate", eval_func)
   toolbox.register("mate", tools.cxTwoPoint)
   toolbox.register("mutate", tools.mutFlipBit, indpb = 0.05)
   toolbox.register("select", tools.selTournament, tournsize = 3)
   return toolbox

主函数

if __name__ == "__main__":
   num_bits = 45
   toolbox = create_toolbox(num_bits)
   random.seed(7)
   population = toolbox.population(n = 500)
   probab_crossing, probab_mutating = 0.5, 0.2
   num_generations = 10
   print('\nEvolution process starts')

   # 评估整个种群
   fitnesses = list(map(toolbox.evaluate, population))
   for ind, fit in zip(population, fitnesses):
       ind.fitness.values = fit
   print('\nEvaluated', len(population), 'individuals')

   # 创建并迭代通过世代
   for g in range(num_generations):
       print("\n- Generation", g)
       # 选择下一代个体
       offspring = toolbox.select(population, len(population))
       # 克隆选定的个体
       offspring = list(map(toolbox.clone, offspring))

       # 应用交叉和变异
       for child1, child2 in zip(offspring[::2], offspring[1::2]):
           if random.random() < probab_crossing:
               toolbox.mate(child1, child2)
           del child1.fitness.values
           del child2.fitness.values

       for mutant in offspring:
           if random.random() < probab_mutating:
               toolbox.mutate(mutant)
               del mutant.fitness.values

       # 评估无效适应度的个体
       invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
       fitnesses = map(toolbox.evaluate, invalid_ind)
       for ind, fit in zip(invalid_ind, fitnesses):
           ind.fitness.values = fit
       print('Evaluated', len(invalid_ind), 'individuals')

       # 替换种群与下一代个体
       population[:] = offspring

       # 打印当前世代的统计信息
       fits = [ind.fitness.values[0] for ind in population]
       length = len(population)
       mean = sum(fits) / length
       sum2 = sum(x*x for x in fits)
       std = abs(sum2 / length - mean**2)**0.5
       print('Min =', min(fits), ', Max =', max(fits))
       print('Average =', round(mean, 2), ', Standard deviation =', round(std, 2))
   print("\n- Evolution ends")

   # 打印最终输出
   best_ind = tools.selBest(population, 1)[0]
   print('\nBest individual:\n', best_ind)
   print('\nNumber of ones:', sum(best_ind))

输出示例

Evolution process starts
Evaluated 500 individuals
- Generation 0
Evaluated 295 individuals
Min = 32.0 , Max = 45.0
Average = 40.29 , Standard deviation = 2.61
- Generation 1
Evaluated 292 individuals
Min = 34.0 , Max = 45.0
Average = 42.35 , Standard deviation = 1.91
- Generation 2
Evaluated 277 individuals
Min = 37.0 , Max = 45.0
Average = 43.39 , Standard deviation = 1.46
… … … …
- Generation 9
Evaluated 299 individuals
Min = 40.0 , Max = 45.0
Average = 44.12 , Standard deviation = 1.11
- Evolution ends
Best individual:
[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1,
 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0,
 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1]
Number of ones: 15

符号回归问题

这是遗传编程中已知的最佳问题之一。所有的符号回归问题都使用任意的数据分布,并试图用符号公式拟合最准确的数据。通常,使用 RMSE(均方根误差)这样的度量来衡量个体的适应度。这是一个经典的回归问题,这里我们使用方程 5x^3-6x^2+8x=1。我们需要遵循上面例子中的所有步骤,但主要的部分是创建原始集合,因为它们是个体的基础,所以评估可以开始。在这里我们将使用经典的一组原始。

Python 代码详解

import operator
import math
import random
import numpy as np
from deap import algorithms, base, creator, tools, gp

def division_operator(numerator, denominator):
   if denominator == 0:
      return 1
   return numerator / denominator

def eval_func(individual, points):
   func = toolbox.compile(expr=individual)
   mse = [(func(x) - (5*x**3 - 6*x**2 + 8*x)) ** 2 for x in points]
   return math.fsum(mse) / len(points),

def create_toolbox():
   pset = gp.PrimitiveSet("MAIN", 1)
   pset.addPrimitive(operator.add, 2)
   pset.addPrimitive(operator.sub, 2)
   pset.addPrimitive(operator.mul, 2)
   pset.addPrimitive(division_operator, 2)
   pset.addPrimitive(operator.neg, 1)
   pset.addPrimitive(math.cos, 1)
   pset.addPrimitive(math.sin, 1)
   pset.addEphemeralConstant("rand101", lambda: random.randint(-1,1))
   pset.renameArguments(ARG0 = 'x')
   creator.create("FitnessMin", base.Fitness, weights = (-1.0,))
   creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMin)
   toolbox = base.Toolbox()
   toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=2)
   toolbox.register("population", tools.initRepeat, list, toolbox.individual)
   toolbox.register("compile", gp.compile, pset = pset)
   toolbox.register("evaluate", eval_func, points = [x/10. for x in range(-10,10)])
   toolbox.register("select", tools.selTournament, tournsize = 3)
   toolbox.register("mate", gp.cxOnePoint)
   toolbox.register("expr_mut", gp.genFull, min_=0, max_=2)
   toolbox.register("mutate", gp.mutUniform, expr = toolbox.expr_mut, pset = pset)
   toolbox.decorate("mate", gp.staticLimit(key = operator.attrgetter("height"), max_value = 17))
   toolbox.decorate("mutate", gp.staticLimit(key = operator.attrgetter("height"), max_value = 17))
   return toolbox

if __name__ == "__main__":
   random.seed(7)
   toolbox = create_toolbox()
   population = toolbox.population(n = 450)
   hall_of_fame = tools.HallOfFame(1)
   stats_fit = tools.Statistics(lambda x: x.fitness.values)
   stats_size = tools.Statistics(len)
   mstats = tools.MultiStatistics(fitness=stats_fit, size = stats_size)
   mstats.register("avg", np.mean)
   mstats.register("std", np.std)
   mstats.register("min", np.min)
   mstats.register("max", np.max)
   probab_crossover = 0.4
   probab_mutate = 0.2
   number_gen = 10
   population, log = algorithms.eaSimple(population, toolbox,
      probab_crossover, probab_mutate, number_gen,
      stats = mstats, halloffame = hall_of_fame, verbose = True)

注意,所有的基本步骤与生成比特模式时使用的步骤相同。这个程序将在 10 代之后给我们输出 min, max, std(标准偏差)。

上一章 下一章
阅读号二维码

关注阅读号

联系二维码

联系我们

© 2024 Yoagoa. All rights reserved.

粤ICP备18007391号

站点地图