Сохранение и использование модели

Сохранение обученной модели через joblib

Содержание курса

Схема признаков и метаданные версии: сохранение сопутствующих объектов

Когда LogisticRegression обучается на DataFrame со строковыми именами столбцов, sklearn сохраняет их в атрибуте feature_names_in_. Начиная с sklearn 1.2 несовпадение имён при predict поднимает ValueError; в версиях 1.0–1.1 то же самое могло завершиться лишь FutureWarning без остановки. Встроенная защита есть, но её поведение зависит от версии окружения.

Поэтому надёжнее иметь собственный явный контракт — отдельный файл с зафиксированным списком признаков. Схема — обычный словарь:

feature_schema = {'features': list(X_train.columns)}
joblib.dump(feature_schema, 'feature_schema.joblib')

list(X_train.columns) фиксирует порядок именно той версии X_train, на которой вызван fit. Для нашего проекта это ['distance_km', 'items_count', 'warehouse_load', 'forecast_rain_mm', 'is_weekend'] — ровно пять признаков, с которыми обучалась модель.

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

# пример проверки перед predict (тема следующего урока)
# assert list(X_new.columns) == feature_schema['features'], 'несовпадение схемы признаков'

Важно понимать: feature_schema.joblib десериализуется тем же механизмом joblib.load, что и сама модель — а значит, несёт те же риски при загрузке подменённого файла. Ожидаемый тип dict и небольшой размер не защищают от исполнения произвольного кода при десериализации. Загружать feature_schema.joblib безопасно только в том случае, если файл был создан вами же и его происхождение не вызывает сомнений. Сравнение списков признаков проверяет входные данные, но не безопасность самого файла — это разные задачи.

Второй сопутствующий файл — метаданные версии. Спустя месяц может быть неочевидно, какой версией sklearn обучена модель: sklearn иногда меняет численные алгоритмы между минорными версиями, и coef_ может незначительно отличаться. Зафиксированная версия позволяет сравнить окружения:

import sklearn

metadata = {
    'model_version': '1.0',
    'trained_on': 'deliveries_v1',
    'sklearn_version': sklearn.__version__
}
joblib.dump(metadata, 'metadata.joblib')

sklearn.__version__ — строка вида '1.4.2', она читается прямо в рантайме и гарантированно соответствует той версии, которая только что выполнила fit. Поле trained_on — произвольная метка датасета, чтобы было ясно, на каких данных обучалась модель.

Каждый из трёх объектов сохраняется отдельным вызовом joblib.dump в отдельный файл. На диске появляются model.joblib, feature_schema.joblib и metadata.joblib — три независимых артефакта, которые вместе описывают один обученный результат.