Hey all, wanted to discuss a new feature proposal with the community. I’ve not contributed to TVM before so please let me know if there is a strict process to follow. When loading a traced pytorch model using tvm.relay.frontend.from_pytorch
, TVM auto assigns span names since 0.14.0 based on the operator (like aten::conv2d...
). However, for a large number of applications, preserving the true Pytorch scope name is important.
Consider a BERT model being imported, we may not want the a dense operator to be renamed to 'aten::dense…` but actually preserve the true “scope name” in Pytorch “bert.encoder.layer.11.output.dense”. Scope name preservation is important for some TVM projects if the users wish to specify additional configs, quantization information etc. that is all tied to the names / layers they see in the original pytorch input which gets lost in conversion today.
Our company has a fork of TVM where we already have a fix for this that I’d love to bring into open-source TVM. Basically, with tvm.relay.frontend.from_pytorch
, we can accept an additional boolean called preserve_pytorch_scope_names
which has default False (aka current behavior) but if True, we can preserve the scopes. The change required is something as simple as:
Current Code:
def _rename_outputs(node, source_map, op_type_dict, use_parser_friendly_name):
"""Rewrite debug name of node outputs with its operator type"""
def _get_source_name(op_type):
op_idx = 0
if op_type in op_type_dict:
op_idx = op_type_dict[op_type] + 1
op_type_dict[op_type] = op_idx
return "_".join([op_type, str(op_idx)])
# get source name of operator and rename all of its outputs
# e.g. node.kind(): aten::adaptive_max_pool2d
# node_src_name -> aten::adaptive_max_pool2d_x
# output_1 -> aten::adaptive_max_pool2d_x_0
# output_2 -> aten::adaptive_max_pool2d_x_1
if node.kind() != "prim::GetAttr":
node_src_name = _get_source_name(node.kind())
for index, output in enumerate(node.outputs()):
output.setDebugName("_".join([node_src_name, str(index)]))
# update source map
# if use_parser_friendly_name is True: e.g. prim::Constant_0 -> prim__Constant_0
if use_parser_friendly_name:
node_src_name = re.sub(r":|\.", "_", node_src_name)
source_map[node] = node_src_name
New Code to preserve Pytorch Scopes:
def _rename_outputs(node, source_map, op_type_dict, use_parser_friendly_name):
"""Rewrite debug name of node outputs with its operator type"""
def _get_source_name(op_type):
op_idx = 0
if op_type in op_type_dict:
op_idx = op_type_dict[op_type] + 1
op_type_dict[op_type] = op_idx
return "_".join([op_type, str(op_idx)])
if node.kind() != "prim::GetAttr":
node_src_name = node.scopeName().split("/")[-1]
if node_src_name.startswith("__module."):
node_src_name = node_src_name[len("__module.") :]
for index, output in enumerate(node.outputs()):
output.setDebugName("_".join([_get_source_name(node_src_name), str(index)]))
# update source map
# if use_parser_friendly_name is True: e.g. prim::Constant_0 -> prim__Constant_0
if use_parser_friendly_name:
node_src_name = re.sub(r":|\.", "_", node_src_name)
source_map[node] = node_src_name
If this is something of interest to the community, I can clean this up and make a formal pull request to the TVM project. Thanks!