differential_evolution#
- scipy.optimize.differential_evolution(функция, границы, args=(), стратегия='best1bin', maxiter=1000, popsize=15, tol=0.01, мутация=(0.5, 1), рекомбинация=0.7, rng=None, callback=None, disp=False, полировка=True, init='latinhypercube', atol=0, обновление='immediate', workers=1, ограничения=(), x0=None, *, integrality=None, векторизованный=False, seed=None)[источник]#
Находит глобальный минимум многомерной функции.
Метод дифференциальной эволюции [1] имеет стохастическую природу. Он не использует градиентные методы для поиска минимума и может исследовать большие области пространства кандидатов, но часто требует большего количества вычислений функции, чем традиционные градиентные методы.
Алгоритм принадлежит Шторну и Прайсу [2].
- Параметры:
- функцияcallable
Целевая функция для минимизации. Должна быть в форме
f(x, *args), гдеxявляется аргументом в виде одномерного массива иargsявляется кортежем любых дополнительных фиксированных параметров, необходимых для полного определения функции. Количество параметров, N, равноlen(x).- границыпоследовательность или
Bounds Границы для переменных. Есть два способа указать границы:
Экземпляр
Boundsкласс.(min, max)пары для каждого элемента вx, определяя конечные нижнюю и верхнюю границы для оптимизируемого аргумента функция.
Общее количество границ используется для определения числа параметров, N. Если есть параметры с равными границами, общее количество свободных параметров равно
N - N_equal.- argsкортеж, необязательный
Любые дополнительные фиксированные параметры, необходимые для полного определения целевой функции.
- стратегия{str, callable}, optional
Стратегия дифференциальной эволюции для использования. Должна быть одной из:
‘best1bin’
‘best1exp’
‘rand1bin’
‘rand1exp’
'rand2bin'
‘rand2exp’
‘randtobest1bin’
‘randtobest1exp’
'currenttobest1bin'
‘currenttobest1exp’
'best2exp'
'best2bin'
По умолчанию используется 'best1bin'. Стратегии, которые могут быть реализованы, описаны в разделе 'Примечания'. Альтернативно стратегия дифференциальной эволюции может быть настроена путем предоставления вызываемого объекта, который строит пробный вектор. Вызываемый объект должен иметь форму
strategy(candidate: int, population: np.ndarray, rng=None), гдеcandidateявляется целым числом, указывающим, какой элемент популяции эволюционирует,populationявляется массивом формы(S, N)содержащий всех членов популяции (где S - общий размер популяции), иrngиспользуется ли генератор случайных чисел внутри решателя.candidateбудет в диапазоне[0, S).strategyдолжен возвращать пробный вектор с формой(N,). Пригодность этого пробного вектора сравнивается с пригодностьюpopulation[candidate].Изменено в версии 1.12.0: Настройка стратегии эволюции через вызываемый объект.
- maxiterint, необязательный
Максимальное количество поколений, в течение которых эволюционирует вся популяция. Максимальное количество вычислений функции (без полировки) составляет:
(maxiter + 1) * popsize * (N - N_equal)- popsizeint, необязательный
Множитель для установки общего размера популяции. Популяция имеет
popsize * (N - N_equal)отдельных особей. Этот ключевой параметр переопределяется, если начальная популяция предоставляется через init ключевое слово. При использованииinit='sobol'размер популяции вычисляется как следующая степень 2 послеpopsize * (N - N_equal).- tolfloat, опционально
Относительный допуск для сходимости, решение останавливается, когда
np.std(population_energies) <= atol + tol * np.abs(np.mean(population_energies)), где и atol и tol являются абсолютной и относительной погрешностью соответственно.- мутацияfloat или tuple(float, float), опционально
Константа мутации. В литературе это также известно как дифференциальный вес, обозначаемый \(F\). Если указано как float, должно быть в диапазоне [0, 2). Если указано как кортеж
(min, max)применяется дизеринг. Дизеринг случайным образом изменяет константу мутации от поколения к поколению. Константа мутации для этого поколения берётся изU[min, max). Дизеринг может значительно ускорить сходимость. Увеличение константы мутации увеличивает радиус поиска, но замедлит сходимость.- рекомбинацияfloat, опционально
Константа рекомбинации должна быть в диапазоне [0, 1]. В литературе это также известно как вероятность кроссовера, обозначаемая как CR. Увеличение этого значения позволяет большему числу мутантов перейти в следующее поколение, но с риском стабильности популяции.
- rng{None, int,
numpy.random.Generator, опционально Если rng передается по ключевому слову, типы, отличные от
numpy.random.Generatorпередаются вnumpy.random.default_rngдля создания экземпляраGenerator. Если rng уже являетсяGeneratorэкземпляр, то предоставленный экземпляр используется. Укажите rng для повторяемого поведения функции.Если этот аргумент передаётся по позиции или seed передается по ключевому слову, устаревшее поведение для аргумента seed применяется:
Если seed равно None (или
numpy.random),numpy.random.RandomStateиспользуется синглтон.Если seed является int, новый
RandomStateиспользуется экземпляр, инициализированный с seed.Если seed уже является
GeneratorилиRandomStateэкземпляр, тогда этот экземпляр используется.
Изменено в версии 1.15.0: В рамках SPEC-007 переход от использования
numpy.random.RandomStatetonumpy.random.Generator, этот ключевое слово было изменено с seed to rng. В переходный период оба ключевых слова будут продолжать работать, хотя только одно может быть указано за раз. После переходного периода вызовы функций, использующие seed ключевое слово будет выдавать предупреждения. Поведение обоих seed и rng описаны выше, но только rng ключевое слово должно использоваться в новом коде.- dispbool, необязательно
Выводит вычисленное функция на каждой итерации.
- callbackвызываемый объект, необязательный
Вызываемый объект, вызываемый после каждой итерации. Имеет сигнатуру:
callback(intermediate_result: OptimizeResult)
где
intermediate_resultявляется ключевым параметром, содержащимOptimizeResultс атрибутамиxиfun, лучшее найденное на данный момент решение и целевая функция. Обратите внимание, что имя параметра должно бытьintermediate_resultдля callback, чтобы передатьOptimizeResult.Обратный вызов также поддерживает сигнатуру вида:
callback(x, convergence: float=val)
valпредставляет дробное значение сходимости популяции. Когдаvalбольше чем1.0, функция останавливается.Интроспекция используется для определения того, какая из сигнатур вызывается.
Глобальная минимизация остановится, если обратный вызов вызовет
StopIterationили возвращаетTrue; любая полировка все еще выполняется.Изменено в версии 1.12.0: callback принимает
intermediate_resultключевое слово.- полировкаbool, необязательно
Если True (по умолчанию), то
scipy.optimize.minimizeс L-BFGS-B метод используется для полировки лучшего члена популяции в конце, что может немного улучшить минимизацию. Если изучается задача с ограничениями, то trust-constr метод используется вместо этого. Для больших задач со многими ограничениями полировка может занимать много времени из-за вычислений матрицы Якоби.Изменено в версии 1.15.0: Если workers указан, то вызываемый объект, подобный отображению, который оборачивает функция предоставляется
minimizeвместо использования функция напрямую. Это позволяет вызывающей стороне контролировать, как и где выполняются вызовы.- initstr или array-like, необязательный
Укажите, какой тип инициализации популяции выполняется. Должен быть одним из:
'latinhypercube'
‘sobol’
'halton'
‘random’
массив, задающий начальную популяцию. Массив должен иметь форму
(S, N), где S - общий размер популяции, а N - количество параметров.
init обрезается до границы перед использованием.
По умолчанию используется 'latinhypercube'. Латинский гиперкуб пытается максимизировать покрытие доступного пространства параметров.
‘sobol’ и ‘halton’ являются превосходными альтернативами и максимизируют пространство параметров еще больше. ‘sobol’ обеспечит начальный размер популяции, который рассчитывается как следующая степень двойки после
popsize * (N - N_equal). ‘halton’ не имеет требований, но немного менее эффективен. См.scipy.stats.qmcдля получения дополнительной информации.‘random’ инициализирует популяцию случайным образом — это имеет недостаток, заключающийся в том, что может происходить кластеризация, препятствующая покрытию всего пространства параметров. Использование массива для указания популяции может быть применено, например, для создания плотной группы начальных приближений в области, где известно существование решения, тем самым сокращая время сходимости.
- atolfloat, опционально
Абсолютная погрешность сходимости, решение останавливается, когда
np.std(pop) <= atol + tol * np.abs(np.mean(population_energies)), где и atol и tol являются абсолютной и относительной погрешностью соответственно.- обновление{‘immediate’, ‘deferred’}, опционально
Если
'immediate', лучший вектор решения непрерывно обновляется в пределах одного поколения [4]. Это может привести к более быстрой сходимости, так как пробные векторы могут использовать преимущества непрерывных улучшений в лучшем решении. С'deferred', лучший вектор решения обновляется один раз за поколение. Только'deferred'совместим с параллелизацией или векторизацией, и workers и векторизованный ключевые слова могут переопределить эту опцию.Добавлено в версии 1.2.0.
- workersint или вызываемый объект, подобный отображению, необязательный
Если workers является целым числом, популяция подразделяется на workers разделы и вычисляются параллельно (использует
multiprocessing.Pool). Укажите -1 для использования всех доступных ядер CPU. Альтернативно укажите вызываемый объект, подобный map, такой как multiprocessing.Pool.map для параллельной оценки популяции. Эта оценка выполняется какworkers(func, iterable). Эта опция переопределит обновление ключевое слово дляupdating='deferred'ifworkers != 1. Эта опция переопределяет векторизованный ключевое слово ifworkers != 1. Требует, чтобы функция быть сериализуемым через pickle.Добавлено в версии 1.2.0.
- ограничения{NonLinearConstraint, LinearConstraint, Bounds}
Ограничения для решателя, помимо тех, что применяются границы kwd. Использует подход Лампинена [5].
Добавлено в версии 1.4.0.
- x0None или array-like, опционально
Предоставляет начальное предположение для минимизации. После инициализации популяции этот вектор заменяет первого (лучшего) члена. Эта замена выполняется даже если init задана начальная популяция.
x0.shape == (N,).Добавлено в версии 1.7.0.
- integrality1-D массив, необязательный
Для каждой переменной решения логическое значение, указывающее, ограничена ли переменная решения целыми значениями. Массив транслируется в
(N,). Если какие-либо переменные решения ограничены целочисленными значениями, они не будут изменяться в процессе полировки. Используются только целые значения, лежащие между нижней и верхней границами. Если нет целых значений, лежащих между границами, то ValueError вызывается исключение.Добавлено в версии 1.9.0.
- векторизованныйbool, необязательно
Если
vectorized is True, функция отправляется x массив сx.shape == (N, S), и ожидается, что вернёт массив формы(S,), где S количество векторов решений, которые необходимо вычислить. Если применяются ограничения, каждая из функций, используемых для построения Ограничение объект должен принимать x массив сx.shape == (N, S), и вернуть массив формы(M, S), где M — это количество компонентов ограничений. Эта опция является альтернативой параллелизации, предлагаемой workers, и может помочь в скорости оптимизации за счет уменьшения накладных расходов интерпретатора от множественных вызовов функций. Этот ключевой аргумент игнорируется, еслиworkers != 1. Эта опция переопределит обновление ключевое слово дляupdating='deferred'. См. раздел примечаний для дальнейшего обсуждения, когда использовать'vectorized', и когда использовать'workers'.Добавлено в версии 1.9.0.
- Возвращает:
- resOptimizeResult
Результат оптимизации, представленный как
OptimizeResultобъект. Важные атрибуты:xмассив решения,successлогический флаг, указывающий, успешно ли завершился оптимизатор,messageкоторое описывает причину завершения,populationвекторы решений, присутствующие в популяции, иpopulation_energiesзначение целевой функции для каждого элемента вpopulation. См.OptimizeResultдля описания других атрибутов. Если полировка был использован, и полировка дала более низкий минимум, тогда OptimizeResult также содержитjacатрибут. Если окончательное решение не удовлетворяет применённым ограничениямsuccessбудет False.
Примечания
Дифференциальная эволюция — это стохастический популяционный метод, который полезен для задач глобальной оптимизации. На каждом проходе по популяции алгоритм мутирует каждое кандидатное решение, смешивая его с другими кандидатными решениями для создания пробного кандидата. Существует несколько стратегий [3] для создания кандидатов на испытание, которые подходят для одних задач больше, чем для других. Стратегия 'best1bin' является хорошей отправной точкой для многих систем. В этой стратегии случайным образом выбираются два члена популяции. Их разность используется для мутации лучшего члена (где 'best' в 'best1bin' означает лучший). \(x_0\), до сих пор:
\[b' = x_0 + F \cdot (x_{r_0} - x_{r_1})\]где \(F\) является мутация параметр. Затем строится пробный вектор. Начиная со случайно выбранного i-го параметра, пробный вектор последовательно заполняется (по модулю) параметрами из
b'или исходный кандидат. Выбор, использовать лиb'или исходный кандидат создаётся с биномиальным распределением ('bin' в 'best1bin') - генерируется случайное число в [0, 1). Если это число меньше, чем рекомбинация константа, то параметр загружается изb', в противном случае он загружается из исходного кандидата. Финальный параметр всегда загружается изb'. После построения пробного кандидата оценивается его пригодность. Если пробный кандидат лучше исходного, то он занимает его место. Если он также лучше лучшего общего кандидата, он также заменяет его.Другие доступные стратегии описаны в Qiang и Mitchell (2014) [3].
rand1: \(b' = x_{r_0} + F \cdot (x_{r_1} - x_{r_2})\)rand2: \(b' = x_{r_0} + F \cdot (x_{r_1} + x_{r_2} - x_{r_3} - x_{r_4})\)best1: \(b' = x_0 + F \cdot (x_{r_0} - x_{r_1})\)best2: \(b' = x_0 + F \cdot (x_{r_0} + x_{r_1} - x_{r_2} - x_{r_3})\)currenttobest1: \(b' = x_i + F \cdot (x_0 - x_i + x_{r_0} - x_{r_1})\)randtobest1: \(b' = x_{r_0} + F \cdot (x_0 - x_{r_0} + x_{r_1} - x_{r_2})\)
где целые числа \(r_0, r_1, r_2, r_3, r_4\) выбираются случайным образом из интервала [0, NP) с NP где общий размер популяции и исходный кандидат имеет индекс i. Пользователь может полностью настроить генерацию пробных кандидатов, предоставив вызываемый объект в
strategy.Чтобы увеличить шансы нахождения глобального минимума, используйте более высокие popsize значения, с более высокими мутация и (сглаживание), но ниже рекомбинация значения. Это приводит к расширению радиуса поиска, но замедляет сходимость.
По умолчанию лучший вектор решения обновляется непрерывно в течение одной итерации (
updating='immediate'). Это модификация [4] оригинального алгоритма дифференциальной эволюции, что может привести к более быстрой сходимости, поскольку пробные векторы могут немедленно использовать улучшенные решения. Чтобы использовать оригинальное поведение Storn и Price, обновляя лучшее решение один раз за итерацию, установитеupdating='deferred'.'deferred'подход совместим как с параллелизацией, так и с векторизацией ('workers'и'vectorized'ключевые слова). Они могут улучшить скорость минимизации, используя ресурсы компьютера более эффективно.'workers'распределять вычисления по нескольким процессорам. По умолчанию Pythonmultiprocessingмодуль используется, но также возможны другие подходы, такие как интерфейс передачи сообщений (MPI), используемый в кластерах [6] [7]. Накладные расходы от этих подходов (создание новых процессов и т.д.) могут быть значительными, что означает, что вычислительная скорость не обязательно масштабируется с количеством используемых процессоров. Параллелизация лучше всего подходит для вычислительно затратных целевых функций. Если целевая функция менее затратна, то'vectorized'может помочь, вызывая целевую функцию только один раз за итерацию, а не несколько раз для всех членов популяции; накладные расходы интерпретатора уменьшаются.Добавлено в версии 0.15.0.
Ссылки
[1]Дифференциальная эволюция, Википедия, http://en.wikipedia.org/wiki/Differential_evolution
[2]Шторн, Р. и Прайс, К., Дифференциальная эволюция — простой и эффективный эвристический метод глобальной оптимизации в непрерывных пространствах, Journal of Global Optimization, 1997, 11, 341 - 359.
[3] (1,2)Qiang, J., Mitchell, C., A Unified Differential Evolution Algorithm for Global Optimization, 2014, https://www.osti.gov/servlets/purl/1163659
[4] (1,2)Wormington, M., Panaccione, C., Matney, K. M., Bowen, D. K., - Characterization of structures from X-ray scattering data using genetic algorithms, Phil. Trans. R. Soc. Lond. A, 1999, 357, 2827-2848
[5]Lampinen, J., Подход к обработке ограничений для алгоритма дифференциальной эволюции. Труды Конгресса по эволюционным вычислениям 2002 года. CEC’02 (Cat. No. 02TH8600). Том 2. IEEE, 2002.
Примеры
Рассмотрим задачу минимизации функции Розенброка. Эта функция реализована в
rosenвscipy.optimize.>>> import numpy as np >>> from scipy.optimize import rosen, differential_evolution >>> bounds = [(0,2), (0, 2), (0, 2), (0, 2), (0, 2)] >>> result = differential_evolution(rosen, bounds) >>> result.x, result.fun (array([1., 1., 1., 1., 1.]), 1.9216496320061384e-19)
Теперь повторите, но с параллелизацией.
>>> result = differential_evolution(rosen, bounds, updating='deferred', ... workers=2) >>> result.x, result.fun (array([1., 1., 1., 1., 1.]), 1.9216496320061384e-19)
Выполним ограниченную минимизацию.
>>> from scipy.optimize import LinearConstraint, Bounds
Мы добавляем ограничение, что сумма
x[0]иx[1]должно быть меньше или равно 1.9. Это линейное ограничение, которое может быть записано какA @ x <= 1.9, гдеA = array([[1, 1]]). Это может быть закодировано какLinearConstraintэкземпляр:>>> lc = LinearConstraint([[1, 1]], -np.inf, 1.9)
Задать пределы с помощью
Boundsобъект.>>> bounds = Bounds([0., 0.], [2., 2.]) >>> result = differential_evolution(rosen, bounds, constraints=lc, ... rng=1) >>> result.x, result.fun (array([0.96632622, 0.93367155]), 0.0011352416852625719)
Далее найти минимум функции Акклея (https://en.wikipedia.org/wiki/Test_functions_for_optimization).
>>> def ackley(x): ... arg1 = -0.2 * np.sqrt(0.5 * (x[0] ** 2 + x[1] ** 2)) ... arg2 = 0.5 * (np.cos(2. * np.pi * x[0]) + np.cos(2. * np.pi * x[1])) ... return -20. * np.exp(arg1) - np.exp(arg2) + 20. + np.e >>> bounds = [(-5, 5), (-5, 5)] >>> result = differential_evolution(ackley, bounds, rng=1) >>> result.x, result.fun (array([0., 0.]), 4.440892098500626e-16)
Функция Аккли записана векторизованным образом, поэтому
'vectorized'ключевое слово может быть использовано. Обратите внимание на уменьшенное количество вычислений функции.>>> result = differential_evolution( ... ackley, bounds, vectorized=True, updating='deferred', rng=1 ... ) >>> result.x, result.fun (array([0., 0.]), 4.440892098500626e-16)
Следующая пользовательская функция стратегии имитирует ‘best1bin’:
>>> def custom_strategy_fn(candidate, population, rng=None): ... parameter_count = population.shape(-1) ... mutation, recombination = 0.7, 0.9 ... trial = np.copy(population[candidate]) ... fill_point = rng.choice(parameter_count) ... ... pool = np.arange(len(population)) ... rng.shuffle(pool) ... ... # two unique random numbers that aren't the same, and ... # aren't equal to candidate. ... idxs = [] ... while len(idxs) < 2 and len(pool) > 0: ... idx = pool[0] ... pool = pool[1:] ... if idx != candidate: ... idxs.append(idx) ... ... r0, r1 = idxs[:2] ... ... bprime = (population[0] + mutation * ... (population[r0] - population[r1])) ... ... crossovers = rng.uniform(size=parameter_count) ... crossovers = crossovers < recombination ... crossovers[fill_point] = True ... trial = np.where(crossovers, bprime, trial) ... return trial