1use nuvec::{
5 Array, DType, Result, add, dequantize, fast, matmul, multiply, quantize, quantized_matmul,
6 random, take,
7};
8
9use crate::{Module, Parameters};
10
11#[derive(Debug, Clone)]
14pub struct Linear {
15 pub weight: Array,
17 pub bias: Option<Array>,
19}
20
21impl Linear {
22 pub fn new(input_dims: usize, output_dims: usize, bias: bool) -> Result<Self> {
25 let scale = (1.0 / input_dims as f64).sqrt();
26 let draw = |shape: &[usize]| random::uniform(-scale, scale, shape, DType::F32, None);
27 let weight = draw(&[output_dims, input_dims])?;
28 let bias = if bias {
29 Some(draw(&[output_dims])?)
30 } else {
31 None
32 };
33 Ok(Self { weight, bias })
34 }
35
36 pub fn forward(&self, x: &Array) -> Result<Array> {
39 match &self.bias {
40 Some(b) => nuvec::addmm(b, x, &self.weight.t()?, 1.0, 1.0),
41 None => matmul(x, &self.weight.t()?),
42 }
43 }
44}
45
46impl Module for Linear {
47 fn visit(&mut self, p: &mut Parameters<'_>) {
48 p.param("weight", &mut self.weight);
49 p.optional("bias", &mut self.bias);
50 }
51}
52
53#[derive(Debug, Clone)]
58pub struct QuantizedLinear {
59 pub weight: Array,
61 pub scales: Array,
63 pub biases: Array,
65 pub bias: Option<Array>,
67 pub group_size: usize,
69 pub bits: u32,
71}
72
73impl QuantizedLinear {
74 pub fn from_linear(linear: &Linear, group_size: usize, bits: u32) -> Result<Self> {
77 let (weight, scales, biases) = quantize(&linear.weight, group_size, bits)?;
78 Ok(Self {
79 weight,
80 scales,
81 biases,
82 bias: linear.bias.clone(),
83 group_size,
84 bits,
85 })
86 }
87
88 pub fn dequantized_weight(&self) -> Result<Array> {
90 dequantize(
91 &self.weight,
92 &self.scales,
93 &self.biases,
94 self.group_size,
95 self.bits,
96 )
97 }
98
99 pub fn forward(&self, x: &Array) -> Result<Array> {
101 let y = quantized_matmul(
102 x,
103 &self.weight,
104 &self.scales,
105 &self.biases,
106 true,
107 self.group_size,
108 self.bits,
109 )?;
110 match &self.bias {
111 Some(b) => add(&y, b),
112 None => Ok(y),
113 }
114 }
115}
116
117impl Module for QuantizedLinear {
118 fn visit(&mut self, p: &mut Parameters<'_>) {
119 p.frozen("weight", &mut self.weight);
120 p.frozen("scales", &mut self.scales);
121 p.frozen("biases", &mut self.biases);
122 p.optional("bias", &mut self.bias);
123 }
124}
125
126#[derive(Debug, Clone)]
128pub struct Embedding {
129 pub weight: Array,
131}
132
133impl Embedding {
134 pub fn new(num_embeddings: usize, dims: usize) -> Result<Self> {
137 let scale = (1.0 / dims as f64).sqrt();
138 let weight = random::normal(&[num_embeddings, dims], DType::F32, None, Some(scale), None)?;
139 Ok(Self { weight })
140 }
141
142 pub fn forward(&self, x: &Array) -> Result<Array> {
144 take(&self.weight, x, Some(0))
145 }
146
147 pub fn as_linear(&self, x: &Array) -> Result<Array> {
149 matmul(x, &self.weight.t()?)
150 }
151}
152
153impl Module for Embedding {
154 fn visit(&mut self, p: &mut Parameters<'_>) {
155 p.param("weight", &mut self.weight);
156 }
157}
158
159#[derive(Debug, Clone)]
162pub struct QuantizedEmbedding {
163 pub weight: Array,
165 pub scales: Array,
167 pub biases: Array,
169 pub group_size: usize,
171 pub bits: u32,
173}
174
175impl QuantizedEmbedding {
176 pub fn from_embedding(embedding: &Embedding, group_size: usize, bits: u32) -> Result<Self> {
178 let (weight, scales, biases) = quantize(&embedding.weight, group_size, bits)?;
179 Ok(Self {
180 weight,
181 scales,
182 biases,
183 group_size,
184 bits,
185 })
186 }
187
188 pub fn forward(&self, x: &Array) -> Result<Array> {
190 dequantize(
191 &take(&self.weight, x, Some(0))?,
192 &take(&self.scales, x, Some(0))?,
193 &take(&self.biases, x, Some(0))?,
194 self.group_size,
195 self.bits,
196 )
197 }
198
199 pub fn as_linear(&self, x: &Array) -> Result<Array> {
201 quantized_matmul(
202 x,
203 &self.weight,
204 &self.scales,
205 &self.biases,
206 true,
207 self.group_size,
208 self.bits,
209 )
210 }
211}
212
213impl Module for QuantizedEmbedding {
214 fn visit(&mut self, p: &mut Parameters<'_>) {
215 p.frozen("weight", &mut self.weight);
216 p.frozen("scales", &mut self.scales);
217 p.frozen("biases", &mut self.biases);
218 }
219}
220
221#[derive(Debug, Clone)]
224pub struct RmsNorm {
225 pub weight: Array,
227 pub eps: f32,
229}
230
231impl RmsNorm {
232 pub fn new(dims: usize, eps: f32) -> Result<Self> {
234 Ok(Self {
235 weight: nuvec::ones(&[dims], DType::F32)?,
236 eps,
237 })
238 }
239
240 pub fn forward(&self, x: &Array) -> Result<Array> {
242 fast::rms_norm(x, Some(&self.weight), self.eps)
243 }
244}
245
246impl Module for RmsNorm {
247 fn visit(&mut self, p: &mut Parameters<'_>) {
248 p.param("weight", &mut self.weight);
249 }
250}
251
252#[derive(Debug, Clone)]
255pub struct LayerNorm {
256 pub weight: Option<Array>,
258 pub bias: Option<Array>,
260 pub eps: f32,
262}
263
264impl LayerNorm {
265 pub fn new(dims: usize, eps: f32, affine: bool, bias: bool) -> Result<Self> {
268 let weight = affine
269 .then(|| nuvec::ones(&[dims], DType::F32))
270 .transpose()?;
271 let bias = (affine && bias)
272 .then(|| nuvec::zeros(&[dims], DType::F32))
273 .transpose()?;
274 Ok(Self { weight, bias, eps })
275 }
276
277 pub fn forward(&self, x: &Array) -> Result<Array> {
279 fast::layer_norm(x, self.weight.as_ref(), self.bias.as_ref(), self.eps)
280 }
281}
282
283impl Module for LayerNorm {
284 fn visit(&mut self, p: &mut Parameters<'_>) {
285 p.optional("weight", &mut self.weight);
286 p.optional("bias", &mut self.bias);
287 }
288}
289
290#[derive(Debug, Clone)]
293pub struct Rope {
294 pub dims: usize,
296 pub traditional: bool,
298 pub base: f32,
300 pub scale: f32,
302}
303
304impl Rope {
305 pub fn new(dims: usize) -> Self {
307 Self {
308 dims,
309 traditional: false,
310 base: 10000.0,
311 scale: 1.0,
312 }
313 }
314
315 pub fn forward(&self, x: &Array, offset: usize) -> Result<Array> {
317 fast::rope(
318 x,
319 self.dims,
320 self.traditional,
321 Some(self.base),
322 self.scale,
323 &Array::scalar(offset as i32),
324 None,
325 )
326 }
327}
328
329impl Module for Rope {
330 fn visit(&mut self, _: &mut Parameters<'_>) {}
331}
332
333#[derive(Debug, Clone)]
335pub enum LoraBase {
336 Linear(Linear),
338 Quantized(QuantizedLinear),
340}
341
342#[derive(Debug, Clone)]
346pub struct LoraLinear {
347 pub base: LoraBase,
349 pub lora_a: Array,
351 pub lora_b: Array,
353 pub scale: f32,
355}
356
357impl LoraLinear {
358 pub fn from_base(base: LoraBase, r: usize, scale: f32) -> Result<Self> {
361 let (output_dims, input_dims) = match &base {
362 LoraBase::Linear(l) => (l.weight.shape()[0], l.weight.shape()[1]),
363 LoraBase::Quantized(q) => (
364 q.weight.shape()[0],
365 q.weight.shape()[1] * 32 / q.bits as usize,
366 ),
367 };
368 Linear::new(input_dims, output_dims, false)?;
371 let bound = 1.0 / (input_dims as f64).sqrt();
372 let lora_a = random::uniform(-bound, bound, &[input_dims, r], DType::F32, None)?;
373 let lora_b = nuvec::zeros(&[r, output_dims], DType::F32)?;
374 Ok(Self {
375 base,
376 lora_a,
377 lora_b,
378 scale,
379 })
380 }
381
382 pub fn forward(&self, x: &Array) -> Result<Array> {
384 let y = match &self.base {
385 LoraBase::Linear(l) => l.forward(x)?,
386 LoraBase::Quantized(q) => q.forward(x)?,
387 };
388 let z = matmul(&matmul(x, &self.lora_a)?, &self.lora_b)?;
389 add(&y, multiply(z, f64::from(self.scale))?.astype(x.dtype())?)
390 }
391
392 pub fn fuse(&self) -> Result<Linear> {
395 let (weight, bias) = match &self.base {
396 LoraBase::Linear(l) => (l.weight.clone(), l.bias.clone()),
397 LoraBase::Quantized(q) => (q.dequantized_weight()?, q.bias.clone()),
398 };
399 let delta = matmul(
400 &multiply(f64::from(self.scale), self.lora_b.t()?)?,
401 &self.lora_a.t()?,
402 )?
403 .astype(weight.dtype())?;
404 Ok(Linear {
405 weight: add(&weight, &delta)?,
406 bias,
407 })
408 }
409}
410
411impl Module for LoraLinear {
412 fn visit(&mut self, p: &mut Parameters<'_>) {
413 let base = &mut self.base;
415 p.freeze(|p| match base {
416 LoraBase::Linear(l) => p.module("linear", l),
417 LoraBase::Quantized(q) => p.module("linear", q),
418 });
419 p.param("lora_a", &mut self.lora_a);
420 p.param("lora_b", &mut self.lora_b);
421 }
422}