Ctrl K
ComunidadGuías…

internal/autogen/kvdefault_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package autogen

import "testing"

// A plain-attention model with room to spare keeps f16; the same model on a card
// that can't buy denseMinCtx at f16 steps down to q8_0.
func TestDefaultKvQuant_StepsDownOnlyUnderPressure(t *testing.T) {
	// 32 layers x 8 kv heads x 128 k/v dims => ~0.5 MB/token at f16.
	meta := Metadata{
		BlockCount: 32, HeadCountKv: 8, KeyLength: 128, ValueLength: 128,
		ContextLength: 131072, FileSizeGB: 8,
	}
	s := Settings{DenseMinCtx: 32768}

	f16 := GetKvCostModel(meta, "f16", "f16")
	roomy := 8 + 1 + f16.SlopeGB*32768 + 0.5 // weights + overhead + 32k of f16 KV
	if got := defaultKvQuant(s, meta, roomy, 1.0); got != "f16" {
		t.Errorf("roomy budget: got %q, want f16", got)
	}
	// Half the KV budget: f16 can't reach 32k, q8_0 (~0.53x) can.
	tight := 8 + 1 + f16.SlopeGB*16384
	if got := defaultKvQuant(s, meta, tight, 1.0); got != "q8_0" {
		t.Errorf("tight budget: got %q, want q8_0", got)
	}
}

// settings.kvQuant pins the type outright; an unknown value falls back to auto.
func TestDefaultKvQuant_SettingPin(t *testing.T) {
	meta := Metadata{BlockCount: 32, HeadCountKv: 8, KeyLength: 128, ValueLength: 128, FileSizeGB: 8}
	if got := defaultKvQuant(Settings{KvQuant: "q5_1", DenseMinCtx: 32768}, meta, 100, 1.0); got != "q5_1" {
		t.Errorf("pinned: got %q, want q5_1", got)
	}
	// Never emit a type llama would reject, even if a config asks for it.
	if got := defaultKvQuant(Settings{KvQuant: "iq4_nl", DenseMinCtx: 32768}, meta, 100, 1.0); got != "f16" {
		t.Errorf("iq4_nl pin: got %q, want the auto pick f16", got)
	}
}

// A one-sided pin mirrors rather than collapsing to the default. Dropping it
// used to size the fleet default f16 for a model pinned to q8_0, which on a
// tight budget costs a whole layer of offload in the editor's estimate.
func TestResolveKvPair(t *testing.T) {
	cases := []struct {
		name         string
		k, v         string
		wantK, wantV string
	}{
		{"both blank => default", "", "", "f16", "f16"},
		{"both set", "q8_0", "q8_0", "q8_0", "q8_0"},
		{"K only mirrors to V", "q8_0", "", "q8_0", "q8_0"},
		{"V only mirrors to K", "", "q8_0", "q8_0", "q8_0"},
		{"genuine mismatch => default", "q8_0", "q5_0", "f16", "f16"},
		{"unsupported type => default", "iq4_nl", "", "f16", "f16"},
	}
	for _, c := range cases {
		gotK, gotV := resolveKvPair(c.k, c.v, "f16", "f16")
		if gotK != c.wantK || gotV != c.wantV {
			t.Errorf("%s: resolveKvPair(%q,%q) = %q,%q; want %q,%q",
				c.name, c.k, c.v, gotK, gotV, c.wantK, c.wantV)
		}
	}
}

func TestValidKvPair(t *testing.T) {
	for _, q := range []string{"f32", "f16", "bf16", "q8_0", "q5_1", "q5_0", "q4_1", "q4_0"} {
		if !ValidKvPair(q, q) {
			t.Errorf("%s/%s should be valid", q, q)
		}
	}
	// Mismatched K/V breaks flash-attention; iq4_nl has no FA kernel at all.
	if ValidKvPair("q8_0", "f16") {
		t.Error("mismatched K/V should be rejected")
	}
	if ValidKvPair("iq4_nl", "iq4_nl") {
		t.Error("iq4_nl should be rejected")
	}
	if ValidKvPair("q3_k", "q3_k") {
		t.Error("unknown quant should be rejected")
	}
}