1use crate::utils::{
6 get_scale_min_k4, group_for_dequantization, group_for_quantization, make_q3_quants,
7 make_qkx1_quants, make_qkx3_quants, make_qp_quants, make_qx_quants, nearest_int,
8};
9use byteorder::{ByteOrder, LittleEndian};
10use fuel_ir::Result;
11use fuel_ir::quantized::GgmlDType;
12use half::{bf16, f16, slice::HalfFloatSliceExt};
13use rayon::prelude::*;
14
15pub const QK_K: usize = 256;
17pub const K_SCALE_SIZE: usize = 12;
18
19pub const QK4_0: usize = 32;
20pub const QK4_1: usize = 32;
21pub const QK5_0: usize = 32;
22pub const QK5_1: usize = 32;
23pub const QK8_0: usize = 32;
24pub const QK8_1: usize = 32;
25
26pub trait GgmlType: Sized + Clone + Send + Sync + bytemuck::Pod {
35 const DTYPE: GgmlDType;
36 const BLCK_SIZE: usize;
37 const DIRECT_COPY: bool = false;
38 type VecDotType: GgmlType;
39
40 fn zeros() -> Self {
42 <Self as bytemuck::Zeroable>::zeroed()
43 }
44 fn to_float(xs: &[Self], ys: &mut [f32]);
45 fn from_float(xs: &[f32], ys: &mut [Self]);
46 fn from_float_imatrix(
47 _xs: &[f32],
48 _ys: &mut [Self],
49 _imatrix_weights: &[f32],
50 _n_per_row: usize,
51 ) {
52 panic!(
53 "`from_float_imatrix` is unimplemented for {:?}",
54 Self::DTYPE
55 );
56 }
57
58 fn direct_copy(_xs: &[f32], _ys: &mut [Self]) {}
59
60 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32;
63
64 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32;
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
69#[repr(C)]
70pub struct BlockQ4_0 {
71 pub(crate) d: f16,
72 pub(crate) qs: [u8; QK4_0 / 2],
73}
74const _: () = assert!(std::mem::size_of::<BlockQ4_0>() == 18);
75
76#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
77#[repr(C)]
78pub struct BlockQ4_1 {
79 pub(crate) d: f16,
80 pub(crate) m: f16,
81 pub(crate) qs: [u8; QK4_1 / 2],
82}
83const _: () = assert!(std::mem::size_of::<BlockQ4_1>() == 20);
84
85#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
86#[repr(C)]
87pub struct BlockQ5_0 {
88 pub(crate) d: f16,
89 pub(crate) qh: [u8; 4],
90 pub(crate) qs: [u8; QK5_0 / 2],
91}
92const _: () = assert!(std::mem::size_of::<BlockQ5_0>() == 22);
93
94#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
95#[repr(C)]
96pub struct BlockQ5_1 {
97 pub(crate) d: f16,
98 pub(crate) m: f16,
99 pub(crate) qh: [u8; 4],
100 pub(crate) qs: [u8; QK5_1 / 2],
101}
102const _: () = assert!(std::mem::size_of::<BlockQ5_1>() == 24);
103
104#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
105#[repr(C)]
106pub struct BlockQ8_0 {
107 pub(crate) d: f16,
108 pub(crate) qs: [i8; QK8_0],
109}
110const _: () = assert!(std::mem::size_of::<BlockQ8_0>() == 34);
111
112#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
113#[repr(C)]
114pub struct BlockQ8_1 {
115 pub(crate) d: f16,
116 pub(crate) s: f16,
117 pub(crate) qs: [i8; QK8_1],
118}
119const _: () = assert!(std::mem::size_of::<BlockQ8_1>() == 36);
120
121#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
122#[repr(C)]
123pub struct BlockQ2K {
124 pub(crate) scales: [u8; QK_K / 16],
125 pub(crate) qs: [u8; QK_K / 4],
126 pub(crate) d: f16,
127 pub(crate) dmin: f16,
128}
129const _: () = assert!(QK_K / 16 + QK_K / 4 + 2 * 2 == std::mem::size_of::<BlockQ2K>());
130
131#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
132#[repr(C)]
133pub struct BlockQ3K {
134 pub(crate) hmask: [u8; QK_K / 8],
135 pub(crate) qs: [u8; QK_K / 4],
136 pub(crate) scales: [u8; 12],
137 pub(crate) d: f16,
138}
139const _: () = assert!(QK_K / 8 + QK_K / 4 + 12 + 2 == std::mem::size_of::<BlockQ3K>());
140
141#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
142#[repr(C)]
144pub struct BlockQ4K {
145 pub(crate) d: f16,
146 pub(crate) dmin: f16,
147 pub(crate) scales: [u8; K_SCALE_SIZE],
148 pub(crate) qs: [u8; QK_K / 2],
149}
150const _: () = assert!(QK_K / 2 + K_SCALE_SIZE + 2 * 2 == std::mem::size_of::<BlockQ4K>());
151
152#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
153#[repr(C)]
154pub struct BlockQ5K {
155 pub(crate) d: f16,
156 pub(crate) dmin: f16,
157 pub(crate) scales: [u8; K_SCALE_SIZE],
158 pub(crate) qh: [u8; QK_K / 8],
159 pub(crate) qs: [u8; QK_K / 2],
160}
161const _: () =
162 assert!(QK_K / 8 + QK_K / 2 + 2 * 2 + K_SCALE_SIZE == std::mem::size_of::<BlockQ5K>());
163
164#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
165#[repr(C)]
166pub struct BlockQ6K {
167 pub(crate) ql: [u8; QK_K / 2],
168 pub(crate) qh: [u8; QK_K / 4],
169 pub(crate) scales: [i8; QK_K / 16],
170 pub(crate) d: f16,
171}
172const _: () = assert!(3 * QK_K / 4 + QK_K / 16 + 2 == std::mem::size_of::<BlockQ6K>());
173
174#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
175#[repr(C)]
176pub struct BlockQ8K {
177 pub(crate) d: f32,
178 pub(crate) qs: [i8; QK_K],
179 pub(crate) bsums: [i16; QK_K / 16],
180}
181const _: () = assert!(4 + QK_K + QK_K / 16 * 2 == std::mem::size_of::<BlockQ8K>());
182
183pub fn blocks_as_bytes<T: GgmlType>(blocks: &[T]) -> &[u8] {
188 bytemuck::cast_slice(blocks)
189}
190
191pub fn blocks_from_bytes_cow<T: GgmlType>(bytes: &[u8]) -> std::borrow::Cow<'_, [T]> {
202 let size = std::mem::size_of::<T>();
203 let whole = &bytes[..(bytes.len() / size) * size];
204 match bytemuck::try_cast_slice::<u8, T>(whole) {
205 Ok(blocks) => std::borrow::Cow::Borrowed(blocks),
206 Err(_) => std::borrow::Cow::Owned(
207 whole
208 .chunks_exact(size)
209 .map(bytemuck::pod_read_unaligned::<T>)
210 .collect(),
211 ),
212 }
213}
214
215impl GgmlType for BlockQ4_0 {
216 const DTYPE: GgmlDType = GgmlDType::Q4_0;
217 const BLCK_SIZE: usize = QK4_0;
218 type VecDotType = BlockQ8_0;
219
220 fn to_float(xs: &[Self], ys: &mut [f32]) {
222 let k = ys.len();
223 let qk = Self::BLCK_SIZE;
224 debug_assert!(
225 k.is_multiple_of(qk),
226 "dequantize_row_q4_0: {k} is not divisible by {qk}"
227 );
228
229 let nb = k / qk;
230 for i in 0..nb {
231 let d = xs[i].d.to_f32();
232
233 for j in 0..(qk / 2) {
234 let x0 = (xs[i].qs[j] & 0x0F) as i16 - 8;
235 let x1 = (xs[i].qs[j] >> 4) as i16 - 8;
236
237 ys[i * qk + j] = (x0 as f32) * d;
238 ys[i * qk + j + qk / 2] = (x1 as f32) * d;
239 }
240 }
241 }
242
243 fn from_float(xs: &[f32], ys: &mut [Self]) {
244 let qk = Self::BLCK_SIZE;
246 let k = xs.len();
247 debug_assert!(k.is_multiple_of(qk), "{k} is not divisible by {qk}");
248 debug_assert_eq!(
249 ys.len(),
250 k / qk,
251 "size mismatch {} {} {}",
252 xs.len(),
253 ys.len(),
254 qk,
255 );
256 for (i, ys) in ys.iter_mut().enumerate() {
257 let mut amax = 0f32;
258 let mut max = 0f32;
259
260 let xs = &xs[i * qk..(i + 1) * qk];
261 for &x in xs.iter() {
262 if amax < x.abs() {
263 amax = x.abs();
264 max = x;
265 }
266 }
267 let d = max / -8.0;
268 let id = if d != 0f32 { 1. / d } else { 0. };
269 ys.d = f16::from_f32(d);
270
271 for (j, q) in ys.qs.iter_mut().enumerate() {
272 let x0 = xs[j] * id;
273 let x1 = xs[qk / 2 + j] * id;
274 let xi0 = u8::min(15, (x0 + 8.5) as u8);
275 let xi1 = u8::min(15, (x1 + 8.5) as u8);
276 *q = xi0 | (xi1 << 4)
277 }
278 }
279 }
280
281 #[allow(unreachable_code)]
283 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
284 #[cfg(target_feature = "avx2")]
285 return super::avx::vec_dot_q4_0_q8_0(n, xs, ys);
286
287 #[cfg(target_feature = "neon")]
288 return super::neon::vec_dot_q4_0_q8_0(n, xs, ys);
289
290 Self::vec_dot_unopt(n, xs, ys)
291 }
292
293 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
294 debug_assert!(
295 n.is_multiple_of(QK8_0),
296 "vec_dot_q4_0_q8_0: {n} is not divisible by {QK8_0}"
297 );
298 let mut sumf = 0f32;
300 for (xs, ys) in xs.iter().zip(ys.iter()) {
301 let mut sum_i = 0;
302 for j in 0..QK8_0 / 2 {
303 let v0 = (xs.qs[j] & 0x0F) as i32 - 8;
304 let v1 = (xs.qs[j] >> 4) as i32 - 8;
305 sum_i += v0 * ys.qs[j] as i32 + v1 * ys.qs[j + QK8_0 / 2] as i32
306 }
307 sumf += sum_i as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
308 }
309 sumf
310 }
311}
312
313impl GgmlType for BlockQ4_1 {
314 const DTYPE: GgmlDType = GgmlDType::Q4_1;
315 const BLCK_SIZE: usize = QK4_1;
316 type VecDotType = BlockQ8_1;
317
318 #[allow(unreachable_code)]
319 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
320 #[cfg(target_feature = "avx2")]
321 return super::avx::vec_dot_q4_1_q8_1(n, xs, ys);
322
323 Self::vec_dot_unopt(n, xs, ys)
324 }
325
326 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
327 let qk = QK8_1;
329 debug_assert!(
330 n.is_multiple_of(qk),
331 "vec_dot_q4_1_q8_1: {n} is not divisible by {qk}"
332 );
333 debug_assert!(
334 (n / qk).is_multiple_of(2),
335 "vec_dot_q4_1_q8_1: {n}, nb is not divisible by 2"
336 );
337
338 let mut sumf = 0f32;
340
341 for (xs, ys) in xs.iter().zip(ys.iter()) {
342 let mut sumi = 0i32;
343
344 for j in 0..qk / 2 {
345 let v0 = xs.qs[j] as i32 & 0x0F;
346 let v1 = xs.qs[j] as i32 >> 4;
347 sumi += (v0 * ys.qs[j] as i32) + (v1 * ys.qs[j + qk / 2] as i32);
348 }
349
350 sumf += sumi as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
351 + f16::to_f32(xs.m) * f16::to_f32(ys.s)
352 }
353 sumf
354 }
355
356 fn from_float(xs: &[f32], ys: &mut [Self]) {
357 let qk = Self::BLCK_SIZE;
359
360 debug_assert_eq!(
361 ys.len() * qk,
362 xs.len(),
363 "size mismatch {} {} {}",
364 xs.len(),
365 ys.len(),
366 qk,
367 );
368 for (i, ys) in ys.iter_mut().enumerate() {
369 let xs = &xs[i * qk..(i + 1) * qk];
370
371 let mut min = f32::INFINITY;
372 let mut max = f32::NEG_INFINITY;
373 for &x in xs.iter() {
374 min = f32::min(x, min);
375 max = f32::max(x, max);
376 }
377 let d = (max - min) / ((1 << 4) - 1) as f32;
378 let id = if d != 0f32 { 1. / d } else { 0. };
379 ys.d = f16::from_f32(d);
380 ys.m = f16::from_f32(min);
381
382 for (j, q) in ys.qs.iter_mut().take(qk / 2).enumerate() {
383 let x0 = (xs[j] - min) * id;
384 let x1 = (xs[qk / 2 + j] - min) * id;
385
386 let xi0 = u8::min(15, (x0 + 0.5) as u8);
387 let xi1 = u8::min(15, (x1 + 0.5) as u8);
388
389 *q = xi0 | (xi1 << 4);
390 }
391 }
392 }
393
394 fn to_float(xs: &[Self], ys: &mut [f32]) {
396 let k = ys.len();
397 debug_assert!(
398 k.is_multiple_of(QK4_1),
399 "dequantize_row_q4_1: {k} is not divisible by {QK4_1}"
400 );
401
402 let nb = k / QK4_1;
403 for i in 0..nb {
404 let d = xs[i].d.to_f32();
405 let m = xs[i].m.to_f32();
406
407 for j in 0..(QK4_1 / 2) {
408 let x0 = xs[i].qs[j] & 0x0F;
409 let x1 = xs[i].qs[j] >> 4;
410
411 ys[i * QK4_1 + j] = (x0 as f32) * d + m;
412 ys[i * QK4_1 + j + QK4_1 / 2] = (x1 as f32) * d + m;
413 }
414 }
415 }
416}
417
418impl GgmlType for BlockQ5_0 {
419 const DTYPE: GgmlDType = GgmlDType::Q5_0;
420 const BLCK_SIZE: usize = QK5_0;
421 type VecDotType = BlockQ8_0;
422
423 #[allow(unreachable_code)]
424 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
425 let qk = Self::BLCK_SIZE;
426
427 debug_assert!(
428 n.is_multiple_of(qk),
429 "vec_dot_q5_0_q8_0: {n} is not divisible by {qk}"
430 );
431 debug_assert!(
432 (n / qk).is_multiple_of(2),
433 "vec_dot_q5_0_q8_0: {n}, nb is not divisible by 2"
434 );
435
436 #[cfg(target_feature = "avx2")]
437 return super::avx::vec_dot_q5_0_q8_0(n, xs, ys);
438
439 Self::vec_dot_unopt(n, xs, ys)
440 }
441
442 fn vec_dot_unopt(_n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
443 let mut sumf = 0f32;
445
446 for (xs, ys) in xs.iter().zip(ys.iter()) {
447 let qh = LittleEndian::read_u32(&xs.qh);
448 let mut sumi = 0i32;
449
450 for j in 0..Self::BLCK_SIZE / 2 {
451 let xh_0 = (((qh & (1u32 << j)) >> j) << 4) as u8;
452 let xh_1 = ((qh & (1u32 << (j + 16))) >> (j + 12)) as u8;
453
454 let x0 = ((xs.qs[j] & 0x0F) as i32 | xh_0 as i32) - 16;
455 let x1 = ((xs.qs[j] >> 4) as i32 | xh_1 as i32) - 16;
456
457 sumi += (x0 * ys.qs[j] as i32) + (x1 * ys.qs[j + Self::BLCK_SIZE / 2] as i32);
458 }
459
460 sumf += sumi as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
461 }
462 sumf
463 }
464
465 fn from_float(xs: &[f32], ys: &mut [Self]) {
466 debug_assert_eq!(
468 ys.len() * Self::BLCK_SIZE,
469 xs.len(),
470 "size mismatch {} {} {}",
471 xs.len(),
472 ys.len(),
473 Self::BLCK_SIZE,
474 );
475 for (i, ys) in ys.iter_mut().enumerate() {
476 let xs = &xs[i * Self::BLCK_SIZE..(i + 1) * Self::BLCK_SIZE];
477
478 let mut amax = 0f32;
479 let mut max = 0f32;
480 for &x in xs.iter() {
481 if amax < x.abs() {
482 amax = x.abs();
483 max = x;
484 }
485 }
486 let d = max / -16.;
487 let id = if d != 0f32 { 1. / d } else { 0. };
488 ys.d = f16::from_f32(d);
489 let mut qh = 0u32;
490 for j in 0..Self::BLCK_SIZE / 2 {
491 let x0 = xs[j] * id;
492 let x1 = xs[j + Self::BLCK_SIZE / 2] * id;
493 let xi0 = ((x0 + 16.5) as i8).min(31) as u8;
494 let xi1 = ((x1 + 16.5) as i8).min(31) as u8;
495 ys.qs[j] = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4);
496 qh |= ((xi0 as u32 & 0x10) >> 4) << j;
497 qh |= ((xi1 as u32 & 0x10) >> 4) << (j + Self::BLCK_SIZE / 2);
498 }
499 LittleEndian::write_u32(&mut ys.qh, qh)
500 }
501 }
502
503 fn to_float(xs: &[Self], ys: &mut [f32]) {
505 let k = ys.len();
506 debug_assert!(
507 k.is_multiple_of(QK5_0),
508 "dequantize_row_q5_0: {k} is not divisible by {QK5_0}"
509 );
510 let nb = k / QK5_0;
511 for i in 0..nb {
512 let d = xs[i].d.to_f32();
513 let qh: u32 = LittleEndian::read_u32(&xs[i].qh);
514
515 for j in 0..(QK5_0 / 2) {
516 let xh_0 = (((qh >> j) << 4) & 0x10) as u8;
517 let xh_1 = ((qh >> (j + 12)) & 0x10) as u8;
518
519 let x0 = ((xs[i].qs[j] & 0x0F) | xh_0) as i32 - 16;
520 let x1 = ((xs[i].qs[j] >> 4) | xh_1) as i32 - 16;
521
522 ys[i * QK5_0 + j] = (x0 as f32) * d;
523 ys[i * QK5_0 + j + QK5_0 / 2] = (x1 as f32) * d;
524 }
525 }
526 }
527}
528
529impl GgmlType for BlockQ5_1 {
530 const DTYPE: GgmlDType = GgmlDType::Q5_1;
531 const BLCK_SIZE: usize = QK5_1;
532 type VecDotType = BlockQ8_1;
533
534 #[allow(unreachable_code)]
535 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
536 #[cfg(target_feature = "avx2")]
537 return super::avx::vec_dot_q5_1_q8_1(n, xs, ys);
538
539 Self::vec_dot_unopt(n, xs, ys)
540 }
541
542 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
543 let qk = Self::BLCK_SIZE;
544 debug_assert!(
545 n.is_multiple_of(qk),
546 "vec_dot_q5_1_q8_1: {n} is not divisible by {qk}"
547 );
548 debug_assert!(
549 (n / qk).is_multiple_of(2),
550 "vec_dot_q5_1_q8_1: {n}, nb is not divisible by 2"
551 );
552
553 let mut sumf = 0f32;
555
556 for (xs, ys) in xs.iter().zip(ys.iter()) {
557 let qh = LittleEndian::read_u32(&xs.qh);
558 let mut sumi = 0i32;
559
560 for j in 0..Self::BLCK_SIZE / 2 {
561 let xh_0 = ((qh >> j) << 4) & 0x10;
562 let xh_1 = (qh >> (j + 12)) & 0x10;
563
564 let x0 = (xs.qs[j] as i32 & 0xF) | xh_0 as i32;
565 let x1 = (xs.qs[j] as i32 >> 4) | xh_1 as i32;
566
567 sumi += (x0 * ys.qs[j] as i32) + (x1 * ys.qs[j + Self::BLCK_SIZE / 2] as i32);
568 }
569
570 sumf += sumi as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
571 + f16::to_f32(xs.m) * f16::to_f32(ys.s)
572 }
573 sumf
574 }
575
576 fn from_float(xs: &[f32], ys: &mut [Self]) {
577 let qk = Self::BLCK_SIZE;
579 debug_assert_eq!(
580 ys.len() * qk,
581 xs.len(),
582 "size mismatch {} {} {}",
583 xs.len(),
584 ys.len(),
585 qk,
586 );
587 for (i, ys) in ys.iter_mut().enumerate() {
588 let xs = &xs[i * qk..(i + 1) * qk];
589
590 let mut min = f32::INFINITY;
591 let mut max = f32::NEG_INFINITY;
592 for &x in xs.iter() {
593 min = f32::min(x, min);
594 max = f32::max(x, max);
595 }
596 let d = (max - min) / ((1 << 5) - 1) as f32;
597 let id = if d != 0f32 { 1. / d } else { 0. };
598 ys.d = f16::from_f32(d);
599 ys.m = f16::from_f32(min);
600
601 let mut qh = 0u32;
602 for (j, q) in ys.qs.iter_mut().take(qk / 2).enumerate() {
603 let x0 = (xs[j] - min) * id;
604 let x1 = (xs[qk / 2 + j] - min) * id;
605
606 let xi0 = (x0 + 0.5) as u8;
607 let xi1 = (x1 + 0.5) as u8;
608
609 *q = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4);
610 qh |= ((xi0 as u32 & 0x10) >> 4) << j;
612 qh |= ((xi1 as u32 & 0x10) >> 4) << (j + qk / 2);
613 }
614 LittleEndian::write_u32(&mut ys.qh, qh);
615 }
616 }
617
618 fn to_float(xs: &[Self], ys: &mut [f32]) {
620 let k = ys.len();
621 debug_assert!(
622 k.is_multiple_of(QK5_1),
623 "dequantize_row_q5_1: {k} is not divisible by {QK5_1}"
624 );
625
626 let nb = k / QK5_1;
627 for i in 0..nb {
628 let d = xs[i].d.to_f32();
629 let m = xs[i].m.to_f32();
630 let qh: u32 = LittleEndian::read_u32(&xs[i].qh);
631
632 for j in 0..(QK5_1 / 2) {
633 let xh_0 = (((qh >> j) << 4) & 0x10) as u8;
634 let xh_1 = ((qh >> (j + 12)) & 0x10) as u8;
635
636 let x0 = (xs[i].qs[j] & 0x0F) | xh_0;
637 let x1 = (xs[i].qs[j] >> 4) | xh_1;
638
639 ys[i * QK5_1 + j] = (x0 as f32) * d + m;
640 ys[i * QK5_1 + j + QK5_1 / 2] = (x1 as f32) * d + m;
641 }
642 }
643 }
644}
645
646impl GgmlType for BlockQ8_0 {
647 const DTYPE: GgmlDType = GgmlDType::Q8_0;
648 const BLCK_SIZE: usize = QK8_0;
649 type VecDotType = BlockQ8_0;
650
651 fn to_float(xs: &[Self], ys: &mut [f32]) {
653 let k = ys.len();
654 debug_assert!(
655 k.is_multiple_of(QK8_0),
656 "dequantize_row_q8_0: {k} is not divisible by {QK8_0}"
657 );
658
659 let nb = k / QK8_0;
660
661 for i in 0..nb {
662 let d = xs[i].d.to_f32();
663
664 for j in 0..QK8_0 {
665 ys[i * QK8_0 + j] = xs[i].qs[j] as f32 * d;
666 }
667 }
668 }
669
670 fn from_float(xs: &[f32], ys: &mut [Self]) {
671 let k = xs.len();
673 debug_assert!(
674 k.is_multiple_of(Self::BLCK_SIZE),
675 "{k} is not divisible by {}",
676 Self::BLCK_SIZE
677 );
678 debug_assert_eq!(
679 ys.len(),
680 k / Self::BLCK_SIZE,
681 "size mismatch {} {} {}",
682 xs.len(),
683 ys.len(),
684 Self::BLCK_SIZE
685 );
686 for (i, ys) in ys.iter_mut().enumerate() {
687 let mut amax = 0f32;
688 let xs = &xs[i * Self::BLCK_SIZE..(i + 1) * Self::BLCK_SIZE];
689 for &x in xs.iter() {
690 amax = amax.max(x.abs())
691 }
692 let d = amax / ((1 << 7) - 1) as f32;
693 let id = if d != 0f32 { 1. / d } else { 0. };
694 ys.d = f16::from_f32(d);
695 for (y, &x) in ys.qs.iter_mut().zip(xs.iter()) {
696 *y = f32::round(x * id) as i8
697 }
698 }
699 }
700
701 #[allow(unreachable_code)]
702 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
703 #[cfg(target_feature = "avx2")]
704 return super::avx::vec_dot_q8_0_q8_0(n, xs, ys);
705
706 #[cfg(target_feature = "neon")]
707 return super::neon::vec_dot_q8_0_q8_0(n, xs, ys);
708
709 Self::vec_dot_unopt(n, xs, ys)
710 }
711
712 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
713 debug_assert!(
714 n.is_multiple_of(QK8_0),
715 "vec_dot_q8_0_q8_0: {n} is not divisible by {QK8_0}"
716 );
717
718 let mut sumf = 0f32;
720 for (xs, ys) in xs.iter().zip(ys.iter()) {
721 let sum_i = xs
722 .qs
723 .iter()
724 .zip(ys.qs.iter())
725 .map(|(&x, &y)| x as i32 * y as i32)
726 .sum::<i32>();
727 sumf += sum_i as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
728 }
729 sumf
730 }
731}
732
733impl GgmlType for BlockQ8_1 {
734 const DTYPE: GgmlDType = GgmlDType::Q8_1;
735 const BLCK_SIZE: usize = QK8_1;
736 type VecDotType = BlockQ8_1;
737
738 #[allow(unreachable_code)]
739 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
740 #[cfg(target_feature = "avx2")]
741 return super::avx::vec_dot_q8_1_q8_1(n, xs, ys);
742
743 Self::vec_dot_unopt(n, xs, ys)
744 }
745
746 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
747 debug_assert!(
748 n.is_multiple_of(QK8_1),
749 "vec_dot_q8_1_q8_1: {n} is not divisible by {QK8_1}"
750 );
751
752 let mut sumf = 0f32;
754 for (xs, ys) in xs.iter().zip(ys.iter()) {
755 let sum_i = xs
756 .qs
757 .iter()
758 .zip(ys.qs.iter())
759 .map(|(&x, &y)| x as i32 * y as i32)
760 .sum::<i32>();
761 sumf += sum_i as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
762 }
763 sumf
764 }
765
766 fn from_float(xs: &[f32], ys: &mut [Self]) {
767 debug_assert_eq!(
769 ys.len() * Self::BLCK_SIZE,
770 xs.len(),
771 "size mismatch {} {} {}",
772 xs.len(),
773 ys.len(),
774 Self::BLCK_SIZE
775 );
776 for (i, ys) in ys.iter_mut().enumerate() {
777 let mut amax = 0f32;
778 let xs = &xs[i * Self::BLCK_SIZE..(i + 1) * Self::BLCK_SIZE];
779 for &x in xs.iter() {
780 amax = amax.max(x.abs())
781 }
782 let d = amax / ((1 << 7) - 1) as f32;
783 let id = if d != 0f32 { 1. / d } else { 0. };
784 ys.d = f16::from_f32(d);
785 let mut sum = 0i32;
786 for j in 0..Self::BLCK_SIZE / 2 {
787 let v0 = xs[j] * id;
788 let v1 = xs[j + Self::BLCK_SIZE / 2] * id;
789 ys.qs[j] = f32::round(v0) as i8;
790 ys.qs[j + Self::BLCK_SIZE / 2] = f32::round(v1) as i8;
791 sum += ys.qs[j] as i32 + ys.qs[j + Self::BLCK_SIZE / 2] as i32;
792 }
793 ys.s = f16::from_f32(sum as f32) * ys.d;
794 }
795 }
796
797 fn to_float(_xs: &[Self], _ys: &mut [f32]) {
798 unimplemented!("no support for vec-dot on Q8_1") }
800}
801
802impl GgmlType for BlockQ2K {
803 const DTYPE: GgmlDType = GgmlDType::Q2K;
804 const BLCK_SIZE: usize = QK_K;
805 type VecDotType = BlockQ8K;
806
807 #[allow(unreachable_code)]
808 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
809 #[cfg(target_feature = "avx2")]
810 return super::avx::vec_dot_q2k_q8k(n, xs, ys);
811
812 #[cfg(target_feature = "neon")]
813 return super::neon::vec_dot_q2k_q8k(n, xs, ys);
814
815 Self::vec_dot_unopt(n, xs, ys)
816 }
817
818 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
819 debug_assert!(
820 n.is_multiple_of(QK_K),
821 "vec_dot_q2k_q8k: {n} is not divisible by {QK_K}"
822 );
823
824 let mut sumf = 0.0;
825 for (x, y) in xs.iter().zip(ys.iter()) {
826 let mut q2: &[_] = &x.qs;
827 let mut q8: &[_] = &y.qs;
828 let sc = &x.scales;
829
830 let mut summs = 0;
831 for (bsum, scale) in y.bsums.iter().zip(sc) {
832 summs += *bsum as i32 * ((scale >> 4) as i32);
833 }
834
835 let dall = y.d * x.d.to_f32();
836 let dmin = y.d * x.dmin.to_f32();
837
838 let mut isum = 0;
839 let mut is = 0;
840 for _ in 0..(QK_K / 128) {
841 let mut shift = 0;
842 for _ in 0..4 {
843 let d = (sc[is] & 0xF) as i32;
844 is += 1;
845 let mut isuml = 0;
846 for l in 0..16 {
847 isuml += q8[l] as i32 * (((q2[l] >> shift) & 3) as i32);
848 }
849 isum += d * isuml;
850 let d = (sc[is] & 0xF) as i32;
851 is += 1;
852 isuml = 0;
853 for l in 16..32 {
854 isuml += q8[l] as i32 * (((q2[l] >> shift) & 3) as i32);
855 }
856 isum += d * isuml;
857 shift += 2;
858 q8 = &q8[32..];
860 }
861 q2 = &q2[32..];
863 }
864 sumf += dall * isum as f32 - dmin * summs as f32;
865 }
866
867 sumf
868 }
869
870 fn from_float(xs: &[f32], ys: &mut [Self]) {
872 const Q4SCALE: f32 = 15.0;
873
874 for (block, x) in group_for_quantization(xs, ys) {
875 let mut mins: [f32; QK_K / 16] = [0.0; QK_K / 16];
877 let mut scales: [f32; QK_K / 16] = [0.0; QK_K / 16];
878
879 for (j, x_scale_slice) in x.chunks(16).enumerate() {
880 (scales[j], mins[j]) = make_qkx1_quants(3, 5, x_scale_slice);
881 }
882 let max_scale = scales.iter().fold(0.0, |max, &val| val.max(max));
884 let max_min = mins.iter().fold(0.0, |max, &val| val.max(max));
885
886 if max_scale > 0.0 {
887 let iscale = Q4SCALE / max_scale;
888 for (j, scale) in scales.iter().enumerate().take(QK_K / 16) {
889 block.scales[j] = nearest_int(iscale * scale) as u8;
890 }
891 block.d = f16::from_f32(max_scale / Q4SCALE);
892 } else {
893 for j in 0..QK_K / 16 {
894 block.scales[j] = 0;
895 }
896 block.d = f16::from_f32(0.0);
897 }
898
899 if max_min > 0.0 {
900 let iscale = Q4SCALE / max_min;
901 for (j, scale) in block.scales.iter_mut().enumerate() {
902 let l = nearest_int(iscale * mins[j]) as u8;
903 *scale |= l << 4;
904 }
905 block.dmin = f16::from_f32(max_min / Q4SCALE);
906 } else {
907 block.dmin = f16::from_f32(0.0);
908 }
909
910 let mut big_l: [u8; QK_K] = [0; QK_K];
911
912 for j in 0..QK_K / 16 {
913 let d = block.d.to_f32() * (block.scales[j] & 0xF) as f32;
914 if d == 0.0 {
915 continue;
916 }
917 let dm = block.dmin.to_f32() * (block.scales[j] >> 4) as f32;
918 for ii in 0..16 {
919 let ll = nearest_int((x[16 * j + ii] + dm) / d).clamp(0, 3);
920 big_l[16 * j + ii] = ll as u8;
921 }
922 }
923
924 for j in (0..QK_K).step_by(128) {
925 for ll in 0..32 {
926 block.qs[j / 4 + ll] = big_l[j + ll]
927 | (big_l[j + ll + 32] << 2)
928 | (big_l[j + ll + 64] << 4)
929 | (big_l[j + ll + 96] << 6);
930 }
931 }
932 }
933 }
934
935 fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
936 for (sblk_idx, (block, x)) in group_for_quantization(xs, ys).into_iter().enumerate() {
937 let mut mins: [f32; QK_K / 16] = [0.0; QK_K / 16];
938 let mut scales: [f32; QK_K / 16] = [0.0; QK_K / 16];
939 let mut weights: [f32; 16] = [0.0; 16];
940 let mut sw: [f32; QK_K / 16] = [0.0; QK_K / 16];
941 let mut ls: [u8; QK_K / 16] = [0; QK_K / 16];
942 let mut lm: [u8; QK_K / 16] = [0; QK_K / 16];
943
944 let sum_x2 = x.iter().map(|x| x * x).sum::<f32>();
945 let sigma2 = sum_x2 / QK_K as f32;
946 for (j, x_scale_slice) in x.as_chunks::<16>().0.iter().enumerate() {
947 for (l, (w_elem, x_elem)) in weights.iter_mut().zip(x_scale_slice).enumerate() {
948 let imatrix_row = sblk_idx % (n_per_row / QK_K);
949 let imatrix_w = imatrix_weights[imatrix_row * QK_K + 16 * j + l];
950 *w_elem = imatrix_w * (sigma2 + x_elem * x_elem).sqrt();
951 }
952 let sumw = weights.iter().sum::<f32>();
953 sw[j] = sumw;
954 (scales[j], mins[j]) =
955 make_qkx3_quants(3, x_scale_slice, Some(&weights), -0.9, 0.05, 36, false);
956 }
957
958 let d_block = make_qp_quants(QK_K / 16, 15, &scales, &mut ls, &sw);
959 let m_block = make_qp_quants(QK_K / 16, 15, &mins, &mut lm, &sw);
960
961 block.d = f16::from_f32(d_block);
962 block.dmin = f16::from_f32(m_block);
963
964 for j in 0..QK_K / 16 {
965 block.scales[j] = ls[j] | (lm[j] << 4);
966 }
967
968 let mut big_l: [u8; QK_K] = [0; QK_K];
969
970 for j in 0..QK_K / 16 {
971 let d = block.d.to_f32() * (block.scales[j] & 0xF) as f32;
972 if d == 0.0 {
973 continue;
974 }
975 let dm = block.dmin.to_f32() * (block.scales[j] >> 4) as f32;
976 for ii in 0..16 {
977 let ll = nearest_int((x[16 * j + ii] + dm) / d).clamp(0, 3);
978 big_l[16 * j + ii] = ll as u8;
979 }
980 }
981
982 for j in (0..QK_K).step_by(128) {
983 for ll in 0..32 {
984 block.qs[j / 4 + ll] = big_l[j + ll]
985 | (big_l[j + ll + 32] << 2)
986 | (big_l[j + ll + 64] << 4)
987 | (big_l[j + ll + 96] << 6);
988 }
989 }
990 }
991 }
992 fn to_float(xs: &[Self], ys: &mut [f32]) {
994 for (block, y) in group_for_dequantization(xs, ys) {
995 let d = block.d.to_f32();
996 let min = block.dmin.to_f32();
997
998 let mut is = 0;
999
1000 for (y_block, qs) in y
1001 .as_chunks_mut::<128>()
1002 .0
1003 .iter_mut()
1004 .zip(block.qs.as_chunks::<32>().0.iter())
1005 {
1006 let mut shift = 0;
1008 let mut y_block_index = 0;
1009 for _j in 0..4 {
1010 let sc = block.scales[is];
1011 is += 1;
1012 let dl = d * (sc & 0xF) as f32;
1013 let ml = min * (sc >> 4) as f32;
1014 for q in &qs[..16] {
1015 let y = dl * ((q >> shift) & 3) as f32 - ml;
1016 y_block[y_block_index] = y;
1017 y_block_index += 1;
1018 }
1019
1020 let sc = block.scales[is];
1021 is += 1;
1022 let dl = d * (sc & 0xF) as f32;
1023 let ml = min * (sc >> 4) as f32;
1024 for q in &qs[16..] {
1025 let y = dl * ((q >> shift) & 3) as f32 - ml;
1026 y_block[y_block_index] = y;
1027 y_block_index += 1;
1028 }
1029
1030 shift += 2;
1031 }
1032 }
1033 }
1034 }
1035}
1036
1037impl GgmlType for BlockQ3K {
1038 const DTYPE: GgmlDType = GgmlDType::Q3K;
1039 const BLCK_SIZE: usize = QK_K;
1040 type VecDotType = BlockQ8K;
1041
1042 #[allow(unreachable_code)]
1043 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1044 #[cfg(target_feature = "avx2")]
1045 return super::avx::vec_dot_q3k_q8k(n, xs, ys);
1046
1047 #[cfg(target_feature = "neon")]
1048 return super::neon::vec_dot_q3k_q8k(n, xs, ys);
1049
1050 Self::vec_dot_unopt(n, xs, ys)
1051 }
1052
1053 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1054 debug_assert!(
1055 n.is_multiple_of(QK_K),
1056 "vec_dot_q3k_q8k: {n} is not divisible by {QK_K}"
1057 );
1058
1059 const KMASK1: u32 = 0x03030303;
1060 const KMASK2: u32 = 0x0f0f0f0f;
1061
1062 let mut aux8: [i8; QK_K] = [0; QK_K];
1063 let mut aux16: [i16; 8] = [0; 8];
1064 let mut sums: [f32; 8] = [0.0; 8];
1065 let mut aux32: [i32; 8] = [0; 8];
1066
1067 let mut auxs: [u32; 4] = [0; 4];
1068
1069 for (x, y) in xs.iter().zip(ys.iter()) {
1070 let mut q3: &[u8] = &x.qs;
1071 let hmask: &[u8] = &x.hmask;
1072 let mut q8: &[i8] = &y.qs;
1073
1074 aux32.fill(0);
1075 let mut a = &mut aux8[..];
1076
1077 let mut m = 1;
1078 for _ in 0..QK_K / 128 {
1080 a.iter_mut()
1081 .take(32)
1082 .zip(q3)
1083 .for_each(|(a_val, q3_val)| *a_val = (q3_val & 3) as i8);
1084 a.iter_mut()
1085 .take(32)
1086 .zip(hmask)
1087 .for_each(|(a_val, hmask_val)| {
1088 *a_val -= if hmask_val & m != 0 { 0 } else { 4 }
1089 });
1090 a = &mut a[32..];
1091 m <<= 1;
1092
1093 a.iter_mut()
1094 .take(32)
1095 .zip(q3)
1096 .for_each(|(a_val, q3_val)| *a_val = ((q3_val >> 2) & 3) as i8);
1097 a.iter_mut()
1098 .take(32)
1099 .zip(hmask)
1100 .for_each(|(a_val, hmask_val)| {
1101 *a_val -= if hmask_val & m != 0 { 0 } else { 4 }
1102 });
1103 a = &mut a[32..];
1104 m <<= 1;
1105
1106 a.iter_mut()
1107 .take(32)
1108 .zip(q3)
1109 .for_each(|(a_val, q3_val)| *a_val = ((q3_val >> 4) & 3) as i8);
1110 a.iter_mut()
1111 .take(32)
1112 .zip(hmask)
1113 .for_each(|(a_val, hmask_val)| {
1114 *a_val -= if hmask_val & m != 0 { 0 } else { 4 }
1115 });
1116 a = &mut a[32..];
1117 m <<= 1;
1118
1119 a.iter_mut()
1120 .take(32)
1121 .zip(q3)
1122 .for_each(|(a_val, q3_val)| *a_val = ((q3_val >> 6) & 3) as i8);
1123 a.iter_mut()
1124 .take(32)
1125 .zip(hmask)
1126 .for_each(|(a_val, hmask_val)| {
1127 *a_val -= if hmask_val & m != 0 { 0 } else { 4 }
1128 });
1129 a = &mut a[32..];
1130 m <<= 1;
1131 q3 = &q3[32..];
1132 }
1133
1134 a = &mut aux8[..];
1135
1136 LittleEndian::read_u32_into(&x.scales, &mut auxs[0..3]);
1137
1138 let tmp = auxs[2];
1139 auxs[2] = ((auxs[0] >> 4) & KMASK2) | (((tmp >> 4) & KMASK1) << 4);
1140 auxs[3] = ((auxs[1] >> 4) & KMASK2) | (((tmp >> 6) & KMASK1) << 4);
1141 auxs[0] = (auxs[0] & KMASK2) | (((tmp) & KMASK1) << 4);
1142 auxs[1] = (auxs[1] & KMASK2) | (((tmp >> 2) & KMASK1) << 4);
1143
1144 for aux in auxs {
1145 for scale in aux.to_le_bytes() {
1146 let scale = i8::from_be_bytes([scale]);
1147 for l in 0..8 {
1148 aux16[l] = q8[l] as i16 * a[l] as i16;
1149 }
1150 for l in 0..8 {
1151 aux32[l] += (scale as i32 - 32) * aux16[l] as i32;
1152 }
1153 q8 = &q8[8..];
1154 a = &mut a[8..];
1155
1156 for l in 0..8 {
1157 aux16[l] = q8[l] as i16 * a[l] as i16;
1158 }
1159 for l in 0..8 {
1160 aux32[l] += (scale as i32 - 32) * aux16[l] as i32;
1161 }
1162 q8 = &q8[8..];
1163 a = &mut a[8..];
1164 }
1165 }
1166 let d = x.d.to_f32() * y.d;
1167 for l in 0..8 {
1168 sums[l] += d * aux32[l] as f32;
1169 }
1170 }
1171
1172 sums.iter().sum()
1173 }
1174
1175 fn from_float(xs: &[f32], ys: &mut [Self]) {
1176 for (block, x) in group_for_quantization(xs, ys) {
1177 let mut scales: [f32; QK_K / 16] = [0.0; QK_K / 16];
1178 for (j, x_scale_slice) in x.as_chunks::<16>().0.iter().enumerate() {
1179 scales[j] = make_q3_quants(x_scale_slice, 4, true);
1180 }
1181
1182 let mut max_scale: f32 = 0.0;
1184 for &scale in scales.iter() {
1185 if scale.abs() > max_scale.abs() {
1186 max_scale = scale;
1187 }
1188 }
1189
1190 block.scales.fill(0);
1191
1192 if max_scale != 0.0 {
1193 let iscale = -32.0 / max_scale;
1194 for (j, scale) in scales.iter().enumerate() {
1195 let l_val = nearest_int(iscale * scale);
1196 let l_val = l_val.clamp(-32, 31) + 32;
1197 if j < 8 {
1198 block.scales[j] = (l_val & 0xF) as u8;
1199 } else {
1200 block.scales[j - 8] |= ((l_val & 0xF) << 4) as u8;
1201 }
1202 let l_val = l_val >> 4;
1203 block.scales[j % 4 + 8] |= (l_val << (2 * (j / 4))) as u8;
1204 }
1205 block.d = f16::from_f32(1.0 / iscale);
1206 } else {
1207 block.d = f16::from_f32(0.0);
1208 }
1209
1210 let mut l: [i8; QK_K] = [0; QK_K];
1211
1212 for j in 0..QK_K / 16 {
1213 let sc = if j < 8 {
1214 block.scales[j] & 0xF
1215 } else {
1216 block.scales[j - 8] >> 4
1217 };
1218 let sc = (sc | (((block.scales[8 + j % 4] >> (2 * (j / 4))) & 3) << 4)) as i8 - 32;
1219 let d = block.d.to_f32() * sc as f32;
1220 if d != 0.0 {
1221 for ii in 0..16 {
1222 let l_val = nearest_int(x[16 * j + ii] / d);
1223 l[16 * j + ii] = (l_val.clamp(-4, 3) + 4) as i8;
1224 }
1225 }
1226 }
1227
1228 block.hmask.fill(0);
1229 let mut m = 0;
1230 let mut hm = 1;
1231
1232 for ll in l.iter_mut() {
1233 if *ll > 3 {
1234 block.hmask[m] |= hm;
1235 *ll -= 4;
1236 }
1237 m += 1;
1238 if m == QK_K / 8 {
1239 m = 0;
1240 hm <<= 1;
1241 }
1242 }
1243
1244 for j in (0..QK_K).step_by(128) {
1245 for l_val in 0..32 {
1246 block.qs[j / 4 + l_val] = (l[j + l_val]
1247 | (l[j + l_val + 32] << 2)
1248 | (l[j + l_val + 64] << 4)
1249 | (l[j + l_val + 96] << 6))
1250 as u8;
1251 }
1252 }
1253 }
1254 }
1255
1256 fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
1257 for (sblk_idx, (block, x)) in group_for_quantization(xs, ys).into_iter().enumerate() {
1258 let mut scales: [f32; QK_K / 16] = [0.0; QK_K / 16];
1259 let mut weights: [f32; 16] = [0.0; 16];
1260 let mut sw: [f32; QK_K / 16] = [0.0; QK_K / 16];
1261 let mut ls: [i8; QK_K / 16] = [0; QK_K / 16];
1262 let mut l: [i8; QK_K] = [0; QK_K];
1263
1264 let sum_x2 = x.iter().map(|x| x * x).sum::<f32>();
1265 let sigma2 = 2. * sum_x2 / QK_K as f32;
1266
1267 for (j, x_scale_slice) in x.as_chunks::<16>().0.iter().enumerate() {
1268 for (l_idx, (w_elem, x_elem)) in weights.iter_mut().zip(x_scale_slice).enumerate() {
1269 let imatrix_row = sblk_idx % (n_per_row / QK_K);
1270 let imatrix_w = imatrix_weights[imatrix_row * QK_K + 16 * j + l_idx];
1271 *w_elem = imatrix_w * (sigma2 + x_elem * x_elem).sqrt();
1272 }
1273 let sumw = weights.iter().sum::<f32>();
1274 sw[j] = sumw;
1275 scales[j] = unsafe {
1276 make_qx_quants(
1277 16,
1278 4,
1279 x_scale_slice.as_ptr(),
1280 l.as_mut_ptr().add(16 * j),
1281 1,
1282 weights.as_ptr(),
1283 )
1284 };
1285 }
1286
1287 block.scales.fill(0);
1288 let d_block = unsafe {
1289 make_qx_quants(
1290 QK_K / 16,
1291 32,
1292 scales.as_ptr(),
1293 ls.as_mut_ptr(),
1294 1,
1295 sw.as_ptr(),
1296 )
1297 };
1298 block.d = f16::from_f32(d_block);
1299 for (j, l_val) in ls.iter().enumerate().take(QK_K / 16) {
1300 if j < 8 {
1301 block.scales[j] = (l_val & 0xF) as u8;
1302 } else {
1303 block.scales[j - 8] |= ((l_val & 0xF) << 4) as u8;
1304 }
1305 let l_val = l_val >> 4;
1306 block.scales[j % 4 + 8] |= (l_val << (2 * (j / 4))) as u8;
1307 }
1308
1309 for j in 0..QK_K / 16 {
1310 let sc = if j < 8 {
1311 block.scales[j] & 0xF
1312 } else {
1313 block.scales[j - 8] >> 4
1314 };
1315 let sc = (sc | (((block.scales[8 + j % 4] >> (2 * (j / 4))) & 3) << 4)) as i8 - 32;
1316 let d = block.d.to_f32() * sc as f32;
1317 if d != 0.0 {
1318 for ii in 0..16 {
1319 let l_val = nearest_int(x[16 * j + ii] / d);
1320 l[16 * j + ii] = (l_val.clamp(-4, 3) + 4) as i8;
1321 }
1322 }
1323 }
1324
1325 block.hmask.fill(0);
1326 let mut m = 0;
1327 let mut hm = 1;
1328
1329 for ll in l.iter_mut() {
1330 if *ll > 3 {
1331 block.hmask[m] |= hm;
1332 *ll -= 4;
1333 }
1334 m += 1;
1335 if m == QK_K / 8 {
1336 m = 0;
1337 hm <<= 1;
1338 }
1339 }
1340
1341 for j in (0..QK_K).step_by(128) {
1342 for l_val in 0..32 {
1343 block.qs[j / 4 + l_val] = (l[j + l_val]
1344 | (l[j + l_val + 32] << 2)
1345 | (l[j + l_val + 64] << 4)
1346 | (l[j + l_val + 96] << 6))
1347 as u8;
1348 }
1349 }
1350 }
1351 }
1352
1353 fn to_float(xs: &[Self], ys: &mut [f32]) {
1355 const KMASK1: u32 = 0x03030303;
1356 const KMASK2: u32 = 0x0f0f0f0f;
1357
1358 for (block, y) in group_for_dequantization(xs, ys) {
1359 let mut aux = [0; 4];
1361 LittleEndian::read_u32_into(&block.scales, &mut aux[0..3]);
1362
1363 let tmp = aux[2];
1364 aux[2] = ((aux[0] >> 4) & KMASK2) | (((tmp >> 4) & KMASK1) << 4);
1365 aux[3] = ((aux[1] >> 4) & KMASK2) | (((tmp >> 6) & KMASK1) << 4);
1366 aux[0] = (aux[0] & KMASK2) | (((tmp) & KMASK1) << 4);
1367 aux[1] = (aux[1] & KMASK2) | (((tmp >> 2) & KMASK1) << 4);
1368
1369 let scales: &mut [i8] =
1371 unsafe { std::slice::from_raw_parts_mut(aux.as_mut_ptr() as *mut i8, 16) };
1372
1373 let d_all = block.d.to_f32();
1374 let mut m = 1;
1375 let mut is = 0;
1376
1377 for (y, qs) in y
1381 .as_chunks_mut::<128>()
1382 .0
1383 .iter_mut()
1384 .zip(block.qs.as_chunks::<32>().0.iter())
1385 {
1386 let mut shift = 0;
1387 for shift_scoped_y in y.as_chunks_mut::<32>().0.iter_mut() {
1388 for (scale_index, scale_scoped_y) in shift_scoped_y
1389 .as_chunks_mut::<16>()
1390 .0
1391 .iter_mut()
1392 .enumerate()
1393 {
1394 let dl = d_all * (scales[is] as f32 - 32.0);
1395 for (i, inner_y) in scale_scoped_y.iter_mut().enumerate() {
1396 let new_y = dl
1397 * (((qs[i + 16 * scale_index] >> shift) & 3) as i8
1398 - if (block.hmask[i + 16 * scale_index] & m) == 0 {
1399 4
1400 } else {
1401 0
1402 }) as f32;
1403 *inner_y = new_y;
1404 }
1405 is += 1;
1407 }
1408 shift += 2;
1410 m <<= 1;
1411 }
1412 }
1413 }
1414 }
1415}
1416
1417impl GgmlType for BlockQ4K {
1418 const DTYPE: GgmlDType = GgmlDType::Q4K;
1419 const BLCK_SIZE: usize = QK_K;
1420 type VecDotType = BlockQ8K;
1421
1422 #[allow(unreachable_code)]
1423 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1424 #[cfg(target_feature = "avx2")]
1425 return super::avx::vec_dot_q4k_q8k(n, xs, ys);
1426
1427 #[cfg(target_feature = "neon")]
1428 return super::neon::vec_dot_q4k_q8k(n, xs, ys);
1429
1430 Self::vec_dot_unopt(n, xs, ys)
1431 }
1432
1433 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1434 debug_assert!(
1435 n.is_multiple_of(QK_K),
1436 "vec_dot_q4k_q8k: {n} is not divisible by {QK_K}"
1437 );
1438
1439 const KMASK1: u32 = 0x3f3f3f3f;
1440 const KMASK2: u32 = 0x0f0f0f0f;
1441 const KMASK3: u32 = 0x03030303;
1442
1443 let mut utmp: [u32; 4] = [0; 4];
1444 let mut scales: [u8; 8] = [0; 8];
1445 let mut mins: [u8; 8] = [0; 8];
1446
1447 let mut aux8: [i8; QK_K] = [0; QK_K];
1448 let mut aux16: [i16; 8] = [0; 8];
1449 let mut sums: [f32; 8] = [0.0; 8];
1450 let mut aux32: [i32; 8] = [0; 8];
1451
1452 let mut sumf = 0.0;
1453 for (y, x) in ys.iter().zip(xs.iter()) {
1454 let q4 = &x.qs;
1455 let q8 = &y.qs;
1456 aux32.fill(0);
1457
1458 let mut a = &mut aux8[..];
1459 let mut q4 = &q4[..];
1460 for _ in 0..QK_K / 64 {
1461 for l in 0..32 {
1462 a[l] = (q4[l] & 0xF) as i8;
1463 }
1464 a = &mut a[32..];
1465 for l in 0..32 {
1466 a[l] = (q4[l] >> 4) as i8;
1467 }
1468 a = &mut a[32..];
1469 q4 = &q4[32..];
1470 }
1471
1472 LittleEndian::read_u32_into(&x.scales, &mut utmp[0..3]);
1473
1474 utmp[3] = ((utmp[2] >> 4) & KMASK2) | (((utmp[1] >> 6) & KMASK3) << 4);
1475 let uaux = utmp[1] & KMASK1;
1476 utmp[1] = (utmp[2] & KMASK2) | (((utmp[0] >> 6) & KMASK3) << 4);
1477 utmp[2] = uaux;
1478 utmp[0] &= KMASK1;
1479
1480 LittleEndian::write_u32_into(&utmp[0..2], &mut scales);
1482 LittleEndian::write_u32_into(&utmp[2..4], &mut mins);
1483
1484 let mut sumi = 0;
1485 for j in 0..QK_K / 16 {
1486 sumi += y.bsums[j] as i32 * mins[j / 2] as i32;
1487 }
1488
1489 let mut a = &mut aux8[..];
1490 let mut q8 = &q8[..];
1491
1492 for scale in scales {
1493 let scale = scale as i32;
1494 for _ in 0..4 {
1495 for l in 0..8 {
1496 aux16[l] = q8[l] as i16 * a[l] as i16;
1497 }
1498 for l in 0..8 {
1499 aux32[l] += scale * aux16[l] as i32;
1500 }
1501 q8 = &q8[8..];
1502 a = &mut a[8..];
1503 }
1504 }
1505 let d = x.d.to_f32() * y.d;
1506 for l in 0..8 {
1507 sums[l] += d * aux32[l] as f32;
1508 }
1509 let dmin = x.dmin.to_f32() * y.d;
1510 sumf -= dmin * sumi as f32;
1511 }
1512 sumf + sums.iter().sum::<f32>()
1513 }
1514
1515 fn from_float(xs: &[f32], ys: &mut [Self]) {
1516 for (block, x) in group_for_quantization(xs, ys) {
1517 let mut mins: [f32; QK_K / 32] = [0.0; QK_K / 32];
1518 let mut scales: [f32; QK_K / 32] = [0.0; QK_K / 32];
1519
1520 for (j, x_scale_slice) in x.as_chunks::<32>().0.iter().enumerate() {
1521 (scales[j], mins[j]) = make_qkx1_quants(15, 5, x_scale_slice);
1522 }
1523
1524 let max_scale = scales.iter().fold(0.0, |max, &val| val.max(max));
1526 let max_min = mins.iter().fold(0.0, |max, &val| val.max(max));
1527
1528 let inv_scale = if max_scale > 0.0 {
1529 63.0 / max_scale
1530 } else {
1531 0.0
1532 };
1533 let inv_min = if max_min > 0.0 { 63.0 / max_min } else { 0.0 };
1534
1535 for j in 0..QK_K / 32 {
1536 let ls = nearest_int(inv_scale * scales[j]).min(63) as u8;
1537 let lm = nearest_int(inv_min * mins[j]).min(63) as u8;
1538 if j < 4 {
1539 block.scales[j] = ls;
1540 block.scales[j + 4] = lm;
1541 } else {
1542 block.scales[j + 4] = (ls & 0xF) | ((lm & 0xF) << 4);
1543 block.scales[j - 4] |= (ls >> 4) << 6;
1544 block.scales[j] |= (lm >> 4) << 6;
1545 }
1546 }
1547
1548 block.d = f16::from_f32(max_scale / 63.0);
1549 block.dmin = f16::from_f32(max_min / 63.0);
1550
1551 let mut l: [u8; QK_K] = [0; QK_K];
1552
1553 for j in 0..QK_K / 32 {
1554 let (sc, m) = get_scale_min_k4(j, &block.scales);
1555 let d = block.d.to_f32() * sc as f32;
1556 if d != 0.0 {
1557 let dm = block.dmin.to_f32() * m as f32;
1558 for ii in 0..32 {
1559 let l_val = nearest_int((x[32 * j + ii] + dm) / d);
1560 l[32 * j + ii] = l_val.clamp(0, 15) as u8;
1561 }
1562 }
1563 }
1564
1565 let q = &mut block.qs;
1566 for j in (0..QK_K).step_by(64) {
1567 for l_val in 0..32 {
1568 let offset_index = (j / 64) * 32 + l_val;
1569 q[offset_index] = l[j + l_val] | (l[j + l_val + 32] << 4);
1570 }
1571 }
1572 }
1573 }
1574
1575 fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
1576 for (sblk_idx, (block, x)) in group_for_quantization(xs, ys).into_iter().enumerate() {
1577 let mut mins: [f32; QK_K / 32] = [0.0; QK_K / 32];
1578 let mut scales: [f32; QK_K / 32] = [0.0; QK_K / 32];
1579 let mut weights: [f32; 32] = [0.0; 32];
1580 let mut sw: [f32; QK_K / 32] = [0.0; QK_K / 32];
1581 let mut ls: [u8; QK_K / 32] = [0; QK_K / 32];
1582 let mut lm: [u8; QK_K / 32] = [0; QK_K / 32];
1583
1584 let sum_x2 = x.iter().map(|x| x * x).sum::<f32>();
1585 let sigma2 = 2. * sum_x2 / QK_K as f32;
1586
1587 for (j, x_scale_slice) in x.as_chunks::<32>().0.iter().enumerate() {
1588 for (l, (w_elem, x_elem)) in weights.iter_mut().zip(x_scale_slice).enumerate() {
1589 let imatrix_row = sblk_idx % (n_per_row / QK_K);
1590 let imatrix_w = imatrix_weights[imatrix_row * QK_K + 32 * j + l];
1591 *w_elem = imatrix_w * (sigma2 + x_elem * x_elem).sqrt();
1592 }
1593 let sumw = weights.iter().sum::<f32>();
1594 sw[j] = sumw;
1595 (scales[j], mins[j]) =
1596 make_qkx3_quants(15, x_scale_slice, Some(&weights), -0.9, 0.05, 36, false);
1597 }
1598
1599 let d_block = make_qp_quants(QK_K / 32, 63, &scales, &mut ls, &sw);
1600 let m_block = make_qp_quants(QK_K / 32, 63, &mins, &mut lm, &sw);
1601 for j in 0..QK_K / 32 {
1602 let ls_val = ls[j];
1603 let lm_val = lm[j];
1604 if j < 4 {
1605 block.scales[j] = ls_val;
1606 block.scales[j + 4] = lm_val;
1607 } else {
1608 block.scales[j + 4] = (ls_val & 0xF) | ((lm_val & 0xF) << 4);
1609 block.scales[j - 4] |= (ls_val >> 4) << 6;
1610 block.scales[j] |= (lm_val >> 4) << 6;
1611 }
1612 }
1613
1614 block.d = f16::from_f32(d_block);
1615 block.dmin = f16::from_f32(m_block);
1616
1617 let mut l: [u8; QK_K] = [0; QK_K];
1618 for j in 0..QK_K / 32 {
1619 let (sc, m) = get_scale_min_k4(j, &block.scales);
1620 let d = block.d.to_f32() * sc as f32;
1621 if d != 0.0 {
1622 let dm = block.dmin.to_f32() * m as f32;
1623 for ii in 0..32 {
1624 let l_val = nearest_int((x[32 * j + ii] + dm) / d);
1625 l[32 * j + ii] = l_val.clamp(0, 15) as u8;
1626 }
1627 }
1628 }
1629
1630 let q = &mut block.qs;
1631 for j in (0..QK_K).step_by(64) {
1632 for l_val in 0..32 {
1633 let offset_index = (j / 64) * 32 + l_val;
1634 q[offset_index] = l[j + l_val] | (l[j + l_val + 32] << 4);
1635 }
1636 }
1637 }
1638 }
1639 fn to_float(xs: &[Self], ys: &mut [f32]) {
1641 for (block, y) in group_for_dequantization(xs, ys) {
1642 let d = block.d.to_f32();
1643 let min = block.dmin.to_f32();
1644 let q = &block.qs;
1645 let mut is = 0;
1646 let mut ys_index = 0;
1647
1648 for j in (0..QK_K).step_by(64) {
1649 let q = &q[j / 2..j / 2 + 32];
1650 let (sc, m) = get_scale_min_k4(is, &block.scales);
1651 let d1 = d * sc as f32;
1652 let m1 = min * m as f32;
1653 let (sc, m) = get_scale_min_k4(is + 1, &block.scales);
1654 let d2 = d * sc as f32;
1655 let m2 = min * m as f32;
1656 for q in q {
1657 y[ys_index] = d1 * (q & 0xF) as f32 - m1;
1658 ys_index += 1;
1659 }
1660 for q in q {
1661 y[ys_index] = d2 * (q >> 4) as f32 - m2;
1662 ys_index += 1;
1663 }
1664 is += 2;
1665 }
1666 }
1667 }
1668}
1669
1670impl GgmlType for BlockQ5K {
1672 const DTYPE: GgmlDType = GgmlDType::Q5K;
1673 const BLCK_SIZE: usize = QK_K;
1674 type VecDotType = BlockQ8K;
1675
1676 #[allow(unreachable_code)]
1677 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1678 #[cfg(target_feature = "avx2")]
1679 return super::avx::vec_dot_q5k_q8k(n, xs, ys);
1680
1681 #[cfg(target_feature = "neon")]
1682 return super::neon::vec_dot_q5k_q8k(n, xs, ys);
1683
1684 Self::vec_dot_unopt(n, xs, ys)
1685 }
1686
1687 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1688 debug_assert!(
1689 n.is_multiple_of(QK_K),
1690 "vec_dot_q5k_q8k: {n} is not divisible by {QK_K}"
1691 );
1692
1693 const KMASK1: u32 = 0x3f3f3f3f;
1694 const KMASK2: u32 = 0x0f0f0f0f;
1695 const KMASK3: u32 = 0x03030303;
1696
1697 let mut utmp: [u32; 4] = [0; 4];
1698 let mut scales: [u8; 8] = [0; 8];
1699 let mut mins: [u8; 8] = [0; 8];
1700
1701 let mut aux8: [i8; QK_K] = [0; QK_K];
1702 let mut aux16: [i16; 8] = [0; 8];
1703 let mut sums: [f32; 8] = [0.0; 8];
1704 let mut aux32: [i32; 8] = [0; 8];
1705
1706 let mut sumf = 0.0;
1707 for (y, x) in ys.iter().zip(xs.iter()) {
1708 let q5 = &x.qs;
1709 let hm = &x.qh;
1710 let q8 = &y.qs;
1711 aux32.fill(0);
1712
1713 let mut a = &mut aux8[..];
1714 let mut q5 = &q5[..];
1715 let mut m = 1u8;
1716
1717 for _ in 0..QK_K / 64 {
1718 for l in 0..32 {
1719 a[l] = (q5[l] & 0xF) as i8;
1720 a[l] += if hm[l] & m != 0 { 16 } else { 0 };
1721 }
1722 a = &mut a[32..];
1723 m <<= 1;
1724 for l in 0..32 {
1725 a[l] = (q5[l] >> 4) as i8;
1726 a[l] += if hm[l] & m != 0 { 16 } else { 0 };
1727 }
1728 a = &mut a[32..];
1729 m <<= 1;
1730 q5 = &q5[32..];
1731 }
1732
1733 LittleEndian::read_u32_into(&x.scales, &mut utmp[0..3]);
1734
1735 utmp[3] = ((utmp[2] >> 4) & KMASK2) | (((utmp[1] >> 6) & KMASK3) << 4);
1736 let uaux = utmp[1] & KMASK1;
1737 utmp[1] = (utmp[2] & KMASK2) | (((utmp[0] >> 6) & KMASK3) << 4);
1738 utmp[2] = uaux;
1739 utmp[0] &= KMASK1;
1740
1741 LittleEndian::write_u32_into(&utmp[0..2], &mut scales);
1743 LittleEndian::write_u32_into(&utmp[2..4], &mut mins);
1744
1745 let mut sumi = 0;
1746 for j in 0..QK_K / 16 {
1747 sumi += y.bsums[j] as i32 * mins[j / 2] as i32;
1748 }
1749
1750 let mut a = &mut aux8[..];
1751 let mut q8 = &q8[..];
1752
1753 for scale in scales {
1754 let scale = scale as i32;
1755 for _ in 0..4 {
1756 for l in 0..8 {
1757 aux16[l] = q8[l] as i16 * a[l] as i16;
1758 }
1759 for l in 0..8 {
1760 aux32[l] += scale * aux16[l] as i32;
1761 }
1762 q8 = &q8[8..];
1763 a = &mut a[8..];
1764 }
1765 }
1766 let d = x.d.to_f32() * y.d;
1767 for l in 0..8 {
1768 sums[l] += d * aux32[l] as f32;
1769 }
1770 let dmin = x.dmin.to_f32() * y.d;
1771 sumf -= dmin * sumi as f32;
1772 }
1773 sumf + sums.iter().sum::<f32>()
1774 }
1775
1776 fn from_float(xs: &[f32], ys: &mut [Self]) {
1778 for (block, x) in group_for_quantization(xs, ys) {
1779 let mut mins: [f32; QK_K / 32] = [0.0; QK_K / 32];
1780 let mut scales: [f32; QK_K / 32] = [0.0; QK_K / 32];
1781
1782 for (j, x_scale_slice) in x.as_chunks::<32>().0.iter().enumerate() {
1783 (scales[j], mins[j]) = make_qkx1_quants(31, 5, x_scale_slice);
1784 }
1785
1786 let max_scale = scales.iter().fold(0.0, |max, &val| val.max(max));
1788 let max_min = mins.iter().fold(0.0, |max, &val| val.max(max));
1789
1790 let inv_scale = if max_scale > 0.0 {
1791 63.0 / max_scale
1792 } else {
1793 0.0
1794 };
1795 let inv_min = if max_min > 0.0 { 63.0 / max_min } else { 0.0 };
1796 for j in 0..QK_K / 32 {
1797 let ls = nearest_int(inv_scale * scales[j]).min(63) as u8;
1798 let lm = nearest_int(inv_min * mins[j]).min(63) as u8;
1799 if j < 4 {
1800 block.scales[j] = ls;
1801 block.scales[j + 4] = lm;
1802 } else {
1803 block.scales[j + 4] = (ls & 0xF) | ((lm & 0xF) << 4);
1804 block.scales[j - 4] |= (ls >> 4) << 6;
1805 block.scales[j] |= (lm >> 4) << 6;
1806 }
1807 }
1808 block.d = f16::from_f32(max_scale / 63.0);
1809 block.dmin = f16::from_f32(max_min / 63.0);
1810
1811 let mut l: [u8; QK_K] = [0; QK_K];
1812 for j in 0..QK_K / 32 {
1813 let (sc, m) = get_scale_min_k4(j, &block.scales);
1814 let d = block.d.to_f32() * sc as f32;
1815 if d == 0.0 {
1816 continue;
1817 }
1818 let dm = block.dmin.to_f32() * m as f32;
1819 for ii in 0..32 {
1820 let ll = nearest_int((x[32 * j + ii] + dm) / d);
1821 l[32 * j + ii] = ll.clamp(0, 31) as u8;
1822 }
1823 }
1824
1825 let qh = &mut block.qh;
1826 let ql = &mut block.qs;
1827 qh.fill(0);
1828
1829 let mut m1 = 1;
1830 let mut m2 = 2;
1831 for n in (0..QK_K).step_by(64) {
1832 let offset = (n / 64) * 32;
1833 for j in 0..32 {
1834 let mut l1 = l[n + j];
1835 if l1 > 15 {
1836 l1 -= 16;
1837 qh[j] |= m1;
1838 }
1839 let mut l2 = l[n + j + 32];
1840 if l2 > 15 {
1841 l2 -= 16;
1842 qh[j] |= m2;
1843 }
1844 ql[offset + j] = l1 | (l2 << 4);
1845 }
1846 m1 <<= 2;
1847 m2 <<= 2;
1848 }
1849 }
1850 }
1851
1852 fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
1853 for (sblk_idx, (block, x)) in group_for_quantization(xs, ys).into_iter().enumerate() {
1854 let mut mins: [f32; QK_K / 32] = [0.0; QK_K / 32];
1855 let mut scales: [f32; QK_K / 32] = [0.0; QK_K / 32];
1856 let mut weights: [f32; 32] = [0.0; 32];
1857 let mut sw: [f32; QK_K / 32] = [0.0; QK_K / 32];
1858 let mut ls: [u8; QK_K / 32] = [0; QK_K / 32];
1859 let mut lm: [u8; QK_K / 32] = [0; QK_K / 32];
1860
1861 let sum_x2 = x.iter().map(|x| x * x).sum::<f32>();
1862 let sigma2 = 2. * sum_x2 / QK_K as f32;
1863
1864 for (j, x_scale_slice) in x.as_chunks::<32>().0.iter().enumerate() {
1865 for (l, (w_elem, x_elem)) in weights.iter_mut().zip(x_scale_slice).enumerate() {
1866 let imatrix_row = sblk_idx % (n_per_row / QK_K);
1867 let imatrix_w = imatrix_weights[imatrix_row * QK_K + 32 * j + l];
1868 *w_elem = imatrix_w * (sigma2 + x_elem * x_elem).sqrt();
1869 }
1870 let sumw = weights.iter().sum::<f32>();
1871 sw[j] = sumw;
1872 (scales[j], mins[j]) =
1873 make_qkx3_quants(31, x_scale_slice, Some(&weights), -0.9, 0.05, 36, false);
1874 }
1875
1876 let d_block = make_qp_quants(QK_K / 32, 63, &scales, &mut ls, &sw);
1877 let m_block = make_qp_quants(QK_K / 32, 63, &mins, &mut lm, &sw);
1878 for j in 0..QK_K / 32 {
1879 let ls_val = ls[j].min(63);
1880 let lm_val = lm[j].min(63);
1881 if j < 4 {
1882 block.scales[j] = ls_val;
1883 block.scales[j + 4] = lm_val;
1884 } else {
1885 block.scales[j + 4] = (ls_val & 0xF) | ((lm_val & 0xF) << 4);
1886 block.scales[j - 4] |= (ls_val >> 4) << 6;
1887 block.scales[j] |= (lm_val >> 4) << 6;
1888 }
1889 }
1890
1891 block.d = f16::from_f32(d_block);
1892 block.dmin = f16::from_f32(m_block);
1893
1894 let mut l: [u8; QK_K] = [0; QK_K];
1895 for j in 0..QK_K / 32 {
1896 let (sc, m) = get_scale_min_k4(j, &block.scales);
1897 let d = block.d.to_f32() * sc as f32;
1898 if d != 0.0 {
1899 let dm = block.dmin.to_f32() * m as f32;
1900 for ii in 0..32 {
1901 let l_val = nearest_int((x[32 * j + ii] + dm) / d);
1902 l[32 * j + ii] = l_val.clamp(0, 31) as u8;
1903 }
1904 }
1905 }
1906
1907 let qh = &mut block.qh;
1908 let ql = &mut block.qs;
1909 qh.fill(0);
1910
1911 let mut m1 = 1;
1912 let mut m2 = 2;
1913 for n in (0..QK_K).step_by(64) {
1914 let offset = (n / 64) * 32;
1915 for j in 0..32 {
1916 let mut l1 = l[n + j];
1917 if l1 > 15 {
1918 l1 -= 16;
1919 qh[j] |= m1;
1920 }
1921 let mut l2 = l[n + j + 32];
1922 if l2 > 15 {
1923 l2 -= 16;
1924 qh[j] |= m2;
1925 }
1926 ql[offset + j] = l1 | (l2 << 4);
1927 }
1928 m1 <<= 2;
1929 m2 <<= 2;
1930 }
1931 }
1932 }
1933
1934 fn to_float(xs: &[Self], ys: &mut [f32]) {
1936 for (block, y) in group_for_dequantization(xs, ys) {
1937 let d = block.d.to_f32();
1938 let min = block.dmin.to_f32();
1939 let ql = &block.qs;
1940 let qh = &block.qh;
1941 let mut is = 0;
1942 let mut u1 = 1;
1943 let mut u2 = 2;
1944 let mut ys_index = 0;
1945
1946 for j in (0..QK_K).step_by(64) {
1947 let ql = &ql[j / 2..j / 2 + 32];
1948 let (sc, m) = get_scale_min_k4(is, &block.scales);
1949 let d1 = d * sc as f32;
1950 let m1 = min * m as f32;
1951 let (sc, m) = get_scale_min_k4(is + 1, &block.scales);
1952 let d2 = d * sc as f32;
1953 let m2 = min * m as f32;
1954 for (ql, qh) in ql.iter().zip(qh) {
1955 let to_add = if qh & u1 != 0 { 16f32 } else { 0f32 };
1956 y[ys_index] = d1 * ((ql & 0xF) as f32 + to_add) - m1;
1957 ys_index += 1;
1958 }
1959 for (ql, qh) in ql.iter().zip(qh) {
1960 let to_add = if qh & u2 != 0 { 16f32 } else { 0f32 };
1961 y[ys_index] = d2 * ((ql >> 4) as f32 + to_add) - m2;
1962 ys_index += 1;
1963 }
1964 is += 2;
1965 u1 <<= 2;
1966 u2 <<= 2;
1967 }
1968 }
1969 }
1970}
1971
1972impl GgmlType for BlockQ6K {
1973 const DTYPE: GgmlDType = GgmlDType::Q6K;
1974 const BLCK_SIZE: usize = QK_K;
1975 type VecDotType = BlockQ8K;
1976
1977 #[allow(unreachable_code)]
1978 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1979 #[cfg(target_feature = "avx2")]
1980 return super::avx::vec_dot_q6k_q8k(n, xs, ys);
1981
1982 #[cfg(target_feature = "neon")]
1983 return super::neon::vec_dot_q6k_q8k(n, xs, ys);
1984
1985 Self::vec_dot_unopt(n, xs, ys)
1986 }
1987
1988 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1989 debug_assert!(
1990 n.is_multiple_of(QK_K),
1991 "vec_dot_q6k_q8k: {n} is not divisible by {QK_K}"
1992 );
1993
1994 let mut aux8 = [0i8; QK_K];
1995 let mut aux16 = [0i16; 8];
1996 let mut sums = [0f32; 8];
1997 let mut aux32 = [0f32; 8];
1998
1999 for (x, y) in xs.iter().zip(ys.iter()) {
2000 let q4 = &x.ql;
2001 let qh = &x.qh;
2002 let q8 = &y.qs;
2003 aux32.fill(0f32);
2004
2005 for j in (0..QK_K).step_by(128) {
2006 let aux8 = &mut aux8[j..];
2007 let q4 = &q4[j / 2..];
2008 let qh = &qh[j / 4..];
2009 for l in 0..32 {
2010 aux8[l] = (((q4[l] & 0xF) | ((qh[l] & 3) << 4)) as i32 - 32) as i8;
2011 aux8[l + 32] =
2012 (((q4[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) as i32 - 32) as i8;
2013 aux8[l + 64] = (((q4[l] >> 4) | (((qh[l] >> 4) & 3) << 4)) as i32 - 32) as i8;
2014 aux8[l + 96] =
2015 (((q4[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) as i32 - 32) as i8;
2016 }
2017 }
2018
2019 for (j, &scale) in x.scales.iter().enumerate() {
2020 let scale = scale as f32;
2021 let q8 = &q8[16 * j..];
2022 let aux8 = &aux8[16 * j..];
2023 for l in 0..8 {
2024 aux16[l] = q8[l] as i16 * aux8[l] as i16;
2025 }
2026 for l in 0..8 {
2027 aux32[l] += scale * aux16[l] as f32
2028 }
2029 let q8 = &q8[8..];
2030 let aux8 = &aux8[8..];
2031 for l in 0..8 {
2032 aux16[l] = q8[l] as i16 * aux8[l] as i16;
2033 }
2034 for l in 0..8 {
2035 aux32[l] += scale * aux16[l] as f32
2036 }
2037 }
2038
2039 let d = x.d.to_f32() * y.d;
2040 for (sum, &a) in sums.iter_mut().zip(aux32.iter()) {
2041 *sum += a * d;
2042 }
2043 }
2044 sums.iter().sum()
2045 }
2046
2047 fn from_float(xs: &[f32], ys: &mut [Self]) {
2048 debug_assert_eq!(
2049 xs.len(),
2050 ys.len() * Self::BLCK_SIZE,
2051 "quantize_row_q6k: size mismatch {} {} {}",
2052 xs.len(),
2053 ys.len(),
2054 Self::BLCK_SIZE
2055 );
2056 let mut l = [0i8; QK_K];
2057 let mut scales = [0f32; QK_K / 16];
2058 let mut x = xs.as_ptr();
2059 let l = l.as_mut_ptr();
2060 unsafe {
2061 for y in ys.iter_mut() {
2062 let mut max_scale = 0f32;
2063 let mut max_abs_scale = 0f32;
2064 for (ib, scale_) in scales.iter_mut().enumerate() {
2065 let scale =
2066 make_qx_quants(16, 32, x.add(16 * ib), l.add(16 * ib), 1, std::ptr::null());
2067 *scale_ = scale;
2068 let abs_scale = scale.abs();
2069 if abs_scale > max_abs_scale {
2070 max_abs_scale = abs_scale;
2071 max_scale = scale
2072 }
2073 }
2074
2075 let iscale = -128f32 / max_scale;
2076 y.d = f16::from_f32(1.0 / iscale);
2077
2078 for (y_scale, scale) in y.scales.iter_mut().zip(scales.iter()) {
2079 *y_scale = nearest_int(iscale * scale).min(127) as i8
2080 }
2081
2082 for (j, &y_scale) in y.scales.iter().enumerate() {
2083 let d = y.d.to_f32() * y_scale as f32;
2084 if d == 0. {
2085 continue;
2086 }
2087 for ii in 0..16 {
2088 let ll = nearest_int(*x.add(16 * j + ii) / d).clamp(-32, 31);
2089 *l.add(16 * j + ii) = (ll + 32) as i8
2090 }
2091 }
2092
2093 let mut ql = y.ql.as_mut_ptr();
2094 let mut qh = y.qh.as_mut_ptr();
2095
2096 for j in (0..QK_K).step_by(128) {
2097 for l_idx in 0..32 {
2098 let q1 = *l.add(j + l_idx) & 0xF;
2099 let q2 = *l.add(j + l_idx + 32) & 0xF;
2100 let q3 = *l.add(j + l_idx + 64) & 0xF;
2101 let q4 = *l.add(j + l_idx + 96) & 0xF;
2102 *ql.add(l_idx) = (q1 | (q3 << 4)) as u8;
2103 *ql.add(l_idx + 32) = (q2 | (q4 << 4)) as u8;
2104 *qh.add(l_idx) = ((*l.add(j + l_idx) >> 4)
2105 | ((*l.add(j + l_idx + 32) >> 4) << 2)
2106 | ((*l.add(j + l_idx + 64) >> 4) << 4)
2107 | ((*l.add(j + l_idx + 96) >> 4) << 6))
2108 as u8;
2109 }
2110 ql = ql.add(64);
2111 qh = qh.add(32);
2112 }
2113
2114 x = x.add(QK_K)
2115 }
2116 }
2117 }
2118
2119 fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
2120 debug_assert_eq!(
2121 xs.len(),
2122 ys.len() * Self::BLCK_SIZE,
2123 "quantize_row_q6k imatrix: size mismatch {} {} {}",
2124 xs.len(),
2125 ys.len(),
2126 Self::BLCK_SIZE
2127 );
2128 let mut l = [0i8; QK_K];
2129 let mut scales = [0f32; QK_K / 16];
2130 let mut x = xs.as_ptr();
2131 let imatrix_weights = imatrix_weights.as_ptr();
2132 let l = l.as_mut_ptr();
2133 unsafe {
2134 for (sblk_idx, y) in ys.iter_mut().enumerate() {
2135 let mut max_scale = 0f32;
2136 let mut max_abs_scale = 0f32;
2137 for (ib, scale_) in scales.iter_mut().enumerate() {
2138 let imatrix_row = sblk_idx % (n_per_row / QK_K);
2139 let scale = make_qx_quants(
2140 16,
2141 32,
2142 x.add(16 * ib),
2143 l.add(16 * ib),
2144 1,
2145 imatrix_weights.add(QK_K * imatrix_row + 16 * ib),
2146 );
2147 *scale_ = scale;
2148 let abs_scale = scale.abs();
2149 if abs_scale > max_abs_scale {
2150 max_abs_scale = abs_scale;
2151 max_scale = scale
2152 }
2153 }
2154
2155 let iscale = -128f32 / max_scale;
2156 y.d = f16::from_f32(1.0 / iscale);
2157
2158 for (y_scale, scale) in y.scales.iter_mut().zip(scales.iter()) {
2159 *y_scale = nearest_int(iscale * scale).min(127) as i8
2160 }
2161
2162 for (j, &y_scale) in y.scales.iter().enumerate() {
2163 let d = y.d.to_f32() * y_scale as f32;
2164 if d == 0. {
2165 continue;
2166 }
2167 for ii in 0..16 {
2168 let ll = nearest_int(*x.add(16 * j + ii) / d).clamp(-32, 31);
2169 *l.add(16 * j + ii) = (ll + 32) as i8
2170 }
2171 }
2172
2173 let mut ql = y.ql.as_mut_ptr();
2174 let mut qh = y.qh.as_mut_ptr();
2175
2176 for j in (0..QK_K).step_by(128) {
2177 for l_idx in 0..32 {
2178 let q1 = *l.add(j + l_idx) & 0xF;
2179 let q2 = *l.add(j + l_idx + 32) & 0xF;
2180 let q3 = *l.add(j + l_idx + 64) & 0xF;
2181 let q4 = *l.add(j + l_idx + 96) & 0xF;
2182 *ql.add(l_idx) = (q1 | (q3 << 4)) as u8;
2183 *ql.add(l_idx + 32) = (q2 | (q4 << 4)) as u8;
2184 *qh.add(l_idx) = ((*l.add(j + l_idx) >> 4)
2185 | ((*l.add(j + l_idx + 32) >> 4) << 2)
2186 | ((*l.add(j + l_idx + 64) >> 4) << 4)
2187 | ((*l.add(j + l_idx + 96) >> 4) << 6))
2188 as u8;
2189 }
2190 ql = ql.add(64);
2191 qh = qh.add(32);
2192 }
2193
2194 x = x.add(QK_K)
2195 }
2196 }
2197 }
2198
2199 fn to_float(xs: &[Self], ys: &mut [f32]) {
2201 let k = ys.len();
2202 debug_assert!(
2203 k.is_multiple_of(QK_K),
2204 "dequantize_row_q6k: {k} is not divisible by {QK_K}"
2205 );
2206
2207 for (idx_x, x) in xs.iter().enumerate() {
2208 let d = x.d.to_f32();
2209 let ql = &x.ql;
2210 let qh = &x.qh;
2211 let sc = &x.scales;
2212 for n in (0..QK_K).step_by(128) {
2213 let idx = n / 128;
2214 let ys = &mut ys[idx_x * QK_K + n..];
2215 let sc = &sc[8 * idx..];
2216 let ql = &ql[64 * idx..];
2217 let qh = &qh[32 * idx..];
2218 for l in 0..32 {
2219 let is = l / 16;
2220 let q1 = ((ql[l] & 0xF) | ((qh[l] & 3) << 4)) as i8 - 32;
2221 let q2 = ((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) as i8 - 32;
2222 let q3 = ((ql[l] >> 4) | (((qh[l] >> 4) & 3) << 4)) as i8 - 32;
2223 let q4 = ((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) as i8 - 32;
2224 ys[l] = d * sc[is] as f32 * q1 as f32;
2225 ys[l + 32] = d * sc[is + 2] as f32 * q2 as f32;
2226 ys[l + 64] = d * sc[is + 4] as f32 * q3 as f32;
2227 ys[l + 96] = d * sc[is + 6] as f32 * q4 as f32;
2228 }
2229 }
2230 }
2231 }
2232}
2233
2234impl GgmlType for BlockQ8K {
2235 const DTYPE: GgmlDType = GgmlDType::Q8K;
2236 const BLCK_SIZE: usize = QK_K;
2237 type VecDotType = BlockQ8K;
2238
2239 #[allow(unreachable_code)]
2240 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2241 #[cfg(target_feature = "avx2")]
2242 return super::avx::vec_dot_q8k_q8k(n, xs, ys);
2243
2244 #[cfg(target_feature = "neon")]
2245 return super::neon::vec_dot_q8k_q8k(n, xs, ys);
2246
2247 Self::vec_dot_unopt(n, xs, ys)
2248 }
2249
2250 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2251 debug_assert!(
2252 n.is_multiple_of(QK_K),
2253 "vec_dot_q8k_q8k: {n} is not divisible by {QK_K}"
2254 );
2255 let mut sumf = 0f32;
2257 for (xs, ys) in xs.iter().zip(ys.iter()) {
2258 let sum_i = xs
2259 .qs
2260 .iter()
2261 .zip(ys.qs.iter())
2262 .map(|(&x, &y)| x as i32 * y as i32)
2263 .sum::<i32>();
2264 sumf += sum_i as f32 * xs.d * ys.d
2265 }
2266 sumf
2267 }
2268
2269 fn from_float(xs: &[f32], ys: &mut [Self]) {
2270 let k = xs.len();
2271 debug_assert!(
2272 k.is_multiple_of(QK_K),
2273 "quantize_row_q8k: {k} is not divisible by {QK_K}"
2274 );
2275 for (i, y) in ys.iter_mut().enumerate() {
2276 let mut max = 0f32;
2277 let mut amax = 0f32;
2278 let xs = &xs[i * QK_K..(i + 1) * QK_K];
2279 for &x in xs.iter() {
2280 if amax < x.abs() {
2281 amax = x.abs();
2282 max = x;
2283 }
2284 }
2285 if amax == 0f32 {
2286 y.d = 0f32;
2287 y.qs.fill(0)
2288 } else {
2289 let iscale = -128f32 / max;
2290 for (j, q) in y.qs.iter_mut().enumerate() {
2291 let v = (iscale * xs[j]).round();
2294 *q = v.min(127.) as i8
2295 }
2296 for j in 0..QK_K / 16 {
2297 let mut sum = 0i32;
2298 for ii in 0..16 {
2299 sum += y.qs[j * 16 + ii] as i32
2300 }
2301 y.bsums[j] = sum as i16
2302 }
2303 y.d = 1.0 / iscale
2304 }
2305 }
2306 }
2307
2308 fn to_float(xs: &[Self], ys: &mut [f32]) {
2309 let k = ys.len();
2310 debug_assert!(
2311 k.is_multiple_of(QK_K),
2312 "dequantize_row_q8k: {k} is not divisible by {QK_K}"
2313 );
2314 for (i, x) in xs.iter().enumerate() {
2315 for (j, &q) in x.qs.iter().enumerate() {
2316 ys[i * QK_K + j] = x.d * q as f32
2317 }
2318 }
2319 }
2320}
2321
2322pub fn matmul<T: GgmlType>(
2324 (m, k, n): (usize, usize, usize),
2325 lhs: &[f32],
2326 rhs_t: &[T],
2327 dst: &mut [f32],
2328) -> Result<()> {
2329 debug_assert_eq!(
2330 T::BLCK_SIZE,
2331 T::VecDotType::BLCK_SIZE,
2332 "Mismatched block sizes"
2333 );
2334 debug_assert_eq!(
2335 m * k,
2336 lhs.len(),
2337 "unexpected lhs length {} ({m},{k},{n})",
2338 lhs.len()
2339 );
2340 if cfg!(feature = "float-dot") {
2341 return matmul_float_dot((m, k, n), lhs, rhs_t, dst);
2342 }
2343 let k_in_blocks = k.div_ceil(T::BLCK_SIZE);
2344
2345 let mut lhs_b = vec![T::VecDotType::zeros(); m * k_in_blocks];
2347 if T::DIRECT_COPY {
2349 T::VecDotType::direct_copy(lhs, &mut lhs_b);
2350 } else {
2351 for row_idx in 0..m {
2352 let lhs_b_mut = &mut lhs_b[row_idx * k_in_blocks..(row_idx + 1) * k_in_blocks];
2353 let lhs = &lhs[row_idx * k..(row_idx + 1) * k];
2354 T::VecDotType::from_float(lhs, lhs_b_mut)
2355 }
2356 }
2357
2358 for row_idx in 0..m {
2359 let lhs_row = &lhs_b[row_idx * k_in_blocks..(row_idx + 1) * k_in_blocks];
2360 let dst_row = &mut dst[row_idx * n..(row_idx + 1) * n];
2361
2362 dst_row
2363 .into_par_iter()
2364 .enumerate()
2365 .with_min_len(128)
2366 .with_max_len(512)
2367 .for_each(|(col_idx, dst)| {
2368 let rhs_col = &rhs_t[col_idx * k_in_blocks..(col_idx + 1) * k_in_blocks];
2369 *dst = T::vec_dot(k, rhs_col, lhs_row);
2370 });
2371 }
2372 Ok(())
2373}
2374
2375pub const FLOAT_DOT: bool = cfg!(feature = "float-dot");
2378
2379fn dot_f32(a: &[f32], b: &[f32]) -> f32 {
2381 let mut acc = [0f32; 8];
2382 let ((ca, ra), (cb, rb)) = (a.as_chunks::<8>(), b.as_chunks::<8>());
2383 let tail: f32 = ra.iter().zip(rb).map(|(x, y)| x * y).sum();
2384 for (xa, xb) in ca.iter().zip(cb) {
2385 for l in 0..8 {
2386 acc[l] += xa[l] * xb[l];
2387 }
2388 }
2389 acc.iter().sum::<f32>() + tail
2390}
2391
2392fn matmul_float_dot<T: GgmlType>(
2396 (m, k, n): (usize, usize, usize),
2397 lhs: &[f32],
2398 rhs_t: &[T],
2399 dst: &mut [f32],
2400) -> Result<()> {
2401 if m * k != lhs.len() || m * n != dst.len() {
2402 fuel_ir::bail!(
2403 "float-dot matmul: bad lengths lhs {} dst {} for ({m},{k},{n})",
2404 lhs.len(),
2405 dst.len()
2406 );
2407 }
2408 let k_in_blocks = k.div_ceil(T::BLCK_SIZE);
2409 let mut tmp = vec![0f32; m * n];
2412 tmp.par_chunks_mut(m)
2413 .enumerate()
2414 .with_min_len(64)
2415 .for_each_init(
2416 || vec![0f32; k_in_blocks * T::BLCK_SIZE],
2417 |buf, (col, out)| {
2418 T::to_float(&rhs_t[col * k_in_blocks..(col + 1) * k_in_blocks], buf);
2419 for (row, o) in out.iter_mut().enumerate() {
2420 *o = dot_f32(&buf[..k], &lhs[row * k..(row + 1) * k]);
2421 }
2422 },
2423 );
2424 for col in 0..n {
2425 for row in 0..m {
2426 dst[row * n + col] = tmp[col * m + row];
2427 }
2428 }
2429 Ok(())
2430}
2431
2432pub fn matmul_f16<T: GgmlType>(
2433 mkn: (usize, usize, usize),
2434 lhs: &[f16],
2435 rhs_t: &[T],
2436 dst: &mut [f16],
2437) -> Result<()> {
2438 let (m, k, n) = mkn;
2439 if m * k != lhs.len() {
2440 fuel_ir::bail!("unexpected lhs length {} {mkn:?}", lhs.len());
2441 }
2442 if cfg!(feature = "float-dot") {
2443 let lhs32: Vec<f32> = lhs.iter().map(|x| x.to_f32()).collect();
2444 let mut dst32 = vec![0f32; m * n];
2445 matmul_float_dot(mkn, &lhs32, rhs_t, &mut dst32)?;
2446 for (d, s) in dst.iter_mut().zip(dst32) {
2447 *d = f16::from_f32(s);
2448 }
2449 return Ok(());
2450 }
2451
2452 let k_in_lhs_blocks = k.div_ceil(T::BLCK_SIZE);
2453 let k_in_rhs_blocks = k.div_ceil(T::VecDotType::BLCK_SIZE);
2454 let mut lhs_b = vec![T::VecDotType::zeros(); m * k_in_lhs_blocks];
2455 let mut lhs_f32 = vec![0f32; k];
2456 for row_idx in 0..m {
2457 let lhs_b = &mut lhs_b[row_idx * k_in_lhs_blocks..(row_idx + 1) * k_in_lhs_blocks];
2458 let lhs = &lhs[row_idx * k..(row_idx + 1) * k];
2459 for (dst, &src) in lhs_f32.iter_mut().zip(lhs.iter()) {
2460 *dst = src.to_f32();
2461 }
2462 T::VecDotType::from_float(&lhs_f32, lhs_b);
2463 }
2464 let lhs_b = lhs_b.as_slice();
2465
2466 for row_idx in 0..m {
2467 let lhs_row = &lhs_b[row_idx * k_in_lhs_blocks..(row_idx + 1) * k_in_lhs_blocks];
2468 let dst_row = &mut dst[row_idx * n..(row_idx + 1) * n];
2469
2470 dst_row
2471 .into_par_iter()
2472 .enumerate()
2473 .with_min_len(128)
2474 .with_max_len(512)
2475 .for_each(|(col_idx, dst)| {
2476 let rhs_col = &rhs_t[col_idx * k_in_rhs_blocks..(col_idx + 1) * k_in_rhs_blocks];
2477 let value = T::vec_dot(k, rhs_col, lhs_row);
2478 *dst = f16::from_f32(value);
2479 });
2480 }
2481 Ok(())
2482}
2483
2484impl GgmlType for f32 {
2485 const DTYPE: GgmlDType = GgmlDType::F32;
2486 const BLCK_SIZE: usize = 1;
2487 const DIRECT_COPY: bool = true;
2488 type VecDotType = f32;
2489
2490 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2491 Self::vec_dot_unopt(n, xs, ys)
2492 }
2493
2494 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2495 debug_assert!(xs.len() >= n, "size mismatch xs {} < {n}", xs.len());
2496 debug_assert!(ys.len() >= n, "size mismatch ys {} < {n}", ys.len());
2497 let mut res = 0f32;
2498 unsafe { fuel_cpu_kernels::vec_dot_f32(xs.as_ptr(), ys.as_ptr(), &mut res, n) };
2499 res
2500 }
2501
2502 fn from_float(xs: &[f32], ys: &mut [Self]) {
2503 debug_assert_eq!(
2504 xs.len(),
2505 ys.len(),
2506 "size mismatch xs {} != ys {}",
2507 xs.len(),
2508 ys.len()
2509 );
2510 ys.copy_from_slice(xs);
2511 }
2512
2513 fn to_float(xs: &[Self], ys: &mut [f32]) {
2514 debug_assert_eq!(
2515 xs.len(),
2516 ys.len(),
2517 "size mismatch xs {} != ys {}",
2518 xs.len(),
2519 ys.len()
2520 );
2521 ys.copy_from_slice(xs);
2522 }
2523
2524 fn direct_copy(xs: &[f32], ys: &mut [Self]) {
2525 Self::from_float(xs, ys)
2526 }
2527}
2528
2529impl GgmlType for f16 {
2530 const DTYPE: GgmlDType = GgmlDType::F16;
2531 const BLCK_SIZE: usize = 1;
2532 const DIRECT_COPY: bool = true;
2533 type VecDotType = f16;
2534
2535 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2536 Self::vec_dot_unopt(n, xs, ys)
2537 }
2538
2539 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2540 debug_assert!(xs.len() >= n, "size mismatch xs {} < {n}", xs.len());
2541 debug_assert!(ys.len() >= n, "size mismatch ys {} < {n}", ys.len());
2542 let mut res = 0f32;
2543 unsafe { fuel_cpu_kernels::vec_dot_f16(xs.as_ptr(), ys.as_ptr(), &mut res, n) };
2544 res
2545 }
2546
2547 fn from_float(xs: &[f32], ys: &mut [Self]) {
2548 debug_assert_eq!(
2549 xs.len(),
2550 ys.len(),
2551 "size mismatch xs {} != ys {}",
2552 xs.len(),
2553 ys.len()
2554 );
2555 ys.convert_from_f32_slice(xs);
2556 }
2557
2558 fn to_float(xs: &[Self], ys: &mut [f32]) {
2559 debug_assert_eq!(
2560 xs.len(),
2561 ys.len(),
2562 "size mismatch xs {} != ys {}",
2563 xs.len(),
2564 ys.len()
2565 );
2566 xs.convert_to_f32_slice(ys);
2567 }
2568
2569 fn direct_copy(xs: &[f32], ys: &mut [Self]) {
2570 Self::from_float(xs, ys)
2571 }
2572}
2573
2574impl GgmlType for bf16 {
2575 const DTYPE: GgmlDType = GgmlDType::BF16;
2576 const BLCK_SIZE: usize = 1;
2577 const DIRECT_COPY: bool = true;
2578 type VecDotType = bf16;
2579
2580 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2581 Self::vec_dot_unopt(n, xs, ys)
2582 }
2583
2584 fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2585 debug_assert!(xs.len() >= n, "size mismatch xs {} < {n}", xs.len());
2586 debug_assert!(ys.len() >= n, "size mismatch ys {} < {n}", ys.len());
2587 let mut res = 0f32;
2588 unsafe { fuel_cpu_kernels::vec_dot_bf16(xs.as_ptr(), ys.as_ptr(), &mut res, n) };
2589 res
2590 }
2591
2592 fn from_float(xs: &[f32], ys: &mut [Self]) {
2593 debug_assert_eq!(
2594 xs.len(),
2595 ys.len(),
2596 "size mismatch xs {} != ys {}",
2597 xs.len(),
2598 ys.len()
2599 );
2600 ys.convert_from_f32_slice(xs);
2601 }
2602
2603 fn to_float(xs: &[Self], ys: &mut [f32]) {
2604 debug_assert_eq!(
2605 xs.len(),
2606 ys.len(),
2607 "size mismatch xs {} != ys {}",
2608 xs.len(),
2609 ys.len()
2610 );
2611 xs.convert_to_f32_slice(ys);
2612 }
2613
2614 fn direct_copy(xs: &[f32], ys: &mut [Self]) {
2615 Self::from_float(xs, ys)
2616 }
2617}
2618
2619macro_rules! verify_block_size {
2620 ( $block_type:ident ) => {
2621 const _: () =
2622 assert!($block_type::BLCK_SIZE == <$block_type as GgmlType>::VecDotType::BLCK_SIZE);
2623 };
2624}
2625
2626macro_rules! verify_block_sizes {
2627 ( $( $block_type:ident ),* ) => {
2628 $(
2629 verify_block_size!($block_type);
2630 )*
2631 };
2632}
2633
2634verify_block_sizes!(
2635 BlockQ4_0, BlockQ4_1, BlockQ5_0, BlockQ5_1, BlockQ8_0, BlockQ8_1, BlockQ2K, BlockQ3K, BlockQ4K,
2636 BlockQ5K, BlockQ6K, BlockQ8K, f32, f16, bf16
2637);
2638
2639#[cfg(test)]
2640mod float_dot_tests {
2641 use super::*;
2642
2643 fn fill(len: usize, seed: u32) -> Vec<f32> {
2645 (0..len as u32)
2646 .map(|i| {
2647 let x = (i
2648 .wrapping_mul(2654435761)
2649 .wrapping_add(seed.wrapping_mul(40503)))
2650 >> 8;
2651 (x % 2001) as f32 / 1000.0 - 1.0
2652 })
2653 .collect()
2654 }
2655
2656 #[test]
2659 fn float_dot_equals_the_f32_matmul_of_the_dequantised_weights() {
2660 let (m, k, n) = (3usize, 64usize, 8usize);
2661 let w = fill(n * k, 7);
2662 let x = fill(m * k, 11);
2663 let mut blocks = vec![BlockQ4_0::zeros(); n * k / QK4_0];
2664 BlockQ4_0::from_float(&w, &mut blocks);
2665 let mut deq = vec![0f32; n * k];
2666 BlockQ4_0::to_float(&blocks, &mut deq);
2667 let mut want = vec![0f32; m * n];
2668 for r in 0..m {
2669 for c in 0..n {
2670 want[r * n + c] = (0..k).map(|i| x[r * k + i] * deq[c * k + i]).sum();
2671 }
2672 }
2673 let mut got = vec![0f32; m * n];
2674 matmul_float_dot((m, k, n), &x, &blocks, &mut got).expect("float-dot matmul");
2675 assert!(
2676 want.iter().any(|v| v.abs() > 0.1),
2677 "control: the reference is not all zeros"
2678 );
2679 for (g, w) in got.iter().zip(&want) {
2680 assert!(
2681 (g - w).abs() <= 1e-3 * w.abs().max(1.0),
2682 "float-dot {g} vs reference {w}"
2683 );
2684 }
2685 }
2686
2687 #[test]
2690 fn the_default_matmul_is_close_to_the_f32_reference() {
2691 let (m, k, n) = (2usize, 64usize, 8usize);
2692 let w = fill(n * k, 3);
2693 let x = fill(m * k, 5);
2694 let mut blocks = vec![BlockQ4_0::zeros(); n * k / QK4_0];
2695 BlockQ4_0::from_float(&w, &mut blocks);
2696 let mut deq = vec![0f32; n * k];
2697 BlockQ4_0::to_float(&blocks, &mut deq);
2698 let mut got = vec![0f32; m * n];
2699 matmul((m, k, n), &x, &blocks, &mut got).expect("matmul");
2700 for r in 0..m {
2701 for c in 0..n {
2702 let want: f32 = (0..k).map(|i| x[r * k + i] * deq[c * k + i]).sum();
2703 assert!(
2704 (got[r * n + c] - want).abs() <= 0.05 * want.abs().max(1.0),
2705 "matmul {} vs reference {want} (float-dot build: {FLOAT_DOT})",
2706 got[r * n + c]
2707 );
2708 }
2709 }
2710 }
2711}