跳至主要内容

机器学习实验:Weights & Biases 入门

了解如何使用 Weights & Biases 规划、记录并分析您的机器学习实验。
· 9分钟 阅读

使用 AI 探索

不量化,就无法分析

image6.png

您是否曾在回顾某个机器学习项目时,想不起当时为何做出某些决定,甚至不确定代码具体在做什么?例如,为什么选择了这组特征、最终模型训练用的是哪个数据版本、不同超参数组合如何影响了性能?听起来,您需要在机器学习项目中引入规范的实验实践!

机器学习实验是指围绕既定评估指标(如 F1 分数、RMSE 等)设计、构建、记录并评估一条机器学习流水线,以确定达到目标性能的模型。这既是在部署前也是在重训过程中开发机器学习模型的关键环节。与其他实验一样,它的设计应当:

  • 可复现
  • 尽量降低偏差
  • 完整追踪所有必要的文件与工件

秉持这些目标,您就能轻松定位所需内容(如模型超参数或数据集版本),并方便共享信息(如模型表现与源码)。

好在,这正是 Weights & Biases 大显身手的地方! 

使用 Weights & Biases 构建机器学习流水线

Weights & Biases 是一个平台与 Python 库,为机器学习工程师提供实验运行、工件记录、超参数自动调优与性能评估能力。本教程将通过一个机器学习流水线示例介绍其核心功能:记录关键要素并在仪表盘中加以查看!

安装与登录

# Install Python library
!pip install wandb

要登录,您需要先注册一个账号。

创建完成后,访问授权页面获取可用于登录的 API 密钥。请妥善保存,切勿与他人共享!

登录方式:可以打开新终端并输入 wandb login,或在笔记本中新增一个单元并执行 !wandb login。

系统会提示您提供 API 密钥。复制粘贴后即可成功登录。此后您的凭据会本地存储在 ~/.netrc。

wandb login

创建实验

Weights & Biases 包含多个组件,如 Experiments、Artifacts、Sweeps 和 Models。我们先从工作流的核心——创建并运行实验——开始。

# Import required modules
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import wandb
from sklearn.model_selection import train_test_split, GridSearchCV, KFold
from sklearn.linear_model import LinearRegression, Ridge
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error, r2_score

在 Weights & Biases 中,Experiment 也称为项目(project)。要创建新项目,调用 wand.init() 函数,并将项目名称作为字符串传递给 project 关键字参数。您可以将其赋给名为 run 的变量,以便向该 run 记录重要的文件、模型和指标。

此外,您还可以为 job_type 关键字参数提供字符串,便于区分不同步骤,如 EDA、特征工程或超参数调优。并且,将 save_code 设为 True 可记录您执行的代码。

# Initialize a run
run = wandb.init(project="predicting_london_temperature",
                 job_type="Baseline modeling",
                 save_code=True)

记录工件

您可以将任何重要信息(如数据集、变量或文件)以 Artifact 的形式记录。具体做法是,先调用 wandb.Artifact() 创建一个变量,提供名称与类型,然后使用 wandb.log_artifact() 进行记录。我们先来记录原始数据集。

original_data = "london_weather.csv"
# Create an Artifact
data_artifact = wandb.Artifact(name="original_dataset", 
                               type="data",
                               description="London weather dataset")
# Add the file to the Artifact
data_artifact.add_file(original_data)
# Log the Artifact as part of the run
run.log_artifact(data_artifact)

探索性数据分析

探索性数据分析(EDA)是机器学习工作流中的关键步骤,帮助您确保数据类型正确且不存在缺失值与离群值。这也是检查特征分布与相互关系的机会。

使用 Weights & Biases 的额外好处在于,您在预处理时可以一并记录数据以及生成的可视化。

# Read in the data
london = pd.read_csv(original_data)

# Previewing the first five rows
london.head()

image12.png

# Visualize distributions
plt.figure(figsize=(12,8))
london.hist()
plt.tight_layout()
plt.show()

image13.png

# View data types and non-null counts
london.info()


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 15341 entries, 0 to 15340
Data columns (total 10 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   date              15341 non-null  int64  
 1   cloud_cover       15322 non-null  float64
 2   sunshine          15341 non-null  float64
 3   global_radiation  15322 non-null  float64
 4   max_temp          15335 non-null  float64
 5   mean_temp         15305 non-null  float64
 6   min_temp          15339 non-null  float64
 7   precipitation     15335 non-null  float64
 8   pressure          15337 non-null  float64
 9   snow_depth        13900 non-null  float64
dtypes: float64(9), int64(1)
memory usage: 1.2 MB


# Convert date to datetime
london["date"] = pd.to_datetime(london["date"], format="%Y%m%d")

# Add a month column
london["month"] = london["date"].dt.month

# Drop missing values
london.dropna(inplace=True)

现在数据已清洗完毕,您可以使用 wand.Artifact() 将其作为一个 Artifact 记录下来。

# Save and log the new version of the data
london.to_csv("london_weather_preprocessed.csv", index=False)
preprocessed_data = "london_weather_preprocessed.csv"
# Create an Artifact
preprocessed_data_artifact = wandb.Artifact(name="london_weather_preprocessed", 
                               type="data",
                               description="London weather dataset - preprocessed")
# Add the file to the Artifact
preprocessed_data_artifact.add_file(preprocessed_data)
# Log the Artifact as part of the run
run.log_artifact(preprocessed_data_artifact)


<wandb.sdk.artifacts.local_artifact.Artifact at 0x15bfe6710>

特征选择

下一步是识别潜在建模特征并避免多重共线性。可以先绘制相关性热力图,再使用岭回归衡量特征对预测“mean_temperature”的重要性。

# Correlation heatmap
sns.heatmap(london.corr(), annot=True, center=True)
plt.show()

image2.png

您可以使用 wandb.Image() 来记录这张图!

# Log the heatmap
wandb.log({"correlation_heatmap": wandb.Image(plt)})


# Split the data
X = london.drop(columns=["mean_temp", "min_temp", "max_temp", "date"])
y = london["mean_temp"]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.2)

# Build a Ridge regression model
ridge = Ridge(alpha=0.1)
ridge.fit(X_train, y_train)
y_pred = ridge.predict(X_test)

# Visualize feature importance using the coefficients
fig = plt.figure()
sns.barplot(x=X_train.columns, y=ridge.coef_)
plt.xticks(rotation=30)
plt.tight_layout()
plt.savefig("feature_selection.png")
plt.show()

image11.png

让我们使用 pickle.dump() 和 wandb.log() 保存模型与特征重要性图。

import pickle
pickle.dump(ridge, open("feature_selection_model.pkl", "wb"))
feature_selection_model = wandb.Artifact("feature_selection_model", type="model")
feature_selection_model.add_file("feature_selection_model.pkl")
run.log_artifact(feature_selection_model)
wandb.log({"feature_selection_plot": wandb.Image(fig)})


<Figure size 640x480 with 0 Axes>

训练与记录

做得很好!现在用已识别的重要特征来训练基线模型,这些特征在岭回归模型中的系数大于 0。您还将记录新的训练与测试数据。

X = london[["cloud_cover", "global_radiation", "precipitation", "month"]]
y = london["mean_temp"]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.2)

def log_data(X_train, y_train, X_test, y_test):
    # Log the training and test data
    training_features = wandb.Artifact(name="X_train", 
                               type="data",
                               description="Training features")
    X_train.to_csv("X_train.csv", index=False)
    training_features.add_file("X_train.csv")
    run.log_artifact(training_features)

    training_labels = wandb.Artifact(name="y_train", 
                               type="data",
                               description="Training labels")
    y_train.to_csv("y_train.csv", index=False)

    training_labels.add_file("y_train.csv")
    run.log_artifact(training_labels)

    test_features = wandb.Artifact(name="X_test", 
                               type="data",
                               description="Test features")
    X_test.to_csv("X_test.csv", index=False)
    test_features.add_file("X_test.csv")
    run.log_artifact(test_features)

    test_labels = wandb.Artifact(name="y_test", 
                               type="data",
                               description="Test labels")
    y_test.to_csv("y_test.csv", index=False)
    test_labels.add_file("y_test.csv")
    run.log_artifact(test_labels)

log_data(X_train, y_train, X_test, y_test)

我们来训练并评估一个决策树回归模型,以均方根误差(RMSE)与 R 方作为性能指标。

# Fit and evaluate the model
dt_reg = DecisionTreeRegressor(random_state=42)
dt_reg.fit(X_train, y_train)
y_pred = dt_reg.predict(X_test)
rmse = mean_squared_error(y_test, y_pred, squared=False)
r_squared = r2_score(y_test, y_pred)
print(rmse, r_squared)


3.8627385194713346 0.5399282872125385

# Save and log the model and metrics
pickle.dump(dt_reg, open("baseline_decision_tree.pkl", "wb"))
baseline_model = wandb.Artifact("baseline_decision_tree", type="model")
baseline_model.add_file("baseline_decision_tree.pkl")
run.log_artifact(baseline_model)
wandb.log({"rmse": rmse, "r_squared": r_squared})

您还可以通过可视化残差来更深入分析模型表现。Weights & Biases 在其 sklearn 模块中提供了对应函数!

# Plot training residuals
wandb.log({"baseline_residuals_plot": wandb.sklearn.plot_residuals(dt_reg, X_train, y_train)})

image7.jpg

训练与评估已完成,让我们结束当前 run。

# Finish run
wandb.finish()

image4.png

超参数调优

现在您已创建并记录了一个包含性能指标的基线模型,接下来看看如何结合 Weights & Biases 与 scikit-learn 进行超参数调优并为模型做版本管理。

我们将使用 GridSearchCV 在超参数空间中搜索基于 RMSE 表现最佳的模型。

# Initialize a new run
run_v2 = wandb.init(project="predicting_london_temperature",
                 job_type="Hyperparameter tuning",
                 save_code=True)

# Split the data and create a KFold object
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.2)
kf = KFold(n_splits=5, shuffle=True, random_state=42)

# Create the hyperparameter space
params = {"max_depth":[2, 5, 8, 12, 20],
          "min_samples_split": [2, 5, 8, 12, 20],
          "max_features": [1, 2, 3, 4],
          "random_state": [42]
          }

# Create a GridSearchCV object
dt_reg = DecisionTreeRegressor()
dt_reg_cv = GridSearchCV(dt_reg, 
                         params, 
                         cv=kf,
                         scoring="neg_root_mean_squared_error")

# Fit the data
dt_reg_cv.fit(X_train, y_train)

# Evaluate and log performance
## GridSearchCV uses negative RMSE
## so you can convert it to positive
print(f"Best RMSE: {-1 * dt_reg_cv.best_score_})")
print(f"Best model: {dt_reg_cv.best_estimator_}")

# Save and log the model, metrics, and parameters
pickle.dump(dt_reg_cv, open("tuned_decision_tree.pkl", "wb"))
tuned_decision_tree = wandb.Artifact("tuned_decision_tree", type="model")
tuned_decision_tree.add_file("tuned_decision_tree.pkl")
run_v2.log_artifact(tuned_decision_tree)
wandb.log({"rmse": -1 * dt_reg_cv.best_score_})
wandb.finish()

image5.png

image1.png

查看仪表盘

要查看 runs 与工件,您可以访问 www.wandb.ai/<your-profile-name>/projects,然后选择您创建的项目。

进入后,您会看到自己创建的每个 run,以及相关媒体(如图表),类似这样:

image3.jpg

点击 Runs 图标,您可以查看所有 run 及其关键信息,包括记录的指标,如 RMSE 和 R 方。

image8.jpg

后续步骤

Weights & Biases 还有许多功能可供探索,例如在新 run 中使用现有工件、命令行界面工具,以及用于开发大语言模型的Prompts!

若想巩固关于机器学习实验及更广泛 MLOps 技术的知识,您可以查看:

  • MLOps Concepts——一门涵盖从设计到部署与维护的机器学习生命周期的概念课程,并介绍贯穿全程的关键理念与相关方!
  • Introduction to MLFlow——这门 Python 课程将教您使用 MLFlow 的四大核心组件:Tracking、Models、Projects 和 Model Registry。
George Boorman

作者

George Boorman

George 是 DataCamp 的课程主管。他拥有健康运动学研究生文凭(PGDip)和运动科学荣誉学士学位(BSc Hons),并在公共卫生、应用研究和非营利领域具有项目管理经验。George 热衷于体育、“技术向善”,以及与数据科学有关的一切。

主题