Всем привет. Меня зовут Станислав Кириллов, я работаю в команде, которая отвечает за развитие библиотеки машинного обучения CatBoost. Мы впервые поделились ей с сообществом четыре года назад — хотя мы привыкли строить бинарные деревья, поэтому и отсчёт лет предпочитаем вести так же. Это шутка, конечно, но «столетие» — хороший повод для выпуска первой «production ready» версии библиотеки с символичным номером 1.0.0.

Сегодня я кратко отвечу, почему мы считаем выпуск версии 1.0.0 важной вехой, и подсвечу главные изменения (и в новой версии, и в целом за год). А уже завтра выступлю с рассказом на встрече, которая будет целиком и полностью посвящена практике применения CatBoost и противостоянию нейросетей и градиентного бустинга. Если эти слова для вас что-то значат, то добро пожаловать под кат.



Чуть-чуть предыстории.

CatBoost — это метод машинного обучения, который основан на градиентном бустинге и разработан нами так, чтобы одинаково хорошо работать «из коробки» как с числовыми признаками, так и с категориальными (отсюда и название — ни один котик при разработке не пострадал). Мы изначально создавали его как библиотеку для применения в сервисах Яндекса, отсюда характерные для большой компании требования. К примеру, у наших сервисов всегда высокие нагрузки, поэтому скорость инференса модели критична для CatBoost.

После выкладки технологии в опенсорс эти и другие особенности оказались востребованы не только у нас. Началась работа с сообществом и коллегами по индустрии. Так изначально внутрияндексовое решение, созданное нами без оглядки на других, коммит за коммитом, версия за версией (а их, на минуточку, вышло 76 штук) стало обрастать полезными доработками, исправлениями, инструментами.

Начинали мы с малого. Несколько лет назад даже в Яндексе область применения библиотеки была небольшой. Сейчас CatBoost применяется в большинстве наших сервисов: от ранжирования и рекомендаций музыки до прогнозирования осадков и беспилотных автомобилей. Во внешнем мире мы не только накопили 6 тысяч звёздочек на гитхабе (что тоже немало), но и встречаем CatBoost в проектах сторонних компаний, таких как Авито, Ламода, Сбер, Cloudflare.


Просто снимок главной сцены WWDC 2018

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

Быстрее, ещё быстрее


Все 4 года, что CatBoost находится в открытом доступе, мы не перестаём ускорять обучение. На графике ниже как раз пример такого прогресса за 2,5 года на примере датасета higgs при обучении 100 деревьев в 28 потоков.



В релизе 1.0.0 мы ускоряем время обучения в режиме бинарной классификации на CPU от 15% до 35%. Помимо этого, с марта 2020 года до текущего релиза мы ускорили CatBoost в 1,7 раза. Это были как алгоритмические, так и технические ускорения. Например, при помощи команды разработчиков из Intel мы улучшили масштабирование по потокам и тем самым ускорили обучение CatBoost на машинах со 128-ю ядрами почти в 2 раза.

Распределённое обучение на терабайтах данных


Когда мы говорим про обучение на больших данных на кластерах, первая технология, которая приходит на ум, — Apache Spark. На самом деле возможность распределённого обучения была доступна в CatBoost ещё с 2018 года, но пользоваться ей было не очень привычно и удобно. Поэтому возможность запуска распределённого обучения с помощью привычных интерфейсов, таких как Apache Spark, была одной из самых запрашиваемых функций.

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

Помимо этого, мы исправили ещё несколько критических проблем — считаем поддержку Apache Spark готовой к использованию в продакшен-процессах.

CPU vs GPU


В CatBoost есть 2 способа учить модели: на CPU и на GPU, однако у этих процессоров почти независимые реализации бустинга, а наборы возможностей немного отличаются. За последний год по набору функций и по качеству обучения мы наконец приблизили их друг к другу.

В частности, мы поддержали:

  • регулировку размера формулы, которая штрафует слишком дорогие по размеру вычисляемые признаки,
  • применение моделей на GPU в Python,
  • новый способ сэмплировать данные — Minimal Variance Sampling (придуман нашими исследователями, почитать можно здесь),
  • и ещё одну идею наших исследователей: обучение с динамикой Ланжевана (подробнее здесь), что позволяет учить модели, способные предсказывать неопределённость своих предсказаний.

Открытая документация


Раньше документация была написана в DITA с очень неудобным форматом в XML. С докой было много мелких проблем: неудобная визуализация параметров, невозможность настройки прочих эстетических вещей. Вылезали и существенные недостатки:

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

Сейчас мы перешли на удобный и привычный во всем опенсорс-сообществе Markdown. Исходники документации появились в нашем репозитории, а внешние контрибьюторы теперь тоже могут что-то поменять. Дока стала красивой и удобной: мы отказались от таблиц в вёрстке, сделали более прозрачную навигацию.

Но это ещё не финал. Впереди у нас большая работа по актуализации и внесению неописанных фич.

Multilabel-классификация


Появился режим multilabel-классификации. Представьте, что у ваших объектов есть возможный набор меток, каждому объекту может быть проставлено несколько таких меток, и вам нужно по объекту предсказывать, какие метки ему проставлены. В CatBoost 1.0.0 мы ввели такую фичу — например, она может быть полезна в поведенческом анализе для предсказания возможных характеристик объекта.

R — на полпути в CRAN


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

Сейчас наша цель — появление CatBoost в библиотеке пакетов CRAN. На пути к этому мы уже починили бóльшую часть проблем, но, к сожалению, успели сделать не всё. Здесь мы очень ждём помощи контрибьюторов, которым небезразлична судьба R.



С одной стороны, версия 1.0.0 — важный этап для всего проекта. А с другой, хочется верить, что это лишь начало длинного и интересного пути.

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


  1. Cost_Estimator
    01.10.2021 16:34

    Спасибо за то, что развиваетесь. Сейчас как раз на кегле обкатываю вашу модель с разными параметрами. С оставшимся временем какие-то скачки, в чем может быть дело?

    model = CatBoostRegressor()


    1. PythonAnalyst
      03.10.2021 19:16

      В качестве предположения: возможно у вас есть сильно коррелирующие фичи и CatBoost делает гигантские шаги (поскольку производная практически равна 0), на которых при "небольшом" относительном промахе получается сильное отдаление от итоговой точки.


      1. Cost_Estimator
        03.10.2021 19:24

        Не совсем понял, при чем тут скачки времени, оставшегося до окончания перекрестной проверки?


    1. kizill Автор
      03.10.2021 20:25

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


      1. Cost_Estimator
        03.10.2021 20:36

        grid = {'iterations': [500],
                'leaf_estimation_iterations': [10],
                'learning_rate': [0.03, 0.1, 0.5],
                'depth': [4, 6, 10],
                'l2_leaf_reg': [1, 3, 5, 7, 9]}


        1. kizill Автор
          04.10.2021 11:12

          'depth': [4, 6, 10],

          Дело вот в этом - время растет нелинейно с глубиной, так как число листьев, которые нужно подсчитать это 2^{depth}, поэтому оценка тут может ошибаться из-за того, что некоторые прогоны в разы длиннее других.


          1. Cost_Estimator
            04.10.2021 11:18

            Фух. Спасибо, так будет проще планировать выполнение задачи. А то ж на kaggle ограничение в 9 часов.


  1. vba
    25.10.2021 11:09

    И встал Айболит, побежал Айболит.
    По полям, но лесам, по лугам он бежит.
    И одно только слово твердит Айболит:
    «Julia, Julia, Julia!»

    Скажите у вас в планах есть поддержка Julia? Если так, то когда же? И как там с поддержкой .NET?