¿Suena interesante? Si es así, este artículo está aquí para ayudarte a empezar. mlflow.pyfunc. 🥂
- En primer lugar, veamos un ejemplo sencillo de creación de un juguete.
mlflow.pyfuncclase. - Luego, definiremos una
mlflow.pyfuncClase que encapsula una secuencia de aprendizaje automático (un estimador más cierta lógica de preprocesamiento, por ejemplo). También entrenaremos, registraremos y cargaremos esta secuencia de aprendizaje automático para inferencia. - Por último, profundicemos en el encapsulado.
mlflow.pyfuncobjeto, explore los ricos metadatos y artefactos rastreados automáticamente para nosotros pormlflowy comprender mejor todo el poder quemlflow.pyfuncofertas.
🔗 Todo el código y la configuración están disponibles en GitHub. 🧰
Primero, vamos a crear un juguete sencillo. mlflow.pyfunc modelo y luego usarlo con el flujo de trabajo mlflow.
- Paso 1: Crear el modelo
- Paso 2: Registrar el modelo
- Paso 3: Cargue el modelo registrado para realizar la inferencia
# Step 1: Create a mlflow.pyfunc model
class ToyModel(mlflow.pyfunc.PythonModel):
"""
ToyModel is a simple example implementation of an MLflow Python model.
"""def predict(self, context, model_input):
"""
A basic predict function that takes a model_input list and returns a new list
where each element is increased by one.
Parameters:
- context (Any): An optional context parameter provided by MLflow.
- model_input (list of int or float): A list of numerical values that the model will use for prediction.
Returns:
- list of int or float: A list with each element in model_input is increased by one.
"""
return [x + 1 for x in model_input]
Como puede ver en el ejemplo anterior, puede crear un mlflow.pyfunc modelo para implementar cualquier función de Python personalizada que considere adecuada para su solución de aprendizaje automático, que no tiene por qué ser un algoritmo de aprendizaje automático estándar.
Luego puede registrar este modelo y cargarlo más tarde para realizar la inferencia.
# Step 2: log this model as an mlflow run
with mlflow.start_run():
mlflow.pyfunc.log_model(
artifact_path = "model",
python_model=ToyModel()
)
run_id = mlflow.active_run().info.run_id
# Step 3: load the logged model to perform inference
model = mlflow.pyfunc.load_model(f"runs:/{run_id}/model")
# dummy new data
x_new = [1,2,3]
# model inference for the new data
print(model.predict(x_new))
[2, 3, 4]
Ahora, vamos a crear una canalización de ML que encapsule un estimador con lógica personalizada adicional.
En el ejemplo siguiente, el XGB_PIPELINE La clase es un contenedor que integra el estimador con pasos de preprocesamiento, lo que puede ser deseable para algunas implementaciones de MLOps. mlflow.pyfuncEste contenedor es independiente del estimador y ofrece una representación uniforme del modelo. En concreto,
fit():En lugar de utilizar la API nativa de XGBoost (xgboost.train()), esta clase utiliza.fit()que se adhiere a las convenciones de sklearn, lo que permite una integración sencilla en las canalizaciones de sklearn y garantiza la coherencia entre diferentes estimadores.DMatrix():DMatrixes una estructura de datos central en XGBoost que optimiza los datos para el entrenamiento y la predicción. En esta clase, se explica el paso para transformar un DataFrame de pandas en unDMatrixestá envuelto dentro de la clase, lo que permite una integración perfecta con pandas DataFrames como todos los demás estimadores de sklearn.predict():Este es elmlflow.pyfuncAPI de inferencia universal del modelo. Es coherente con esta canalización de ML, con el modelo de juguete anterior y con cualquier algoritmo de aprendizaje automático o lógica personalizada que incluyamos en unmlflow.pyfuncmodelo.
import json
import xgboost as xgb
import mlflow.pyfunc
from typing import Any, Dict, Union
import pandas as pdclass XGB_PIPELINE(mlflow.pyfunc.PythonModel):
"""
XGBWithPreprocess is an example implementation of an MLflow Python model with XGBoost.
"""
def __init__(self, params: Dict[str, Union[str, int, float]]):
"""
Initialize the model with given parameters.
Parameters:
- params (Dict[str, Union[str, int, float]]): Parameters for the XGBoost model.
"""
self.params = params
self.xgb_model = None
self.config = None
def preprocess_input(self, model_input: pd.DataFrame) -> pd.DataFrame:
"""
Preprocess the input data.
Parameters:
- model_input (pd.DataFrame): The input data to preprocess.
Returns:
- pd.DataFrame: The preprocessed input data.
"""
processed_input = model_input.copy()
# put any desired preprocessing logic here
processed_input.drop(processed_input.columns[0], axis=1, inplace=True)
return processed_input
def fit(self, X_train: pd.DataFrame, y_train: pd.Series):
"""
Train the XGBoost model.
Parameters:
- X_train (pd.DataFrame): The training input data.
- y_train (pd.Series): The target values.
"""
processed_model_input = self.preprocess_input(X_train.copy())
dtrain = xgb.DMatrix(processed_model_input, label=y_train)
self.xgb_model = xgb.train(self.params, dtrain)
def predict(self, context: Any, model_input: pd.DataFrame) -> Any:
"""
Predict using the trained XGBoost model.
Parameters:
- context (Any): An optional context parameter provided by MLflow.
- model_input (pd.DataFrame): The input data for making predictions.
Returns:
- Any: The prediction results.
"""
processed_model_input = self.preprocess_input(model_input.copy())
dmatrix = xgb.DMatrix(processed_model_input)
return self.xgb_model.predict(dmatrix)
Ahora, entrenemos y registremos este modelo.
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
import pandas as pd# Generate synthetic datasets for demo
X, y = make_regression(n_samples=1000, n_features=10, noise=0.1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# train and log the model
with mlflow.start_run(run_name = 'xgb_demo') as run:
# Create an instance of XGB_PIPELINE
params = {
'objective': 'reg:squarederror',
'max_depth': 3,
'learning_rate': 0.1,
}
model = XGB_PIPELINE(params)
# Fit the model
model.fit(X_train=pd.DataFrame(X_train), y_train=y_train)
# Log the model
model_info = mlflow.pyfunc.log_model(
artifact_path = 'model',
python_model = model,
)
run_id = mlflow.active_run().info.run_id
El modelo se ha registrado correctamente. ✌️Ahora, carguémoslo para realizar inferencias.
loaded_model = mlflow.pyfunc.load_model(model_uri=model_info.model_uri)
loaded_model.predict(pd.DataFrame(X_test))
array([ 4.11692047e+00, 7.30551958e+00, -2.36042137e+01, -1.31888123e+02,
...
El proceso anterior es bastante sencillo, ¿no? Esto representa la funcionalidad básica del mlflow.pyfunc objeto. Ahora, profundicemos más para explorar todo el poder que tiene mlflow.pyfunc tiene para ofrecer.
1. información del modelo
En el ejemplo anterior, el model_info objeto devuelto por mlflow.pyfunc.log_model() es un ejemplo de mlflow.models.model.ModelInfo clase. Contiene metadatos e información sobre el modelo registrado. Por ejemplo
Siéntete libre de correr dir(model_info) Para explorar más o consultar El código fuente para todos los atributos definidos. El atributo que más utilizo es model_urique indica dónde se puede encontrar el modelo registrado dentro del mlflow sistema de seguimiento.
2. modelo_cargado
Vale la pena aclarar que la loaded_model no es una instancia de la XGB_PIPELINE clase, sino más bien un objeto contenedor proporcionado por mlflow.pyfunc para realizar inferencias independientes del algoritmo. Como se muestra a continuación, se devolverá un error si intenta recuperar los atributos de la XGB_PIPELINE clase de la loaded_model.
print(loaded_model.params)
AttributeError: 'PyFuncModel' object has no attribute 'params'
3. modelo_desenvuelto
Muy bien, te preguntarás, ¿dónde está entonces la instancia entrenada de XGB_PIPELINE¿Se registra y se puede recuperar a través de? mlflow¿también?
No te preocupes, lo guardas de forma segura y lo puedes desenvolver fácilmente, como se muestra a continuación.
unwrapped_model = loaded_model.unwrap_python_model()
print(unwrapped_model.params)
{'objective': 'reg:squarederror', 'max_depth': 3, 'learning_rate': 0.1}
Así se hace. 😎 Con el unwrapped_model¡Puedes acceder a cualquier propiedad o método de tu canalización de ML personalizada de esta manera! A veces agrego métodos útiles como explain_model o post_processing en la canalización personalizada, o incluir atributos útiles para rastrear el proceso de entrenamiento del modelo y ofrecer diagnósticos 🤩… Bueno, será mejor que me detenga aquí y deje eso para los siguientes artículos. Basta con decir que puede personalizar libremente su canalización de ML para su caso de uso y saber que
- Tendrá acceso a todos estos métodos y atributos personalizados para su uso posterior y
- Este modelo personalizado hecho a medida se envolverá dentro del uniforme.
mlflow.pyfuncAPI de inferencia y, por lo tanto, disfruta de una migración fluida a otros estimadores si es necesario.
4. Context
Quizás hayas notado que hay una context parámetro para el predict métodos en ambos mlflow.pyfunc Clase definida anteriormente. Pero, curiosamente, este parámetro no es necesario cuando hacemos predicciones con el modelo cargado. ¿Por qué?
loaded_model = mlflow.pyfunc.load_model(model_uri)
# the context parameter is not needed when calling `predict`
loaded_model.predict(model_input)
Esto se debe a que loaded_model Arriba hay un objeto contenedor proporcionado por mlflowSi usamos el modelo sin envolver, debemos definir el contexto explícitamente, como se muestra a continuación; de lo contrario, el código devolverá un error.
unwrapped_model = loaded_model.unwrap_python_model()
# need to provide context mannually
unwrapped_model.predict(context=None, model_input)
Entonces, ¿qué es esto? context? ¿Y qué papel juega en la predict ¿método?
El context es un PythonModelContext objeto que contiene artefactospyfunc El modelo puede utilizarlo al realizar inferencias. Lo crea de forma implícita y automática el log_method() método.
Navegar hasta el mlruns subcarpeta en el repositorio de su proyecto, que se crea automáticamente por mlflow Cuando inicias sesión mlflow modelo. Busque la carpeta que lleva el nombre del modelo. run_idEn el interior, encontrará los artefactos del modelo registrados automáticamente, como se muestra a continuación.
# get run_id of a loaded model
print(loaded_model.metadata.run_id)
38a617d0f30645e8ae95eea4642a03c2
Bastante ordenado, ¿no? 😁 Siéntete libre de explorar estos artefactos a tu gusto; a continuación se muestran las capturas de pantalla de los requirements y MLmodel archivo de la carpeta FYR.
El requiarements A continuación se especifican las versiones de las dependencias necesarias para recrear el entorno para ejecutar el modelo.
El MLmodel El documento a continuación define los metadatos y la configuración necesarios para cargar y servir el modelo en formato YAML.