GAFT:一个使用Python实现的遗传算法框架

前言

最近需要用到遗传算法来优化一些东西,最初是打算直接基于某些算法实现一个简单的函数来优化,但是感觉单纯写个非通用的函数运行后期改进算子或者别人使用起来都会带来困难,同时遗传算法基本概念和运行流程相对固定,改进也一般通过编码机制,选择策略,交叉变异算子以及参数设计等方面,对于算法的整体结构并没有大的影响。这样对于遗传算法来说,就非常适合写个相对固定的框架然后给算子、参数等留出空间以便对新算法进行测试和改进。于是就动手写了个遗传算法的小框架gaft,本文对此框架进行一些介绍并分别以一个一维搜索和二维搜索为例子对使用方法进行了介绍。

  • GitHub: https://github.com/PytLab/gaft
  • PyPI: https://pypi.python.org/pypi/gaft

目前框架只是完成了最初的版本,比较简陋,内置了几个基本的常用算子,使用者可以根据接口规则实现自定义的算子并放入框架中运行。我自己也会根据自己的需求后续添加更多的改进算子,同时改进框架使其更加通用.

正文

遗传算法介绍

这里我对遗传算法的基本概念进行简要的介绍,并阐述gaft的设计原则。

简单而言,遗传算法使用群体搜索技术,将种群代表一组问题的可行解,通过对当前种群施加选择,交叉,变异等一些列遗传操作来产生新一代的种群,并逐步是种群进化到包含近似全局最优解的状态。下面我将遗传学和遗传算法相关术语的对应关系总结一下:

术语

算法特点

  1. 以决策变量的编码作为运算对象,使得优化过程借鉴生物学中的概念成为可能
  2. 直接以目标函数作为搜索信息,确定搜索方向很范围,属于无导数优化
  3. 同时使用多个搜索点的搜索信息,算是一种隐含的并行性
  4. 是一种基于概率的搜索技术
  5. 具有自组织,自适应和自学习等特性

算法流程

gaft 设计原则

由于遗传算法的流程相对固定,我们优化算法基本上也是在流程整体框架下对编码机制,算子,参数等进行修改,因此在写框架的时候,我便想把那些固定的遗传算子,适应度函数写成接口,并使用元类、装饰器等方式实现对接口的限制和优化,这样便可以方便后续自定义算符和适应度函数定制。最后将各个部分组合到一起组成一个engine然后根据算法流程运行遗传算法对目标进行优化.

这样我们便脱离每次都要写遗传算法流程的繁琐,每次只需要像写插件一样实现自己的算子和适应度函数便可以将其放入gaft开始对算法进行测试或者对目标函数进行优化了。

GAFT文件结构

此部分我对自己实现的框架的整体结构进行下介绍.


  1.  
  2. ├── LICENSE 
  3.  
  4. ├── MANIFEST.in 
  5.  
  6. ├── README.rst 
  7.  
  8. ├── examples 
  9.  
  10. │ ├── ex01 
  11.  
  12. │ └── ex02 
  13.  
  14. ├── gaft 
  15.  
  16. │ ├── __init__.py 
  17.  
  18. │ ├── __pycache__ 
  19.  
  20. │ ├── analysis 
  21.  
  22. │ ├── components 
  23.  
  24. │ ├── engine.py 
  25.  
  26. │ ├── operators 
  27.  
  28. │ └── plugin_interfaces 
  29.  
  30. ├── setup.cfg 
  31.  
  32. ├── setup.py 
  33.  
  34. └── tests 
  35.  
  36. ├── flip_bit_mutation_test.py 
  37.  
  38. ├── gaft_test.py 
  39.  
  40. ├── individual_test.py 
  41.  
  42. ├── population_test.py 
  43.  
  44. ├── roulette_wheel_selection_test.py 
  45.  
  46. └── uniform_crossover_test.py  

目前的文件结果如上所示,

  • /gaft/components中定义了内置的个体和种群类型,提供了两种不同的遗传编码方式:二进制编码和实数编码。
  • /gaft/plugin_interfaces中是插件接口定义,所有的算子定义以及on-the-fly分析的接口规则都在里面,使用者可以根据此来编写自己的插件并放入到engine中。
  • /gaft/operators里面是内置遗传算子,他们也是遵循/gaft/plugin_interfaces中的规则进行编写,可以作为编写算子的例子。其中算子我目前内置了roulette
    wheel选择算子,uniform 交叉算子和flipbit变异算子,使用者可以直接使用内置算子来使用gaft对自己的问题进行优化。
  • /gaft/analysis里面是内置的on-the-fly分析插件,他可以在遗传算法迭代的过程中对迭代过程中的变量进行分析,例如我在里面内置了控制台日志信息输出,以及迭代适应度值的保存等插件方便对进化曲线作图。
  • /gaft/engine便是遗传算法的流程控制模块了,他将所有的之前定义的各个部分组合到一起使用遗传算法流程进行优化迭代。

使用GAFT

下面我就以两个函数作为例子来使用GAFT对目标函数进行优化.

一维搜索

首先我们先对一个简单的具有多个局部极值的函数进行优化,我们来使用内置的算子求函数 f(x)=x+10sin(5x)+7cos(4x)的极大值,x的取值范围为[0,10]

1. 先导入需要的模块


  1. from math import sin, cos 
  2.  
  3.   
  4.  
  5. # 导入种群和内置算子相关类 
  6.  
  7. from gaft import GAEngine 
  8.  
  9. from gaft.components import GAIndividual 
  10.  
  11. from gaft.components import GAPopulation 
  12.  
  13. from gaft.operators import RouletteWheelSelection 
  14.  
  15. from gaft.operators import UniformCrossover 
  16.  
  17. from gaft.operators import FlipBitMutation 
  18.  
  19.   
  20.  
  21. # 用于编写分析插件的接口类 
  22.  
  23. from gaft.plugin_interfaces.analysis import OnTheFlyAnalysis 
  24.  
  25.   
  26.  
  27. # 内置的存档适应度函数的分析类 
  28.  
  29. from gaft.analysis.fitness_store import FitnessStoreAnalysis 
  30.  
  31.   
  32.  
  33. # 我们将用两种方式将分析插件注册到遗传算法引擎中  

2. 创建引擎


  1. # 定义种群 
  2.  
  3. indv_template = GAIndividual(ranges=[(0, 10)], encoding='binary', eps=0.001) 
  4.  
  5. population = GAPopulation(indv_template=indv_template, size=50) 
  6.  
  7.   
  8.  
  9. # 创建遗传算子 
  10.  
  11. selection = RouletteWheelSelection() 
  12.  
  13. crossover = UniformCrossover(pc=0.8, pe=0.5) 
  14.  
  15. mutation = FlipBitMutation(pm=0.1) 
  16.  
  17.   
  18.  
  19. # 创建遗传算法引擎, 分析插件和适应度函数可以以参数的形式传入引擎中 
  20.  
  21. engine = GAEngine(population=population, selection=selection, 
  22.  
  23.                   crossover=crossover, mutation=mutation, 
  24.  
  25.                   analysis=[FitnessStoreAnalysis])  

3. 自定义适应度函数

可以通过修饰符的方式将,适应度函数注册到引擎中。


  1. @engine.fitness_register 
  2.  
  3. def fitness(indv): 
  4.  
  5.     x, = indv.variants 
  6.  
  7.     return x + 10*sin(5*x) + 7*cos(4*x)  

4. 自定义on-the-fly分析插件

也可以通过修饰符在定义的时候直接将插件注册到引擎中


  1. @engine.analysis_register 
  2.  
  3. class ConsoleOutputAnalysis(OnTheFlyAnalysis): 
  4.  
  5.     interval = 1 
  6.  
  7.   
  8.  
  9.     def register_step(self, ng, population, engine): 
  10.  
  11.         best_indv = population.best_indv(engine.fitness) 
  12.  
  13.         msg = 'Generation: {}, best fitness: {:.3f}'.format(ng, engine.fitness(best_indv)) 
  14.  
  15.         engine.logger.info(msg) 
  16.  
  17.   
  18.  
  19.     def finalize(self, population, engine): 
  20.  
  21.         best_indv = population.best_indv(engine.fitness) 
  22.  
  23.         x = best_indv.variants 
  24.  
  25.         y = engine.fitness(best_indv) 
  26.  
  27.         msg = 'Optimal solution: ({}, {})'.format(x, y) 
  28.  
  29.         engine.logger.info(msg)  

5. Ok, 开始跑(优化)吧!

我们这里跑100代种群.


  1. if '__main__' == __name__: 
  2.  
  3.     # Run the GA engine. 
  4.  
  5.     engine.run(ng=100)  

内置的分析插件会在每步迭代中记录得到的每一代的最优个体,并生成数据保存。

绘制一下函数本身的曲线和我们使用遗传算法得到的进化曲线:

优化过程动画:

二维搜索

下面我们使用GAFT内置算子来搜索同样具有多个极值点的二元函数f(x)=ysin(2πx)+xcos(2πy) 的最大值,x, y 的范围为 [−2,2] .

这里我们就不自定义分析插件了,直接使用内置的分析类,并在构造引擎时直接传入.


  1. ''' 
  2.  
  3. Find the global maximum for binary function: f(x) = y*sim(2*pi*x) + x*cos(2*pi*y) 
  4.  
  5. ''' 
  6.  
  7.   
  8.  
  9. from math import sin, cos, pi 
  10.  
  11.   
  12.  
  13. from gaft import GAEngine 
  14.  
  15. from gaft.components import GAIndividual 
  16.  
  17. from gaft.components import GAPopulation 
  18.  
  19. from gaft.operators import RouletteWheelSelection 
  20.  
  21. from gaft.operators import UniformCrossover 
  22.  
  23. from gaft.operators import FlipBitMutation 
  24.  
  25.   
  26.  
  27. # Built-in best fitness analysis. 
  28.  
  29. from gaft.analysis.fitness_store import FitnessStoreAnalysis 
  30.  
  31. from gaft.analysis.console_output import ConsoleOutputAnalysis 
  32.  
  33.   
  34.  
  35. # Define population. 
  36.  
  37. indv_template = GAIndividual(ranges=[(-2, 2), (-2, 2)], encoding='binary', eps=0.001) 
  38.  
  39. population = GAPopulation(indv_template=indv_template, size=50) 
  40.  
  41.   
  42.  
  43. # Create genetic operators. 
  44.  
  45. selection = RouletteWheelSelection() 
  46.  
  47. crossover = UniformCrossover(pc=0.8, pe=0.5) 
  48.  
  49. mutation = FlipBitMutation(pm=0.1) 
  50.  
  51.   
  52.  
  53. # Create genetic algorithm engine. 
  54.  
  55. # Here we pass all built-in analysis to engine constructor. 
  56.  
  57. engine = GAEngine(population=population, selection=selection, 
  58.  
  59.                   crossover=crossover, mutation=mutation, 
  60.  
  61.                   analysis=[ConsoleOutputAnalysis, FitnessStoreAnalysis]) 
  62.  
  63.   
  64.  
  65. # Define fitness function. 
  66.  
  67. @engine.fitness_register 
  68.  
  69. def fitness(indv): 
  70.  
  71.     x, y = indv.variants 
  72.  
  73.     return y*sin(2*pi*x) + x*cos(2*pi*y) 
  74.  
  75.   
  76.  
  77. if '__main__' == __name__: 
  78.  
  79.     engine.run(ng=100)  

进化曲线:

二维函数面:

搜索过程动画:

可见目前内置的基本算子都能很好的找到例子中函数的最优点。

总结

本文主要介绍了本人开发的一个用于遗传算法做优化计算的Python框架,框架内置了遗传算法中常用的组件,包括不同编码方式的个体,种群,以及遗传算子等。同时框架还提供了自定义遗传算子和分析插件的接口,能够方便快速搭建遗传算法流程并用于算法测试。

目前框架仅仅处于初步阶段,后续会在自己使用的过程中逐步完善更多的内置算子,是框架更加通用。本文中的两个优化例子均能在GitHub上找到源码(https://github.com/PytLab/gaft/tree/master/examples)

目前的计划:1. 添加更多的内置算子; 2. 给内置算子和组件添加C++ backend; 3. 并行化

参考

  • 《智能优化算法及其MATLAB实例》
  • 《MATLAB最优化计算》 

作者:佚名

来源:51CTO

时间: 2024-10-28 12:48:33

GAFT:一个使用Python实现的遗传算法框架的相关文章

ShutIt:一个基于Python的shell自动化框架

译者注:本文通过实例简单介绍了ShutIt这个基于Python的自动化框架的使用方法.除了pexpect,我们又多了这个选择.以下是译文. ShutIt是一个易于使用的基于shell的自动化框架.它对基于python的expect库(pexpect)进行了包装.你可以把它看作是"没有痛点的expect".它可以通过pip进行安装. Hello World 让我们从最简单的例子开始吧.创建一个名为example.py的文件: import shutit      session = sh

Python实现简单状态框架的方法

 这篇文章主要介绍了Python实现简单状态框架的方法,涉及Python状态框架的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了Python实现简单状态框架的方法.分享给大家供大家参考.具体分析如下: 这里使用Python实现一个简单的状态框架,代码需要在python3.2环境下运行   代码如下: from time import sleep from random import randint, shuffle class StateMachine(object

解读Python的web.py框架下的application.py模块

  这篇文章主要介绍了Python的web.py框架下的application.py模块,作者深入分析了web.py的源码,需要的朋友可以参考下 本文主要分析的是web.py库的application.py这个模块中的代码.总的来说,这个模块主要实现了WSGI兼容的接口,以便应用程序能够被WSGI应用服务器调用.WSGI是Web Server Gateway Interface的缩写,具体细节可以查看WSGI的WIKI页面 接口的使用 使用web.py自带的HTTP Server 下面这个例子来

使用Python的web.py框架实现类似Django的ORM查询的教程

  这篇文章主要介绍了使用Python的web.py框架实现类似Django的ORM查询的教程,集成的ORM操作数据库向来是Python最强大的功能之一,本文则探讨如何在web.py框架上实现,需要的朋友可以参考下 Django中的对象查询 Django框架自带了ORM,实现了一些比较强大而且方便的查询功能,这些功能和表无关.比如下面这个例子: ? 1 2 3 4 5 6 7 class Question(models.Model): question_text = models.CharFie

Python中编写ORM框架的入门指引

  这篇文章主要介绍了Python中编写ORM框架的入门指引,示例代码基于Python2.x版本,需要的朋友可以参考下 有了db模块,操作数据库直接写SQL就很方便.但是,我们还缺少ORM.如果有了ORM,就可以用类似这样的语句获取User对象: ? 1 user = User.get('123') 而不是写SQL然后再转换成User对象: ? 1 2 u = db.select_one('select * from users where id=?', '123') user = User(*

浅谈Python Web的五大框架

说到Web Framework,Ruby的世界Rails一统江湖,而Python则是一个百花齐放的世界,各种micro-framework.framework不可胜数,不完全列表见: http://wiki.python.org/moin/WebFrameworks. 虽然另一大脚本语言PHP也有不少框架,但远没有Python这么夸张,也正是因为Python Web Framework(Python Web开发框架,以下简称Python框架)太多,所以在Python社区总有关于Python框架孰

SQLObject v1.1发布 Python数据库对象映射框架

SQLObject 1.1.0 发布,SQLObject 是一个流行的Python 数据库对象映射框架,映射的规则就是表->类.字段->属性. 过提供用于操作数据库表的类和对象,对象关系映射工具有助于提高生产率.Python 最好的对象关系映射工具是 SQLObject -- 一个开放源码项目,它几乎完成编程数据库所需的所有操作.本文介绍 SQLObject 及其功能.阅读本文后,您将能够不编写任何 SQL 代码而连接 Python 与数据库. 当面向对象编程范例满足大多数数据库的关系范例时,

Python下的twisted框架入门指引_python

什么是twisted? twisted是一个用python语言写的事件驱动的网络框架,他支持很多种协议,包括UDP,TCP,TLS和其他应用层协议,比如HTTP,SMTP,NNTM,IRC,XMPP/Jabber. 非常好的一点是twisted实现和很多应用层的协议,开发人员可以直接只用这些协议的实现.其实要修改Twisted的SSH服务器端实现非常简单.很多时候,开发人员需要实现protocol类. 一个Twisted程序由reactor发起的主循环和一些回调函数组成.当事件发生了,比如一个c

安装Python的web.py框架并从hello world开始编程_python

最近有一个小的web项目,想用喜爱都python,但是想到之前接触过都django我感觉一阵不寒而栗,为什么?Django的配置太过复杂,而且小项目不太适合MVC的开发模式,所以我将目光转向了web.py这个小型web框架,并且真正让我动心都是其官方网站上都一句话:"Django lets you write web apps in Django. TurboGears lets you write web apps in TurboGears. Web.py lets you write we