123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- package ggml
- import (
- "maps"
- "slices"
- "strings"
- "testing"
- "github.com/google/go-cmp/cmp"
- )
- type ggufModel struct {
- kv KV
- tensors Tensors
- }
- func (m *ggufModel) KV() KV { return m.kv }
- func (m *ggufModel) Tensors() Tensors { return m.tensors }
- func TestGraphNoVocab(t *testing.T) {
- g := &GGML{
- container: &containerGGUF{},
- model: &ggufModel{
- kv: KV{
- "general.architecture": "llama",
- "block_count": uint32(1),
- },
- tensors: Tensors{
- items: []*Tensor{},
- },
- },
- }
- // This should not panic
- _, _, _ = g.GraphSize(1, 1, "f16")
- }
- func TestTensorLayers(t *testing.T) {
- tensors := make(map[string]*Tensor)
- for _, name := range []string{
- "token_embd.weight",
- "blk.0.attn_k.weight",
- "blk.0.attn_output.weight",
- "blk.0.attn_q.weight",
- "blk.0.attn_v.weight",
- "blk.0.attn_norm.weight",
- "blk.0.ffn_down.weight",
- "blk.0.ffn_gate.weight",
- "blk.0.ffn_up.weight",
- "blk.0.ffn_norm.weight",
- "output_norm.weight",
- "mm.0.bias",
- "mm.0.weight",
- "v.blk.0.attn_k.weight",
- "v.blk.0.attn_output.weight",
- "v.blk.0.attn_q.weight",
- "v.blk.0.attn_v.weight",
- "v.blk.0.attn_norm.weight",
- "v.blk.0.ffn_down.weight",
- "v.blk.0.ffn_gate.weight",
- "v.blk.0.ffn_up.weight",
- "v.blk.0.ffn_norm.weight",
- "v.patch_embd.weight",
- "v.position_embd.gate",
- "v.position_embd.weight",
- } {
- tensors[name] = &Tensor{Name: name}
- }
- cases := []struct {
- name string
- items []*Tensor
- want map[string]Layer
- }{
- {
- name: "text",
- items: slices.Collect(func(yield func(*Tensor) bool) {
- for k, v := range tensors {
- if !strings.HasPrefix(k, "mm.") && !strings.HasPrefix(k, "v.") {
- if !yield(v) {
- return
- }
- }
- }
- }),
- want: map[string]Layer{
- "blk.0": {
- "attn_k.weight": tensors["blk.0.attn_k.weight"],
- "attn_q.weight": tensors["blk.0.attn_q.weight"],
- "attn_v.weight": tensors["blk.0.attn_v.weight"],
- "attn_output.weight": tensors["blk.0.attn_output.weight"],
- "attn_norm.weight": tensors["blk.0.attn_norm.weight"],
- "ffn_down.weight": tensors["blk.0.ffn_down.weight"],
- "ffn_gate.weight": tensors["blk.0.ffn_gate.weight"],
- "ffn_up.weight": tensors["blk.0.ffn_up.weight"],
- "ffn_norm.weight": tensors["blk.0.ffn_norm.weight"],
- },
- "token_embd": {"weight": tensors["token_embd.weight"]},
- "output_norm": {"weight": tensors["output_norm.weight"]},
- },
- },
- {
- name: "vision",
- items: slices.Collect(func(yield func(*Tensor) bool) {
- for k, v := range tensors {
- if strings.HasPrefix(k, "mm.") || strings.HasPrefix(k, "v.") {
- if !yield(v) {
- return
- }
- }
- }
- }),
- want: map[string]Layer{
- "mm.0": {
- "bias": tensors["mm.0.bias"],
- "weight": tensors["mm.0.weight"],
- },
- "v.blk.0": {
- "attn_k.weight": tensors["v.blk.0.attn_k.weight"],
- "attn_q.weight": tensors["v.blk.0.attn_q.weight"],
- "attn_v.weight": tensors["v.blk.0.attn_v.weight"],
- "attn_output.weight": tensors["v.blk.0.attn_output.weight"],
- "attn_norm.weight": tensors["v.blk.0.attn_norm.weight"],
- "ffn_down.weight": tensors["v.blk.0.ffn_down.weight"],
- "ffn_gate.weight": tensors["v.blk.0.ffn_gate.weight"],
- "ffn_up.weight": tensors["v.blk.0.ffn_up.weight"],
- "ffn_norm.weight": tensors["v.blk.0.ffn_norm.weight"],
- },
- "v": {
- "patch_embd.weight": tensors["v.patch_embd.weight"],
- "position_embd.gate": tensors["v.position_embd.gate"],
- "position_embd.weight": tensors["v.position_embd.weight"],
- },
- },
- },
- {
- name: "vision and text",
- items: slices.Collect(maps.Values(tensors)),
- want: map[string]Layer{
- "blk.0": {
- "attn_k.weight": tensors["blk.0.attn_k.weight"],
- "attn_q.weight": tensors["blk.0.attn_q.weight"],
- "attn_v.weight": tensors["blk.0.attn_v.weight"],
- "attn_output.weight": tensors["blk.0.attn_output.weight"],
- "attn_norm.weight": tensors["blk.0.attn_norm.weight"],
- "ffn_down.weight": tensors["blk.0.ffn_down.weight"],
- "ffn_gate.weight": tensors["blk.0.ffn_gate.weight"],
- "ffn_up.weight": tensors["blk.0.ffn_up.weight"],
- "ffn_norm.weight": tensors["blk.0.ffn_norm.weight"],
- },
- "token_embd": {"weight": tensors["token_embd.weight"]},
- "output_norm": {"weight": tensors["output_norm.weight"]},
- "mm.0": {
- "bias": tensors["mm.0.bias"],
- "weight": tensors["mm.0.weight"],
- },
- "v.blk.0": {
- "attn_k.weight": tensors["v.blk.0.attn_k.weight"],
- "attn_q.weight": tensors["v.blk.0.attn_q.weight"],
- "attn_v.weight": tensors["v.blk.0.attn_v.weight"],
- "attn_output.weight": tensors["v.blk.0.attn_output.weight"],
- "attn_norm.weight": tensors["v.blk.0.attn_norm.weight"],
- "ffn_down.weight": tensors["v.blk.0.ffn_down.weight"],
- "ffn_gate.weight": tensors["v.blk.0.ffn_gate.weight"],
- "ffn_up.weight": tensors["v.blk.0.ffn_up.weight"],
- "ffn_norm.weight": tensors["v.blk.0.ffn_norm.weight"],
- },
- "v": {
- "patch_embd.weight": tensors["v.patch_embd.weight"],
- "position_embd.gate": tensors["v.position_embd.gate"],
- "position_embd.weight": tensors["v.position_embd.weight"],
- },
- },
- },
- }
- for _, tt := range cases {
- t.Run(tt.name, func(t *testing.T) {
- got := Tensors{items: tt.items}.GroupLayers()
- if diff := cmp.Diff(got, tt.want); diff != "" {
- t.Errorf("unexpected layers (-got +want):\n%s", diff)
- }
- })
- }
- }
|