Другое

Полное руководство по исправлению ошибки sklearn2pmml XGBoost classes_

Решение ошибки параметра classes_ в sklearn2pmml XGBoost при создании PMML-файлов. Узнайте причины, решения и лучшие практики для успешного преобразования модели.

Как решить ошибку sklearn2pmml с параметром ‘classes_’ при создании PMML из модели XGBoost?

Я столкнулся с ошибкой при попытке создать PMML-файл из модели XGBoost с использованием sklearn2pmml. Вот мой код:

python
from sklearn.preprocessing import LabelEncoder
y_h_train = LabelEncoder().fit_transform(y_train.copy(deep=True))

modele_label_encoded = model.fit(X_train, y_h_train)

import sklearn2pmml as skpmml
from sklearn2pmml import PMMLPipeline, sklearn2pmml

cols_used = list(X_train.columns)
pmml_model = skpmml.make_pmml_pipeline(modele_label_encoded)
pmml_model.active_fields = cols_used
pmml_model.target_fields = ['Target']
skpmml.sklearn2pmml(pmml_model, os.path.join('test.pmml'), debug=True)

Однако я получаю следующую ошибку:

Exception in thread "main" java.lang.IllegalArgumentException: The value of 'xgboost.sklearn.XGBClassifier.classes_' attribute (null) is not a supported array type

Я проверил, что моя модель имеет атрибут classes_ с правильным типом массива:

python
modele_label_encoded.classes_
Output: array([0, 1])

Несмотря на наличие правильного типа массива, sklearn2pmml все равно выдает эту ошибку. Кто-нибудь сталкивался с этой проблемой раньше и нашел решение?

Ошибка sklearn2pmml с параметром ‘classes_’ при создании PMML из моделей XGBoost обычно возникает из-за несовместимости версий между XGBoost и sklearn2pmml, или проблем с тем, как атрибут classes_ доступен для конвертера PMML на базе Java. Эта ошибка происходит, несмотря на то, что модель Python имеет правильный атрибут classes_, что указывает на проблему сериализации или преобразования типов.

Содержание

Понимание ошибки

Сообщение об ошибке java.lang.IllegalArgumentException: The value of 'xgboost.sklearn.XGBClassifier.classes_' attribute (null) is not a supported array type указывает на то, что хотя ваша модель XGBoost в Python имеет правильно установленный атрибут classes_, конвертер PMML на базе Java не может правильно получить доступ или преобразовать этот атрибут.

Как сообщают пользователи Stack Overflow, это обычно не проблема на уровне Python, а проблема сериализации между компонентами Python и Java. Конвертер ожидает, что атрибут classes_ будет доступен в определенном формате, который может обработать среда Java.

Ключевое наблюдение: Ошибка возникает в процессе преобразования PMML на базе Java, а не во время обучения модели Python, что объясняет, почему ваша модель, похоже, имеет правильный атрибут classes_ в Python.

Основные причины

1. Проблемы с атрибутом Label Encoder

Наиболее распространенной причиной является проблема с атрибутом _le (label encoder) в XGBClassifier. Согласно GitHub issue #197, проблема часто возникает из-за:

java.lang.IllegalArgumentException: Attribute 'xgboost.sklearn.XGBClassifier._le' has an unsupported value (Python class sklearn.preprocessing._label.LabelEncoder)

Это происходит, потому что sklearn2pmml ожидает, что label encoder будет определенного типа, но более новые версии XGBoost могут использовать разные реализации внутреннего label encoder.

2. Проблемы с декораторами домена

Другая частая проблема связана с тем, что декораторы домена не настроены должным образом. Как упоминается в GitHub issue #278:

java.lang.IllegalArgumentException: The value of 'sklearn2pmml.decoration.ContinuousDomain.data_min_' attribute (null) is not a supported array type

Эта ошибка указывает на то, что декораторы домена нужно настроить перед преобразованием.

3. Проблемы преобразования типов массивов

Исследования показывают, что существуют проблемы преобразования типов между массивами Python и коллекциями Java. Из GitHub issue #16:

java.lang.ClassCastException: numpy.core.NDArray cannot be cast to java.util.List

Это указывает на то, что процесс преобразования не удается при попытке преобразовать массивы numpy в совместимые с Java структуры данных.

Проблемы совместимости версий

Результаты исследований последовательно указывают на проблемы совместимости версий как на основную причину:

Совместимость версий XGBoost

  • Переход от XGBoost 1.2.X к 1.3.X: Как отмечено в исследованиях, этот конкретный переход версий связан с характерными сообщениями об исключениях
  • Ожидания пакета: Пакет sklearn2pmml ожидает, что label encoder (атрибут XGBClassifier._le) будет “обычным” классом label encoder Scikit-Learn, но более новые версии XGBoost могут использовать разные реализации

Требования к версиям sklearn2pmml

  • Поддерживаемые пакеты: На момент sklearn2pmml 0.84(.2), пакеты LightGBM и XGBoost перечислены как поддерживаемые, но проблемы совместимости все еще сохраняются
  • Поддержка функций: Пакет может не полностью поддерживать все функции XGBoost или может иметь конкретные требования для определенных конфигураций моделей

Решения и обходные пути

Решение 1: Понижение версии

Если вы используете XGBoost 1.3.X, рассмотрите возможность понижения до XGBoost 1.2.X. Согласно исследованиям, переход с 1.2.X на 1.3.X связан с характерными сообщениями об исключениях, которые вы видите.

python
# Установка совместимой версии XGBoost
!pip install xgboost==1.2.1

Решение 2: Использование оберток sklearn2pmml

Создайте обертку, которая явно обрабатывает атрибут classes_:

python
from sklearn2pmml import sklearn2pmml
from sklearn2pmml.decoration import CategoricalDomain, ContinuousDomain
from sklearn2pmml.pipeline import PMMLPipeline
import sklearn2pmml as skpmml

# Создайте конвейер с явными декораторами домена
cols_used = list(X_train.columns)

# Настройте декораторы домена при необходимости
domain_features = {}
for col in cols_used:
    if X_train[col].dtype == 'object':
        domain_features[col] = CategoricalDomain()
    else:
        domain_features[col] = ContinuousDomain()

pmml_model = PMMLPipeline([
    ("classifier", modele_label_encoded)
])

# Установите активные и целевые поля
pmml_model.active_fields = cols_used
pmml_model.target_fields = ['Target']

# Настройте конвейер с декораторами домена
pmml_model.fit(X_train, y_h_train)

# Преобразуйте в PMML
skpmml.sklearn2pmml(pmml_model, 'test.pmml', debug=True)

Решение 3: Ручная настройка Label Encoder

Как предлагается в исследованиях, убедитесь, что ваша настройка label encoder соответствует ожиданиям sklearn2pmml:

python
from sklearn.preprocessing import LabelEncoder
from xgboost import XGBClassifier

# Создайте и настройте label encoder отдельно
le = LabelEncoder()
y_h_train = le.fit_transform(y_train.copy(deep=True))

# Создайте и настройте модель
modele_label_encoded = XGBClassifier()
modele_label_encoded.fit(X_train, y_h_train)

# Проверьте, что атрибут classes_ существует и правильный
print(f"Classes: {modele_label_encoded.classes_}")
print(f"Classes label encoder: {le.classes_}")

# Создайте конвейер PMML
pmml_model = skpmml.make_pmml_pipeline(modele_label_encoded)
pmml_model.active_fields = cols_used
pmml_model.target_fields = ['Target']

skpmml.sklearn2pmml(pmml_model, 'test.pmml', debug=True)

Решение 4: Использование PMMLPipeline напрямую

Вместо использования make_pmml_pipeline, создайте конвейер PMML более явно:

python
from sklearn2pmml import PMMLPipeline
from sklearn2pmml.decoration import ContinuousDomain

# Создайте явный конвейер
pipeline = PMMLPipeline([
    ("classifier", modele_label_encoded)
])

# Настройте конвейер
pipeline.active_fields = cols_used
pipeline.target_fields = ['Target']

# Настройте и преобразуйте
pipeline.fit(X_train, y_h_train)
skpmml.sklearn2pmml(pipeline, 'test.pmml', debug=True)

Лучшие практики

1. Проверка совместимости модели

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

python
# Проверьте, имеет ли модель необходимые атрибуты
print(f"Has classes_: {hasattr(modele_label_encoded, 'classes_')}")
print(f"Classes type: {type(modele_label_encoded.classes_)}")
print(f"Classes shape: {modele_label_encoded.classes_.shape}")

# Дополнительные проверки для label encoder
print(f"Has _le: {hasattr(modele_label_encoded, '_le')}")
if hasattr(modele_label_encoded, '_le'):
    print(f"_le type: {type(modele_label_encoded._le)}")

2. Тестирование с простыми моделями

Всегда тестируйте преобразование с простой моделью сначала, чтобы изолировать проблему:

python
# Создайте простую тестовую модель
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier

X_test, y_test = make_classification(n_samples=100, n_features=4, n_classes=2, random_state=42)
test_model = RandomForestClassifier(random_state=42)
test_model.fit(X_test, y_test)

# Протестируйте преобразование
test_pipeline = PMMLPipeline([("classifier", test_model)])
skpmml.sklearn2pmml(test_pipeline, 'test_model.pmml', debug=True)

3. Использование режима отладки

Всегда используйте режим отладки при устранении неполадок:

python
skpmml.sklearn2pmml(pmml_model, 'test.pmml', debug=True)

Это предоставляет подробную информацию об ошибках, которая может помочь определить коренную причину.

Альтернативные подходы

1. Использование других инструментов преобразования PMML

Если sklearn2pmml продолжает давать сбой, рассмотрите альтернативные инструменты преобразования PMML:

  • JPMML-Sklearn: Основная Java-библиотека, которую обертывает sklearn2pmml
  • ONNX Runtime: Сначала преобразуйте в формат ONNX, затем в PMML
  • Пользовательская генерация PMML: Напишите код для пользовательской генерации PMML

2. Переключение на альтернативные модели

Если проблемы совместимости с XGBoost сохраняются, рассмотрите использование нативно поддерживаемых моделей:

python
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression

# Используйте нативно поддерживаемые модели
model = RandomForestClassifier(random_state=42)
# или
model = LogisticRegression(random_state=42)

3. Обновление до последних версий

Иногда обновление до последних стабильных версий обоих пакетов решает проблемы совместимости:

python
!pip install --upgrade sklearn2pmml xgboost

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

Заключение

Ошибка sklearn2pmml ‘classes_’ с моделями XGBoost в основном вызвана несовместимостью версий между XGBoost и sklearn2pmml, или проблемами с тем, как Java-конвертер обращается к атрибутам модели Python. Ключевые выводы включают:

  1. Совместимость версий имеет решающее значение - Переход с XGBoost 1.2.X на 1.3.X особенно проблематичен
  2. Проблемы с label encoder распространены - Атрибут _le часто вызывает проблемы сериализации
  3. Декораторы домена нуждаются в правильной настройке - Убедитесь, что все декораторы настроены перед преобразованием
  4. Режим отладки предоставляет ценную информацию - Используйте debug=True для получения подробных сообщений об ошибках
  5. Могут потребоваться альтернативные подходы - Рассмотрите другие инструменты или модели, если проблемы сохраняются

Для немедленного решения попробуйте понизить версию XGBoost до 1.2.X или используйте явное построение конвейера PMML с правильно настроенными декораторами домена. Если проблемы продолжаются, рассмотрите альтернативные инструменты преобразования PMML или временно переключитесь на нативно поддерживаемые модели, такие как RandomForest.

Источники

  1. Stack Overflow - Error writing XGBoost Classifier to pmml with sklearn2pmml
  2. GitHub Issue #265 - Attribute ‘xgboost.sklearn.XGBClassifier._le’ not set
  3. GitHub Issue #278 - XGBoost to PMML fails for unknown reason
  4. GitHub Issue #197 - Attribute ‘xgboost.sklearn.XGBClassifier._le’ has an unsupported value
  5. GitHub Issue #16 - XGBClassifier wrapper failing to convert
  6. Stack Overflow - sklearn2pmML error with pycaret model to PMML
Авторы
Проверено модерацией
Модерация