Model-logging for "hybrid models" (e.g. SKlearn Pipeline including KerasWrapper) possible?

Viewed 1470

I have wrapped my keras-tf-model into a Sklearn Pipeline, which also does some pre- and postprocessing. I want to serialize this model and capture its dependencies via MLflow.

I have tried mlflow.keras.save_model(), which seems not appropriate. (it's not a "pure" keras model and as no save() attribute)

I also tried mlflow.sklearn.save_model() and mlflow.pyfunc.save_model(), which both lead my to the same error:

NotImplementedError: numpy() is only available when eager execution is enabled.

(This error seems to stem from a clash between python and tensorflow, maybe?)

I wonder, should it already/ generally be possible to serialize these kind of "hybrid" models with mlflow?

Please finde a minimal example below

# In[1]:


from mlflow.sklearn import save_model
import mlflow.sklearn
from sklearn.datasets import load_iris
from sklearn import tree

from tensorflow.keras.models import Sequential

import numpy as np

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder

from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam


# ### Save Keras Model

# In[2]:


iris_data = load_iris() 

x = iris_data.data
y_ = iris_data.target.reshape(-1, 1)

# One Hot encode the class labels
encoder = OneHotEncoder(sparse=False)
y = encoder.fit_transform(y_)

# Split the data for training and testing
train_x, test_x, train_y, test_y = train_test_split(x, y, test_size=0.20)

# Build the model
model = Sequential()

model.add(Dense(10, input_shape=(4,), activation='relu', name='fc1'))
model.add(Dense(10, activation='relu', name='fc2'))
model.add(Dense(3, activation='softmax', name='output'))

optimizer = Adam(lr=0.001)
model.compile(optimizer, loss='categorical_crossentropy', metrics=['accuracy'])

# Train the model
model.fit(train_x, train_y, verbose=2, batch_size=5, epochs=20)


# In[3]:


import mlflow.keras

mlflow.keras.save_model(model, "modelstorage/model40")


# ### Save Minimal SKlearn-Pipeline (with Keras)

# In[4]:


from category_encoders.target_encoder import TargetEncoder
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from keras.wrappers.scikit_learn import KerasClassifier


# In[5]:


def define_model():
    """
    Create fully connected network with given parameters.
    """
    keras_model = Sequential()

    keras_model.add(Dense(10, input_shape=(4,), activation='relu', name='fc1'))
    keras_model.add(Dense(10, activation='relu', name='fc2'))
    keras_model.add(Dense(3, activation='softmax', name='output'))

    optimizer = Adam(lr=0.001)
    keras_model.compile(optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
    return model


# In[6]:


# target_encoder = TargetEncoder() 
scaler = StandardScaler()
keras_model = KerasClassifier(define_model, batch_size=5, epochs=20)


# In[7]:


pipeline = Pipeline([
#     ('encoding', target_encoder),
    ('scaling', scaler),
    ('modeling', keras_model)
])


# In[8]:


pipeline.fit(train_x, train_y)


# In[9]:


mlflow.keras.save_model(pipeline, "modelstorage/model42")   #not working


# In[10]:


import mlflow.sklearn

mlflow.sklearn.save_model(pipeline, "modelstorage/model43")

Output from modelstorage/model43/conda.yaml:

======================
channels:
- defaults
dependencies:
- python=3.6.7
- scikit-learn=0.21.2
- pip:
  - mlflow
  - cloudpickle==1.2.1
name: mlflow-env
======================

Doesn't seem to capture Tensorflow.
1 Answers

You can add extra dependencies when you save your model, for example if you have a keras step in your pipeline you can add keras & tensorflow:

  conda_env = mlflow.sklearn.get_default_conda_env()
  conda_env["dependencies"] = ['keras==2.2.4', 'tensorflow==1.14.0'] + conda_env["dependencies"]
  mlflow.sklearn.log_model(pipeline, "modelstorage/model43", conda_env = conda_env)
Related