Fix UnsqueezeParser for ONNX Opset 13+#119
Conversation
- axes attribute was change to input starting from ONNX opset 13
📝 WalkthroughSummary by CodeRabbit
WalkthroughUnsqueeze parser updated to support axes provided either as a node attribute (opset v11 behavior) or as a second input tensor (opset v13+). parseNodeCtxt input-to-context mapping adjusted; axes are extracted from the appropriate source and axes buffer is marked non-deployable when axes come from an input. CHANGELOG updated accordingly. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant ONNX as ONNX Node
participant Parser as UnsqueezeParser
participant Ctxt as parseNodeCtxt
participant Op as OperatorRepresentation
Note over Parser, Op: Unsqueeze axes handling differs by opset
Parser->>ONNX: Inspect node.attrs and node.inputs
alt Opset v11 (axes as attribute)
ONNX-->>Parser: attrs contain `axes`
Parser->>Ctxt: Map single input -> data_in/data_out
Parser->>Op: Set axes = node.attrs['axes'] (list of ints)
else Opset v13+ (axes as input)
ONNX-->>Parser: inputs[0]=data, inputs[1]=axesTensor
Parser->>Ctxt: Map inputs[0] -> data_in/data_out, inputs[1] -> axes_buf
Parser->>Op: Read axes list from axes_buf tensor
Note right of Ctxt: axes_buf._live = False<br/>axes_buf._deploy = False
end
Parser-->>Op: Emit operatorRepresentation with axes populated
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Deeploy/Targets/Generic/Parsers.py (1)
962-973: Bug: opset13 path stores axes as a tensor name, not values. Extract constant axes and don’t expose it as a runtime input.Templates likely expect numeric axes (as in opset 11). Keep representation consistent and mark the axes constant as not deployed.
- if len(node.inputs) == 1: - inputs = ['data_in'] - else: - inputs = ['data_in','axes'] - outputs = ['data_out'] - - for idx, inputNode in enumerate(node.inputs): - self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name - for idx, outputNode in enumerate(node.outputs): - self.operatorRepresentation[outputs[idx]] = ctxt.lookup(outputNode.name).name + outputs = ['data_out'] + if len(node.inputs) == 1: + inputs = ['data_in'] + for idx, inputNode in enumerate(node.inputs): + self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name + for idx, outputNode in enumerate(node.outputs): + self.operatorRepresentation[outputs[idx]] = ctxt.lookup(outputNode.name).name + else: + # data + data_in = ctxt.lookup(node.inputs[0].name) + data_out = ctxt.lookup(node.outputs[0].name) + self.operatorRepresentation['data_in'] = data_in.name + self.operatorRepresentation['data_out'] = data_out.name + # axes must be a constant; extract values + axes_buf = ctxt.lookup(node.inputs[1].name) + assert hasattr(axes_buf, 'values'), "Unsqueeze: expected constant 'axes' input for opset 13+" + axes_vals = np.array(axes_buf.values).astype(int).flatten().tolist() + self.operatorRepresentation['axes'] = axes_vals + # Do not deploy the axes tensor + axes_buf._live = False + axes_buf._deploy = False
🧹 Nitpick comments (1)
Deeploy/Targets/Generic/Parsers.py (1)
943-954: Normalize axes handling and fix ONNX doc reference.
- Use Unsqueeze doc link.
- For opset 11, store axes as a list of ints.
- For opset 13+, don’t set axes here; defer extraction to parseNodeCtxt.
- # ONNX v11: 'axes' is a node attribute + # ONNX v11: 'axes' is a node attribute if 'axes' in node.attrs: ret = all(['axes' in node.attrs, len(node.inputs) == 1, len(node.outputs) == 1]) - # ONNX v13+: 'axes' becomes an input together with the data (source: https://onnx.ai/onnx/operators/onnx__Squeeze.html) + # ONNX v13+: 'axes' becomes an input with the data + # Source: https://onnx.ai/onnx/operators/onnx__Unsqueeze.html else: ret = all([len(node.inputs) == 2, len(node.outputs) == 1]) - if ret and 'axes' in node.attrs: - self.operatorRepresentation['axes'] = node.attrs['axes'] - elif ret: - self.operatorRepresentation['axes'] = node.inputs[1] + if ret and 'axes' in node.attrs: + axes_attr = node.attrs['axes'] + self.operatorRepresentation['axes'] = [int(axes_attr)] if isinstance(axes_attr, int) \ + else [int(a) for a in axes_attr] + # For opset 13+, axes will be extracted from the second input in parseNodeCtxt
… CCT_2_32_32_128_Opset20 test case using ONNX Opset version 20
…on ONNX Opset version and number of inputs
…higher as list of PRs
Looks good to me. To ensure compatibility with the new parser when using ONNX opset > 13, the implementation should follow the logic outlined here: Deeploy/Deeploy/OperatorDescriptor.py Lines 443 to 455 in 610e530 but |
Xeratec
left a comment
There was a problem hiding this comment.
I am okay with the changes and open to merge it. However, I strongly suggest adding the new test to the CI to prevent future fallbacks.
…platforms testing Squeeze and Unsqueeze new format for recent ONNX Opsets
This PR updates the `Squeeze` and `Unsqueeze` operators to align with the ONNX Opset 13+ standard, where axes is now provided as an input instead of a node attribute. The change is backward compatible, as the old logic remains for single-input cases. A new test case, `CCT/CCT_2_32_32_128_Opset20`, has been added using models exported from PyTorch with ONNX Opset 20 to verify compatibility with recent versions. ## Added - Added support for ONNX Opset 13 and higher. ## Changed - UnsqueezeParser in Generic NodeParser - Check for the presence of `axes` in node attributes and use the old workflow otherwise check for exactly 2 inputs (data and axes). - Node context was changes accordingly; 1 single input follows the old workflow, 2 inputs uses the new 2 input Op. format. ## Fixed - Breaking compilation with ONNX Opset 13 and higher when using `Squeeze` Op.
This PR updates the `Squeeze` and `Unsqueeze` operators to align with the ONNX Opset 13+ standard, where axes is now provided as an input instead of a node attribute. The change is backward compatible, as the old logic remains for single-input cases. A new test case, `CCT/CCT_2_32_32_128_Opset20`, has been added using models exported from PyTorch with ONNX Opset 20 to verify compatibility with recent versions. ## Added - Added support for ONNX Opset 13 and higher. ## Changed - UnsqueezeParser in Generic NodeParser - Check for the presence of `axes` in node attributes and use the old workflow otherwise check for exactly 2 inputs (data and axes). - Node context was changes accordingly; 1 single input follows the old workflow, 2 inputs uses the new 2 input Op. format. ## Fixed - Breaking compilation with ONNX Opset 13 and higher when using `Squeeze` Op.
This release includes improvements to the tiling and DMA code generation, new networks and operators, improved CI workflows, migration to PyTest, and support for PyPi package releases. Note: Since the release tag references the Docker container tagged with the release tag (ghcr.io/pulp-platform/deeploy:v0.2.1), the CI will initially fail. The Deeploy Docker image must be built after the release PR is merged and the CI restarted. ### List of Pull Requests - PyPi Package Deployment + Remove Banshee Dept [#154](#154) - PyTest Migration [#144](#144) - Update submodule `pulp-nn-mixed` [#145](#145) - Improve Profiling [#138](#138) - FP32 ReduceMean operator improvement [#137](#137) - Support for RMSNorm (Pow and Sqrt operators) [#136](#136) - Demo TinyViT compatibility with tiled Siracusa [#124](#124) - TinyViT on non-tiled Siracusa [#117](#117) - Support Fully Asynchronous DMAs [#114](#114) - Disallow shape inference [#128](#128) - Remove memory-aware node bindings [#123](#123) - Fix missing const's layout transformation and refactor NCHWtoNHWC passes [#122](#122) - Fix aliasing [#125](#125) - Support for 1D Autoencoder [#98](#98) - Refactor Logging for Improved Debugging [#115](#115) - Add reuse-tool as an SPDX license header linter [#113](#113) - Bug fixes, API Cleanup and Reduce Compiler Warning on PULP [#112](#112) - Fix PULP GEMM `batch` serialization [#109](#109) - Split CI Workflows by Platform and Task, Improve Formatting and Linting Reliability [#108](#108) - Refactor tiling code generation [#105](#105) - Change order of typeMatching entries [#68](#68) - Node Mangling to avoid duplication [#93](#93) - Prepare Post v0.2.0 Release [#104](#104) - Use Docker digests instead of arch-specific tags [#106](#106) - Fix `Unsqueeze` Op. when using ONNX opset 13 or higher (from attribute to input) [#119](#119) - Fix bias hoisting in generic GEMM with no bias [#126](#126)
PR to align the recent ONNX Opset standard for
Squeeze/UnsqueezeOps.Starting from version 13, 'axes' is not anymore a node attribute but rather an input together with the data.
Complete changelog from ONNX documentation: https://onnx.ai/onnx/operators/text_diff_Squeeze_11_13.html and https://onnx.ai/onnx/operators/text_diff_Unsqueeze_11_13.html
Changes should be non-breaking since the old flow is still called when there is only 1 single input.
There is already a test for
SqueezeOp in FP but it is failing under both old and new ONNX Opsets.To test if it works with recent Opsets of ONNX, I added
CCT/CCT_2_32_32_128_Opset20test case with input, output, and network files exported from PyTorch using ONNX Opset version 20.Added
Changed
axesin node attributes and use the old workflow otherwise check for exactly 2 inputs (data and axes).Fixed
SqueezeOp.PR Merge Checklist
develcommit and pointing todevel.CHANGELOG.mdfile has been updated.