記錄 MLflow 模型

本文說明如何將定型的模型 (或成品) 記錄為 MLflow 模型。 並探索如何自訂不同的 MLflow 封裝模型方式,以及其執行方式。

為何要記錄模型而不是成品?

從成品到 MLflow 中的模型描述與記錄 MLflow 模型相比,記錄成品或檔案之間的差異。

MLflow 模型也是成品。 但是,該模型具有特定結構,可作為模型建立者與想要使用模型者之間的合約。 此合約有助於在成品本身與其意義之間建立橋樑。

模型記錄具有下列優點:

  • 您可以使用 mlflow.<flavor>.load_model 直接載入模型以進行推斷,而且可以使用 predict 函式
  • 管線輸入可以直接使用模型
  • 無需指示評分指令碼或環境,您便可以部署模型
  • Swagger 會自動在已部署的端點中啟用,而 Azure Machine Learning Studio 可以使用 Test 功能
  • 您可以使用負責任的 AI 儀表板

本節說明如何在 Azure Machine Learning 中搭配 MLflow 使用模型的概念:

使用 autolog 記錄模型

您可以使用 MLflow autolog 功能。 Autolog 可讓 MLflow 指示相關聯架構,來記錄所有該架構視為相關的計量、參數、成品和模型。 根據預設,如果已啟用 autolog,則會記錄大部分的模型。 在某些情況下,某些變體可能不會記錄模型。 舉例來說,PySpark 變體不會記錄超過特定大小的模型。

使用 mlflow.autolog()mlflow.<flavor>.autolog() 來啟用自動記錄。 此範例會使用 autolog() 來記錄使用 XGBoost 定型的分類器模型:

import mlflow
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score

mlflow.autolog()

model = XGBClassifier(use_label_encoder=False, eval_metric="logloss")
model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)

y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)

提示

如果使用 Machine Learning 管線,例如 Scikit-Learn 管線,請使用該管線類別的 autolog 功能來記錄模型。 在管線物件上呼叫 fit() 方法時,模型記錄會自動開始。 使用 MLflow 筆記本訓練和追蹤 XGBoost 分類器 (英文) 會示範如何使用管線記錄含前置處理的模型。

記錄含有自訂簽章、環境或範例的模型

MLflow mlflow.<flavor>.log_model 方法可以手動記錄模型。 此工作流程可以控制模型記錄的不同層面。

使用此方法的時機:

  • 您想要指出 pip 套件或 conda 環境與自動偵測到的項目不同
  • 您想要包含輸入範例
  • 您想要將特定成品包含在所需套件中
  • autolog 未正確推斷您的簽章。 當您處理張量輸入時,對簽章有特定形狀要求,這事關重大
  • 自動記錄行為出於某些原因未涵蓋您的用途

此範例程式碼會記錄 XGBoost 分類器的模型:

import mlflow
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score
from mlflow.models import infer_signature
from mlflow.utils.environment import _mlflow_conda_env

mlflow.autolog(log_models=False)

model = XGBClassifier(use_label_encoder=False, eval_metric="logloss")
model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)
y_pred = model.predict(X_test)

accuracy = accuracy_score(y_test, y_pred)

# Signature
signature = infer_signature(X_test, y_test)

# Conda environment
custom_env =_mlflow_conda_env(
    additional_conda_deps=None,
    additional_pip_deps=["xgboost==1.5.2"],
    additional_conda_channels=None,
)

# Sample
input_example = X_train.sample(n=1)

# Log the model manually
mlflow.xgboost.log_model(model, 
                         artifact_path="classifier", 
                         conda_env=custom_env,
                         signature=signature,
                         input_example=input_example)

注意

  • autolog 具有 log_models=False 組態。 這可防止自動 MLflow 模型記錄。 自動 MLflow 模型記錄會在稍後進行,改為手動程序
  • 使用 infer_signature 方法嘗試直接從輸入和輸出推斷簽章
  • mlflow.utils.environment._mlflow_conda_env 方法是 MLflow SDK 中的隱藏方法。 在此範例中,它會讓程式碼更簡單,但請謹慎使用。 這在未來可能會變更。 或者,您可以手動產生 YAML 定義做為 Python 字典。

記錄在 predict 方法中具有不同行為的模型

使用 mlflow.autologmlflow.<flavor>.log_model 記錄模型時,模型類別會決定如何執行推斷,以及模型傳回的內容。 MLflow 不會依 predict 產生結果的方式強制執行任何特定行為。 某些情節中,您可能想要在執行模型之前和之後執行一些前置處理或後續處理。

此情況下,請實作機器學習管線,以從輸入直接移至輸出。 雖然此實作可行,有時也能夠改善效能,但要實現可能會有些困難。 在這些情況下,自訂模型處理推斷的方式會有所幫助 ,如下一節所述。

記錄自訂模型

MLflow 支援許多機器學習架構,包括

  • CatBoost
  • FastAI
  • h2o
  • Keras
  • LightGBM
  • MLeap
  • MXNet Gluon
  • ONNX
  • Prophet
  • PyTorch
  • Scikit-Learn
  • spaCy
  • Spark MLLib
  • statsmodels
  • TensorFlow
  • XGBoost

不過,您可能需要變更變體的運作方式、記錄 MLflow 原本不支援的模型,甚至記錄使用來自不同架構多個元素的模型。 在這類案例中,您可能需要建立自訂模型變體。

為了解決問題,MLflow 引進了 pyfunc 變體 (從 Python 函式開始)。 只要該物件符合兩個條件,這個變體就可以將任何物件記錄為模型:

  • 您至少要實作 predict 方法
  • Python 物件繼承自 mlflow.pyfunc.PythonModel

提示

只要是實作 Scikit-learn API 的可序列化模型,您即可使用 Scikit-learn 變體來記錄模型,而不論模型是否使用 Scikit-learn 來建置。 如果您可以將模型保存為 Pickle 格式,而且物件至少具有 predict()predict_proba() 方法,則您可以使用 mlflow.sklearn.log_model() 在 MLflow 執行中加以記錄模型。

如果您在現有的模型物件周圍建立包裝函式,則建立自訂模型的變體會是最簡單的方法。 MLflow 會為您序列化並封裝。 當物件可在檔案系統中儲存為檔案時,Python 物件即為可序列化,通常是以 Pickle 格式。 在運行時間,物件可以從該檔案具體化。 這會還原儲存時可用的所有值、屬性和方法。

使用此方法的時機:

  • 您能夠以 Pickle 格式序列化模型
  • 您想要保留模型剛定型之後的狀態
  • 您想要自訂 predict 函式的運作方式。

此程式碼範例會包裝使用 XGBoost 建立的模型,使其行為與 XGBoost 變體預設實作不同。 相反,它會傳回機率,而不是類別:

from mlflow.pyfunc import PythonModel, PythonModelContext

class ModelWrapper(PythonModel):
    def __init__(self, model):
        self._model = model

    def predict(self, context: PythonModelContext, data):
        # You don't have to keep the semantic meaning of `predict`. You can use here model.recommend(), model.forecast(), etc
        return self._model.predict_proba(data)

    # You can even add extra functions if you need to. Since the model is serialized,
    # all of them will be available when you load your model back.
    def predict_batch(self, data):
        pass

在執行中記錄自訂模型:

import mlflow
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score
from mlflow.models import infer_signature

mlflow.xgboost.autolog(log_models=False)

model = XGBClassifier(use_label_encoder=False, eval_metric="logloss")
model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)
y_probs = model.predict_proba(X_test)

accuracy = accuracy_score(y_test, y_probs.argmax(axis=1))
mlflow.log_metric("accuracy", accuracy)

signature = infer_signature(X_test, y_probs)
mlflow.pyfunc.log_model("classifier", 
                        python_model=ModelWrapper(model),
                        signature=signature)

提示

截至目前,infer_signature 方法會使用 y_probs 來推斷簽章。 我們的目標資料行具有目標類別,但模型現在卻傳回每個類別的兩個機率。

下一步