1 августа 2012 года торговая фирма Knight Capital развернула новую версию торгового ПО SMARS. Из-за ошибки при развёртывании на одном из восьми серверов осталась старая тестовая версия кода, из-за чего торговый робот начал неконтролируемо рассылать миллионы ошибочных заявок на покупку и продажу акций. Этот процесс длился около 45 минут и привел к убыткам в размере примерно 440 миллионов долларов — почти весь капитал компании.

Ключевая проблема мониторинга состояла в том, что система PMON (Position Monitor) полностью полагалась на ручной мониторинг: она не генерировала автоматических оповещений и не выделяла превышение лимитов. Трейдеры Knight видели аномальную активность в логах, но не понимали контекст:
Огромные позиции появлялись в специальном аккаунте «33».
У счёта был лимит в $2 млн, но этот лимит не был связан с автоматической системой контроля риска, поэтому превышение не вызвало ни сигналов, ни блокировок.
Никаких circuit breakers (автоматических прерываний торговли), предотвращающих лавинообразные убытки, не было.
Отсутствие контекстуального анализа отчета о работе ПО и автоматических оповещений привело к тому, что персонал просто не успел среагировать на катастрофу высокочастотного трейдинга.
Аналитика того, как ведет себя программа — это важно. Ещё важнее отлавливать случаи некорректной работы вашего ПО — как правило, для этого пользуются логами, и либо отсматривают их вручную (как в уже почившей Knight Capital), либо пользуются некоторыми regex-скриптами для отлавливания специфичных строк вроде «warning», «error» (что применимо, скорее, для небольших локальных проектов) и т. д. Однако проблема такой проверки в том, что она не учитывает контекст прошлых строк, что может (и часто является) причиной ложных срабатываний. Пример:
INFO: Skipping optional module (error handling disabled)
Regex-скрипт, просто ищущий «error», ошибочно сочтет эту строку проблемной. И таких совпадений может быть очень много, что ведёт к alert fatigue — усталости от ложных оповещений, когда приходится сталкиваться с настолько большим количеством уведомлений и тревожных сигналов, что со временем начинаешь игнорировать или пропускать действительно важные сообщения.
Привет, меня зовут Михаил Зуев, я Data Scientist в Сбере. Думаю, после такой истории стало понятно, что читать логи глазами — не самая масштабируемая стратегия. В этой статье расскажу про LogBERT и ансамбли моделей, которые делают это за нас. И да, спойлер: иногда одной модели действительно достаточно, но я узнал об этом только после того, как обучил двадцать пять.
ML
В общем, именно анализ предшествующего контекста — наиболее понятное и логичное решение. Устоявшейся практикой по анализу логов в больших технологических компаниях давно стало машинное обучение (ML-стек в Elasticsearch и Datadog, Splunk Machine Learning Toolkit и т. д.)
Среди наиболее значимых научных работ по этой теме можно выделить DeepLog, LogAnomaly и LogBERT-модели, специально настроенные под задачу детекции аномалий. Вкратце расскажу о них.
DeepLog
DeepLog — это одна из первых моделей, применяющих рекуррентные нейронные сети (LSTM) для обнаружения аномалий в системных логах. Она рассматривает поток логов как последовательность событий, обучаясь на нормальных сообщениях, выстраивая вероятностную модель того, какие события и в каком порядке обычно происходят. Если при последующем наблюдении встречается событие, вероятность которого низкая, то оно считается аномалией. По такому же принципу (с некоторыми модификациями) работает и LogAnomaly, и LogBERT (о них расскажу далее).
Предобработка. Сперва логи разбивают на шаблоны (log keys) и параметры (parameter values). Например, сообщения типа Block 34567 replicated to node 9876 превращаются в шаблон Block 1* replicated to node 2* с параметрами 1* = 34567, 2* = 9876». За формирование таких шаблонов отвечают специальные алгоритмы — парсеры (Drain, Spell использующие regex-скрипты для такой разбивки). Пример подобного извлечения приведен ниже:

По сути, каждый лог в контексте модели теперь представляет собой сочетание шаблона и вектора значений параметров:
k_x = Received block <*> of size <*> from /<*>
ValueVector_x = ["blk_-562725280853087685", "67108864", "10.251.91.84"]
log_seq_x = k_x + ValueVector_x
Формирование обучающих данных. Для каждого окна последовательности из предыдущих событий модель обучается предсказывать следующее (где
— распаршенный шаблон лога):
Этот этап отводится LSTM под обучение контекстным зависимостям в логах.

Классификация. На этапе обнаружения модель получает окно последних событий и выдаёт распределение вероятностей для следующего события
. Если реальный ключ не входит в число наиболее вероятных (например, топ-10 по вероятности), то всё окно последовательностей (в которое входит ключ) маркируется как аномалия.
LogAnomaly
В эту модель добавлен механизм Attention и дополнительная векторизация шаблонов, что позволяет ей понимать семантические сходства между ними, только на этот раз анализируя на стадии инференса смещение в эмбеддинговом пространстве шаблонов.
LogBERT
И, наконец, LogBERT — долгое время считавшийся SOTA-решением, как можно догадаться по названию, — использует трансформерную архитектуру. Этот метод использует контекстно-позиционное представление логов, векторизируя не только шаблоны, но и их позиционное расположение в иерархии следования логов друг за другом (см. картинку, взятую из оригинальной статьи)

Теперь немного об архитектуре, она тут весьма любопытна. Модель также обучается на нормальных последовательностях (вспоминаем Deeplog), только теперь с помощью задач маскированного предсказания логов (masked log key prediction — чисто трансформерная фича) и минимизации объёма гиперсферы (просто ещё одна loss‑функция, смысл добавления которой строится на предположении, что нормальные лог‑последовательности в сферическом пространстве эмбеддингов компактно располагаются рядом друг с другом ближе к центру сферы, в то время как аномальные — далеко от него).

То есть, LogBERT содержит комбинированную функцию потерь: кросс‑энтропию для восстановления маскированных токенов и регуляризирующую функцию минимизации объёма гиперсферы для сжатия эмбеддингов нормальных данных. Такой подход обеспечивает высокую эффективность в формировании эмбеддингов логов и обнаружении аномалий на их основе.
Часть ключевых токенов логов в последовательности случайным образом заменяется на маскировочные токены (MASK), и модель пытается предсказать исходные значения маскированных логов. Если модель точно предсказывает замаскированные лог‑ключи, то последовательность считается нормальной. Если же предсказания оказываются плохими (буквально через пару слов в скобках укажу параметры, которые отвечают за эту «плохость»), то это говорит о том, что паттерн логов отклоняется от нормального ( — топ кандидатов на
‑тое место параметра в последовательности, и
— порог токенов (параметров), не сумев предсказать которые, модель считает лог аномальным).
Аномальный балл для последовательности формируется на основе вероятностных предсказаний модели для маскированных токенов. Если реальный токен не входит в набор наиболее вероятных кандидатов, то последовательность помечается как аномальная. К тому же не забываем про loss объема гиперсферы (Volume Hyperspere Minimization — VHM Loss). Итоговый loss:

Теперь посмотрим на самое ценное, что определяет архитектурную эффективность каждой из моделей — бенчмарки!
Общепринятыми являются три набора данных HDFS (логи распределенной файловой системы HADOOP), BGL (логи суперкомпьютера Blue Gene L) и Thunderbird‑mini. Сводная таблица по каждому датасету представлена ниже:
Наименование |
Количество записей |
Количество аномалий |
HDFS |
11 175 629 |
16 838 |
BGL |
4 747 963 |
348 460 |
Thunderbird-mini |
20 000 000 |
758 562 |
Вот таблица сравнения по ключевым метрикам Precision, Recall и F1 для вышеописанных моделей (последние 3):

Как видите, LogBERT оверперформит на всех датасетах. Оно не удивительно — эра attention is all you need ещё не исчерпала себя (на момент написания статьи).
Моей ключевой идеей было размножить нашу SOTA-модель LogBERT для последующего ансамблирования.

В данном случае я использовал классический бэггинг: брал из датасетов бутстрапированные (с возвращением) выборки окон (последовательности подряд идущих строк) и обучал каждый экземпляр LogBERT на этих уникальных для каждого из них данных.
Основная идея состоит в объединении нескольких независимых оценок для получения более точного и надёжного результата, чем мнение одного. Такое предположение для случая бинарной классификации подтверждается в статье «Bias Plus Variance Decomposition for Zero-One Loss Functions». Главная мысль в том, что если мы используем достаточно независимых оценщиков, то variance итогового предсказания значительно снижается. Кстати, при принятии итогового решения я использовал принцип мажоритарного голосования (когда ответ большинства принимается как ответ ансамбля). И… эта идея сработала!
Я взял из репозитория готовую реализацию logBERT, встроил вышеописанным способом ансамбль от 5 до 25 моделей, протестировал на HDFS, BGL и Thunderbird с величиной эмбеддингов в 512, размером батча в 32 и 8 головами attention. Словом, не менял ничего из архитектурных аспектов, чтобы посмотреть, как справится ансамбль из множества моделей по сравнению с бейзлайном в виде соло‑модели. К слову, на 3070Ti время расчёта 25 моделей (train+test) для HDFS заняло около 5 часов, BGL — 7 часов, Thunderbird — 9 часов. Конечно, Knight Capital это не спасло бы, но, с другой стороны, пока это чисто локальный эксперимент, не видевший параллелизма вычислений на кластере топовых GPU.

Вот что я получил (измерял только F1 как некую результирующую Precision и Recall):



Примечательно, что прирост весьма неоднороден: в HDFS он снижается с ростом количества экземпляров, в BGL и Thunderbird — увеличивается. А то, что он такой скачкообразный, объясняется чётностью или нечётностью количества оценщиков.
Для каждого из датасетов получилось такое сравнение:
HDFS |
BGL |
Thunderbird-mini |
|
Ансамбль (приведён лучший F1) |
84,43 % |
93,34 % |
100 % |
Соло-модель |
79,56 % |
90,11 % |
96,63 % |
Однако есть во всём этом приросте и ложка дёгтя, и имя ей — длительность вычислений, которую я уже обозначил выше. Я считал всё на одной видеокарте последовательно, модель за моделью. И у вас, если возьмётесь провернуть что-то схожее, длительность расчётов будет , где
— длительность расчёта одной модели на бутстрапированной выборке датасета [секунды, минуты, часы, дни, годы, декады], а
— количество экземпляров модели. Но, думаю, если точность для вас имеет решающее значение и есть риск потерять несколько сотен миллионов долларов из-за недостающих 3 % покрытия по F1, то тут можно и подождать.
Резюмируя: использование ансамблей (в данном случае — бэггинг), как я убедился благодаря проделанной работе, — хорошая идея, если у вас есть:
Хорошая базовая модель с небольшим bias (в противном случае комбинация из изначально плохо предсказывающих моделей будет просто путать итоговый «суммирующий механизм», и снижение variance окажется не заметно).
Время на расчёты и уверенность в том, что это того стоит.
Badsanta83
Так а разве рандомный лес не на том же принципе основан? Только голосовать будут на разные модели, а в одной разные деревья решений. Ну если я все правильно понял конечно)
mikneue Автор
Да, случайный лес — это тот же бэггинг :)