Unsupported FX Nodes: {'call_function': ['aten.quantized_gru.input', 'quantized.linear_dynamic.default']}
メンテナーはふだん 3 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 35/100
- issue の種類
- 機能追加
- 明瞭さ
- おおむね明確
- 活発さ
- 停滞
調査の方向性
torch.onnx.dynamo_export と、torch/onnx/_internal/fx/analysis/unsupported_nodes.py にある未サポートノードの分析から始めます。報告された aten.quantized_gru.input ノードおよび quantized.linear_dynamic.default ノードを、既存の aten_quantized_gru_cell のサポートと、診断で言及されている FX パスと比較します。示されている量子化モデルが、これらの未サポートノードエラーなしに ONNX へ正常にエクスポートできれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Hello,
I am trying to convert a torchao quantized deep learning model(consisting of Linear, GRU layers, etc) to onnx but running into the error: Unsupported FX nodes: {'call_function': ['aten.quantized_gru.input', 'quantized.linear_dynamic.default']}.
Post-Training Quantization(using torch.ao.quantization.quantize_fx)
The quantization method used is Post-Training Dynamic Int8 Quantization(weights-only) in FX mode.
Adding the snippet of quantizing the model and saving it as .pth below:
input_tensor = torch.randn(batch_size, 3840)
qconfig_mapping = QConfigMapping().set_global(torch.ao.quantization.default_dynamic_qconfig)
model_prepared = quantize_fx.prepare_fx(model_to_quantize, qconfig_mapping, input_tensor)
model_quantized = quantize_fx.convert_fx(model_prepared)
torch.save(model_quantized, "fx_quant.pth")
Conversion to ONNX
Upon converting the quantized model to onnx:
onnx_program = torch.onnx.dynamo_export(model_quantized, input_tensor)
I run into the below error:
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/_exporter_legacy.py", line 1222, in dynamo_export
).export()
File "/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/_exporter_legacy.py", line 976, in export
graph_module = self.options.fx_tracer.generate_fx(
File "/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/dynamo_graph_extractor.py", line 217, in generate_fx
return self.pre_export_passes(options, model, graph_module, updated_model_args) # type: ignore[return-value]
File "/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/dynamo_graph_extractor.py", line 226, in pre_export_passes
return _exporter_legacy.common_pre_export_passes(
File "/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/_exporter_legacy.py", line 1275, in common_pre_export_passes
).analyze(infra.levels.ERROR)
File "/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/analysis/unsupported_nodes.py", line 85, in analyze
self._lint(analysis_result, diagnostic_level)
File "/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/analysis/unsupported_nodes.py", line 37, in _lint
self.diagnostic_context.log_and_raise_if_error(diagnostic)
File "/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/diagnostics/infra/context.py", line 356, in log_and_raise_if_error
raise RuntimeErrorWithDiagnostic(diagnostic)
torch.onnx._internal.diagnostics.infra.context.RuntimeErrorWithDiagnostic: Unsupported FX nodes: {'call_function': ['aten.quantized_gru.input', 'quantized.linear_dynamic.default']}.
Note
- the conversion to onnx with the original model(without quantization) happens successfully
- I can find the support for op
aten_quantized_gru_cell. is it possible to make use of this and if yes, then how?
report_dynamo_export.sarif
{
"runs":[
{
"tool":{
"driver":{
"name":"torch.onnx.dynamo_export",
"contents":[
"localizedData",
"nonLocalizedData"
],
"language":"en-US",
"rules":[
{
"id":"FXE0012",
"fullDescription":{
"text":"Result from FX graph analysis to reveal unsupported FX nodes.",
"markdown":"This error indicates that an FX graph contains one or more unsupported nodes. The error message\nis typically accompanied by a list of the unsupported nodes found during analysis.\n\nTo resolve this error, you can try resolving each individual unsupported node error by following\nthe suggestions by its diagnostic. Typically, options include:\n\n- If exists, apply the auto-fix suggested by the diagnostic. TODO: this part is not available yet.\n- Rewrite the model using only supported PyTorch operators or functions.\n- Follow this [guide](https://pytorch.org/docs/stable/onnx.html#onnx-script-functions) to write and\n register a custom symbolic function for the unsupported call_function FX node.\n"
},
"name":"unsupported-fx-node-analysis",
"shortDescription":{
"text":"Result from FX graph analysis to reveal unsupported FX nodes."
}
},
{
"id":"FXE0015",
"fullDescription":{
"text":"Determine if type promotion is required for the FX node. Insert cast nodes if needed.",
"markdown":"This diagnostic monitors the node-level type promotion insertion process. In PyTorch, there is an automatic process called implicit type promotion,\nwhere the input types of an operator are promoted to a common type. The determination of the common type is based on the type promotion rule specific to each operator.\nTo learn more about PyTorch's type promotion rules, refer to the [elementwise_dtypes doc](https://github.com/pytorch/pytorch/blob/f044613f78df713fb57f70c608483c9f10ad332e/torch/_prims_common/__init__.py#L1252-L1335)\nand [torch._refs ops](https://github.com/pytorch/pytorch/blob/a475ea4542dfe961c9d097e33ab5041f61c8c17f/torch/_refs/__init__.py#L484).\n\nHowever, implicit type promotion is not supported in ONNX. Therefore, to replicate the PyTorch behavior, we need to explicitly insert cast nodes.\nThis diagnostic tracks the process of node-level type promotion insertion.\n\nThe type promotion rules used by this process can be found in `torch/onnx/_internal/fx/passes/type_promotion.py.`\nTo update or add new type promotion rules, please refer to the [Note: Update type promotion rule] section.\n"
},
"name":"fx-node-insert-type-promotion",
"shortDescription":{
"text":"Determine if type promotion is required for the FX node. Insert cast nodes if needed."
}
},
{
"id":"FXE0010",
"fullDescription":{
"text":"FX graph transformation during ONNX export before converting from FX IR to ONNX IR.",
"markdown":"This diagnostic tracks the FX passes executed during the ONNX export process prior\nto converting from FX IR (Intermediate Representation) to ONNX IR.\n\nUnder the scope of ONNX export, an FX pass refers to a specific transformation applied to the FX GraphModule.\nThe primary aim of these passes is to streamline the graph into a format that aligns more with the ONNX IR.\nMoreover, these passes work to substitute unsupported FX IR features with those recognized and endorsed by\nONNX IR. Common transformations include, but aren't limited to, decomposition, functionalization and\ntype promotion.\n\nFor those who are interested in a comprehensive log detailing the modifications made during these passes,\nthere are a couple of options:\n\n- Set DiagnosticOptions.verbosity_level to logging.DEBUG.\n- Activate the environment variable TORCH_LOGS='onnx_diagnostics'.\n\nHowever, it's noteworthy that by default, such detailed logging is turned off. The primary reason being\nits considerable impact on performance.\n\nFor an in-depth understanding of each specific pass, please refer to the directory: torch/onnx/_internal/fx/passes.\n"
},
"name":"fx-pass",
"shortDescription":{
"text":"FX graph transformation during ONNX export before converting from FX IR to ONNX IR."
}
}
],
"version":"2.5.1+cu124"
}
},
"language":"en-US",
"newlineSequences":[
"\r\n",
"\n"
],
"results":[
{
"message":{
"markdown":"Running Decompose pass. \n\n## Additional Message:\n\n## Function Signature\n### Function Signature Transform.run\n- self: <class 'torch.onnx._internal.fx.passes.decomp.Decompose'>\n- args: Tuple[length=1](\nTensor(f32[1, 3840]),\n)\nFor detailed logging of graph modifications by this pass, either set `DiagnosticOptions.verbosity_level` to `logging.DEBUG` or use the environment variable `TORCH_LOGS='onnx_diagnostics'`.\n## Return values\ntorch.fx.GraphModule(<lambda>)",
"text":"Running Decompose pass. "
},
"codeFlows":[
{
"threadFlows":[
{
"locations":[]
}
]
}
],
"graphs":[],
"kind":"informational",
"level":"none",
"locations":[
{
"message":{
"text":"Transform.run"
},
"physicalLocation":{
"artifactLocation":{
"uri":"/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/_pass.py"
},
"region":{
"snippet":{
"text":"@diagnostics.diagnose_call("
},
"startLine":240
}
}
}
],
"properties":{
"tags":[]
},
"ruleId":"FXE0010",
"stacks":[]
},
{
"message":{
"markdown":"Running Functionalize pass. \n\n## Additional Message:\n\n## Function Signature\n### Function Signature Transform.run\n- self: <class 'torch.onnx._internal.fx.passes.functionalization.Functionalize'>\n- args: Tuple[length=1](\nTensor(f32[1, 3840]),\n)\nFor detailed logging of graph modifications by this pass, either set `DiagnosticOptions.verbosity_level` to `logging.DEBUG` or use the environment variable `TORCH_LOGS='onnx_diagnostics'`.\n## Return values\ntorch.fx.GraphModule(<lambda>)",
"text":"Running Functionalize pass. "
},
"codeFlows":[
{
"threadFlows":[
{
"locations":[]
}
]
}
],
"graphs":[],
"kind":"informational",
"level":"none",
"locations":[
{
"message":{
"text":"Transform.run"
},
"physicalLocation":{
"artifactLocation":{
"uri":"/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/_pass.py"
},
"region":{
"snippet":{
"text":"@diagnostics.diagnose_call("
},
"startLine":240
}
}
}
],
"properties":{
"tags":[]
},
"ruleId":"FXE0010",
"stacks":[]
},
{
"message":{
"markdown":"Running RemoveInputMutation pass. \n\n## Additional Message:\n\n## Function Signature\n### Function Signature Transform.run\n- self: <class 'torch.onnx._internal.fx.passes.functionalization.RemoveInputMutation'>\n- args: Tuple[length=1](\nTensor(f32[1, 3840]),\n)\nFor detailed logging of graph modifications by this pass, either set `DiagnosticOptions.verbosity_level` to `logging.DEBUG` or use the environment variable `TORCH_LOGS='onnx_diagnostics'`.\n## Return values\ntorch.fx.GraphModule(<lambda>)",
"text":"Running RemoveInputMutation pass. "
},
"codeFlows":[
{
"threadFlows":[
{
"locations":[]
}
]
}
],
"graphs":[],
"kind":"informational",
"level":"none",
"locations":[
{
"message":{
"text":"Transform.run"
},
"physicalLocation":{
"artifactLocation":{
"uri":"/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/_pass.py"
},
"region":{
"snippet":{
"text":"@diagnostics.diagnose_call("
},
"startLine":240
}
}
}
],
"properties":{
"tags":[]
},
"ruleId":"FXE0010",
"stacks":[]
},
{
"message":{
"markdown":"Skipped l_x_: not a call_function.\n\n## Additional Message:\n\n## Function Signature\n### Function Signature _TypePromotionInterpreter.run_node\n- self: <class 'torch.onnx._internal.fx.passes.type_promotion._TypePromotionInterpreter'>\n- node: fx.Node(arg0)[placeholder]:Tensor(f32[1, 3840])\n## Return values\nTensor(f32[1, 3840])",
"text":"Skipped l_x_: not a call_function."
},
"codeFlows":[
{
"threadFlows":[
{
"locations":[]
}
]
}
],
"graphs":[],
"kind":"informational",
"level":"none",
"locations":[
{
"message":{
"text":"_TypePromotionInterpreter.run_node"
},
"physicalLocation":{
"artifactLocation":{
"uri":"/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/passes/type_promotion.py"
},
"region":{
"snippet":{
"text":"@diagnostics.diagnose_call("
},
"startLine":1607
}
}
}
],
"properties":{
"tags":[]
},
"ruleId":"FXE0015",
"stacks":[]
},
{
"message":{
"markdown":"Skipped for fx.Node(aten.unsqueeze.default)[call_function]:Tensor(f32[1, 1, 3840]): Cannot find type promotion rule for op: aten.unsqueeze.default\n\n## Additional Message:\n\n## Function Signature\n### Function Signature _TypePromotionInterpreter.run_node\n- self: <class 'torch.onnx._internal.fx.passes.type_promotion._TypePromotionInterpreter'>\n- node: fx.Node(aten.unsqueeze.default)[call_function]:Tensor(f32[1, 1, 3840])\n## Return values\nTensor(f32[1, 1, 3840])",
"text":"Skipped for fx.Node(aten.unsqueeze.default)[call_function]:Tensor(f32[1, 1, 3840]): Cannot find type promotion rule for op: aten.unsqueeze.default"
},
"codeFlows":[
{
"threadFlows":[
{
"locations":[]
}
]
}
],
"graphs":[],
"kind":"informational",
"level":"none",
"locations":[
{
"message":{
"text":"_TypePromotionInterpreter.run_node"
},
"physicalLocation":{
"artifactLocation":{
"uri":"/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/passes/type_promotion.py"
},
"region":{
"snippet":{
"text":"@diagnostics.diagnose_call("
},
"startLine":1607
}
}
}
],
"properties":{
"tags":[]
},
"ruleId":"FXE0015",
"stacks":[]
},
{
"message":{
"markdown":"Skipped _param_constant0: not a call_function.\n\n## Additional Message:\n\n## Function Signature\n### Function Signature _TypePromotionInterpreter.run_node\n- self: <class 'torch.onnx._internal.fx.passes.type_promotion._TypePromotionInterpreter'>\n- node: fx.Node(_param_constant0)[get_attr]:None\n## Return values\nParameter(Tensor(f32[1280, 1, 960]))",
"text":"Skipped _param_constant0: not a call_function."
},
"codeFlows":[
{
"threadFlows":[
{
"locations":[]
}
]
}
],
"graphs":[],
"kind":"informational",
"level":"none",
"locations":[
{
"message":{
"text":"_TypePromotionInterpreter.run_node"
},
"physicalLocation":{
"artifactLocation":{
"uri":"/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/passes/type_promotion.py"
},
"region":{
"snippet":{
"text":"@diagnostics.diagnose_call("
},
"startLine":1607
}
}
}
],
"properties":{
"tags":[]
},
"ruleId":"FXE0015",
"stacks":[]
},
{
"message":{
"markdown":"Skipped for fx.Node(aten.convolution.default)[call_function]:Tensor(f32[1, 1280, 7]): Cannot find type promotion rule for op: aten.convolution.default\n\n## Additional Message:\n\n## Function Signature\n### Function Signature _TypePromotionInterpreter.run_node\n- self: <class 'torch.onnx._internal.fx.passes.type_promotion._TypePromotionInterpreter'>\n- node: fx.Node(aten.convolution.default)[call_function]:Tensor(f32[1, 1280, 7])\n## Return values\nTensor(f32[1, 1280, 7])",
"text":"Skipped for fx.Node(aten.convolution.default)[call_function]:Tensor(f32[1, 1280, 7]): Cannot find type promotion rule for op: aten.convolution.default"
},
"codeFlows":[
{
"threadFlows":[
{
"locations":[]
}
]
}
],
"graphs":[],
"kind":"informational",
"level":"none",
"locations":[
{
"message":{
"text":"_TypePromotionInterpreter.run_node"
},
"physicalLocation":{
"artifactLocation":{
"uri":"/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/passes/type_promotion.py"
},
"region":{
"snippet":{
"text":"@diagnostics.diagnose_call("
},
"startLine":1607
}
}
}
],
"properties":{
"tags":[]
},
"ruleId":"FXE0015",
"stacks":[]
},
{
"message":{
"markdown":"Type promotion not needed for relu. \n\n## Additional Message:\n\n## Function Signature\n### Function Signature _TypePromotionInterpreter.run_node\n- self: <class 'torch.onnx._internal.fx.passes.type_promotion._TypePromotionInterpreter'>\n- node: fx.Node(aten.relu.default)[call_function]:Tensor(f32[1, 1280, 7])\nFound type promotion rule: ElementwiseTypePromotionRule('aten', 'relu', [0], [], ELEMENTWISE_TYPE_PROMOTION_KIND.DEFAULT)\nArgument convolution is not promoted. Already torch.float32.\n## Return values\nTensor(f32[1, 1280, 7])",
"text":"Type promotion not needed for relu. "
},
"codeFlows":[
{
"threadFlows":[
{
"locations":[]
}
]
}
],
"graphs":[],
"kind":"informational",
"level":"none",
"locations":[
{
"message":{
"text":"_TypePromotionInterpreter.run_node"
},
"physicalLocation":{
"artifactLocation":{
"uri":"/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/passes/type_promotion.py"
},
"region":{
"snippet":{
"text":"@diagnostics.diagnose_call("
},
"startLine":1607
}
}
}
],
"properties":{
"tags":[]
},
"ruleId":"FXE0015",
"stacks":[]
},
{
"message":{
"markdown":"Skipped for fx.Node(aten.detach.default)[call_function]:Tensor(f32[1, 1280, 7]): Cannot find type promotion rule for op: aten.detach.default\n\n## Additional Message:\n\n## Function Signature\n### Function Signature _TypePromotionInterpreter.run_node\n- self: <class 'torch.onnx._internal.fx.passes.type_promotion._TypePromotionInterpreter'>\n- node: fx.Node(aten.detach.default)[call_function]:Tensor(f32[1, 1280, 7])\n## Return values\nTensor(f32[1, 1280, 7])",
"text":"Skipped for fx.Node(aten.detach.default)[call_function]:Tensor(f32[1, 1280, 7]): Cannot find type promotion rule for op: aten.detach.default"
},
................................(too long to paste here)
Is there any guideline on how to solve this problem and implement the support for the aforementioned operations?
Thank you, and sorry for the long post.
- 主要言語
- Python
- スター
- 457
- フォーク
- 149
- 平均マージ
- 3日 15時間
- マージ済み PR(30日)
- 24
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
microsoft/onnxscript のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
microsoft/onnxscript#3003 · コメント 3 件 ·
メンテナーはふだん 3 日以内に返信
-
CI : Pin github actions to full commit SHA対応中かも @Aniketsy が 183 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
microsoft/onnxscript#2903 · コメント 6 件 ·
メンテナーはふだん 3 日以内に返信
-
optimize() crashes when constant folding produces a string tensor対応中かも @nniiovoo が 8 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
microsoft/onnxscript#3129 ·
メンテナーはふだん 3 日以内に返信
-
bug module: torchlib
難易度 3/5 1〜2日 初心者へのやさしさ 64/100
microsoft/onnxscript#3124 · コメント 4 件 · リアクション 1 件 ·
メンテナーはふだん 3 日以内に返信
-
[torchlib] Float remainder is off by the divisor when the quotient rounds up, and nan for an infinite divisor対応中かも @usmanmateen が 14 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 68/100
microsoft/onnxscript#3116 ·
メンテナーはふだん 3 日以内に返信
microsoft/onnxscript の issue をすべて見る
似ている issue
-
HandyModRTransform.deriv3 is wrong for m > 2対応中かも @SajalDevX が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
read_messages: the first read after subscribe/psubscribe returns no messages even when some are waiting対応中かも @matheussilvano が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 80/100
The-Swarm-Corporation/swarms-framework-docs#399 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
メンテナーはふだん 1 日以内に返信
-
bump patch
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
autowarefoundation/autoware_carla_scenario#1321 ·
メンテナーはふだん 1 日以内に返信