入门:在 Azure Databricks 上构建第一个机器学习模型

本文介绍了如何使用 Azure Databricks 上的 scikit-learn 库构建机器学习分类模型。

目标是创建一个分类模型来预测葡萄酒是否被视为“高品质”。 数据集包含不同葡萄酒的 11 个特征(如酒精含量、酸度和残糖)以及 1 到 10 之间的质量排名。

此示例还说明了如何使用 MLflow 跟踪模型开发过程,以及如何使用 Hyperopt 自动执行超参数优化。

数据集来自 UCI 机器学习存储库,发表在通过物理化学性质的数据挖掘对葡萄酒偏好进行建模 [Cortez et al., 2009] 中。

开始之前

  • 必须为 Unity Catalog 启用你的工作区。
  • 必须具有创建群集或访问群集的权限。
  • 必须对目录拥有 USE_CATALOG 特权。
  • 在该目录中,必须对架构拥有以下特权:USE_SCHEMA、CREATE_TABLE 和 CREATE_MODEL。

提示

本文中的所有代码均可在笔记本中找到,可以将其直接导入到工作区中。 请参阅示例笔记本:构建分类模型

步骤 1:创建 Databricks 笔记本

若要在工作区中创建笔记本,请单击边栏中的““新建”图标 新建”,然后单击“笔记本”。 将在工作区中打开一个空白笔记本。

若要了解有关创建和管理笔记本的详细信息,请参阅管理笔记本

步骤 2:连接到计算资源

若要进行探索性数据分析和数据工程,必须具有计算访问权限。

有关连接到现有计算资源的说明,请参阅计算。 有关配置新计算资源的说明,请参阅计算配置参考

本文中的步骤需要用于机器学习的 Databricks Runtime。 有关选择 Databricks Runtime 的 ML 版本的详细信息和说明,请参阅用于机器学习的 Databricks Runtime

步骤 3:设置模型注册表、目录和架构

开始之前需要完成两个重要步骤。 首先,必须配置 MLflow 客户端以使用 Unity Catalog 作为模型注册表。 在笔记本的新单元格中输入以下代码。

import mlflow
mlflow.set_registry_uri("databricks-uc")

还必须设置要在其中注册模型的目录和架构。 必须对目录具有 USE CATALOG 特权,并且对架构具有 USE_SCHEMA、CREATE_TABLE 和 CREATE_MODEL 特权。

有关如何使用 Unity Catalog 的详细信息,请参阅什么是 Unity Catalog?

在笔记本的新单元格中输入以下代码。

# If necessary, replace "main" and "default" with a catalog and schema for which you have the required permissions.
CATALOG_NAME = "main"
SCHEMA_NAME = "default"

步骤 4:加载数据并创建 Unity Catalog 表

此示例使用 Azure Databricks 中内置的两个 CSV 文件。 若要了解如何引入你自己的数据,请参阅将数据引入到 Databricks 湖屋

在笔记本的新单元格中输入以下代码。

white_wine = spark.read.csv("dbfs:/databricks-datasets/wine-quality/winequality-white.csv", sep=';', header=True)
red_wine = spark.read.csv("dbfs:/databricks-datasets/wine-quality/winequality-red.csv", sep=';', header=True)

# Remove the spaces from the column names
for c in white_wine.columns:
    white_wine = white_wine.withColumnRenamed(c, c.replace(" ", "_"))
for c in red_wine.columns:
    red_wine = red_wine.withColumnRenamed(c, c.replace(" ", "_"))

# Define table names
red_wine_table = f"{CATALOG_NAME}.{SCHEMA_NAME}.red_wine"
white_wine_table = f"{CATALOG_NAME}.{SCHEMA_NAME}.white_wine"

# Write to tables in Unity Catalog
spark.sql(f"DROP TABLE IF EXISTS {red_wine_table}")
spark.sql(f"DROP TABLE IF EXISTS {white_wine_table}")
white_wine.write.saveAsTable(f"{CATALOG_NAME}.{SCHEMA_NAME}.white_wine")
red_wine.write.saveAsTable(f"{CATALOG_NAME}.{SCHEMA_NAME}.red_wine")

步骤 5。 预处理和拆分数据

在此步骤中,将在步骤 4 中创建的 Unity Catalog 表中的数据加载到 Pandas DataFrame 并预处理数据。 本节中的代码执行以下操作:

  1. 将数据加载为 Pandas DataFrame。
  2. 向每个 DataFrame 添加一个布尔列以区分红葡萄酒和白葡萄酒,然后将 DataFrame 组合成一个新的 DataFrame data_df
  3. 数据集包含一个 quality 列,对葡萄酒进行从 1 到 10 的评级,其中 10 表示最高品质。 代码将此列转换为两个分类值:“True”表示高品质葡萄酒 (quality>= 7),“False”表示非高品质葡萄酒 (quality< 7)。
  4. 将 DataFrame 拆分为单独的训练数据集和测试数据集。

首先,导入所需的库:

import numpy as np
import pandas as pd
import sklearn.datasets
import sklearn.metrics
import sklearn.model_selection
import sklearn.ensemble

import matplotlib.pyplot as plt

from hyperopt import fmin, tpe, hp, SparkTrials, Trials, STATUS_OK
from hyperopt.pyll import scope

现在加载并预处理数据:

# Load data from Unity Catalog as Pandas dataframes
white_wine = spark.read.table(f"{CATALOG_NAME}.{SCHEMA_NAME}.white_wine").toPandas()
red_wine = spark.read.table(f"{CATALOG_NAME}.{SCHEMA_NAME}.red_wine").toPandas()

# Add Boolean fields for red and white wine
white_wine['is_red'] = 0.0
red_wine['is_red'] = 1.0
data_df = pd.concat([white_wine, red_wine], axis=0)

# Define classification labels based on the wine quality
data_labels = data_df['quality'].astype('int') >= 7
data_df = data_df.drop(['quality'], axis=1)

# Split 80/20 train-test
X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(
  data_df,
  data_labels,
  test_size=0.2,
  random_state=1
)

步骤 6。 训练分类模型

此步骤使用默认算法设置来训练梯度提升分类器。 然后,它将生成的模型应用于测试数据集,并计算、记录和显示受试者工作曲线下的面积,以评估模型的性能。

首先,启用 MLflow 自动日志记录:

mlflow.autolog()

现在启动模型训练运行:

with mlflow.start_run(run_name='gradient_boost') as run:
    model = sklearn.ensemble.GradientBoostingClassifier(random_state=0)

    # Models, parameters, and training metrics are tracked automatically
    model.fit(X_train, y_train)

    predicted_probs = model.predict_proba(X_test)
    roc_auc = sklearn.metrics.roc_auc_score(y_test, predicted_probs[:,1])
    roc_curve = sklearn.metrics.RocCurveDisplay.from_estimator(model, X_test, y_test)

    # Save the ROC curve plot to a file
    roc_curve.figure_.savefig("roc_curve.png")

    # The AUC score on test data is not automatically logged, so log it manually
    mlflow.log_metric("test_auc", roc_auc)

    # Log the ROC curve image file as an artifact
    mlflow.log_artifact("roc_curve.png")

    print("Test AUC of: {}".format(roc_auc))

单元格结果会显示曲线下的计算面积和 ROC 曲线图:

分类模型的 ROC 曲线。

步骤 7. 在 MLflow 中查看试验运行

Lflow 试验跟踪可通过在迭代开发模型时记录代码和结果来帮助跟踪模型开发。

若要查看刚刚执行的训练运行的记录结果,请单击单元格输出中的链接,如下图所示。

链接到单元格结果中的试验。

试验页允许比较运行并查看特定运行的详细信息。 请参阅 MLflow 试验跟踪

步骤 8。 超参数优化

开发 ML 模型的一个重要步骤是通过优化控制算法的参数(称为超参数)来优化模型的准确性。

Databricks Runtime ML 包含 Hyperopt,它是一个用于超参数优化的 Python 库。 可以使用 Hyperopt 运行超参数扫描并并行训练多个模型,从而减少优化模型性能所需的时间。 MLflow 跟踪与 Hyperopt 集成,以自动记录模型和参数。 有关在 Databricks 中使用 Hyperopt 的详细信息,请参阅超参数优化

以下代码展示了使用 Hyperopt 的示例。

# Define the search space to explore
search_space = {
  'n_estimators': scope.int(hp.quniform('n_estimators', 20, 1000, 1)),
  'learning_rate': hp.loguniform('learning_rate', -3, 0),
  'max_depth': scope.int(hp.quniform('max_depth', 2, 5, 1)),
}

def train_model(params):
  # Enable autologging on each worker
  mlflow.autolog()
  with mlflow.start_run(nested=True):
    model_hp = sklearn.ensemble.GradientBoostingClassifier(
      random_state=0,
      **params
    )
    model_hp.fit(X_train, y_train)
    predicted_probs = model_hp.predict_proba(X_test)
    # Tune based on the test AUC
    # In production, you could use a separate validation set instead
    roc_auc = sklearn.metrics.roc_auc_score(y_test, predicted_probs[:,1])
    mlflow.log_metric('test_auc', roc_auc)

    # Set the loss to -1*auc_score so fmin maximizes the auc_score
    return {'status': STATUS_OK, 'loss': -1*roc_auc}

# SparkTrials distributes the tuning using Spark workers
# Greater parallelism speeds processing, but each hyperparameter trial has less information from other trials
# On smaller clusters try setting parallelism=2
spark_trials = SparkTrials(
  parallelism=1
)

with mlflow.start_run(run_name='gb_hyperopt') as run:
  # Use hyperopt to find the parameters yielding the highest AUC
  best_params = fmin(
    fn=train_model,
    space=search_space,
    algo=tpe.suggest,
    max_evals=32,
    trials=spark_trials)

步骤 9. 找到最佳模型并将其注册到 Unity Catalog

以下代码识别产生最佳结果的运行,以 ROC 曲线下的面积来衡量:

# Sort runs by their test auc. In case of ties, use the most recent run.
best_run = mlflow.search_runs(
  order_by=['metrics.test_auc DESC', 'start_time DESC'],
  max_results=10,
).iloc[0]
print('Best Run')
print('AUC: {}'.format(best_run["metrics.test_auc"]))
print('Num Estimators: {}'.format(best_run["params.n_estimators"]))
print('Max Depth: {}'.format(best_run["params.max_depth"]))
print('Learning Rate: {}'.format(best_run["params.learning_rate"]))

以下代码使用为最佳模型确定的 run_id 将该模型注册到 Unity Catalog。

model_uri = 'runs:/{run_id}/model'.format(
    run_id=best_run.run_id
  )

mlflow.register_model(model_uri, f"{CATALOG_NAME}.{SCHEMA_NAME}.wine_quality_model")

示例笔记本:构建分类模型

使用以下笔记本执行本文中的步骤。 有关将笔记本导入 Azure Databricks 工作区的说明,请参阅导入笔记本

使用 Databricks 构建第一个机器学习模型

获取笔记本

了解详细信息

Databricks 提供了一个单一平台,从原始数据到保存所服务模型的每个请求和响应的推理表,为 ML 开发和部署的每个步骤提供服务。 数据科学家、数据工程师、ML 工程师和 DevOps 可使用同一组工具和数据的单一事实来源来执行其工作。

若要了解更多信息,请参阅下列文章: