internal/autogen/mmproj_test.go
Rama main · réplica de lectura del repositorio original.
package autogen
import (
"math"
"testing"
)
// Only dedicated VL models cap their vision twin ctx; a plain LLM-with-mmproj
// keeps full context. Detection is by name or gguf arch.
func TestIsVLModel(t *testing.T) {
cases := []struct {
name, arch string
want bool
}{
{"qwen3-vl-30b", "qwen3vlmoe", true},
{"qwen2-vl-7b", "qwen2vl", true},
{"internvl-8b", "qwen2", true}, // VL by name
{"some-model", "cogvlm", true}, // VL by arch
{"gemma-3-12b", "gemma3", false}, // LLM-with-vision
{"mistral-small", "llama", false},
{"llama-3.2-11b-vision", "mllama", false}, // vision LLM, not a "-vl" family
}
for _, c := range cases {
if got := isVLModel(c.name, c.arch); got != c.want {
t.Errorf("isVLModel(%q,%q)=%v want %v", c.name, c.arch, got, c.want)
}
}
}
// A "-vision" twin's projector footprint (weights + VisionOverheadGB CLIP
// reserve) must reach EstVramGB via EstimateInput.MmprojGB — this is the charge
// the spawn-time guard (LiveOffloadArgs) feeds in so it sizes the twin like the
// baked plan, instead of sizing a projector-blind bare LLM and under-offloading.
func TestEstimatePlan_MmprojChargedToVram(t *testing.T) {
// Small dense model with a big VRAM target -> fully GPU-resident, fixed ctx,
// so any EstVram delta is exactly the overhead delta (placement unchanged).
meta := Metadata{Architecture: "llama", BlockCount: 32, HeadCountKv: 8,
KeyLength: 128, ValueLength: 128, FileSizeGB: 4, ContextLength: 8192}
s := Settings{TargetVramGB: 40, VramOverheadGB: 1, ComputeBufFactor: 1, VisionOverheadGB: 1}
base := EstimateInput{Ctx: 4096}
r0, err := EstimatePlan(s, meta, base)
if err != nil {
t.Fatal(err)
}
withProj := base
withProj.MmprojGB = MmprojVramGB("", 0.7, s) // 0.7 GB projector + 1.0 reserve = 1.7 (no path -> flat fallback)
r1, err := EstimatePlan(s, meta, withProj)
if err != nil {
t.Fatal(err)
}
if r1.Ngl != r0.Ngl {
t.Fatalf("placement changed (ngl %d->%d); test assumption broken", r0.Ngl, r1.Ngl)
}
delta := r1.EstVramGB - r0.EstVramGB
if math.Abs(delta-1.7) > 1e-6 {
t.Fatalf("EstVram delta=%.4f want 1.7 (projector 0.7 + reserve 1.0)", delta)
}
// With no mmproj path the helper falls back to the flat VisionOverheadGB pad:
// fileSize + whatever VisionOverheadGB holds (per-projector modeling needs the file).
if g := MmprojVramGB("", 0.7, Settings{VisionOverheadGB: 1.5}); math.Abs(g-2.2) > 1e-9 {
t.Fatalf("MmprojVramGB=%.4f want 2.2", g)
}
}