llama: default qwen2.5vl window attention metadata (#16868)
Existing qwen2.5vl GGUFs can contain an empty qwen25vl.vision.fullatt_block_indexes array. The compat layer translated the projector metadata but left clip.vision.n_wa_pattern unset, causing llama-server to fail loading the CLIP model. Default the runtime compat value to the standard Qwen2.5-VL pattern when the key cannot be derived, and make the converter emit the same default for nil or empty fullatt block metadata. Fixes #16540
This commit is contained in:
@@ -39,10 +39,6 @@ func (q *qwen25VLModel) KV(t *Tokenizer) KV {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if q.VisionModel.FullAttentionBlocks == nil {
|
|
||||||
kv["qwen25vl.vision.fullatt_block_indexes"] = []int32{7, 15, 23, 31}
|
|
||||||
}
|
|
||||||
|
|
||||||
kv["qwen25vl.vision.block_count"] = cmp.Or(q.VisionModel.Depth, 32)
|
kv["qwen25vl.vision.block_count"] = cmp.Or(q.VisionModel.Depth, 32)
|
||||||
kv["qwen25vl.vision.embedding_length"] = q.VisionModel.HiddenSize
|
kv["qwen25vl.vision.embedding_length"] = q.VisionModel.HiddenSize
|
||||||
kv["qwen25vl.vision.attention.head_count"] = cmp.Or(q.VisionModel.NumHeads, 16)
|
kv["qwen25vl.vision.attention.head_count"] = cmp.Or(q.VisionModel.NumHeads, 16)
|
||||||
@@ -53,12 +49,19 @@ func (q *qwen25VLModel) KV(t *Tokenizer) KV {
|
|||||||
kv["qwen25vl.vision.window_size"] = cmp.Or(q.VisionModel.WindowSize, 112)
|
kv["qwen25vl.vision.window_size"] = cmp.Or(q.VisionModel.WindowSize, 112)
|
||||||
kv["qwen25vl.vision.attention.layer_norm_epsilon"] = cmp.Or(q.VisionModel.RMSNormEps, 1e-6)
|
kv["qwen25vl.vision.attention.layer_norm_epsilon"] = cmp.Or(q.VisionModel.RMSNormEps, 1e-6)
|
||||||
kv["qwen25vl.vision.rope.freq_base"] = cmp.Or(q.VisionModel.RopeTheta, 1e4)
|
kv["qwen25vl.vision.rope.freq_base"] = cmp.Or(q.VisionModel.RopeTheta, 1e4)
|
||||||
kv["qwen25vl.vision.fullatt_block_indexes"] = q.VisionModel.FullAttentionBlocks
|
kv["qwen25vl.vision.fullatt_block_indexes"] = q.fullAttentionBlocks()
|
||||||
kv["qwen25vl.vision.temporal_patch_size"] = cmp.Or(q.VisionModel.TemporalPatchSize, 2)
|
kv["qwen25vl.vision.temporal_patch_size"] = cmp.Or(q.VisionModel.TemporalPatchSize, 2)
|
||||||
|
|
||||||
return kv
|
return kv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *qwen25VLModel) fullAttentionBlocks() []int32 {
|
||||||
|
if len(q.VisionModel.FullAttentionBlocks) > 0 {
|
||||||
|
return q.VisionModel.FullAttentionBlocks
|
||||||
|
}
|
||||||
|
return []int32{7, 15, 23, 31}
|
||||||
|
}
|
||||||
|
|
||||||
func (q *qwen25VLModel) Tensors(ts []Tensor) []*ggml.Tensor {
|
func (q *qwen25VLModel) Tensors(ts []Tensor) []*ggml.Tensor {
|
||||||
var out []*ggml.Tensor
|
var out []*ggml.Tensor
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestQwen25VLFullAttentionBlockDefaults(t *testing.T) {
|
||||||
|
tokenizer := &Tokenizer{Vocabulary: &Vocabulary{}}
|
||||||
|
|
||||||
|
for _, tt := range []struct {
|
||||||
|
name string
|
||||||
|
blocks []int32
|
||||||
|
want []int32
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "nil",
|
||||||
|
want: []int32{7, 15, 23, 31},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
blocks: []int32{},
|
||||||
|
want: []int32{7, 15, 23, 31},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom",
|
||||||
|
blocks: []int32{5, 17},
|
||||||
|
want: []int32{5, 17},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
model := &qwen25VLModel{}
|
||||||
|
model.VisionModel.FullAttentionBlocks = tt.blocks
|
||||||
|
|
||||||
|
got, ok := model.KV(tokenizer)["qwen25vl.vision.fullatt_block_indexes"].([]int32)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("fullatt_block_indexes has unexpected type %T", got)
|
||||||
|
}
|
||||||
|
if !slices.Equal(got, tt.want) {
|
||||||
|
t.Fatalf("fullatt_block_indexes = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+1
@@ -2958,6 +2958,7 @@ void handle_qwen25vl_clip(gguf_context * meta, ggml_context * ctx) {
|
|||||||
gguf_set_val_u32(meta, "clip.vision.n_wa_pattern", (uint32_t)(arr[0] + 1));
|
gguf_set_val_u32(meta, "clip.vision.n_wa_pattern", (uint32_t)(arr[0] + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
inject_u32_if_missing(meta, "clip.vision.n_wa_pattern", 8);
|
||||||
|
|
||||||
// Default image_size = 560 (Qwen2VLVisionModel default, no image_size in HF config).
|
// Default image_size = 560 (Qwen2VLVisionModel default, no image_size in HF config).
|
||||||
inject_u32_if_missing(meta, "clip.vision.image_size", 560);
|
inject_u32_if_missing(meta, "clip.vision.image_size", 560);
|
||||||
|
|||||||
Reference in New Issue
Block a user