Repository navigation
Qualcomm AI Engine Direct - Support QAT for concat observer - #23347
shewu-quic wants to merge 5 commits into
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/23347
Note: Links to docs will display an error until the docs builds have been completed.
|
This PR needs a
|
8340e1f to
a05b2fd
Compare
|
@billmguo has imported this pull request. If you are a Meta employee, you can view this in D122948809. |
|
@shewu-quic seems this cover#23298 and use different method to fix concat as #23299 1 With SharedQuantizationSpec in pt2e, every input edge and the output get one shared observer instance. Your approach does observe all of them, not just the first input.The real weakness is in the QAT observer, which uses a moving average. Calls on x+1, y*4 and the cat output are blended rather than combined into one overall min/max. So the wider input can be partly clipped. Your test only checked that there is one qparam, not that the range covers every input, which is why it didn't catch this. #23347's shared_range_covers_every_input subtest does check it. |
|
Two cats sharing an input fight over its range (S4). Both ConcatObservers overwrite the observer on a+1, and the last one to write wins. So cat0 ends up with input qparams that don't match its output. I haven't checked whether QNN's Concat accepts mixed input encodings or adds a requantize. do you able to try a model on device or simulator and see whether this case is covered |
|
@shewu-quic when will u mainline this PR? |
a05b2fd to
25b93e1
Compare
I have test with test_qat_concat for multi-step QAT process and test_concat_observer_deepcopy for deep copy issue. |
|
@shewu-quic when can u mainline on this I will ask our model team use this PR once mainline. |
|
Hi @psiddh, |
Summary
See PR #23299 for the root-cause writeup —
ConcatObserveris PTQ-only (plain observer, pokes other observers'min_val/max_valdirectly), which breaks under QAT since the output never gets fake-quantized and the write lands on a dead attribute onFusedMovingAvgObsFakeQuantizeinputs.This PR takes a different fix than #23299's
SharedQuantizationSpecapproach: that shares qparams only with the first cat input, which clips any other input with a wider range (verified with acat([x+1, y*4])toy model — the first input's calibrated range doesn't cover the second). Instead,concat_observer_ctr()keepsConcatObserverunchanged for PTQ, and addsConcatFakeQuantizefor QAT — aFakeQuantizepaired withConcatObserver, same pattern as the existingPerBlockParamObserver/PerBlockParamFakeQuantize— so the output is still fake-quantized whileConcatObserverkeeps aggregating the true max range across every input and the output, not just the first.Test plan
Added to
backends/qualcomm/tests/rework/utils/test.py(no device required):test_qat_concat— QAT-preparedcat([x+1, y*4]): output isConcatFakeQuantizewrappingConcatObserver, its observed range covers both inputs within one quant step, andconvert_pt2egives inputs and output one shared qparam.test_concat_observer_deepcopy— cat at the end of a 300-node chain:copy.deepcopy+convert_pt2edoesn't raiseRecursionError, and the copy'sinput_observerspoint at the copy's own submodules.