предисловие
В этой статье автор использует интерфейс MPI Python mpi4py для ускорения своей собственной структуры генетического алгоритма GAFT для параллельного ускорения нескольких процессов. И простой тест эффекта ускорения.
Ссылка на проект:
- GitHub: github.com/PytLab/gaft
- PyPI: pypi.python.org/pypi/gaft
текст
Когда мы используем генетический алгоритм для оптимизации целевой функции, функция обычно является функцией большой размерности, и ее производную обычно трудно получить. Таким образом, расчет нашей фитнес-функции обычно занимает много времени.
Например, при использовании генетического алгоритма для поиска оптимальной структуры обычно необходимо вызывать количественное программное обеспечение для расчета полной энергии структуры из первого принципа, что является очень трудоемким процессом; например, когда мы оптимизируем параметры силового поля, энергия, рассчитанная силовым полем, такая же, как ошибка до того, как эталонная энергия используется в качестве пригодности, и также необходимо вызвать соответствующую программу силового поля, чтобы получить полную энергию для получения, и этот процесс также занимает относительно много времени.
Это приводит к проблеме, когда нашиотносительно большое населениеВ настоящее время нам необходимо использовать информацию о пригодности для создания следующего поколения популяции, и процесс воспроизводства каждого поколения будет занимать много времени. Но, к счастью, процесс отбора, скрещивания и мутации популяции касается отдельных особей популяции.Независимыймы можем распараллелить эту часть, чтобы ускорить итерацию генетического алгоритма.
использовать mpi4py
Поскольку все кластеры в лаборатории являются средами MPI, я по-прежнему предпочитаю использовать интерфейс MPI для распараллеливания кода Здесь я по-прежнему использую Python-версию интерфейса MPI, mpi4py, для распараллеливания кода. Что касается использования mpi4py, я написал блог, чтобы представить его, вы можете обратиться к«Практика многопроцессорного параллельного программирования на Python — использование mpi4py»
Далее инкапсулируйте интерфейс mpi4py
Для того, чтобы интерфейс mpi было удобнее вызывать в GAFT, я решил дополнительно инкапсулировать mpi4py для тех мест, которые нужно использовать в генетическом алгоритме, для этого я написал отдельныйMPIUtil
класс, см. подробный кодgaft/mpiutil.py.
Инкапсулирует часто используемые интерфейсы коммуникаторов
Например, синхронизация процессов, получение ранга, количества процессов, оценка того, является ли он основным процессом и т. д.
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
Интерфейс коллективной внутригрупповой связи
Поскольку задача этого распараллеливания выполняется при размножении популяции, мне нужно разделить популяцию предыдущего поколения на несколько подчастей, а затем выполнить генетические операции, такие как отбор, скрещивание и мутация над разделенными подчастями в каждом процессе. . . . В конце субпопуляции, полученные из каждой части слова, собираются и объединяются. Для этого написано несколько интерфейсов для разделения и сбора:
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))
Декоратор, используемый для ограничения выполнения программы в основном процессе.
Некоторые функции, такие как функции вывода журнала и сбора данных, я хочу выполнять только в основном процессе.Для удобства я написал декоратор, ограничивающий выполнение функций в основном процессе:
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
Добавление параллелизма в основной цикл генетического алгоритма
В основном при воспроизводстве популяции популяция делится по количеству процессов, затем параллельно выполняется генетическая операция, а субпопуляция объединяется для завершения параллели, а изменений кода немного. Видеть:GitHub.com/pgirllab/GA ft…
# 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. Различное время оптимизации и Коэффициенты ускорения могут быть получены для разных номеров ядер. Визуализация выглядит следующим образом:
количество ядер | Время оптимизации (с) | Коэффициент ускорения |
---|---|---|
1 | 1.473 | 1.0 |
2 | 0.877 | 1.68 |
3 | 0.657 | 2.24 |
4 | 0.533 | 2.76 |
5 | 0.467 | 3.15 |
6 | 0.540 | 2.73 |
7 | 0.431 | 3.42 |
8 | 0.382 | 3.86 |
9 | 0.355 | 4.15 |
10 | 0.317 | 4.65 |
Зависимость между количеством ядер и временем оптимизации:
Количество ядер и ускорение:
Оптимизация испытательного силового поля
Здесь я провожу ускоренный тест на объекте, который хочу изучить.Эта часть кода не является открытым исходным кодом.Расчет пригодности для каждого человека требует вызова других программ расчета.Поэтому этот процесс требует большего расчета, чем расчет целевой функции напрямую с функциональными выражениями.
Опять же, я смотрю на ускорение в кластере с использованием MPI для разного количества ядер:
количество ядер | Время оптимизации (с) | Время оптимизации | Коэффициент ускорения |
---|---|---|---|
1 | 2.29e04 | 6 h 21 min | 1.0 |
2 | 1.94e04 | 5 h 23 min | 1.18 |
4 | 1.62e04 | 4 h 30 min | 1.41 |
6 | 1.35e04 | 3 h 45 min | 1.69 |
12 | 8.73e03 | 2 h 25 min | 2.62 |
Зависимость между количеством ядер и временем оптимизации:
Количество ядер и ускорение:
Видно, что для двух вышеперечисленных случаев ускорение генетического алгоритма по MPI все еще относительно идеально, и программу можно закинуть на кластер и летать~~~
Суммировать
Эта статья в основном суммирует метод и процесс использования mpi4py для распараллеливания генетического алгоритма и проверяет эффект ускорения.Можно видеть, что эффект ускорения MPI на структуру генетического алгоритма GAFT все еще относительно идеален. Платформа генетического алгоритма с параллелизмом MPI теперь также была обновлена и загружена на GitHub (github.com/PytLab/gaft) Добро пожаловать на просмотр[]~( ̄▽ ̄)~*