如何使用-MLflow-记录数据

如何使用 MLflow 记录数据

原文:towardsdatascience.com/how-to-log-your-data-with-mlflow-23c8027e4021/

MLflow, MLOps, 数据科学

Photo by Chris Liverani on Unsplash

Photo by Chris Liverani on Unsplash

前言

数据是机器学习过程中最关键的组成部分之一。实际上,用于训练模型的数据质量往往决定了整个项目的成功或失败。虽然算法和模型很重要,但没有准确、干净且能代表你要解决的问题的数据,它们就无能为力。无论你处理的是结构化数据、非结构化数据还是大规模数据集,数据的准备和理解都是任何机器学习系统的基础。一个精心整理的数据集可以为模型提供必要的信号,使其能够有效地学习,而质量差或存在偏见的数据可能导致预测错误、过拟合,甚至在模型应用于现实世界应用时产生有害的社会影响。

随着机器学习工作流程的日益复杂,确保实验的可重复性和可追溯性已成为一个关键问题。这正是MLOps(机器学习运维)发挥作用的地方。MLOps 是将数据科学和运维结合起来的实践,以自动化和简化机器学习工作流程。MLOps 的一个关键方面是跟踪机器学习项目的整个生命周期中的数据集。跟踪不仅仅是捕捉模型的参数和指标;在过程的每个阶段记录使用的数据集同样重要。这确保了在将来,当模型被重新评估或重新训练时,可以引用、测试或重用相同的数据集。它允许更好地比较结果、理解变化,最重要的是,确保结果可以被他人重复。

作为现代机器学习系统的最佳实践,我建议全球所有机器学习从业者记录训练过程中的数据

在这个背景下,MLflow 通过提供一系列工具来帮助简化这些 MLOps 实践,发挥着关键作用。MLflow 的一个关键组件是其 mlflow.data 模块,它提供了将数据集作为机器学习实验的一部分进行记录的能力。 mlflow.data 模块确保数据集得到适当的文档记录,其元数据得到跟踪,并且可以在未来的运行中检索和重用。这有助于防止常见问题,如“数据漂移”,即模型由于底层数据的微妙变化而开始表现不佳。MLflow 能够跟踪数据集、模型和参数,确保任何新的实验都可以可靠地使用确切相同的数据与之前的运行进行比较,从而提供透明度和清晰度。

由 Brian McGowan 在 Unsplash 上拍摄的照片

Brian McGowanUnsplash 拍摄的照片


概述

本文将指导您在 MLflow 中记录数据集的最佳实践,以加利福尼亚住房数据集为例。 我们将探索 mlflow.data 接口,并演示您如何在机器学习实验中跟踪和管理您的数据集。

想象一下,你是一名数据科学家,正在从事一个基于各种特征(如中位数收入、人口和位置)预测加利福尼亚州房价的项目。你已经花费数小时从多个来源整理数据集,清理数据,并确保其准备好进行训练。现在你准备运行你的机器学习实验。在这个阶段记录你的数据集至关重要,因为它作为特定训练运行中使用的确切数据的快照。如果你几个月后需要重新访问实验——可能是为了改进模型、调整超参数或审计结果——你希望确保你使用的是相同的数据库以保持一致性和可比性。如果不记录你的数据集,很容易失去对所使用数据版本的跟踪,尤其是如果数据随时间更新或更改的话。

不再拖延,让我们开始吧!


设置

在本地设置 MLflow 服务器很简单。使用以下命令:

mlflow server --host 127.0.0.1 --port 8080

然后设置跟踪 URI。

mlflow.set_tracking_uri("http://127.0.0.1:8080")

对于更高级的配置,请参阅MLflow 文档

加利福尼亚住房数据集

由 Robert Bye 在 Unsplash 上拍摄的照片

Robert ByeUnsplash 拍摄的照片

对于这篇文章,我们使用的是加利福尼亚住房数据集(CC BY 许可证)。然而,您可以将相同的原理应用于记录和跟踪您选择的任何数据集。

关于加利福尼亚住房数据集的更多信息,请参阅这份文档

Dataset 和 DatasetSource

mlflow.data.dataset.Dataset

在深入数据集记录、评估和检索之前,了解 MLflow 中数据集的概念非常重要。MLflow 提供了mlflow.data.dataset.Dataset对象,它表示在 MLflow Tracking 中使用的数据集。

class mlflow.data.dataset.Dataset(source: mlflow.data.dataset_source.DatasetSource, name: Optional[str] = None, digest: Optional[str] = None)

此对象包含以下关键属性:

  • 一个必需的参数,source(数据集的数据源,作为mlflow.data.dataset_source.DatasetSource对象)

  • digest(数据集的指纹)和name(数据集的名称),这些可以通过参数设置。

  • schemaprofile用于描述数据集的结构和统计属性。

  • 关于数据集的来源信息,例如其存储位置。

您可以使用to_dict()轻松将数据集转换为字典,或使用to_json()转换为 JSON 字符串。

支持流行的数据集格式

MLflow 通过扩展核心mlflow.data.dataset.Dataset类的专用类,使得处理各种类型的数据集变得简单。在撰写本文时,以下是 MLflow 支持的一些显著的 dataset 类:

  • pandas: mlflow.data.pandas_dataset.PandasDataset

  • NumPy: mlflow.data.numpy_dataset.NumpyDataset

  • Spark: mlflow.data.spark_dataset.SparkDataset

  • Hugging Face: mlflow.data.huggingface_dataset.HuggingFaceDataset

  • TensorFlow: mlflow.data.tensorflow_dataset.TensorFlowDataset

  • 评估数据集: mlflow.data.evaluation_dataset.EvaluationDataset

所有这些类都提供了方便的mlflow.data.from_* API,可以直接将数据集加载到 MLflow 中。这使得无论数据集的底层格式如何,都可以轻松构建和管理数据集。

mlflow.data.dataset_source.DatasetSource

mlflow.data.dataset.DatasetSource类用于在 MLflow 中表示数据集的来源。在创建mlflow.data.dataset.Dataset对象时,source参数可以是字符串(例如,文件路径或 URL)或mlflow.data.dataset.DatasetSource类的实例。

class mlflow.data.dataset_source.DatasetSource

如果提供了字符串作为source,MLflow 会内部调用resolve_dataset_source函数。此函数遍历预定义的数据源和DatasetSource类列表,以确定最合适的来源类型。然而,MLflow 准确解析数据集来源的能力有限,尤其是在将candidate_sources参数(潜在来源列表)设置为None时,这是默认值。

DatasetSource类无法解析原始来源的情况下,MLflow 会抛出一个异常。为了最佳实践,我建议在定义数据集的来源时,明确创建并使用mlflow.data.dataset.DatasetSource类的实例。

  • class HTTPDatasetSource(DatasetSource)

  • class DeltaDatasetSource(DatasetSource)

  • class FileSystemDatasetSource(DatasetSource)

  • class HuggingFaceDatasetSource(DatasetSource)

  • class SparkDatasetSource(DatasetSource)

每当 Jack Chang 发布邮件时获取通知

使用 mlflow.log_input() API 记录数据集

由 Claudio Schwarz 在 Unsplash 上的照片

Claudio SchwarzUnsplash上的照片

在 MLflow 中记录数据集最直接的方法之一是通过mlflow.log_input() API。这允许你以与mlflow.data.dataset.Dataset兼容的任何格式记录数据集,这在管理大规模实验时可能非常有帮助。

步骤指南

首先,让我们获取加利福尼亚住房数据集并将其转换为pandas.DataFrame,以便更容易地操作。在这里,我们创建了一个结合了特征数据(california_data)和目标数据(california_target)的数据框。

california_housing = fetch_california_housing()
california_data: pd.DataFrame = pd.DataFrame(california_housing.data, columns=california_housing.feature_names)
california_target: pd.DataFrame = pd.DataFrame(california_housing.target, columns=['Target'])

california_housing_df: pd.DataFrame = pd.concat([california_data, california_target], axis=1)

为了记录具有有意义元数据的数据集,我们定义了一些参数,如数据源 URL、数据集名称和目标列。这些将在以后检索数据集时提供有用的上下文。

如果我们深入查看fetch_california_housing 源代码,我们可以看到数据来源于www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.tgz

dataset_source_url: str = 'https://www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.tgz'
dataset_source: DatasetSource = HTTPDatasetSource(url=dataset_source_url)
dataset_name: str = 'California Housing Dataset'
dataset_target: str = 'Target'
dataset_tags = {
    'description': california_housing.DESCR,
}

一旦定义了数据和元数据,我们就可以将pandas.DataFrame转换为mlflow.data.Dataset对象。

dataset: PandasDataset = mlflow.data.from_pandas(
    df=california_housing_df, source=dataset_source, targets=dataset_target, name=dataset_name
)

print(f'Dataset name: {dataset.name}')
print(f'Dataset digest: {dataset.digest}')
print(f'Dataset source: {dataset.source}')
print(f'Dataset schema: {dataset.schema}')
print(f'Dataset profile: {dataset.profile}')
print(f'Dataset targets: {dataset.targets}')
print(f'Dataset predictions: {dataset.predictions}')
print(dataset.df.head())

示例输出:

Dataset name: California Housing Dataset
Dataset digest: 55270605
Dataset source: <mlflow.data.http_dataset_source.HTTPDatasetSource object at 0x101153a90>
Dataset schema: ['MedInc': double (required), 'HouseAge': double (required), 'AveRooms': double (required), 'AveBedrms': double (required), 'Population': double (required), 'AveOccup': double (required), 'Latitude': double (required), 'Longitude': double (required), 'Target': double (required)]
Dataset profile: {'num_rows': 20640, 'num_elements': 185760}
Dataset targets: Target
Dataset predictions: None
   MedInc  HouseAge  AveRooms  AveBedrms  Population  AveOccup  Latitude  Longitude  Target
0  8.3252      41.0  6.984127   1.023810       322.0  2.555556     37.88    -122.23   4.526
1  8.3014      21.0  6.238137   0.971880      2401.0  2.109842     37.86    -122.22   3.585
2  7.2574      52.0  8.288136   1.073446       496.0  2.802260     37.85    -122.24   3.521
3  5.6431      52.0  5.817352   1.073059       558.0  2.547945     37.85    -122.25   3.413
4  3.8462      52.0  6.281853   1.081081       565.0  2.181467     37.85    -122.25   3.422

注意:你甚至可以将数据集转换为字典以访问额外的属性,如source_type

for k,v in dataset.to_dict().items():
    print(f"{k}: {v}")
name: California Housing Dataset
digest: 55270605
source: {"url": "https://www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.tgz"}
source_type: http
schema: {"mlflow_colspec": [{"type": "double", "name": "MedInc", "required": true}, {"type": "double", "name": "HouseAge", "required": true}, {"type": "double", "name": "AveRooms", "required": true}, {"type": "double", "name": "AveBedrms", "required": true}, {"type": "double", "name": "Population", "required": true}, {"type": "double", "name": "AveOccup", "required": true}, {"type": "double", "name": "Latitude", "required": true}, {"type": "double", "name": "Longitude", "required": true}, {"type": "double", "name": "Target", "required": true}]}
profile: {"num_rows": 20640, "num_elements": 185760}

现在我们已经准备好了数据集,是时候将其记录到 MLflow 运行中。这允许我们捕获数据集的元数据,使其成为实验的一部分,以便将来参考。

with mlflow.start_run():
    mlflow.log_input(dataset=dataset, context='training', tags=dataset_tags)
🏃  View run sassy-jay-279 at: http://127.0.0.1:8080/#/experiments/0/runs/5ef16e2e81bf40068c68ce536121538c
🧪 View experiment at: http://127.0.0.1:8080/#/experiments/0

让我们探索 MLflow UI 中的数据集。你将在默认实验下找到你的数据集。在使用的数据集部分,你可以查看数据集的上下文,在本例中标记为用于训练。此外,数据集的所有相关字段和属性也将显示出来。

MLflow UI 中的训练数据集;来源:我

MLflow UI 中的训练数据集;来源:我

恭喜!你已经记录了你的第一个数据集!


在评估 mlflow.evaluate() API 时记录数据集

由 Dino Reichmuth 在 Unsplash 上的照片

Dino ReichmuthUnsplash上的照片

让我们继续我们的旅程,探索如何使用 mlflow.evaluate() API 评估数据集。这个功能,它将数据集与 MLflow 的评估框架集成,是在 MLflow 2.8.0 中引入的。MLflow 早期版本的用户将无法访问此功能。

步骤指南

首先,让我们对加利福尼亚住房数据进行训练-测试拆分:

X_train, X_test, y_train, y_test = train_test_split(california_data, california_target, test_size=0.25, random_state=42)

对于这部分,我们将使用类似的元数据来创建训练数据集,但请注意,训练和评估数据集有不同的名称。

training_dataset_name: str = 'California Housing Training Dataset'
training_dataset_target: str = 'Target'
eval_dataset_name: str = 'California Housing Evaluation Dataset'
eval_dataset_target: str = 'Target'
eval_dataset_prediction: str = 'Prediction'

对于建模,让我们拟合一个随机森林回归模型。

model = RandomForestRegressor(random_state=42)
model.fit(X_train, y_train.to_numpy().flatten())

模型训练完成后,我们需要准备一个评估数据集。将使用 mlflow.data.from_pandas() 函数创建此数据集,并将其传递给 mlflow.evaluate() 函数以进行模型评估。请注意,这里指定了 predictions 参数以指示包含模型预测输出的列。

y_test_pred: pd.Series = model.predict(X=X_test)
eval_df: pd.DataFrame = X_test.copy()
eval_df[eval_dataset_target] = y_test.to_numpy().flatten()
eval_df[eval_dataset_prediction] = y_test_pred

eval_dataset: PandasDataset = mlflow.data.from_pandas(
    df=eval_df, targets=eval_dataset_target, name=eval_dataset_name, predictions=eval_dataset_prediction
)

准备好训练和评估数据集后,是时候使用 MLflow 记录模型并评估其性能了。

mlflow.sklearn.autolog()
with mlflow.start_run():
    mlflow.log_input(dataset=training_dataset, context='training')

    mlflow.sklearn.log_model(model, artifact_path='rf', input_example=X_test)

    result = mlflow.evaluate(
        data=eval_dataset,
        predictions=None,
        model_type='regressor',
    )

    print(f'metrics: {result.metrics}')

这里使用的是 默认评估器,它会自动记录几个重要指标:

example_count, mean_absolute_error, mean_squared_error, root_mean_squared_error, sum_on_target, mean_on_target, r2_score, max_error, mean_absolute_percentage_error

这些指标可以在 MLflow UI 中实验运行的指标部分找到。我建议使用 mlflow.evaluate 尝试不同的模型类型,以探索默认评估器的全部功能。它提供了一系列有价值的指标以及有用的可视化。

使用 mlflow.evaluate 的回归指标;来源:本人

使用 mlflow.evaluate 的回归指标;来源:本人

注意,如果您正在使用 MLflow PandasDataset,则必须在 mlflow.data.from_pandas() 函数中使用 predictions 参数指定包含模型预测输出的列。在调用 mlflow.evaluate() 时,设置 predictions = None,因为预测列已经包含在数据集中。这确保了适当的集成和评估。

示例输出:

2025/01/16 15:11:36 INFO mlflow.models.evaluation.default_evaluator: Testing metrics on first row...
2025/01/16 15:11:37 INFO mlflow.models.evaluation.evaluators.shap: Shap explainer ExactExplainer is used.
metrics: {'example_count': 5160, 'mean_absolute_error': np.float64(0.32909333102713195), 'mean_squared_error': np.float64(0.2545599452819612), 'root_mean_squared_error': np.float64(0.5045393396772557), 'sum_on_target': np.float64(10646.03931999994), 'mean_on_target': np.float64(2.0631859147286704), 'r2_score': 0.8076205696273513, 'max_error': np.float64(3.626845299999994), 'mean_absolute_percentage_error': np.float64(0.1909308987066793)}
🏃  View run bouncy-fox-193 at: http://127.0.0.1:8080/#/experiments/0/runs/65b25856e28142fd85c54b38db4f2b3d
🧪 View experiment at: http://127.0.0.1:8080/#/experiments/0

让我们转到 MLflow UI 查看结果。您将看到我们的评估数据集已成功记录在训练的同一运行中。因此,该运行现在包含训练和评估数据集。

MLflow UI 中的评估数据集;来源:本人

MLflow UI 中的评估数据集;来源:本人


结语

记录数据集对于可重复性和问责制至关重要。例如,如果你在医疗保健或金融等受监管的行业工作,证明用于训练模型的数据符合某些标准且未经适当跟踪未进行更改是至关重要的。在协作项目中,能够共享你的数据集日志也有助于更高效的协作和结果共享。通过使用 MLflow 等工具记录数据集,你确保你的实验是透明的、可重复的且稳健的,有助于建立对你机器学习成果的信任。

总结来说,数据集是机器学习的心脏,记录它们对于任何 MLOps 工作流程中的跟踪、可重复性和透明度至关重要。MLflow 的 mlflow.data 模块提供了确保数据旅程的每一步都被捕获、记录并可检索以供未来使用的工具,确保一致性并提高机器学习实验的整体可靠性。

这是文章中所有代码的 Github 仓库

由 Jordan Cormack 在 Unsplash 上拍摄的照片

Jordan CormackUnsplash 拍摄的照片

概括和要点

  • 使用 mlflow.log_input() API 记录数据集:这用于记录你的训练数据,确保在实验中捕获所有相关元数据,以便进行可追溯性和可重复性。

  • 使用 mlflow.evaluate() API 评估时记录数据集:这用于评估你的模型,并自动记录关键性能指标,帮助你跟踪模型在评估期间的有效性。

每当 Jack Chang 发布时,都会收到电子邮件

请随时在评论中分享你的想法。我喜欢了解数据并反思(撰写关于)我在实际应用中学到的知识。如果你喜欢这篇文章,请鼓掌以示支持。如果你有更多要讨论的,可以通过 LinkedIn 联系我。此外,你也可以在 Medium 上关注我,以获取即将到来的更多数据科学文章!

来数据科学游乐场一起玩吧!

posted @ 2026-03-28 09:34  绝不原创的飞龙  阅读(0)  评论(0)    收藏  举报