metrale_model_arch/tp_shard/
quant_shard.rs1use anyhow::{Result, ensure};
13use metrale_gpu_runtime::gpu::{DevicePtr, GpuBackend};
14
15use super::TpShardKind;
16use metrale_model_layers::weight_map::{Fp8Weight, QuantizedWeight};
17
18pub fn shard_quantized_nvfp4(
37 src: &QuantizedWeight,
38 out_dim: usize,
39 in_dim: usize,
40 kind: TpShardKind,
41 tp_rank: usize,
42 tp_size: usize,
43 group_size: usize,
44 gpu: &dyn GpuBackend,
45) -> Result<QuantizedWeight> {
46 if tp_size <= 1 || kind == TpShardKind::Replicated {
47 return Ok(*src);
48 }
49 ensure!(
50 in_dim.is_multiple_of(group_size),
51 "NVFP4 in_dim {in_dim} not divisible by group_size {group_size}",
52 );
53 let half_in = in_dim / 2;
54 let scale_in = in_dim / group_size;
55 match kind {
56 TpShardKind::Replicated => unreachable!("handled above"),
57 TpShardKind::ColumnParallel => {
58 ensure!(
59 out_dim.is_multiple_of(tp_size),
60 "NVFP4 ColumnParallel: out_dim {out_dim} not divisible by tp_size {tp_size}",
61 );
62 let local_out = out_dim / tp_size;
63 let w_row_bytes = half_in;
65 let w_local_bytes = local_out * w_row_bytes;
66 let w_dst = gpu.alloc(w_local_bytes)?;
67 let w_offset = tp_rank * local_out * w_row_bytes;
68 gpu.copy_d2d(
69 DevicePtr(src.weight.0 + w_offset as u64),
70 w_dst,
71 w_local_bytes,
72 )?;
73 let s_row_bytes = scale_in;
75 let s_local_bytes = local_out * s_row_bytes;
76 let s_dst = gpu.alloc(s_local_bytes)?;
77 let s_offset = tp_rank * local_out * s_row_bytes;
78 gpu.copy_d2d(
79 DevicePtr(src.weight_scale.0 + s_offset as u64),
80 s_dst,
81 s_local_bytes,
82 )?;
83 Ok(QuantizedWeight {
84 weight: w_dst,
85 weight_scale: s_dst,
86 weight_scale_2: src.weight_scale_2,
87 input_scale: src.input_scale,
88 weight_scale_2_vec: src.weight_scale_2_vec,
89 act: src.act,
90 })
91 }
92 TpShardKind::RowParallel => {
93 ensure!(
94 in_dim.is_multiple_of(tp_size),
95 "NVFP4 RowParallel: in_dim {in_dim} not divisible by tp_size {tp_size}",
96 );
97 ensure!(
98 half_in.is_multiple_of(tp_size),
99 "NVFP4 RowParallel: half_in {half_in} (=K/2) not divisible by tp_size {tp_size}",
100 );
101 ensure!(
102 scale_in.is_multiple_of(tp_size),
103 "NVFP4 RowParallel: scale_in {scale_in} (=K/group_size) not divisible by tp_size {tp_size}",
104 );
105 let local_w_in = half_in / tp_size;
106 let local_s_in = scale_in / tp_size;
107 let w_local_row_bytes = local_w_in;
109 let w_src_row_bytes = half_in;
110 let w_local_bytes = out_dim * w_local_row_bytes;
111 let w_dst = gpu.alloc(w_local_bytes)?;
112 let w_col_offset = tp_rank * w_local_row_bytes;
113 for r in 0..out_dim {
114 gpu.copy_d2d(
115 DevicePtr(src.weight.0 + (r * w_src_row_bytes + w_col_offset) as u64),
116 DevicePtr(w_dst.0 + (r * w_local_row_bytes) as u64),
117 w_local_row_bytes,
118 )?;
119 }
120 let s_local_row_bytes = local_s_in;
121 let s_src_row_bytes = scale_in;
122 let s_local_bytes = out_dim * s_local_row_bytes;
123 let s_dst = gpu.alloc(s_local_bytes)?;
124 let s_col_offset = tp_rank * s_local_row_bytes;
125 for r in 0..out_dim {
126 gpu.copy_d2d(
127 DevicePtr(src.weight_scale.0 + (r * s_src_row_bytes + s_col_offset) as u64),
128 DevicePtr(s_dst.0 + (r * s_local_row_bytes) as u64),
129 s_local_row_bytes,
130 )?;
131 }
132 Ok(QuantizedWeight {
133 weight: w_dst,
134 weight_scale: s_dst,
135 weight_scale_2: src.weight_scale_2,
136 input_scale: src.input_scale,
137 weight_scale_2_vec: src.weight_scale_2_vec,
138 act: src.act,
139 })
140 }
141 }
142}
143
144pub fn shard_fp8_block_scaled(
148 src: &Fp8Weight,
149 kind: TpShardKind,
150 tp_rank: usize,
151 tp_size: usize,
152 block_size: usize,
153 gpu: &dyn GpuBackend,
154) -> Result<Fp8Weight> {
155 if tp_size <= 1 || kind == TpShardKind::Replicated {
156 return Ok(*src);
157 }
158 let n = src.n as usize;
159 let k = src.k as usize;
160 ensure!(
161 n.is_multiple_of(block_size),
162 "FP8 N {n} not divisible by block_size {block_size}",
163 );
164 ensure!(
165 k.is_multiple_of(block_size),
166 "FP8 K {k} not divisible by block_size {block_size}",
167 );
168 let scale_n = n / block_size;
169 let scale_k = k / block_size;
170 let scale_elem_bytes = 4usize;
171 match kind {
172 TpShardKind::Replicated => unreachable!("handled above"),
173 TpShardKind::ColumnParallel => {
174 ensure!(
175 n.is_multiple_of(tp_size),
176 "FP8 ColumnParallel: N {n} not divisible by tp_size {tp_size}",
177 );
178 ensure!(
179 scale_n.is_multiple_of(tp_size),
180 "FP8 ColumnParallel: scale_n {scale_n} not divisible by tp_size {tp_size}",
181 );
182 let local_n = n / tp_size;
183 let local_scale_n = scale_n / tp_size;
184 let w_row_bytes = k;
186 let w_local_bytes = local_n * w_row_bytes;
187 let w_dst = gpu.alloc(w_local_bytes)?;
188 let w_offset = tp_rank * local_n * w_row_bytes;
189 gpu.copy_d2d(
190 DevicePtr(src.weight.0 + w_offset as u64),
191 w_dst,
192 w_local_bytes,
193 )?;
194 let s_row_bytes = scale_k * scale_elem_bytes;
196 let s_local_bytes = local_scale_n * s_row_bytes;
197 let s_dst = gpu.alloc(s_local_bytes)?;
198 let s_offset = tp_rank * local_scale_n * s_row_bytes;
199 gpu.copy_d2d(
200 DevicePtr(src.row_scale.0 + s_offset as u64),
201 s_dst,
202 s_local_bytes,
203 )?;
204 Ok(Fp8Weight {
205 weight: w_dst,
206 row_scale: s_dst,
207 n: local_n as u32,
208 k: src.k,
209 scale_format: src.scale_format,
210 })
211 }
212 TpShardKind::RowParallel => {
213 ensure!(
214 k.is_multiple_of(tp_size),
215 "FP8 RowParallel: K {k} not divisible by tp_size {tp_size}",
216 );
217 ensure!(
218 scale_k.is_multiple_of(tp_size),
219 "FP8 RowParallel: scale_k {scale_k} not divisible by tp_size {tp_size}",
220 );
221 let local_k = k / tp_size;
222 let local_scale_k = scale_k / tp_size;
223 let w_local_row_bytes = local_k;
224 let w_src_row_bytes = k;
225 let w_local_bytes = n * w_local_row_bytes;
226 let w_dst = gpu.alloc(w_local_bytes)?;
227 let w_col_offset = tp_rank * w_local_row_bytes;
228 for r in 0..n {
229 gpu.copy_d2d(
230 DevicePtr(src.weight.0 + (r * w_src_row_bytes + w_col_offset) as u64),
231 DevicePtr(w_dst.0 + (r * w_local_row_bytes) as u64),
232 w_local_row_bytes,
233 )?;
234 }
235 let s_local_row_bytes = local_scale_k * scale_elem_bytes;
236 let s_src_row_bytes = scale_k * scale_elem_bytes;
237 let s_local_bytes = scale_n * s_local_row_bytes;
238 let s_dst = gpu.alloc(s_local_bytes)?;
239 let s_col_offset = tp_rank * s_local_row_bytes;
240 for r in 0..scale_n {
241 gpu.copy_d2d(
242 DevicePtr(src.row_scale.0 + (r * s_src_row_bytes + s_col_offset) as u64),
243 DevicePtr(s_dst.0 + (r * s_local_row_bytes) as u64),
244 s_local_row_bytes,
245 )?;
246 }
247 Ok(Fp8Weight {
248 weight: w_dst,
249 row_scale: s_dst,
250 n: src.n,
251 k: local_k as u32,
252 scale_format: src.scale_format,
253 })
254 }
255 }
256}