3. Базовые операции

3. Базовые операции

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

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

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

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

import torch
from evox.algorithms import PSO                      # Импорт алгоритма PSO
from evox.problems.numerical import Ackley           # Импорт задачи оптимизации Ackley
from evox.workflows import StdWorkflow, EvalMonitor  # Импорт стандартного рабочего процесса и монитора

# 1. Определение алгоритма оптимизации и задачи
algorithm = PSO(
    pop_size=50,                    # Размер популяции 50
    lb=-32 * torch.ones(2),         # Нижняя граница переменных решения: 2D вектор, каждая -32
    ub= 32 * torch.ones(2)          # Верхняя граница переменных решения: 2D вектор, каждая 32
)
problem = Ackley()                  # Задача оптимизации: функция Экли (размерность по умолчанию соответствует алгоритму)

# 2. Сборка рабочего процесса и добавление монитора для отслеживания результатов
monitor = EvalMonitor()
workflow = StdWorkflow(algorithm, problem, monitor)

# 3. Инициализация рабочего процесса
workflow.init_step()  # Инициализация внутреннего состояния алгоритма и задачи

# 4. Выполнение итераций оптимизации
for i in range(100):
    workflow.step()   # Продвижение оптимизации на один шаг

# 5. Получение результатов (например, вывод оптимального значения)
best_fitness = monitor.get_best_fitness() # Получение лучшего значения приспособленности из монитора
print("Итерация завершена, текущее лучшее найденное значение приспособленности:", float(best_fitness))

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

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

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

Итерация завершена, текущее лучшее найденное значение приспособленности: 9.5367431640625e-07

Поскольку мы не выводили промежуточные результаты в цикле, они не будут отображаться. Однако вы можете судить о сходимости алгоритма по конечному значению приспособленности. Например, оптимальное значение функции Экли равно 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 и напрямую запросить объект алгоритма после цикла — это зависит от реализации алгоритма. Однако, поскольку 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 на другой алгоритм, замените функцию Экли другой тестовой функцией или используйте монитор для извлечения дополнительной информации — это поможет вам оценить гибкость настройки проектов EvoX.