前言

本文中作者使用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 并行化遗传算法的更多相关文章

  1. python的遗传算法--Hello World入门篇

    本系列文章代码取材于书籍<Genetic Algorithms with Python>,本人是在校电气专业的研究生,立志从事于Python相关的代码工作,具体什么方向还有待深究. 众所周 ...

  2. 遗传算法中几种不同选择算子及Python实现

    前言 本文对遗传算法中的几种选择策略进行了总结, 其中包括: Proportionate Roulette Wheel Selection Linear Ranking Selection Expon ...

  3. 大数据并行计算利器之MPI/OpenMP

    大数据集群计算利器之MPI/OpenMP ---以连通域标记算法并行化为例 1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出 ...

  4. 70个Python练手项目列表(都有完整教程)

    前言: 不管学习那门语言都希望能做出实际的东西来,这个实际的东西当然就是项目啦,不用多说大家都知道学编程语言一定要做项目才行. 这里整理了70个Python实战项目列表,都有完整且详细的教程,你可以从 ...

  5. 再一波Python实战项目列表

    前言: 近几年Python可谓是大热啊,很多人都纷纷投入Python的学习中,以前我们实验楼总结过多篇Python实战项目列表,不但有用还有趣,最主要的是咱们实验楼不但有详细的开发教程,更有在线开发环 ...

  6. 别再说找不到Python练手项目了,这80个拿去过冬

    开头真的很重要!!!一个吻,一部小说,一篇文章......好的开头就像一个漂亮女孩的问候,问完了,你还期待着她接下来会对你说些什么甜蜜的话呢. 真可惜!我不是漂亮女孩,我的这个开头也不好.但开头不好, ...

  7. 【Python秘籍】十进制整数与二进制数的转换

    最近在用Python写遗传算法时,发现需要将十进制的整数转换成二进制数,那么怎么来转换呢?当然如果你学过进制转换的有关计算方法,你可以手动编写一些函数来实现,不过总体来说还是比较麻烦的,这里介绍Pyt ...

  8. 实验楼Python项目

    整理几个实验楼小项目,有免费的也有会员的,会员的可以参考他们的实验报告. 直接去实验楼这个网站,粘贴上就能搜到. 免费专区: Kmeans聚类算法评估足球比赛 Python实现3D建模工具 K-近邻算 ...

  9. Python项目列表

    70个Python项目列表: 1.[Python 图片转字符画]2.[200行Python代码实现2048]3.[Python3 实现火车票查询工具]4.[高德API+Python解决租房问题 ]5. ...

随机推荐

  1. Java中的集合框架-Collection(二)

    上一篇<Java中的集合框架-Collection(一)>把Java集合框架中的Collection与List及其常用实现类的功能大致记录了一下,本篇接着记录Collection的另一个子 ...

  2. MessageBox.Show用法

    private void button3_Click(object sender, EventArgs e) { MessageBox.Show("  1  个参数 "); } ~ ...

  3. Autolayout中Hugging和Compression使用注意

    前言 本文主要侧重Autolayout使用过程中,通过代码和SB添加含有intrinsicSize属性控件约束的一些细节. 来自我的博客,欢迎访问:To Be Independent. Hugging ...

  4. C# 解压gzip文件(.tgz)

    1.引用 SharpCompress.dll 2.代码 using System;using System.IO;using System.Text;using SharpCompress.Reade ...

  5. 一道hive面试题(窗口函数)

    表student中的数据格式如下: name month degree s1 201801 As1 201802 As1 201803 Cs1 201804 As1 201805 As1 201806 ...

  6. SDR软件无线电知识要点(三)EVM

    SDR软件无线电知识要点(三)EVM 信号质量如何评估 Noise Figure (NF) or sensitivity and Error Vector Magnitude (EVM) provid ...

  7. 20155209实验二《Java面向对象程序设计》

    20155209实验二<Java面向对象程序设计> 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计 ...

  8. Deepin Linux下的Metasploit安装及优化

    前言 本文不限于Deepin Linux系统,类似的在ubuntu debian xubuntu等血统类似的Linux发行版中都可以使用这里方法来安装原生的metasploit 配置Kali Linu ...

  9. WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书

    原文:WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书 最近项目中使用弹出控件Popup,发现弹出框的对齐方式在不同的系统中存在不同(Popup在win10上是 ...

  10. oracle-11g-64位安装和plaql

    1.oracle卸载 如果是新装,请跳过此步骤 卸载步骤: 1.停止所有服务 2.用自带删除软件,删除所有目录 3.打开注册表: -->运行regedit,删除HKEY_LOCAL_MACHIN ...