故障排除¶
请注意,本节中的信息可能会在未来的PyTorch/XLA软件版本中被移除,因为其中许多信息特定于某个内部实现,而这些实现可能会发生变化。
完整性检查¶
在进行任何深入调试之前,我们希望对已安装的PyTorch/XLA进行健全性检查。
检查PyTorch/XLA版本¶
PyTorch 和 PyTorch/XLA 版本应匹配。查看我们的 README 以获取有关可用版本的更多详细信息。
vm:~$ python
>>> import torch
>>> import torch_xla
>>> print(torch.__version__)
2.1.0+cu121
>>> print(torch_xla.__version__)
2.1.0
执行一个简单的计算¶
vm:~$ export PJRT_DEVICE=TPU
vm:~$ python3
>>> import torch
>>> import torch_xla.core.xla_model as xm
>>> t1 = torch.tensor(100, device=xm.xla_device())
>>> t2 = torch.tensor(200, device=xm.xla_device())
>>> print(t1 + t2)
tensor(300, device='xla:0')
使用假数据运行Resnet¶
对于夜间版本
vm:~$ git clone https://github.com/pytorch/xla.git
vm:~$ python xla/test/test_train_mp_imagenet.py --fake_data
对于发布版本 x.y,您应该使用分支 rx.y。例如,如果您安装了2.1版本,您应该执行
vm:~$ git clone --branch r2.1 https://github.com/pytorch/xla.git
vm:~$ python xla/test/test_train_mp_imagenet.py --fake_data
如果你能让resnet运行,我们就可以得出结论,torch_xla安装正确。
性能调试¶
为了诊断性能问题,我们可以使用PyTorch/XLA提供的执行指标和计数器。当模型运行缓慢时,首先要检查的是生成一个指标报告。
指标报告在诊断问题时非常有帮助。如果您有该报告,请尝试将其包含在发送给我们的错误报告中。
PyTorch/XLA 调试工具¶
您可以通过设置PT_XLA_DEBUG_LEVEL=2来启用PyTorch/XLA调试工具,该工具提供了一些有用的调试功能。您还可以将调试级别降低到1以跳过执行分析。
执行自动指标分析¶
调试工具将分析指标报告并提供摘要。一些示例输出将是
pt-xla-profiler: CompileTime too frequent: 21 counts during 11 steps
pt-xla-profiler: TransferFromDeviceTime too frequent: 11 counts during 11 steps
pt-xla-profiler: Op(s) not lowered: aten::_ctc_loss, aten::_ctc_loss_backward, Please open a GitHub issue with the above op lowering requests.
pt-xla-profiler: CompileTime too frequent: 23 counts during 12 steps
pt-xla-profiler: TransferFromDeviceTime too frequent: 12 counts during 12 steps
编译与执行分析¶
调试工具将分析您的模型的每次编译和执行。一些示例输出将是
Compilation Analysis: ================================================================================
Compilation Analysis: Compilation Cause
Compilation Analysis: mark_step in parallel loader at step end
Compilation Analysis: Graph Info:
Compilation Analysis: Graph Hash: c74c3b91b855b2b123f833b0d5f86943
Compilation Analysis: Number of Graph Inputs: 35
Compilation Analysis: Number of Graph Outputs: 107
Compilation Analysis: Python Frame Triggered Execution:
Compilation Analysis: mark_step (/workspaces/dk3/pytorch/xla/torch_xla/core/xla_model.py:1055)
Compilation Analysis: next (/workspaces/dk3/pytorch/xla/torch_xla/distributed/parallel_loader.py:44)
Compilation Analysis: __next__ (/workspaces/dk3/pytorch/xla/torch_xla/distributed/parallel_loader.py:32)
Compilation Analysis: train_loop_fn (/workspaces/dk3/pytorch/xla/examples/train_decoder_only_base.py:48)
Compilation Analysis: start_training (/workspaces/dk3/pytorch/xla/examples/train_decoder_only_base.py:65)
Compilation Analysis: <module> (/workspaces/dk3/pytorch/xla/examples/train_decoder_only_base.py:73)
Compilation Analysis: --------------------------------------------------------------------------------
Compilation Analysis: ================================================================================
Post Compilation Analysis: ================================================================================
Post Compilation Analysis: Graph input size: 1.548000 GB
Post Compilation Analysis: Graph output size: 7.922460 GB
Post Compilation Analysis: Aliased Input size: 1.547871 GB
Post Compilation Analysis: Intermediate tensor size: 12.124478 GB
Post Compilation Analysis: Compiled program size: 0.028210 GB
Post Compilation Analysis: --------------------------------------------------------------------------------
Post Compilation Analysis: ================================================================================
Execution Analysis: ================================================================================
Execution Analysis: Execution Cause
Execution Analysis: mark_step in parallel loader at step end
Execution Analysis: Graph Info:
Execution Analysis: Graph Hash: c74c3b91b855b2b123f833b0d5f86943
Execution Analysis: Number of Graph Inputs: 35
Execution Analysis: Number of Graph Outputs: 107
Execution Analysis: Python Frame Triggered Execution:
Execution Analysis: mark_step (/workspaces/dk3/pytorch/xla/torch_xla/core/xla_model.py:1055)
Execution Analysis: next (/workspaces/dk3/pytorch/xla/torch_xla/distributed/parallel_loader.py:44)
Execution Analysis: __next__ (/workspaces/dk3/pytorch/xla/torch_xla/distributed/parallel_loader.py:32)
Execution Analysis: train_loop_fn (/workspaces/dk3/pytorch/xla/examples/train_decoder_only_base.py:48)
Execution Analysis: start_training (/workspaces/dk3/pytorch/xla/examples/train_decoder_only_base.py:65)
Execution Analysis: <module> (/workspaces/dk3/pytorch/xla/examples/train_decoder_only_base.py:73)
Execution Analysis: --------------------------------------------------------------------------------
Execution Analysis: ================================================================================
编译/执行的一些常见原因是
用户手动调用
mark_step。Parallel loader 每 x(可配置)批次调用
mark_step。Dynamo 决定编译/执行图形。
用户试图在
mark_step之前访问(通常由于日志记录)张量的值。
由1-4引起的执行是预期的,我们希望通过减少访问张量值的频率或在访问之前手动添加mark_step来避免5。
用户应该期望在前几步看到Compilation Cause + Execution Cause对。模型稳定后,用户应该期望只看到Execution Cause(你可以通过PT_XLA_DEBUG_LEVEL=1禁用执行分析)。为了高效使用PyTorch/XLA,我们期望每一步运行相同的模型代码,并且每个图只编译一次。如果你一直看到Compilation Cause,你应该尝试按照此部分转储IR/HLO,并比较每一步的图,理解差异的来源。
以下部分将解释如何获取和理解更详细的指标报告。
获取指标报告¶
将以下行放入您的程序中以生成报告:
import torch_xla.debug.metrics as met
# For short report that only contains a few key metrics.
print(met.short_metrics_report())
# For full report that includes all metrics.
print(met.metrics_report())
理解指标报告¶
报告内容包括:
我们发出XLA编译的次数以及发出所花费的时间。
我们执行了多少次以及执行所花费的时间
我们创建/销毁了多少设备数据句柄等。
此信息以样本的百分位数形式报告。一个例子是:
Metric: CompileTime
TotalSamples: 202
Counter: 06m09s401ms746.001us
ValueRate: 778ms572.062us / second
Rate: 0.425201 / second
Percentiles: 1%=001ms32.778us; 5%=001ms61.283us; 10%=001ms79.236us; 20%=001ms110.973us; 50%=001ms228.773us; 80%=001ms339.183us; 90%=001ms434.305us; 95%=002ms921.063us; 99%=21s102ms853.173us
我们还提供计数器,这些是用于跟踪内部软件状态的命名整数变量。例如:
Counter: CachedSyncTensors
Value: 395
在本报告中,任何以aten::开头的计数器表示XLA设备和CPU之间的上下文切换,这可能是模型代码中的一个潜在性能优化区域。
计数器有助于理解哪些操作被路由回PyTorch的CPU引擎。 它们完全限定在其C++命名空间中:
Counter: aten::nonzero
Value: 33
如果你看到除了nonzero和_local_scalar_dense之外的aten::操作,这通常意味着在PyTorch/XLA中缺少一个降级。欢迎在GitHub issues上为其提交功能请求。
PyTorch/XLA + Dynamo 调试工具¶
您可以通过设置XLA_DYNAMO_DEBUG=1来启用PyTorch/XLA + Dynamo调试工具。
简单的基准测试¶
请查看 ``examples/train_resnet_benchmark.py` <https://github.com/pytorch/xla/blob/master/examples/train_resnet_benchmark.py>`_ 以了解如何对 PyTorch/XLA 模型进行基准测试。
已知的性能注意事项¶
PyTorch/XLA 在语义上表现得像常规的 PyTorch,并且 XLA 张量与 CPU 和 GPU 张量共享完整的张量接口。 然而,XLA/硬件中的限制和惰性评估模型表明某些模式可能会导致性能不佳。
如果你的模型表现不佳,请记住以下注意事项:
XLA/TPU 由于过多的重新编译导致性能下降。
XLA编译成本很高。PyTorch/XLA每次遇到新形状时都会自动重新编译图形。 通常模型应该在几步之内稳定下来,你可以在训练的其余部分看到巨大的加速。
为了避免重新编译,不仅形状必须是常量,而且所有主机中跨XLA设备的计算也应该是常量。
可能的来源:
直接或间接使用
nonzero会引入动态形状;例如,掩码索引base[index],其中index是一个掩码张量。步骤之间迭代次数不同的循环可能导致不同的执行图,因此需要重新编译。
解决方案:
在迭代之间,张量的形状应该相同,或者应该使用少量的形状变化。
尽可能将张量填充到固定大小。
某些操作没有原生的XLA翻译。
对于这些操作,PyTorch/XLA 会自动传输到 CPU 内存,在 CPU 上评估,并将结果传输回 XLA 设备。 在训练步骤中执行太多此类操作可能会导致显著的减速。
可能的来源:
item()操作明确要求评估结果。除非必要,否则不要使用它。
解决方案:
即使已知PyTorch张量是标量,也应避免使用
tensor.item()。将其保留为张量并在其上使用张量操作。在适用时使用
torch.where来替代控制流。 例如,在clip_grad*norm*中使用的带有item()的控制流是有问题的,并且会影响性能,因此我们通过调用torch.where来修补了clip_grad_norm_,这为我们带来了显著的性能提升。 .. code-block:: python… 否则:
device = parameters[0].device total_norm = torch.zeros([], device=device if parameters else None) for p in parameters:
param_norm = p.grad.data.norm(norm_type) ** norm_type total_norm.add_(param_norm)
total_norm = (total_norm ** (1. / norm_type))
clip_coef = torch.tensor(max_norm, device=device) / (total_norm + 1e-6) for p in parameters:
p.grad.data.mul_(torch.where(clip_coef < 1, clip_coef, torch.tensor(1., device=device)))
在``torch_xla.distributed.data_parallel``中的迭代器可能会丢弃输入迭代器中的最后几个批次。
这是为了确保我们在所有XLA设备上做相同的工作量。
解决方案:
当数据集较小且步骤太少时,可能会导致一个无操作的时期。因此,在这些情况下,最好使用小批量大小。
XLA 张量特性¶
XLA 张量的内部结构是不透明的。 XLA 张量总是看起来是连续的,并且没有存储。网络不应尝试检查 XLA 张量的步幅。
在保存XLA张量之前,应将其移动到CPU。 直接保存XLA张量会导致它们在加载时被放回保存它们的设备上。如果在加载时设备不可用,则加载将失败。在保存XLA张量之前将其移动到CPU,可以让您决定将加载的张量放在哪个设备上。如果您想在没有XLA设备的机器上加载张量,这是必要的。然而,在保存XLA张量之前将其移动到CPU时应小心,因为跨设备类型移动张量不会保留视图关系。相反,应在加载张量后根据需要重建视图。
使用Python的copy.copy复制XLA张量会返回一个深拷贝,而不是浅拷贝。 使用XLA张量的视图来获取其浅拷贝。
处理共享权重。 模块可以通过将一个模块的参数设置为另一个模块的参数来共享权重。这种模块权重的“绑定”应该在模块移动到XLA设备之后进行。否则,在XLA设备上会创建共享张量的两个独立副本。
更多调试工具¶
我们不期望用户使用本节中的工具来调试他们的模型。但我们可能会在您提交错误报告时要求使用这些工具,因为它们提供了指标报告所没有的额外信息。
print(torch_xla._XLAC._get_xla_tensors_text([res]))其中res是结果张量,打印出IR。print(torch_xla._XLAC._get_xla_tensors_hlo([res]))其中res是结果张量,打印出生成的XLA HLO。
请注意,这些函数必须在mark_step()之前调用,否则张量将已经被具体化。
环境变量¶
还有一些环境变量控制着PyTorch/XLA软件栈的行为。
设置这些变量会导致不同程度的性能下降,因此它们应仅在调试时启用。
XLA_IR_DEBUG: 启用Python堆栈跟踪以捕获创建IR节点的位置, 从而允许理解哪个PyTorch操作负责生成IR。XLA_HLO_DEBUG: 当_XLA_IRDEBUG激活时,启用捕获的Python堆栈帧,并将其传播到XLA HLO元数据中。XLA_SAVE_TENSORS_FILE: 用于在执行期间转储IR图的文件路径。请注意,如果该选项保持启用状态并且PyTorch程序长时间运行,文件可能会变得非常大。图会被追加到文件中,因此为了每次运行都有一个干净的记录,应显式删除该文件。XLA_SAVE_TENSORS_FMT: 存储在_XLA_SAVE_TENSORSFILE文件中的图形格式。可以是text(默认值)、dot(Graphviz格式)或hlo。XLA_FLAGS=--xla_dump_to: 如果设置为=/tmp/dir_name,XLA 编译器将在每次编译时转储未优化和优化的 HLO。XLA_METRICS_FILE: 如果设置了,这是内部指标将在每一步保存到的本地文件的路径。如果文件已存在,指标将被追加到文件中。XLA_SAVE_HLO_FILE: 如果设置,则在编译/执行错误时,违规的HLO图将保存到本地文件的路径。XLA_SYNC_WAIT: 强制XLA张量同步操作在完成之前等待,然后继续下一步。XLA_USE_EAGER_DEBUG_MODE: 强制XLA张量以急切模式执行,即逐个编译和执行torch操作。这对于绕过长时间的编译时间非常有用,但由于所有编译器优化都将被跳过,整体步骤时间将大大减慢,内存使用量也会更高。TF_CPP_LOG_THREAD_ID: 如果设置为1,TF日志将显示线程ID,有助于调试多线程进程。TF_CPP_VMODULE: 用于TF VLOGs的环境变量,格式为TF_CPP_VMODULE=name=value,...。请注意,对于VLOGs,您必须设置TF_CPP_MIN_LOG_LEVEL=0。TF_CPP_MIN_LOG_LEVEL: 打印消息的级别。TF_CPP_MIN_LOG_LEVEL=0将开启 INFO 日志记录,TF_CPP_MIN_LOG_LEVEL=1将开启 WARNING 日志记录,以此类推。我们的 PyTorch/XLATF_VLOG默认使用tensorflow::INFO级别,因此要查看 VLOGs,请设置TF_CPP_MIN_LOG_LEVEL=0。XLA_DUMP_HLO_GRAPH: 如果设置为=1,在编译或执行错误的情况下,有问题的HLO图将被转储为xla_util.cc引发的运行时错误的一部分。
常见的调试环境变量组合¶
以IR格式记录图形执行
XLA_IR_DEBUG=1 XLA_HLO_DEBUG=1 XLA_SAVE_TENSORS_FMT="text" XLA_SAVE_TENSORS_FILE="/tmp/save1.ir"
以HLO格式记录图形执行
XLA_IR_DEBUG=1 XLA_HLO_DEBUG=1 XLA_SAVE_TENSORS_FMT="hlo" XLA_SAVE_TENSORS_FILE="/tmp/save1.hlo"
显示运行时和图编译/执行的调试VLOG
TF_CPP_MIN_LOG_LEVEL=0 TF_CPP_VMODULE="xla_graph_executor=5,pjrt_computation_client=3"
重现PyTorch/XLA CI/CD单元测试失败。¶
你可能会看到一些PR的测试失败,例如:
To execute this test, run the following from the base repo dir:
PYTORCH_TEST_WITH_SLOW=1 python ../test/test_torch.py -k test_put_xla_uint8
直接在命令行中运行此操作无效。您需要将环境变量 TORCH_TEST_DEVICES 设置为您本地的 pytorch/xla/test/pytorch_test_base.py。例如:
TORCH_TEST_DEVICES=/path/to/pytorch/xla/test/pytorch_test_base.py PYTORCH_TEST_WITH_SLOW=1 python ../test/test_torch.py -k test_put_xla_uint8 应该可以工作。