1use std::collections::HashMap;
20use std::io::{BufReader, Read, Seek, SeekFrom};
21use std::path::Path;
22use std::sync::Mutex;
23
24use half::f16;
25
26use crate::ops::quantized_matmul_ggml::GgmlType;
27use crate::{DType, MlxBuffer, MlxBufferPool, MlxDevice, MlxError, Result};
28
29const GGUF_MAGIC: u32 = 0x4655_4747;
35
36const GGUF_VERSION: u32 = 3;
38
39const GGUF_DEFAULT_ALIGNMENT: u64 = 32;
41
42const GGUF_ALIGNMENT_KEY: &str = "general.alignment";
44
45const GGUF_TYPE_UINT8: u32 = 0;
50const GGUF_TYPE_INT8: u32 = 1;
51const GGUF_TYPE_UINT16: u32 = 2;
52const GGUF_TYPE_INT16: u32 = 3;
53const GGUF_TYPE_UINT32: u32 = 4;
54const GGUF_TYPE_INT32: u32 = 5;
55const GGUF_TYPE_FLOAT32: u32 = 6;
56const GGUF_TYPE_BOOL: u32 = 7;
57const GGUF_TYPE_STRING: u32 = 8;
58const GGUF_TYPE_ARRAY: u32 = 9;
59const GGUF_TYPE_UINT64: u32 = 10;
60const GGUF_TYPE_INT64: u32 = 11;
61const GGUF_TYPE_FLOAT64: u32 = 12;
62
63const GGML_TYPE_F32: u32 = 0;
68const GGML_TYPE_F16: u32 = 1;
69const GGML_TYPE_Q4_0: u32 = 2;
70const GGML_TYPE_Q5_1: u32 = 7;
71const GGML_TYPE_Q8_0: u32 = 8;
72const GGML_TYPE_Q4_K: u32 = 12;
73const GGML_TYPE_Q5_K: u32 = 13;
74const GGML_TYPE_Q6_K: u32 = 14;
75const GGML_TYPE_I16: u32 = 17;
76const GGML_TYPE_IQ4_NL: u32 = 20;
77const GGML_TYPE_IQ4_XS: u32 = 23;
78
79const KVALUES_IQ4_NL: [i8; 16] = [
83 -127, -104, -83, -65, -49, -35, -22, -10, 1, 13, 25, 38, 53, 69, 89, 113,
84];
85
86#[derive(Debug, Clone)]
92pub enum MetadataValue {
93 Uint8(u8),
94 Int8(i8),
95 Uint16(u16),
96 Int16(i16),
97 Uint32(u32),
98 Int32(i32),
99 Float32(f32),
100 Bool(bool),
101 String(String),
102 Array(Vec<MetadataValue>),
103 Uint64(u64),
104 Int64(i64),
105 Float64(f64),
106}
107
108impl MetadataValue {
109 pub fn as_str(&self) -> Option<&str> {
111 match self {
112 MetadataValue::String(s) => Some(s.as_str()),
113 _ => None,
114 }
115 }
116
117 pub fn as_u32(&self) -> Option<u32> {
119 match self {
120 MetadataValue::Uint32(v) => Some(*v),
121 MetadataValue::Uint8(v) => Some(*v as u32),
122 MetadataValue::Uint16(v) => Some(*v as u32),
123 MetadataValue::Int32(v) if *v >= 0 => Some(*v as u32),
124 _ => None,
125 }
126 }
127
128 pub fn as_f32(&self) -> Option<f32> {
130 match self {
131 MetadataValue::Float32(v) => Some(*v),
132 MetadataValue::Float64(v) => Some(*v as f32),
133 _ => None,
134 }
135 }
136}
137
138#[derive(Debug, Clone)]
140pub struct TensorInfo {
141 pub name: String,
143 pub shape: Vec<usize>,
145 pub ggml_type: GgmlType,
147 pub offset: u64,
149 pub byte_len: usize,
151}
152
153pub struct GgufFile {
159 metadata: HashMap<String, MetadataValue>,
160 tensors: HashMap<String, TensorInfo>,
161 tensor_data_offset: u64,
163 reader: Mutex<BufReader<std::fs::File>>,
164}
165
166fn read_u8<R: Read>(r: &mut R) -> Result<u8> {
172 let mut buf = [0u8; 1];
173 r.read_exact(&mut buf)
174 .map_err(|e| MlxError::GgufParseError(format!("read u8: {e}")))?;
175 Ok(buf[0])
176}
177
178fn read_i8<R: Read>(r: &mut R) -> Result<i8> {
180 Ok(read_u8(r)? as i8)
181}
182
183fn read_u16<R: Read>(r: &mut R) -> Result<u16> {
185 let mut buf = [0u8; 2];
186 r.read_exact(&mut buf)
187 .map_err(|e| MlxError::GgufParseError(format!("read u16: {e}")))?;
188 Ok(u16::from_le_bytes(buf))
189}
190
191fn read_i16<R: Read>(r: &mut R) -> Result<i16> {
193 let mut buf = [0u8; 2];
194 r.read_exact(&mut buf)
195 .map_err(|e| MlxError::GgufParseError(format!("read i16: {e}")))?;
196 Ok(i16::from_le_bytes(buf))
197}
198
199fn read_u32<R: Read>(r: &mut R) -> Result<u32> {
201 let mut buf = [0u8; 4];
202 r.read_exact(&mut buf)
203 .map_err(|e| MlxError::GgufParseError(format!("read u32: {e}")))?;
204 Ok(u32::from_le_bytes(buf))
205}
206
207fn read_i32<R: Read>(r: &mut R) -> Result<i32> {
209 let mut buf = [0u8; 4];
210 r.read_exact(&mut buf)
211 .map_err(|e| MlxError::GgufParseError(format!("read i32: {e}")))?;
212 Ok(i32::from_le_bytes(buf))
213}
214
215fn read_u64<R: Read>(r: &mut R) -> Result<u64> {
217 let mut buf = [0u8; 8];
218 r.read_exact(&mut buf)
219 .map_err(|e| MlxError::GgufParseError(format!("read u64: {e}")))?;
220 Ok(u64::from_le_bytes(buf))
221}
222
223fn read_i64<R: Read>(r: &mut R) -> Result<i64> {
225 let mut buf = [0u8; 8];
226 r.read_exact(&mut buf)
227 .map_err(|e| MlxError::GgufParseError(format!("read i64: {e}")))?;
228 Ok(i64::from_le_bytes(buf))
229}
230
231fn read_f32<R: Read>(r: &mut R) -> Result<f32> {
233 let mut buf = [0u8; 4];
234 r.read_exact(&mut buf)
235 .map_err(|e| MlxError::GgufParseError(format!("read f32: {e}")))?;
236 Ok(f32::from_le_bytes(buf))
237}
238
239fn read_f64<R: Read>(r: &mut R) -> Result<f64> {
241 let mut buf = [0u8; 8];
242 r.read_exact(&mut buf)
243 .map_err(|e| MlxError::GgufParseError(format!("read f64: {e}")))?;
244 Ok(f64::from_le_bytes(buf))
245}
246
247fn read_gguf_string<R: Read>(r: &mut R) -> Result<String> {
250 let len = read_u64(r)? as usize;
251 if len > 256 * 1024 * 1024 {
252 return Err(MlxError::GgufParseError(format!(
253 "string length {len} exceeds 256 MiB safety limit"
254 )));
255 }
256 let mut buf = vec![0u8; len];
257 r.read_exact(&mut buf)
258 .map_err(|e| MlxError::GgufParseError(format!("read string bytes: {e}")))?;
259 String::from_utf8(buf)
260 .map_err(|e| MlxError::GgufParseError(format!("invalid UTF-8 in string: {e}")))
261}
262
263fn read_metadata_value<R: Read>(r: &mut R, value_type: u32) -> Result<MetadataValue> {
269 match value_type {
270 GGUF_TYPE_UINT8 => Ok(MetadataValue::Uint8(read_u8(r)?)),
271 GGUF_TYPE_INT8 => Ok(MetadataValue::Int8(read_i8(r)?)),
272 GGUF_TYPE_UINT16 => Ok(MetadataValue::Uint16(read_u16(r)?)),
273 GGUF_TYPE_INT16 => Ok(MetadataValue::Int16(read_i16(r)?)),
274 GGUF_TYPE_UINT32 => Ok(MetadataValue::Uint32(read_u32(r)?)),
275 GGUF_TYPE_INT32 => Ok(MetadataValue::Int32(read_i32(r)?)),
276 GGUF_TYPE_FLOAT32 => Ok(MetadataValue::Float32(read_f32(r)?)),
277 GGUF_TYPE_BOOL => {
278 let byte = read_u8(r)?;
279 Ok(MetadataValue::Bool(byte != 0))
280 }
281 GGUF_TYPE_STRING => Ok(MetadataValue::String(read_gguf_string(r)?)),
282 GGUF_TYPE_ARRAY => {
283 let elem_type = read_u32(r)?;
284 let count = read_u64(r)? as usize;
285 if count > 64 * 1024 * 1024 {
286 return Err(MlxError::GgufParseError(format!(
287 "array count {count} exceeds 64M element safety limit"
288 )));
289 }
290 let mut elems = Vec::with_capacity(count);
291 for _ in 0..count {
292 elems.push(read_metadata_value(r, elem_type)?);
293 }
294 Ok(MetadataValue::Array(elems))
295 }
296 GGUF_TYPE_UINT64 => Ok(MetadataValue::Uint64(read_u64(r)?)),
297 GGUF_TYPE_INT64 => Ok(MetadataValue::Int64(read_i64(r)?)),
298 GGUF_TYPE_FLOAT64 => Ok(MetadataValue::Float64(read_f64(r)?)),
299 other => Err(MlxError::GgufParseError(format!(
300 "unknown metadata value type {other}"
301 ))),
302 }
303}
304
305fn ggml_type_from_u32(id: u32) -> Result<GgmlType> {
311 match id {
312 GGML_TYPE_F32 => Ok(GgmlType::F32),
313 GGML_TYPE_F16 => Ok(GgmlType::F16),
314 GGML_TYPE_Q4_0 => Ok(GgmlType::Q4_0),
315 GGML_TYPE_Q5_1 => Ok(GgmlType::Q5_1),
316 GGML_TYPE_Q8_0 => Ok(GgmlType::Q8_0),
317 GGML_TYPE_Q4_K => Ok(GgmlType::Q4_K),
318 GGML_TYPE_Q5_K => Ok(GgmlType::Q5_K),
319 GGML_TYPE_Q6_K => Ok(GgmlType::Q6_K),
320 GGML_TYPE_I16 => Ok(GgmlType::I16),
321 GGML_TYPE_IQ4_NL => Ok(GgmlType::IQ4_NL),
322 GGML_TYPE_IQ4_XS => Ok(GgmlType::IQ4_XS),
323 other => Err(MlxError::GgufParseError(format!(
324 "unsupported GGML type ID {other}"
325 ))),
326 }
327}
328
329fn compute_byte_len(shape: &[usize], ggml_type: GgmlType) -> Result<usize> {
334 let total_elements: usize = shape.iter().product();
335 if total_elements == 0 {
336 return Ok(0);
337 }
338
339 let elems_per_block = ggml_type.block_values() as usize;
340 let bytes_per_block = ggml_type.block_bytes() as usize;
341
342 if total_elements % elems_per_block != 0 {
343 return Err(MlxError::GgufParseError(format!(
344 "total elements {total_elements} not divisible by block size {elems_per_block} \
345 for type {:?}",
346 ggml_type
347 )));
348 }
349
350 Ok((total_elements / elems_per_block) * bytes_per_block)
351}
352
353#[inline]
359fn f16_from_le_bytes(bytes: [u8; 2]) -> f32 {
360 f16::from_le_bytes(bytes).to_f32()
361}
362
363fn dequantize_q4_0(data: &[u8], output: &mut [f32]) -> Result<()> {
369 const BLOCK_BYTES: usize = 18;
370 const BLOCK_ELEMS: usize = 32;
371
372 if data.len() % BLOCK_BYTES != 0 {
373 return Err(MlxError::GgufParseError(format!(
374 "Q4_0 data length {} not divisible by block size {BLOCK_BYTES}",
375 data.len()
376 )));
377 }
378
379 let num_blocks = data.len() / BLOCK_BYTES;
380 if output.len() < num_blocks * BLOCK_ELEMS {
381 return Err(MlxError::GgufParseError(
382 "Q4_0 output buffer too small".into(),
383 ));
384 }
385
386 for i in 0..num_blocks {
387 let block = &data[i * BLOCK_BYTES..(i + 1) * BLOCK_BYTES];
388 let d = f16_from_le_bytes([block[0], block[1]]);
389 let qs = &block[2..18]; let out = &mut output[i * BLOCK_ELEMS..(i + 1) * BLOCK_ELEMS];
392
393 for j in 0..16 {
394 let x0 = (qs[j] & 0x0F) as i16 - 8;
395 let x1 = (qs[j] >> 4) as i16 - 8;
396 out[j] = x0 as f32 * d;
397 out[j + 16] = x1 as f32 * d;
398 }
399 }
400 Ok(())
401}
402
403fn dequantize_q8_0(data: &[u8], output: &mut [f32]) -> Result<()> {
409 const BLOCK_BYTES: usize = 34;
410 const BLOCK_ELEMS: usize = 32;
411
412 if data.len() % BLOCK_BYTES != 0 {
413 return Err(MlxError::GgufParseError(format!(
414 "Q8_0 data length {} not divisible by block size {BLOCK_BYTES}",
415 data.len()
416 )));
417 }
418
419 let num_blocks = data.len() / BLOCK_BYTES;
420 if output.len() < num_blocks * BLOCK_ELEMS {
421 return Err(MlxError::GgufParseError(
422 "Q8_0 output buffer too small".into(),
423 ));
424 }
425
426 for i in 0..num_blocks {
427 let block = &data[i * BLOCK_BYTES..(i + 1) * BLOCK_BYTES];
428 let d = f16_from_le_bytes([block[0], block[1]]);
429 let qs = &block[2..34]; let out = &mut output[i * BLOCK_ELEMS..(i + 1) * BLOCK_ELEMS];
432
433 for j in 0..32 {
434 out[j] = (qs[j] as i8) as f32 * d;
435 }
436 }
437 Ok(())
438}
439
440#[inline]
453fn get_scale_min_k4(j: usize, scales: &[u8]) -> (u8, u8) {
454 if j < 4 {
455 let sc = scales[j] & 63;
456 let m = scales[j + 4] & 63;
457 (sc, m)
458 } else {
459 let sc = (scales[j + 4] & 0xF) | ((scales[j - 4] >> 6) << 4);
460 let m = (scales[j + 4] >> 4) | ((scales[j] >> 6) << 4);
461 (sc, m)
462 }
463}
464
465fn dequantize_q5_k(data: &[u8], output: &mut [f32]) -> Result<()> {
483 const BLOCK_BYTES: usize = 176;
484 const BLOCK_ELEMS: usize = 256;
485
486 if data.len() % BLOCK_BYTES != 0 {
487 return Err(MlxError::GgufParseError(format!(
488 "Q5_K data length {} not divisible by block size {BLOCK_BYTES}",
489 data.len()
490 )));
491 }
492
493 let num_blocks = data.len() / BLOCK_BYTES;
494 if output.len() < num_blocks * BLOCK_ELEMS {
495 return Err(MlxError::GgufParseError(
496 "Q5_K output buffer too small".into(),
497 ));
498 }
499
500 for i in 0..num_blocks {
501 let block = &data[i * BLOCK_BYTES..(i + 1) * BLOCK_BYTES];
502
503 let d = f16_from_le_bytes([block[0], block[1]]);
504 let dmin = f16_from_le_bytes([block[2], block[3]]);
505 let scales = &block[4..16]; let qh = &block[16..48]; let qs = &block[48..176]; let out = &mut output[i * BLOCK_ELEMS..(i + 1) * BLOCK_ELEMS];
510
511 let mut is = 0usize;
515 let mut u1: u8 = 1;
516 let mut u2: u8 = 2;
517 let mut ys_index = 0usize;
518 let mut ql_off = 0usize;
519
520 while ql_off < 128 {
521 let ql = &qs[ql_off..ql_off + 32];
522
523 let (sc1, m1) = get_scale_min_k4(is, scales);
524 let d1 = d * sc1 as f32;
525 let m1 = dmin * m1 as f32;
526 let (sc2, m2) = get_scale_min_k4(is + 1, scales);
527 let d2 = d * sc2 as f32;
528 let m2 = dmin * m2 as f32;
529
530 for l in 0..32 {
532 let low = (ql[l] & 0x0F) as u32;
533 let high = if (qh[l] & u1) != 0 { 16 } else { 0 };
534 let q = low + high;
535 out[ys_index] = d1 * q as f32 - m1;
536 ys_index += 1;
537 }
538 for l in 0..32 {
540 let low = (ql[l] >> 4) as u32;
541 let high = if (qh[l] & u2) != 0 { 16 } else { 0 };
542 let q = low + high;
543 out[ys_index] = d2 * q as f32 - m2;
544 ys_index += 1;
545 }
546
547 is += 2;
548 ql_off += 32;
549 u1 <<= 2;
550 u2 <<= 2;
551 }
552 }
553 Ok(())
554}
555
556fn dequantize_i16(data: &[u8], output: &mut [f32]) -> Result<()> {
565 if data.len() % 2 != 0 {
566 return Err(MlxError::GgufParseError(format!(
567 "I16 data length {} not even",
568 data.len()
569 )));
570 }
571 let num_elements = data.len() / 2;
572 if output.len() < num_elements {
573 return Err(MlxError::GgufParseError(
574 "I16 output buffer too small".into(),
575 ));
576 }
577 for i in 0..num_elements {
578 let v = i16::from_le_bytes([data[2 * i], data[2 * i + 1]]);
579 output[i] = v as f32;
580 }
581 Ok(())
582}
583
584fn dequantize_q4_k(data: &[u8], output: &mut [f32]) -> Result<()> {
596 const BLOCK_BYTES: usize = 144;
597 const BLOCK_ELEMS: usize = 256;
598
599 if data.len() % BLOCK_BYTES != 0 {
600 return Err(MlxError::GgufParseError(format!(
601 "Q4_K data length {} not divisible by block size {BLOCK_BYTES}",
602 data.len()
603 )));
604 }
605
606 let num_blocks = data.len() / BLOCK_BYTES;
607 if output.len() < num_blocks * BLOCK_ELEMS {
608 return Err(MlxError::GgufParseError(
609 "Q4_K output buffer too small".into(),
610 ));
611 }
612
613 for i in 0..num_blocks {
614 let block = &data[i * BLOCK_BYTES..(i + 1) * BLOCK_BYTES];
615
616 let d = f16_from_le_bytes([block[0], block[1]]);
617 let dmin = f16_from_le_bytes([block[2], block[3]]);
618 let scales = &block[4..16]; let qs = &block[16..144]; let out = &mut output[i * BLOCK_ELEMS..(i + 1) * BLOCK_ELEMS];
622
623 let mut is = 0usize;
627 let mut ys_index = 0usize;
628
629 let mut j = 0usize;
632 while j < 128 {
633 let q = &qs[j..j + 32];
634 let (sc1, m1) = get_scale_min_k4(is, scales);
635 let d1 = d * sc1 as f32;
636 let min1 = dmin * m1 as f32;
637 let (sc2, m2) = get_scale_min_k4(is + 1, scales);
638 let d2 = d * sc2 as f32;
639 let min2 = dmin * m2 as f32;
640
641 for byte in q.iter() {
643 out[ys_index] = d1 * (*byte & 0xF) as f32 - min1;
644 ys_index += 1;
645 }
646 for byte in q.iter() {
648 out[ys_index] = d2 * (*byte >> 4) as f32 - min2;
649 ys_index += 1;
650 }
651
652 is += 2;
653 j += 32;
654 }
655 }
656 Ok(())
657}
658
659fn dequantize_q6_k(data: &[u8], output: &mut [f32]) -> Result<()> {
670 const BLOCK_BYTES: usize = 210;
671 const BLOCK_ELEMS: usize = 256;
672
673 if data.len() % BLOCK_BYTES != 0 {
674 return Err(MlxError::GgufParseError(format!(
675 "Q6_K data length {} not divisible by block size {BLOCK_BYTES}",
676 data.len()
677 )));
678 }
679
680 let num_blocks = data.len() / BLOCK_BYTES;
681 if output.len() < num_blocks * BLOCK_ELEMS {
682 return Err(MlxError::GgufParseError(
683 "Q6_K output buffer too small".into(),
684 ));
685 }
686
687 for i in 0..num_blocks {
688 let block = &data[i * BLOCK_BYTES..(i + 1) * BLOCK_BYTES];
689
690 let ql = &block[0..128];
691 let qh = &block[128..192];
692 let sc = &block[192..208]; let d = f16_from_le_bytes([block[208], block[209]]);
694
695 let out = &mut output[i * BLOCK_ELEMS..(i + 1) * BLOCK_ELEMS];
696
697 for idx in 0..2 {
699 let ql_base = &ql[64 * idx..];
700 let qh_base = &qh[32 * idx..];
701 let sc_base = &sc[8 * idx..];
702 let out_base = &mut out[128 * idx..];
703
704 for l in 0..32 {
705 let is = l / 16; let q1 = ((ql_base[l] & 0xF) | ((qh_base[l] & 3) << 4)) as i8 - 32_i8;
708 let q2 = ((ql_base[l + 32] & 0xF) | (((qh_base[l] >> 2) & 3) << 4)) as i8
709 - 32_i8;
710 let q3 = ((ql_base[l] >> 4) | (((qh_base[l] >> 4) & 3) << 4)) as i8 - 32_i8;
711 let q4 = ((ql_base[l + 32] >> 4) | (((qh_base[l] >> 6) & 3) << 4)) as i8
712 - 32_i8;
713
714 out_base[l] = d * sc_base[is] as i8 as f32 * q1 as f32;
715 out_base[l + 32] = d * sc_base[is + 2] as i8 as f32 * q2 as f32;
716 out_base[l + 64] = d * sc_base[is + 4] as i8 as f32 * q3 as f32;
717 out_base[l + 96] = d * sc_base[is + 6] as i8 as f32 * q4 as f32;
718 }
719 }
720 }
721 Ok(())
722}
723
724fn dequantize_f16(data: &[u8], output: &mut [f32]) -> Result<()> {
726 if data.len() % 2 != 0 {
727 return Err(MlxError::GgufParseError(
728 "F16 data length not even".into(),
729 ));
730 }
731 let count = data.len() / 2;
732 if output.len() < count {
733 return Err(MlxError::GgufParseError(
734 "F16 output buffer too small".into(),
735 ));
736 }
737 for i in 0..count {
738 output[i] = f16_from_le_bytes([data[2 * i], data[2 * i + 1]]);
739 }
740 Ok(())
741}
742
743fn copy_f32(data: &[u8], output: &mut [f32]) -> Result<()> {
745 if data.len() % 4 != 0 {
746 return Err(MlxError::GgufParseError(
747 "F32 data length not multiple of 4".into(),
748 ));
749 }
750 let count = data.len() / 4;
751 if output.len() < count {
752 return Err(MlxError::GgufParseError(
753 "F32 output buffer too small".into(),
754 ));
755 }
756 for i in 0..count {
757 output[i] = f32::from_le_bytes([
758 data[4 * i],
759 data[4 * i + 1],
760 data[4 * i + 2],
761 data[4 * i + 3],
762 ]);
763 }
764 Ok(())
765}
766
767fn dequantize_q5_1(data: &[u8], output: &mut [f32]) -> Result<()> {
782 const BLOCK_BYTES: usize = 24;
783 const BLOCK_ELEMS: usize = 32;
784
785 if data.len() % BLOCK_BYTES != 0 {
786 return Err(MlxError::GgufParseError(format!(
787 "Q5_1 data length {} not divisible by block size {BLOCK_BYTES}",
788 data.len()
789 )));
790 }
791
792 let num_blocks = data.len() / BLOCK_BYTES;
793 if output.len() < num_blocks * BLOCK_ELEMS {
794 return Err(MlxError::GgufParseError(
795 "Q5_1 output buffer too small".into(),
796 ));
797 }
798
799 for i in 0..num_blocks {
800 let block = &data[i * BLOCK_BYTES..(i + 1) * BLOCK_BYTES];
801
802 let d = f16_from_le_bytes([block[0], block[1]]);
803 let m = f16_from_le_bytes([block[2], block[3]]);
804 let qh = u32::from_le_bytes([block[4], block[5], block[6], block[7]]);
805 let qs = &block[8..24]; let out = &mut output[i * BLOCK_ELEMS..(i + 1) * BLOCK_ELEMS];
808
809 for j in 0..(BLOCK_ELEMS / 2) {
810 let xh_0 = (((qh >> j) << 4) & 0x10) as u8;
814 let xh_1 = ((qh >> (j + 12)) & 0x10) as u8;
815 let x0 = ((qs[j] & 0x0F) | xh_0) as i32;
816 let x1 = ((qs[j] >> 4) | xh_1) as i32;
817 out[j] = (x0 as f32) * d + m;
818 out[j + BLOCK_ELEMS / 2] = (x1 as f32) * d + m;
819 }
820 }
821 Ok(())
822}
823
824fn dequantize_iq4_nl(data: &[u8], output: &mut [f32]) -> Result<()> {
836 const BLOCK_BYTES: usize = 18;
837 const BLOCK_ELEMS: usize = 32;
838
839 if data.len() % BLOCK_BYTES != 0 {
840 return Err(MlxError::GgufParseError(format!(
841 "IQ4_NL data length {} not divisible by block size {BLOCK_BYTES}",
842 data.len()
843 )));
844 }
845
846 let num_blocks = data.len() / BLOCK_BYTES;
847 if output.len() < num_blocks * BLOCK_ELEMS {
848 return Err(MlxError::GgufParseError(
849 "IQ4_NL output buffer too small".into(),
850 ));
851 }
852
853 for i in 0..num_blocks {
854 let block = &data[i * BLOCK_BYTES..(i + 1) * BLOCK_BYTES];
855
856 let d = f16_from_le_bytes([block[0], block[1]]);
857 let qs = &block[2..18];
858
859 let out = &mut output[i * BLOCK_ELEMS..(i + 1) * BLOCK_ELEMS];
860
861 for j in 0..(BLOCK_ELEMS / 2) {
862 let lo = (qs[j] & 0x0F) as usize;
863 let hi = (qs[j] >> 4) as usize;
864 out[j] = d * KVALUES_IQ4_NL[lo] as f32;
865 out[j + BLOCK_ELEMS / 2] = d * KVALUES_IQ4_NL[hi] as f32;
866 }
867 }
868 Ok(())
869}
870
871fn dequantize_iq4_xs(data: &[u8], output: &mut [f32]) -> Result<()> {
891 const BLOCK_BYTES: usize = 136;
892 const BLOCK_ELEMS: usize = 256;
893
894 if data.len() % BLOCK_BYTES != 0 {
895 return Err(MlxError::GgufParseError(format!(
896 "IQ4_XS data length {} not divisible by block size {BLOCK_BYTES}",
897 data.len()
898 )));
899 }
900 let num_blocks = data.len() / BLOCK_BYTES;
901 if output.len() < num_blocks * BLOCK_ELEMS {
902 return Err(MlxError::GgufParseError(
903 "IQ4_XS output buffer too small".into(),
904 ));
905 }
906 for i in 0..num_blocks {
907 let block = &data[i * BLOCK_BYTES..(i + 1) * BLOCK_BYTES];
908 let d = f16_from_le_bytes([block[0], block[1]]);
909 let scales_h = u16::from_le_bytes([block[2], block[3]]);
910 let scales_l = &block[4..8];
911 let qs = &block[8..];
912 let out = &mut output[i * BLOCK_ELEMS..(i + 1) * BLOCK_ELEMS];
913 for ib32 in 0..(BLOCK_ELEMS / 32) {
914 let lo_nibble = (scales_l[ib32 / 2] >> (4 * (ib32 % 2))) & 0xf;
915 let hi_two = ((scales_h >> (2 * ib32)) & 0x3) as u8;
916 let ls = (lo_nibble | (hi_two << 4)) as i32;
917 let dl = d * ((ls - 32) as f32);
918 let qs_sub = &qs[16 * ib32..16 * (ib32 + 1)];
919 let out_sub = &mut out[32 * ib32..32 * (ib32 + 1)];
920 for j in 0..16 {
921 let lo = (qs_sub[j] & 0x0f) as usize;
922 let hi = (qs_sub[j] >> 4) as usize;
923 out_sub[j] = dl * KVALUES_IQ4_NL[lo] as f32;
924 out_sub[j + 16] = dl * KVALUES_IQ4_NL[hi] as f32;
925 }
926 }
927 }
928 Ok(())
929}
930
931#[doc(hidden)]
936pub fn test_only_dequantize_q5_1(data: &[u8], output: &mut [f32]) -> Result<()> {
937 dequantize_q5_1(data, output)
938}
939
940#[doc(hidden)]
942pub fn test_only_dequantize_iq4_xs(data: &[u8], output: &mut [f32]) -> Result<()> {
943 dequantize_iq4_xs(data, output)
944}
945
946#[doc(hidden)]
948pub fn test_only_dequantize_iq4_nl(data: &[u8], output: &mut [f32]) -> Result<()> {
949 dequantize_iq4_nl(data, output)
950}
951
952#[doc(hidden)]
955pub fn test_only_kvalues_iq4_nl() -> [i8; 16] {
956 KVALUES_IQ4_NL
957}
958
959#[doc(hidden)]
963pub fn test_only_dequantize(data: &[u8], ggml_type: GgmlType, output: &mut [f32]) -> Result<()> {
964 dequantize_to_f32(data, ggml_type, output)
965}
966
967fn dequantize_to_f32(data: &[u8], ggml_type: GgmlType, output: &mut [f32]) -> Result<()> {
969 match ggml_type {
970 GgmlType::F32 => copy_f32(data, output),
971 GgmlType::F16 => dequantize_f16(data, output),
972 GgmlType::Q4_0 => dequantize_q4_0(data, output),
973 GgmlType::Q8_0 => dequantize_q8_0(data, output),
974 GgmlType::Q4_K => dequantize_q4_k(data, output),
975 GgmlType::Q6_K => dequantize_q6_k(data, output),
976 GgmlType::Q5_K => dequantize_q5_k(data, output),
977 GgmlType::I16 => dequantize_i16(data, output),
978 GgmlType::Q5_1 => dequantize_q5_1(data, output),
979 GgmlType::IQ4_NL => dequantize_iq4_nl(data, output),
980 GgmlType::IQ4_XS => dequantize_iq4_xs(data, output),
981 }
982}
983
984impl GgufFile {
989 pub fn open(path: &Path) -> Result<Self> {
1001 let file = std::fs::File::open(path).map_err(|e| {
1002 MlxError::IoError(format!("cannot open GGUF file '{}': {e}", path.display()))
1003 })?;
1004 let mut reader = BufReader::new(file);
1005
1006 let magic = read_u32(&mut reader)?;
1008 if magic != GGUF_MAGIC {
1009 return Err(MlxError::GgufParseError(format!(
1010 "bad magic: expected 0x{GGUF_MAGIC:08X}, got 0x{magic:08X}"
1011 )));
1012 }
1013
1014 let version = read_u32(&mut reader)?;
1015 if version != GGUF_VERSION {
1016 return Err(MlxError::GgufParseError(format!(
1017 "unsupported GGUF version {version} (only v3 is supported)"
1018 )));
1019 }
1020
1021 let tensor_count = read_u64(&mut reader)? as usize;
1022 let metadata_kv_count = read_u64(&mut reader)? as usize;
1023
1024 if tensor_count > 100_000 {
1026 return Err(MlxError::GgufParseError(format!(
1027 "tensor_count {tensor_count} exceeds 100k safety limit"
1028 )));
1029 }
1030 if metadata_kv_count > 1_000_000 {
1031 return Err(MlxError::GgufParseError(format!(
1032 "metadata_kv_count {metadata_kv_count} exceeds 1M safety limit"
1033 )));
1034 }
1035
1036 let mut metadata = HashMap::with_capacity(metadata_kv_count);
1038 for _ in 0..metadata_kv_count {
1039 let key = read_gguf_string(&mut reader)?;
1040 let value_type = read_u32(&mut reader)?;
1041 let value = read_metadata_value(&mut reader, value_type)?;
1042 metadata.insert(key, value);
1043 }
1044
1045 let alignment = metadata
1047 .get(GGUF_ALIGNMENT_KEY)
1048 .and_then(|v| v.as_u32())
1049 .map(|v| v as u64)
1050 .unwrap_or(GGUF_DEFAULT_ALIGNMENT);
1051
1052 if alignment == 0 || (alignment & (alignment - 1)) != 0 {
1053 return Err(MlxError::GgufParseError(format!(
1054 "alignment {alignment} is not a power of two"
1055 )));
1056 }
1057
1058 let mut tensors = HashMap::with_capacity(tensor_count);
1060 for _ in 0..tensor_count {
1061 let name = read_gguf_string(&mut reader)?;
1062 let n_dims = read_u32(&mut reader)? as usize;
1063
1064 if n_dims > 8 {
1065 return Err(MlxError::GgufParseError(format!(
1066 "tensor '{name}' has {n_dims} dimensions (max 8)"
1067 )));
1068 }
1069
1070 let mut shape = Vec::with_capacity(n_dims);
1071 for _ in 0..n_dims {
1072 shape.push(read_u64(&mut reader)? as usize);
1073 }
1074 shape.reverse();
1078
1079 let ggml_type_id = read_u32(&mut reader)?;
1080 let ggml_type = ggml_type_from_u32(ggml_type_id).map_err(|e| {
1081 MlxError::GgufParseError(format!("tensor '{name}': {e}"))
1082 })?;
1083
1084 let offset = read_u64(&mut reader)?;
1085 let byte_len = compute_byte_len(&shape, ggml_type).map_err(|e| {
1086 MlxError::GgufParseError(format!("tensor '{name}': {e}"))
1087 })?;
1088
1089 tensors.insert(
1090 name.clone(),
1091 TensorInfo {
1092 name,
1093 shape,
1094 ggml_type,
1095 offset,
1096 byte_len,
1097 },
1098 );
1099 }
1100
1101 let pos = reader
1105 .stream_position()
1106 .map_err(|e| MlxError::GgufParseError(format!("stream_position: {e}")))?;
1107 let tensor_data_offset = align_offset(pos, alignment);
1108
1109 Ok(GgufFile {
1110 metadata,
1111 tensors,
1112 tensor_data_offset,
1113 reader: Mutex::new(reader),
1114 })
1115 }
1116
1117 pub fn metadata(&self, key: &str) -> Option<&MetadataValue> {
1123 self.metadata.get(key)
1124 }
1125
1126 pub fn metadata_string(&self, key: &str) -> Option<&str> {
1128 self.metadata.get(key).and_then(|v| v.as_str())
1129 }
1130
1131 pub fn metadata_u32(&self, key: &str) -> Option<u32> {
1133 self.metadata.get(key).and_then(|v| v.as_u32())
1134 }
1135
1136 pub fn metadata_f32(&self, key: &str) -> Option<f32> {
1138 self.metadata.get(key).and_then(|v| v.as_f32())
1139 }
1140
1141 pub fn tensor_names(&self) -> Vec<&str> {
1147 self.tensors.keys().map(|s| s.as_str()).collect()
1148 }
1149
1150 pub fn tensor_info(&self, name: &str) -> Option<&TensorInfo> {
1152 self.tensors.get(name)
1153 }
1154
1155 pub fn tensor_count(&self) -> usize {
1157 self.tensors.len()
1158 }
1159
1160 pub fn metadata_count(&self) -> usize {
1162 self.metadata.len()
1163 }
1164
1165 pub fn tensor_data_offset(&self) -> u64 {
1171 self.tensor_data_offset
1172 }
1173
1174 fn read_tensor_bytes(&self, info: &TensorInfo) -> Result<Vec<u8>> {
1183 let abs_offset = self.tensor_data_offset + info.offset;
1184 let mut reader = self
1185 .reader
1186 .lock()
1187 .map_err(|_| MlxError::GgufParseError("reader mutex poisoned".into()))?;
1188
1189 reader
1190 .seek(SeekFrom::Start(abs_offset))
1191 .map_err(|e| MlxError::IoError(format!("seek to tensor '{}': {e}", info.name)))?;
1192
1193 let mut buf = vec![0u8; info.byte_len];
1194 reader.read_exact(&mut buf).map_err(|e| {
1195 MlxError::IoError(format!(
1196 "read tensor '{}' ({} bytes at offset {}): {e}",
1197 info.name, info.byte_len, abs_offset
1198 ))
1199 })?;
1200
1201 Ok(buf)
1202 }
1203
1204 pub fn load_tensor(&self, name: &str, device: &MlxDevice) -> Result<MlxBuffer> {
1216 let info = self.tensors.get(name).ok_or_else(|| {
1217 MlxError::GgufParseError(format!("tensor '{name}' not found in GGUF file"))
1218 })?;
1219
1220 let data = self.read_tensor_bytes(info)?;
1221
1222 match info.ggml_type {
1223 GgmlType::F32 => {
1224 let mut buf =
1225 device.alloc_buffer(info.byte_len, DType::F32, info.shape.clone())?;
1226 {
1227 let slice: &mut [u8] = buf.as_mut_slice()?;
1228 slice.copy_from_slice(&data);
1229 }
1230 Ok(buf)
1231 }
1232 GgmlType::F16 => {
1233 let mut buf =
1234 device.alloc_buffer(info.byte_len, DType::F16, info.shape.clone())?;
1235 {
1236 let slice: &mut [u8] = buf.as_mut_slice()?;
1237 slice.copy_from_slice(&data);
1238 }
1239 Ok(buf)
1240 }
1241 GgmlType::Q4_0
1242 | GgmlType::Q8_0
1243 | GgmlType::Q4_K
1244 | GgmlType::Q5_K
1245 | GgmlType::Q6_K
1246 | GgmlType::I16
1247 | GgmlType::Q5_1
1248 | GgmlType::IQ4_NL
1249 | GgmlType::IQ4_XS => {
1255 let mut buf =
1268 device.alloc_buffer(info.byte_len, DType::U8, info.shape.clone())?;
1269 {
1270 let slice: &mut [u8] = buf.as_mut_slice()?;
1271 slice.copy_from_slice(&data);
1272 }
1273 Ok(buf)
1274 }
1275 }
1276 }
1277
1278 pub fn load_tensor_f32(&self, name: &str, device: &MlxDevice) -> Result<MlxBuffer> {
1289 let info = self.tensors.get(name).ok_or_else(|| {
1290 MlxError::GgufParseError(format!("tensor '{name}' not found in GGUF file"))
1291 })?;
1292
1293 let data = self.read_tensor_bytes(info)?;
1294 let total_elements: usize = info.shape.iter().product();
1295
1296 if total_elements == 0 {
1297 return Err(MlxError::GgufParseError(format!(
1298 "tensor '{name}' has zero elements"
1299 )));
1300 }
1301
1302 let f32_byte_len = total_elements * 4;
1303 let mut buf =
1304 device.alloc_buffer(f32_byte_len, DType::F32, info.shape.clone())?;
1305
1306 {
1307 let out_slice: &mut [f32] = buf.as_mut_slice()?;
1308 dequantize_to_f32(&data, info.ggml_type, out_slice)?;
1309 }
1310
1311 Ok(buf)
1312 }
1313
1314 pub fn load_tensor_into_pool(
1350 &self,
1351 name: &str,
1352 device: &MlxDevice,
1353 pool: &mut MlxBufferPool,
1354 ) -> Result<MlxBuffer> {
1355 let buf = self.load_tensor(name, device)?;
1356 pool.register_existing(device, &buf)?;
1357 Ok(buf)
1358 }
1359}
1360
1361fn align_offset(offset: u64, alignment: u64) -> u64 {
1367 let mask = alignment - 1;
1368 (offset + mask) & !mask
1369}