fix: eliminate non-constant Slice ends in Gemma4 sliding-window CB subfunction - #1170
Open
quic-amitraj wants to merge 1 commit into
Open
Conversation
…bfunction
QEffGemma4DynamicLayer.update() computed rolling_indices as:
all_indices = torch.arange(layer_ctx_len) + kv_position_ids.max() + 1
rolling_indices = torch.where(...)
rolling_indices = rolling_indices[:ctx_len] # <- Slice_520
When compiled with -sub-functions, QAIC subfunction lowering rejects
Slice operators whose `ends` input is a non-constant function argument.
`ctx_len` (= Shape(past_key.0)[2] = sliding_window) is pre-computed in
the outer ONNX graph as Gather(Shape(past_key), 2) and injected into the
subfunction as an opaque INT32 parameter (onnx::Cast_1033). The compiler
therefore raises:
[Operator-'Slice_520'] : Slice: Non-constant ends tensor not supported.
Fix: replace torch.arange(layer_ctx_len)[:ctx_len] with torch.arange(ctx_len)
directly. arange(n)[:n] == arange(n) identically, so there is no
behavioural change. The resulting Range node with a dynamic upper bound
is already supported in QAIC subfunction lowering -- the existing
ctx_indices = torch.arange(ctx_len)[None, None, ...]
line in the same method demonstrates this. Slice_520 is eliminated
entirely from the exported subfunction body.
This is the same class of bug as the CtxGatherCB comp_ctx_len regression
fixed in c89c4f7.
Also updates the gemma4_cb.py example to use_onnx_subfunctions=True to
exercise and demonstrate the now-working path.
Tested: gemma4_cb.py (FULL_BATCH_SIZE=4, 2-layer reduced config) with
use_onnx_subfunctions=True compiles and runs end-to-end on AI100.
Signed-off-by: Amit Raj <amitraj@qti.qualcomm.com>
Contributor
|
@quic-amitraj - Can you please post the following, you can use Gemma4-E2B-IT model (quick for testing)
Lets get it ready by Monday, so that we can merge your changes. |
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When compiling
Gemma4ForConditionalGenerationwithuse_onnx_subfunctions=Trueandcontinuous_batching=True, the QAIC compiler fails with:This occurs during language-decoder QPC compilation when
-sub-functionsis passed. The vision encoder compiles successfully; only the decoder fails.Root Cause
In
QEffGemma4DynamicLayer.update()(cache_utils.py), the sliding-window rolling-index computation was:The
rolling_indices[:ctx_len]slice translates to an ONNXSlicenode inside theQEffGemma4TextDecoderLayersubfunction. Itsendstensor isctx_len = Shape(past_key.0)[2](=sliding_window), which is pre-computed in the outer ONNX graph asGather(Shape(past_key.0), 2)and injected into the subfunction as an opaqueINT32argument (onnx::Cast_1033). Inside the subfunction body, the QAIC compiler sees this as a dynamic value — not a shape-derived constant — and rejects it.This is the same class of bug as the
CtxGatherCBcomp_ctx_lenregression fixed in c89c4f7.Fix
Replace
torch.arange(layer_ctx_len)[:ctx_len]withtorch.arange(ctx_len)directly.arange(n)[:n] == arange(n)identically, so there is no behavioural change. TheRangeop with a dynamic upper bound is already permitted in QAIC subfunction lowering — the existingctx_indices = torch.arange(ctx_len)[None, None, ...]line in the same method demonstrates this.Slice_520is eliminated entirely from the exported subfunction body.The fix is also correct for the CCL case:
torch.arange(min(sliding_window, CCL))naturally producesCCLelements without any slice.Changes
QEfficient/transformers/cache_utils.pyarange(layer_ctx_len)[:ctx_len]witharange(ctx_len)inQEffGemma4DynamicLayer.update()examples/image_text_to_text/models/gemma_vision/gemma4/gemma4_cb.pyuse_onnx_subfunctions=Trueto exercise the now-working pathTest Plan
gemma4_cb.pywithuse_onnx_subfunctions=True,continuous_batching=True,full_batch_size=4, 2-layer reduced config — compiles and runs end-to-end on AI100gemma4_cb.pywithuse_onnx_subfunctions=False— continues to pass (no regression)Slice_520is absent from the re-exported subfunction ONNX body