Suppose I have an XGBoost 0.90 model set up like so, using scikit-learn pipelines to do some preprocessing. I want to upgrade to XGBoost 1.0+ and still be able to use this model, without having to refit it.
import pandas as pd
import numpy as np
from sklearn_pandas import DataFrameMapper
from xgboost import XGBRegressor
from sklearn.preprocessing import FunctionTransformer, MinMaxScaler
from sklearn.pipeline import Pipeline
df = pd.DataFrame({
'a': [0.0, 45.0, 90.0, 135.0, 180.0, np.nan],
'b': [180.0, 135.0, 90.0, 45.0, 0.0, np.nan],
'y': [1.0, 3.0, 4.0 ,5.0 ,6.0 ,0.0]
})
pipeline = Pipeline([
('mapper', DataFrameMapper([
(['a', 'b'], [MinMaxScaler(feature_range=(0, 2*np.pi)), FunctionTransformer(np.cos)], ),
(['a', 'b'], [MinMaxScaler(feature_range=(0, 2*np.pi)), FunctionTransformer(np.sin)], )
])),
('regressor', XGBRegressor())
])
pipeline.fit(df[['a', 'b']], df['y'])
If I pickle the pipeline when I have XGBoost 0.90 installed, I can't load it when I subsequently have XGBoost 1.0+ installed. The XGBoost docs suggest that I should convert the 0.90 pickle using a script that they've provided:
The script is available here:
https://github.com/dmlc/xgboost/blob/master/doc/python/convert_090to100.py
However, this script only works for XGBoost Booster objects. So I've tried the following:
- Extract the model from my pipeline via
pipeline.named_steps.regressor(in an env with XGBoost 0.90 installed) - Pickle the model (still 0.90)
- Convert the pickle using the script (still 0.90)
- Load the model from the file produced by the script (in the new env with XGBoost 1.0+)
Now I'm a bit stuck though. How I can reassemble my pipeline using the mapper from my original 0.90 pickle and the booster loaded from the exported file?
UPDATE
Here's a bit more detail about how I saved and reloaded the booster:
First, I pickled the final estimator from the pipeline:
joblib.dump(pipeline._final_estimator, './final_estimator.pkl')
Next, I ran the conversion script on the pickle:
python3 convert_090to100.py --old-pickle final_estimator.pkl
Then I imported the file produced by the script:
final_estimator_reloaded = XGBRegressor()
final_estimator_reloaded.load_model('./xgboost_native_model_from_final_estimator.pkl-0.bin')
Then I produced a pipeline using this reloaded model and tried to produce predictions with it:
rebuilt_pipeline = Pipeline([
('mapper', pipeline[0]),
('regressor', final_estimator_reloaded)
])
rebuilt_pipeline.predict(df)
Further update: this worked after all.