Preserve shape ops when removing QDQ pairs#5048
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #5048 +/- ##
===========================================
+ Coverage 92.78% 92.81% +0.03%
===========================================
Files 596 597 +1
Lines 32011 32164 +153
===========================================
+ Hits 29700 29851 +151
- Misses 2311 2313 +2
🚀 New features to boost your workflow:
|
Regressions detected 🔴 |
|
TedThemistokleous
left a comment
There was a problem hiding this comment.
Hey thanks for your contribution!
I have a few suggested changes and some initial questions
| inline auto get_input_path(instruction_ref ins) | ||
| { | ||
| return unfold(ins, [](instruction_ref x) -> std::optional<instruction_ref> { | ||
| if(x->inputs().size() != 1) |
There was a problem hiding this comment.
What if there's multiple inputs?
Is this intending on check for single inputs or non zero non multi inputs. Some ops can have two inputs like gather (calculate shape for indicies and data).
| if(q_pos == input_path.end()) | ||
| return std::nullopt; | ||
| auto is_pack_unpack = [](auto x) { | ||
| return contains({"pack_fp4", "unpack_fp4"}, x->name()); |
There was a problem hiding this comment.
Make this a helper instead of a lamda so we can target all pack/unpacks in general.
Do the same for has_pack_unpack below
| if(contains(replay_ops(), x->name())) | ||
| { | ||
| if(not has_pack_unpack) | ||
| ops.push_back(x->get_operator()); |
There was a problem hiding this comment.
I think we should separate this between "should we add" and "we are adding the replay op" to the list. Is the intent here to check and ensure we have replays that we can then if not just return no replacement?
| if(replacement->get_shape() != dq_ins->get_shape()) | ||
| return std::nullopt; | ||
| return replacement; | ||
| } |
There was a problem hiding this comment.
There's a few code paths here where things just go to nullopt after a bunch of operations. Is there a way to reduce the complexity of this or return earlier by bundling a few of these checks?
| static const std::unordered_set<std::string> ops = { | ||
| "pack_fp4", "unpack_fp4", "broadcast", "slice", "reshape", "reshape_lazy", "pad"}; | ||
| return ops; | ||
| } |
There was a problem hiding this comment.
Not sure why this had to change to a function same with below for replay_ops return this back as a regular static const std:unordered_set for both.
| } | ||
| if(not has_pack_unpack) | ||
| { | ||
| std::reverse(ops.begin(), ops.end()); |
There was a problem hiding this comment.
Not sure why we need to do a reverse here?, also we're inserting new items in the graph with the insert below.
|
Adding Shiv since he's looked a lot of the QDQ stuff |
| new_cat_inputs.end(), | ||
| replacement_inputs.begin(), | ||
| [](const auto& input) { return *input; }); | ||
| m.replace_instruction(ins, cat_ins->get_operator(), replacement_inputs); |
There was a problem hiding this comment.
Can you add a regression test for this finder? So its easier to understand what was failing before and is now fixed by this change
Motivation
Fix
simplify_qdqso Q/DQ pair removal does not accidentally drop intervening shape operations or produce shape-changing rewrites.Technical Details
Updated Q/DQ removal to replay supported shape operations when removing non-FP4 fake quantization chains, while continuing to drop FP4 pack/unpack adapter operations where appropriate. Added guards for concat QLinear splitting when sliced scale or zero-point shapes do not match the corresponding concat input. Added a regression test for preserving
sliceandreshapethrough Q/DQ removal.Changelog Category
Add a
CHANGELOG.mdentry for any option other thanNot Applicable