1use burn::tensor::{Device, Int, Tensor, TensorData, backend::Backend};
4
5use crate::metadata::ModelMetadata;
6use crate::tokenizer::TokenizerSpec;
7use crate::{FormatError, Result};
8
9pub trait ModelSource: Send + Sync {
15 fn metadata(&self) -> &ModelMetadata;
17
18 fn tensor_names(&self) -> Vec<String>;
20
21 fn open_tensor(&self, name: &str) -> Result<TensorReader<'_>>;
23
24 fn tokenizer(&self) -> Result<TokenizerSpec>;
26
27 fn sampler_defaults(&self) -> Option<SamplerConfig>;
29
30 fn open_tensor_quant(&self, _name: &str) -> Result<Option<QuantTensor<'_>>> {
36 Ok(None)
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum QuantFormat {
43 Q4_0,
45 Q5_0,
47 Q8_0,
49 Q4K,
51 Q5K,
53 Q6K,
55}
56
57pub struct QuantTensor<'a> {
59 pub format: QuantFormat,
61 pub shape: Vec<usize>,
63 pub data: std::borrow::Cow<'a, [u8]>,
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum TensorDtype {
71 F64,
73 F32,
75 F16,
77 BF16,
79 I64,
81 I32,
83 I16,
85 I8,
87 U64,
89 U32,
91 U16,
93 U8,
95 Bool,
97}
98
99impl TensorDtype {
100 pub fn size(&self) -> usize {
102 match self {
103 TensorDtype::F64 | TensorDtype::I64 | TensorDtype::U64 => 8,
104 TensorDtype::F32 | TensorDtype::I32 | TensorDtype::U32 => 4,
105 TensorDtype::F16 | TensorDtype::BF16 | TensorDtype::I16 | TensorDtype::U16 => 2,
106 TensorDtype::I8 | TensorDtype::U8 | TensorDtype::Bool => 1,
107 }
108 }
109}
110
111impl std::fmt::Display for TensorDtype {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 match self {
114 TensorDtype::F64 => write!(f, "F64"),
115 TensorDtype::F32 => write!(f, "F32"),
116 TensorDtype::F16 => write!(f, "F16"),
117 TensorDtype::BF16 => write!(f, "BF16"),
118 TensorDtype::I64 => write!(f, "I64"),
119 TensorDtype::I32 => write!(f, "I32"),
120 TensorDtype::I16 => write!(f, "I16"),
121 TensorDtype::I8 => write!(f, "I8"),
122 TensorDtype::U64 => write!(f, "U64"),
123 TensorDtype::U32 => write!(f, "U32"),
124 TensorDtype::U16 => write!(f, "U16"),
125 TensorDtype::U8 => write!(f, "U8"),
126 TensorDtype::Bool => write!(f, "Bool"),
127 }
128 }
129}
130
131pub struct TensorReader<'a> {
137 name: String,
138 shape: Vec<usize>,
139 dtype: TensorDtype,
140 data: std::borrow::Cow<'a, [u8]>,
141}
142
143impl<'a> TensorReader<'a> {
144 pub fn new(name: String, shape: Vec<usize>, dtype: TensorDtype, data: &'a [u8]) -> Self {
147 TensorReader {
148 name,
149 shape,
150 dtype,
151 data: std::borrow::Cow::Borrowed(data),
152 }
153 }
154
155 pub fn owned(name: String, shape: Vec<usize>, data: Vec<u8>) -> Self {
157 TensorReader {
158 name,
159 shape,
160 dtype: TensorDtype::F32,
161 data: std::borrow::Cow::Owned(data),
162 }
163 }
164
165 pub fn owned_with_dtype(
168 name: String,
169 shape: Vec<usize>,
170 dtype: TensorDtype,
171 data: Vec<u8>,
172 ) -> Self {
173 TensorReader {
174 name,
175 shape,
176 dtype,
177 data: std::borrow::Cow::Owned(data),
178 }
179 }
180
181 pub fn shape(&self) -> &[usize] {
183 &self.shape
184 }
185
186 pub fn dtype(&self) -> TensorDtype {
188 self.dtype
189 }
190
191 pub fn num_elements(&self) -> usize {
193 self.shape.iter().product()
194 }
195
196 pub fn load_data(&self) -> Result<TensorData> {
200 let values: Vec<f32> = match self.dtype {
201 TensorDtype::F64 => self
202 .data
203 .chunks_exact(8)
204 .map(|c| f64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]]) as f32)
205 .collect(),
206 TensorDtype::F32 => self
207 .data
208 .chunks_exact(4)
209 .map(|c| f32::from_le_bytes([c[0], c[1], c[2], c[3]]))
210 .collect(),
211 TensorDtype::F16 => self
212 .data
213 .chunks_exact(2)
214 .map(|c| half::f16::from_le_bytes([c[0], c[1]]).to_f32())
215 .collect(),
216 TensorDtype::BF16 => self
217 .data
218 .chunks_exact(2)
219 .map(|c| half::bf16::from_le_bytes([c[0], c[1]]).to_f32())
220 .collect(),
221 TensorDtype::I64 => self
222 .data
223 .chunks_exact(8)
224 .map(|c| i64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]]) as f32)
225 .collect(),
226 TensorDtype::I32 => self
227 .data
228 .chunks_exact(4)
229 .map(|c| i32::from_le_bytes([c[0], c[1], c[2], c[3]]) as f32)
230 .collect(),
231 TensorDtype::I16 => self
232 .data
233 .chunks_exact(2)
234 .map(|c| i16::from_le_bytes([c[0], c[1]]) as f32)
235 .collect(),
236 TensorDtype::I8 => self
237 .data
238 .iter()
239 .map(|&b| b as i8 as f32)
240 .collect(),
241 TensorDtype::U64 => self
242 .data
243 .chunks_exact(8)
244 .map(|c| u64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]]) as f32)
245 .collect(),
246 TensorDtype::U32 => self
247 .data
248 .chunks_exact(4)
249 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) as f32)
250 .collect(),
251 TensorDtype::U16 => self
252 .data
253 .chunks_exact(2)
254 .map(|c| u16::from_le_bytes([c[0], c[1]]) as f32)
255 .collect(),
256 TensorDtype::U8 => self.data.iter().map(|&b| b as f32).collect(),
257 TensorDtype::Bool => self.data.iter().map(|&b| (b != 0) as i32 as f32).collect(),
258 };
259 if values.len() != self.num_elements() {
260 return Err(FormatError::Safetensors(format!(
261 "tensor {}: expected {} elements, got {} (dtype {})",
262 self.name,
263 self.num_elements(),
264 values.len(),
265 self.dtype
266 )));
267 }
268 Ok(TensorData::new(values, self.shape.clone()))
269 }
270
271 pub fn load_to_tensor<B: Backend, const D: usize>(
273 &self,
274 device: &Device<B>,
275 ) -> Result<Tensor<B, D>> {
276 let data = self.load_data()?;
277 if self.shape.len() != D {
278 return Err(FormatError::Safetensors(format!(
279 "tensor {}: expected rank {D}, got {}",
280 self.name,
281 self.shape.len()
282 )));
283 }
284 Ok(Tensor::from_data(data, device))
285 }
286
287 pub fn load_int_tensor<B: Backend, const D: usize>(
291 &self,
292 device: &Device<B>,
293 ) -> Result<Tensor<B, D, Int>> {
294 if self.dtype != TensorDtype::U8 {
295 return Err(FormatError::Safetensors(format!(
296 "tensor {}: load_int_tensor requires U8, got {}",
297 self.name, self.dtype
298 )));
299 }
300 if self.shape.len() != D {
301 return Err(FormatError::Safetensors(format!(
302 "tensor {}: expected rank {D}, got {}",
303 self.name,
304 self.shape.len()
305 )));
306 }
307 let values: Vec<i32> = self.data.iter().map(|&b| b as i32).collect();
308 Ok(Tensor::from_data(
309 TensorData::new(values, self.shape.clone()),
310 device,
311 ))
312 }
313
314 pub fn raw_bytes(&self) -> &[u8] {
316 &self.data
317 }
318}
319
320impl<T: ModelSource + ?Sized> ModelSource for Box<T> {
323 fn metadata(&self) -> &crate::ModelMetadata {
324 (**self).metadata()
325 }
326 fn tensor_names(&self) -> Vec<String> {
327 (**self).tensor_names()
328 }
329 fn open_tensor(&self, name: &str) -> crate::Result<TensorReader<'_>> {
330 (**self).open_tensor(name)
331 }
332 fn tokenizer(&self) -> crate::Result<TokenizerSpec> {
333 (**self).tokenizer()
334 }
335 fn sampler_defaults(&self) -> Option<SamplerConfig> {
336 (**self).sampler_defaults()
337 }
338 fn open_tensor_quant(&self, name: &str) -> Result<Option<QuantTensor<'_>>> {
344 (**self).open_tensor_quant(name)
345 }
346}
347
348#[derive(Debug, Clone, Default)]
350pub struct SamplerConfig { pub temperature: Option<f32>,
352 pub top_p: Option<f32>,
354 pub top_k: Option<usize>,
356 pub repetition_penalty: Option<f32>,
358 pub max_new_tokens: Option<usize>,
360}