快捷方式

委托调试

由于其行为定义的灵活性,委托后端是设备上模型的重要组成部分。这种灵活性的一个副作用是它充当一种不透明的转换。这会模糊掉在后处理中有价值的丰富关联和变异。

  • 例如,如果在委托中发生两个不同的算子融合,后处理将无法区分这两种转换。

具体来说,这使得将运行时信息(例如性能分析结果)与委托图相关联变得困难。委托调试标识符提供了一个框架,通过该框架,委托作者可以传播此信息并将其用于运行后分析。

准备分为三个阶段:

  • 提前(AOT):委托作者生成一个 调试句柄映射 (Debug Handle Map)

  • 运行时:委托作者使用在 提前 (AOT) 阶段注册到 调试句柄映射 (Debug Handle Map) 中的 委托调试标识符 (Delegate Debug Identifiers) 进行日志记录。

  • 反序列化:委托作者为委托事件中的自定义元数据提供一个解析器。

提前集成

委托作者通过从后端实现返回一个 调试句柄映射 (Debug Handle Map) 来传播在已降低的后端中发生的转换。

生成调试句柄映射

调试句柄映射 (Debug Handle Maps) 通过将 委托调试标识符 (Delegate Debug Identifiers) 映射到调试句柄来传达在后端中发生的转换。

委托调试标识符 (Delegate Debug Identifiers) 是为表示运行时中的兴趣点而生成或用户提供的标识符。回想一下,调试句柄是模型图中算子实例的唯一标识符。

例如

  • { 0: (10, 11), 1: (11, 12) }: 运行时中的标识符 0 和 1 分别对应于具有调试句柄 (10, 11) 和 (11, 12) 的算子。

  • { “fused_op_1_2_3”: (11, 12, 15) }: 运行时中的标识符 “fused_op_1_2_3” 对应于具有调试句柄 (11, 12, 15) 的算子,其中 11、12、15 分别对应于算子 1、算子 2 和算子 3。

注意

标识符是连接运行时结果与模型图的手段;标识符的解释由委托作者定义。

调试句柄映射 (Debug Handle Maps) 通过使用 DelegateMappingBuilder 构建,并作为 PreprocessResult 的一部分返回。

class PreprocessResult:
    processed_bytes: bytes = bytes()

    debug_handle_map: Optional[
        Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]
    ] = None

PreprocessResult 定义在 这里

DelegateMappingBuilder

DelegateMappingBuilder 是一个用于管理和构建调试句柄映射的辅助类。生成器的结果应在构造 PreprocessResult 时传入。

DelegateMappingBuilder 定义在 这里

一个 DelegateMappingBuilder 实例可以以 2 种模式之一构建:手动标识符或生成标识符。

# Manual Identifiers, Default
builder = DelegateMappingBuilder(generated_identifiers=False)

# Generated Identifiers
builder = DelegateMappingBuilder(generated_identifiers=True)

使用 手动标识符 时,用户在创建条目时传入 委托调试标识符 (Delegate Debug Identifier)。使用 生成标识符 时,生成器将自动分配一个 委托调试标识符 (Delegate Debug Identifier)

要将条目添加到 调试句柄映射 (Debug Handle Map),请使用 insert_delegate_mapping_entry。它将一个或多个 fx.Node 或调试句柄(来自 node.meta[“debug_handle”])与一个可选的 委托调试标识符 (Delegate Debug Identifier)(用于手动标识符)关联起来。返回的标识符是调用时记录的。

def insert_delegate_mapping_entry(
    self,
    nodes: Optional[Union[Node, List[Node]]] = None,
    handles: Optional[Union[int, List[int]]] = None,
    identifier: Optional[Union[int, str]] = None,
) -> Union[int, str]:

要检索 调试句柄映射 (Debug Handle Map),请使用 get_delegate_mapping

def get_delegate_mapping(
    self,
) -> Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]

AOT 映射的演示可以在 这里 找到

运行时日志记录

与 AOT 映射相对应,运行时定义了记录这些事件的功能。

实时日志记录

ExecuTorch 允许您实时记录。实时日志记录 (Real time Logging) 在可用时间戳时执行,非常有用。它具有最小的开销,并且对作者来说调用直观。

要实时记录事件(例如,显式标记性能分析的开始和结束),将使用 event_tracer_start_profiling_delegate 来创建 EventEntry,并使用 event_tracer_end_profiling_delegate 来结束为提供的 EventTracer 准备的 EventEntry

要使用 event_tracer_start_profiling_delegate 启动 EventTracerEntry,将 委托调试标识符 (Delegate Debug Identifier)(提前 (AOT) 提供给 debug_handle_map)作为 name 或 delegate_debug_id 参数传入,具体取决于 委托调试标识符 (Delegate Debug Identifier) 的类型(分别为 str 和 int)。

EventTracerEntry event_tracer_start_profiling_delegate(
    EventTracer* event_tracer,
    const char* name,
    DebugHandle delegate_debug_id)

要结束 EventTracerEntry,只需将原始 EventTracerEntry 提供给 event_tracer_end_profiling_delegate

可选地,此时还可以记录额外的运行时 metadata

void event_tracer_end_profiling_delegate(
    EventTracer* event_tracer,
    EventTracerEntry event_tracer_entry,
    const void* metadata = nullptr,
    size_t metadata_len = 0)

事后日志记录

ExecuTorch 还允许您在事后记录。一些运行时设置在执行时无法访问时间戳。事后日志记录 (Post-Time Logging) 使作者仍然能够记录这些事件。

要事后记录事件(例如,同时记录开始和结束时间),将调用 event_tracer_log_profiling_delegate,并结合实时日志记录 API 中使用的参数和时间戳。

void event_tracer_log_profiling_delegate(
    EventTracer* event_tracer,
    const char* name,
    DebugHandle delegate_debug_id,
    et_timestamp_t start_time,
    et_timestamp_t end_time,
    const void* metadata = nullptr,
    size_t metadata_len = 0)

运行时代码的演示可以在 这里 找到。

从委托事件中呈现自定义元数据

如上面的运行时日志记录 API 所示,用户可以与其委托性能分析事件一起记录字节数组。我们通过 Inspector API 在后处理中为用户提供此数据。

用户可以在创建 Inspector 实例时传入一个元数据解析器。解析器是一个可调用对象,它反序列化数据并返回一个字符串列表或一个包含键值对的字典。然后,反序列化后的数据会被添加回事件块中对应的事件,供用户使用。以下是如何编写此解析器的示例:

注意:反序列化器的输入是一个列表,其中每个条目都是一系列字节(本质上每个条目都是一个不可变的字节数组)。用户应遍历此列表,反序列化每个条目,然后以预期的格式返回,即字符串列表或字典。

Inspector(
    etdump_path=etdump_path,
    # Optional
    etrecord=etrecord_path,
    # Optional, only needed if debugging was enabled.
    buffer_path=buffer_path,
    delegate_metadata_parser=parse_delegate_metadata
)


def parse_delegate_metadata(delegate_metadatas: List[bytes]) -> Union[List[str], Dict[str, Any]]:
    metadata_str = []
    for metadata_bytes in delegate_metadatas:
        metadata_str += str(metadata_bytes)
    return metadata_str

文档

访问全面的 PyTorch 开发者文档

查看文档

教程

为初学者和高级开发者提供深入的教程

查看教程

资源

查找开发资源并让您的问题得到解答

查看资源