В настоящее время я использую алгоритм дифференциальной эволюции в python, и все замечательно при работе в меньших измерениях, однако, когда я начинаю увеличивать размеры пространства поиска, время, затрачиваемое на запуск алгоритма, увеличивается в геометрической прогрессии. После небольшого профилирования я обнаружил, что большую часть времени проводит в функции мутации, которая выглядит следующим образом:
def _mutate(self, candidate: int) -> np.ndarray:
# r0, r1, & r2 are np.ndarrays of shape (dimension,)
r0, r1, r2 = self._select_samples(candidate)
# mutant is an np.ndarray of shape (dimension,)
mutant = np.copy(self.population[candidate])
j_rand = int(np.random.uniform() * self.dimensions)
for j in range(self.dimensions):
if np.random.uniform() < self.cr or j == j_rand:
# bound the mutant to the search space
mutant[j] = np.clip(r0[j] + self.F * (r1[j] - r2[j]),
self.range[0], self.range[1])
Теперь для population size
из 100
и dimension
из20
, общее время, необходимое для запуска алгоритма, составляет ~ 40 секунд, ~ 20 из этих секунд тратятся на mutate
.
Теперь я остановился на этой функции, оптимизировав ее на ~ 3 секунды по сравнению с предыдущей версией.
def _mutate_2(self, candidate: int) -> np.ndarray:
r0, r1, r2 = self._select_samples(candidate)
mutant = np.copy(self.population[candidate])
j_rand = np.random.randint(self.dimensions)
cross_indxs = np.flatnonzero(np.random.rand(self.dimensions) < self.cr)
cross_indxs = np.append(
cross_indxs, [j_rand]) if j_rand not in cross_indxs else cross_indxs
for j in cross_indxs:
mutant[j] = np.clip(r0[j] + self.F * (r1[j] - r2[j]), self.range[0],
self.range[1])
return mutant
Но, очевидно, этого еще недостаточно. Мне интересно, может ли быть хитрость в numpy
, чтобы удалить цикл for, применяя поэлементные операции к r0, r1, r2, and mutant
. Суть в том, что можно использовать только элементы, индексы которых cross_indxs
.