В этой статье хочу рассказать о задаче с которой мы столкнулись и о найденном решении. Надеюсь наш опыт окажется кому-то полезен и натолкнет на решение других подобных задач.
Если вкратце, то в рамках нашей работы по созданию RAG-системы нового поколения перед нами встала фундаментальная задача — необходимость точной временной привязки документов, событий и фактов. В естественном языке временные представления крайне разнообразны: от точных дат до нечетких описаний вроде «в начале прошлого года» или «через пару недель». Для эффективного поиска и анализа было необходимо универсальное решение, способное обрабатывать это многообразие и переводить его в форму, пригодную для машинного использования.
Изначально эмбеддинги больших языковых моделей казались подходящими кандидатами — очень хорошо определяли семантическое сходство временных выражений, однако их использование выявило ряд существенных недостатков. Во-первых, они не специализированы для временных представлений и потому избыточны, кодируя множество ненужных для данной задачи семантических признаков. Во-вторых, скорость их работы была неудовлетворительной для высоконагруженных приложений. Локальное использование предъявляло высокие требования к «железу». Мы обратили внимание на более компактные модели, такие как BART-base, но и здесь столкнулись с проблемами: размерность эмбеддинга в 768 измерений все еще была избыточной, а качество связности временных признаков для разных языков (в нашем случае русского и английского) оказалось низким. Это привело нас к выводу о необходимости разработки собственной специализированной модели.
Подход к разработке: контрастное обучение и специализированная архитектура
В качестве основы для TimeCoder мы выбрали трансформерную архитектуру типа encoder-decoder и подход на основе контрастного обучения (contrastive learning). Его цель — построить векторное пространство, в котором семантически близкие временные выражения будут иметь близкие по косинусному расстоянию эмбеддинги, а семантически далекие — наоборот.
Для обучения был создан датасет из 370 тысяч триплетов формата (якорь, позитив, негатив). В качестве якоря и позитива выступали семантически эквивалентные выражения («прошлый месяц» и «предыдущий месяц»), в том числе на английском языке («last week» и «прошлая неделя»). Негативный пример представлял собой семантически нерелевантное выражение. Около 60% датасета было сгенерировано с помощью LLM с частичной ручной проверкой качества + аугментация, остальное — синтетика.
Обучение проводилось с использованием взвешенной комбинированной функции потерь (contrastive loss + triplet loss), минимизирующей расстояние для позитивных пар и максимизирующей для негативных. Она показала лучше результаты по сравнению с чистой contrastive loss.
Один из ключевых аспектов — размерность эмбеддинга. В ходе экспериментов мы установили, что размерность 160 является оптимальной. Уменьшение этого значения (например, до 128) приводило к заметной деградации качества модели (на 4-5%), в то время как дальнейшее увеличение не давало существенного прироста точности, но повышало вычислительные затраты. Возможно для более узкой формулировки задачи размерность можно было бы еще уменьшить, но мы старались максимально широко охватить семантику временных представлений, чтобы получить универсальное решение.
Обучение проводилось на GPU RTX 5090 и заняло в сумме вместе с экспериментами около 37 часов машинного времени.
Сравнительный анализ производительности и качества
Мы провели сравнительный анализ TimeCoder с моделью BART-base, оценивая два ключевых параметра: скорость генерации эмбеддингов и качество представления временных данных. Тесты проводились на задаче генерации 1000 эмбеддингов на GPU среднего класса (RTX 2060).
Производительность:
TimeCoder: 286 эмбеддингов/сек.
BART-base: 248 эмбеддингов/сек.
TimeCoder показал прирост производительности на 15%, что является критичным для систем, работающих в режиме реального времени.
Качество (средняя косинусная схожесть для семантически близких пар):
TimeCoder: 0.9232
BART-base: 0.7858
Наиболее существенное различие проявилось на билингвальных парах. Если на монолингвальных русских данных модели показывали сопоставимые результаты, то на русско-английских парах точность BART-base падала до 0.55–0.65. TimeCoder, благодаря специализированному обучению на двуязычных триплетах, продемонстрировал стабильно высокое качество, что подтвердило правильность выбранного подхода.
Также стоит отметить, что размерность эмбеддингов TimeCoder составляет 160 против 768 у BART-base.
От эмбеддингов к практике: экстрактор временных признаков
Эмбеддинги, полученные от TimeCoder, хорошо подходят для задач семантического сравнения, но для фильтрации данных по временным диапазонам их недостаточно. Сырой эмбеддинг инкапсулирует признаки в неявном виде, и для практических запросов («события до X даты», «в интервале Y-Z») требуется явное извлечение временных атрибутов.
Для этой цели мы разработали вторую нейронную сеть — экстрактор. Это легковесная multitask-модель на основе полносвязных слоев, которая принимает на вход 160-мерный эмбеддинг TimeCoder и предсказывает вероятностные распределения для года, месяца и дня. Для обучения использовалась функция потерь на основе KL-дивергенции, что позволило модели работать с «мягкими» вероятностями и адекватно представлять нечеткие понятия, например, «начало месяца» (распределяя вероятность по первым числам).
Экстрактор продемонстрировал высокую точность на тестовой выборке:
Год: 1.0
Месяц: 0.9985
День: 0.9884
Не абсолютная точность метрик по месяцу и дню в отличие от года объясняется особенностями использованных примеров, которые для этих классов содержали нечеткие временные выражения и периоды, распределенные по нескольким значениям, а потому абсолютная точность здесь вряд-ли достижима.
Полученный итоговый результат подтверждает, что эмбеддинги TimeCoder содержат всю необходимую для декодирования информацию о времени, что делает их применимыми для построения сложных запросов.
Интеграция и сценарии использования
Связка «TimeCoder + экстрактор» позволяет реализовать следующие сценарии:
Фильтрация данных: Преобразование пользовательского запроса («события за прошлый квартал») в вероятностные распределения по датам для последующего применения в SQL/NoSQL запросах к индексированным полям.
Поиск по временным периодам: Генерация распределений для интервалов («между январем и мартом») и их сравнение с датами документов через вероятностные метрики.
Аналитика в реальном времени: Быстрое кодирование потока событий для фильтрации и агрегации данных на лету.
Подход является масштабируемым: по аналогии можно создавать экстракторы для других временных атрибутов, таких как время суток, сезоны или длительность, открывая возможности для применения в IoT, логистике и других NLP-приложениях.
Заключение
В заключении можно отметить, что достигнутый результат мы считаем достаточно качественным для экспериментального применения, но от идеального он пока еще далек. В частности, предстоит большая работа по повышению качества созданного датасета. Несмотря на частичную ручную фильтрацию результатов генерации с помощью LLM, в нем по прежнему остается немало артефактов, обусловленное не очень высокой производительностью использованных для генерации LLM. Также есть дисбаланс по классам временных выражений, который нужно выравнивать.
Еще предстоит работа по созданию дополнительных экстракторов для декодирования других временных признаков и написание библиотеки по их использованию.
Надеюсь наш опыт окажется кому-то полезным, буду рад ответить на возникшие вопросы.