【指南】如何使用MLflow记录数据

2025年01月22日 由 alex 发表 4574 0

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


随着机器学习工作流程的日益复杂,确保实验的可重复性和可追溯性已成为一个关键问题。这就是MLOps(机器学习运维)发挥作用的地方。MLOps是将数据科学和运维结合起来的实践,用于自动化和简化机器学习工作流程。MLOps的一个关键方面是跟踪机器学习项目整个生命周期中的数据集。跟踪不仅仅是捕获模型的参数和指标;同样重要的是记录每个阶段使用的数据集。这确保了在未来重新评估或重新训练模型时,可以引用、测试或重用相同的数据集。它有助于更好地比较结果、理解变化,并且最重要的是,确保结果可以由其他人重现。作为现代机器学习系统的最佳实践,我建议全球所有机器学习从业者都在训练期间记录他们的数据。


昨天的数据与今天的数据?


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


2


概述

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


假设你是一名数据科学家,正在开展一个基于各种特征(如中位数收入、人口和位置)预测加州房价的项目。你花了数小时从多个来源整理数据集、进行清洗,并确保其已准备好用于训练。现在,你已准备好运行机器学习实验。在这个阶段记录你的数据集至关重要,因为它相当于特定训练运行中使用的确切数据的快照。如果你需要在数月后重新审视这个实验——可能是为了改进模型、调整超参数或审核结果——你希望确保使用的是相同的数据集,以保持一致性和可比性。如果不记录数据集,很容易忘记使用了哪个版本的数据,特别是在数据随时间更新或变化的情况下。


设置

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


mlflow server --host 127.0.0.1 --port 8080


然后设置跟踪统一资源标识符(URI)。


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


加州住房数据集


3


对于本文,我们使用的是加州住房数据集(遵循CC BY许可)。但是,你可以将相同的原理应用于记录和跟踪你选择的任何数据集。


数据集和数据集源

mlflow.data.dataset.Dataset

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


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(数据集的名称),可以通过参数设置。
  • schema和profile用于描述数据集的结构和统计属性。
  • 有关数据集来源的信息,例如其存储位置。


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


对流行数据集格式的支持

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


  • 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


如果提供的是字符串作为数据源,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)


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

在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'])'Target'])
california_housing_df: pd.DataFrame = pd.concat([california_data, california_target], axis=1)


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


dataset_source_url: str = 'https://www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.tgz'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>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#/experiments/0/runs/5ef16e2e81bf40068c68ce536121538c
? View experiment at: http://127.0.0.1:8080/#/experiments/0


让我们在MLflow用户界面()中探索这个数据集。你会发现你的数据集列在默认实验下。在“使用的数据集”部分,你可以查看数据集的上下文,在此情况下,它被标记为用于训练。此外,数据集的所有相关字段和属性都将显示出来。


5


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

让我们继续我们的探索之旅,了解如何使用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)0.25, random_state=42)


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


training_dataset_name: str = 'California Housing Training Dataset'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)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}')


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


示例计数、平均绝对误差、均方误差、均方根误差、目标总和、目标平均值、R²得分、最大误差、平均绝对百分比误差


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


7


请注意,如果你正在使用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)}'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用户界面查看结果。你会看到我们的评估数据集已成功记录在与训练相同的运行中。因此,该运行现在同时包含训练数据集和评估数据集。


9


结论

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


总之,数据集是机器学习的核心,而记录数据集对于任何MLOps工作流中的跟踪、可重复性和透明度都是基础性的。MLflow的mlflow.data模块提供了必要的工具,以确保数据旅程的每一步都被捕获、记录和可供将来检索,从而确保一致性并提高机器学习实验的整体可靠性。

文章来源:https://medium.com/towards-data-science/how-to-log-your-data-with-mlflow-23c8027e4021
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消