safetensors.go 6.95 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
package convert

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"slices"
Michael Yang's avatar
cleanup  
Michael Yang committed
13
	"strings"
14
15
16
17
18
19
20
21
22
23
24
25
26
27

	"github.com/d4l3k/go-bfloat16"
	"github.com/x448/float16"

	"github.com/ollama/ollama/llm"
)

type safetensorWriterTo struct {
	t *llm.Tensor

	params *Params
	bo     ByteOrder

	filename string
28
	dtype    string
29

Michael Yang's avatar
Michael Yang committed
30
31
	offset, size int64
	repacker     func(string, []float32, []uint64) ([]float32, error)
32
33
}

Michael Yang's avatar
Michael Yang committed
34
35
36
37
type safetensorMetadata struct {
	Type    string   `json:"dtype"`
	Shape   []uint64 `json:"shape"`
	Offsets []int64  `json:"data_offsets"`
38
39
40
41
42
43
}

type SafetensorFormat struct{}

func (m *SafetensorFormat) GetTensors(dirpath string, params *Params) ([]llm.Tensor, error) {
	var tensors []llm.Tensor
Michael Yang's avatar
Michael Yang committed
44
	matches, err := filepath.Glob(filepath.Join(dirpath, "*.safetensors"))
45
46
47
48
49
	if err != nil {
		return nil, err
	}

	var offset uint64
Michael Yang's avatar
Michael Yang committed
50
	for _, f := range matches {
51
52
53
54
55
56
		var t []llm.Tensor
		var err error
		t, offset, err = m.readTensors(f, offset, params)
		if err != nil {
			return nil, err
		}
Michael Yang's avatar
Michael Yang committed
57

58
59
60
61
62
63
64
65
66
67
68
69
		tensors = append(tensors, t...)
	}
	return tensors, nil
}

func (m *SafetensorFormat) readTensors(fn string, offset uint64, params *Params) ([]llm.Tensor, uint64, error) {
	f, err := os.Open(fn)
	if err != nil {
		return nil, 0, err
	}
	defer f.Close()

Michael Yang's avatar
Michael Yang committed
70
71
	var n int64
	if err := binary.Read(f, binary.LittleEndian, &n); err != nil {
72
73
74
		return nil, 0, err
	}

Michael Yang's avatar
Michael Yang committed
75
76
	b := bytes.NewBuffer(make([]byte, 0, n))
	if _, err = io.CopyN(b, f, n); err != nil {
77
78
79
		return nil, 0, err
	}

Michael Yang's avatar
Michael Yang committed
80
81
	var headers map[string]safetensorMetadata
	if err := json.NewDecoder(b).Decode(&headers); err != nil {
82
83
84
85
		return nil, 0, err
	}

	var keys []string
Michael Yang's avatar
Michael Yang committed
86
87
88
89
	for key := range headers {
		if !strings.HasSuffix(key, "self_attn.rotary_embd.inv_freq") {
			keys = append(keys, key)
		}
90
91
92
93
94
	}

	slices.Sort(keys)

	var tensors []llm.Tensor
Michael Yang's avatar
Michael Yang committed
95
96
	for _, key := range keys {
		value := headers[key]
97
98

		var kind uint32
Michael Yang's avatar
Michael Yang committed
99
		switch len(value.Shape) {
100
		case 0:
Michael Yang's avatar
Michael Yang committed
101
			// valuedata
102
103
104
105
106
			continue
		case 2:
			kind = 1
		}

Michael Yang's avatar
Michael Yang committed
107
		name, err := m.GetLayerName(key)
108
109
110
111
		if err != nil {
			return nil, 0, err
		}

Michael Yang's avatar
Michael Yang committed
112
113
		shape := make([]uint64, len(value.Shape))
		copy(shape, value.Shape)
114

Michael Yang's avatar
Michael Yang committed
115
116
117
		pad := func(s int64) int64 {
			return 8 + n + s
		}
Patrick Devine's avatar
Patrick Devine committed
118

119
		t := llm.Tensor{
Michael Yang's avatar
Michael Yang committed
120
			Name:   name,
121
122
			Kind:   kind,
			Offset: offset,
Michael Yang's avatar
Michael Yang committed
123
			Shape:  shape,
124
125
126
127
128
129
130
		}

		t.WriterTo = safetensorWriterTo{
			t:        &t,
			params:   params,
			bo:       params.ByteOrder,
			filename: fn,
Michael Yang's avatar
Michael Yang committed
131
132
133
			dtype:    value.Type,
			offset:   pad(value.Offsets[0]),
			size:     pad(value.Offsets[1]) - pad(value.Offsets[0]),
134
135
		}

Michael Yang's avatar
Michael Yang committed
136
		offset += t.Size()
137
		tensors = append(tensors, t)
138
	}
139

140
141
142
143
144
145
146
147
148
149
150
151
	return tensors, offset, nil
}

func (m *SafetensorFormat) GetParams(dirpath string) (*Params, error) {
	f, err := os.Open(filepath.Join(dirpath, "config.json"))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var params Params

Michael Yang's avatar
Michael Yang committed
152
	if err := json.NewDecoder(f).Decode(&params); err != nil {
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
		return nil, err
	}

	params.ByteOrder = binary.LittleEndian
	return &params, nil
}

func (m *SafetensorFormat) GetLayerName(n string) (string, error) {
	directMap := map[string]string{
		"model.embed_tokens.weight": "token_embd.weight",
		"lm_head.weight":            "output.weight",
		"model.norm.weight":         "output_norm.weight",
	}

	tMap := map[string]string{
168
169
170
171
172
173
174
175
176
177
178
179
180
		"model.layers.(\\d+).input_layernorm.weight":                    "blk.$1.attn_norm.weight",
		"model.layers.(\\d+).mlp.down_proj.weight":                      "blk.$1.ffn_down.weight",
		"model.layers.(\\d+).mlp.gate_proj.weight":                      "blk.$1.ffn_gate.weight",
		"model.layers.(\\d+).mlp.up_proj.weight":                        "blk.$1.ffn_up.weight",
		"model.layers.(\\d+).post_attention_layernorm.weight":           "blk.$1.ffn_norm.weight",
		"model.layers.(\\d+).self_attn.k_proj.weight":                   "blk.$1.attn_k.weight",
		"model.layers.(\\d+).self_attn.o_proj.weight":                   "blk.$1.attn_output.weight",
		"model.layers.(\\d+).self_attn.q_proj.weight":                   "blk.$1.attn_q.weight",
		"model.layers.(\\d+).self_attn.v_proj.weight":                   "blk.$1.attn_v.weight",
		"model.layers.(\\d+).block_sparse_moe.gate.weight":              "blk.$1.ffn_gate_inp.weight",
		"model.layers.(\\d+).block_sparse_moe.experts.(\\d+).w1.weight": "blk.$1.ffn_gate.$2.weight",
		"model.layers.(\\d+).block_sparse_moe.experts.(\\d+).w2.weight": "blk.$1.ffn_down.$2.weight",
		"model.layers.(\\d+).block_sparse_moe.experts.(\\d+).w3.weight": "blk.$1.ffn_up.$2.weight",
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
	}

	v, ok := directMap[n]
	if ok {
		return v, nil
	}

	// quick hack to rename the layers to gguf format
	for k, v := range tMap {
		re := regexp.MustCompile(k)
		newName := re.ReplaceAllString(n, v)
		if newName != n {
			return newName, nil
		}
	}

	return "", fmt.Errorf("couldn't find a layer name for '%s'", n)
}

func (r safetensorWriterTo) WriteTo(w io.Writer) (n int64, err error) {
	f, err := os.Open(r.filename)
	if err != nil {
		return 0, err
	}
	defer f.Close()

Michael Yang's avatar
Michael Yang committed
207
	if _, err = f.Seek(r.offset, io.SeekStart); err != nil {
208
209
210
		return 0, err
	}

211
212
213
	var f32s []float32
	switch r.dtype {
	case "F32":
Michael Yang's avatar
Michael Yang committed
214
		f32s = make([]float32, r.size/4)
215
216
217
218
		if err = binary.Read(f, r.bo, f32s); err != nil {
			return 0, err
		}
	case "F16":
Michael Yang's avatar
Michael Yang committed
219
220
		u16s := make([]uint16, r.size/2)
		if err = binary.Read(f, r.bo, u16s); err != nil {
221
222
			return 0, err
		}
223

Michael Yang's avatar
Michael Yang committed
224
		for _, b := range u16s {
225
226
			f32s = append(f32s, float16.Frombits(b).Float32())
		}
227

228
	case "BF16":
Michael Yang's avatar
Michael Yang committed
229
230
		u8s := make([]uint8, r.size)
		if err = binary.Read(f, r.bo, u8s); err != nil {
231
232
233
			return 0, err
		}

Michael Yang's avatar
Michael Yang committed
234
		f32s = bfloat16.DecodeFloat32(u8s)
235
236
237
	default:
		return 0, fmt.Errorf("unknown data type: %s", r.dtype)
	}
238

239
240
241
242
	if r.repacker != nil {
		f32s, err = r.repacker(r.t.Name, f32s, r.t.Shape)
		if err != nil {
			return 0, err
243
		}
244
245
246
247
248
249
250
251
252
	}

	switch r.t.Kind {
	case 0:
		return 0, binary.Write(w, r.bo, f32s)
	case 1:
		f16s := make([]uint16, len(f32s))
		for i := range f32s {
			f16s[i] = float16.Fromfloat32(f32s[i]).Bits()
253
		}
254
255
256
257

		return 0, binary.Write(w, r.bo, f16s)
	default:
		return 0, fmt.Errorf("unknown storage type: %d", r.t.Kind)
258
259
260
261
262
263
264
265
266
	}
}

func (m *SafetensorFormat) GetModelArch(name, dirPath string, params *Params) (ModelArch, error) {
	switch len(params.Architectures) {
	case 0:
		return nil, fmt.Errorf("No architecture specified to convert")
	case 1:
		switch params.Architectures[0] {
Patrick Devine's avatar
Patrick Devine committed
267
268
269
270
271
272
273
274
275
		case "LlamaForCausalLM":
			return &LlamaModel{
				ModelData{
					Name:   name,
					Path:   dirPath,
					Params: params,
					Format: m,
				},
			}, nil
276
277
278
279
280
281
282
283
284
		case "MistralForCausalLM":
			return &MistralModel{
				ModelData{
					Name:   name,
					Path:   dirPath,
					Params: params,
					Format: m,
				},
			}, nil
285
286
287
288
289
290
291
292
293
		case "MixtralForCausalLM":
			return &MixtralModel{
				ModelData{
					Name:   name,
					Path:   dirPath,
					Params: params,
					Format: m,
				},
			}, nil
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
		case "GemmaForCausalLM":
			return &GemmaModel{
				ModelData{
					Name:   name,
					Path:   dirPath,
					Params: params,
					Format: m,
				},
			}, nil
		default:
			return nil, fmt.Errorf("Models based on '%s' are not yet supported", params.Architectures[0])
		}
	}

	return nil, fmt.Errorf("Unknown error")
}