Глава 214: Эволюционный поиск архитектур нейросетей для трейдинга
1. Введение
Поиск архитектур нейросетей (Neural Architecture Search, NAS) трансформировал глубокое обучение, автоматизируя проектирование архитектур нейронных сетей. Традиционно практики вручную создают топологии сетей методом проб и ошибок, опираясь на интуицию и экспертизу в предметной области. В количественном трейдинге, где пространство поиска потенциальных моделей огромно, а связь между выбором архитектуры и прибыльностью неочевидна, автоматизированный поиск архитектур становится особенно ценным.
Эволюционные алгоритмы (ЭА) предлагают убедительную парадигму для NAS. Вдохновлённые биологической эволюцией, эти алгоритмы поддерживают популяцию кандидатных архитектур, которые проходят через отбор, скрещивание и мутацию на протяжении последовательных поколений. Наиболее приспособленные особи — те, чьи архитектуры дают лучшие торговые результаты — выживают и размножаются, а слабые кандидаты отсеиваются. За множество поколений этот процесс обнаруживает архитектуры, хорошо адаптированные к специфическим характеристикам финансовых данных.
Привлекательность эволюционного NAS для трейдинга многогранна. Во-первых, финансовые рынки демонстрируют нестационарную динамику; архитектура, которая превосходно работает в одном режиме, может оказаться неэффективной в другом. Эволюционные методы естественным образом исследуют различные области пространства архитектур, создавая популяцию решений, а не единственную точечную оценку. Во-вторых, торговые цели по своей природе многомерны: нас интересует точность предсказания, но также и задержка вывода (для развёртывания в реальном времени), устойчивость модели (для избежания переобучения) и интерпретируемость. Эволюционная многоцелевая оптимизация изящно обрабатывает эти конкурирующие цели через отбор на основе Парето.
В этой главе разрабатывается полный фреймворк эволюционного NAS для трейдинга на Rust. Мы кодируем нейронные архитектуры как хромосомы, эволюционируем их с помощью турнирного отбора и генетических операторов, включаем регуляризацию на основе возраста для поддержания разнообразия популяции и применяем ранжирование по Парето в стиле NSGA-II для многоцелевой приспособленности. Система интегрируется с данными биржи Bybit для реалистичной оценки.
2. Математические основы
2.1 Генетические алгоритмы
Генетический алгоритм (ГА) оперирует популяцией $P = {x_1, x_2, \ldots, x_N}$ из $N$ особей, где каждая особь $x_i$ кодирует кандидатное решение. Алгоритм итеративно проходит следующий цикл:
- Оценка: Вычислить приспособленность $f(x_i)$ для каждой особи.
- Отбор: Выбрать родителей из популяции на основе приспособленности.
- Скрещивание: Комбинировать пары родителей для создания потомства.
- Мутация: Применить случайные возмущения к потомству.
- Замена: Сформировать следующее поколение из потомства и (опционально) выживших родителей.
Процесс повторяется в течение $G$ поколений или до выполнения критерия сходимости.
2.2 Турнирный отбор
Турнирный отбор — широко используемый механизм отбора благодаря своей простоте и управляемому давлению отбора. Для выбора одного родителя мы равномерно случайно выбираем $k$ особей из популяции и выбираем особь с наивысшей приспособленностью:
$$\text{selected} = \arg\max_{x \in S_k} f(x), \quad S_k \subset P, \quad |S_k| = k$$
Размер турнира $k$ контролирует давление отбора. При $k = 1$ отбор чисто случайный; с увеличением $k$ отбор становится более элитарным. Типичный выбор: $k \in [2, 7]$.
2.3 Операторы скрещивания
Скрещивание комбинирует генетический материал двух родителей $x_a$ и $x_b$ для создания потомства. Мы рассматриваем два основных оператора:
Одноточечное скрещивание: Выбирается случайная точка скрещивания $c \in [1, L-1]$, где $L$ — длина хромосомы. Потомок наследует гены $1, \ldots, c$ от родителя $a$ и гены $c+1, \ldots, L$ от родителя $b$:
$$\text{offspring}[i] = \begin{cases} x_a[i] & \text{если } i \leq c \ x_b[i] & \text{если } i > c \end{cases}$$
Равномерное скрещивание: Каждый ген независимо наследуется от любого из родителей с равной вероятностью:
$$\text{offspring}[i] = \begin{cases} x_a[i] & \text{с вероятностью } 0.5 \ x_b[i] & \text{с вероятностью } 0.5 \end{cases}$$
2.4 Мутация
Мутация вводит случайные изменения для поддержания генетического разнообразия. В контексте NAS операторы мутации включают:
- Добавление слоя: Вставка нового слоя в случайную позицию со случайными параметрами.
- Удаление слоя: Удаление случайно выбранного слоя (если в сети больше минимального количества).
- Изменение размера слоя: Модификация количества нейронов в случайно выбранном слое.
- Изменение активации: Замена функции активации случайного слоя.
Каждая мутация применяется с вероятностью $p_m$ (обычно от $0.1$ до $0.3$).
2.5 Оценка приспособленности
Для трейдинга приспособленность $f(x)$ вычисляется следующим образом:
- Декодирование генома $x$ в архитектуру нейронной сети.
- Обучение сети на историческом наборе ценовых данных.
- Оценка торговых результатов на валидационном наборе.
Функция приспособленности может быть коэффициентом Шарпа, общей доходностью или составной метрикой. Мы используем упрощённую симуляцию, где предсказанные сигналы сравниваются с фактическими ценовыми движениями.
2.6 Разнообразие популяции
Поддержание разнообразия критически важно для избежания преждевременной сходимости. Мы измеряем разнообразие как среднее попарное расстояние Хэмминга между геномами:
$$D(P) = \frac{2}{N(N-1)} \sum_{i < j} d_H(x_i, x_j)$$
Если разнообразие падает ниже порога, мы увеличиваем частоту мутаций или вводим случайных особей.
3. Нейроэволюция
3.1 Эволюция топологии и весов
Нейроэволюция расширяет генетические алгоритмы для эволюции как топологии, так и весов нейронных сетей. Фреймворк NEAT (NeuroEvolution of Augmenting Topologies) ввёл несколько ключевых идей:
- Комплексификация: Начинать с минимальных сетей и постепенно добавлять сложность. Это смещает поиск в сторону более простых решений и избегает проблемы «конкурирующих конвенций», когда функционально идентичные сети имеют разные кодировки.
- Инновационные номера: Отслеживание истории структурных мутаций, чтобы скрещивание могло осмысленно сопоставлять гены разных родителей.
- Видообразование: Группировка похожих особей в виды и защита новых структур от элиминации до того, как они получат возможность оптимизироваться.
В нашем фреймворке NAS для трейдинга мы используем упрощённую форму комплексификации. Начальные геномы кодируют небольшие сети (1-3 слоя), а мутация может добавлять слои со временем. Это поощряет эволюционный процесс сначала находить хорошие мелкие архитектуры, а затем улучшать их добавлением глубины, когда это выгодно.
3.2 Кодирование архитектуры
Каждый геном — это список дескрипторов слоёв переменной длины:
Genome = [Layer_1, Layer_2, ..., Layer_n]Layer_i = (size: u32, activation: Activation)Activation in {ReLU, Tanh, Sigmoid, LeakyReLU, Swish, Linear}Размерность входа определяется данными, а размерность выхода фиксирована (например, 1 для регрессии, 3 для классификации на покупку/удержание/продажу). Геном кодирует только скрытые слои.
4. Применение в трейдинге
4.1 Эволюция архитектур для поиска альфа-сигналов
Поиск альфа-сигналов — нахождение предсказательных сигналов в рыночных данных — по сути является задачей поиска. Пространство возможных преобразований признаков и архитектур моделей огромно. Эволюционный NAS формулирует это как задачу оптимизации в пространстве архитектур.
Каждая кандидатная архитектура неявно определяет конвейер извлечения признаков и предсказания. Эволюционируя архитектуры на скользящих окнах рыночных данных, мы можем обнаруживать модели, адаптирующиеся к изменяющимся рыночным режимам. Эволюционный процесс может раскрыть неочевидные архитектурные паттерны: возможно, определённая комбинация размеров слоёв и активаций улавливает динамику возврата к среднему, тогда как другая топология превосходно работает при обнаружении моментума.
4.2 Многоцелевая эволюция
Торговые системы должны одновременно балансировать несколько целей:
- Точность предсказания: Измеряется направленной точностью или корреляцией с будущей доходностью.
- Задержка вывода: Меньшие, более простые модели работают быстрее — критично для высокочастотных стратегий.
- Устойчивость: Архитектура должна обобщаться на различные рыночные условия, а не только на период обучения.
Мы применяем ранжирование по Парето в стиле NSGA-II. Особь $x_a$ доминирует $x_b$ (записывается $x_a \succ x_b$), если $x_a$ не хуже $x_b$ по всем целям и строго лучше хотя бы по одной:
$$x_a \succ x_b \iff \forall i: f_i(x_a) \geq f_i(x_b) \land \exists j: f_j(x_a) > f_j(x_b)$$
Популяция сортируется в недоминируемые фронты $F_1, F_2, \ldots$, где $F_1$ содержит особей, не доминируемых никакими другими, $F_2$ содержит особей, доминируемых только теми, что в $F_1$, и так далее. Отбор предпочитает особей из фронтов с меньшим номером.
В пределах одного фронта мы используем расстояние скученности для поощрения разнообразия. Расстояние скученности особи измеряет, насколько она изолирована в пространстве целей — особи в менее плотных регионах предпочитаются для поддержания хорошо распределённого фронта Парето.
5. Эволюция со старением
Регуляризованная эволюция, представленная Real и др. (2019), добавляет механизм возраста в эволюционный процесс. Каждая особь имеет возраст, который увеличивается с каждым поколением. Вместо замены наименее приспособленной особи мы удаляем самую старую особь из популяции независимо от её приспособленности.
Алгоритм работает следующим образом:
- Инициализировать популяцию из $N$ случайных архитектур.
- Оценить приспособленность всех особей.
- Повторять в течение $G$ поколений: a. Выбрать родителя с помощью турнирного отбора. b. Создать потомка мутацией родителя (без скрещивания в простейшем варианте). c. Оценить приспособленность потомка. d. Добавить потомка в популяцию. e. Удалить самую старую особь из популяции.
Удаление по возрасту предотвращает бессрочное доминирование любой архитектуры в популяции, даже если она имеет высокую приспособленность. Это поддерживает давление исследования и особенно ценно в нестационарных средах, таких как финансовые рынки, где оптимальная вчерашняя архитектура может не быть оптимальной завтра.
Простота эволюции со старением — практическое преимущество. Она требует меньше гиперпараметров, чем традиционные ГА, и было показано, что она сравнивается или превосходит по производительности более сложные методы NAS, включая подходы на основе обучения с подкреплением.
6. Пошаговая реализация
Наша реализация на Rust организована в несколько основных компонентов:
6.1 Кодирование генома
Структура Genome содержит вектор записей LayerGene, каждая из которых определяет размер слоя и функцию активации. Геном также отслеживает свой возраст (поколение создания) и кэшированные оценки приспособленности.
pub struct LayerGene { pub size: usize, pub activation: Activation,}
pub struct Genome { pub layers: Vec<LayerGene>, pub fitness: Option<f64>, pub birth_generation: usize, // Компоненты многоцелевой приспособленности pub accuracy_score: f64, pub latency_score: f64, pub robustness_score: f64, pub pareto_rank: usize, pub crowding_distance: f64,}6.2 Генетические операторы
Метод mutate применяет одну из четырёх мутаций случайным образом: добавление слоя, удаление слоя, изменение размера слоя или изменение функции активации. Функция crossover поддерживает как одноточечную, так и равномерную стратегии.
6.3 Движок эволюции
EvolutionEngine управляет эволюционным циклом. Он поддерживает популяцию, выполняет турнирный отбор, применяет генетические операторы, оценивает приспособленность и отслеживает статистику по поколениям. Движок поддерживает как стандартную смену поколений, так и эволюцию со старением.
6.4 Оценка приспособленности
Приспособленность вычисляется путём симуляции простой торговой стратегии: геном определяет архитектуру сети, мы выполняем прямой проход со случайными весами (как приближение — в продакшене вы бы обучали веса) и измеряем направленную точность относительно фактических движений цен. Многоцелевая приспособленность комбинирует точность, задержку (обратно пропорциональную размеру сети) и устойчивость (согласованность по нескольким окнам оценки).
6.5 Интеграция с Bybit
BybitClient получает OHLCV-данные свечей через API Bybit V5. Эти данные предобрабатываются в векторы признаков (доходности, волатильность, коэффициенты скользящих средних) для оценки архитектуры.
pub struct BybitClient { base_url: String, client: reqwest::blocking::Client,}
impl BybitClient { pub fn fetch_klines(&self, symbol: &str, interval: &str, limit: usize) -> Result<Vec<Kline>>;}7. Интеграция данных Bybit
Реализация подключается к публичному API Bybit для получения реальных рыночных данных. Конвейер данных работает следующим образом:
- Получение: Запрос OHLCV-свечей для заданного символа (например, BTCUSDT) и таймфрейма.
- Предобработка: Вычисление признаков, включая логарифмические доходности, скользящую волатильность, индикаторы моментума типа RSI и сигналы пересечения скользящих средних.
- Разделение: Деление на обучающий, валидационный и тестовый наборы с использованием временного порядка (без заглядывания в будущее).
- Оценка: Каждый геном в популяции оценивается на разбиении обучение/валидация. Тестовый набор зарезервирован для финальной оценки лучшей архитектуры.
Используемый эндпоинт Bybit V5 API:
GET https://api.bybit.com/v5/market/kline?category=linear&symbol=BTCUSDT&interval=60&limit=200Данные парсятся в структуры Kline и конвертируются в матрицы признаков для эволюционной функции приспособленности.
8. Ключевые выводы
-
Эволюционный NAS автоматизирует проектирование архитектур для торговых моделей, устраняя необходимость ручного проектирования сетей методом проб и ошибок и позволяя исследовать архитектуры, которые человек мог бы не рассмотреть.
-
Генетические алгоритмы предоставляют гибкий фреймворк оптимизации с хорошо изученными операторами (отбор, скрещивание, мутация), которые можно настроить под пространство поиска архитектур.
-
Многоцелевая эволюция через ранжирование по Парето естественно обрабатывает конкурирующие требования торговых систем: точность, скорость и устойчивость можно оптимизировать одновременно, не сводя их к единому скаляру.
-
Эволюция со старением предлагает простоту и эффективность. Удаляя самых старых особей вместо наименее приспособленных, она поддерживает давление исследования и хорошо адаптируется к нестационарным финансовым данным.
-
Комплексификация через нейроэволюцию смещает поиск в сторону более простых архитектур изначально, добавляя сложность только когда она улучшает приспособленность — неявная форма регуляризации, помогающая предотвратить переобучение.
-
Разнообразие популяции существенно для избежания преждевременной сходимости. Турнирный отбор с умеренным давлением в сочетании с мутацией и заменой по возрасту поддерживает здоровое разнообразие кандидатных архитектур.
-
Rust обеспечивает преимущества производительности для эволюционного NAS, где внутренний цикл включает оценку множества архитектур за поколение. Низкоуровневый контроль над памятью и вычислениями обеспечивает эффективное управление популяцией и оценку приспособленности.
-
Интеграция реальных рыночных данных через Bybit гарантирует, что эволюционировавшие архитектуры тестируются на фактической рыночной динамике, а не на синтетических данных, повышая практическую значимость обнаруженных архитектур.