Глава 326: Deep Ensembles для Трейдинга
Обзор
Deep Ensembles (Глубокие Ансамбли) - это простой, но мощный подход для оценки неопределенности в глубоком обучении. Обучая несколько нейронных сетей с различными случайными инициализациями, Deep Ensembles захватывают неопределенность модели (эпистемическую неопределенность) и обеспечивают робастные предсказания, критически важные для торговых решений с учетом риска.
Почему Deep Ensembles для Трейдинга?
Проблема Одиночных Моделей
Одиночная нейронная сеть дает точечные предсказания без какой-либо меры уверенности:
Одиночная модель: Цена → Нейросеть → Предсказание: +2.5% (Но насколько модель уверена?)В трейдинге это опасно, потому что:
- Самоуверенные предсказания ведут к завышенным позициям
- Нет оценки риска при смене рыночных режимов
- Ошибки модели происходят тихо и катастрофично
Решение Deep Ensembles
Deep Ensembles обучают M независимых сетей и агрегируют их предсказания:
Deep Ensemble: Цена → [НС₁, НС₂, НС₃, ..., НСₘ] → Среднее: +2.5%, Стд: 0.8% (Теперь мы знаем неопределенность!)Ключевая идея: Несогласие между членами ансамбля указывает на неопределенность.
Основные Концепции
1. Разнообразие Ансамбля через Случайную Инициализацию
Нейронные сети невыпуклы. Разные случайные инициализации находят разные локальные минимумы:
Ландшафт функции потерь: ↓ Иниц. 1 ↓ Иниц. 2 ↓ Иниц. 3 \ | / \ | / ↘ ↓ ↙ Минимум A Минимум B Минимум C
Каждый минимум дает разную (но валидную) модель!Почему это работает:
- Нейронные сети с разными инициализациями сходятся к разным решениям
- Эти решения делают разные ошибки на разных входах
- Усреднение уменьшает индивидуальные ошибки (снижение дисперсии)
- Несогласие выявляет области, где модели неуверены
2. Декомпозиция Неопределенности
Deep Ensembles естественно разделяют неопределенность на два типа:
Общая неопределенность = Эпистемическая + Алеаторная
┌─────────────────────────────────────────────────────────────────┐│ ││ ЭПИСТЕМИЧЕСКАЯ (Модельная) АЛЕАТОРНАЯ (Шум данных) ││ ───────────────────────── ──────────────────────── ││ • Снижается с данными • Неснижаемый шум ││ • Высокая при несогласии • Врожденная случайность ││ • Означает "Я не знаю" • Означает "Хаос на рынке" ││ ││ Оценка: Дисперсия средних Оценка: Средняя дисперсия ││ │└─────────────────────────────────────────────────────────────────┘Математическая формулировка:
Для ансамбля из M моделей, предсказывающих гауссовы распределения:
- Каждая модель m выдает: μₘ(x), σₘ²(x)
Общая дисперсия = (1/M) Σ σₘ²(x) + (1/M) Σ (μₘ(x) - μ̄(x))² └─────────────┘ └────────────────────────┘ Алеаторная Эпистемическая (средняя дисперсия) (дисперсия средних)3. Правильные Функции Оценки и NLL Loss
Deep Ensembles используют Negative Log-Likelihood (NLL) loss для правильной оценки неопределенности:
# Для гауссова выходаdef nll_loss(mu, sigma, target): """ NLL = 0.5 * log(2π) + log(σ) + (y - μ)²/(2σ²) """ return 0.5 * np.log(2 * np.pi) + np.log(sigma) + 0.5 * ((target - mu) / sigma) ** 2Почему NLL важен:
- Правильная функция оценки: Стимулирует честные оценки неопределенности
- Модель учит и среднее, И дисперсию
- Самоуверенные предсказания штрафуются
- Неуверенные предсказания тоже штрафуются
4. Несогласие Ансамбля
Несогласие ансамбля - ключевой сигнал для торговых решений:
Высокое несогласие Низкое несогласие(Не торгуем!) (Торгуем уверенно!)
Модель 1: +5% Модель 1: +2.4%Модель 2: -3% ← КОНФЛИКТ Модель 2: +2.6% ← СОГЛАСИЕМодель 3: +1% Модель 3: +2.5%Модель 4: -2% Модель 4: +2.5%Модель 5: +4% Модель 5: +2.4%
Среднее: +1%, Стд: 3.2% Среднее: +2.5%, Стд: 0.08%5. Гиперпараметрические Ансамбли
Помимо случайной инициализации, можно создавать ансамбли по гиперпараметрам:
Разнообразие гиперпараметров:├── Архитектура: [64-32, 128-64, 256-128-64]├── Learning rate: [0.001, 0.0005, 0.0001]├── Dropout: [0.1, 0.2, 0.3]├── Активация: [ReLU, GELU, SiLU]└── Batch size: [32, 64, 128]
Результат: Более разнообразный ансамбль = Лучшие оценки неопределенности6. Параллелизация
Deep Ensembles тривиально параллелизуются:
┌─────────────────────────────────────────────────────────────┐│ ПАРАЛЛЕЛЬНОЕ ОБУЧЕНИЕ │├─────────────────────────────────────────────────────────────┤│ ││ GPU 0: Обучение модели 1 ────────────→ Веса модели 1 ││ GPU 1: Обучение модели 2 ────────────→ Веса модели 2 ││ GPU 2: Обучение модели 3 ────────────→ Веса модели 3 ││ GPU 3: Обучение модели 4 ────────────→ Веса модели 4 ││ GPU 4: Обучение модели 5 ────────────→ Веса модели 5 ││ ││ Все обучаются одновременно! Коммуникация не нужна. │└─────────────────────────────────────────────────────────────┘Параллелизация инференса:
Батч данных → Параллельный forward pass на всех моделях → Агрегация предсказаний (Можно использовать model parallelism или разбиение батча)Архитектура Модели
┌─────────────────────────────────────────────────────────────────┐│ МОДЕЛЬ DEEP ENSEMBLE │├─────────────────────────────────────────────────────────────────┤│ ││ ВХОД: Рыночные признаки [batch, features] ││ ││ ┌────────────────────────────────────────────────────────────┐ ││ │ ЧЛЕНЫ АНСАМБЛЯ (M независимых сетей) │ ││ │ │ ││ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ ││ │ │ Модель 1 │ │ Модель 2 │ │ Модель 3 │ ... │ Модель M │ │ ││ │ │ │ │ │ │ │ │ │ │ ││ │ │ Linear │ │ Linear │ │ Linear │ │ Linear │ │ ││ │ │ ReLU │ │ ReLU │ │ ReLU │ │ ReLU │ │ ││ │ │ Dropout │ │ Dropout │ │ Dropout │ │ Dropout │ │ ││ │ │ Linear │ │ Linear │ │ Linear │ │ Linear │ │ ││ │ │ ReLU │ │ ReLU │ │ ReLU │ │ ReLU │ │ ││ │ │ Linear │ │ Linear │ │ Linear │ │ Linear │ │ ││ │ │ (μ, σ) │ │ (μ, σ) │ │ (μ, σ) │ │ (μ, σ) │ │ ││ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ ││ │ │ │ │ │ │ ││ └───────┼────────────┼────────────┼────────────────┼────────┘ ││ │ │ │ │ ││ ▼ ▼ ▼ ▼ ││ ┌────────────────────────────────────────────────────────────┐ ││ │ СЛОЙ АГРЕГАЦИИ │ ││ │ │ ││ │ μ_ансамбля = (1/M) Σ μₘ │ ││ │ σ²_эпистемич = (1/M) Σ (μₘ - μ_ансамбля)² │ ││ │ σ²_алеаторная = (1/M) Σ σₘ² │ ││ │ σ²_общая = σ²_эпистемич + σ²_алеаторная │ ││ │ │ ││ └────────────────────────────────────────────────────────────┘ ││ ││ ВЫХОД: (μ_ансамбля, σ_общая, σ_эпистемич, σ_алеаторная) ││ │└─────────────────────────────────────────────────────────────────┘Торговая Стратегия
Генерация Сигналов с Учетом Неопределенности
def generate_signals(ensemble, features, threshold=0.6): """ Генерация торговых сигналов с учетом неопределенности для размера позиции. """ # Получаем предсказания ансамбля mean_pred, total_std, epistemic_std, aleatoric_std = ensemble.predict(features)
# Вычисляем силу сигнала signal_strength = mean_pred / total_std # Отношение типа Шарпа
signals = [] for i in range(len(mean_pred)): # Проверяем уверенность предсказания if epistemic_std[i] > threshold * total_std[i]: # Высокая модельная неопределенность - не торгуем signals.append(Signal("HOLD", confidence=0)) continue
# Генерируем сигнал на основе предсказания if signal_strength[i] > 1.5: confidence = min(0.95, 1 - epistemic_std[i] / total_std[i]) signals.append(Signal("LONG", confidence=confidence)) elif signal_strength[i] < -1.5: confidence = min(0.95, 1 - epistemic_std[i] / total_std[i]) signals.append(Signal("SHORT", confidence=confidence)) else: signals.append(Signal("HOLD", confidence=0))
return signalsРазмер Позиции на Основе Неопределенности
def calculate_position_size(signal, uncertainty, max_position=0.1): """ Размер позиции обратно пропорционален неопределенности.
Размер по Келли с поправкой на неопределенность. """ if signal.type == "HOLD": return 0
# Базовая доля по Келли kelly_fraction = signal.confidence / (1 + uncertainty["total_std"])
# Уменьшаем позицию при высокой эпистемической неопределенности epistemic_penalty = 1 - min(1, uncertainty["epistemic_std"] / uncertainty["total_std"])
# Итоговая позиция position = kelly_fraction * epistemic_penalty * max_position
return position if signal.type == "LONG" else -positionДетекция Режима через Неопределенность
def detect_regime(ensemble_predictions, window=20): """ Детекция смены рыночного режима через динамику неопределенности. """ recent_epistemic = epistemic_std[-window:] recent_aleatoric = aleatoric_std[-window:]
epistemic_trend = np.polyfit(range(window), recent_epistemic, 1)[0] aleatoric_trend = np.polyfit(range(window), recent_aleatoric, 1)[0]
if epistemic_trend > 0.1: return "REGIME_CHANGE" # Модель становится неуверенной elif aleatoric_trend > 0.1: return "VOLATILITY_SPIKE" # Рынок становится хаотичным elif np.mean(recent_epistemic) < 0.1 and np.mean(recent_aleatoric) < 0.1: return "STABLE" else: return "NORMAL"Детали Реализации
Конфигурация Обучения
ensemble: num_models: 5 architecture: hidden_dims: [256, 128, 64] activation: "relu" dropout: 0.2 output_type: "gaussian" # Выход (μ, σ)
training: batch_size: 64 learning_rate: 0.001 weight_decay: 0.0001 max_epochs: 100 early_stopping_patience: 10 loss: "nll" # Negative log-likelihood
data: train_split: 0.7 val_split: 0.15 test_split: 0.15 sequence_length: 60 prediction_horizon: 5
features: - returns_1m - returns_5m - returns_15m - returns_1h - volume_ratio - volatility - rsi_14 - macd_signal - spread_bpsИнженерия Признаков
features = { # Ценовые признаки 'returns_1m': log_return(close, 1), 'returns_5m': log_return(close, 5), 'returns_15m': log_return(close, 15), 'returns_1h': log_return(close, 60), 'returns_4h': log_return(close, 240),
# Признаки волатильности 'volatility_1h': rolling_std(returns, 60), 'volatility_24h': rolling_std(returns, 1440), 'volatility_ratio': volatility_1h / volatility_24h,
# Признаки объема 'volume_ratio': volume / volume_ma_20, 'vwap_deviation': (close - vwap) / vwap,
# Технические индикаторы 'rsi_14': rsi(close, 14), 'macd_signal': macd(close) - macd_signal(close), 'bb_position': (close - bb_lower) / (bb_upper - bb_lower),
# Признаки книги ордеров 'spread_bps': (ask - bid) / mid * 10000, 'depth_imbalance': (bid_depth - ask_depth) / (bid_depth + ask_depth),}Ключевые Метрики
Качество Модели
| Метрика | Описание | Цель |
|---|---|---|
| NLL | Negative log-likelihood | Меньше лучше |
| Calibration Error | Насколько неопределенность соответствует ошибкам | < 0.1 |
| Sharpness | Средняя предсказанная неопределенность | Баланс с калибровкой |
| CRPS | Continuous Ranked Probability Score | Меньше лучше |
Торговое Качество
| Метрика | Описание | Цель |
|---|---|---|
| Sharpe Ratio | Доходность с учетом риска | > 2.0 |
| Sortino Ratio | С учетом нисходящего риска | > 2.5 |
| Max Drawdown | Максимальная просадка | < 10% |
| Win Rate | % прибыльных сделок | > 55% |
| Profit Factor | Валовая прибыль / Валовый убыток | > 1.5 |
| Uncertainty-Adjusted Return | Доходность / Средняя неопределенность | Выше лучше |
Метрики Калибровки
def calibration_error(predictions, actuals, num_bins=10): """ Expected Calibration Error (ECE)
Для хорошо откалиброванных предсказаний, X% исходов должны попадать в X% доверительные интервалы. """ confidences = 1 - predictions['std'] / predictions['std'].max() accuracies = np.abs(predictions['mean'] - actuals) < predictions['std']
ece = 0 for bin_lower in np.linspace(0, 1, num_bins): bin_upper = bin_lower + 1/num_bins in_bin = (confidences > bin_lower) & (confidences <= bin_upper)
if in_bin.sum() > 0: avg_confidence = confidences[in_bin].mean() avg_accuracy = accuracies[in_bin].mean() ece += np.abs(avg_accuracy - avg_confidence) * in_bin.mean()
return eceПреимущества Deep Ensembles
| Аспект | Одиночная модель | Deep Ensemble |
|---|---|---|
| Оценка неопределенности | Нет | Встроенная |
| Робастность | Склонна к переобучению | Более робастна |
| Калибровка | Часто самоуверенна | Лучше откалибрована |
| Качество | Один оптимум | Агрегация оптимумов |
| Интерпретируемость | Черный ящик | Несогласие = неопределенность |
| Масштабируемость | Н/Д | Тривиально параллелится |
Сравнение с Другими Методами
vs. Байесовские Нейронные Сети (BNN)
BNN:+ Принципиальная неопределенность из апостериора- Сложно обучать- Дорогой инференс- Требует аппроксимаций (VI, MCMC)
Deep Ensembles:+ Просто реализовать+ Параллельное обучение+ Часто лучше калибровка- Требует M forward passes- Нет интерпретации апостериораvs. MC Dropout
MC Dropout:+ Одна модель, много проходов+ Экономия памяти- Недооценивает неопределенность- Зависит от dropout rate
Deep Ensembles:+ Лучшие оценки неопределенности+ Более разнообразные предсказания- Больше памяти (M моделей)- Больше время обученияvs. Одиночная Модель с Калибровкой Softmax
Калибровка Softmax:+ Одна модель+ Post-hoc калибровка- Только классификация- Ограниченные типы неопределенности
Deep Ensembles:+ Работает для регрессии+ Разделение эпистемич/алеаторной- Выше вычислительные затратыПродакшн Соображения
Пайплайн инференса:├── Сбор данных (Bybit WebSocket)│ └── Real-time OHLCV + обновления книги ордеров├── Вычисление признаков│ └── Расчеты скользящих окон├── Инференс ансамбля│ ├── Параллельный forward pass (M моделей)│ ├── Агрегация (среднее, стд)│ └── Декомпозиция неопределенности├── Генерация сигналов│ ├── Фильтрация по уверенности│ └── Размер позиции└── Исполнение ордеров └── Интеграция с риск-менеджментом
Бюджет задержки:├── Сбор данных: ~10мс (WebSocket)├── Вычисление признаков: ~5мс├── Инференс ансамбля: ~20мс (параллельно, GPU)├── Генерация сигналов: ~2мс└── Итого: ~40мс (без учета исполнения)Структура Директории
326_deep_ensembles_trading/├── README.md # Английская версия├── README.ru.md # Этот файл├── readme.simple.md # Простое объяснение├── readme.simple.ru.md # Простое объяснение на русском├── python/ # Python реализация│ ├── requirements.txt # Зависимости Python│ ├── deep_ensemble.py # Основная модель ансамбля│ ├── data_fetcher.py # Получение данных с Bybit и инженерия признаков│ ├── strategy.py # Торговая стратегия с учетом неопределенности│ ├── backtest.py # Фреймворк бэктестинга│ └── example.py # Полный пример└── rust_deep_ensembles/ # Rust реализация ├── Cargo.toml ├── src/ │ ├── lib.rs # Точка входа библиотеки │ ├── api/ # Клиент API Bybit │ ├── ensemble/ # Реализация Deep Ensemble │ ├── features/ # Инженерия признаков │ ├── strategy/ # Торговая стратегия │ └── backtest/ # Движок бэктестинга └── examples/ ├── fetch_data.rs ├── train_ensemble.rs ├── backtest.rs └── live_signals.rsСсылки
-
Simple and Scalable Predictive Uncertainty Estimation using Deep Ensembles (Lakshminarayanan et al., 2017)
-
Deep Ensembles: A Loss Landscape Perspective (Fort et al., 2019)
-
Uncertainty Quantification in Deep Learning (Abdar et al., 2021)
-
Can You Trust Your Model’s Uncertainty? (Ovadia et al., 2019)
-
Hyperparameter Ensembles (Wenzel et al., 2020)
Уровень Сложности
Средний - Требует понимания:
- Обучения нейронных сетей
- Вероятностных распределений (гауссово)
- Основ оценки неопределенности
- Основ трейдинга
Дисклеймер
Эта глава предназначена только для образовательных целей. Торговля криптовалютами связана со значительным риском. Стратегии, описанные здесь, не были проверены в реальной торговле и должны быть тщательно протестированы перед любым применением в реальном мире. Прошлые результаты не гарантируют будущих результатов.