搜索运行
本指南将引导您了解如何通过 MLflow UI 和 Python API 搜索您的 MLflow 运行。如果您有兴趣根据运行的指标、参数、标签、数据集信息或运行元数据查询特定运行,此资源将非常有价值。
简而言之,您可以利用类似 SQL 的语法,根据各种条件过滤您的运行。请注意,不支持 OR
关键字,并且与 SQL 还有一些其他差异(如下所述),但尽管存在这些限制,运行搜索功能仍然非常强大。
在 MLflow UI 上搜索运行
MLflow UI 提供了一个强大的搜索界面,允许您过滤运行。下面我们将...
- 创建示例 MLflow 运行
- 查看一个简单的查询示例
- 深入了解查询语法
- 提供各种示例查询
创建示例 MLflow 运行
首先,让我们创建一些示例 MLflow 运行。本文档基于使用以下脚本创建的实验。如果您不想在您的机器上以交互方式探索它,请跳过此部分。
在运行脚本之前,让我们先在本地主机上启动 MLflow UI。
mlflow ui
让我们在我们的 Web 浏览器中访问 https://:5000/
。这样做之后,您会注意到我们没有任何实验或模型。让我们通过使用下面的脚本创建一些 MLflow 运行来解决这个问题。
请注意,当您运行此脚本时,您需要从您运行 mlflow ui
命令的同一目录中运行它。
import mlflow
import numpy as np
mlflow.set_experiment("search-run-guide")
accuracy = np.arange(0, 1, 0.1)
loss = np.arange(1, 0, -0.1)
log_scale_loss = np.log(loss)
f1_score = np.arange(0, 1, 0.1)
batch_size = [2] * 5 + [4] * 5
learning_rate = [0.001, 0.01] * 5
model = ["GPT-2", "GPT-3", "GPT-3.5", "GPT-4"] + [None] * 6
task = ["classification", "regression", "causal lm"] + [None] * 7
environment = ["notebook"] * 5 + [None] * 5
dataset_name = ["custom"] * 5 + ["also custom"] * 5
dataset_digest = ["s8ds293b", "jks834s2"] + [None] * 8
dataset_context = ["train"] * 5 + ["test"] * 5
for i in range(10):
with mlflow.start_run():
mlflow.log_metrics(
{
"loss": loss[i],
"accuracy": accuracy[i],
"log-scale-loss": log_scale_loss[i],
"f1 score": f1_score[i],
}
)
mlflow.log_params(
{
"batch_size": batch_size[i],
"learning rate": learning_rate[i],
"model": model[i],
}
)
mlflow.set_tags(
{
"task": task[i],
"environment": environment[i],
}
)
dataset = mlflow.data.from_numpy(
features=np.random.uniform(size=[20, 28, 28, 3]),
targets=np.random.randint(0, 10, size=[20]),
name=dataset_name[i],
digest=dataset_digest[i],
)
mlflow.log_input(dataset, context=dataset_context[i])
上面的代码创建了 10 个具有不同指标、参数、标签和数据集信息的 MLflow 运行。成功执行后,如果您返回浏览器中的 MLflow UI,您应该在实验“search-run-guide”下找到所有这些运行,如下面的屏幕截图所示。
在 MLflow 的实际生产部署中,通常有数千甚至数十万个运行。在这种情况下,能够基于特定标准过滤和搜索运行非常重要。
搜索查询示例
为了过滤您的 MLflow 运行,您需要编写**搜索查询**,这些查询是以独特的语法表达的伪 SQL 条件。
为了展示这个功能,让我们看看下面的代码示例。
import mlflow
all_runs = mlflow.search_runs(search_all_experiments=True)
print(all_runs)
run_id ... tags.mlflow.user
0 5984a3488161440f92de9847e846b342 ... michael.berk
1 41160f238a5841998dda263794b26067 ... michael.berk
2 babe221a676b4fa4b204f8240f2c4f14 ... michael.berk
3 45eb4f02c5a1461aa6098fa550233be6 ... michael.berk
4 1c7c459486c44b23bb016028aee1f153 ... michael.berk
5 4453f59f1ab04491bb9582d8cba5f437 ... michael.berk
6 22db81f070f6413588641c8c343cdd72 ... michael.berk
7 c3680e37d0fa44eb9c9fb7828f6b5481 ... michael.berk
8 67973142b9c0470d8d764ada07c5a988 ... michael.berk
9 59853d5f17f946218f63de1dc82de07b ... michael.berk
[10 rows x 19 columns]
其次,让我们尝试过滤我们真正糟糕的模型运行:metrics.loss > 0.8
。
import mlflow
bad_runs = mlflow.search_runs(
filter_string="metrics.loss > 0.8", search_all_experiments=True
)
print(bad_runs)
run_id ... tags.mlflow.source.name
0 67973142b9c0470d8d764ada07c5a988 ... delete.py
1 59853d5f17f946218f63de1dc82de07b ... delete.py
[2 rows x 19 columns]
您会注意到我们现在显示的是 2 个运行,而不是 10 个。非常简单,对吧?
搜索语法概述
MLflow 的搜索功能利用域特定语言 (DSL) 进行查询。它受到 SQL 的启发,但不提供 SQL 的全部功能。
本节描述语法格式,重点关注搜索查询中的“左侧”和“右侧”元素。“左侧”指的是要过滤的字段,例如 metrics.loss
,而“右侧”指的是与该字段进行比较的值,例如 0.8
。
搜索组件的可视化表示
左侧和右侧元素的有效语法
-
左侧语法
- 没有特殊字符或保留关键字的字段可以直接引用(例如,
tag.test
)。 - 对于包含特殊字符或属于保留关键字的字段,请使用反引号。
- 双引号也可以接受用于包围字段名称(例如,
tag."test"
)。
不支持
- 单引号对于包围字段名称是**无效的**(例如,
tag.'test'
会导致语法错误)。
- 没有特殊字符或保留关键字的字段可以直接引用(例如,
-
右侧语法
- 根据内容要求,将值括在单引号或双引号中(例如,
tag.`test` = 'abc'
或tag.`test` = "abc"
)。 - 非指标值,**包括可能存储为标签或参数的数字值**,必须用引号括起来。
不支持
- 不允许对值使用反引号或不进行包装。无效语法的例子包括
这会导致语法错误,因为反引号不能用于右侧值。
tag.`test` = `abc`
这会导致语法错误,因为如果值不是指标,则必须用双引号括起来。
tag.`test` = abc
- 根据内容要求,将值括在单引号或双引号中(例如,
搜索查询语法深入探讨
如上所述,MLflow 搜索语法与 SQL 类似,但有一些值得注意的例外。
- 不支持 SQL 的
OR
关键字。 - 对于包含特殊字符或以数字开头的字段,这些字段应该用**反引号**括起来。
- Bad: metrics.cross-entropy-loss < 0.5
+ Good: metrics.`cross-entropy-loss` < 0.5
- Bad: params.1st_iteration_timestamp = "2022-01-01"
+ Good: params.`1st_iteration_timestamp` = "2022-01-01"
- 对于 SQL 的
IN
关键字,您必须用**单引号**包围列表中的值。
- Bad: attributes.run_id IN ("5984a3488161440f92de9847e846b342", "babe221a676b4fa4b204f8240f2c4f14")
+ Good: attributes.run_id IN ('5984a3488161440f92de9847e846b342', 'babe221a676b4fa4b204f8240f2c4f14')
-
对于 SQL 的
IN
关键字,您只能搜索以下字段datasets.name
datasets.digest
datasets.context
attributes.run_id
-
不支持数值字段的非空条件,例如
metrics.accuracy != "None"
将会失败。
除此之外,对于任何使用过 SQL 的人来说,语法都应该是直观的。要组装一个单独的搜索条件,您必须使用以下组件组装一个不等式...
-
一个 MLflow 字段:一个指标、参数、标签、数据集或运行元数据。
-
一个比较器:一个不等式运算符。
-
对于数值,MLflow 支持
=
、!=
、>
、>=
、<
和<=
。例子包括metrics.accuracy > 0.72
metrics.loss <= 0.15
metrics.accuracy != 0.15 -
对于字符串,MLflow 支持
=
、!=
、LIKE
(区分大小写)和ILIKE
(不区分大小写)。例子包括params.model = "GPT-4o"
params.model LIKE "GPT%"
params.model ILIKE "gpt%" -
对于集合,MLflow 支持
IN
。例子包括datasets.name IN ('custom', 'also custom', 'another custom name')
datasets.digest IN ('s8ds293b', 'jks834s2')
attributes.run_id IN ('5984a3488161440f92de9847e846b342')
-
-
一个参考值:一个数值、字符串或字符串集。
让我们看一些更多的例子。
示例查询
在本节中,我们将介绍如何按不同的 MLflow 字段类别进行搜索。对于每个类别,我们提供了一些示例查询。如果您已经执行了我们提供的运行创建脚本,这些查询应该获取某些运行,但有时需要修改以获取特定于运行的信息,例如 start_time
。
1 - 按指标搜索
指标是通常用于评估模型在训练期间或之后性能的定量度量。指标可以包括诸如准确率、精确率、召回率、F1 分数等值,并且可以随着模型的训练而随时间变化。它们通过 mlflow.log_metric
或 mlflow.log_metrics
手动记录,或通过自动日志记录自动记录。
要通过过滤指标来搜索运行,您必须在不等式的左侧包含 metrics
前缀。请注意,它们**存储为数字**,因此您必须使用数值比较器。
metrics.accuracy > 0.72
metrics."accuracy" > 0.72
metrics.loss <= 0.15
metrics.`log-scale-loss` <= 0
metrics.`f1 score` >= 0.5
metrics.accuracy > 0.72 AND metrics.loss <= 0.15
2 - 按参数搜索
参数是通常表示模型配置方面的字符串。参数可以包括诸如学习率、批量大小和 epoch 数等值。它们通过 mlflow.log_param
或 mlflow.log_params
手动记录,或通过自动日志记录自动记录。
要通过过滤参数来搜索运行,您必须在不等式的左侧包含 params
前缀。请注意,它们**存储为字符串**,因此您必须使用字符串比较器,例如 =
和 !=
。
请注意,存储为参数的数值在跟踪存储中被转换为字符串。在查询数值参数时,您必须通过将它们括在**双引号**中来指定它们为字符串。
params.batch_size = "2"
params.model LIKE "GPT%"
params.model ILIKE "gPt%"
params.model LIKE "GPT%" AND params.batch_size = "2"
3 - 按标签搜索
标签是通常提供关于运行的附加上下文的元数据。标签可以包括诸如用户名、团队等值。它们通过 mlflow.set_tag
或 mlflow.set_tags
手动记录。此外,系统标签,例如 mlflow.user
,会被自动记录。
要通过过滤标签来搜索运行,您必须在不等式的左侧包含 tags
或 mlflow
前缀。请注意,标签**存储为字符串**,因此您必须使用字符串比较器,例如 =
和 !=
。
tags."environment" = "notebook"
tags.environment = "notebook"
tags.task = "Classification"
tags.task ILIKE "classif%"
4 - 按数据集信息搜索
数据集表示在模型训练或评估中使用的数据,包括特征、目标、预测以及元数据,例如数据集的名称、摘要(哈希)、模式、配置文件和来源。它们通过 mlflow.log_input
记录,或通过自动日志记录自动记录。
要通过过滤数据集信息来搜索运行,您必须过滤以下字段之一
datasets.name
,它是数据集的名称。datasets.digest
,它是数据集的唯一标识符。datasets.context
,它表示数据集是用于训练、评估还是测试。
请注意,数据集信息**存储为字符串**,因此您必须使用字符串比较器,例如 =
和 !=
。另请注意,数据集支持集合比较器,例如 IN
。
datasets.name LIKE "custom"
datasets.digest IN ('s8ds293b', 'jks834s2')
datasets.context = "train"
5 - 按运行的元数据搜索
运行元数据是各种用户指定和系统生成的属性,它们提供了关于运行的附加上下文。
要通过过滤运行的元数据来搜索运行,您必须在不等式的左侧包含 attributes
前缀。请注意,运行元数据可以是字符串或数字,具体取决于属性,因此您必须使用适当的比较器。 有关属性的完整列表,请参见
mlflow.entities.RunInfo,但请注意,并非 RunInfo 对象中的所有字段都可搜索。
要通过过滤标签来搜索运行,您必须在不等式的左侧包含 tags
或 mlflow
前缀。请注意,标签**存储为字符串**,因此您必须使用字符串比较器,例如 =
和 !=
。
attributes.status = "ACTIVE"
attributes.user_id LIKE "user1"
attributes.run_name = "my-run"
attributes.run_id = "a1b2c3d4"
attributes.run_id IN ('a1b2c3d4', 'e5f6g7h8')
attributes.start_time >= 1664067852747
attributes.end_time < 1664067852747
attributes.created > 1664067852747
6 - 在集合上搜索
您可以通过 IN
关键字过滤一组可接受的值来搜索运行。如上所述,这仅支持以下字段
datasets.{any_attribute}
attributes.run_id
datasets.name IN ('custom', 'also custom')
datasets.digest IN ('s8ds293b', 'jks834s2')
attributes.run_id IN ('a1b2c3d4', 'e5f6g7h8')
7 - 链式查询
您可以使用 AND
关键字将多个查询链接在一起。例如,要搜索具有各种条件的运行,您可以使用以下查询
metrics.accuracy > 0.72 AND metrics.loss <= 0.15
metrics.accuracy > 0.72 AND metrics.batch_size != 0
metrics.accuracy > 0.72 AND metrics.batch_size != 0 AND attributes.run_id IN ('a1b2c3d4', 'e5f6g7h8')
您还可以在同一字段上应用多个条件,例如搜索所有 BETWEEN
0.1 和 0.15(包括 0.1 和 0.15)之间的损失指标
metrics.loss <= 0.15 AND metrics.loss >= 0.1
最后,在继续之前,重要的是要重申您不能在查询中使用 OR
关键字。
8 - 非空查询
要搜索字段(仅支持字符串类型)不为 null 的运行,请使用 field != "None"
语法。 例如,要搜索 batch_size 不为 null 的运行,您可以使用以下查询
params.batch_size != "None"
以编程方式搜索运行
在扩展到大型生产系统时,通常您希望在 MLflow UI 之外与您的运行交互。 这可以使用 MLflow 客户端 API 以编程方式完成。
Python
mlflow.client.MlflowClient.search_runs()
或 mlflow.search_runs()
接受与上述 UI 示例相同的参数,甚至更多! 它们返回所有与指定过滤器匹配的运行。 您最好的资源是每个函数的文档字符串,但这里有一些有用的例子。
1 - 复杂过滤器
Python 提供了以编程方式构建这些查询的强大方法。 一些提示
- 对于复杂的过滤器,特别是那些既有单引号又有双引号的过滤器,使用多行字符串或
\\"
来转义引号。 - 当处理列表时,使用
.join()
方法用分隔符连接列表元素。 - 使用 fluent API 通常是最简洁的,因此下面我们仅使用 fluent API 进行演示。
import mlflow
run_ids = ["22db81f070f6413588641c8c343cdd72", "c3680e37d0fa44eb9c9fb7828f6b5481"]
run_id_condition = "'" + "','".join(run_ids) + "'"
complex_filter = f"""
attributes.run_id IN ({run_id_condition})
AND metrics.loss > 0.3
AND metrics."f1 score" < 0.5
AND params.model LIKE "GPT%"
"""
runs_with_complex_filter = mlflow.search_runs(
experiment_names=["search-run-guide"],
filter_string=complex_filter,
)
print(runs_with_complex_filter)
输出将是一个 pandas DataFrame,其中包含与指定过滤器匹配的运行,如下所示。
run_id ... tags.mlflow.runName
0 22db81f070f6413588641c8c343cdd72 ... orderly-quail-568
1 c3680e37d0fa44eb9c9fb7828f6b5481 ... melodic-lynx-301
[2 rows x 19 columns]
2 - run_view_type
如 mlflow.entities.ViewType 枚举中所述,run_view_type
参数公开了额外的过滤选项。 例如,如果您只想过滤活动运行(这是 UI 中的一个下拉列表),只需传递 run_view_type=ViewType.ACTIVE_ONLY
。
import mlflow
from mlflow.entities import ViewType
active_runs = mlflow.search_runs(
experiment_names=["search-run-guide"],
run_view_type=ViewType.ACTIVE_ONLY,
order_by=["metrics.accuracy DESC"],
)
3 - 排序
搜索 API 中提供的另一个有用功能是允许对返回的搜索结果进行排序。 您可以在 order_by
kwarg 中指定感兴趣的列的列表以及 DESC
或 ASC
。 请注意,DESC
或 ASC
值是可选的,因此当未提供该值时,默认值为 ASC
。 另请注意,当省略 order_by
参数时,默认排序是按 start_time DESC
排序,然后按 run_id ASC
排序。
import mlflow
from mlflow.entities import ViewType
active_runs_ordered_by_accuracy = mlflow.search_runs(
experiment_names=["search-run-guide"],
run_view_type=ViewType.ACTIVE_ONLY,
order_by=["metrics.accuracy DESC"],
)
一个常见的用例是获得前 n
个结果,例如,按准确率排序的前 5 个运行。 当与 max_results
参数结合使用时,您可以获得与您的查询匹配的前 n
个结果。
import mlflow
from mlflow.entities import ViewType
highest_accuracy_run = mlflow.search_runs(
experiment_names=["search-run-guide"],
run_view_type=ViewType.ACTIVE_ONLY,
max_results=1,
order_by=["metrics.accuracy DESC"],
)[0]
4 - 搜索所有实验
现在您可能想知道如何搜索所有实验。 就像指定 search_all_experiments=True
并省略 experiment_ids
参数一样简单。
import mlflow
from mlflow.entities import ViewType
model_of_interest = "GPT-4"
gpt_4_runs_global = mlflow.search_runs(
filter_string=f"params.model = '{model_of_interest}'",
run_view_type=ViewType.ALL,
search_all_experiments=True,
)
最后,mlflow.client.MlflowClient.search_runs()
或 mlflow.search_runs()
方法中还有其他有用的功能,因此请务必查看文档以获取更多详细信息。
R
R API 与 Python API 类似,区别在于过滤器条件必须用字符串包装。 由于这种行为,右侧条件元素对于参数、属性和标签必须用单引号包装。
library(mlflow)
mlflow_search_runs(
filter = "metrics.rmse < 0.9 and tags.production = 'true'",
experiment_ids = as.character(1:2),
order_by = "params.lr DESC"
)
Java
Java API 与 Python API 类似,区别在于整个条件过滤器语法都被字符串封装。 这是因为 Java API 是 Python 核心 API 周围的一个薄包装器,因此将在两种语言之间进行翻译。
List<Long> experimentIds = Arrays.asList("1", "2", "4", "8");
List<RunInfo> searchResult = client.searchRuns(experimentIds, "metrics.accuracy_score < 99.90");