Commit 18b74fa41 for llama.cpp

commit 18b74fa41dcac1f55ae1371fe58153f7225941f6
Author: Seungjun Bae <linkedlatch@gmail.com>
Date:   Mon Nov 16 03:45:17 2026 +0900

    model : read qwen3vl output head size from the tensor (#32349)

    Allows Qwen3-ForcedAligner, whose output head (5000 timestamp classes) is smaller than the vocab.

diff --git a/src/models/qwen3vl.cpp b/src/models/qwen3vl.cpp
index 480e570dc..ed9fe6507 100644
--- a/src/models/qwen3vl.cpp
+++ b/src/models/qwen3vl.cpp
@@ -13,14 +13,20 @@ void llama_model_qwen3vl::load_arch_hparams(llama_model_loader & ml) {
     }
 }

-void llama_model_qwen3vl::load_arch_tensors(llama_model_loader &) {
+void llama_model_qwen3vl::load_arch_tensors(llama_model_loader & ml) {
     LLAMA_LOAD_LOCALS;

+    // the output head can be smaller than the vocab (Qwen3-TTS codec head, Qwen3-ForcedAligner timestamp head)
     int64_t n_vocab_out = n_vocab;
-    if (arch == LLM_ARCH_QWEN3TTS) {
+    if (const ggml_tensor * meta = ml.get_tensor_meta(tn(LLM_TENSOR_OUTPUT, "weight").str().c_str())) {
+        n_vocab_out = meta->ne[1];
+    } else if (arch == LLM_ARCH_QWEN3TTS) {
         // [TAG_LLAMA_N_VOCAB_OUT]
         n_vocab_out = 3072;
     }
+    if (n_vocab_out < 1 || n_vocab_out > n_vocab) {
+        throw std::runtime_error(format("tensor 'output.weight' has invalid head size %lld (vocab size %lld)", (long long) n_vocab_out, (long long) n_vocab));
+    }

     tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);

@@ -164,7 +170,7 @@ llama_model_qwen3vl::graph::graph(const llm_graph_params & params) : llm_graph_c
     int64_t n_vocab_in  = model.tok_embd->ne[1];
     int64_t n_vocab_out = model.output->ne[1];
     if (n_vocab_in > n_vocab_out) {
-        // case: Qwen3TTS model with codec_head as output
+        // case: output head smaller than vocab, see load_arch_tensors
         GGML_ASSERT(model.output_norm);
         int64_t pad = n_vocab_in - n_vocab_out;