Как обучать CatBoost на датасете, который не помещается в оперативную память?

«Как обучать CatBoost на датасете, который не помещается в оперативную память?» — вопрос из категории Деревья и ансамбли, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

CatBoost имеет встроенные механизмы для эффективной работы с большими данными. Вот стратегии, которые я применял на практике.

1. Использование встроенной обработки больших данных CatBoost может считывать данные прямо из файла, не загружая их полностью в память, с помощью класса Pool и метода from_file. Это основной метод.

from catboost import CatBoostClassifier, Pool

# Создание пула данных напрямую из CSV-файла
# CatBoost будет читать данные порциями
train_pool = Pool.from_file(
    'large_dataset.csv',
    delimiter=',',
    has_header=True,
    column_description='column_description.cd'  # Файл с указанием типов колонок
)

# Инициализация и обучение модели
model = CatBoostClassifier(
    iterations=1000,
    learning_rate=0.03,
    depth=8,
    verbose=100  # Вывод лога каждые 100 итераций
)

model.fit(train_pool)

2. Оптимизация формата данных

  • Категориальные признаки: Я всегда явно указываю CatBoost, какие признаки являются категориальными (через параметр cat_features или файл .cd). Это позволяет алгоритму обрабатывать их оптимально, не преобразуя в one-hot, что экономит память.
  • Собственный бинарный формат: Для максимальной скорости и экономии памяти можно конвертировать данные в собственный бинарный формат CatBoost с помощью утилиты catboost fit или метода save() объекта Pool, а затем загружать через Pool('data.cb').

3. Настройка параметров обучения Некоторые параметры напрямую влияют на потребление памяти и скорость:

model = CatBoostClassifier(
    iterations=2000,
    learning_rate=0.05,
    depth=10,  # Увеличение глубины увеличивает потребление памяти
    l2_leaf_reg=5,
    bootstrap_type='Bernoulli',  # 'Bernoulli' или 'Bayesian' для ускорения
    subsample=0.8,  # Обучение на подвыборке объектов в каждой итерации
    sampling_frequency='PerTree',  # или 'PerTreeLevel'
    boosting_type='Ordered',  # 'Ordered' точнее, но 'Plain' быстрее и требует меньше памяти
    task_type='GPU',  # КРИТИЧНО для больших данных. Использование GPU радикально ускоряет обучение.
    devices='0:1'  # Указание конкретных GPU
)

4. Стратегия "вне ядра" (Out-of-Core) для огромных данных Если даже поточное чтение не помогает, я разбиваю данные на несколько файлов и обучаю модель инкрементально, используя model.fit() на первом чанке, а затем model.fit() на следующих с параметром init_model.

# Псевдокод для инкрементального обучения
model = CatBoostClassifier(...)
for chunk_file in ['chunk_1.csv', 'chunk_2.csv', 'chunk_3.csv']:
    chunk_pool = Pool.from_file(chunk_file, ...)
    model.fit(chunk_pool, init_model=model)  # Продолжаем обучение существующей модели

Мой стандартный пайплайн: 1) Подготовить файл с описанием колонок (.cd), 2) Использовать Pool.from_file() для загрузки, 3) Включить task_type='GPU', 4) Настроить subsample и boosting_type='Plain' при нехватке памяти.