- BrainTools - https://www.braintools.ru -
Главная проблема поиска сотрудников — предвзятость. Порой кажется, что наше резюме подходит под свою роль на 100 %, а рекрутер отклоняет его. Проблема с противоположной стороны баррикад: рекрутер должен отсмотреть по 200, 300 и более резюме в день. По разным данным, на каждое уходит всего лишь 6–10 секунд.
А что если можно решить эти две проблемы с помощью ML? Сделать модель, которая исключит любой байес и поможет рекрутеру объективно отбирать подходящих кандидатов (где «подходящесть» обусловлена красивой математикой [1]!).
Мы это сделали. Оказалось, что если вы хотите добиться непредвзятости, то вам придётся внести в систему предвзятость. Оксюморон в статистике!
Что мы увидели:
Но давайте начну с начала.
Для Росатома нужно нанимать много людей: сейчас мы уже много чего сделали для отрасли в направлении HR Tech: собрали базу данных по кандидатам, развернули карьерный портал. Про функционал внутри него сегодня и пойдёт речь.
Мы увидели проблему: уходит какое-то нереальное количество времени на попытки понять, что в резюме кандидата совпадает с требованиями, а что — нет. Эйчары даже прикалывались, что если они ищут кандидата в своей базе, то нужно посмотреть 100 резюме, а если на Хедхантере — всего 10.
Так появился проект по прикручиванию ML-модели к внутренней базе кандидатов Skillaz для ранжирования резюме по степени сходства с требованиями.
История с алгоритмом Amazon 2018 года [2], который дискриминировал женщин при отборе кандидатов, стала хрестоматийным примером рисков непрозрачных алгоритмов. Прежде чем приступать к оценке, мы обсудили базовые этические принципы:
Заказчики:
Источником данных была наша внутренняя система Skillaz. В ней около 20 NoSQL-таблиц, описывающих заявки, кандидатов и их статусы в воронке. Информация поступала из нескольких каналов: интеграции с HeadHunter, единого карьерного портала Росатома, и немного дополнительных источников.
Проблемы начались сразу. Во-первых, не было подробного документа по структуре данных и связям между сущностями. Пришлось постоянно дёргать коллег из HR, чтобы разобраться, и параллельно самим документировать всё на ходу. Во-вторых, качество данных сильно разнилось. Резюме с HH и портала были чистыми и структурированными. А вот ручные загрузки — часто это просто текст без какого-либо шаблона.
Самой серьёзной проблемой при обработке текстовых полей резюме оказалось отсутствие единого шаблона. Люди разных профессий пишут резюме совершенно по-разному. Некоторые используют стандартные шаблоны с сайтов интернет-рекрутмента, но очень часто встречаются резюме, созданные с помощью сайтов «сделай мне красиво», которые невозможно нормально обрабатывать и разбивать на сущности. А ещё встречается откровенный мусор, о котором — ниже.
Для очистки пришлось применять стандартный набор:
Критерии выбирали сами, без глубокой валидации, кроме контрольной выборки для тестов: её вычистили до блеска.
Как ранжировать — это был один из самых сложных моментов. По «похожести»? По вероятности найма?
После долгих обсуждений мы решили опираться на историю продвижения кандидата по воронке. В нашей базе используются статусы и связанное с ними поле order (число от 1 до 18, чем выше — тем дальше кандидат прошёл). Однако использовать бинарную метку (принят/не принят) по эталонным статусам не получилось: данных мало, классы несбалансированы, а статусы вели не всегда аккуратно.

Мы решили нормализовать значение поля order в диапазон [0, 1] и поставили задачу регрессии: предсказать это значение для каждой пары «заявка — резюме». Чем больше значение, тем выше кандидат в итоговом списке.
Мы начали с TF-IDF (Term Frequency-Inverse Document Frequency) — базового метода обработки текстов. Он представляет резюме и заявку как наборы слов, взвешивая каждое по его важности: слово тем важнее, чем чаще оно встречается в этом документе, но реже — во всех остальных документах базы. Это позволяет выделить ключевые термины. Хотя этот метод не понимает смысла или синонимов, он быстрый и часто даёт неплохой старт.
Процесс выглядел так:
Стандартный способ формирования словаря — просто отсечь слишком частые и слишком редкие слова — показал себя плохо. В итоговом словаре оставались названия компаний, городов и всего того, из-за чего модель запоминала не навыки кандидатов, а конкретные компании. Мы пошли другим путём: выбрали только те слова (токены), частота которых коррелировала (положительно или отрицательно) с нашей целевой переменной (order). В результате это дало гораздо более чистый и релевантный словарь.

Полнота базы данных характеристик кандидатов

Полнота базы данных характеристик заявок

Полнота базы данных характеристик вакансий
Эти подходы дали какое-то базовое качество, но оно всё ещё заставляло желать лучшего. Особенно для сложных случаев, где важен не просто набор ключевых слов, а их смысл и контекст. Мы искали универсальное решение, работающее на разных типах вакансий и резюме, а TF-IDF был слишком поверхностным.
BERT-архитектуры
Нужно было научить систему понимать нюансы языка, распознавать синонимы и улавливать контекст. Например, что «ML Engineer» и «Инженер по машинному обучению» — это одно и то же, чего TF-IDF не поймёт. Мы двинулись к трансформерам, в частности, к моделям на основе BERT (Bidirectional Encoder Representations from Transformers). Это большие нейросети, предварительно обученные на гигантских объёмах текстов (Википедия, книги и т. д.). Они умеют улавливать семантические связи между словами и превращать тексты в векторы (эмбеддинги), которые отражают их смысл.
Мы попробовали разные подходы: Multilingual E5, TinyBERT, BGE-M3 и другие, ориентируясь на те, что хорошо работают с русским языком (например, по бенчмаркам encodechka).
Baseline (просто эмбеддинги). Для начала проверили, даёт ли сама по себе семантика BERT прирост по сравнению с TF-IDF. Взяли предобученную модель, получили эмбеддинги для резюме и заявки, сравнили их косинусным сходством.
Feature Extraction. Затем попробовали использовать эмбеддинги от BERT как входные признаки для XGBoost/CatBoost. Идея была в том, чтобы совместить глубокое понимание текста от нейросети с мощностью градиентного бустинга для предсказания order.
Cross Encoder (прямое сравнение парой). Подавали сцепленный текст (например, «[CLS] текст заявки [SEP] текст резюме [SEP]») прямо на вход BERT, чтобы модель сразу училась оценивать релевантность этой пары. Этот подход обычно самый точный, но он оказался слишком медленным для нашей задачи из-за большой длины резюме и заявок.
MLP поверх эмбеддингов. Получали отдельные эмбеддинги для заявки и резюме с помощью BERT, объединяли их и подавали на вход простого многослойного перцептрона, который уже предсказывал скор order.
Сиамские сети (Sentence-BERT) с Triplet Loss. Этот элегантный подход эффективен при поиске по большой базе и подходит для задач поиска и сравнения. Мы обучали две идентичные BERT-модели (сиамские близнецы) так, чтобы они генерировали эмбеддинги, где релевантные пары (подходящее резюме для заявки) располагались близко в векторном пространстве, а нерелевантные — далеко друг от друга. При дообучении BERT-моделей мы использовали техники вроде заморозки части слоёв (чтобы обучать только верхние слои: это быстрее и требует меньше ресурсов) и подбирали планировщик скорости обучения [5] (learning rate scheduler, например, для AdamW), чтобы оно было стабильным. Из-за ограничения на длину текста (многие BERT-модели принимают до 512 токенов) мы подбирали модели, работающие до 2 048 токенов, чтобы охватить большинство резюме и заявок.
Экспериментов было много. Чтобы не потеряться, использовали MLOps-платформу ClearML: логировали все параметры, метрики и артефакты каждого эксперимента, используя систему тегов для фильтрации (bert, tfidf, cb, feature_extraction и т. д.).
Когда пришло время выбирать финальную модель, нужно было убедиться, что она будет работать быстро и стабильно в реальных условиях. Мы перевели лучшие модели в формат ONNX, запаковали их в Docker-контейнеры с такими же ограничениями ресурсов, как на проде, и провели нагрузочное тестирование с помощью Locust. Это помогло понять реальную производительность и требования к инфраструктуре.
После всех тестов и сравнений по нашей кастомной метрике лучшим компромиссом между качеством понимания текста, скоростью работы и ресурсоёмкостью оказалась архитектура на основе дообученного Tiny Sentence BERT с небольшим MLP поверх эмбеддингов. Она достаточно хорошо понимала семантику, работала быстро и создавала не слишком большие эмбеддинги, что было удобно для хранения и поиска.
Стандартные метрики ранжирования нам не подошли, т. к.:
Мы разработали свою метрику, которую внутренне назвали SmartAdaptPrecision@K. Наша метрика сравнивает топ предсказанных и топ эталонных кандидатов, но обходит проблему ничьих. Если у нескольких кандидатов одинаковый ранг, то метрика не просто тупо считает совпадения, а аналитически вычисляет вероятность совпадения, учитывая количество кандидатов с одинаковыми рангами.
Это делает оценку стабильной: каждый запуск выдаёт один и тот же результат, даже если кандидаты с равными баллами случайно меняются местами. Результат нормализуется от нуля до единицы с помощью стандартной min-max-нормализации. Чем ближе результат к единице — тем точнее модель отражает истинное ранжирование рейтинга кандидатов.
Разработав и обучив модель, мы перешли к сравнению её с людьми. Сделали так:
Получилось так, что наша моделька в среднем отработала чуть хуже, чем HR-специалист в своей категории: модель — 78 %, профильный HR из отрасли — 84 %. Но модель показала себя лучше, чем средний кадровик на чужой территории, где точность не превышает 70 %. Другими словами, модель не превосходит узкого специалиста на его поле, но стабильно держит хороший уровень по всем направлениям и помогает там, где у человека нет глубокой экспертизы. Это подтверждает её ценность.
Сейчас HR-рутина автоматизирована, и система исправно выдаёт рекомендацию в виде ранга подходящих кандидатов из внутренней базы. Сейчас модель пока стоит «немножко сбоку» от основной базы данных, из-за этого пользоваться ею не очень удобно. Но полноценная интеграция — впереди.
Мы собираем обратную связь от HR. Массовую аналитику и ROI будем считать после полной интеграции, когда системой начнут активно пользоваться. Но первые отзывы — позитивные: рекрутеры отмечают, что стало проще находить релевантных кандидатов и сократилось время подбора — не кардинально, но ощутимо. Точные цифры обязательно приведём в следующей статье, когда отработаем на больших данных.
Теперь думаем над тем, как всё это улучшить. Вот наш ту-ду-лист:
Если у вас был опыт [6] внедрения похожих систем — расскажите: что ждёт нас дальше? Что у вас сработало, а что — нет? Какие подводные камни появились после интеграции? Мы будем рады обсудить это в комментариях.
Автор: ksidorov
Источник [7]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/16292
URLs in this post:
[1] математикой: http://www.braintools.ru/article/7620
[2] с алгоритмом Amazon 2018 года: https://vc.ru/hr/47756-reuters-amazon-razrabotala-ii-dlya-poiska-sotrudnikov-i-otkazalas-ot-nego-iz-za-diskriminacii-zhenshin
[3] ошибку: http://www.braintools.ru/article/4192
[4] внимание: http://www.braintools.ru/article/7595
[5] обучения: http://www.braintools.ru/article/5125
[6] опыт: http://www.braintools.ru/article/6952
[7] Источник: https://habr.com/ru/companies/greenatom/articles/917546/?utm_campaign=917546&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.