使用 MPI for Python 并行化遗传算法
前言
本文中作者使用MPI的Python接口mpi4py来将自己的遗传算法框架GAFT进行多进程并行加速。并对加速效果进行了简单测试。
项目链接:
正文
我们在用遗传算法优化目标函数的时候,函数通常都是高维函数,其导数一般比较难求取。这样我们的适应度函数计算通常都是比较费时的计算。
例如在使用遗传算法寻找最优结构时候通常需要调用量化软件进行第一性原理计算结构的total energy,这是非常费时的过程; 例如我们优化力场参数的时候,以力场计算出的能量同基准能量之前的误差作为适应度,也需要调用相应的力场程序获取总能量来求取,同样这个过程也是相对耗时的。
这就会导致一个问题,当我们的种群比较大的时候,我们需要利用适应度信息来产生下一代种群,这时候每一代繁殖的过程将会很耗时。但有幸的是,种群的选择交叉变异过程对于种群中的个体都是相互独立的过程,我们可以将这一部分进行并行处理来加速遗传算法的迭代。
使用mpi4py
由于实验室的集群都是MPI环境,我还是选择使用MPI接口来将代码并行化,这里我还是用了MPI接口的Python版本mpi4py来将代码并行化。关于mpi4py的使用,我之前写过一篇博客专门做了介绍,可以参见《Python多进程并行编程实践-mpi4py的使用》
将mpi4py的接口进一步封装
为了能让mpi的接口在GAFT中更方便的调用,我决定将mpi4py针对遗传算法中需要用的地方进行进一步封装,为此我单独写了个MPIUtil类, 详细代码参见gaft/mpiutil.py。
封装通信子常用的接口
例如进程同步, 获取rank,进程数,判断是否为主进程等。
Python
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
class MPIUtil(object):
def __init__(self):
logger_name = 'gaft.{}'.format(self.__class__.__name__)
self._logger = logging.getLogger(logger_name)
# Wrapper for common MPI interfaces.
def barrier(self):
if MPI_INSTALLED:
mpi_comm = MPI.COMM_WORLD
mpi_comm.barrier()
@property
def rank(self):
if MPI_INSTALLED:
mpi_comm = MPI.COMM_WORLD
return mpi_comm.Get_rank()
else:
return 0
@property
def size(self):
if MPI_INSTALLED:
mpi_comm = MPI.COMM_WORLD
return mpi_comm.Get_size()
else:
return 1
@property
def is_master(self):
return self.rank == 0
|
组内集合通信接口
由于本次并行化的任务是在种群繁衍时候进行的,因此我需要将上一代种群进行划分,划分成多个子部分,然后在每个进程中对划分好的子部分进行选择交叉变异等遗传操作。在最后将每个字部分得到的子种群进行收集合并。为此写了几个划分和收集的接口:
Python
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
def split_seq(self, sequence):
'''
Split the sequence according to rank and processor number.
'''
starts = [i for i in range(0, len(sequence), len(sequence)//self.size)]
ends = starts[1: ] + [len(sequence)]
start, end = list(zip(starts, ends))[self.rank]
return sequence[start: end]
def split_size(self, size):
'''
Split a size number(int) to sub-size number.
'''
if size < self.size:
warn_msg = ('Splitting size({}) is smaller than process ' +
'number({}), more processor would be ' +
'superflous').format(size, self.size)
self._logger.warning(warn_msg)
splited_sizes = [1]*size + [0]*(self.size - size)
elif size % self.size != 0:
residual = size % self.size
splited_sizes = [size // self.size]*self.size
for i in range(residual):
splited_sizes[i] += 1
else:
splited_sizes = [size // self.size]*self.size
return splited_sizes[self.rank]
def merge_seq(self, seq):
'''
Gather data in sub-process to root process.
'''
if self.size == 1:
return seq
mpi_comm = MPI.COMM_WORLD
merged_seq= mpi_comm.allgather(seq)
return list(chain(*merged_seq))
|
用于限制程序在主进程执行的装饰器
有些函数例如日志输出,数据收集的函数,我只希望在主进程执行,为了方便,写了个装饰器来限制函数在主进程中执行:
Python
|
1
2
3
4
5
6
7
8
9
10
11
|
def master_only(func):
'''
Decorator to limit a function to be called
only in master process in MPI env.
'''
@wraps(func)
def _call_in_master_proc(*args, **kwargs):
if mpi.is_master:
return func(*args, **kwargs)
return _call_in_master_proc
|
在遗传算法主循环中添加并行
主要在种群繁衍中对种群针对进程数进行划分然后并行进行遗传操作并合并子种群完成并行,代码改动很少。详见:https://github.com/PytLab/gaft/blob/master/gaft/engine.py#L67
Python
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
# Enter evolution iteration.
for g in range(ng):
# Scatter jobs to all processes.
local_indvs = []
local_size = mpi.split_size(self.population.size // 2)
# Fill the new population.
for _ in range(local_size):
# Select father and mother.
parents = self.selection.select(self.population, fitness=self.fitness)
# Crossover.
children = self.crossover.cross(*parents)
# Mutation.
children = [self.mutation.mutate(child) for child in children]
# Collect children.
local_indvs.extend(children)
# Gather individuals from all processes.
indvs = mpi.merge_seq(local_indvs)
# The next generation.
self.population.individuals = indvs
|
测试加速效果
测试一维搜索
下面我针对项目中的一维优化的例子进行并行加速测试来看看加速的效果。例子代码在/examples/ex01/
由于自己本子核心数量有限,我把gaft安装在实验室集群上使用MPI利用多核心进行并行计算一维优化,种群大小为50,代数为100,针对不同核心数可以得到不同的优化时间和加速比。可视化如下图:

核心数与优化时间的关系:

核心数与加速比:

测试力场优化
这里我对自己要研究的对象进行加速测试,这部分代码并未开源,针对每个个体的适应度计算都需要调用其他的计算程序,因此此过程相比直接有函数表达式的目标函数计算要耗时很多。厦门chache
同样,我针对不同核心数看看使用MPI在集群上加速的效果:

核心数与优化时间的关系:

核心数与加速比:

可见针对上述两个案例,MPI对遗传算法的加速还是比较理想的,程序可以扔到集群上飞起啦~~~
总结
本文主要总结了使用mpi4py对遗传算法进行并行化的方法和过程,并对加速效果进行了测试,可见MPI对于遗传算法框架GAFT的加速效果还是较为理想的。带有MPI并行的遗传算法框架目前也已更新并上传至GitHub(https://github.com/PytLab/gaft) 欢迎围观[]~( ̄▽ ̄)~*
使用 MPI for Python 并行化遗传算法的更多相关文章
- python的遗传算法--Hello World入门篇
本系列文章代码取材于书籍<Genetic Algorithms with Python>,本人是在校电气专业的研究生,立志从事于Python相关的代码工作,具体什么方向还有待深究. 众所周 ...
- 遗传算法中几种不同选择算子及Python实现
前言 本文对遗传算法中的几种选择策略进行了总结, 其中包括: Proportionate Roulette Wheel Selection Linear Ranking Selection Expon ...
- 大数据并行计算利器之MPI/OpenMP
大数据集群计算利器之MPI/OpenMP ---以连通域标记算法并行化为例 1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出 ...
- 70个Python练手项目列表(都有完整教程)
前言: 不管学习那门语言都希望能做出实际的东西来,这个实际的东西当然就是项目啦,不用多说大家都知道学编程语言一定要做项目才行. 这里整理了70个Python实战项目列表,都有完整且详细的教程,你可以从 ...
- 再一波Python实战项目列表
前言: 近几年Python可谓是大热啊,很多人都纷纷投入Python的学习中,以前我们实验楼总结过多篇Python实战项目列表,不但有用还有趣,最主要的是咱们实验楼不但有详细的开发教程,更有在线开发环 ...
- 别再说找不到Python练手项目了,这80个拿去过冬
开头真的很重要!!!一个吻,一部小说,一篇文章......好的开头就像一个漂亮女孩的问候,问完了,你还期待着她接下来会对你说些什么甜蜜的话呢. 真可惜!我不是漂亮女孩,我的这个开头也不好.但开头不好, ...
- 【Python秘籍】十进制整数与二进制数的转换
最近在用Python写遗传算法时,发现需要将十进制的整数转换成二进制数,那么怎么来转换呢?当然如果你学过进制转换的有关计算方法,你可以手动编写一些函数来实现,不过总体来说还是比较麻烦的,这里介绍Pyt ...
- 实验楼Python项目
整理几个实验楼小项目,有免费的也有会员的,会员的可以参考他们的实验报告. 直接去实验楼这个网站,粘贴上就能搜到. 免费专区: Kmeans聚类算法评估足球比赛 Python实现3D建模工具 K-近邻算 ...
- Python项目列表
70个Python项目列表: 1.[Python 图片转字符画]2.[200行Python代码实现2048]3.[Python3 实现火车票查询工具]4.[高德API+Python解决租房问题 ]5. ...
随机推荐
- python - 流程控制基础习题
#打印1 到100 的和** i = 0 s = 0 while i <100: i += 1 s += i print(s) print('1+2+,,100=',s) #打印字符A~Z fo ...
- 有关dubbo面试的那些事儿
dubbo是什么 dubbo是一个分布式框架,远程服务调用的分布式框架,其核心部分包含: 集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集 ...
- java基础需要掌握的内容
一.Java的基本程序设计结构 二.对象与类 三.继承 四.接口.lambda表达式与内部类 五.异常,断言与日志 六.泛型程序设计 七.集合 八.并发(线程) 九.输入与输出(IO流) 十.网络 十 ...
- 洛谷P1501 [国家集训队]Tree II(LCT)
题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...
- docker故障问题修复
systemctl start docker启动 systemctl restart docker重启 执行 vi /etc/sysconfig/selinux , 把 selinux 属性值改为di ...
- ionic ios 打包 真机测试常见问题
1.ionic 项目在windows下正常打包安卓包时 迁移到mac下打包ios时 不需要复制平台目录platforms即可 不用再mac下去安装各种插件信息 2.ionic 下不能访问api信 ...
- ES6学习之-let 和const命令
let 和const命令 let命令 用来声明变量,类似于var .let声明的变量 只在let命令所在的代码块内有效. 在for循环里也是如此 每次循环其实都是一个代码块 function fn() ...
- laravel5.5源码笔记(四、路由)
今天这篇博文来探索一下laravel的路由.在第一篇讲laravel入口文件的博文里,我们就提到过laravel的路由是在application对象的初始化阶段,通过provider来加载的.这个路由 ...
- 我的 Delphi 学习之路 —— Delphi 的安装
标题:我的 Delphi 学习之路 -- Delphi 的安装 作者:断桥烟雨旧人伤 1. Delphi 版本的选择 Delphi 版本众多,我该选择哪一个,这确实是个问题,自从 Borland 公司 ...
- CentOS6安装各种大数据软件 第一章:各个软件版本介绍
相关文章链接 CentOS6安装各种大数据软件 第一章:各个软件版本介绍 CentOS6安装各种大数据软件 第二章:Linux各个软件启动命令 CentOS6安装各种大数据软件 第三章:Linux基础 ...