- BrainTools - https://www.braintools.ru -
Если вы когда-нибудь пытались натравить классическую LSTM на минутные свечи волатильных активов, вы знаете эту боль [1]. Сначала Loss красиво падает на трейне, вы предвкушаете покупку острова, а на тесте модель превращается в тыкву. Она либо предсказывает скользящую среднюю со сдвигом на один шаг, либо упирается в «стену» Loss = 0.693 (то есть −ln(0.5)), сводя всё к подбрасыванию монетки.
Проблема не в вас. Проблема в том, что рекуррентные сети (RNN, LSTM, GRU) живут в дискретном времени. Для них шаг между 10:00 и 10:01 абсолютно идентичен шагу между пятницей и утром понедельника. Они не умеют сжимать и растягивать восприятие [2] времени, когда волатильность взрывается.
В этой статье мы отойдем от мейнстримных архитектур и напишем с нуля Liquid Neural Network (Жидкую Нейронную Сеть). Мы заставим время течь непрерывно, используя численные методы дифференциальных уравнений прямо внутри PyTorch-графа, и посмотрим, как она вытаскивает скрытый макро-тренд из абсолютного рыночного хаоса.
Теория без воды: Что делает сеть «жидкой»?
Концепция Liquid Time-Constant Networks была представлена исследователями из Лаборатории искусственного интеллекта [3] MIT (CSAIL). Их изначальная цель — управление дронами и автопилотами в непредсказуемой среде. Но финансовые рынки — это та же турбулентность, только выраженная в долларах , рублях и других валютах.
В классической RNN скрытое состояние $h_t$ обновляется по дискретным шагам:
$$h_t = tanh(W_{in} x_t + W_h h_{t-1} + b)$$
В Liquid Network мы отказываемся от дискретности. Состояние нейрона [4] $h(t)$ — это непрерывная переменная, описываемая обыкновенным дифференциальным уравнением (ОДУ):
$$frac{dh(t)}{dt} = -frac{h(t)}{tau} + f(W_{in} x(t) + W_h h(t) + b)$$
Главная магия скрыта в обучаемом параметре $tau$ (tau). Это постоянная времени, или «вязкость» нейрона:
Если $tau$ маленькое (стремится к нулю), нейрон [5] «быстрый». Он мгновенно реагирует на рыночный шум, скачки спреда и минутные импульсы.
Если $tau$ большое, нейрон «медленный» и вязкий. Он игнорирует шум и накапливает долгосрочный контекст.
Позволяя сети самой выучить распределение $tau$ для каждого нейрона, мы получаем систему, которая автоматически балансирует между мгновенной реакцией [6] на новостные шоки и удержанием глобального тренда.
Хватит теории, давайте писать код. Нам нужно реализовать слой, который будет решать дифференциальное уравнение Эйлеровым шагом прямо во время forward прохода.
В отличие от LSTM с ее громоздкой системой ворот (Forget/Update gates), ядро «жидкой» сети выглядит удивительно минималистично:
Python
import torch
import torch.nn as nn
class LiquidLayer(nn.Module):
def __init__(self, in_features, hidden_features, dt=0.05):
super(LiquidLayer, self).__init__()
self.dt = dt # Шаг времени для интеграции Эйлера
self.hidden_features = hidden_features
# Линейные трансформации
self.W_in = nn.Linear(in_features, hidden_features)
self.W_h = nn.Linear(hidden_features, hidden_features)
# Обучаемый параметр "вязкости" для каждого нейрона
self.tau = nn.Parameter(torch.rand(hidden_features) * 2.0 + 0.5)
def forward(self, x):
batch_size, seq_len, _ = x.size()
h = torch.zeros(batch_size, self.hidden_features, device=x.device)
outputs = []
for t in range(seq_len):
# 1. Вычисляем входящий "поток" (Forcing term)
forcing_term = torch.tanh(self.W_in(x[:, t, :]) + self.W_h(h))
# 2. Защита от взрыва градиентов
# Ограничиваем tau снизу, иначе при tau -> 0 производная улетит в NaN
safe_tau = torch.clamp(self.tau, min=0.01)
# 3. Решаем ОДУ: dh/dt = -h/tau + forcing_term
dh = (-h / safe_tau) + forcing_term
# 4. Шаг интеграции (Euler method)
h = h + self.dt * dh
outputs.append(h.unsqueeze(1))
return torch.cat(outputs, dim=1)
Важная деталь архитектуры: мы ограничиваем $tau$ снизу через torch.clamp. Если $tau$ приблизится к нулю, наша «жидкость» вскипит, уравнение уйдет в бесконечность, и мы получим классическую проблему Exploding Gradients.
Для полноценной работы оборачиваем это в простую сеть с линейным слоем (readout) на конце:
Python
class LiquidNet(nn.Module):
def __init__(self, in_features, hidden_features, out_features):
super(LiquidNet, self).__init__()
self.liquid = LiquidLayer(in_features, hidden_features)
self.readout = nn.Linear(hidden_features, out_features)
def forward(self, x):
liquid_states = self.liquid(x)
# Берем последнее состояние для предсказания
return self.readout(liquid_states[:, -1, :])
Проверять сеть на обычном синусе скучно. Мы сгенерируем суровый финансовый датасет (смесь Geometric Brownian Motion с прыжками).
Чтобы задача имела математическое решение, мы спрячем внутри сильный шум очень слабую синусоиду (макро-тренд). Задача сети — бинарная классификация: предсказать, будет ли цена через 5 шагов выше текущей.
Python
import numpy as np
def generate_market_data(seq_len=60, samples=10000, future_steps=5):
X_data, Y_data = [], []
for _ in range(samples):
# 1. Скрытый макро-тренд (очень слабый сигнал)
phase = np.random.uniform(0, 2 * np.pi)
t = np.linspace(0, 4 * np.pi, seq_len + future_steps)
macro_trend = np.sin(t + phase) * 0.03
# 2. Рыночный хаос (Случайный шум + Прыжки волатильности)
noise = np.random.normal(0, 0.02, seq_len + future_steps)
jumps = np.random.choice([0, 1, -1], size=seq_len + future_steps, p=[0.96, 0.02, 0.02]) * np.random.uniform(0.1, 0.25)
returns = macro_trend + noise + jumps
price_path = np.cumsum(returns)
x_window = price_path[:seq_len] - price_path[0] # Нормализация
# Таргет: 1 если цена выросла, 0 если упала
y_label = 1.0 if price_path[-1] > price_path[seq_len-1] else 0.0
X_data.append(x_window)
Y_data.append(y_label)
return np.array(X_data), np.array(Y_data)
Мы обучали сеть (hidden_features=64, Adam lr=0.002, BCEWithLogitsLoss) на 50 эпохах. Как было сказано в начале, любая попытка предсказать чистое случайное блуждание упирается в Loss: 0.693 и точность в районе 50%.
Но наша Liquid Network пробила эту стену:

Точность взлетела до стабильных 83%. Сеть успешно отфильтровала высокочастотный хаос и зацепилась за скрытый паттерн.
Самое интересное происходит под капотом во время инференса. Давайте достанем из сети обученные параметры $tau$ и посмотрим на непрерывную динамику внутренних состояний $h(t)$ нескольких нейронов в момент предсказания.

Посмотрите на распределение обученных параметров (в консоли под графиком):
Минимальная вязкость ($tau$): 0.548
Максимальная вязкость ($tau$): 2.549
Эта разница в 5 раз визуально бросается в глаза на нижнем графике!
Фиолетовая и синяя линии (Быстрые нейроны): У них низкий $tau$. Они вибрируют, реагируя на локальный шум «стакана» и скачки волатильности входного сигнала.
Оранжевая и красная линии (Медленные нейроны): У них высокий $tau$. Посмотрите, какие они плавные. Они почти полностью игнорируют высокочастотный хаос и накапливают долгосрочную память [7] о глобальном тренде.
Сеть самостоятельно, исключительно через Backpropagation, распределила роли: кто-то из нейронов работает скальпером, а кто-то — долгосрочным инвестором.
Liquid Neural Networks — это не просто красивый академический концепт из MIT. Это элегантный, “white-box” способ внедрить физику непрерывного времени в дискретный мир тензоров.
Если вы работаете с высоко-волатильными временными рядами, где время и интенсивность событий непредсказуемы (крипта, HFT, снятие показаний с датчиков IoT) — попробуйте заменить ваши громоздкие LSTM-блоки на компактный «жидкий» слой. Возможно, именно он поможет вам пробить стену в 0.693.
Код экспериментов доступен для воспроизведения. Пишите в комментариях, пробовали ли вы уже интегрировать дифференциальные уравнения в свои DL-пайплайны!
Автор: Livadies
Источник [8]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/28441
URLs in this post:
[1] боль: http://www.braintools.ru/article/9901
[2] восприятие: http://www.braintools.ru/article/7534
[3] интеллекта: http://www.braintools.ru/article/7605
[4] нейрона: http://www.braintools.ru/article/6020
[5] нейрон: http://www.braintools.ru/article/9161
[6] реакцией: http://www.braintools.ru/article/1549
[7] память: http://www.braintools.ru/article/4140
[8] Источник: https://habr.com/ru/articles/1020630/?utm_campaign=1020630&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.