除錯委派¶
我們提供了一系列實用函式,讓使用者瞭解在 to_backend() 階段圖模組發生了什麼。
獲取委派摘要¶
方法 get_delegation_info() 提供了在呼叫 to_backend() 後模型發生的變更摘要。
from executorch.devtools.backend_debug import get_delegation_info
from tabulate import tabulate
# ... After call to to_backend(), but before to_executorch()
graph_module = edge_manager.exported_program().graph_module
delegation_info = get_delegation_info(graph_module)
print(delegation_info.get_summary())
df = delegation_info.get_operator_delegation_dataframe()
print(tabulate(df, headers="keys", tablefmt="fancy_grid"))
示例輸出
Total delegated subgraphs: 86
Number of delegated nodes: 473
Number of non-delegated nodes: 430
操作型別 |
在委派圖中的出現次數 |
在未委派圖中的出現次數 |
|
|---|---|---|---|
0 |
aten__softmax_default |
12 |
0 |
1 |
aten_add_tensor |
37 |
0 |
2 |
aten_addmm_default |
48 |
0 |
3 |
aten_arange_start_step |
0 |
25 |
… |
|||
23 |
aten_view_copy_default |
170 |
48 |
… |
|||
26 |
總計 |
473 |
430 |
從表中可以看出,操作 aten_view_copy_default 在委派圖中出現 170 次,在未委派圖中出現 48 次。使用者可以使用此類資訊進行除錯。
視覺化委派圖¶
要檢視更詳細的資訊,可以使用方法 format_delegated_graph() 獲取整個圖的字串輸出,或使用 print_delegated_graph() 直接列印。
from executorch.exir.backend.utils import format_delegated_graph
graph_module = edge_manager.exported_program().graph_module
print(format_delegated_graph(graph_module)) # or call print_delegated_graph(graph_module)
它將列印整個模型以及由後端消耗的子圖。由 fx 提供的通用除錯函式,如 print_tabular() 或 print_readable(),只會顯示 call_delegate,但會隱藏由後端消耗的子圖內容,而此函式則會暴露子圖內部的內容。
在下面的示例輸出中,請注意 embedding 和 add 操作已被委派給 XNNPACK,而 sub 操作則沒有。
%aten_unsqueeze_copy_default_22 : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.unsqueeze_copy.default](args = (%aten_arange_start_step_23, -2), kwargs = {})
%aten_unsqueeze_copy_default_23 : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.unsqueeze_copy.default](args = (%aten_arange_start_step_24, -1), kwargs = {})
%lowered_module_0 : [num_users=1] = get_attr[target=lowered_module_0]
backend_id: XnnpackBackend
lowered graph():
%aten_embedding_default : [num_users=1] = placeholder[target=aten_embedding_default]
%aten_embedding_default_1 : [num_users=1] = placeholder[target=aten_embedding_default_1]
%aten_add_tensor : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.add.Tensor](args = (%aten_embedding_default, %aten_embedding_default_1), kwargs = {})
return (aten_add_tensor,)
%executorch_call_delegate : [num_users=1] = call_function[target=torch.ops.higher_order.executorch_call_delegate](args = (%lowered_module_0, %aten_embedding_default, %aten_embedding_default_1), kwargs = {})
%aten_sub_tensor : [num_users=1] = call_function[target=executorch.exir.dialects.edge._ops.aten.sub.Tensor](args = (%aten_unsqueeze_copy_default, %aten_unsqueeze_copy_default_1), kwargs = {})