Bug
ChannelsLastTaggedReshapePass.input_to_nhwc crashes with AttributeError: 'immutable_list' object has no attribute 'graph' when lowering a dynamically quantized model to XNNPACK without per_op_mode.
Root Cause
Two issues in channels_last_tagged_reshape_pass.py:
1. input_to_nhwc while loop (line ~402)
if is_dynamic_input:
while getattr(input_node, "args", None):
input_node = input_node.args[0]
When tracing back through dynamic quantization nodes, args[0] can be an immutable_list (e.g., from a cat op where the first argument is a list of tensors). The loop assigns this list to input_node, then graph.inserting_after(input_node) crashes because immutable_list has no .graph attribute.
Fix: Add an isinstance check:
if is_dynamic_input:
while getattr(input_node, "args", None) and isinstance(input_node.args[0], torch.fx.Node):
input_node = input_node.args[0]
2. call method (line ~508)
self.input_to_nhwc(graph_module, node.args[0], node)
For ops like cat, node.args[0] is an immutable_list of tensors, not a single Node. This is passed directly as input_node to input_to_nhwc.
Fix: Guard with isinstance:
if isinstance(node.args[0], torch.fx.Node):
self.input_to_nhwc(graph_module, node.args[0], node)
Reproduction
- Export a model containing
torch.cat operations
- Apply dynamic quantization via
XNNPACKQuantizer with get_symmetric_quantization_config(is_per_channel=True, is_dynamic=True)
- Lower with
to_edge_transform_and_lower using XnnpackPartitioner() (without per_op_mode)
The crash occurs during the ChannelsLastTaggedReshapePass preprocessing step. Using per_op_mode=True works around the issue.
Stack Trace
File ".../channels_last_tagged_reshape_pass.py", line 508, in call
self.input_to_nhwc(graph_module, node.args[0], node)
File ".../channels_last_tagged_reshape_pass.py", line 405, in input_to_nhwc
with graph_module.graph.inserting_after(input_node):
File ".../torch/fx/graph.py", line 1583, in inserting_after
if n.graph != self:
AttributeError: 'immutable_list' object has no attribute 'graph'
Environment
- ExecuTorch 1.1.0
- PyTorch 2.9.1
- macOS (Apple Silicon)
Workaround
Use XnnpackPartitioner(per_op_mode=True) to bypass the fusion pass.
Bug
ChannelsLastTaggedReshapePass.input_to_nhwccrashes withAttributeError: 'immutable_list' object has no attribute 'graph'when lowering a dynamically quantized model to XNNPACK withoutper_op_mode.Root Cause
Two issues in
channels_last_tagged_reshape_pass.py:1.
input_to_nhwcwhile loop (line ~402)When tracing back through dynamic quantization nodes,
args[0]can be animmutable_list(e.g., from acatop where the first argument is a list of tensors). The loop assigns this list toinput_node, thengraph.inserting_after(input_node)crashes becauseimmutable_listhas no.graphattribute.Fix: Add an
isinstancecheck:2.
callmethod (line ~508)For ops like
cat,node.args[0]is animmutable_listof tensors, not a singleNode. This is passed directly asinput_nodetoinput_to_nhwc.Fix: Guard with isinstance:
Reproduction
torch.catoperationsXNNPACKQuantizerwithget_symmetric_quantization_config(is_per_channel=True, is_dynamic=True)to_edge_transform_and_lowerusingXnnpackPartitioner()(withoutper_op_mode)The crash occurs during the
ChannelsLastTaggedReshapePasspreprocessing step. Usingper_op_mode=Trueworks around the issue.Stack Trace
Environment
Workaround
Use
XnnpackPartitioner(per_op_mode=True)to bypass the fusion pass.