gguf.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. package llm
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "slices"
  9. "sort"
  10. "strings"
  11. "golang.org/x/exp/maps"
  12. )
  13. type containerGGUF struct {
  14. ByteOrder binary.ByteOrder
  15. Version uint32
  16. V1 struct {
  17. NumTensor uint32
  18. NumKV uint32
  19. }
  20. V2 struct {
  21. NumTensor uint64
  22. NumKV uint64
  23. }
  24. V3 struct {
  25. NumTensor uint64
  26. NumKV uint64
  27. }
  28. maxArraySize int
  29. }
  30. func (c *containerGGUF) canCollectArray(size int) bool {
  31. return c.maxArraySize < 0 || size <= c.maxArraySize
  32. }
  33. func (c *containerGGUF) Name() string {
  34. return "gguf"
  35. }
  36. func (c *containerGGUF) Decode(rs io.ReadSeeker) (model, error) {
  37. if err := binary.Read(rs, c.ByteOrder, &c.Version); err != nil {
  38. return nil, err
  39. }
  40. var err error
  41. switch c.Version {
  42. case 1:
  43. err = binary.Read(rs, c.ByteOrder, &c.V1)
  44. case 2:
  45. err = binary.Read(rs, c.ByteOrder, &c.V2)
  46. default:
  47. err = binary.Read(rs, c.ByteOrder, &c.V3)
  48. }
  49. if err != nil {
  50. return nil, err
  51. }
  52. model := newGGUF(c)
  53. if err := model.Decode(rs); err != nil {
  54. return nil, err
  55. }
  56. return model, nil
  57. }
  58. const (
  59. ggufTypeUint8 uint32 = iota
  60. ggufTypeInt8
  61. ggufTypeUint16
  62. ggufTypeInt16
  63. ggufTypeUint32
  64. ggufTypeInt32
  65. ggufTypeFloat32
  66. ggufTypeBool
  67. ggufTypeString
  68. ggufTypeArray
  69. ggufTypeUint64
  70. ggufTypeInt64
  71. ggufTypeFloat64
  72. )
  73. type gguf struct {
  74. *containerGGUF
  75. kv KV
  76. tensors []*Tensor
  77. parameters uint64
  78. scratch [16 << 10]byte
  79. }
  80. func newGGUF(container *containerGGUF) *gguf {
  81. return &gguf{
  82. containerGGUF: container,
  83. kv: make(KV),
  84. }
  85. }
  86. func NewGGUFV3(bo binary.ByteOrder) *gguf {
  87. return newGGUF(&containerGGUF{ByteOrder: bo, Version: 3})
  88. }
  89. func (llm *gguf) KV() KV {
  90. return llm.kv
  91. }
  92. func (llm *gguf) Tensors() Tensors {
  93. return llm.tensors
  94. }
  95. func (llm *gguf) numTensor() uint64 {
  96. switch llm.Version {
  97. case 1:
  98. return uint64(llm.V1.NumTensor)
  99. case 2:
  100. return llm.V2.NumTensor
  101. default:
  102. return llm.V3.NumTensor
  103. }
  104. }
  105. func (llm *gguf) numKV() uint64 {
  106. switch llm.Version {
  107. case 1:
  108. return uint64(llm.V1.NumKV)
  109. case 2:
  110. return llm.V2.NumKV
  111. default:
  112. return llm.V3.NumKV
  113. }
  114. }
  115. func (llm *gguf) Decode(rs io.ReadSeeker) error {
  116. // decode key-values
  117. for i := 0; uint64(i) < llm.numKV(); i++ {
  118. k, err := readGGUFString(llm, rs)
  119. if err != nil {
  120. return err
  121. }
  122. t, err := readGGUF[uint32](llm, rs)
  123. if err != nil {
  124. return err
  125. }
  126. var v any
  127. switch t {
  128. case ggufTypeUint8:
  129. v, err = readGGUF[uint8](llm, rs)
  130. case ggufTypeInt8:
  131. v, err = readGGUF[int8](llm, rs)
  132. case ggufTypeUint16:
  133. v, err = readGGUF[uint16](llm, rs)
  134. case ggufTypeInt16:
  135. v, err = readGGUF[int16](llm, rs)
  136. case ggufTypeUint32:
  137. v, err = readGGUF[uint32](llm, rs)
  138. case ggufTypeInt32:
  139. v, err = readGGUF[int32](llm, rs)
  140. case ggufTypeUint64:
  141. v, err = readGGUF[uint64](llm, rs)
  142. case ggufTypeInt64:
  143. v, err = readGGUF[int64](llm, rs)
  144. case ggufTypeFloat32:
  145. v, err = readGGUF[float32](llm, rs)
  146. case ggufTypeFloat64:
  147. v, err = readGGUF[float64](llm, rs)
  148. case ggufTypeBool:
  149. v, err = readGGUF[bool](llm, rs)
  150. case ggufTypeString:
  151. v, err = readGGUFString(llm, rs)
  152. case ggufTypeArray:
  153. v, err = readGGUFArray(llm, rs)
  154. default:
  155. return fmt.Errorf("invalid type: %d", t)
  156. }
  157. if err != nil {
  158. return err
  159. }
  160. llm.kv[k] = v
  161. }
  162. // decode tensors
  163. for range llm.numTensor() {
  164. name, err := readGGUFString(llm, rs)
  165. if err != nil {
  166. return fmt.Errorf("failed to read tensor name: %w", err)
  167. }
  168. // dims is the number of dimensions in the tensor
  169. dims, err := readGGUF[uint32](llm, rs)
  170. if err != nil {
  171. return fmt.Errorf("failed to read tensor dimensions: %w", err)
  172. }
  173. shape := [4]uint64{1, 1, 1, 1}
  174. for i := 0; uint32(i) < dims; i++ {
  175. shape[i], err = readGGUF[uint64](llm, rs)
  176. if err != nil {
  177. return fmt.Errorf("failed to read tensor shape: %w", err)
  178. }
  179. }
  180. kind, err := readGGUF[uint32](llm, rs)
  181. if err != nil {
  182. return fmt.Errorf("failed to read tensor kind: %w", err)
  183. }
  184. offset, err := readGGUF[uint64](llm, rs)
  185. if err != nil {
  186. return fmt.Errorf("failed to read tensor offset: %w", err)
  187. }
  188. tensor := Tensor{
  189. Name: name,
  190. Kind: kind,
  191. Offset: offset,
  192. Shape: shape[:],
  193. }
  194. llm.tensors = append(llm.tensors, &tensor)
  195. llm.parameters += tensor.parameters()
  196. }
  197. // patch KV with parameter count
  198. llm.kv["general.parameter_count"] = llm.parameters
  199. alignment, ok := llm.kv["general.alignment"].(uint32)
  200. if !ok {
  201. alignment = 32
  202. }
  203. for _, tensor := range llm.tensors {
  204. offset, err := rs.Seek(0, io.SeekCurrent)
  205. if err != nil {
  206. return fmt.Errorf("failed to get current offset: %w", err)
  207. }
  208. padding := llm.padding(offset, int64(alignment))
  209. if _, err := rs.Seek(padding, io.SeekCurrent); err != nil {
  210. return fmt.Errorf("failed to seek to init padding: %w", err)
  211. }
  212. if _, err := rs.Seek(int64(tensor.Size()), io.SeekCurrent); err != nil {
  213. return fmt.Errorf("failed to seek to tensor: %w", err)
  214. }
  215. }
  216. return nil
  217. }
  218. func readGGUF[T any](llm *gguf, r io.Reader) (T, error) {
  219. var t T
  220. err := binary.Read(r, llm.ByteOrder, &t)
  221. return t, err
  222. }
  223. func writeGGUF[V any](llm *gguf, w io.Writer, t uint32, v V) error {
  224. if err := binary.Write(w, llm.ByteOrder, t); err != nil {
  225. return err
  226. }
  227. return binary.Write(w, llm.ByteOrder, v)
  228. }
  229. func readGGUFV1String(llm *gguf, r io.Reader) (string, error) {
  230. var length uint64
  231. if err := binary.Read(r, llm.ByteOrder, &length); err != nil {
  232. return "", err
  233. }
  234. var b bytes.Buffer
  235. if _, err := io.CopyN(&b, r, int64(length)); err != nil {
  236. return "", err
  237. }
  238. // gguf v1 strings are null-terminated
  239. b.Truncate(b.Len() - 1)
  240. return b.String(), nil
  241. }
  242. func discardGGUFString(llm *gguf, r io.Reader) error {
  243. buf := llm.scratch[:8]
  244. _, err := io.ReadFull(r, buf)
  245. if err != nil {
  246. return err
  247. }
  248. size := int(llm.ByteOrder.Uint64(buf))
  249. for size > 0 {
  250. n, err := r.Read(llm.scratch[:min(size, cap(llm.scratch))])
  251. if err != nil {
  252. return err
  253. }
  254. size -= n
  255. }
  256. return nil
  257. }
  258. func readGGUFString(llm *gguf, r io.Reader) (string, error) {
  259. if llm.Version == 1 {
  260. return readGGUFV1String(llm, r)
  261. }
  262. buf := llm.scratch[:8]
  263. _, err := io.ReadFull(r, buf)
  264. if err != nil {
  265. return "", err
  266. }
  267. length := int(llm.ByteOrder.Uint64(buf))
  268. if length > len(llm.scratch) {
  269. buf = make([]byte, length)
  270. } else {
  271. buf = llm.scratch[:length]
  272. }
  273. clear(buf)
  274. _, err = io.ReadFull(r, buf)
  275. if err != nil {
  276. return "", err
  277. }
  278. return string(buf), nil
  279. }
  280. func writeGGUFString(llm *gguf, w io.Writer, s string) error {
  281. if err := binary.Write(w, llm.ByteOrder, ggufTypeString); err != nil {
  282. return err
  283. }
  284. if err := binary.Write(w, llm.ByteOrder, uint64(len(s))); err != nil {
  285. return err
  286. }
  287. _, err := io.Copy(w, strings.NewReader(s))
  288. return err
  289. }
  290. type array struct {
  291. size int
  292. values []any
  293. }
  294. func (a *array) MarshalJSON() ([]byte, error) {
  295. return json.Marshal(a.values)
  296. }
  297. func readGGUFV1Array(llm *gguf, r io.Reader) (*array, error) {
  298. t, err := readGGUF[uint32](llm, r)
  299. if err != nil {
  300. return nil, err
  301. }
  302. n, err := readGGUF[uint32](llm, r)
  303. if err != nil {
  304. return nil, err
  305. }
  306. a := &array{size: int(n)}
  307. if llm.canCollectArray(int(n)) {
  308. a.values = make([]any, 0, int(n))
  309. }
  310. for i := range n {
  311. var e any
  312. switch t {
  313. case ggufTypeUint8:
  314. e, err = readGGUF[uint8](llm, r)
  315. case ggufTypeInt8:
  316. e, err = readGGUF[int8](llm, r)
  317. case ggufTypeUint16:
  318. e, err = readGGUF[uint16](llm, r)
  319. case ggufTypeInt16:
  320. e, err = readGGUF[int16](llm, r)
  321. case ggufTypeUint32:
  322. e, err = readGGUF[uint32](llm, r)
  323. case ggufTypeInt32:
  324. e, err = readGGUF[int32](llm, r)
  325. case ggufTypeUint64:
  326. e, err = readGGUF[uint64](llm, r)
  327. case ggufTypeInt64:
  328. e, err = readGGUF[int64](llm, r)
  329. case ggufTypeFloat32:
  330. e, err = readGGUF[float32](llm, r)
  331. case ggufTypeFloat64:
  332. e, err = readGGUF[float64](llm, r)
  333. case ggufTypeBool:
  334. e, err = readGGUF[bool](llm, r)
  335. case ggufTypeString:
  336. e, err = readGGUFV1String(llm, r)
  337. default:
  338. return nil, fmt.Errorf("invalid array type: %d", t)
  339. }
  340. if err != nil {
  341. return nil, err
  342. }
  343. if a.values != nil {
  344. a.values[i] = e
  345. }
  346. }
  347. return a, nil
  348. }
  349. func readGGUFArray(llm *gguf, r io.Reader) (*array, error) {
  350. if llm.Version == 1 {
  351. return readGGUFV1Array(llm, r)
  352. }
  353. t, err := readGGUF[uint32](llm, r)
  354. if err != nil {
  355. return nil, err
  356. }
  357. n, err := readGGUF[uint64](llm, r)
  358. if err != nil {
  359. return nil, err
  360. }
  361. a := &array{size: int(n)}
  362. if llm.canCollectArray(int(n)) {
  363. a.values = make([]any, int(n))
  364. }
  365. for i := range n {
  366. var e any
  367. switch t {
  368. case ggufTypeUint8:
  369. e, err = readGGUF[uint8](llm, r)
  370. case ggufTypeInt8:
  371. e, err = readGGUF[int8](llm, r)
  372. case ggufTypeUint16:
  373. e, err = readGGUF[uint16](llm, r)
  374. case ggufTypeInt16:
  375. e, err = readGGUF[int16](llm, r)
  376. case ggufTypeUint32:
  377. e, err = readGGUF[uint32](llm, r)
  378. case ggufTypeInt32:
  379. e, err = readGGUF[int32](llm, r)
  380. case ggufTypeUint64:
  381. e, err = readGGUF[uint64](llm, r)
  382. case ggufTypeInt64:
  383. e, err = readGGUF[int64](llm, r)
  384. case ggufTypeFloat32:
  385. e, err = readGGUF[float32](llm, r)
  386. case ggufTypeFloat64:
  387. e, err = readGGUF[float64](llm, r)
  388. case ggufTypeBool:
  389. e, err = readGGUF[bool](llm, r)
  390. case ggufTypeString:
  391. if a.values != nil {
  392. e, err = readGGUFString(llm, r)
  393. } else {
  394. err = discardGGUFString(llm, r)
  395. }
  396. default:
  397. return nil, fmt.Errorf("invalid array type: %d", t)
  398. }
  399. if err != nil {
  400. return nil, err
  401. }
  402. if a.values != nil {
  403. a.values[i] = e
  404. }
  405. }
  406. return a, nil
  407. }
  408. func writeGGUFArray[S ~[]E, E any](llm *gguf, w io.Writer, t uint32, s S) error {
  409. if err := binary.Write(w, llm.ByteOrder, ggufTypeArray); err != nil {
  410. return err
  411. }
  412. if err := binary.Write(w, llm.ByteOrder, t); err != nil {
  413. return err
  414. }
  415. if err := binary.Write(w, llm.ByteOrder, uint64(len(s))); err != nil {
  416. return err
  417. }
  418. for _, e := range s {
  419. if err := binary.Write(w, llm.ByteOrder, e); err != nil {
  420. return err
  421. }
  422. }
  423. return nil
  424. }
  425. var ggufKVOrder = map[string][]string{
  426. "llama": {
  427. "general.architecture",
  428. "general.name",
  429. "llama.vocab_size",
  430. "llama.context_length",
  431. "llama.embedding_length",
  432. "llama.block_count",
  433. "llama.feed_forward_length",
  434. "llama.attention.head_count",
  435. "llama.attention.head_count_kv",
  436. "llama.attention.layer_norm_rms_epsilon",
  437. "llama.rope.freq_base",
  438. "llama.rope.dimension_count",
  439. "llama.expert_count",
  440. "llama.expert_used_count",
  441. "gemma.context_length",
  442. "gemma.embedding_length",
  443. "gemma.block_count",
  444. "gemma.feed_forward_length",
  445. "gemma.attention.head_count",
  446. "gemma.attention.head_count_kv",
  447. "gemma.attention.layer_norm_rms_epsilon",
  448. "gemma.attention.key_length",
  449. "gemma.attention.value_length",
  450. "general.file_type",
  451. "tokenizer.ggml.pre",
  452. "tokenizer.ggml.model",
  453. "tokenizer.ggml.tokens",
  454. "tokenizer.ggml.scores",
  455. "tokenizer.ggml.merges",
  456. "tokenizer.ggml.token_type",
  457. "tokenizer.ggml.bos_token_id",
  458. "tokenizer.ggml.eos_token_id",
  459. "tokenizer.ggml.unknown_token_id",
  460. "tokenizer.ggml.padding_token_id",
  461. "tokenizer.ggml.add_bos_token",
  462. "tokenizer.ggml.add_eos_token",
  463. "tokenizer.chat_template",
  464. },
  465. }
  466. func (llm *gguf) Encode(ws io.WriteSeeker, kv KV, tensors []Tensor) error {
  467. switch llm.Version {
  468. case 3:
  469. llm.V3.NumTensor = uint64(len(tensors))
  470. llm.V3.NumKV = uint64(len(kv))
  471. default:
  472. return fmt.Errorf("not implemented: ggufv%d", llm.Version)
  473. }
  474. if err := binary.Write(ws, llm.ByteOrder, []byte("GGUF")); err != nil {
  475. return err
  476. }
  477. if err := binary.Write(ws, llm.ByteOrder, llm.Version); err != nil {
  478. return err
  479. }
  480. if err := binary.Write(ws, llm.ByteOrder, llm.numTensor()); err != nil {
  481. return err
  482. }
  483. if err := binary.Write(ws, llm.ByteOrder, llm.numKV()); err != nil {
  484. return err
  485. }
  486. kvCheck := make(map[string]bool)
  487. for k := range kv {
  488. kvCheck[k] = false
  489. }
  490. for _, k := range ggufKVOrder["llama"] {
  491. v, ok := kv[k]
  492. if !ok {
  493. continue
  494. }
  495. kvCheck[k] = true
  496. if err := binary.Write(ws, llm.ByteOrder, uint64(len(k))); err != nil {
  497. return err
  498. }
  499. if err := binary.Write(ws, llm.ByteOrder, []byte(k)); err != nil {
  500. return err
  501. }
  502. var err error
  503. switch v := v.(type) {
  504. case uint32:
  505. err = writeGGUF(llm, ws, ggufTypeUint32, v)
  506. case float32:
  507. err = writeGGUF(llm, ws, ggufTypeFloat32, v)
  508. case bool:
  509. err = writeGGUF(llm, ws, ggufTypeBool, v)
  510. case string:
  511. err = writeGGUFString(llm, ws, v)
  512. case []int32:
  513. err = writeGGUFArray(llm, ws, ggufTypeInt32, v)
  514. case []uint32:
  515. err = writeGGUFArray(llm, ws, ggufTypeUint32, v)
  516. case []float32:
  517. err = writeGGUFArray(llm, ws, ggufTypeFloat32, v)
  518. case []string:
  519. if err := binary.Write(ws, llm.ByteOrder, ggufTypeArray); err != nil {
  520. return err
  521. }
  522. if err := binary.Write(ws, llm.ByteOrder, ggufTypeString); err != nil {
  523. return err
  524. }
  525. if err := binary.Write(ws, llm.ByteOrder, uint64(len(v))); err != nil {
  526. return err
  527. }
  528. for _, e := range v {
  529. if err := binary.Write(ws, llm.ByteOrder, uint64(len(e))); err != nil {
  530. return err
  531. }
  532. if err := binary.Write(ws, llm.ByteOrder, []byte(e)); err != nil {
  533. return err
  534. }
  535. }
  536. default:
  537. return fmt.Errorf("improper type for '%s'", k)
  538. }
  539. if err != nil {
  540. return err
  541. }
  542. }
  543. for k, v := range kvCheck {
  544. if !v {
  545. return fmt.Errorf("Didn't know how to write kv %s", k)
  546. }
  547. }
  548. for _, tensor := range tensors {
  549. if err := binary.Write(ws, llm.ByteOrder, uint64(len(tensor.Name))); err != nil {
  550. return err
  551. }
  552. if err := binary.Write(ws, llm.ByteOrder, []byte(tensor.Name)); err != nil {
  553. return err
  554. }
  555. var dims int
  556. for cnt := range len(tensor.Shape) {
  557. if tensor.Shape[cnt] > 0 {
  558. dims++
  559. }
  560. }
  561. if err := binary.Write(ws, llm.ByteOrder, uint32(dims)); err != nil {
  562. return err
  563. }
  564. for i := range dims {
  565. if err := binary.Write(ws, llm.ByteOrder, tensor.Shape[dims-1-i]); err != nil {
  566. return err
  567. }
  568. }
  569. if err := binary.Write(ws, llm.ByteOrder, tensor.Kind); err != nil {
  570. return err
  571. }
  572. if err := binary.Write(ws, llm.ByteOrder, tensor.Offset); err != nil {
  573. return err
  574. }
  575. }
  576. var alignment int64 = 32
  577. for _, tensor := range tensors {
  578. offset, err := ws.Seek(0, io.SeekCurrent)
  579. if err != nil {
  580. return err
  581. }
  582. padding := llm.padding(offset, alignment)
  583. if err := binary.Write(ws, llm.ByteOrder, bytes.Repeat([]byte{0}, int(padding))); err != nil {
  584. return err
  585. }
  586. if _, err := tensor.WriteTo(ws); err != nil {
  587. return err
  588. }
  589. }
  590. return nil
  591. }
  592. func (gguf) padding(offset, align int64) int64 {
  593. return (align - offset%align) % align
  594. }
  595. // Reader and WriterTo
  596. type GGUFWriter struct {
  597. KV
  598. Tensors
  599. }
  600. var _ io.Reader = (*GGUFWriter)(nil)
  601. var _ io.WriterTo = (*GGUFWriter)(nil)
  602. func (GGUFWriter) Read([]byte) (int, error) {
  603. panic("not implemeneted")
  604. }
  605. func (gguf GGUFWriter) WriteTo(w io.Writer) (int64, error) {
  606. if err := binary.Write(w, binary.LittleEndian, []byte("GGUF")); err != nil {
  607. return 0, err
  608. }
  609. if err := binary.Write(w, binary.LittleEndian, uint32(3)); err != nil {
  610. return 0, err
  611. }
  612. if err := binary.Write(w, binary.LittleEndian, uint64(len(gguf.Tensors))); err != nil {
  613. return 0, err
  614. }
  615. if err := binary.Write(w, binary.LittleEndian, uint64(len(gguf.KV))); err != nil {
  616. return 0, err
  617. }
  618. keys := maps.Keys(gguf.KV)
  619. slices.Sort(keys)
  620. for _, key := range keys {
  621. if err := ggufWriteKV(w, key, gguf.KV[key]); err != nil {
  622. return 0, err
  623. }
  624. }
  625. sort.Sort(gguf.Tensors)
  626. var s uint64
  627. for _, t := range gguf.Tensors {
  628. t.Offset = s
  629. if err := ggufWriteTensorInfo(w, t); err != nil {
  630. return 0, err
  631. }
  632. s += t.Size()
  633. }
  634. var alignment int64 = 32
  635. for _, t := range gguf.Tensors {
  636. if err := ggufWriteTensor(w, t, alignment); err != nil {
  637. return 0, err
  638. }
  639. }
  640. return 0, nil
  641. }
  642. func ggufWriteTensor(io.Writer, *Tensor, int64) error {
  643. return nil
  644. }
  645. func ggufWriteTensorInfo(io.Writer, *Tensor) error {
  646. return nil
  647. }
  648. func ggufWriteKV(io.Writer, string, any) error {
  649. return nil
  650. }