От хакерства к гармонии структурирование правил продукта в рекомендациях

From hacking to harmony structuring product rules in recommendations

Не позволяйте эвристикам подрывать ваше машинное обучение, научитесь их комбинировать

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

Например:

  • Нельзя слишком часто рекомендовать треки от одного и того же исполнителя;
  • Необходимо включать контент из подписок в ленту, но не перегружать ее;
  • Если пользователь уже не понравилась определенная категория или автор, связанный контент должен быть наказан или даже исключен;
  • Нельзя рекомендовать эксплицитный контент — за исключением случаев, когда это уместно.
Фото от Cam Bradford на Unsplash

Правила бывают двух типов: жесткие и мягкие. Жесткие правила действуют как фильтры, запрещая определенные документы быть рекомендованными в конкретных контекстах; несоблюдение считается ошибкой продукта. В этих правилах нет ничего плохого, но их количество должно быть ограничено. Более того, они должны применяться как можно раньше в процессе ранжирования, либо на стадии генерации кандидатов, либо даже при построении индекса. Мягкие правила, с другой стороны, больше похожи на руководства: вы можете рекомендовать такие элементы, но желательно не слишком много (или наоборот, чем больше, тем лучше). Слишком много таких мягких правил может затруднить отладку и разработку системы.

Правила — это технический долг.

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

На протяжении своей карьеры я часто сталкивался с повторяющимся шаблоном. Команда инженеров борется с обучением системы таким образом, чтобы получить хорошие рекомендации (в целом или в конкретных аспектах). Затем команда продукта прибегает к тому, что они знают лучше всего — добавлению новых правил. Такие патчи оправданы, когда требуются быстрые исправления, но их трудно удалить позже. Система часто остается в таком запатченном состоянии до тех пор, пока не произойдет крупная рефакторинговая работа, похожая на обычный технический долг.

Мораль истории — не экономьте на найме квалифицированных инженеров 🙂

В идеальной системе не должно быть таких правил; вся нечеткая логика должна обрабатываться достаточно совершенной моделью. Я мечтаю о том, что когда-нибудь мы достигнем этого технологического состояния (и у меня есть гипотеза о том, как это достичь). Однако, на данный момент это не реалистично. Вместо полного запрета таких правил, я расскажу о подходе, который позволяет организовать и ограничить хаос.

Структурированный подход: Каркас переранжировки

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

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

Вот основные принципы подхода.

  1. Результаты генерируются итеративно, начиная с первой позиции и заканчивая последней. На каждой итерации мы выбираем наиболее подходящий документ для предстоящей позиции. Так работает большинство стратегий переранжировки, таких как широко известный DPP для диверсификации. Для нелинейных выходов позиции могут быть ранжированы по важности.
  2. На каждой итерации мы берем все оставшиеся документы и сортируем их по функции значения. Это может быть что-то простое, например, результат модели вероятности клика, или что-то более сложное: комбинация различных выходов моделей (или нескольких моделей), предсказывающих различные события, компоненты разнообразия (такие как сходство с предыдущими документами) и ручные усиления и т.д. Функция значения может быть пересчитана на каждой итерации и, следовательно, может зависеть как от позиции, так и от документов, уже находящихся в конечном выводе. Она должна быть вычислительно эффективной. Создание правильной функции значения является самостоятельной темой; каркас не ограничивает или упрощает этот аспект.
  3. Продуктовые правила выражаются следующим образом: в пределах подмножества позиций X, количество документов с свойством f должно быть выше или ниже определенного порога C. Обычно X является диапазоном начальных позиций, таких как от 1 до 10 (первая страница). Свойство f лучше всего выражается как правило-порог некоторой функции, т.е. [feature(doc) > threshold]. При необходимости этот формат может быть обобщен для включения не бинарных свойств.
  4. Правила имеют приоритет. Если мы не можем удовлетворить все правила, мы отбрасываем наименее важные. Более точно: если самое важное правило достижимо в данной позиции, оно будет наверняка применено; в противном случ

    Вот несколько примеров правил в этом формате:

    • По крайней мере половина документов во всем выводе должна быть подписками. Однако, если все документы из подписок уже были прочитаны, это правило становится невыполнимым и будет отброшено.
    • Количество документов низкого качества в первых 10 позициях не должно превышать 2.
    • Между позициями 10 и 20 должен быть хотя бы один документ из новой категории.

    Стоит отметить, что правила вроде “по крайней мере 5 документов с определенным свойством должны находиться в первых 10 позициях” могут привести к тому, что первые 5 позиций заполнятся документами, не обладающими этим свойством, а затем следуют 5 с ним. Чтобы сделать это более равномерным, можно добавить правила для промежуточных диапазонов: по крайней мере 1 в первых 2 позициях, по крайней мере 2 в первых 4 и так далее.

    Реализация этой структуры эффективно является хорошим испытанием, но полностью выполнимой. Вот набросок кода на Python, чтобы проиллюстрировать, как можно реализовать описанную структуру повторной оценки. Имейте в виду, что это не оптимизировано для эффективности, но должно дать хорошую отправную точку.

    def rerank(documents, count, rules, scorer):    result = []    while len(result) < count and len(documents) > 0:        position = len(result)        candidates = documents        for rule in rules:            filtered = [doc for doc in candidates if rule(position, doc)]            if len(filtered) > 0:                candidates = filtered        next_doc = max(candidates, key=lambda doc: scorer(position, doc))        result.append(next_doc)        documents.remove(next_doc)        scorer.update(position, next_doc)        for rule in rules:            rule.update(position, next_doc)    return result

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

    Как мы видели, система рекомендаций без правил остается больше идеалом, чем реальностью на данный момент. Но это не означает, что мы застряли в хаосе. Хорошо структурированная структура для управления правилами может дать вам необходимую организацию, не подавляя потенциал системы.