Bopalv commited on
Commit
b6eaadb
·
verified ·
1 Parent(s): d8755ad

Upload convert_to_gguf_pure.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. convert_to_gguf_pure.py +241 -0
convert_to_gguf_pure.py ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Convert pure Python DGPO model to GGUF format.
4
+ Usage: python3 convert_to_gguf_pure.py
5
+ """
6
+
7
+ import os
8
+ import struct
9
+ import pickle
10
+ import numpy as np
11
+
12
+ # GGUF constants
13
+ GGUF_MAGIC = 0x46475546 # "GGUF"
14
+ GGUF_VERSION = 3
15
+
16
+ # GGML types
17
+ GGML_TYPE_F32 = 0
18
+ GGML_TYPE_F16 = 1
19
+
20
+ # Tensor types mapping
21
+ DTYPE_MAP = {
22
+ np.dtype('float32'): GGML_TYPE_F32,
23
+ np.dtype('float64'): GGML_TYPE_F32,
24
+ }
25
+
26
+ class GGUFWriter:
27
+ """Minimal GGUF file writer."""
28
+
29
+ def __init__(self, path):
30
+ self.path = path
31
+ self.metadata = {}
32
+ self.tensors = []
33
+
34
+ def add_metadata(self, key, value):
35
+ """Add metadata key-value pair."""
36
+ self.metadata[key] = value
37
+
38
+ def add_tensor(self, name, data):
39
+ """Add a tensor."""
40
+ if not isinstance(data, np.ndarray):
41
+ data = np.array(data, dtype=np.float32)
42
+ else:
43
+ data = data.astype(np.float32)
44
+ self.tensors.append((name, data))
45
+
46
+ def write(self):
47
+ """Write GGUF file."""
48
+ with open(self.path, 'wb') as f:
49
+ # Header
50
+ f.write(struct.pack('<I', GGUF_MAGIC))
51
+ f.write(struct.pack('<I', GGUF_VERSION))
52
+
53
+ # Tensor count
54
+ f.write(struct.pack('<Q', len(self.tensors)))
55
+
56
+ # Metadata count
57
+ f.write(struct.pack('<Q', len(self.metadata)))
58
+
59
+ # Write metadata
60
+ for key, value in self.metadata.items():
61
+ self._write_string(f, key)
62
+ self._write_metadata_value(f, value)
63
+
64
+ # Calculate data offset (after header + metadata + tensor info)
65
+ header_size = 4 + 4 + 8 + 8 # magic + version + tensor_count + metadata_count
66
+ metadata_size = 0
67
+ for key, value in self.metadata.items():
68
+ metadata_size += 2 + len(key) # key length + key
69
+ metadata_size += self._metadata_value_size(value)
70
+
71
+ tensor_info_size = 0
72
+ for name, data in self.tensors:
73
+ tensor_info_size += 2 + len(name) # name length + name
74
+ tensor_info_size += 4 # ndim
75
+ tensor_info_size += data.ndim * 8 # shape
76
+ tensor_info_size += 4 # dtype
77
+ tensor_info_size += 8 # offset
78
+
79
+ alignment = 32
80
+ data_offset = header_size + metadata_size + tensor_info_size
81
+ padded_offset = ((data_offset + alignment - 1) // alignment) * alignment
82
+
83
+ # Write tensor info
84
+ current_offset = 0
85
+ for name, data in self.tensors:
86
+ self._write_string(f, name)
87
+ f.write(struct.pack('<I', data.ndim))
88
+ for dim in data.shape:
89
+ f.write(struct.pack('<Q', dim))
90
+ f.write(struct.pack('<I', GGML_TYPE_F32))
91
+ f.write(struct.pack('<Q', padded_offset + current_offset))
92
+ current_offset += data.nbytes
93
+
94
+ # Pad to alignment
95
+ f.write(b'\x00' * (padded_offset - (header_size + metadata_size + tensor_info_size)))
96
+
97
+ # Write tensor data
98
+ for name, data in self.tensors:
99
+ f.write(data.tobytes())
100
+
101
+ print(f"Written GGUF: {self.path}")
102
+ print(f" Tensors: {len(self.tensors)}")
103
+ print(f" Size: {os.path.getsize(self.path) / 1024:.1f} KB")
104
+
105
+ def _write_string(self, f, s):
106
+ """Write a string."""
107
+ encoded = s.encode('utf-8')
108
+ f.write(struct.pack('<Q', len(encoded)))
109
+ f.write(encoded)
110
+
111
+ def _write_metadata_value(self, f, value):
112
+ """Write a metadata value."""
113
+ if isinstance(value, str):
114
+ # String type = 8
115
+ f.write(struct.pack('<I', 8))
116
+ encoded = value.encode('utf-8')
117
+ f.write(struct.pack('<Q', len(encoded)))
118
+ f.write(encoded)
119
+ elif isinstance(value, int):
120
+ # UINT64 type = 10
121
+ f.write(struct.pack('<I', 10))
122
+ f.write(struct.pack('<Q', value))
123
+ elif isinstance(value, float):
124
+ # FLOAT64 type = 13
125
+ f.write(struct.pack('<I', 13))
126
+ f.write(struct.pack('<d', value))
127
+ elif isinstance(value, bool):
128
+ # BOOL type = 6
129
+ f.write(struct.pack('<I', 6))
130
+ f.write(struct.pack('<?', value))
131
+ elif isinstance(value, list):
132
+ # Array type = 9
133
+ f.write(struct.pack('<I', 9))
134
+ if value and isinstance(value[0], str):
135
+ f.write(struct.pack('<I', 8)) # String array
136
+ f.write(struct.pack('<Q', len(value)))
137
+ for s in value:
138
+ encoded = s.encode('utf-8')
139
+ f.write(struct.pack('<Q', len(encoded)))
140
+ f.write(encoded)
141
+ else:
142
+ f.write(struct.pack('<I', 10)) # UINT64 array
143
+ f.write(struct.pack('<Q', len(value)))
144
+ for v in value:
145
+ f.write(struct.pack('<Q', v))
146
+
147
+ def _metadata_value_size(self, value):
148
+ """Calculate metadata value size."""
149
+ if isinstance(value, str):
150
+ return 4 + 8 + len(value.encode('utf-8'))
151
+ elif isinstance(value, (int, float, bool)):
152
+ return 4 + 8
153
+ elif isinstance(value, list):
154
+ size = 4 + 4 + 8
155
+ for v in value:
156
+ if isinstance(v, str):
157
+ size += 8 + len(v.encode('utf-8'))
158
+ else:
159
+ size += 8
160
+ return size
161
+ return 0
162
+
163
+ def convert():
164
+ """Convert pure Python model to GGUF."""
165
+ model_path = "./dgpo-tiny-pure/dgpo_tiny.pkl"
166
+ output_path = "./dgpo-tiny-pure.gguf"
167
+
168
+ if not os.path.exists(model_path):
169
+ print(f"Model not found: {model_path}")
170
+ print("Run: python3 train_dgpo_pure.py")
171
+ return
172
+
173
+ print("=" * 50)
174
+ print("Converting to GGUF")
175
+ print("=" * 50)
176
+
177
+ # Load model
178
+ with open(model_path, "rb") as f:
179
+ model_data = pickle.load(f)
180
+
181
+ config = model_data["config"]
182
+ vocab_size, d_model, n_heads, n_layers, max_len = config
183
+
184
+ print(f"Model config: vocab={vocab_size}, d_model={d_model}, layers={n_layers}, heads={n_heads}")
185
+
186
+ # Create GGUF writer
187
+ writer = GGUFWriter(output_path)
188
+
189
+ # Add metadata
190
+ writer.add_metadata("general.architecture", "gpt2")
191
+ writer.add_metadata("general.name", "dgpo-tiny-pure")
192
+ writer.add_metadata("gpt2.context_length", max_len)
193
+ writer.add_metadata("gpt2.embedding_length", d_model)
194
+ writer.add_metadata("gpt2.block_count", n_layers)
195
+ writer.add_metadata("gpt2.head_count", n_heads)
196
+ writer.add_metadata("gpt2.vocab_size", vocab_size)
197
+
198
+ # Add tensors
199
+ # Embedding
200
+ embed = np.array(model_data["embed"], dtype=np.float32)
201
+ writer.add_tensor("token_embd.weight", embed)
202
+
203
+ # Position embedding
204
+ pos_embed = np.array(model_data["pos_embed"], dtype=np.float32)
205
+ writer.add_tensor("position_embd.weight", pos_embed)
206
+
207
+ # Transformer layers
208
+ for i, layer in enumerate(model_data["layers"]):
209
+ prefix = f"blk.{i}"
210
+
211
+ # Layer norm 1
212
+ writer.add_tensor(f"{prefix}.ln1.weight", np.array(layer["ln1_gamma"], dtype=np.float32))
213
+ writer.add_tensor(f"{prefix}.ln1.bias", np.array(layer["ln1_beta"], dtype=np.float32))
214
+
215
+ # Attention
216
+ writer.add_tensor(f"{prefix}.attn.q.weight", np.array(layer["wq"], dtype=np.float32).T)
217
+ writer.add_tensor(f"{prefix}.attn.k.weight", np.array(layer["wk"], dtype=np.float32).T)
218
+ writer.add_tensor(f"{prefix}.attn.v.weight", np.array(layer["wv"], dtype=np.float32).T)
219
+ writer.add_tensor(f"{prefix}.attn.o.weight", np.array(layer["wo"], dtype=np.float32).T)
220
+
221
+ # Layer norm 2
222
+ writer.add_tensor(f"{prefix}.ln2.weight", np.array(layer["ln2_gamma"], dtype=np.float32))
223
+ writer.add_tensor(f"{prefix}.ln2.bias", np.array(layer["ln2_beta"], dtype=np.float32))
224
+
225
+ # FFN
226
+ writer.add_tensor(f"{prefix}.ffn_up.weight", np.array(layer["w1"], dtype=np.float32).T)
227
+ writer.add_tensor(f"{prefix}.ffn_down.weight", np.array(layer["w2"], dtype=np.float32).T)
228
+
229
+ # Output
230
+ output_proj = np.array(model_data["output_proj"], dtype=np.float32)
231
+ writer.add_tensor("output.weight", output_proj.T)
232
+
233
+ # Write file
234
+ writer.write()
235
+
236
+ print("\n" + "=" * 50)
237
+ print(f"Done! GGUF: {output_path}")
238
+ print("=" * 50)
239
+
240
+ if __name__ == "__main__":
241
+ convert()