Skip to main content

Model Evaluation

Classic ML Evaluation System

This documentation covers MLflow's classic evaluation system (mlflow.models.evaluate) which uses EvaluationMetric and make_metric for custom metrics.

For GenAI/LLM evaluation, please use the system at GenAI Evaluation which uses:

  • mlflow.genai.evaluate() instead of mlflow.models.evaluate()
  • Scorer objects instead of EvaluationMetric
  • Built-in LLM judges and scorers

Important: These two systems are not interoperable. EvaluationMetric objects cannot be used with mlflow.genai.evaluate(), and Scorer objects cannot be used with mlflow.models.evaluate().

Introduction

MLflow's evaluation framework provides automated model assessment for classification and regression tasks. It generates performance metrics, visualizations, and diagnostic information through a unified API.

Unified Evaluation API

Evaluate models, Python functions, or static datasets with mlflow.models.evaluate() using a consistent interface across different evaluation modes.

Automated Metrics & Visualizations

Generate task-specific metrics and plots automatically, including confusion matrices, ROC curves, and feature importance with SHAP integration.

Custom Metrics

Define domain-specific evaluation criteria with make_metric() for business-specific performance measures beyond standard ML metrics.

Plugin Architecture

Extend evaluation with specialized frameworks like Giskard and Trubrics for advanced validation and vulnerability scanning.

Model Evaluation

Evaluate classification and regression models with automated metrics and visualizations.

Quick Start

python
import mlflow
import pandas as pd
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from mlflow.models import infer_signature

# Load dataset
X, y = load_breast_cancer(return_X_y=True, as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)

# Train model
model = xgb.XGBClassifier().fit(X_train, y_train)

# Create evaluation dataset
eval_data = X_test.copy()
eval_data["label"] = y_test

with mlflow.start_run():
# Log model
signature = infer_signature(X_test, model.predict(X_test))
model_info = mlflow.sklearn.log_model(model, name="model", signature=signature)

# Evaluate
result = mlflow.models.evaluate(
model_info.model_uri,
eval_data,
targets="label",
model_type="classifier",
)

print(f"Accuracy: {result.metrics['accuracy_score']:.3f}")
print(f"F1 Score: {result.metrics['f1_score']:.3f}")
print(f"ROC AUC: {result.metrics['roc_auc']:.3f}")

This automatically generates performance metrics (accuracy, precision, recall, F1-score, ROC-AUC), visualizations (confusion matrix, ROC curve, precision-recall curve), and saves all artifacts to MLflow.

Model Types

For classification tasks:

python
result = mlflow.models.evaluate(
model_uri,
eval_data,
targets="label",
model_type="classifier",
)

# Access metrics
print(f"Precision: {result.metrics['precision_score']:.3f}")
print(f"Recall: {result.metrics['recall_score']:.3f}")
print(f"F1 Score: {result.metrics['f1_score']:.3f}")
print(f"ROC AUC: {result.metrics['roc_auc']:.3f}")

Automatically generates: accuracy, precision, recall, F1-score, ROC-AUC, precision-recall AUC, log loss, brier score, confusion matrix, and classification report.

Evaluator Configuration

Control evaluator behavior with the evaluator_config parameter:

python
# Include SHAP explainer for feature importance
result = mlflow.models.evaluate(
model_uri,
eval_data,
targets="label",
model_type="classifier",
evaluator_config={
"log_explainer": True,
"explainer_type": "exact",
},
)

Common options: log_explainer (log SHAP explainer), explainer_type (SHAP type: "exact", "permutation", "partition"), pos_label (positive class label for binary classification), average (averaging strategy for multiclass: "macro", "micro", "weighted").

Evaluation Results

Access metrics, artifacts, and evaluation data:

python
# Run evaluation
result = mlflow.models.evaluate(
model_uri, eval_data, targets="label", model_type="classifier"
)

# Access metrics
for metric_name, value in result.metrics.items():
print(f"{metric_name}: {value}")

# Access artifacts (plots, tables)
for artifact_name, path in result.artifacts.items():
print(f"{artifact_name}: {path}")

# Access evaluation table
eval_table = result.tables["eval_results_table"]

Model Validation

warning

MLflow 2.18.0 moved model validation from mlflow.models.evaluate() to mlflow.validate_evaluation_results().

Validate evaluation metrics against thresholds:

python
from mlflow.models import MetricThreshold

# Evaluate model
result = mlflow.models.evaluate(
model_uri, eval_data, targets="label", model_type="classifier"
)

# Define thresholds
thresholds = {
"accuracy_score": MetricThreshold(threshold=0.85, greater_is_better=True),
"precision_score": MetricThreshold(threshold=0.80, greater_is_better=True),
}

# Validate
try:
mlflow.validate_evaluation_results(
candidate_result=result,
validation_thresholds=thresholds,
)
print("Model meets all thresholds")
except mlflow.exceptions.ModelValidationFailedException as e:
print(f"Validation failed: {e}")

Dataset Evaluation

Evaluate pre-computed predictions without re-running the model.

Usage

python
import mlflow
import pandas as pd
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

# Generate sample data and train a model
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)

model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# Generate predictions
predictions = model.predict(X_test)
prediction_probabilities = model.predict_proba(X_test)[:, 1]

# Create evaluation dataset with predictions
eval_dataset = pd.DataFrame(
{
"prediction": predictions,
"target": y_test,
}
)

with mlflow.start_run():
result = mlflow.models.evaluate(
data=eval_dataset,
predictions="prediction",
targets="target",
model_type="classifier",
)

print(f"Accuracy: {result.metrics['accuracy_score']:.3f}")
print(f"F1 Score: {result.metrics['f1_score']:.3f}")

Parameters

  • data: DataFrame containing predictions and targets
  • predictions: Column name containing model predictions
  • targets: Column name containing ground truth labels
  • model_type: Task type ("classifier" or "regressor")

When evaluating classification models with probability scores, include a column with probabilities for metrics like ROC-AUC:

python
eval_dataset = pd.DataFrame(
{
"prediction": predictions,
"prediction_proba": prediction_probabilities, # For ROC-AUC
"target": y_test,
}
)

Function Evaluation

Evaluate Python functions directly without logging models to MLflow.

Usage

python
import mlflow
import pandas as pd
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

# Generate sample data
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)

# Train a model
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)


# Define a prediction function
def predict_function(input_data):
return model.predict(input_data)


# Create evaluation dataset
eval_data = pd.DataFrame(X_test)
eval_data["target"] = y_test

with mlflow.start_run():
result = mlflow.models.evaluate(
predict_function,
eval_data,
targets="target",
model_type="classifier",
)

print(f"Accuracy: {result.metrics['accuracy_score']:.3f}")
print(f"F1 Score: {result.metrics['f1_score']:.3f}")

Function Requirements

The function must:

  • Accept input data as its first parameter (DataFrame, numpy array, or compatible format)
  • Return predictions in a format compatible with the specified model_type
  • Be callable without additional arguments beyond the input data

For classification tasks, the function should return class predictions. For regression tasks, it should return continuous values.

Custom Metrics & Visualizations

Define custom evaluation metrics and create specialized visualizations.

Custom Metrics

Classic System Only

The make_metric function is part of MLflow's classic evaluation system.

For GenAI/LLM custom metrics, use the @scorer decorator instead.

Create custom metrics with make_metric:

python
import mlflow
import numpy as np
from mlflow.models import make_metric
from mlflow.metrics.base import MetricValue


# Define custom metric
def custom_metric_fn(predictions, targets, metrics):
"""Custom metric function."""
tp = np.sum((predictions == 1) & (targets == 1))
fp = np.sum((predictions == 1) & (targets == 0))

# Calculate custom value
custom_value = (tp * 100) - (fp * 20)

return MetricValue(
aggregate_results={
"custom_value": custom_value,
"value_per_prediction": custom_value / len(predictions),
},
)


# Create metric
custom_metric = make_metric(
eval_fn=custom_metric_fn, greater_is_better=True, name="custom_metric"
)

with mlflow.start_run():
result = mlflow.models.evaluate(
model_uri,
eval_data,
targets="target",
model_type="classifier",
extra_metrics=[custom_metric],
)

print(f"Custom Value: {result.metrics['custom_metric/custom_value']:.2f}")

Custom metric functions receive three parameters:

  • predictions: Model predictions (numpy array)
  • targets: Ground truth labels (numpy array)
  • metrics: Dictionary of built-in metrics already computed

Return a MetricValue object with aggregate_results dict containing your custom metric values.

Custom Visualizations

Create custom visualization artifacts:

python
import matplotlib.pyplot as plt
import os


def create_custom_plot(eval_df, builtin_metrics, artifacts_dir):
"""Create custom visualization."""
plt.figure(figsize=(10, 6))
plt.scatter(eval_df["prediction"], eval_df["target"], alpha=0.5)
plt.xlabel("Predictions")
plt.ylabel("Targets")
plt.title("Custom Prediction Analysis")

# Save plot
plot_path = os.path.join(artifacts_dir, "custom_plot.png")
plt.savefig(plot_path)
plt.close()

return {"custom_plot": plot_path}


# Use custom artifact
with mlflow.start_run():
result = mlflow.models.evaluate(
model_uri,
eval_data,
targets="target",
model_type="classifier",
custom_artifacts=[create_custom_plot],
)

Custom artifact functions receive three parameters:

  • eval_df: DataFrame with predictions, targets, and input features
  • builtin_metrics: Dictionary of computed metrics
  • artifacts_dir: Directory path to save artifact files

Return a dictionary mapping artifact names to file paths.

SHAP Integration

MLflow's built-in SHAP integration provides automatic model explanations and feature importance analysis.

Usage

Enable SHAP explanations by setting log_explainer: True in the evaluator config:

python
import mlflow
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from mlflow.models import infer_signature

# Load dataset
X, y = load_breast_cancer(return_X_y=True, as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)

# Train model
model = xgb.XGBClassifier().fit(X_train, y_train)

# Create evaluation dataset
eval_data = X_test.copy()
eval_data["label"] = y_test

with mlflow.start_run():
signature = infer_signature(X_test, model.predict(X_test))
model_info = mlflow.sklearn.log_model(model, name="model", signature=signature)

# Evaluate with SHAP enabled
result = mlflow.models.evaluate(
model_info.model_uri,
eval_data,
targets="label",
model_type="classifier",
evaluator_config={"log_explainer": True},
)

# Check generated SHAP artifacts
for artifact_name in result.artifacts:
if "shap" in artifact_name.lower():
print(f"Generated: {artifact_name}")

This generates feature importance plots, SHAP summary plots, and saves a SHAP explainer model.

Configuration

Control SHAP behavior with evaluator config options:

python
result = mlflow.models.evaluate(
model_uri,
eval_data,
targets="label",
model_type="classifier",
evaluator_config={
"log_explainer": True,
"explainer_type": "exact",
"max_error_examples": 100,
"log_model_explanations": True,
},
)

Configuration Options:

  • log_explainer: Whether to save the SHAP explainer as a model (default: False)
  • explainer_type: SHAP algorithm type - "exact", "permutation", or "partition"
  • max_error_examples: Number of misclassified examples to explain in detail
  • log_model_explanations: Whether to log individual prediction explanations

Using Saved Explainers

Load and use saved SHAP explainers on new data:

python
# Load the saved explainer
explainer_uri = f"runs:/{run_id}/explainer"
explainer = mlflow.pyfunc.load_model(explainer_uri)

# Generate explanations for new data
new_data = X_test[:10]
explanations = explainer.predict(new_data)

# explanations contains SHAP values for each feature and prediction
print(f"Explanations shape: {explanations.shape}")

Plugin Evaluators

MLflow's evaluation framework supports plugin evaluators that extend evaluation with specialized validation capabilities.

Giskard Plugin

The Giskard plugin scans models for vulnerabilities including performance bias, robustness issues, overconfidence, underconfidence, ethical bias, data leakage, stochasticity, and spurious correlations.

Examples:

Documentation: Giskard-MLflow integration docs

Trubrics Plugin

The Trubrics plugin provides a validation framework with pre-built validation checks and support for custom Python validation functions.

Example: Official example notebook

Documentation: Trubrics-MLflow integration docs

API Reference