Давным‑давно, когда мир ML состоял из бустингов, линейных моделей и статистических подходов, перед нашей командой API Яндекс Карт стояла задача сделать качественный Геокодер. Это алгоритм, который конвертирует текстовые запросы пользователей в поисковой строке карт в координаты и обратно. Он нужен, когда люди вводят адреса с ошибками, опечатками или народными наименованиями, например «Мяснитская 8». Геокодер должен понять, что имелось в виду «улица Мясницкая, дом 8/2», и вернуть на карте отметку с точной локацией и координатами.

Разработанный для России Геокодер отлично справлялся, но мы хотели найти способ быстро адаптировать это решение к адресным системам других стран. Технологические ограничения не позволяли быстро адаптировать решение, поскольку для каждой страны требовалась разработка собственных правил геокодирования, которые бы учитывали различия и языковые особенности. Однако появление и развитие алгоритмов deep learning открыло новые горизонты: методы active learning, аугментации данных и contrastive learning позволяют значительно улучшить итоговое качество геокодирования и учитывать нюансы различных адресных систем.

В этой статье мы рассмотрим основные этапы и методы построения нового Геокодера, который быстро масштабируется на адресные системы разных стран. Расскажем, что у него под капотом, как именно использовались механизмы deep learning при его создании, с какими проблемами мы столкнулись и как научили его понимать адреса с ошибками и опечатками.

Задача геокодирования

В широком смысле технология геокодирования решает две задачи: прямого (поиск географических объектов по адресному запросу) и обратного геокодирования (поиск конкретного объекта по географическим координатам).

Задача обратного геокодирования тривиально решается с помощью R‑деревьев, KD‑деревьев или множества других алгоритмов индексации геопространственных данных. Поэтому далее пойдёт речь о задаче прямого геокодирования.

Пример работы сервиса геокодирования как чёрного ящика
Пример работы сервиса геокодирования как чёрного ящика

Геокодер используется и в поиске, в составе геопоиска, и как один из генераторов кандидатов для поисковой строки в сервисах такси и доставки еды, в ритейле и екоме, в сервисах аренды жилья, в логистике, и много где ещё. Но также это один из продуктов в семействе решений API Яндекс Карт.

О прошлом

Начиная с 2004 года технология геокодирования активно развивалась, но она была наиболее близка к классическим поисковым движкам до появления нейросетей. Она состояла из поиска по обратному индексу с множеством условий для обработки разных сценариев пользовательского запроса, отдельных сервисов для анализа самого запроса, сервиса исправления ошибок и ранкеров. Выглядит как что‑то, для поддержки чего нужно несколько команд.

Когда мы решили предоставлять возможности API Яндекс Карт зарубежным компаниям, стало ясно, что различий в практиках градостроения, культурных и поисковых особенностей столько, что работа по адаптации текущего инструмента геокодирования с целью доведения поиска адресов до нужного уровня качества будет крайне долгой и трудоёмкой. Например, в Северной Америке города нередко строятся по принципу прямоугольных кварталов или блоков, в странах Ближнего Востока распространено использование плюскодов, а в турецкой системе адресации конечная точка — не дом, как, например, в России, а подъезд.

Кроме того, появились новые функциональные требования: поиск по организациям, префиксные запросы, поддержка национальных языков и различных адресных систем.

Но технологии не стоят на месте, и стало возможным найти более эффективный метод улучшения поиска адресов в странах, где существуют иная адресная логика и лингвистические нюансы. Например, создать решение с использованием нейросетей, которое было бы лучше, проще и быстрее, и растить качество за счёт данных, в чём классические ML‑системы часто ограничены. Так, это возможно с помощью аугментации данных, использования подходов active learning и обучения на разных задачах.

Из плюсов нейросетевых подходов ещё можно отметить большую обобщающую способность. Как пример — модель геокодирования, обученная на данных пяти‑шести стран, может легко масштабироваться на другие страны за счёт распознавания базовых паттернов в структуре адресов разных стран. Ещё один плюс такого подхода — возможность сделать E2E‑решение без отдельных сервисов исправления ошибок (spell checker) и декомпозиции запроса.

Для тестирования решения мы выбрали Казахстан. Благодаря своей билингвальности местные запросы могут быть как на русском, так и на казахском языках, а ещё как с латинской, так и с русской транслитерацией, что позволяло проверить модель сразу в мультиязычном сетапе. Также частыми были дублирования названий улиц, районов и городов в разных областях Казахстана, что требует от модели более глубокого понимания контекста и пространственных связей. При этом работу по сбору обучающей выборки не пришлось бы делать с нуля, что, безусловно, ускоряло time‑to‑market.

Диаграмма последовательностей при взаимодействии пользователя с сервисом
Диаграмма последовательностей при взаимодействии пользователя с сервисом

Про метрику и данные 

Прежде чем углубиться в детали, давайте определим несколько ключевых терминов:

  • Топонимы — географические объекты разного рода (улицы, дома, район, город, лес, река и т. д.). Например, топоним улицы выглядит так: Москва, ул. Кантемировская.

  • Организация — сущность, аналогичная топониму, но в качестве листового элемента здесь представлена сама организация. Например, Санкт‑Петербург, Рижский проспект, 2, нотариус.

Итак, у нас есть постановка задачи. Но перед тем как решать её, надо было понять, как мы будем измерять качество и какие данные нам доступны — как для замеров, так и для обучения.

Мы решили идти по пути разработки поискового движка, где в основе метрик и обучения лежит понятие релевантности пары <запрос, документ>. Её мы рассчитывали исходя из бинарной асессорской разметки, которая также является прокси на реальный пользовательский сигнал.

При всех своих минусах и сложности поддержки такого подхода (асессоров надо проверять, они допускают ошибки, необходимы модераторы) ручная разметка позволяет учить модели в условиях холодного старта, когда единственное, что есть, — это дамп запросов от потенциальных клиентов. При этом важно находить компромисс между качеством разметки (чем сложнее задача, тем более зашумлённая разметка) и качеством системы. В нашем случае бинарная разметка релевантности стала таким компромиссом.

Запросы, для выдачи которых мы строим асессорскую разметку, делятся на два типа: запросы клиентов и семпл из логов сервисов. Первая сущность для нас — органический источник данных, позволяющий улучшить решение для конкретного клиента. А вторая сильно больше: эти данные мы используем, чтобы обогатить датасет множеством запросов, на которых обобщающая способность модели хуже или которые слабо представлены в клиентских логах. Спойлер: большая часть работ по улучшению моделей — это именно работа с данными.

В дополнение к асессорской разметке для обучения можно использовать генерацию релевантных запросов: как синтетическую, то есть по заданным правилам, так и с помощью LLM. Это вариация аугментации, которая позволяет кратно увеличить размер обучающей выборки.

В парах <запрос, документ> обучающей выборки есть важная деталь, которая влияет на качество данных, — это то, как мы синтезируем документы. Здесь задача состоит в том, чтобы максимально покрыть разнообразие запросов и в документе было представлено всё то, что с наибольшей вероятностью будет присутствовать в запросе. Поэтому документ содержит и синонимы, и мультиязычные вариации названия, и всю иерархию топонимов.

Пример аугментации документа
Пример аугментации документа

Помимо обучающей выборки, существование асессорской разметки упрощает дизайн метрики. В качестве неё мы использовали наличие релевантного/нерелевантного айтема в top k, где k = 1, 5, 10 (далее — rel@k, irrel@k). Однако даже двуградационная разметка при своей простоте и возможностях смещена и имеет процент ошибок. Это послужило основанием смотреть также на результаты ансамбля моделей, а не только единичных экземпляров. Для такой агрегации, к примеру, можно использовать reciprocal rank fusion (RRF).

В итоге у нас есть несколько источников данных, асессорская разметка пар <запрос, документ> и множество сгенерированных разными способами релевантных запросов для документов. И также есть простые, но довольно зашумлённые метрики.

Про архитектуру решения

Как зачастую бывает в современных поисковых движках, наше решение — n‑стадийное.

  • L1 — это retrieval‑часть

  • L2 — стадия для переранжирования топ‑N элементов и/или расчёта требуемых в ответе API атрибута матчинга документа и запроса. Например, насколько дом в документе совпадает с запросом — тот ли это корпус или соседнее здание.

Диаграмма последовательностей нового решения
Диаграмма последовательностей нового решения

Задача стадии L1 — закодировать запрос и документ в векторы таким образом, чтобы в дальнейшем, используя HNSW‑индекс, можно было найти топ‑N документов для того или иного запроса.

Процесс обучения L1 начинается с предобучения сетки, чтобы адаптировать домен модели к задаче геокодирования. Для претрейна мы используем contractive loss, чтобы она научилась отличать одну релевантную пару <запрос 1, документ 1> от другой <запрос 2, документ 2> в наборе таких пар (так называемые in‑batch negatives). При этом запросами в этих парах могут выступать как сгенерированные запросы для документа, так и релевантные пары из асессорской разметки.

Наличие этой стадии даёт возможность учить какую‑то нулевую версию модели совсем без данных — только на парах сгенерированных запросов и документов. Это полезно, когда мы разрабатываем Геокодер для страны, в которой у нас пока нет клиентов и логов наших сервисов мало — как следствие, асессорской разметки тоже нет. Стадия претрейна получается довольно массивной, тем не менее она улучшает итоговые метрики.

Процесс обучения retrieval-стадии (L1)
Процесс обучения retrieval-стадии (L1)

За стадией предобучения идёт finetune. Здесь мы используем поточечный подход из contrastive learning поверх только асессорской разметки, при этом близость <запрос 1, документ 1> должна соответствовать её меткам релевантности. Это достаточно быстрый этап, поэтому именно на нём мы зачастую проводим эксперименты над разными способами итеративного обучения и новыми источниками данных. Чуть больше про итеративное улучшение будет ниже.

Пример реранжирования на стадии L2
Пример реранжирования на стадии L2

Задача стадии L2 — переранжировать топ‑N выдачи из стадии L1 за счёт раннего связывания пары <запрос, документ> и оставить только наиболее релевантные документы. Эту задачу можно решать как бинарную классификацию или как задачу ранжирования на имеющейся асессорской разметке.

Помимо этого, на стадии L2 мы учимся проставлять документу и запросу уровень сопоставления (house precision). Наличие house precision помогает нашим партнёрам понимать точность геокодирования. Ведь топоним в выдаче может относиться к той же улице, что и запрос, но не относиться к запрашиваемому дому или же топоним может быть корпусом запрашиваемого дома.

Эту задачу мы решаем как классификацию раннего связывания пары <запрос 1, документ 1> на pseudo‑labeling разметке, построенной на основе отношений документов в датасете асессорской разметки. Например, если мы проставляем запросу «Рыскулбекова, 30» и релевантному документу «Алматы, улица Рыскулбекова, дом 30» метку exact (точное совпадение вплоть до номера дома), мы аугментируем обучающую выборку для этого запроса документами вида «Алматы, улица Рыскулбекова, дом 28/8» и ставим этой паре метку near (дом находится на той же улице, но у него другой номер). Таким образом, мы имеем только постановку задачи, но за неимением обучающей выборки сгенерировали её зашумлённый аналог для обучения на целевой задаче.

Для стадий L1 и L2 мы используем BERT‑like модели размерности примерно с multilingual‑roberta‑base. Это позволяет нам удерживать косты на инференсе.

Про итеративное улучшение

Рассмотренное выше лишь описывает архитектуру сервиса, но не отвечает на вопрос, как за счёт данных растить качество модели. Ответ можно поделить на три части.

Во‑первых, с помощью использования подходов из active learning. В нашем случае лучше всего себя показал подход, когда мы отправляем на разметку такие пары <запрос, документ>, на которых ансамбль моделей, обученный на чуть разных выборках, показал, что эта пара находится на топовых позициях и ещё не размечена.

Ансамбль позволяет не уйти в feedback loop конкретной модели и улучшать ситуацию в целом, получая баланс между exploration и exploitation. Этот процесс — основной именно для итеративного улучшения качества. Он почти целиком автоматизирован и требует минимальных усилий в плане поддержки.

Процесс итеративной доразметки данных
Процесс итеративной доразметки данных

Во‑вторых, нам помогает доразметка запросов из логов, похожих на те, у которых в обучающей выборке наибольшая ошибка. Зачастую в выдаче по ним либо нет контента, либо это то, что мы искали, и на них мы можем улучшить обобщающую способность модели и её качество. При этом поиск запросов в логах и их разметка помогают на ранней стадии, когда разметки для какой‑то страны нет, но логи уже есть.

В‑третьих, мы применяем аугментацию запросов и документов. В NLP аугментация слабо применима, но простая транслитерация помогает поддерживать другие языки для названий и других имён собственных в условиях, когда контент этого сделать не может.

Пример аугментации запроса
Пример аугментации запроса

Что в итоге

  • От огромного набора сервисов и моделей осталось две стадии: L1 и L2, разработка которых ведётся независимо.

  • Развитием и поддержкой всей системы занимается одна команда из пяти ML‑инженеров.

  • Теперь мы можем за короткое время (буквально за пару недель) выпустить модель геокодирования для новой страны, где ещё нет логов сервисов и клиентов.

  • Нам удалось добиться лучшего качества по сравнению с существующим решением: +14% rel@1 и −18% has‑irrel@10. И это только в Казахстане, где существующее решение уже было на уровне рынка.

  • А ещё в Казахстане мы вплотную подошли к эмпирически выведенному максимуму качества геокодирования.

  • Стало проще поддерживать национальные языки: запрос «Түркістан облысы Келес ауданы Сыртав 2» отлично матчится с «улица Сыртаева Ережепа, 2, село Кошкарата, Келесский район, Туркестанская область».

  • Мы реализовали поддержку саджестовых и полных запросов. Например, Геокодер может обработать даже недописанный запрос «Кызылорда, ул.».

  • Качество моделей можно итеративно прокачивать за счёт обогащения обучающей выборки.

Что же дальше? Теперь мы ставим перед собой такие цели:

  • Обучение geo‑foundation модели для всех стран. То есть мы планируем для всех стран заменить pretrain‑стадию на одну foundation model. Это сводит к нулю стоимость запуска в новой стране, а также сильно упрощает пайплайн обучения для конкретной страны, требуя лишь дообучения модели.

  • Замена L2 в inference на что‑то менее ресурсоёмкое. Достичь этого можно за счёт использования ColBERT или дистилляции L2 в L1 на этапе обучения.

  • Реализация условной генерации запросов для pretrain‑стадии за счёт RL‑based подходов (PPO, DPO). Например, это пригодится в ситуациях, если нам не хватает в обучающей выборке запросов на местных диалектах или префиксных запросов. Это большое направление, в которое мы хотим инвестировать ресурсы, потому что LM‑генерация позволяет искусственно обогатить обучающую выборку для того среза запросов, где это необходимо.

  • Использование явного пользовательского сигнала (explicit feedback) из логов как дополнительный источник данных.

  • При необходимости деплоить модель на новые страны.


В этой статье я постарался показать, что использовать и дообучать нейросети на свои задачи намного легче, чем кажется. Даже для задач information retrieval есть foundation‑модели типа e5, которые несложно адаптировать под свои нужды. При этом улучшать модель может выйти дешевле и проще, чем решение аналогичной задачи методами классического ML.

В конце хочется сказать спасибо команде: Николай Приходько @neird, Иван Дубровин @iod-ine, Маргарита Улитина @tarataratita и Мария Акопян @mariaakopyan

Комментарии (4)


  1. ivantgam
    28.01.2025 13:27

    Здорово, надо бы попробовать завести ваш геокодер в своей проект. Nominatim/Photon довольно часто промахиваются


    1. aliffka_93 Автор
      28.01.2025 13:27

      Будем только рады фидбэку)


  1. Basters
    28.01.2025 13:27

    Спасибо, очень интересно было увидеть, как на самом деле это все организовано под капотом!

    Вопрос касательно упомянутых различий форматом адресов в разных странах.
    Можете подсказать где почитать, какие проекты посмотреть, чтобы постараться увидеть как можно больше различий и решений по хранению адресов? Как раз сейчас на проекте работаем над тем, что нужно хранить адреса, которые могут быть адресом любой страны/села.
    Пытаемся учесть все подводные камни.


    1. aliffka_93 Автор
      28.01.2025 13:27

      У нас команда ML инженеров и нам база топонимов приходит уже как готовый собранный json, и у нас есть отдельная небольшая команда картографов, которая как раз помогает в составлении справочника топонимов и выступает экспертами в этой сфере.

      Если имеете ввиду структуру адресов в разных странах и дизайн БД то я бы посоветовал

      • поспрашивать у gpt-like систем с разными переводами одного и того же промпта

      • посмотреть в отрытых базах типа osm, как организованы топонимы. Там эта информация точно есть. Можно отсемплировать по стране по 200-500 топонимов и пройтись глазами, а также собрать статистику по тегам в OSM XML.

      • использовать системы аля поиска с gpt под капотом аля яндекс-нейро или perplexity. Очень помогает как раз для первоначального ресерча в некоторой сфере.