模型并行故障排除 - Amazon SageMaker
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

模型并行故障排除

在遇到错误时,您可以根据以下列表尝试对训练作业进行故障排除。如果问题仍存在,请联系 Amazon Support

将 SageMaker Debugger 与 SageMaker 模型并行性库结合使用的注意事项

SageMaker Debugger 不可用于 SageMaker 模型并行性库。Debugger 默认情况下对所有 SageMaker TensorFlow 和 PyTorch 训练作业启用,您可能会看到如下所示的错误:

FileNotFoundError: [Errno 2] No such file or directory: '/opt/ml/checkpoints/metadata.json.sagemaker-uploading

要修复此问题,请在创建框架时 estimator 通过传递 debugger_hook_config=False 来禁用 Debugger,如下例所示。

bucket=sagemaker.Session().default_bucket() base_job_name="sagemaker-checkpoint-test" checkpoint_in_bucket="checkpoints" # The S3 URI to store the checkpoints checkpoint_s3_bucket="s3://{}/{}/{}".format(bucket, base_job_name, checkpoint_in_bucket) estimator = TensorFlow( ... distribution={"smdistributed": {"modelparallel": { "enabled": True }}}, checkpoint_s3_uri=checkpoint_s3_bucket, checkpoint_local_path="/opt/ml/checkpoints", debugger_hook_config=False )

保存检查点

在 SageMaker 上保存大型模型的检查点时,您可能会遇到以下错误:

InternalServerError: We encountered an internal error. Please try again

这可能是由于在训练期间,将本地检查点上传到 Amazon S3 时存在 SageMaker 限制。要在 SageMaker 中禁用检查点操作,请使用以下示例明确上传检查点。

如果遇到前述错误,请不要将 checkpoint_s3_uri 用于 SageMaker estimator 调用。在为较大的模型保存检查点时,建议将检查点保存到自定义目录中,然后将这些检查点传递给帮助程序函数(作为 local_path 参数)。

import os def aws_s3_sync(source, destination): """aws s3 sync in quiet mode and time profile""" import time, subprocess cmd = ["aws", "s3", "sync", "--quiet", source, destination] print(f"Syncing files from {source} to {destination}") start_time = time.time() p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() end_time = time.time() print("Time Taken to Sync: ", (end_time-start_time)) return def sync_local_checkpoints_to_s3(local_path="/opt/ml/checkpoints", s3_uri=os.path.dirname(os.path.dirname(os.getenv('SM_MODULE_DIR', '')))+'/checkpoints'): """ sample function to sync checkpoints from local path to s3 """ import boto3 #check if local path exists if not os.path.exists(local_path): raise RuntimeError("Provided local path {local_path} does not exist. Please check") #check if s3 bucket exists s3 = boto3.resource('s3') if not s3_uri.startswith("s3://"): raise ValueError(f"Provided s3 uri {s3_uri} is not valid.") s3_bucket = s3_uri.replace('s3://','').split('/')[0] print(f"S3 Bucket: {s3_bucket}") try: s3.meta.client.head_bucket(Bucket=s3_bucket) except Exception as e: raise e aws_s3_sync(local_path, s3_uri) return def sync_s3_checkpoints_to_local(local_path="/opt/ml/checkpoints", s3_uri=os.path.dirname(os.path.dirname(os.getenv('SM_MODULE_DIR', '')))+'/checkpoints'): """ sample function to sync checkpoints from s3 to local path """ import boto3 #try to create local path if it does not exist if not os.path.exists(local_path): print(f"Provided local path {local_path} does not exist. Creating...") try: os.makedirs(local_path) except Exception as e: raise RuntimeError(f"Failed to create {local_path}") #check if s3 bucket exists s3 = boto3.resource('s3') if not s3_uri.startswith("s3://"): raise ValueError(f"Provided s3 uri {s3_uri} is not valid.") s3_bucket = s3_uri.replace('s3://','').split('/')[0] print(f"S3 Bucket: {s3_bucket}") try: s3.meta.client.head_bucket(Bucket=s3_bucket) except Exception as e: raise e aws_s3_sync(s3_uri, local_path) return

帮助程序函数的用法:

#base_s3_uri - user input s3 uri or save to model directory (default) #curr_host - to save checkpoints of current host #iteration - current step/epoch during which checkpoint is saved # save checkpoints on every node using local_rank if smp.local_rank() == 0: base_s3_uri = os.path.dirname(os.path.dirname(os.getenv('SM_MODULE_DIR', ''))) curr_host = os.environ['SM_CURRENT_HOST'] full_s3_uri = f'{base_s3_uri}/checkpoints/{curr_host}/{iteration}' sync_local_checkpoints_to_s3(local_path=checkpoint_dir, s3_uri=full_s3_uri)

使用模型并行和 TensorFlow 进行收敛

当您将 SageMaker 多节点训练与 TensorFlow 和模型并行性库结合使用时,由于每个节点上的训练输入文件的顺序可能不同,损失可能不会按预期收敛。这可能会导致同一模型并行组中处理不同输入文件有不同的排名,从而导致不一致的情况。为防止这种情况,请确保输入文件在转换为 TensorFlow 数据集之前,在所有排名中都以相同的方式排序。要做到这一点,一种方法是在输入脚本中对输入文件名称排序。

分布式训练作业停顿或崩溃

如果您的训练作业出现了停顿、崩溃或没有响应问题,请阅读以下故障排除项目以确定造成问题的原因。如果您需要任何进一步的支持,请通过 Amazon Support 联系 SageMaker 分布式训练团队。

  • 如果您看见分布式训练作业在 NCCL 初始化步骤停顿,请考虑以下几种情况:

    • 如果您使用的是启用 EFA 的实例之一(ml.p4dml.p3dn 实例)与自定义 VPC 及其子网,请确保使用的安全组在所有端口上具有出站和入站连接。作为一项单独的规则(对于互联网访问),您通常还需要与任意 IP 的出站连接。要查找有关如何为 EFA 通信添加入站和出站规则的说明,请参阅SageMaker 分布式训练作业在初始化期间停滞

  • 如果您在对整个模型执行检查点操作时遇到分布式训练作业停顿的问题,这可能是因为对于具有 rdp_rank()==0(使用张量并行性时)或 dp_rank()==0(使用管道并行性时)的所有排名,没有在其上进行对模型或优化程序的 state_dict() 调用。这些排名需要进行通信来构造所要保存的检查点。在启用了 shard_optimizer_state 时,对部分优化程序执行检查点操作时,也可能会出现类似的停顿问题。

    有关对具有模型并行性的模型执行检查点操作的更多信息,请参阅保存和加载的一般说明对分布式 PyTorch 模型(适用于 v1.6.0 和 v1.9.0 之间的 SageMaker 模型并行性库)执行检查点操作

  • 如果训练作业崩溃并出现 CUDA 内存不足错误,这意味着需要调整分布式训练配置以适应 GPU 集群上的模型。有关更多信息和最佳实践,请参阅针对给定模型设置合适的配置

  • 如果训练作业崩溃并出现不可纠正的 ECC 错误,这意味着集群中的 GPU 之一损坏。如果您需要技术支持,请向 Amazon 团队提供作业 ARN,如果可能,请从某个检查点重新启动训练作业。

  • 在极少数情况下,以前可以正常工作但已接近 GPU 内存限制的作业配置,以后可能会在其他集群上由于 CUDA 内存不足错误而失败。这可能是因为 ECC 错误而导致某些 GPU 的可用内存低于正常情况。

  • 在运行的多节点作业没有使用节点中的所有 GPU 时,可能会出现网络超时崩溃。要解决这个问题,请确保在每个实例中将 processes_per_host 参数设置为 GPU 的数量,从而确保使用了节点上的所有 GPU。例如,对于 ml.p3.16xlargeml.p3dn.24xlargeml.p4d.24xlarge 实例,此项为 processes_per_host=8

  • 如果您发现训练作业的数据下载阶段需要很长时间,请确保为 SageMaker Estimator 类向 checkpoint_s3_uri 提供的 Amazon S3 路径,对于当前的训练作业来说是唯一的。如果在同时运行的多个训练作业中重复使用此路径,则所有这些检查点都将在同一个 Amazon S3 路径中上传和下载,这可能会显著增加检查点加载时间。

  • 处理大型数据和模型时,请使用 FSx for Lustre。

    • 如果您的数据集较大,需要较长的时间来提取,我们建议您将数据集保存在 FSx for Lustre 中。

    • 在训练超过 100 亿个参数的模型时,我们建议使用 FSx for Lustre 执行检查点操作。

    • 创建文件系统后,请务必等待状态变为可用,然后再使用它来启动训练作业。

PyTorch 训练作业收到 NCCL 错误

如果您遇到以下错误,这可能是由于进程耗尽 GPU 内存所造成。

NCCL error in: ../torch/lib/c10d/ProcessGroupNCCL.cpp:825, unhandled system error, NCCL version 2.7.8 ncclSystemError: System call (socket, malloc, munmap, etc) failed.

您可以通过减少批处理大小或 active_microbatches 来解决这个问题。如果自动分区不能得到均衡的分区,则您可能需要考虑手动分区。有关更多信息,请参阅 跨节点的流水线并行性

PyTorch 训练作业收到 RecursionError

该库不支持在模块的前向调用内部调用 super.forward()。如果您使用 super.forward(),则可能会收到以下错误消息。

RecursionError: maximum recursion depth exceeded

要修复错误,您不应调用 super.forward(),而是应调用 super()._orig_forward()