metrale_model_layers/weight_map/
quantize_fns.rs1#![allow(unused_imports)]
10
11use anyhow::{Context, Result, bail, ensure};
12use metrale_gpu_runtime::gpu::{DevicePtr, GpuBackend};
13use metrale_model_weights::weights::{WeightDtype, WeightStore};
14
15use super::*;
16
17pub fn quantize_to_fp8(
21 bf16_weight: &DenseWeight,
22 n: usize,
23 k: usize,
24 gpu: &dyn GpuBackend,
25 quantize_kernel: metrale_gpu_runtime::gpu::KernelHandle,
26 stream: u64,
27) -> Result<Fp8DenseWeight> {
28 use metrale_gpu_runtime::kernel_args::KernelLaunch;
29
30 let fp8_buf = gpu.alloc(n * k)?;
31 let scale_buf = gpu.alloc(n * 4)?;
32
33 KernelLaunch::new(gpu, quantize_kernel)
34 .grid([n as u32, 1, 1])
35 .block([256, 1, 1])
36 .arg_ptr(bf16_weight.weight)
37 .arg_ptr(fp8_buf)
38 .arg_ptr(scale_buf)
39 .arg_u32(n as u32)
40 .arg_u32(k as u32)
41 .launch(stream)?;
42
43 gpu.synchronize(stream)?;
44
45 Ok(Fp8DenseWeight {
46 weight: fp8_buf,
47 row_scale: scale_buf,
48 })
49}
50
51pub fn load_fp8_weight(store: &WeightStore, name: &str, gpu: &dyn GpuBackend) -> Result<Fp8Weight> {
59 let w = store.get(&format!("{name}.weight"))?;
60 ensure!(
61 w.dtype == WeightDtype::FP8E4M3,
62 "Expected FP8E4M3 for {name}.weight, got {:?}",
63 w.dtype,
64 );
65 ensure!(
66 w.shape.len() == 2,
67 "Expected 2D weight for {name}, got {:?}",
68 w.shape
69 );
70 let n = w.shape[0];
71 let k = w.shape[1];
72
73 let weight_ptr = w.ptr;
74
75 let scale_key = format!("{name}.weight_scale");
76 let s = store.get(&scale_key).with_context(|| {
77 format!("Missing per-row scale tensor {scale_key} for FP8 weight {name}")
78 })?;
79 ensure!(
80 s.shape.len() == 1 && s.shape[0] == n,
81 "Expected [{n}] shape for {scale_key}, got {:?}",
82 s.shape,
83 );
84
85 let row_scale_ptr = if s.dtype == WeightDtype::FP32 {
86 s.ptr
87 } else if s.dtype == WeightDtype::BF16 {
88 let mut bf16_buf = vec![0u8; n * 2];
89 gpu.copy_d2h(s.ptr, &mut bf16_buf)?;
90 let mut f32_buf = vec![0u8; n * 4];
91 for i in 0..n {
92 let bf16_bytes = [bf16_buf[i * 2], bf16_buf[i * 2 + 1]];
93 let val = bf16_bytes_to_f32(bf16_bytes);
94 let f32_bytes = val.to_le_bytes();
95 f32_buf[i * 4..i * 4 + 4].copy_from_slice(&f32_bytes);
96 }
97 let f32_ptr = gpu.alloc(n * 4)?;
98 gpu.copy_h2d(&f32_buf, f32_ptr)?;
99 f32_ptr
100 } else {
101 anyhow::bail!(
102 "Unsupported dtype {:?} for {scale_key}, expected FP32 or BF16",
103 s.dtype,
104 );
105 };
106
107 Ok(Fp8Weight {
108 weight: weight_ptr,
109 row_scale: row_scale_ptr,
110 n: n as u32,
111 k: k as u32,
112 scale_format: WeightQuantFormat::Fp8PerRow,
113 })
114}