机器学习管道故障排除

适用于:Azure Machine Learning SDK v1 for Python

重要

本文提供有关使用 Azure Machine Learning SDK v1 的信息。 SDK v1 自 2025 年 3 月 31 日起弃用。 对它的支持将于 2026 年 6 月 30 日结束。 可以在该日期之前安装和使用 SDK v1。 使用 SDK v1 的现有工作流将在支持结束日期后继续运行。 但是,在产品发生体系结构更改时,可能会面临安全风险或中断性变更。

建议在 2026 年 6 月 30 日之前过渡到 SDK v2。 有关 SDK v2 的详细信息,请参阅 什么是 Azure Machine Learning CLI 和 Python SDK v2?SDK v2 参考

注释

已停用的包:以下 SDK v1 包已停用:azureml-pipeline、azureml-pipeline-core、azureml-pipeline-internal、azureml-pipeline-steps 和 azureml-train-core。

本文介绍如何排查在 机器学习管道Azure Machine Learning SDKAzure Machine Learning 设计器 中运行时发生的错误。

故障排除提示

下表包含管道开发期间出现的一些常见问题,以及可能的解决方法。

问题 可能的解决方法
无法将数据传递给 PipelineData 字典 请确保在脚本中创建一个目录,该目录对应于管道需要步骤输出数据的位置。 大多数情况下,输入参数将定义输出目录,然后你需要显式创建该目录。 使用 os.makedirs(args.output_dir, exist_ok=True) 创建输出目录。 有关演示此设计模式的评分脚本示例,请参阅该教程
依赖项错误 如果在远程管道中看到在本地测试时未发生的依赖项错误,请确认远程环境依赖项和版本与测试环境中的依赖项和版本匹配。 (请参阅 环境生成、缓存和重用
计算目标出现不明确的错误 请尝试删除并重新创建计算目标。 重新创建计算目标很快,可以解决一些暂时性问题。
流水线未重用步骤 默认情况下,步骤重用是启用的,但请确保您未在管道步骤中将其禁用。 如果禁用重用,请将 allow_reuse 步骤中的参数设置为 False
管道不必要地重新运行 为了确保步骤只在其基础数据或脚本发生更改时才重新运行,请分离每个步骤的源代码目录。 如果对多个步骤使用相同的源目录,则可能会遇到不必要的重新运行。 在管道步骤对象中使用 source_directory 参数以指向该步骤的隔离目录,并确保未对多个步骤使用同一个 source_directory 路径。
在训练时期或其他循环行为中逐步减速 尝试将任何文件写入操作(包括日志记录)从 as_mount() 切换到 as_upload()。 “挂载”模式使用远程虚拟化文件系统,每次将文件追加到该系统时会上传整个文件。
计算目标启动时间过长 计算目标的 Docker 映像从 Azure Container Registry (ACR) 加载。 默认情况下,Azure Machine Learning创建使用 basic 服务层级的 ACR。 将工作区的 ACR 更改为标准层或高级层可能会缩短生成和加载映像所需的时间。 有关详细信息,请参阅 Azure Container Registry 服务层级

身份验证错误

如果通过远程作业对某个计算目标执行管理操作,会收到以下错误之一:

{"code":"Unauthorized","statusCode":401,"message":"Unauthorized","details":[{"code":"InvalidOrExpiredToken","message":"The request token was either invalid or expired. Please try again with a valid token."}]}
{"error":{"code":"AuthenticationFailed","message":"Authentication failed."}}

例如,如果尝试从提交以进行远程执行的 ML 管道创建或附加计算目标,则会收到错误。

ParallelRunStep 进行故障排除

注释

ParallelRunStep 是已停用的 azureml-pipeline-steps 包的一部分。 计划迁移到 SDK v2 替代方案。 有关详细信息,请参阅 使用 Azure Machine Learning CLI/SDK v2 来生成和运行机器学习管道。

ParallelRunStep 的脚本必须包含两个函数

  • init():此函数适用于后续推理的任何成本高昂或常见的准备工作。 例如,使用它将模型加载到全局对象。 此函数仅在进程开始时调用一次。
  • run(mini_batch):函数将针对每个 mini_batch 实例运行。
    • mini_batchParallelRunStep 调用 run 方法,并将列表或 pandas DataFrame 作为参数传递给该方法。 如果输入是mini_batch,则FileDataset中的每个条目都是文件路径;如果输入是DataFrame,则为 pandasTabularDataset
    • response:该方法 run() 应返回 pandas DataFrame 或数组。 因此 append_rowoutput_action,这些返回的元素将追加到通用输出文件中。 对于 summary_only,将忽略元素的内容。 对于所有的输出操作,每个返回的输出元素都指示输入微型批处理中输入元素的一次成功运行。 确保运行结果中包含足够的数据,以便将输入映射到运行输出结果。 运行输出将写入输出文件中,并且不保证按顺序写入,你应使用输出中某个键将其映射到输入。

注释

此代码示例使用 TensorFlow 1.x API (tf.Sessiontf.reset_default_graph) 。 这些 API 已在 TensorFlow 2.x 中删除。 如果使用的是 TensorFlow 2.x,请使用 tf.compat.v1 兼容性模式或重写为使用即时执行。 有关详细信息,请参阅 将 TensorFlow 1 代码迁移到 TensorFlow 2

%%writefile digit_identification.py
# Snippets from a sample script.
# Refer to the accompanying digit_identification.py
# (https://github.com/Azure/MachineLearningNotebooks/tree/master/how-to-use-azureml/machine-learning-pipelines/parallel-run)
# for the implementation script.

import os
import numpy as np
import tensorflow as tf
from PIL import Image
from azureml.core import Model


def init():
    global g_tf_sess

    # Pull down the model from the workspace
    model_path = Model.get_model_path("mnist")

    # Construct a graph to execute
    tf.reset_default_graph()
    saver = tf.train.import_meta_graph(os.path.join(model_path, 'mnist-tf.model.meta'))
    g_tf_sess = tf.Session()
    saver.restore(g_tf_sess, os.path.join(model_path, 'mnist-tf.model'))


def run(mini_batch):
    print(f'run method start: {__file__}, run({mini_batch})')
    resultList = []
    in_tensor = g_tf_sess.graph.get_tensor_by_name("network/X:0")
    output = g_tf_sess.graph.get_tensor_by_name("network/output/MatMul:0")

    for image in mini_batch:
        # Prepare each image
        data = Image.open(image)
        np_im = np.array(data).reshape((1, 784))
        # Perform inference
        inference_result = output.eval(feed_dict={in_tensor: np_im}, session=g_tf_sess)
        # Find the best probability, and add it to the result list
        best_result = np.argmax(inference_result)
        resultList.append("{}: {}".format(os.path.basename(image), best_result))

    return resultList

如果推理脚本所在的同一目录中包含另一个文件或文件夹,可以通过查找当前工作目录来引用此文件或文件夹。

script_dir = os.path.realpath(os.path.join(__file__, '..',))
file_path = os.path.join(script_dir, "<file_name>")

ParallelRunConfig 的参数

ParallelRunConfig 是Azure Machine Learning管道中 ParallelRunStep 实例的主配置。 使用它包装脚本并配置必要的参数,包括以下所有条目:

  • entry_script:用户脚本作为本地文件路径,在多个节点上并行运行。 如果 source_directory 存在,则使用相对路径。 否则,请使用计算机上可访问的任何路径。
  • mini_batch_size:传递给单个 run() 调用的微型批处理的大小。 (可选;默认值对于 10FileDataset 个文件,对应 1MBTabularDataset。)
    • 对于 FileDataset,指的是文件数量,其最小值为 1。 可以将多个文件合并成一个微型批处理。
    • 对于 TabularDataset,它是数据的大小。 示例值为 10241024KB10MB1GB。 建议值为 1MB。 从 TabularDataset 不跨越文件边界的迷你批处理。 例如,如果你有各种大小的 .csv 文件,最小的文件为 100 KB,最大的文件为 10 MB。 如果设置 mini_batch_size = 1MB,则大小不到 1 MB 的文件将被视为一个微型批处理。 大小不到 1 MB 的文件将会拆分为多个微型批处理。
  • error_threshold:进程忽略的记录失败 TabularDataset 次数和文件失败 FileDataset 次数。 如果整个输入的错误计数超出此值,则作业将中止。 错误阈值适用于整个输入,不适用于发送到该方法的 run() 单个小型批处理。 范围为 [-1, int.max]。 该值 -1 指示在处理过程中忽略所有失败。
  • output_action:以下值之一指示输出的组织方式:
    • summary_only:用户脚本可存储输出。 ParallelRunStep 仅将输出用于错误阈值计算。
    • append_row:对于所有输入,输出文件夹中将仅创建一个文件来追加所有按行分隔的输出。
  • append_row_file_name:自定义输出文件名( append_rowoutput_action 可选;默认值为 parallel_run_step.txt)。
  • source_directory:文件夹的路径,这些文件夹包含要在计算目标上执行的所有文件(可选)。
  • compute_target:仅支持 AmlCompute
  • node_count:用于运行用户脚本的计算节点数。
  • process_count_per_node:每个节点的进程数。 将此值设置为 GPU 或 CPU 一个节点的数目(可选;默认值为 1)。
  • environment:Python环境定义。 可以将它配置为使用现有Python环境或设置临时环境。 定义还负责设置所需的应用程序依赖项(可选)。
  • logging_level:日志详细程度。 递增详细程度的值为:WARNINGINFODEBUG。 (可选;默认值为 INFO
  • run_invocation_timeoutrun() 方法调用超时的时间(以秒为单位)。 (可选;默认值为 60
  • run_max_try:微型批处理的 run() 的最大尝试次数。 run()如果引发异常,或者当达到run_invocation_timeout时没有返回任何内容,将失败(可选;默认值为3)。

可以指定mini_batch_sizenode_countprocess_count_per_nodelogging_levelrun_invocation_timeoutrun_max_try作为PipelineParameter值。 重新提交管道运行时,可以微调这些参数值。 在此示例中,你将对 PipelineParametermini_batch_size 使用 process_count_per_node,并在稍后重新提交运行时更改这些值。

用于创建 ParallelRunStep 的参数

使用脚本、环境配置和参数创建ParallelRunStep。 将已附加到工作区的计算目标指定为推理脚本的执行目标。 使用 ParallelRunStep 创建批处理推理管道步骤,该步骤采用以下所有参数:

  • name:步骤的名称。 名称必须是唯一的,3-32 个字符,并且与正则表达式 ^[a-z]([-a-z0-9]*[a-z0-9])?$匹配。
  • parallel_run_configParallelRunConfig 对象,如前文所述。
  • inputs:要分区进行并行处理的一个或多个单类型Azure Machine Learning数据集。
  • side_inputs:一个或多个引用数据或数据集用作侧输入,无需分区。
  • output:与输出目录相对应的 OutputFileDatasetConfig 对象。
  • arguments:传递给用户脚本的参数列表。 使用 unknown_args 在入口脚本(可选)中检索它们。
  • allow_reuse:使用相同设置和输入运行时,该步骤是否应重复使用以前的结果。 如果将此参数设置为False,在管道执行过程中,管道会为此步骤生成新的执行。 (可选;默认值为 True。)
from azureml.pipeline.steps import ParallelRunStep

parallelrun_step = ParallelRunStep(
    name="predict-digits-mnist",
    parallel_run_config=parallel_run_config,
    inputs=[input_mnist_ds_consumption],
    output=output_dir,
    allow_reuse=True
)

调试方法

调试管道的三种主要技术是:

  • 在本地计算机上调试单个管道步骤。
  • 使用日志记录和 Application Insights 来隔离和诊断问题的来源。
  • 将远程调试器附加到Azure中运行的管道。

在本地调试脚本

管道中最常见的失败之一是域脚本未按预期运行,或者在难以调试的远程计算上下文中包含运行时错误。

管道本身无法在本地运行。 但通过在本地计算机上运行处于隔离状态的脚本,可以更快地进行调试,因为无需等待计算和环境生成过程。 执行此操作需要完成一些开发工作:

  • 如果数据位于云数据存储中,则需要下载并向脚本提供数据。 使用较小的数据样本是减少运行时间并快速获得脚本行为反馈的有效方法。
  • 如果正在尝试模拟某个中间管道步骤,则可能需要手动生成特定脚本预期从前一步骤获取的对象类型
  • 需要定义自己的环境,并复制在远程计算环境中定义的依赖项

在本地环境中设置好脚本后,可以更轻松地进行调试工作,例如:

  • 附加自定义调试配置
  • 暂停执行和检查对象状态
  • 捕获在运行时之前无法被检测到的类型或逻辑错误

提示

确认脚本按预期运行后,合理的下一步是在单步管道中运行该脚本,然后尝试在包含多个步骤的管道中运行该脚本。

配置、写入和查看管道日志

在本地测试脚本是在开始生成管道之前调试主要代码片段和复杂逻辑的好方法。 在某些时候,需要在实际管道自身运行期间调试脚本,特别是在诊断管道步骤之间的交互过程中发生的行为时。 在步骤脚本中使用自由 print() 语句,以便在远程执行期间查看对象状态和预期值,类似于调试 JavaScript 代码的方式。

日志记录选项和行为

下表提供有关管道的不同调试选项的信息。 这不是详尽的列表,因为除了此处所示的Azure Machine Learning和Python选项之外,还有其他选项存在。

类型 示例 目标 资源
Azure 机器学习 SDK 指标 run.log(name, val) Azure Machine Learning 门户用户界面 如何跟踪试验
azureml.core.Run 类
Python打印/日志记录 日志 print(val)
logging.info(message)
驱动程序日志,Azure 机器学习设计器 如何跟踪试验

Python日志记录

日志记录选项示例

import logging

from azureml.core.run import Run

run = Run.get_context()

# Azure Machine Learning Scalar value logging
run.log("scalar_value", 0.95)

# Python print statement
print("I am a python print statement, I will be sent to the driver logs.")

# Initialize Python logger
logger = logging.getLogger(__name__)
logger.setLevel(args.log_level)

# Plain Python logging statements
logger.debug("I am a plain debug statement, I will be sent to the driver logs.")
logger.info("I am a plain info statement, I will be sent to the driver logs.")

handler = AzureLogHandler(connection_string='<connection string>')
logger.addHandler(handler)

注释

AzureLogHandler 包中的 opencensus-ext-azure 已弃用。 对于新项目,请改用 azure-monitor-opentelemetry 包。

Azure 机器学习设计器

对于在设计器中创建的管道,可以在创作页或管道运行详细信息页中找到 70_driver_log 文件。

为实时终结点启用日志记录

若要对设计器中的实时终结点进行故障排除和调试,请使用 SDK 启用 Application Insights 日志记录。 通过使用日志记录,可以排查和调试模型部署和使用问题。 有关详细信息,请参阅对部署的模型进行日志记录

从创作页获取日志

当您提交管道运行并停留在编辑页面时,可以在每个组件完成运行后找到为该组件生成的日志文件。

  1. 选择在创作画布中运行完毕的组件。

  2. 在该组件的右窗格中,转到“输出 + 日志”选项卡。

  3. 展开右窗格,然后选择 70_driver_log.txt 文件,在浏览器中查看该文件。 还可以在本地下载日志。

    设计器中展开的输出窗格

获取管道作业的日志

还可以在管道运行详细信息页中找到特定运行的日志文件。 可以在工作室的 “管道 ”或 “试验 ”部分找到此页面。

  1. 选择在设计器中创建的一个管道运行。

    管道运行页

  2. 在预览窗格中选择一个组件。

  3. 在该组件的右窗格中,转到“输出 + 日志”选项卡。

  4. 展开右窗格以查看浏览器中 的std_log.txt 文件,或选择要在本地下载日志的文件。

重要

若要从管道运行详细信息页面更新管道,必须将管道运行克隆到一个新的管道草稿。 管道运行是管道的快照。 它类似于日志文件,无法更改它。

使用 Visual Studio Code 进行交互式调试

在某些情况下,可能需要以交互方式调试 ML 管道中使用的Python代码。 通过使用 Visual Studio Code (VS Code) 和 debugpy,可以在训练环境中运行时附加到代码。

HyperdriveStep 和 AutoMLStep 因网络隔离而失败

使用 HyperdriveStep 和 AutoMLStep 后,尝试注册模型时,可能会收到错误。

  • 你使用的是 Azure Machine Learning SDK v1。

  • Azure Machine Learning工作区配置为网络隔离(VNet)。

  • 您的管道尝试注册上一步生成的模型。 例如,在以下示例中,inputs 参数是 HyperdriveStep 中的saved_model:

    register_model_step = PythonScriptStep(script_name='register_model.py',
                                       name="register_model_step01",
                                       inputs=[saved_model],
                                       compute_target=cpu_cluster,
                                       arguments=["--saved-model", saved_model],
                                       allow_reuse=True,
                                       runconfig=rcfg)
    

解决方法

重要

使用 Azure Machine Learning SDK v2 时,不会发生此行为。

若要解决此错误,请使用 Run 类获取从 HyperdriveStep 或 AutoMLStep 创建的模型。 以下示例脚本从 HyperdriveStep 获取输出模型:

%%writefile $script_folder/model_download9.py
import argparse
from azureml.core import Run
from azureml.pipeline.core import PipelineRun
from azureml.core.experiment import Experiment
from azureml.train.hyperdrive import HyperDriveRun
from azureml.pipeline.steps import HyperDriveStepRun

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--hd_step_name', 
        type=str, dest='hd_step_name', 
        help='The name of the step that runs AutoML training within this pipeline')
        
        
    
    args = parser.parse_args()
    
    current_run = Run.get_context()

    pipeline_run = PipelineRun(current_run.experiment, current_run.experiment.name)

    hd_step_run = HyperDriveStepRun((pipeline_run.find_step_run(args.hd_step_name))[0])
    hd_best_run = hd_step_run.get_best_run_by_primary_metric()

    print(hd_best_run)
    hd_best_run.download_file("outputs/model/saved_model.pb", "saved_model.pb")
    
    
    print("Successfully downloaded model") 

可以使用在 PythonScriptStep 中获取的文件:

from azureml.pipeline.steps import PythonScriptStep
conda_dep = CondaDependencies()
conda_dep.add_pip_package("azureml-sdk")
conda_dep.add_pip_package("azureml-pipeline")

rcfg = RunConfiguration(conda_dependencies=conda_dep)

model_download_step = PythonScriptStep(
    name="Download Model 9",
    script_name="model_download9.py", 
    arguments=["--hd_step_name", hd_step_name],
    compute_target=compute_target,
    source_directory=script_folder,
    allow_reuse=False,
    runconfig=rcfg
)

后续步骤

注释

azureml-pipeline-core azureml-pipeline-steps 以下部分中的引用适用于从 2026 年 6 月 30 日起已停用的 SDK v1 包。 有关建议的前进路径,请参阅 使用 Azure 机器学习 CLI/SDK v2 构建和运行机器学习管道