Repository navigation
[MODEL] support qwen3.5 series - #19468
Conversation
|
@JJJYmmm no worries, glad if it helped even a little :) |
ngxson
left a comment
There was a problem hiding this comment.
I haven't reviewed the actual implementation, but I assume it's mostly qwen3 next + imrope (please correct if I'm wrong)
Don't hesitate to ping if you need helps to add the vision support!
It definitely helped a lot 🙏 |
ggerganov
left a comment
There was a problem hiding this comment.
The libllama changes are good. I will follow up with a PR to deduplicate and optimize the delta net stuff across the Qwen family.
|
|
||
| // if head keys and value keys are different, repeat to force tensors into matching shapes | ||
| if (num_k_heads != num_v_heads) { | ||
| GGML_ASSERT(num_v_heads % num_k_heads == 0); | ||
| int64_t repeat_factor = num_v_heads / num_k_heads; | ||
|
|
||
| // repeat interleave: reshape to (repeat part, 1, remaining part), do repeat, then reshape back | ||
| ggml_tensor * q_reshaped = ggml_reshape_3d(ctx0, q_conv, head_k_dim, 1, num_k_heads * n_seq_tokens * n_seqs); | ||
| ggml_tensor * k_reshaped = ggml_reshape_3d(ctx0, k_conv, head_k_dim, 1, num_k_heads * n_seq_tokens * n_seqs); | ||
|
|
||
| // Repeat along the third dimension (the new dimension with size 1) | ||
| ggml_tensor * q_repeated = | ||
| ggml_repeat_4d(ctx0, q_reshaped, head_k_dim, repeat_factor, num_k_heads * n_seq_tokens * n_seqs, 1); | ||
| ggml_tensor * k_repeated = | ||
| ggml_repeat_4d(ctx0, k_reshaped, head_k_dim, repeat_factor, num_k_heads * n_seq_tokens * n_seqs, 1); | ||
|
|
||
| // Reshape back to merge the head and repeat dimensions | ||
| // From [head_dim, num_k_heads, repeat_factor, n_seq_tokens * n_seqs] | ||
| // Back to [head_dim, num_k_heads * repeat_factor, n_seq_tokens, n_seqs] | ||
| q_conv = ggml_reshape_4d(ctx0, q_repeated, head_k_dim, num_k_heads * repeat_factor, n_seq_tokens, n_seqs); | ||
| k_conv = ggml_reshape_4d(ctx0, k_repeated, head_k_dim, num_k_heads * repeat_factor, n_seq_tokens, n_seqs); | ||
| } | ||
|
|
There was a problem hiding this comment.
Btw, this is an issue inherited from the Qwen3 Next implementation. Basically we are doing redundant repeats here because the V weights are not arranged correctly during conversion. Ideally this whole section should not be needed and we should only rely on broadcasts.
Basically, we want to broadcast Q and K into V. With the current order of the V heads, we need an interleaved broadcast. However the ggml binary ops perform tiled broadcast. Hence the need for this rearrangement.
There was a problem hiding this comment.
If it is too difficult to figure out how to fix this for the new Qwen3.5 models, we'll have to do it in a follow-up PR. But it's going to be a breaking change. Or maybe we can try to gate it with some flag.
There was a problem hiding this comment.
I would try to fix it in the qwen3.5 gguf conversion since it is not released.
There was a problem hiding this comment.
Since it's a new arch we should not need a flag as such then.
There was a problem hiding this comment.
just reorder the related v weights to avoid repeat_interleave🫡 4248c93
There was a problem hiding this comment.
Nice. Just make sure results are still as expected after this change.
From here, I think we will be able to remove the explicit repeats - this is something for next PR. Thanks a lot!
There was a problem hiding this comment.
Yes, I tested it with the new generated weights, and it works just as before. 🫡
ngxson
left a comment
There was a problem hiding this comment.
The changes outside of cgraph looks good to me (sorry don't have too much time to look deeper, but I believe the review from @ggerganov and @CISC should already be enough)
Looking forward to the vision support PR then!
@ngxson This pr includes the vision part and I test it too! (qwen3.5 uses the same vit as qwen3vl and deepstack was removed temporally)🤗 |
|
@JJJYmmm ah yeah right, thanks for the clarification. Yes I already acknowledge that the deep stack is removed (confirmed by Look good to me then, thanks again! |
|
It seems to me that all review comments are resolved, and @JJJYmmm also confirmed that the model is still working fine with last commit. So, I'll let @ggerganov to decide when to merge this. |
* support qwen3.5 series * remove deepstack for now, and some code clean * code clean * add FULL_ATTENTION_INTERVAL metadata * code clean * reorder v heads for linear attention to avoid expensive interleaved repeat
* support qwen3.5 series * remove deepstack for now, and some code clean * code clean * add FULL_ATTENTION_INTERVAL metadata * code clean * reorder v heads for linear attention to avoid expensive interleaved repeat
* support qwen3.5 series * remove deepstack for now, and some code clean * code clean * add FULL_ATTENTION_INTERVAL metadata * code clean * reorder v heads for linear attention to avoid expensive interleaved repeat
* support qwen3.5 series * remove deepstack for now, and some code clean * code clean * add FULL_ATTENTION_INTERVAL metadata * code clean * reorder v heads for linear attention to avoid expensive interleaved repeat
* support qwen3.5 series * remove deepstack for now, and some code clean * code clean * add FULL_ATTENTION_INTERVAL metadata * code clean * reorder v heads for linear attention to avoid expensive interleaved repeat
* support qwen3.5 series * remove deepstack for now, and some code clean * code clean * add FULL_ATTENTION_INTERVAL metadata * code clean * reorder v heads for linear attention to avoid expensive interleaved repeat
* support qwen3.5 series * remove deepstack for now, and some code clean * code clean * add FULL_ATTENTION_INTERVAL metadata * code clean * reorder v heads for linear attention to avoid expensive interleaved repeat
… support already landed The previous version wrongly concluded llama.cpp had no vision support for Qwen3.5 at all, citing a reverted early PR (#19435) and misreading issue #19917 as an open capability gap. Verified directly against the primary sources this time: - ggml-org/llama.cpp#19468 (merged 2026-02-10) explicitly includes and tests Qwen3.5 vision support. - Issue #19917 is closed -- it reports the standard 'missing --mmproj' hint text, a usage error, not a missing feature. - bartowski/ATH-MaaS_OvisOCR2-GGUF ships a matching mmproj for this exact 0.8B checkpoint. Its GGUF general.architecture is 'qwen35', already in ARCH_TO_FAMILY -- the existing mmproj-upgrade path already promotes it to a vision family with zero new detection code. - The mmproj-upgrade default (lfm2_vl) forces JSON-schema output, wrong for this model's free-text Markdown OCR; vision_ocr is the right family pick -- an operator choice at deploy, not a new family. - The one real llama.cpp correctness bug in this arch's history (#19683) is closed, CUDA-only, and MoE-only -- irrelevant to CPU dense-model serving. Added RUNTIME_NOTES['qwen35'] (cites #19468, warns the mmproj must come from the same checkpoint size -- projector output dimension differs across Qwen3.5 variants) plus a test covering both the plain text and mmproj-upgraded vision verdicts. The two transformers-runtime fixes from the previous commit are unaffected -- they were found while chasing the (ultimately wrong) trust_remote_code theory, but are real, general fixes independent of which family this specific model turned out to need.
…m-code VLMs (#252) * fix(transformers): correct vision detection + honest errors for custom-code VLMs Investigating support for ATH-MaaS/OvisOCR2 (an Ovis-family OCR model on a Qwen3.5 base) surfaced two real gaps in the last-resort transformers serving path, independent of that specific model: - HfTransformersBackend inferred vision capability from which AutoModel constructor happened to succeed (AutoModelForImageTextToText vs a AutoModelForCausalLM fallback). A custom-code VLM whose auto_map registers only under AutoModelForCausalLM (a common, older pattern — the Ovis family included) was silently misclassified as text-only even though its processor is genuinely multimodal. Fixed by deriving vision from the loaded processor's own shape (does it carry an image_processor, the standard ProcessorMixin composition every VLM processor uses regardless of which AutoModel class loaded it). - The chat-completions route only caught ValueError from a backend failure; any other exception (an AttributeError/TypeError from a custom model whose calling convention diverges from the standard apply_chat_template(images=...) contract this shim assumes generically) reached the caller as an unhandled 500 with no actionable message. Now every backend exception comes back OpenAI-shaped, with the real error text. Added a case study to docs/model-onboarding.md documenting why OvisOCR2 needs the transformers_trust_remote_code path rather than a GGUF or a new family: Qwen3.5's hybrid Gated DeltaNet architecture has llama.cpp text-only support as of a few weeks ago (with an open GPU correctness bug), and Ovis's actual vision stack has no llama.cpp implementation at all — so every community GGUF quantization of this repo can only be the text backbone, never a working OCR model. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(docs): correct the OvisOCR2 architecture case study The previous version assumed, from the product name alone, that ATH-MaaS/OvisOCR2 shared AIDC-AI's unrelated 'Ovis' architecture (custom AIMv2 vision tower, needing trust_remote_code). The repo's actual config.json (fetched directly) shows architectures: ['Qwen3_5ForConditionalGeneration'], model_type 'qwen3_5', a native vision_config, and no auto_map -- this is ATH-MaaS's own fine-tune of Qwen's native Qwen3.5-VL, not AIDC-AI's Ovis. Corrected conclusion: no trust_remote_code needed; the real gate is transformers version currency -- Qwen3_5ForConditionalGeneration (confirmed as a real, ~2000-line, standard-registration implementation) lives only on transformers' unreleased main branch as of this writing. The llama.cpp vision gap conclusion is unchanged and now more precisely sourced: ggml-org/llama.cpp#19917 ("Qwen3.5 image input is not supported") is a direct match for this exact vision_config, not an inference about an unrelated architecture. The two code fixes in the previous commit (processor-shape vision detection, honest backend error surfacing) are unaffected -- they are general fixes, not specific to which architecture family this model turned out to be. * fix(docs): OvisOCR2 is a rung-1 model, not rung-3 -- llama.cpp vision support already landed The previous version wrongly concluded llama.cpp had no vision support for Qwen3.5 at all, citing a reverted early PR (#19435) and misreading issue #19917 as an open capability gap. Verified directly against the primary sources this time: - ggml-org/llama.cpp#19468 (merged 2026-02-10) explicitly includes and tests Qwen3.5 vision support. - Issue #19917 is closed -- it reports the standard 'missing --mmproj' hint text, a usage error, not a missing feature. - bartowski/ATH-MaaS_OvisOCR2-GGUF ships a matching mmproj for this exact 0.8B checkpoint. Its GGUF general.architecture is 'qwen35', already in ARCH_TO_FAMILY -- the existing mmproj-upgrade path already promotes it to a vision family with zero new detection code. - The mmproj-upgrade default (lfm2_vl) forces JSON-schema output, wrong for this model's free-text Markdown OCR; vision_ocr is the right family pick -- an operator choice at deploy, not a new family. - The one real llama.cpp correctness bug in this arch's history (#19683) is closed, CUDA-only, and MoE-only -- irrelevant to CPU dense-model serving. Added RUNTIME_NOTES['qwen35'] (cites #19468, warns the mmproj must come from the same checkpoint size -- projector output dimension differs across Qwen3.5 variants) plus a test covering both the plain text and mmproj-upgraded vision verdicts. The two transformers-runtime fixes from the previous commit are unaffected -- they were found while chasing the (ultimately wrong) trust_remote_code theory, but are real, general fixes independent of which family this specific model turned out to need. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This PR adds model support for the upcoming Qwen3.5 models, including both dense and MoE variants. It has been verified with preview checkpoints from the Qwen Team in both vision and pure text modes (with or without mmproj file).
As mentioned here, this PR was planned to be a follow-up PR after #19435 or #19456 by @pwilkin. However, it seems there is still a lot to do without the real checkpoints (such as vision support, vocab, weight mapping, and forward logic), so I'm sharing my implementation here for reference. 🫡
Some differences compared to #19435 or #19456:
@pwilkin Sorry for the work overlap, and I really appreciate your work on Qwen3Next! It has been a huge stepping stone for this PR.
Reference HF implementation: huggingface/transformers#43830