3. Основные операции

3. Основные операции

В этой главе мы проведем вас через запуск вашей первой задачи оптимизации в EvoX, включая то, как запустить EvoX и инициализировать процесс оптимизации, как настроить проект EvoX (выбор алгоритмов и задач и их сборка), а также часто используемые базовые команды (или методы) для управления процессом оптимизации. На простом примере вы изучите основы использования EvoX.

Запуск и инициализация

После проверки установки вы можете приступить к написанию скриптов оптимизации с использованием EvoX. Вы можете импортировать EvoX в любой среде Python (например, терминал, Jupyter Notebook, IDE и т. д.).

Сначала давайте импортируем EvoX и его связанные модули и инициализируем простую задачу оптимизации. Например, мы будем использовать алгоритм Particle Swarm Optimization (PSO) для оптимизации классической функции Ackley. Функция Ackley — это распространенная тестовая функция с известным глобальным оптимумом в ((0,0,\dots,0)), что делает ее подходящей для демонстрации. Вот минимальный пример кода EvoX, который демонстрирует, как запустить и выполнить оптимизацию:

import torch
from evox.algorithms import PSO                      # Import PSO algorithm
from evox.problems.numerical import Ackley           # Import Ackley optimization problem
from evox.workflows import StdWorkflow, EvalMonitor  # Import standard workflow and monitor

# 1. Define the optimization algorithm and problem
algorithm = PSO(
    pop_size=50,                    # Population size of 50
    lb=-32 * torch.ones(2),         # Decision variable lower bound: 2D vector, each -32
    ub= 32 * torch.ones(2)          # Decision variable upper bound: 2D vector, each 32
)
problem = Ackley()                  # Optimization problem: Ackley function (default dimension matches the algorithm)

# 2. Assemble the workflow and add a monitor to track results
monitor = EvalMonitor()
workflow = StdWorkflow(algorithm, problem, monitor)

# 3. Initialize the workflow
workflow.init_step()  # Initialize the internal state of the algorithm and problem

# 4. Execute optimization iterations
for i in range(100):
    workflow.step()   # Advance the optimization by one step

# 5. Obtain results (e.g., print the optimal value)
best_fitness = monitor.get_best_fitness() # Get the best fitness value from the monitor
print("Iteration completed, current best fitness value found:", float(best_fitness))

Приведенный выше код включает следующие шаги:

  • Сначала мы устанавливаем параметры для алгоритма PSO: размер популяции 50 и пространство поиска в 2D в диапазоне [-32, 32].
  • Затем мы определяем задачу Ackley (функция Ackley по умолчанию определена как 2D).
  • Мы создаем стандартный рабочий процесс StdWorkflow, который собирает алгоритм и задачу, и передаем монитор EvalMonitor для записи данных процесса оптимизации.
  • Далее мы завершаем процесс инициализации с помощью workflow.init_step(), который автоматически инициализирует популяцию, случайное число (seed) и другие внутренние состояния.
  • Затем мы запускаем цикл для непрерывного выполнения 100 итераций с помощью workflow.step(). Каждый раз, когда вызывается step(), алгоритм генерирует новые решения и оценивает их приспособленность (fitness), постоянно приближаясь к оптимальному решению.
  • Наконец, мы используем метод get_min_fitness(), предоставляемый монитором, чтобы получить лучшее значение приспособленности в процессе итерации и вывести его на печать.

При запуске этого скрипта вы увидите вывод итераций оптимизации, например:

Iteration completed, current best fitness value found: 9.5367431640625e-07

Поскольку мы явно не выводили промежуточные результаты в цикле, они не будут отображаться. Однако вы можете судить о том, сошелся ли алгоритм, по финальному значению приспособленности. Например, оптимальное значение функции Ackley равно 0, и если результат близок к 0, это указывает на то, что PSO нашел решение, близкое к глобальному оптимуму. Вы также можете вызвать print(monitor.history), чтобы просмотреть исторические данные, записанные монитором, или использовать monitor.plot() для построения кривых сходимости (требуется поддержка визуализации, например, Plotly).

Примечание: StdWorkflow — это инкапсуляция стандартного процесса оптимизации, предоставляемая EvoX. Она внутренне реализует логику «инициализация-обновление итерации», характерную для традиционных эволюционных алгоритмов, и инкапсулирует взаимодействие между алгоритмом и задачей. Для большинства простых приложений будет достаточно прямого использования StdWorkflow. EvalMonitor — это монитор, который реализует такие методы, как get_best_fitness() и plot(), для сбора и отображения метрик производительности в процессе оптимизации. Новички могут временно воспринимать его как журнал записей, в который заносятся лучшие результаты каждой итерации для последующего анализа.

В приведенном выше примере мы создали базовую конфигурацию для проекта EvoX, включая выбор алгоритма, определение задачи и сборку рабочего процесса. Как правило, настройка проекта EvoX включает следующие шаги:

  1. Выбор/определение задачи оптимизации: Уточните, какую задачу оптимизации вы пытаетесь решить. Например, если вы оптимизируете математическую функцию, EvoX предоставляет множество встроенных задач в модуле evox.problems (например, классические функции, такие как Sphere, Rastrigin, Ackley), которые вы можете использовать напрямую. Если ваша задача не охвачена встроенными функциями, вы можете определить свою собственную (описано в следующей главе). При настройке задачи вам обычно нужно знать размерность переменных решения и их диапазон значений.

  2. Выбор/настройка алгоритма оптимизации: Выберите подходящий эволюционный алгоритм в зависимости от типа задачи. EvoX предоставляет богатый набор алгоритмов в evox.algorithms, включая одноцелевые алгоритмы (такие как PSO, GA, CMA-ES) и многоцелевые алгоритмы (такие как NSGA-II, RVEA). После выбора алгоритма вам обычно потребуется установить его параметры, такие как размер популяции (pop_size) и специфические для алгоритма параметры (например, вероятность кроссовера и мутации в GA). Большинству алгоритмов требуется диапазон переменных (нижняя граница lb и верхняя граница ub) и размерность задачи для инициализации популяции. Если вы используете многоцелевой алгоритм, вам также нужно будет указать количество целей (n_objs). Алгоритмы EvoX часто предоставляют значения по умолчанию для общих гиперпараметров, но новичкам следует рассмотреть возможность настройки этих параметров в зависимости от задачи для достижения лучшей производительности.

  3. Сборка рабочего процесса: Когда экземпляры алгоритма и задачи готовы, вам нужно «собрать» их в рабочий процесс, который представляет собой полный контроль над процессом оптимизации. В EvoX StdWorkflow обычно используется для объединения алгоритма и задачи. Если вы хотите отслеживать прогресс оптимизации, вы можете добавить монитор (например, EvalMonitor) в рабочий процесс. Монитор не является обязательным, но он может быть очень полезен при отладке и анализе. Сборка рабочего процесса обычно занимает одну строку кода, например: workflow = StdWorkflow(algo, prob, monitor).

  4. Инициализация: Вызовите метод инициализации рабочего процесса, чтобы начать оптимизацию. Последняя версия EvoX предоставляет удобный метод StdWorkflow.init_step(), который завершает процесс инициализации за один вызов.

  5. Запуск итераций: Используйте цикл для многократного вызова workflow.step(), чтобы продвигать эволюционный процесс вперед. Каждый вызов выполняет одну итерацию, включая такие шаги, как «генерация новых решений -> оценка -> выбор» внутри алгоритма. Во время итераций вы можете использовать монитор для наблюдения за результатами в реальном времени, например, печатая текущую лучшую приспособленность каждые несколько поколений. Критерии остановки могут быть установлены в соответствии с вашими потребностями — распространенные варианты включают фиксированное количество поколений (например, запуск на 100 поколений) или остановку, когда отслеживаемые метрики сходятся (например, отсутствие значительного улучшения в течение нескольких поколений).

  6. Получение результатов: После завершения итераций вам нужно извлечь окончательные результаты из алгоритма — такие как лучшее решение и его целевое значение. В EvoX они обычно получаются через монитор. Например, EvalMonitor.get_best_fitness() возвращает лучшее значение приспособленности. Чтобы получить вектор лучшего решения, один из способов — заставить объект задачи сохранять лучшего кандидата во время оценки или использовать интерфейс монитора. В стандартной реализации EvoX EvalMonitor записывает лучшую особь и приспособленность в каждом поколении, доступ к которым можно получить через его свойства. Предполагая, что monitor.history хранит историю, вы можете извлечь лучшую особь из последнего поколения. Конечно, вы также можете пропустить EvalMonitor и напрямую запросить объект алгоритма после цикла — это зависит от реализации алгоритма. Если ваш пользовательский алгоритм реализует get_best() или хранит лучшую особь в своем состоянии, вы можете извлечь ее напрямую. Однако, поскольку EvoX делает упор на чистые функции и модульность, доступ к результатам обычно осуществляется через модули мониторинга.

Следуя этим шагам, вы сможете четко структурировать код вашей задачи оптимизации. Для новичков важно понимать, как работает трио алгоритм-задача-рабочий процесс: алгоритм отвечает за генерацию и улучшение решений, задача оценивает их качество, а рабочий процесс соединяет их в итерационный цикл.

Далее мы представим некоторые базовые команды и вызовы функций, доступные в EvoX, чтобы помочь углубить ваше понимание процесса оптимизации.

Обзор основных команд

При использовании EvoX есть несколько часто используемых методов и функций, которые действуют как «команды», с которыми вам стоит ознакомиться:

Методы, связанные с рабочим процессом

  • StdWorkflow.init_step(): Инициализация. Это команда быстрого запуска для запуска процесса оптимизации, часто используемая в начале скрипта. Она вызывает логику инициализации как для алгоритма, так и для задачи, генерирует начальную популяцию и оценивает приспособленность. После этого рабочий процесс содержит начальное состояние и готов к итерации.

  • StdWorkflow.step(): Продвижение на один шаг в оптимизации. Каждый вызов заставляет алгоритм генерировать новые потенциальные решения на основе текущего состояния популяции, оценивать их и выбирать следующее поколение. Пользователи обычно вызывают это несколько раз внутри цикла. Функция step() обычно ничего не возвращает (внутреннее состояние обновляется внутри рабочего процесса), хотя старые версии могут возвращать новое состояние. Новички могут просто вызывать ее, не беспокоясь о возвращаемом значении.

Методы, связанные с монитором

На примере EvalMonitor общие методы включают:

  • EvalMonitor.get_best_fitness(): Возвращает самую низкую зафиксированную приспособленность (для задач минимизации) или самую высокую приспособленность (для задач максимизации; монитор обычно различает это). Полезно для получения текущего лучшего результата.
  • EvalMonitor.get_history() или monitor.history: Извлекает полную историю, например, лучшее значение из каждого поколения. Полезно для анализа тенденций сходимости.
  • EvalMonitor.plot(): Строит кривые сходимости или производительности; требуется графическая среда или Notebook. Монитор обычно использует Plotly для рендеринга графиков, помогая вам визуально оценить производительность алгоритма. Внутренне монитор записывает количество оценок и их результаты в каждом поколении — вам обычно не нужно вмешиваться, просто извлекайте данные при необходимости.

Методы, связанные с алгоритмом

  • Метод Algorithm.__init__(): Метод инициализации алгоритма. Переменные обычно оборачиваются с помощью evox.core.Mutable(), а гиперпараметры — с помощью evox.core.Parameter().

  • Метод Algorithm.step(): В специфических сценариях или при использовании пользовательских алгоритмов/задач вы можете напрямую вызывать метод step() алгоритма, который обычно инкапсулирует всю логику итерации алгоритма.

  • Метод Algorithm.init_step(): Метод init_step() включает первую итерацию алгоритма. Если он не переопределен, он просто вызывает метод step(). В типичных случаях первая итерация ничем не отличается от других, поэтому многим алгоритмам может не потребоваться пользовательский init_step(). Но для алгоритмов, включающих настройку гиперпараметров, вам может потребоваться обновить гиперпараметры или связанные переменные здесь.

Управление устройствами и параллелизмом

  • Метод .to(device): Если вам нужно переключить вычислительные устройства в вашей программе, используйте метод PyTorch .to(device) для перемещения тензоров (torch.Tensor) на GPU/CPU (некоторые методы PyTorch, такие как torch.randn, также требуют указания устройства). Как правило, если вы установите устройство по умолчанию с помощью torch.set_default_device() на cuda:0 (при условии, что ваша система поддерживает это, а EvoX и зависимости установлены правильно — проверьте с помощью torch.cuda.is_available()), большинство высокопроизводительных параллельных вычислений EvoX будут автоматически выполняться на GPU. При написании пользовательских алгоритмов, задач или мониторов, если вы создаете новые тензоры или используете чувствительные к устройству методы PyTorch, рекомендуется явно указывать device как cuda:0 или использовать torch.get_default_device(), чтобы избежать падения производительности из-за вычислений, распределенных по разным устройствам.

Для новичков вышеперечисленных методов достаточно для решения типичных задач оптимизации. Вкратце: Инициализация задачи/алгоритма – настройка монитора – сборка рабочего процесса – запуск и получение результатов — это наиболее распространенный рабочий процесс EvoX. Освоение этих шагов позволит вам решать базовые задачи оптимизации с помощью EvoX.

Прежде чем переходить к следующей главе, попробуйте изменить пример: переключитесь с PSO на другой алгоритм, замените функцию Ackley другой тестовой функцией или используйте монитор для извлечения дополнительной информации — это поможет вам оценить гибкость настройки проектов EvoX.