Пример 1. Обучение и сохранение модели

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

Для воспроизводимости важно сохранять весь процесс обработки признаков вместе с моделью.

Рассмотрим сохранение Pipeline, включающего масштабирование и классификатор.

Реализация на Python:

import joblib

from sklearn.datasets import make_classification

from sklearn.model_selection import train_test_split

from sklearn.pipeline import make_pipeline

from sklearn.preprocessing import StandardScaler

from sklearn.linear_model import LogisticRegression

from sklearn.metrics import accuracy_score

 

X, y = make_classification(

    n_samples=300,

    n_features=4,

    n_informative=3,

    n_redundant=0,

    random_state=42

)

 

X_train, X_test, y_train, y_test = train_test_split(

    X, y,

    test_size=0.2,

    stratify=y,

    random_state=42

)

 

model = make_pipeline(

    StandardScaler(),

    LogisticRegression(max_iter=1000)

)

 

model.fit(X_train, y_train)

 

accuracy = accuracy_score(

    y_test,

    model.predict(X_test)

)

 

artifact = {

    "model": model,

    "version": "1.0",

    "feature_names": [

        "feature_1",

        "feature_2",

        "feature_3",

        "feature_4"

    ],

    "test_accuracy": accuracy

}

 

joblib.dump(artifact, "model_v1.joblib")

 

loaded = joblib.load("model_v1.joblib")

 

prediction = loaded["model"].predict(X_test[:1])

 

print("Версия:", loaded["version"])

print("Точность:", round(loaded["test_accuracy"], 3))

print("Прогноз:", prediction)

Результат:

Модель сохраняется в файл model_v1.joblib, а затем загружается для выполнения прогноза.

Вместе с моделью сохраняются версия, названия признаков и значение тестовой метрики.

Загружать файлы joblib следует только из доверенных источников, поскольку их десериализация может выполнять произвольный код.

Пример 2. Проверка JSON-запроса перед прогнозированием

В лекции рассматривается пример API, который получает JSON с признаками, проверяет схему, выполняет тот же Pipeline и возвращает прогноз вместе с версией модели.

Если структура запроса не соответствует ожидаемой схеме, запрос должен отклоняться.

Реализация на Python:

import joblib

import numpy as np

 

artifact = joblib.load("model_v1.joblib")

 

def predict_request(request):

    expected = artifact["feature_names"]

 

    if set(request.keys()) != set(expected):

        raise ValueError("Неверная схема признаков")

 

    values = [request[name] for name in expected]

 

    if any(

        isinstance(value, bool)

        or not isinstance(value, (int, float))

        or not np.isfinite(value)

        for value in values

    ):

        raise ValueError("Признаки должны быть конечными числами")

 

    X = np.array([values], dtype=float)

 

    prediction = artifact["model"].predict(X)[0]

 

    return {

        "prediction": int(prediction),

        "model_version": artifact["version"]

    }

 

request = {

    "feature_1": 1.2,

    "feature_2": 0.5,

    "feature_3": -0.3,

    "feature_4": 2.0

}

 

print(predict_request(request))

Результат:

Функция возвращает словарь с прогнозом и версией модели.

Если в запросе отсутствует необходимый признак или передан лишний признак, возникает ошибка.

В реальном API такая проверка выполняется до обращения к модели. Пример показывает логику обработки запроса, а не запуск отдельного HTTP-сервера.

Пример 3. Обнаружение изменения распределения признаков

После внедрения модели необходимо отслеживать изменения входных данных.

Data drift — изменение распределения признаков по сравнению с данными, использованными при разработке модели.

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

Реализация на Python:

import numpy as np

 

rng = np.random.default_rng(42)

 

train_feature = rng.normal(

    loc=50,

    scale=10,

    size=1000

)

 

current_feature = rng.normal(

    loc=60,

    scale=10,

    size=1000

)

 

train_mean = np.mean(train_feature)

current_mean = np.mean(current_feature)

 

difference = abs(current_mean - train_mean)

 

threshold = 5.0

 

print("Среднее при обучении:", round(train_mean, 2))

print("Текущее среднее:", round(current_mean, 2))

print("Изменение:", round(difference, 2))

 

if difference > threshold:

    print("Обнаружено существенное изменение")

else:

    print("Существенное изменение не обнаружено")

В примере среднее значение признака изменилось примерно с 50 до 60.

Программа обнаруживает это изменение с помощью простого порогового правила.

Такой способ является учебной иллюстрацией мониторинга, а не универсальным статистическим критерием data drift. В реальной системе необходимо анализировать распределения признаков и качество модели после появления истинных меток.