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
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum TensorDtype {
34 F32,
36 F16,
38 BF16,
40 U8,
42}
43
44impl TensorDtype {
45 pub fn size(&self) -> usize {
47 match self {
48 TensorDtype::F32 => 4,
49 TensorDtype::F16 | TensorDtype::BF16 => 2,
50 TensorDtype::U8 => 1,
51 }
52 }
53}
54
55impl std::fmt::Display for TensorDtype {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 TensorDtype::F32 => write!(f, "F32"),
59 TensorDtype::F16 => write!(f, "F16"),
60 TensorDtype::BF16 => write!(f, "BF16"),
61 TensorDtype::U8 => write!(f, "U8"),
62 }
63 }
64}
65
66pub struct TensorReader<'a> {
72 name: String,
73 shape: Vec<usize>,
74 dtype: TensorDtype,
75 data: std::borrow::Cow<'a, [u8]>,
76}
77
78impl<'a> TensorReader<'a> {
79 pub fn new(name: String, shape: Vec<usize>, dtype: TensorDtype, data: &'a [u8]) -> Self {
82 TensorReader {
83 name,
84 shape,
85 dtype,
86 data: std::borrow::Cow::Borrowed(data),
87 }
88 }
89
90 pub fn owned(name: String, shape: Vec<usize>, data: Vec<u8>) -> Self {
92 TensorReader {
93 name,
94 shape,
95 dtype: TensorDtype::F32,
96 data: std::borrow::Cow::Owned(data),
97 }
98 }
99
100 pub fn shape(&self) -> &[usize] {
102 &self.shape
103 }
104
105 pub fn dtype(&self) -> TensorDtype {
107 self.dtype
108 }
109
110 pub fn num_elements(&self) -> usize {
112 self.shape.iter().product()
113 }
114
115 pub fn load_data(&self) -> Result<TensorData> {
118 let values: Vec<f32> = match self.dtype {
119 TensorDtype::F32 => self
120 .data
121 .chunks_exact(4)
122 .map(|c| f32::from_le_bytes([c[0], c[1], c[2], c[3]]))
123 .collect(),
124 TensorDtype::F16 => self
125 .data
126 .chunks_exact(2)
127 .map(|c| half::f16::from_le_bytes([c[0], c[1]]).to_f32())
128 .collect(),
129 TensorDtype::BF16 => self
130 .data
131 .chunks_exact(2)
132 .map(|c| half::bf16::from_le_bytes([c[0], c[1]]).to_f32())
133 .collect(),
134 TensorDtype::U8 => self.data.iter().map(|&b| b as f32).collect(),
135 };
136 if values.len() != self.num_elements() {
137 return Err(FormatError::Safetensors(format!(
138 "tensor {}: expected {} elements, got {}",
139 self.name,
140 self.num_elements(),
141 values.len()
142 )));
143 }
144 Ok(TensorData::new(values, self.shape.clone()))
145 }
146
147 pub fn load_to_tensor<B: Backend, const D: usize>(
149 &self,
150 device: &Device<B>,
151 ) -> Result<Tensor<B, D>> {
152 let data = self.load_data()?;
153 if self.shape.len() != D {
154 return Err(FormatError::Safetensors(format!(
155 "tensor {}: expected rank {D}, got {}",
156 self.name,
157 self.shape.len()
158 )));
159 }
160 Ok(Tensor::from_data(data, device))
161 }
162
163 pub fn load_int_tensor<B: Backend, const D: usize>(
167 &self,
168 device: &Device<B>,
169 ) -> Result<Tensor<B, D, Int>> {
170 if self.dtype != TensorDtype::U8 {
171 return Err(FormatError::Safetensors(format!(
172 "tensor {}: load_int_tensor requires U8, got {}",
173 self.name, self.dtype
174 )));
175 }
176 if self.shape.len() != D {
177 return Err(FormatError::Safetensors(format!(
178 "tensor {}: expected rank {D}, got {}",
179 self.name,
180 self.shape.len()
181 )));
182 }
183 let values: Vec<i32> = self.data.iter().map(|&b| b as i32).collect();
184 Ok(Tensor::from_data(
185 TensorData::new(values, self.shape.clone()),
186 device,
187 ))
188 }
189
190 pub fn raw_bytes(&self) -> &[u8] {
192 &self.data
193 }
194}
195
196impl<T: ModelSource + ?Sized> ModelSource for Box<T> {
199 fn metadata(&self) -> &crate::ModelMetadata {
200 (**self).metadata()
201 }
202 fn tensor_names(&self) -> Vec<String> {
203 (**self).tensor_names()
204 }
205 fn open_tensor(&self, name: &str) -> crate::Result<TensorReader<'_>> {
206 (**self).open_tensor(name)
207 }
208 fn tokenizer(&self) -> crate::Result<TokenizerSpec> {
209 (**self).tokenizer()
210 }
211 fn sampler_defaults(&self) -> Option<SamplerConfig> {
212 (**self).sampler_defaults()
213 }
214}
215
216#[derive(Debug, Clone, Default)]
218pub struct SamplerConfig { pub temperature: Option<f32>,
220 pub top_p: Option<f32>,
222 pub top_k: Option<usize>,
224 pub repetition_penalty: Option<f32>,
226 pub max_new_tokens: Option<usize>,
228}