Меня зовут Максим Хандусь, я ML-инженер в лаборатории машинного обучения Альфа-Банка. Недавно наша команда «Мы МИСИС 177!!!» (Назарий Карпов, Кузнецов Данил, Павел Смирнов, Душенёв Даниил — как вы могли догадаться, все мы студенты НИТУ МИСИС) участвовала в хакатоне PurpleHack2025 с достаточно необычным форматом и заняла там второе место.
Чаще всего, когда говорят «На хакатоне было пять кейсов», то это значит, что команда выбирает только один кейс, а потом призёры определяются в каждом из кейсов отдельно. Но в этот раз предполагалось решать сразу пять кейсов, а призёры определялись по сумме баллов за все кейсы. На решение давалось шесть дней, не очень много для сразу пяти задач.
Хакатон организовывали ребята из МФТИ к предстоящей конференции IT Purple Conf 2025. Почти все пять кейсов хакатона были ориентированы на ML-разработчиков:
-
оптимизация календарного плана проекта от Сбера,
-
создание шопинг-ассистента от Т-Банка,
-
определение основного цвета на фотографии от Авито,
-
планировщик размещения виртуальных машин на физических серверах от МТС,
-
определение взломанных пользователей по данным абонента от ArenaData.
Мы решили распределить одну задачу на одного человека, помогая друг другу в сложных моментах. В результате заняли второе место с небольшим отрывом от первого. Далее подробно расскажем, что происходило в каждой задаче, какие возникали трудности и как мы их решали, а также рассмотрим решения других участников.
Кейс Авито: классификация изображения
Быстрый и качественный поиск по фиксированной базе картинок, в принципе, не сложная задача. Однако при построении базы на постоянно меняющемся массиве изображений возникает целый ряд сложностей.
Если собирать исключительно векторный поиск на эмбеддингах, то даже при использовании алгоритмов построения поиска по пространству векторов (к примеру, HNSW) близких к оптимальным, будут вставать вопросы о масштабировании и пересчётах базы.
Альтернативным маршрутом для пользователя будет выделение качественных дескрипторов и построение поиска уже внутри выделенного подмножества картинок (стандартный подход — «Разделяй и властвуй»). В рамках решения кейса мы работали с подмножеством категорий представленных товаров и набором цветов для выделения основных оттенков.
Таким образом, задача состояла в классификации изображений товаров, загруженных пользователями на платформу.
Немного про данные
Полученный датасет от коллег из AvitoTech представляет собой стандартный датасет для классификации с меткой цвета и ориентир для категории объекта, цвет которого мы и хотим классифицировать. Так как мы работали с данными, максимально близкими к реальной среде, то и столкнулись со всеми проблемами пользовательского ввода.
В первую очередь, это шумные данные — более 2% картинок не содержали объект нужной категории или не несли никакой информации в себе. К примеру, некоторые фотографии вместо «сумки» содержали фотографии стены или были настолько сильно в расфокусе, что определить само наличие объекта в кадре не представлялось возможным. При дальнейшем рассмотрении обнаружили проблему дубликатов и, решив её, отфильтровали ещё около 0,5% данных.
Для борьбы с отсутствием релевантного объекта в кадре использовали few-shot promptable детекцию и test time augmentation для уточнения предсказаний. Подобрали список синонимичных названий для каждой категории и сгенерировали несколько вариантов изображения, повернув на 90 градусов. Дубликаты фильтровали, обучив линейную модель поверх метрики для кластеризации, — так отделили очень похожие объекты от семантически идентичных.
Далее дошли до распределения меток классов и справедливо ужаснулись:

В части про обучение бейзлайна поговорим про то,как справлялись с дисбалансом.
Страдания по обучению
Итак, максимально очистив данные, обучили CNN для обычной мультилейбл-классификации, решив задачу, как нам казалось, полностью. И наш бейзлайн выдал…метрики, еле отличимые от случайных предсказаний: близкое к 0.5 F1 при сравнении двух наиболее репрезентативных классов.
На этом моменте решили начать экспериментировать с моделью: пробовали Group-conv, разные палитры и аугментации, тестировали взвешенный лосс и семплирование, получая в итоге минимальный прирост.
Графики обучения не давали ответов — модель без пиков в лоссе или норме градиентов сходилась к плохой метрике, и лосс не опускался ниже.
После пары дней, потраченных впустую на модель и поиск багов в коде обучения, вернулись к данным и решили посмотреть, что именно модель выделяет в градиентах. Использовали классический GradCam и увидели, что модель буквально не знает, на что смотреть, и простая CNN не способна выделить объект на первом плане, так что сделали это за неё. Заново подняли promptable-детекцию и с помощью того же пайплайна собрали датасет из кропов — далее обучались только на нём.
Так смогли увидеть хоть какой-то значимый прирост в метриках, однако обучение стало более нестабильным. На этом моменте решили, что не модифицировали только лосс, и ванильная кросс-энтропия должна пойти под нож — здесь и пригодились результаты экспериментов со взвешиванием семплов и сбалансированной выборкой.
Благодаря этим результатам построили confusion matrix и модифицировали лосс с учётом цветовой палитры: учитывали не только правильную классификацию, но и то, насколько близко модель попала по палитре к целевому цвету.
Такое решение давало уже уверенные 0.7 на macro-F1, и мы перенаправили свои силы на решение других кейсов.
В последний день решили проверить: может быть, ошибка в пользовательских цветах? Для переразметки отобрали самые сложные семплы из трейна (выбирали по лоссу обученной модели) и взяли SigLIP для выбора наиболее близкого цвета. Сделав несколько таких итераций очистки данных и дообучения модели, пришли к финальному скору — 0.76 F1.
Какие подходы не зашли и возможные причины для этого
Stack more layers.
Когда маленькая модель не справляется с задачей и упирается в потолок метрики, первое интуитивное желание — взять модель побольше. Однако, взяв даже ResNet50 и тем более ResNeXt, модели сразу же столкнулись с переобучением. Возможно, модели нашли связь между категорией объекта и наиболее часто встречающимся цветом для этой категории, что в целом неплохое предположение.
Unsupervised подходы и маппинг названий в цветовые коды.
Частым решением для задачи выделения основного цвета на изображении становится кластеризация — это логичный и формально доказуемый выбор. Однако далее встаёт вопрос сломанного телефона: человек сфотографировал на камеру смартфона объект, который потом сохранили в какую-то палитру на серверах Авито, и теперь его открываем мы, тоже декодируя в какой-то фиксированный набор значений. Всё это может и влияет на отображение цвета, делая самой сложной задачей определение соответствия между распределением значений пикселей на картинке и лингвистическим обозначением для этих цветов.
Протестировав несколько разных подходов, мы пришли к тому, что самый общий способ подбора трешхолдов для подобной формулировки задачи — это обучение нейросети для задачи классификации.
Кейс Т-Банка: Шоппинг ассистент
Т-Банк порадовал интересным и особенно актуальным в последнее время кейсом — предполагалось создать шопинг-ассистента, который помогает клиенту искать лучшие товары по оптимальным ценам и снижает когнитивную нагрузку в процессе подбора.
Целевая аудитория — платёжеспособные люди, которые часто заказывают товары онлайн, но хотят тратить на это меньше времени и сделать свой опыт онлайн-шопинга более «умным».
Вопреки распространённой стратегии «LLM ради LLM», аргументировали необходимость такого ассистента ребята из Т-Банка достаточно справедливо:
«Онлайн-шопинг развивается очень бурно, но из-за быстрого роста маркетплейсов начинает страдать клиентский опыт: накрученные отзывы, некачественные фото товаров, непонятное ценообразование, недоверие к скидкам и т. д. Отдельный пункт — это поиск товаров по жёстким фильтрам, когда для поиска идеального товара нужно углубляться в карточку и принимать решение, насколько товар подходит под критерии пользователя».
В итоге от команд ожидали самостоятельного ассистента, который способен:
-
Провести пользователя по сценарию «сбора корзины».
-
Объяснить результат подбора.
-
Подкорректировать результат на основе комментариев пользователя.
Варианты решений
Самое интересное, что в ТЗ не было строгих ограничений на область применения ассистента — участникам предлагались лишь примеры потенциально полезных решений:
-
Ассистент-стилист, который помогает собрать капсульный гардероб или подбирает несколько образов (с чем носить выбранный элемент одежды).
-
Ассистент-косметолог, подбирающий уход с учетом типа кожи и образа жизни.
-
Ассистент-нутрициолог, формирующий продуктовую корзину на основе КБЖУ и заданного бюджета.
Однако эти примеры были лишь ориентиром, а финальный выбор области применения ассистента оставался за участниками. Именно поэтому данный кейс стал настоящим пространством для экспериментов, позволяя командам проявить максимум креативности. В итоге участники представили множество разнообразных и интересных решений, используя необычные подходы — от генеративных моделей компьютерного зрения до интеллектуального и быстрого поиска по базе товаров.
Например, многие команды решили сосредоточиться на создании ассистентов, представленных в примере ТЗ. Самым распространённым вариантом был ассистент-стилист, собирательный образ которого подразумевал подбор лука под конкретный запрос, например: «Собери мне образ на деловую встречу». Самой яркой проблемой таких решений были тяжеловесные модели (об этом дальше), так как такой ассистент подбирал образы слишком долго. Однако в целом многие решения получились достаточно интересными, и другая команда-призёр реализовала именно такого ассистента.
Также было много решений в виде ассистента-помощника по выбору «всего». То есть подбор предложений к покупке проводился по всей базе товаров (например, с какого-нибудь маркетплейса) без специализации на конкретной области. Здесь получилось так, что, хотя ассистент и был более универсальным, с качеством рекомендаций товаров в конкретном домене и аргументацией выбора возникли проблемы, поскольку не хватало проработки решения для конкретной области.
А что мы?
Поскольку идей было очень много, мы решили оценивать их по следующим критериям:
-
Решение реальной проблемы пользователя. Можно сделать забавную болталку-косметолога, но какой от неё толк, если она не обладает необходимой экспертизой в данной области и не сможет дать пользователю персональные рекомендации, которым он будет доверять?
-
Встраивание в экосистему банка. Можно начать реализовывать приложение с нуля и искать новую аудиторию, а можно посмотреть, какие сервисы уже есть в банке, и какую боль пользователи испытывают при взаимодействии с ними. Вполне возможно, мы сможем найти точку оптимизации уже готового продукта с большой аудиторией, где и сможет помочь ассистент.
-
Целесообразность. Конечно, всем хочется поиграться с моделями на 70B+ параметров, но хочется ли пользователю ждать ответа десятки секунд, а банку — закупать дорогостоящее железо? Обдумав это, мы сразу сделали выбор в сторону легковесных моделей.
Собственно, 90% первоначальных идей не проходили какой-нибудь из этих трёх пунктов. Потратив где-то два дня драгоценного времени в поисках действительно стоящей концепции, мы наконец пришли, на наш взгляд, к действительно классной идее — ассистенту-помощнику для заказа еды.
Почему же мы решили сфокусироваться именно на подборе еды?
-
Во-первых, большинство из нас думают о том, что поесть минимум 3 раза в день. И зачастую этот выбор даётся нам не просто, мы тратим время и силы на размышления, казалось бы, о таком регулярном и рутинном действии. То есть проблема достаточно популярна.
-
Во-вторых, в приложении банка уже есть сервис для заказа еды, куда и можно было бы встроить нашего ассистента. Осталось только сделать достаточно быстрое, но, тем не менее, удобное для использования и полезное решение.
Боли и их решение
Какие текущие боли есть у людей, которые хотят выбрать и заказать еду?
Перегруженность: «Я хочу заказать X, настраиваю фильтры, и получаю X’, Y, X’’ — и только потом X».
А что, если можно лучше? Часто ли перед кнопкой «Заказать» у вас возникает чувство «А что если…?» А что, если я мог найти дешевле? А что, если я мог найти доставку быстрее? А что, если я мог найти вкуснее?
Из за этого мы тратим еще больше времени на выбор товаров, а возможно и не совершаем заказ вовсе.
Поэтому что мы решили делать в нашем прототипе:
-
Один запрос — один ответ. Пользователь пишет: «Я хочу X». Мы даём X. Всё.
-
Находим лучший товар за клиента. Анализируя вкусовые предпочтения, историю, цены, рейтинг товаров и многое другое, ассистент выбирает лучший товар для вас, аргументируя свой выбор, и делает это за несколько секунд.
А как под капотом?
Пайплайн подбора товаров под запрос пользователя выглядит следующим образом:
1. Выделение категории товара или конкретного товара.
Например, пользователь вводит: «Хочу что-нибудь поесть под фильм, и обязательно добавь колу».
На данном этапе агент выделит из запроса необходимые товары для пользователя: [‘Еда под фильм’, ‘Кола’].
2. Поиск кандидатов в базе знаний.
Для каждого из выделенных в первом пункте товаров (или же категорий) мы делаем текстовый поиск по нашей базе товаров. Считаем эмбеддинг товара из запроса и ищем наиболее похожие по косинусной близости товары в базе знаний, предварительно посчитав и сохранив эмбеддинги в векторную БД Faiss. Возвращаем топ N найденных кандидатов для каждого товара, в нашем случае N равнялось 10.
Пример:
Категория: ‘Еда под фильм’. Найденные товары:
-
Чипсы May’s, 140РР. Магазин «СнекМир», 4.95, 40 минут.
-
Орехи солёные, 200Р. Магазин «Пыжик», 4.80, 30 минут.
-
Попкорн карамельный, 120Р. Магазин «Радар», 4.70, 50 минут.
-
Сухарики ржаные, 90Р, Магазин «Перепутье», 4.85, 35 минут.
-
……….
-
Батончик сникерс, 250Р. Магазин «Шестёрочка+», 4.90, 45 минут.
В качестве модели поиска использовали sergeyzh/rubert-tiny-turbo — маленькую encoder-модель, так как поиск должен был быть быстрым. Качество, конечно, проседало в сравнении с, например, deepvk/USER-bge-m3, но модель мы не дообучали, а для прототипа на хакатоне качество поиска удовлетворяло.
3. Выбор наилучшего предложения.
Теперь из кандидатов нужно выбрать наиболее подходящий для пользователя товар. Отвечает за это отдельный агент, который анализирует:
-
Запрос пользователя и его текущие пожелания (‘побыстрее’, ‘подешевле’, ‘с высоким рейтингом’, …)
-
Суммаризированную историю диалога с пользователем в виде ключевых факторов (‘Не любит острое’, ‘Предпочитает вегетарианские блюда’, ….)
-
Характеристики товара — логично выбрать из двух товаров с одинаковой ценой тот, которой приедет быстрее или у которого выше рейтинг.
Теперь, выбрав один из товаров среди всех кандидатов в каждой категории, мы получаем финальную подборку, которую потом выдаем пользователю.
Для запроса «Хочу что нибудь поесть под фильм, и обязательно добавь колу», примером выдачи будет: [‘Чипсы May’s’, ‘Добрая Кола 1л’]
4. Аргументация выбора.
Важным фактором в построении системы с LLM является создание ассистента, которому пользователь будет доверять. В нашей системе дополнительный агент отвечает за аргументацию выбора конкретных продуктов, ибо доверять выбору «черной коробки» будет далеко не каждый.
Пример работы: для запроса «Хочу что нибудь поесть под фильм, и обязательно добавь колу», примером финальной генерации с аргументаций будет: «Конечно! Могу порекомендовать чипсы May’s, так этот товар обладает наибольшим рейтингом среди аналогов со схожей ценой, и освежающую “Добрая Кола”, так как вы заказывали этот товар уже 3 раза! Доставка займет 40 минут, а общая цена 420Р, оформить заказ?»
В качестве LLM для агентной системы мы использовали Gemma2-9b, но на середине хакатона вышло семейство моделей Gemma3, в частности на 4 миллиарда параметров. Её мы и стали использовать в финале, ибо так мы заметно уменьшали время работы, не сильно теряя в качестве.
В результате удалось оперативно создать качественный MVP. Анализ решений других команд, включая призёров и тех, кто не прошёл в финал, показал, что важно сосредотачиваться не на использовании трендовых технологий или моделей, а на их практическом применении, которое одновременно приносит радость пользователю и прибыль бизнесу.
Кейс от МТС: планировщик размещения виртуальных машин
Нам предстояло реализовать планировщик размещения виртуальных машин на физических серверах MWS Cloud Platform. Эффективный планировщик помогает минимизировать количество включённых хостов, снижая затраты на электроэнергию, а также поддерживать баланс между утилизацией и стабильностью работы инфраструктуры. Это снижает вероятность отказов в размещении ВМ и обеспечивает клиентам высокую доступность услуг.
Важной частью стратегии управления ресурсами является понимание того, как влияет утилизация хостов на их надёжность и эффективность. Оптимальной считается загрузка на уровне 80% — это обеспечивает хорошее использование оборудования без перегрузки. Если нагрузка превышает этот порог, вероятность выхода хостов из строя возрастает, что может привести к сбоям в работе облака. Выключенные хосты, в свою очередь, экономят электроэнергию.
Постановка задачи
Задачей было реализовать CLI-приложение, которое итеративно получает информацию о новых событиях и на выходе выдает новое распределение ВМ.
В первый раунд поступают данные о конфигурации хостов, их количестве, изначально они все пустые. Каждый раунд либо в систему поступает ровно одна новая ВМ с какой-то конфигурацией, либо из системы выходит одна ВМ. Для простоты задачи мы учитываем только два параметра конфигурации: количество ядер CPU и количество гигабайт RAM (целые числа).
Каждый раунд подсчитывается количество очков (баллов): чем их больше, тем эффективнее мы решили задачу.
Как начисляются баллы: для каждого хоста считается его утилизация (а она равна max из процента утилизации CPU и процента утилизации RAM), это число мы подаём в функцию расчёта очков. Её формулы и графика, к сожалению, у меня нет, но вот её свойства: при 0 % утилизации количество очков = 0, при росте утилизации к 80 % количество очков растёт до 10, это максимум. Далее при росте к 100 % количество очков падает к 3 баллам, то есть разместили ВМ-ки мы довольно оптимально, но это просто критично для нашей системы. Есть вероятность отказов, которую мы хотим минимизировать.
Также баллы можно получить за то, что мы в течение пяти раундов подряд оставляем хост свободным — то есть его можно выключить и это нам выгодно. Кроме того существовали и штрафы: если мы не можем разместить ВМ, теряем 5 * n_hosts баллов. Каждый раунд мы можем делать миграции (перемещения ВМок между хостами). Это может существенно улучшить утилизацию, разгрузить некоторые хосты, но делать миграции неудобно вычислительно для сервера, поэтому за m миграций за раунд мы получаем штраф m^2 баллов.
По поводу системных ограничений: задача будет тестироваться на ~100-1000 хостах. Для такого объёма нужно, чтобы алгоритм за n раундов отрабатывал примерно за n секунд. При этом ограничение по оперативной памяти < 2 GB. В целом ограничения довольно щадящие и дают достаточно простора для достаточно сложных алгоритмов. Легкие алгосы, основаные на эвристиках, отрабатывали в среднем в > 100 раз быстрее.
Анализ похожих проблем и их решений
Так как на хакатоне нужно было решить 5 кейсов (вместо одного, как обычно делают), нам хотелось как можно меньше париться над скучными кейсами и сделать упор на тех задачах, где мы могли показать класс. Изначально мы думали просто быстро закрыть кейс, подобрать какой-нибудь примитивный алгоритм-затычку и всё. Но в итоге получилось неплохое решение:)
Задача, которую мы рассматриваем, представитель задач типа bin packing problem.
Поискав проблемы, похожие на наши, мы нашли соревнование «the ROADEF/EURO challenge 2012». Пробовали взять какой-то готовый из коробки алгоритм, но, тем не менее, его нужно было адаптировать под наши условия задачи. Мы немного проанализировали их решения и постарались держать баланс между тем, чтобы получить оптимальное решение, и тем, чтобы не упороться в реализацию сложного алгоритма, на который у нас не было ни времени, ни сил.
Далее будут представлены решения, которые мы посчитали нужным реализовать, удерживая наш баланс))
BestFit
Это жадный алгоритм для решения задач упаковки, который:
-
Для каждого объекта (ВМ) выбирает хост с минимальным свободным ресурсом, достаточным для размещения.
-
Цель: минимизировать фрагментацию ресурсов и оптимизировать утилизацию хостов.
Алгоритм является субоптимальным и в целом послужил хорошим бейзлайном, который был быстро реализован. Важной частью задачи было реализовать механизм миграций. Я решил их делать только в самом крайнем случае, когда нет возможности аллоцировать ВМку. И это, по сути, тоже не сильно оптимально. Но при всём этом алгоритм отрабатывал очень быстро.

Тесты
Также важной частью в ходе построения решения были тесты. Их нужно было правильно реализовать и приблизить к реальным условиям.
Было сложно составить тесты, в которых проверялось, был ли ход самым оптимальным. Поэтому я как минимум реализовал проверки по типу: не потерялись ли ВМки случайно после раунда. Ну и сделали подсчёт очков, с помощью чего как раз можно сравнивать алгоритмы. ВМки в ходе каждого раунда сэмплировались случайным образом из равномерного распределения по каждой характеристике (RAM и CPU).
Кстати говоря, для приближения к реальным условиям это распределение можно было делать не равномерным, а, например, похожим на нормальное, или ещё можно делать смещения в сторону характеристик со степенями двойки (например, люди чаще выбирают 2, 4, 8 ядер, чем 1, 3, 5 или 7 ядер).
Генетический алгоритм
Генетический алгоритм — это метод оптимизации, имитирующий эволюцию:
-
Популяция решений (распределений ВМ) проходит отбор по качеству (утилизация, штрафы).
-
Лучшие решения скрещиваются и мутируют, создавая новые поколения, пока не будет найдено оптимальное распределение.
Определяя fitness-функцию (которая, по сути, оптимизируется при подборе следующего хода), мы как раз задаём, сколько баллов мы получим. Так мы оптимизируем напрямую баллы, которые получим за раунд.
Также удобно, что мы не думаем над тактикой миграций — алгоритм сам их подбирает и оценивает, что перевесит: штраф за миграции или очки за утилизацию, которые мы получим в результате миграции. В более крутых решениях, которые я находил, этот алгоритм ещё мешали с BestFit и добавляли некоторый постпроцессинг, но мы решили так сильно не углубляться.
По времени алгоритм отрабатывает, конечно, заметно дольше, чем BestFit (при более-менее оптимальных гиперпараметрах). При этом генетический алгоритм показал буст в ~40% очков от BestFit, что заметно круто.

RL
Также я попробовал ещё реализовать алгоритм на основе обучения с подкреплением. По сути, Reward-функция у меня была почти готова, за меня её описали организаторы, мне оставалось только описать пространство действий, состояний, в общем, описать environment.
К сожалению, времени на хакатоне оставалось не так много, поэтому я решил лишь протестировать гипотезу, будет ли хоть немного этот алгоритм решать нашу задачу. Взял для обучения алгоритма PPO (Proximal Policy Optimization) на простом MLP.
В целом алгоритм сходился и действительно неплохо отрабатывал, но его основной минус — вычислительная сложность: так как на вход может прийти любое количество хостов. Для разного n мне нужно было переобучать модель (для случая с MLP я не стал углубляться) и только потом начинать делать предикты для каждого раунда. В целом даже этого времени на инференс могло хватать в условиях нашей задачи.

В наше решение входило быстрое решение: BestFit. Более оптимальное и при этом не сильно медленное решение: генетический алгоритм. И незаконченное, но подающее надежды, решение: RL.
Кейс Сбера: планировщик
В этой задаче нам нужно было решить проблему планирования задач на проект.
На вход нам бросают кучу данных про проект: кто его будет делать, сколько стоит его время, какие задачи он может выполнять, какие задачи поставлены на проект, сколько они занимают времени, какие у них зависимости… На самом деле условие было не суперпонятным, нам просто дали данные без описания полей, структуры…И из этого всего нужно сложить календарик: определить, кто, когда и что будет делать. Ну просто мечта продакт-менеджера, нажал кнопочку, и всё готово.
Конечно же, календарь должен быть оптимизированным: по продолжительности работ и по затраченным деньгам.
Проблемы
В целом и так понятно, что проблем много: кроме большого количества данных, есть ещё столько же бизнес-требований, условий. Проблем добавляет и достаточно непонятная структура данных. Но если углубиться в задачу, становится понятно, что есть подводные камни (в целом организаторы их тоже выделили):
-
Учёт вложенных задач и подпроектов.
-
Генерация данных для обучения, которые соответствуют всем ограничениям.
-
Обработка сложных зависимостей между задачами.
-
Учёт индивидуальных календарей исполнителей.
Что же делать?
Что мы делаем, когда данные непонятны, непонятно, как решать задачу, непонятно, как учесть много разных условий и, самое главное, как назло, ещё и времени мало?
Подаём все эти данные в блэкбокс, и он сам там придумает, конечно же!
В общем, да, завели мы RL, описали среду, кое-как описали функцию награды, которую как раз можно двигать в зависимости от того, что нам важнее: деньги или время.
Алгоритм кое-как обучился, но у нас не было времени и возможностей качественно провалидировать наше решение, но так как мы заняли призовое место, видимо, мы сделали неплохо!)
Другие варианты
Кажется, можно было ещё попробовать завести генетический алгоритм, но с ходу мне показалось, что имплементировать его с такой кучей условий будет тяжко, так что решили отказаться от этой идеи.
Ребята из другой команды (тоже заняли призовое место, но ниже нас) попробовали подать все данные в LLM (надеюсь, конечно, в локально развёрнутую модель, в целях конфиденциальности). В итоге она сама составляла календарь и отправляла его. В целом, эту идею можно развить с помощью агентов.
Безопасный кейс от ArenaData
В условиях современного телекоммуникационного рынка безопасность пользователей становится первостепенной задачей.
Наш трек от компании ArenaData ставил цель — по данным абонента определить, используется ли его устройство для вредоносных целей, таких как спам-рассылка.
Задача оказалась сложнее, чем можно было предположить: стандартные методы анализа часто не справлялись с высоким уровнем «шумовых» данных, а ложные срабатывания могли приводить к неверной интерпретации ситуации.
Постановка задачи и первичные эксперименты
Первоначально мы тестировали классические ML-алгоритмы на агрегированных данных трафика и получали неутешительно плохие результаты. Так как взломанных юзеров в датасете было чрезвычайно мало, то старый добрый fit predict ни в какую не справлялся с поставленной задачей: или переобучался, или имел очень много ложных срабатываний (что очень плохо в домене задачи).
Тогда мы решили просто взглянуть на данные и найти что-нибудь интересное (интуиция подсказывала, что в синтетических данных будут какие-то явные закономерности, которые будут видны без какой-либо обработки данных). Так мы и пришли к нашему итоговому решению…
Наше решение: анализ временных точек
Было решено изменить подход и сфокусироваться на динамике трафика в конкретных временных точках. Для каждого абонента мы вычисляли количество моментов, когда исходящий трафик превышал входящий. Итоговый критерий был довольно прост: если таких точек оказалось больше шести за всю историю, предоставленную для пользователя, мы фиксировали факт возможного взлома устройства.
Такой алгоритм показал высокую эффективность — на тестовой выборке точность достигала почти 100%. Простота логики позволила не только быстро реализовать решение, но и обеспечила его интерпретируемость. Мы могли легко объяснить, почему именно данный критерий оказался оптимальным, а также оперативно адаптировать его под реальные условия работы телекоммуникационной компании.


Видно, что у взломанного абонента исходящий трафик(синий график) возносится над графиком входящего трафика практически на всей истории абонента.
Обзор альтернативных подходов и взгляд со стороны конкурентов
Интересно отметить, что многие команды на хакатоне делали ставку на сложные модели машинного обучения и нейронные сети. Такие методы могли учитывать большое количество параметров, но зачастую страдали от переобучения и требовали значительных вычислительных ресурсов для инференса. Некоторые участники пытались внедрить эвристические алгоритмы, похожие на наш, однако их решения не достигали нужного баланса между простотой и точностью.
Наш алгоритм, основанный на строгом логическом правиле, позволил добиться стабильного результата за короткое время. Он продемонстрировал, что иногда именно простота и ясность подхода могут принести успех, особенно в условиях хакатона, где время и ресурсы ограничены.
Размышления и дальнейшие шаги
Оглядываясь назад, можно сказать, что выбор нашего решения был продиктован не только техническими ограничениями, но и стремлением понять суть проблемы. Вопрос «Почему именно такое решение?» заставил нас задуматься: возможно, существует универсальный алгоритм, который объединяет простые логические подходы и методы машинного обучения? Если бы сегодня перед нами стояла аналогичная задача, мы рассмотрели бы возможность введения адаптивных пороговых значений, учитывающих специфику различных сегментов пользователей.
Также остаётся интригующим вопрос сравнения наших результатов с подходами конкурентов. Уникальность нашего метода заключается в его прозрачности — мы можем не только объяснить, что работает, но и понять, почему оно работает. Такой подход важен не только для достижения победы на хакатоне, но и для дальнейшего внедрения решения в реальных продуктах.
Кейс ArenaData стал для нас отличным примером того, как глубокий анализ временных характеристик трафика способен выявить вредоносные действия с высокой точностью. Мы убедились, что иногда простое, интуитивно понятное решение может оказаться более эффективным, чем сложные модели. Этот опыт не только принёс победу на хакатоне, но и открыл новые перспективы для дальнейших исследований и практических внедрений.
Автор: MaksKhan