gguf.go 13.5 KB
Newer Older
Michael Yang's avatar
Michael Yang committed
1
package ggml
Bruce MacDonald's avatar
Bruce MacDonald committed
2
3
4

import (
	"bytes"
Michael Yang's avatar
Michael Yang committed
5
	"cmp"
Bruce MacDonald's avatar
Bruce MacDonald committed
6
	"encoding/binary"
7
	"encoding/json"
Bruce MacDonald's avatar
Bruce MacDonald committed
8
9
	"fmt"
	"io"
Michael Yang's avatar
Michael Yang committed
10
	"log/slog"
Michael Yang's avatar
Michael Yang committed
11
	"maps"
Michael Yang's avatar
Michael Yang committed
12
	"slices"
13
	"strings"
Bruce MacDonald's avatar
Bruce MacDonald committed
14
15
)

16
type containerGGUF struct {
17
	ByteOrder binary.ByteOrder
Michael Yang's avatar
ggufv3  
Michael Yang committed
18

Bruce MacDonald's avatar
Bruce MacDonald committed
19
20
21
22
23
24
25
26
27
28
29
	Version uint32

	V1 struct {
		NumTensor uint32
		NumKV     uint32
	}

	V2 struct {
		NumTensor uint64
		NumKV     uint64
	}
30
31
32
33
34

	V3 struct {
		NumTensor uint64
		NumKV     uint64
	}
35
36
37
38

	maxArraySize int
}

39
func (c *containerGGUF) Name() string {
Bruce MacDonald's avatar
Bruce MacDonald committed
40
41
42
	return "gguf"
}

43
func (c *containerGGUF) Decode(rs io.ReadSeeker) (model, error) {
44
	if err := binary.Read(rs, c.ByteOrder, &c.Version); err != nil {
45
46
		return nil, err
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
47

48
	var err error
Bruce MacDonald's avatar
Bruce MacDonald committed
49
50
	switch c.Version {
	case 1:
51
52
53
		err = binary.Read(rs, c.ByteOrder, &c.V1)
	case 2:
		err = binary.Read(rs, c.ByteOrder, &c.V2)
Bruce MacDonald's avatar
Bruce MacDonald committed
54
	default:
55
56
57
58
		err = binary.Read(rs, c.ByteOrder, &c.V3)
	}
	if err != nil {
		return nil, err
Bruce MacDonald's avatar
Bruce MacDonald committed
59
60
	}

61
	model := newGGUF(c)
Michael Yang's avatar
Michael Yang committed
62
	if err := model.Decode(rs); err != nil {
Bruce MacDonald's avatar
Bruce MacDonald committed
63
64
65
66
67
68
		return nil, err
	}

	return model, nil
}

69
const (
70
71
72
73
74
75
76
77
78
79
80
81
82
	ggufTypeUint8 uint32 = iota
	ggufTypeInt8
	ggufTypeUint16
	ggufTypeInt16
	ggufTypeUint32
	ggufTypeInt32
	ggufTypeFloat32
	ggufTypeBool
	ggufTypeString
	ggufTypeArray
	ggufTypeUint64
	ggufTypeInt64
	ggufTypeFloat64
83
)
Bruce MacDonald's avatar
Bruce MacDonald committed
84

85
86
type gguf struct {
	*containerGGUF
87

Michael Yang's avatar
Michael Yang committed
88
89
	kv      KV
	tensors []*Tensor
90

Michael Yang's avatar
Michael Yang committed
91
	parameters   uint64
92
	tensorOffset uint64
93
94

	scratch [16 << 10]byte
Bruce MacDonald's avatar
Bruce MacDonald committed
95
96
}

97
98
99
func newGGUF(container *containerGGUF) *gguf {
	return &gguf{
		containerGGUF: container,
Michael Yang's avatar
Michael Yang committed
100
		kv:            make(KV),
Bruce MacDonald's avatar
Bruce MacDonald committed
101
102
103
	}
}

Michael Yang's avatar
Michael Yang committed
104
105
106
107
func (llm *gguf) KV() KV {
	return llm.kv
}

Michael Yang's avatar
Michael Yang committed
108
109
110
func (llm *gguf) Tensors() Tensors {
	return Tensors{
		items:  llm.tensors,
111
112
		Offset: llm.tensorOffset,
	}
Michael Yang's avatar
Michael Yang committed
113
114
}

115
116
117
func (llm *gguf) numTensor() uint64 {
	switch llm.Version {
	case 1:
118
		return uint64(llm.V1.NumTensor)
119
120
121
122
	case 2:
		return llm.V2.NumTensor
	default:
		return llm.V3.NumTensor
123
124
125
	}
}

126
127
128
func (llm *gguf) numKV() uint64 {
	switch llm.Version {
	case 1:
Bruce MacDonald's avatar
Bruce MacDonald committed
129
		return uint64(llm.V1.NumKV)
130
131
132
133
	case 2:
		return llm.V2.NumKV
	default:
		return llm.V3.NumKV
Bruce MacDonald's avatar
Bruce MacDonald committed
134
135
136
	}
}

137
138
139
140
141
func (llm *gguf) Decode(rs io.ReadSeeker) error {
	// decode key-values
	for i := 0; uint64(i) < llm.numKV(); i++ {
		k, err := readGGUFString(llm, rs)
		if err != nil {
142
143
144
			return err
		}

145
146
		t, err := readGGUF[uint32](llm, rs)
		if err != nil {
147
148
149
			return err
		}

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
		var v any
		switch t {
		case ggufTypeUint8:
			v, err = readGGUF[uint8](llm, rs)
		case ggufTypeInt8:
			v, err = readGGUF[int8](llm, rs)
		case ggufTypeUint16:
			v, err = readGGUF[uint16](llm, rs)
		case ggufTypeInt16:
			v, err = readGGUF[int16](llm, rs)
		case ggufTypeUint32:
			v, err = readGGUF[uint32](llm, rs)
		case ggufTypeInt32:
			v, err = readGGUF[int32](llm, rs)
		case ggufTypeUint64:
			v, err = readGGUF[uint64](llm, rs)
		case ggufTypeInt64:
			v, err = readGGUF[int64](llm, rs)
		case ggufTypeFloat32:
			v, err = readGGUF[float32](llm, rs)
		case ggufTypeFloat64:
			v, err = readGGUF[float64](llm, rs)
		case ggufTypeBool:
			v, err = readGGUF[bool](llm, rs)
		case ggufTypeString:
			v, err = readGGUFString(llm, rs)
		case ggufTypeArray:
			v, err = readGGUFArray(llm, rs)
		default:
			return fmt.Errorf("invalid type: %d", t)
180
181
		}

182
		if err != nil {
183
184
185
			return err
		}

Michael Yang's avatar
Michael Yang committed
186
		llm.kv[k] = v
187
188
	}

189
	// decode tensors
190
	for range llm.numTensor() {
191
		name, err := readGGUFString(llm, rs)
192
		if err != nil {
193
			return fmt.Errorf("failed to read tensor name: %w", err)
194
195
		}

196
197
		// dims is the number of dimensions in the tensor
		dims, err := readGGUF[uint32](llm, rs)
Bruce MacDonald's avatar
Bruce MacDonald committed
198
		if err != nil {
199
			return fmt.Errorf("failed to read tensor dimensions: %w", err)
Bruce MacDonald's avatar
Bruce MacDonald committed
200
201
		}

Michael Yang's avatar
Michael Yang committed
202
		shape := make([]uint64, dims)
203
204
		for i := 0; uint32(i) < dims; i++ {
			shape[i], err = readGGUF[uint64](llm, rs)
Bruce MacDonald's avatar
Bruce MacDonald committed
205
			if err != nil {
206
				return fmt.Errorf("failed to read tensor shape: %w", err)
Bruce MacDonald's avatar
Bruce MacDonald committed
207
208
209
			}
		}

210
		kind, err := readGGUF[uint32](llm, rs)
211
		if err != nil {
212
			return fmt.Errorf("failed to read tensor kind: %w", err)
213
214
		}

215
216
		offset, err := readGGUF[uint64](llm, rs)
		if err != nil {
217
			return fmt.Errorf("failed to read tensor offset: %w", err)
218
219
		}

220
221
		tensor := Tensor{
			Name:   name,
222
223
			Kind:   kind,
			Offset: offset,
Michael Yang's avatar
Michael Yang committed
224
			Shape:  shape[:],
Michael Yang's avatar
Michael Yang committed
225
		}
226

Michael Yang's avatar
Michael Yang committed
227
		llm.tensors = append(llm.tensors, &tensor)
228
		llm.parameters += tensor.parameters()
229
230
	}

Michael Yang's avatar
Michael Yang committed
231
232
233
	// patch KV with parameter count
	llm.kv["general.parameter_count"] = llm.parameters

Michael Yang's avatar
Michael Yang committed
234
	alignment := llm.kv.Uint("general.alignment", 32)
235

236
237
238
239
240
	offset, err := rs.Seek(0, io.SeekCurrent)
	if err != nil {
		return err
	}

Michael Yang's avatar
Michael Yang committed
241
	padding := ggufPadding(offset, int64(alignment))
242
243
	llm.tensorOffset = uint64(offset + padding)

Michael Yang's avatar
Michael Yang committed
244
	for _, tensor := range llm.tensors {
245
246
247
		offset, err := rs.Seek(0, io.SeekCurrent)
		if err != nil {
			return fmt.Errorf("failed to get current offset: %w", err)
248
249
		}

Michael Yang's avatar
Michael Yang committed
250
		padding := ggufPadding(offset, int64(alignment))
251
		if _, err := rs.Seek(padding, io.SeekCurrent); err != nil {
252
253
254
255
256
			return fmt.Errorf("failed to seek to init padding: %w", err)
		}

		if _, err := rs.Seek(int64(tensor.Size()), io.SeekCurrent); err != nil {
			return fmt.Errorf("failed to seek to tensor: %w", err)
Michael Yang's avatar
Michael Yang committed
257
		}
258
259
	}

Bruce MacDonald's avatar
Bruce MacDonald committed
260
261
262
	return nil
}

263
264
265
266
func readGGUF[T any](llm *gguf, r io.Reader) (T, error) {
	var t T
	err := binary.Read(r, llm.ByteOrder, &t)
	return t, err
Bruce MacDonald's avatar
Bruce MacDonald committed
267
268
}

Michael Yang's avatar
Michael Yang committed
269
270
func writeGGUF[V any](w io.Writer, t uint32, v V) error {
	if err := binary.Write(w, binary.LittleEndian, t); err != nil {
271
272
		return err
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
273

Michael Yang's avatar
Michael Yang committed
274
	return binary.Write(w, binary.LittleEndian, v)
Bruce MacDonald's avatar
Bruce MacDonald committed
275
276
}

277
278
279
280
281
func readGGUFV1String(llm *gguf, r io.Reader) (string, error) {
	var length uint64
	if err := binary.Read(r, llm.ByteOrder, &length); err != nil {
		return "", err
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
282
283

	var b bytes.Buffer
284
	if _, err := io.CopyN(&b, r, int64(length)); err != nil {
Bruce MacDonald's avatar
Bruce MacDonald committed
285
286
287
288
289
290
291
292
293
		return "", err
	}

	// gguf v1 strings are null-terminated
	b.Truncate(b.Len() - 1)

	return b.String(), nil
}

Michael Yang's avatar
Michael Yang committed
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
func readGGUFV1StringsData(llm *gguf, r io.Reader, a *array[string]) (any, error) {
	for i := range a.size {
		if a.values != nil {
			e, err := readGGUFV1String(llm, r)
			if err != nil {
				return nil, err
			}

			a.values[i] = e
		} else {
			discardGGUFString(llm, r)
		}
	}

	return a, nil
}

311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
func discardGGUFString(llm *gguf, r io.Reader) error {
	buf := llm.scratch[:8]
	_, err := io.ReadFull(r, buf)
	if err != nil {
		return err
	}

	size := int(llm.ByteOrder.Uint64(buf))
	for size > 0 {
		n, err := r.Read(llm.scratch[:min(size, cap(llm.scratch))])
		if err != nil {
			return err
		}
		size -= n
	}
	return nil
}

329
func readGGUFString(llm *gguf, r io.Reader) (string, error) {
330
	if llm.Version == 1 {
331
		return readGGUFV1String(llm, r)
332
333
	}

334
335
336
	buf := llm.scratch[:8]
	_, err := io.ReadFull(r, buf)
	if err != nil {
337
338
		return "", err
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
339

340
341
342
343
344
	length := int(llm.ByteOrder.Uint64(buf))
	if length > len(llm.scratch) {
		buf = make([]byte, length)
	} else {
		buf = llm.scratch[:length]
Bruce MacDonald's avatar
Bruce MacDonald committed
345
	}
346
	clear(buf)
Bruce MacDonald's avatar
Bruce MacDonald committed
347

348
349
350
351
352
	_, err = io.ReadFull(r, buf)
	if err != nil {
		return "", err
	}
	return string(buf), nil
Bruce MacDonald's avatar
Bruce MacDonald committed
353
354
}

Michael Yang's avatar
Michael Yang committed
355
356
func writeGGUFString(w io.Writer, s string) error {
	if err := binary.Write(w, binary.LittleEndian, ggufTypeString); err != nil {
357
358
		return err
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
359

Michael Yang's avatar
Michael Yang committed
360
	if err := binary.Write(w, binary.LittleEndian, uint64(len(s))); err != nil {
361
362
363
364
365
366
367
		return err
	}

	_, err := io.Copy(w, strings.NewReader(s))
	return err
}

Michael Yang's avatar
Michael Yang committed
368
369
func readGGUFStringsData(llm *gguf, r io.Reader, a *array[string]) (any, error) {
	for i := range a.size {
370
		if a.values != nil {
Michael Yang's avatar
Michael Yang committed
371
372
373
374
375
			e, err := readGGUFString(llm, r)
			if err != nil {
				return nil, err
			}

376
			a.values[i] = e
Michael Yang's avatar
Michael Yang committed
377
378
		} else {
			discardGGUFString(llm, r)
379
		}
Bruce MacDonald's avatar
Bruce MacDonald committed
380
381
	}

382
	return a, nil
Bruce MacDonald's avatar
Bruce MacDonald committed
383
384
}

Michael Yang's avatar
Michael Yang committed
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
type array[T any] struct {
	// size is the actual size of the array
	size int

	// values is the array of values. this is nil if the array is larger than configured maxSize
	values []T
}

func (a *array[T]) MarshalJSON() ([]byte, error) {
	return json.Marshal(a.values)
}

func newArray[T any](size, maxSize int) *array[T] {
	a := array[T]{size: size}
	if maxSize < 0 || size <= maxSize {
		a.values = make([]T, size)
401
	}
Michael Yang's avatar
Michael Yang committed
402
403
	return &a
}
404

Michael Yang's avatar
Michael Yang committed
405
func readGGUFArray(llm *gguf, r io.Reader) (any, error) {
406
407
408
409
	t, err := readGGUF[uint32](llm, r)
	if err != nil {
		return nil, err
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
410

411
412
413
414
	n, err := readGGUF[uint64](llm, r)
	if err != nil {
		return nil, err
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
415

Michael Yang's avatar
Michael Yang committed
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
	switch t {
	case ggufTypeUint8:
		a := newArray[uint8](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeInt8:
		a := newArray[int8](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeUint16:
		a := newArray[uint16](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeInt16:
		a := newArray[int16](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeUint32:
		a := newArray[uint32](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeInt32:
		a := newArray[int32](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeUint64:
		a := newArray[uint64](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeInt64:
		a := newArray[int64](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeFloat32:
		a := newArray[float32](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeFloat64:
		a := newArray[float64](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeBool:
		a := newArray[bool](int(n), llm.maxArraySize)
		return readGGUFArrayData(llm, r, a)
	case ggufTypeString:
		a := newArray[string](int(n), llm.maxArraySize)
		if llm.Version == 1 {
			return readGGUFV1StringsData(llm, r, a)
		}

		return readGGUFStringsData(llm, r, a)
	default:
		return nil, fmt.Errorf("invalid array type: %d", t)
459
	}
Michael Yang's avatar
Michael Yang committed
460
}
461

Michael Yang's avatar
Michael Yang committed
462
463
464
func readGGUFArrayData[T any](llm *gguf, r io.Reader, a *array[T]) (any, error) {
	for i := range a.size {
		e, err := readGGUF[T](llm, r)
465
466
467
468
		if err != nil {
			return nil, err
		}

469
470
471
		if a.values != nil {
			a.values[i] = e
		}
Bruce MacDonald's avatar
Bruce MacDonald committed
472
473
	}

474
	return a, nil
Bruce MacDonald's avatar
Bruce MacDonald committed
475
}
476

Michael Yang's avatar
Michael Yang committed
477
// writeGGUFArray writes a slice s of type E to the write with a gguf type of t
Michael Yang's avatar
Michael Yang committed
478
479
func writeGGUFArray[S ~[]E, E any](w io.Writer, t uint32, s S) error {
	if err := binary.Write(w, binary.LittleEndian, ggufTypeArray); err != nil {
480
481
482
		return err
	}

Michael Yang's avatar
Michael Yang committed
483
	if err := binary.Write(w, binary.LittleEndian, t); err != nil {
484
485
486
		return err
	}

Michael Yang's avatar
Michael Yang committed
487
	if err := binary.Write(w, binary.LittleEndian, uint64(len(s))); err != nil {
488
489
490
		return err
	}

Michael Yang's avatar
Michael Yang committed
491
	return binary.Write(w, binary.LittleEndian, s)
492
493
}

Michael Yang's avatar
Michael Yang committed
494
func WriteGGUF(ws io.WriteSeeker, kv KV, ts []Tensor) error {
Michael Yang's avatar
Michael Yang committed
495
496
	alignment := kv.Uint("general.alignment", 32)

Michael Yang's avatar
Michael Yang committed
497
	if err := binary.Write(ws, binary.LittleEndian, []byte("GGUF")); err != nil {
498
499
500
		return err
	}

Michael Yang's avatar
Michael Yang committed
501
	if err := binary.Write(ws, binary.LittleEndian, uint32(3)); err != nil {
502
503
504
		return err
	}

Michael Yang's avatar
Michael Yang committed
505
	if err := binary.Write(ws, binary.LittleEndian, uint64(len(ts))); err != nil {
506
507
508
		return err
	}

Michael Yang's avatar
Michael Yang committed
509
	if err := binary.Write(ws, binary.LittleEndian, uint64(len(kv))); err != nil {
510
511
512
		return err
	}

Michael Yang's avatar
Michael Yang committed
513
	keys := slices.Collect(maps.Keys(kv))
Michael Yang's avatar
Michael Yang committed
514
515
516
517
518
519
	slices.Sort(keys)

	for _, key := range keys {
		if err := ggufWriteKV(ws, key, kv[key]); err != nil {
			return err
		}
520
521
	}

522
523
524
525
526
527
528
	slices.SortStableFunc(ts, func(a, b Tensor) int {
		if i, j := a.block(), b.block(); i < 0 && j > 0 {
			return 1
		} else if i > 0 && j < 0 {
			return -1
		} else {
			return cmp.Compare(i, j)
529
		}
Michael Yang's avatar
Michael Yang committed
530
531
532
533
	})

	var s uint64
	for _, t := range ts {
534
		t.Offset = s
Michael Yang's avatar
Michael Yang committed
535
		if err := ggufWriteTensorInfo(ws, t); err != nil {
536
537
			return err
		}
Michael Yang's avatar
Michael Yang committed
538
		s += t.Size()
539
		s += uint64(ggufPadding(int64(s), int64(alignment)))
Michael Yang's avatar
Michael Yang committed
540
	}
541

Michael Yang's avatar
Michael Yang committed
542
	for _, t := range ts {
Michael Yang's avatar
Michael Yang committed
543
		if err := ggufWriteTensor(ws, t, int64(alignment)); err != nil {
544
545
			return err
		}
Michael Yang's avatar
Michael Yang committed
546
	}
547

Michael Yang's avatar
Michael Yang committed
548
549
	return nil
}
550

Michael Yang's avatar
Michael Yang committed
551
552
553
554
func ggufWriteKV(ws io.WriteSeeker, k string, v any) error {
	slog.Debug(k, "type", fmt.Sprintf("%T", v))
	if err := binary.Write(ws, binary.LittleEndian, uint64(len(k))); err != nil {
		return err
555
556
	}

Michael Yang's avatar
Michael Yang committed
557
558
	if err := binary.Write(ws, binary.LittleEndian, []byte(k)); err != nil {
		return err
559
560
	}

Michael Yang's avatar
Michael Yang committed
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
	var err error
	switch v := v.(type) {
	case uint32:
		err = writeGGUF(ws, ggufTypeUint32, v)
	case float32:
		err = writeGGUF(ws, ggufTypeFloat32, v)
	case bool:
		err = writeGGUF(ws, ggufTypeBool, v)
	case string:
		err = writeGGUFString(ws, v)
	case []int32:
		err = writeGGUFArray(ws, ggufTypeInt32, v)
	case []uint32:
		err = writeGGUFArray(ws, ggufTypeUint32, v)
	case []float32:
		err = writeGGUFArray(ws, ggufTypeFloat32, v)
	case []string:
		if err := binary.Write(ws, binary.LittleEndian, ggufTypeArray); err != nil {
579
580
581
			return err
		}

Michael Yang's avatar
Michael Yang committed
582
		if err := binary.Write(ws, binary.LittleEndian, ggufTypeString); err != nil {
583
584
585
			return err
		}

Michael Yang's avatar
Michael Yang committed
586
		if err := binary.Write(ws, binary.LittleEndian, uint64(len(v))); err != nil {
587
588
589
			return err
		}

Michael Yang's avatar
Michael Yang committed
590
591
		for _, e := range v {
			if err := binary.Write(ws, binary.LittleEndian, uint64(len(e))); err != nil {
592
593
594
				return err
			}

Michael Yang's avatar
Michael Yang committed
595
596
597
			if err := binary.Write(ws, binary.LittleEndian, []byte(e)); err != nil {
				return err
			}
598
		}
Michael Yang's avatar
Michael Yang committed
599
600
601
	default:
		return fmt.Errorf("improper type for '%s'", k)
	}
602

Michael Yang's avatar
Michael Yang committed
603
604
605
	return err
}

Michael Yang's avatar
Michael Yang committed
606
func ggufWriteTensorInfo(ws io.WriteSeeker, t Tensor) error {
Michael Yang's avatar
Michael Yang committed
607
608
609
	slog.Debug(t.Name, "kind", t.Kind, "shape", t.Shape, "offset", t.Offset)
	if err := binary.Write(ws, binary.LittleEndian, uint64(len(t.Name))); err != nil {
		return err
610
611
	}

Michael Yang's avatar
Michael Yang committed
612
613
614
	if err := binary.Write(ws, binary.LittleEndian, []byte(t.Name)); err != nil {
		return err
	}
615

Michael Yang's avatar
Michael Yang committed
616
617
618
	if err := binary.Write(ws, binary.LittleEndian, uint32(len(t.Shape))); err != nil {
		return err
	}
619

Michael Yang's avatar
Michael Yang committed
620
621
	for _, n := range t.Shape {
		if err := binary.Write(ws, binary.LittleEndian, n); err != nil {
622
623
			return err
		}
624
625
	}

Michael Yang's avatar
Michael Yang committed
626
627
628
629
630
631
632
	if err := binary.Write(ws, binary.LittleEndian, t.Kind); err != nil {
		return err
	}

	return binary.Write(ws, binary.LittleEndian, t.Offset)
}

Michael Yang's avatar
Michael Yang committed
633
func ggufWriteTensor(ws io.WriteSeeker, t Tensor, alignment int64) error {
Michael Yang's avatar
Michael Yang committed
634
635
636
637
638
639
640
641
642
643
644
	offset, err := ws.Seek(0, io.SeekCurrent)
	if err != nil {
		return err
	}

	if err := binary.Write(ws, binary.LittleEndian, bytes.Repeat([]byte{0}, int(ggufPadding(offset, alignment)))); err != nil {
		return err
	}

	_, err = t.WriteTo(ws)
	return err
645
646
}

Michael Yang's avatar
Michael Yang committed
647
func ggufPadding(offset, align int64) int64 {
648
	return (align - offset%align) % align
649
}