1use crate::{Module, ModuleBase, Parameter};
4use torsh_core::device::DeviceType;
5
6#[cfg(feature = "std")]
8use std::collections::HashMap;
9
10#[cfg(not(feature = "std"))]
11use hashbrown::HashMap;
12use torsh_core::error::{Result, TorshError};
13use torsh_tensor::Tensor;
14
15pub struct Embedding {
17 base: ModuleBase,
18 num_embeddings: usize,
19 embedding_dim: usize,
20 padding_idx: Option<usize>,
21 max_norm: Option<f32>,
22 norm_type: f32,
23 scale_grad_by_freq: bool,
24 sparse: bool,
25}
26
27impl Embedding {
28 pub fn new(num_embeddings: usize, embedding_dim: usize) -> Self {
29 let mut base = ModuleBase::new();
30
31 let weight = crate::init::xavier_uniform(&[num_embeddings, embedding_dim])
33 .expect("Failed to initialize embedding weight");
34 base.register_parameter("weight".to_string(), Parameter::new(weight));
35
36 Self {
37 base,
38 num_embeddings,
39 embedding_dim,
40 padding_idx: None,
41 max_norm: None,
42 norm_type: 2.0,
43 scale_grad_by_freq: false,
44 sparse: false,
45 }
46 }
47
48 pub fn with_padding_idx(
49 num_embeddings: usize,
50 embedding_dim: usize,
51 padding_idx: usize,
52 ) -> Self {
53 let mut embedding = Self::new(num_embeddings, embedding_dim);
54 embedding.padding_idx = Some(padding_idx);
55 embedding
56 }
57
58 pub fn with_config(
59 num_embeddings: usize,
60 embedding_dim: usize,
61 padding_idx: Option<usize>,
62 max_norm: Option<f32>,
63 norm_type: f32,
64 scale_grad_by_freq: bool,
65 sparse: bool,
66 ) -> Self {
67 let mut embedding = Self::new(num_embeddings, embedding_dim);
68 embedding.padding_idx = padding_idx;
69 embedding.max_norm = max_norm;
70 embedding.norm_type = norm_type;
71 embedding.scale_grad_by_freq = scale_grad_by_freq;
72 embedding.sparse = sparse;
73 embedding
74 }
75}
76
77impl Module for Embedding {
78 fn forward(&self, input: &Tensor) -> Result<Tensor> {
79 let weight = self.base.parameters["weight"].tensor().read().clone();
84 let weight_data = weight.to_vec()?;
85
86 let input_data = input.to_vec()?;
88 let binding = input.shape();
89 let input_shape = binding.dims();
90
91 let mut output_shape = input_shape.to_vec();
93 output_shape.push(self.embedding_dim);
94
95 let num_indices: usize = input_shape.iter().product();
97 let total_output_size = num_indices * self.embedding_dim;
98
99 let mut output_data = Vec::with_capacity(total_output_size);
100
101 for &idx_f32 in input_data.iter() {
103 let idx = idx_f32 as usize;
105
106 if let Some(padding_idx) = self.padding_idx {
108 if idx == padding_idx {
109 output_data.extend(vec![0.0; self.embedding_dim]);
111 continue;
112 }
113 }
114
115 if idx >= self.num_embeddings {
117 return Err(torsh_core::error::TorshError::InvalidArgument(format!(
118 "Index {} out of bounds for embedding with {} embeddings",
119 idx, self.num_embeddings
120 )));
121 }
122
123 let start_idx = idx * self.embedding_dim;
125 let end_idx = start_idx + self.embedding_dim;
126
127 let mut embedding_vec = weight_data[start_idx..end_idx].to_vec();
129
130 if let Some(max_norm) = self.max_norm {
132 let norm = if self.norm_type == 2.0 {
133 embedding_vec.iter().map(|x| x * x).sum::<f32>().sqrt()
135 } else {
136 embedding_vec
138 .iter()
139 .map(|x| x.abs().powf(self.norm_type))
140 .sum::<f32>()
141 .powf(1.0 / self.norm_type)
142 };
143
144 if norm > max_norm {
145 let scale = max_norm / norm;
147 for val in &mut embedding_vec {
148 *val *= scale;
149 }
150 }
151 }
152
153 output_data.extend(embedding_vec);
154 }
155
156 Tensor::from_vec(output_data, &output_shape)
157 }
158
159 fn parameters(&self) -> HashMap<String, Parameter> {
160 self.base.parameters.clone()
161 }
162
163 fn training(&self) -> bool {
164 self.base.training()
165 }
166
167 fn train(&mut self) {
168 self.base.set_training(true);
169 }
170
171 fn eval(&mut self) {
172 self.base.set_training(false);
173 }
174
175 fn set_training(&mut self, training: bool) {
176 self.base.set_training(training);
177 }
178
179 fn to_device(&mut self, device: DeviceType) -> Result<()> {
180 self.base.to_device(device)
181 }
182
183 fn named_parameters(&self) -> HashMap<String, Parameter> {
184 self.base.named_parameters()
185 }
186}
187
188impl std::fmt::Debug for Embedding {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 f.debug_struct("Embedding")
191 .field("num_embeddings", &self.num_embeddings)
192 .field("embedding_dim", &self.embedding_dim)
193 .field("padding_idx", &self.padding_idx)
194 .finish()
195 }
196}
197
198#[derive(Debug, Clone)]
204pub enum PositionalEncodingType {
205 Sinusoidal,
207 Learnable,
209 Relative,
211 Rotary { base: f32 },
213 Alibi,
215}
216
217pub struct SinusoidalPositionalEncoding {
222 base: ModuleBase,
223 d_model: usize,
224 max_len: usize,
225 dropout: f32,
226}
227
228impl SinusoidalPositionalEncoding {
229 pub fn new(d_model: usize, max_len: usize, dropout: f32) -> Self {
230 let mut base = ModuleBase::new();
231
232 let pe = create_sinusoidal_encoding(max_len, d_model);
234 base.register_parameter("pe".to_string(), Parameter::new(pe));
235
236 Self {
237 base,
238 d_model,
239 max_len,
240 dropout,
241 }
242 }
243}
244
245impl Module for SinusoidalPositionalEncoding {
246 fn forward(&self, input: &Tensor) -> Result<Tensor> {
247 let pe = self.base.parameters["pe"].tensor().read().clone();
248 let seq_len = input.shape().dims()[1]; let pe_slice = pe.narrow(0, 0, seq_len.min(self.max_len))?;
252
253 let output = input.add_op(&pe_slice.unsqueeze(0)?)?;
255
256 if self.dropout > 0.0 && self.training() {
258 crate::functional::dropout(&output, self.dropout, self.training())
259 } else {
260 Ok(output)
261 }
262 }
263
264 fn parameters(&self) -> HashMap<String, Parameter> {
265 self.base.parameters.clone()
266 }
267
268 fn training(&self) -> bool {
269 self.base.training()
270 }
271
272 fn train(&mut self) {
273 self.base.set_training(true);
274 }
275
276 fn eval(&mut self) {
277 self.base.set_training(false);
278 }
279
280 fn set_training(&mut self, training: bool) {
281 self.base.set_training(training);
282 }
283
284 fn to_device(&mut self, device: DeviceType) -> Result<()> {
285 self.base.to_device(device)
286 }
287
288 fn named_parameters(&self) -> HashMap<String, Parameter> {
289 self.base.named_parameters()
290 }
291}
292
293pub struct LearnablePositionalEncoding {
297 base: ModuleBase,
298 d_model: usize,
299 max_len: usize,
300 dropout: f32,
301}
302
303impl LearnablePositionalEncoding {
304 pub fn new(d_model: usize, max_len: usize, dropout: f32) -> Self {
305 let mut base = ModuleBase::new();
306
307 let pe = crate::init::xavier_uniform(&[max_len, d_model])
309 .expect("Failed to initialize positional encoding");
310 base.register_parameter("pe".to_string(), Parameter::new(pe));
311
312 Self {
313 base,
314 d_model,
315 max_len,
316 dropout,
317 }
318 }
319}
320
321impl Module for LearnablePositionalEncoding {
322 fn forward(&self, input: &Tensor) -> Result<Tensor> {
323 let pe = self.base.parameters["pe"].tensor().read().clone();
324 let seq_len = input.shape().dims()[1]; let pe_slice = pe.narrow(0, 0, seq_len.min(self.max_len))?;
328
329 let output = input.add_op(&pe_slice.unsqueeze(0)?)?;
331
332 if self.dropout > 0.0 && self.training() {
334 crate::functional::dropout(&output, self.dropout, self.training())
335 } else {
336 Ok(output)
337 }
338 }
339
340 fn parameters(&self) -> HashMap<String, Parameter> {
341 self.base.parameters.clone()
342 }
343
344 fn training(&self) -> bool {
345 self.base.training()
346 }
347
348 fn train(&mut self) {
349 self.base.set_training(true);
350 }
351
352 fn eval(&mut self) {
353 self.base.set_training(false);
354 }
355
356 fn set_training(&mut self, training: bool) {
357 self.base.set_training(training);
358 }
359
360 fn to_device(&mut self, device: DeviceType) -> Result<()> {
361 self.base.to_device(device)
362 }
363
364 fn named_parameters(&self) -> HashMap<String, Parameter> {
365 self.base.named_parameters()
366 }
367}
368
369pub struct RotaryPositionalEmbedding {
374 d_model: usize,
375 base: f32,
376 max_seq_len: usize,
377}
378
379impl RotaryPositionalEmbedding {
380 pub fn new(d_model: usize, base: f32, max_seq_len: usize) -> Self {
381 Self {
382 d_model,
383 base,
384 max_seq_len,
385 }
386 }
387
388 pub fn apply_rope(&self, q: &Tensor, k: &Tensor) -> Result<(Tensor, Tensor)> {
396 let seq_len = q.shape().dims()[2];
397 let head_dim = q.shape().dims()[3];
398
399 let freqs = self.create_frequencies(seq_len, head_dim)?;
401
402 let q_rot = self.rotate_tensor(q, &freqs)?;
404 let k_rot = self.rotate_tensor(k, &freqs)?;
405
406 Ok((q_rot, k_rot))
407 }
408
409 fn create_frequencies(&self, seq_len: usize, head_dim: usize) -> Result<Tensor> {
410 let mut freqs = Vec::new();
411
412 for pos in 0..seq_len {
413 for i in (0..head_dim).step_by(2) {
414 let freq = 1.0 / self.base.powf(i as f32 / head_dim as f32);
415 let angle = pos as f32 * freq;
416
417 freqs.push(angle.cos());
418 freqs.push(-angle.sin());
419 freqs.push(angle.sin());
420 freqs.push(angle.cos());
421 }
422 }
423
424 Tensor::from_vec(freqs, &[seq_len, head_dim, 2, 2])
425 }
426
427 fn rotate_tensor(&self, x: &Tensor, _freqs: &Tensor) -> Result<Tensor> {
428 Ok(x.clone())
432 }
433}
434
435pub struct AlibiPositionalBias {
440 num_heads: usize,
441 max_seq_len: usize,
442}
443
444impl AlibiPositionalBias {
445 pub fn new(num_heads: usize, max_seq_len: usize) -> Self {
446 Self {
447 num_heads,
448 max_seq_len,
449 }
450 }
451
452 pub fn create_bias(&self, seq_len: usize) -> Result<Tensor> {
459 let mut bias_data = Vec::new();
460
461 let slopes = self.get_slopes();
463
464 for head in 0..self.num_heads {
465 let slope = slopes[head];
466
467 for i in 0..seq_len {
468 for j in 0..seq_len {
469 let distance = (i as i32 - j as i32).abs() as f32;
471 let bias = -slope * distance;
472 bias_data.push(bias);
473 }
474 }
475 }
476
477 Tensor::from_vec(bias_data, &[self.num_heads, seq_len, seq_len])
478 }
479
480 fn get_slopes(&self) -> Vec<f32> {
481 let ratio = 2.0_f32.powf(-8.0 / self.num_heads as f32);
482 let mut slopes = Vec::new();
483
484 for i in 0..self.num_heads {
485 let slope = ratio.powf(i as f32 + 1.0);
486 slopes.push(slope);
487 }
488
489 slopes
490 }
491}
492
493pub struct RelativePositionalEncoding {
498 base: ModuleBase,
499 d_model: usize,
500 max_relative_distance: usize,
501}
502
503impl RelativePositionalEncoding {
504 pub fn new(d_model: usize, max_relative_distance: usize) -> Self {
505 let mut base = ModuleBase::new();
506
507 let num_positions = 2 * max_relative_distance + 1;
510 let relative_pe = crate::init::xavier_uniform(&[num_positions, d_model])
511 .expect("Failed to initialize relative positional encoding");
512 base.register_parameter("relative_pe".to_string(), Parameter::new(relative_pe));
513
514 Self {
515 base,
516 d_model,
517 max_relative_distance,
518 }
519 }
520
521 pub fn get_relative_embeddings(&self, seq_len: usize) -> Result<Tensor> {
528 let relative_pe = self.base.parameters["relative_pe"].tensor().read().clone();
529 let mut relative_data = Vec::new();
530
531 for i in 0..seq_len {
532 for j in 0..seq_len {
533 let relative_distance = (i as i32 - j as i32).clamp(
535 -(self.max_relative_distance as i32),
536 self.max_relative_distance as i32,
537 );
538
539 let idx = (relative_distance + self.max_relative_distance as i32) as usize;
541
542 let embedding = relative_pe.narrow(0, idx as i64, 1)?.squeeze(0)?;
544 let embedding_data = embedding.to_vec()?;
545 relative_data.extend(embedding_data);
546 }
547 }
548
549 Tensor::from_vec(relative_data, &[seq_len, seq_len, self.d_model])
550 }
551}
552
553impl Module for RelativePositionalEncoding {
554 fn forward(&self, input: &Tensor) -> Result<Tensor> {
555 let input_shape_binding = input.shape();
560 let input_shape = input_shape_binding.dims();
561
562 match input_shape.len() {
564 3 => {
565 let batch_size = input_shape[0];
568 let seq_len = input_shape[1];
569 let d_model = input_shape[2];
570
571 let max_relative_position = (seq_len - 1) * 2 + 1;
574
575 let embeddings = self.base.parameters.get("weight").ok_or_else(|| {
577 TorshError::InvalidArgument(
578 "RelativePositionalEncoding missing weight parameter".to_string(),
579 )
580 })?;
581
582 let embedding_data = embeddings.tensor().read().to_vec()?;
583 let input_data = input.to_vec()?;
584
585 let mut output_data = vec![0.0f32; batch_size * seq_len * d_model];
586
587 for b in 0..batch_size {
589 for i in 0..seq_len {
590 for j in 0..seq_len {
591 let relative_pos = (j as i32 - i as i32) + (seq_len - 1) as i32;
593 let relative_pos_clamped =
594 relative_pos.max(0).min(max_relative_position as i32 - 1) as usize;
595
596 let emb_start = relative_pos_clamped * d_model;
598
599 for d in 0..d_model {
601 let input_idx = b * seq_len * d_model + i * d_model + d;
602 let output_idx = b * seq_len * d_model + i * d_model + d;
603
604 if j == 0 {
605 output_data[output_idx] = input_data[input_idx];
607 }
608
609 output_data[output_idx] +=
611 embedding_data[emb_start + d] / seq_len as f32;
612 }
613 }
614 }
615 }
616
617 Tensor::from_vec(output_data, input_shape)
618 }
619 4 => {
620 let batch_size = input_shape[0];
623 let num_heads = input_shape[1];
624 let seq_len_q = input_shape[2];
625 let seq_len_k = input_shape[3];
626
627 if seq_len_q != seq_len_k {
629 return Err(TorshError::InvalidArgument(
630 "RelativePositionalEncoding requires square attention matrices".to_string(),
631 ));
632 }
633
634 let seq_len = seq_len_q;
635 let max_relative_position = (seq_len - 1) * 2 + 1;
636
637 let embeddings = self.base.parameters.get("weight").ok_or_else(|| {
639 TorshError::InvalidArgument(
640 "RelativePositionalEncoding missing weight parameter".to_string(),
641 )
642 })?;
643
644 let embedding_data = embeddings.tensor().read().to_vec()?;
645 let input_data = input.to_vec()?;
646
647 let mut output_data = vec![0.0f32; batch_size * num_heads * seq_len * seq_len];
648
649 for b in 0..batch_size {
651 for h in 0..num_heads {
652 for i in 0..seq_len {
653 for j in 0..seq_len {
654 let relative_pos = (j as i32 - i as i32) + (seq_len - 1) as i32;
656 let relative_pos_clamped =
657 relative_pos.max(0).min(max_relative_position as i32 - 1)
658 as usize;
659
660 let idx = b * num_heads * seq_len * seq_len
662 + h * seq_len * seq_len
663 + i * seq_len
664 + j;
665
666 output_data[idx] =
668 input_data[idx] + embedding_data[relative_pos_clamped];
669 }
670 }
671 }
672 }
673
674 Tensor::from_vec(output_data, input_shape)
675 }
676 _ => {
677 Ok(input.clone())
679 }
680 }
681 }
682
683 fn parameters(&self) -> HashMap<String, Parameter> {
684 self.base.parameters.clone()
685 }
686
687 fn training(&self) -> bool {
688 self.base.training()
689 }
690
691 fn train(&mut self) {
692 self.base.set_training(true);
693 }
694
695 fn eval(&mut self) {
696 self.base.set_training(false);
697 }
698
699 fn set_training(&mut self, training: bool) {
700 self.base.set_training(training);
701 }
702
703 fn to_device(&mut self, device: DeviceType) -> Result<()> {
704 self.base.to_device(device)
705 }
706
707 fn named_parameters(&self) -> HashMap<String, Parameter> {
708 self.base.named_parameters()
709 }
710}
711
712pub struct PositionInterpolation;
714
715impl PositionInterpolation {
716 pub fn interpolate_positions(pe: &Tensor, new_max_len: usize) -> Result<Tensor> {
724 let shape = pe.shape();
725 let pe_shape = shape.dims();
726 let old_max_len = pe_shape[0];
727 let d_model = pe_shape[1];
728
729 if new_max_len <= old_max_len {
730 return pe.narrow(0, 0, new_max_len);
732 }
733
734 let scale_factor = old_max_len as f32 / new_max_len as f32;
736 let mut interpolated_data = Vec::new();
737
738 for new_pos in 0..new_max_len {
739 let old_pos_f = new_pos as f32 * scale_factor;
740 let old_pos_low = old_pos_f.floor() as usize;
741 let old_pos_high = (old_pos_low + 1).min(old_max_len - 1);
742 let alpha = old_pos_f - old_pos_low as f32;
743
744 let pe_low = pe.narrow(0, old_pos_low as i64, 1)?.squeeze(0)?;
746 let pe_high = pe.narrow(0, old_pos_high as i64, 1)?.squeeze(0)?;
747
748 let pe_low_data = pe_low.to_vec()?;
750 let pe_high_data = pe_high.to_vec()?;
751
752 for i in 0..d_model {
753 let interpolated = pe_low_data[i] * (1.0 - alpha) + pe_high_data[i] * alpha;
754 interpolated_data.push(interpolated);
755 }
756 }
757
758 Tensor::from_vec(interpolated_data, &[new_max_len, d_model])
759 }
760
761 pub fn interpolate_rope_frequencies(base: f32, scale_factor: f32, d_model: usize) -> Vec<f32> {
763 let mut freqs = Vec::new();
764
765 for i in (0..d_model).step_by(2) {
766 let freq = 1.0 / (base * scale_factor).powf(i as f32 / d_model as f32);
767 freqs.push(freq);
768 }
769
770 freqs
771 }
772}
773
774pub struct SinusoidalPositionEmbedding {
828 base: ModuleBase,
829 d_model: usize,
830 max_len: usize,
831 learned_scale: bool,
832}
833
834impl SinusoidalPositionEmbedding {
835 pub fn new(d_model: usize, max_len: usize) -> Result<Self> {
847 if d_model % 2 != 0 {
848 return Err(TorshError::InvalidArgument(format!(
849 "d_model must be even, got {}",
850 d_model
851 )));
852 }
853
854 let mut base = ModuleBase::new();
855
856 let embeddings = Self::create_embeddings(max_len, d_model)?;
858 base.register_parameter("embeddings".to_string(), Parameter::new(embeddings));
859
860 Ok(Self {
861 base,
862 d_model,
863 max_len,
864 learned_scale: false,
865 })
866 }
867
868 pub fn with_learned_scale(d_model: usize, max_len: usize) -> Result<Self> {
879 let mut layer = Self::new(d_model, max_len)?;
880 layer.learned_scale = true;
881
882 let scale = Tensor::from_vec(vec![1.0], &[1])?;
884 layer
885 .base
886 .register_parameter("scale".to_string(), Parameter::new(scale));
887
888 Ok(layer)
889 }
890
891 fn create_embeddings(max_len: usize, d_model: usize) -> Result<Tensor> {
897 let mut embeddings = vec![0.0f32; max_len * d_model];
898
899 let mut div_term = Vec::with_capacity(d_model / 2);
901 for i in (0..d_model).step_by(2) {
902 let exponent = i as f32 / d_model as f32;
903 div_term.push(1.0 / 10000.0_f32.powf(exponent));
904 }
905
906 for pos in 0..max_len {
908 let pos_f = pos as f32;
909
910 for (i, &div) in div_term.iter().enumerate() {
911 let angle = pos_f * div;
912
913 embeddings[pos * d_model + (i * 2)] = angle.sin();
915
916 if (i * 2 + 1) < d_model {
918 embeddings[pos * d_model + (i * 2 + 1)] = angle.cos();
919 }
920 }
921 }
922
923 Tensor::from_vec(embeddings, &[max_len, d_model])
924 }
925
926 pub fn get_embeddings(&self, positions: &Tensor) -> Result<Tensor> {
934 let embeddings = self.base.parameters["embeddings"].tensor().read().clone();
935 let positions_data = positions.to_vec()?;
936 let binding = positions.shape();
937 let positions_shape = binding.dims();
938
939 for &pos in positions_data.iter() {
941 let pos_usize = pos as usize;
942 if pos_usize >= self.max_len {
943 return Err(TorshError::InvalidArgument(format!(
944 "Position {} exceeds max_len {}",
945 pos_usize, self.max_len
946 )));
947 }
948 }
949
950 match positions_shape.len() {
952 1 => {
953 let seq_len = positions_shape[0];
956 let mut output = Vec::with_capacity(seq_len * self.d_model);
957 let embeddings_data = embeddings.to_vec()?;
958
959 for &pos in positions_data.iter() {
960 let pos_idx = pos as usize;
961 let start = pos_idx * self.d_model;
962 let end = start + self.d_model;
963 output.extend_from_slice(&embeddings_data[start..end]);
964 }
965
966 let mut result = Tensor::from_vec(output, &[seq_len, self.d_model])?;
967
968 if self.learned_scale {
970 let scale = self.base.parameters["scale"].tensor().read().clone();
971 result = result.mul_op(&scale)?;
972 }
973
974 Ok(result)
975 }
976 2 => {
977 let batch_size = positions_shape[0];
980 let seq_len = positions_shape[1];
981 let mut output = Vec::with_capacity(batch_size * seq_len * self.d_model);
982 let embeddings_data = embeddings.to_vec()?;
983
984 for &pos in positions_data.iter() {
985 let pos_idx = pos as usize;
986 let start = pos_idx * self.d_model;
987 let end = start + self.d_model;
988 output.extend_from_slice(&embeddings_data[start..end]);
989 }
990
991 let mut result = Tensor::from_vec(output, &[batch_size, seq_len, self.d_model])?;
992
993 if self.learned_scale {
995 let scale = self.base.parameters["scale"].tensor().read().clone();
996 result = result.mul_op(&scale)?;
997 }
998
999 Ok(result)
1000 }
1001 _ => Err(TorshError::InvalidArgument(format!(
1002 "Expected 1D or 2D positions tensor, got {}D",
1003 positions_shape.len()
1004 ))),
1005 }
1006 }
1007
1008 pub fn get_embeddings_for_length(&self, seq_len: usize) -> Result<Tensor> {
1016 if seq_len > self.max_len {
1017 return Err(TorshError::InvalidArgument(format!(
1018 "Sequence length {} exceeds max_len {}",
1019 seq_len, self.max_len
1020 )));
1021 }
1022
1023 let embeddings = self.base.parameters["embeddings"].tensor().read().clone();
1024 let mut result = embeddings.narrow(0, 0, seq_len)?;
1025
1026 if self.learned_scale {
1028 let scale = self.base.parameters["scale"].tensor().read().clone();
1029 result = result.mul_op(&scale)?;
1030 }
1031
1032 Ok(result)
1033 }
1034
1035 pub fn max_len(&self) -> usize {
1037 self.max_len
1038 }
1039
1040 pub fn d_model(&self) -> usize {
1042 self.d_model
1043 }
1044}
1045
1046impl Module for SinusoidalPositionEmbedding {
1047 fn forward(&self, input: &Tensor) -> Result<Tensor> {
1048 let binding = input.shape();
1052 let input_shape = binding.dims();
1053
1054 match input_shape.len() {
1055 1 | 2 => {
1056 self.get_embeddings(input)
1058 }
1059 3 => {
1060 let seq_len = input_shape[1];
1062 let pos_emb = self.get_embeddings_for_length(seq_len)?;
1063
1064 let pos_emb_broadcasted = pos_emb.unsqueeze(0)?;
1067 input.add_op(&pos_emb_broadcasted)
1068 }
1069 _ => Err(TorshError::InvalidArgument(format!(
1070 "Unexpected input shape: {:?}",
1071 input_shape
1072 ))),
1073 }
1074 }
1075
1076 fn parameters(&self) -> HashMap<String, Parameter> {
1077 if self.learned_scale {
1078 let mut params = HashMap::new();
1080 if let Some(scale) = self.base.parameters.get("scale") {
1081 params.insert("scale".to_string(), scale.clone());
1082 }
1083 params
1084 } else {
1085 HashMap::new()
1087 }
1088 }
1089
1090 fn training(&self) -> bool {
1091 self.base.training()
1092 }
1093
1094 fn train(&mut self) {
1095 self.base.set_training(true);
1096 }
1097
1098 fn eval(&mut self) {
1099 self.base.set_training(false);
1100 }
1101
1102 fn set_training(&mut self, training: bool) {
1103 self.base.set_training(training);
1104 }
1105
1106 fn to_device(&mut self, device: DeviceType) -> Result<()> {
1107 self.base.to_device(device)
1108 }
1109
1110 fn named_parameters(&self) -> HashMap<String, Parameter> {
1111 if self.learned_scale {
1112 let mut params = HashMap::new();
1114 if let Some(scale) = self.base.parameters.get("scale") {
1115 params.insert("scale".to_string(), scale.clone());
1116 }
1117 params
1118 } else {
1119 HashMap::new()
1121 }
1122 }
1123}
1124
1125impl std::fmt::Debug for SinusoidalPositionEmbedding {
1126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1127 f.debug_struct("SinusoidalPositionEmbedding")
1128 .field("d_model", &self.d_model)
1129 .field("max_len", &self.max_len)
1130 .field("learned_scale", &self.learned_scale)
1131 .finish()
1132 }
1133}
1134
1135fn create_sinusoidal_encoding(max_len: usize, d_model: usize) -> Tensor {
1137 let mut pos_encoding = vec![0.0f32; max_len * d_model];
1138
1139 for pos in 0..max_len {
1140 for i in (0..d_model).step_by(2) {
1141 let angle = pos as f32 / 10000.0_f32.powf(i as f32 / d_model as f32);
1142
1143 pos_encoding[pos * d_model + i] = angle.sin();
1144 if i + 1 < d_model {
1145 pos_encoding[pos * d_model + i + 1] = angle.cos();
1146 }
1147 }
1148 }
1149
1150 Tensor::from_vec(pos_encoding, &[max_len, d_model]).expect("tensor creation should succeed")
1151}
1152
1153impl std::fmt::Debug for SinusoidalPositionalEncoding {
1154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1155 f.debug_struct("SinusoidalPositionalEncoding")
1156 .field("d_model", &self.d_model)
1157 .field("max_len", &self.max_len)
1158 .field("dropout", &self.dropout)
1159 .finish()
1160 }
1161}
1162
1163impl std::fmt::Debug for LearnablePositionalEncoding {
1164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1165 f.debug_struct("LearnablePositionalEncoding")
1166 .field("d_model", &self.d_model)
1167 .field("max_len", &self.max_len)
1168 .field("dropout", &self.dropout)
1169 .finish()
1170 }
1171}
1172
1173impl std::fmt::Debug for RotaryPositionalEmbedding {
1174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1175 f.debug_struct("RotaryPositionalEmbedding")
1176 .field("d_model", &self.d_model)
1177 .field("base", &self.base)
1178 .field("max_seq_len", &self.max_seq_len)
1179 .finish()
1180 }
1181}
1182
1183impl std::fmt::Debug for AlibiPositionalBias {
1184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1185 f.debug_struct("AlibiPositionalBias")
1186 .field("num_heads", &self.num_heads)
1187 .field("max_seq_len", &self.max_seq_len)
1188 .finish()
1189 }
1190}
1191
1192impl std::fmt::Debug for RelativePositionalEncoding {
1193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1194 f.debug_struct("RelativePositionalEncoding")
1195 .field("d_model", &self.d_model)
1196 .field("max_relative_distance", &self.max_relative_distance)
1197 .finish()
1198 }
1199}
1200
1201#[cfg(test)]
1206mod tests {
1207 use super::*;
1208 use approx::assert_relative_eq;
1209
1210 #[test]
1211 fn test_embedding_basic_lookup() -> Result<()> {
1212 let mut embedding = Embedding::new(5, 3);
1214
1215 let weight_data = vec![
1217 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, ];
1223 let weight = Tensor::from_vec(weight_data, &[5, 3])?;
1224 *embedding
1225 .base
1226 .parameters
1227 .get_mut("weight")
1228 .expect("operation should succeed")
1229 .tensor()
1230 .write() = weight;
1231
1232 let input = Tensor::from_vec(vec![2.0], &[1])?;
1234 let output = embedding.forward(&input)?;
1235
1236 let output_data = output.to_vec()?;
1237 assert_eq!(output.shape().dims(), &[1, 3]);
1238 assert_relative_eq!(output_data[0], 7.0, epsilon = 1e-6);
1239 assert_relative_eq!(output_data[1], 8.0, epsilon = 1e-6);
1240 assert_relative_eq!(output_data[2], 9.0, epsilon = 1e-6);
1241
1242 Ok(())
1243 }
1244
1245 #[test]
1246 fn test_embedding_multiple_indices() -> Result<()> {
1247 let mut embedding = Embedding::new(4, 2);
1249
1250 let weight_data = vec![
1251 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, ];
1256 let weight = Tensor::from_vec(weight_data, &[4, 2])?;
1257 *embedding
1258 .base
1259 .parameters
1260 .get_mut("weight")
1261 .expect("operation should succeed")
1262 .tensor()
1263 .write() = weight;
1264
1265 let input = Tensor::from_vec(vec![0.0, 2.0, 1.0], &[3])?;
1267 let output = embedding.forward(&input)?;
1268
1269 let output_data = output.to_vec()?;
1270 assert_eq!(output.shape().dims(), &[3, 2]);
1271
1272 assert_relative_eq!(output_data[0], 1.0, epsilon = 1e-6);
1274 assert_relative_eq!(output_data[1], 2.0, epsilon = 1e-6);
1275
1276 assert_relative_eq!(output_data[2], 5.0, epsilon = 1e-6);
1278 assert_relative_eq!(output_data[3], 6.0, epsilon = 1e-6);
1279
1280 assert_relative_eq!(output_data[4], 3.0, epsilon = 1e-6);
1282 assert_relative_eq!(output_data[5], 4.0, epsilon = 1e-6);
1283
1284 Ok(())
1285 }
1286
1287 #[test]
1288 fn test_embedding_2d_indices() -> Result<()> {
1289 let mut embedding = Embedding::new(3, 2);
1291
1292 let weight_data = vec![
1293 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, ];
1297 let weight = Tensor::from_vec(weight_data, &[3, 2])?;
1298 *embedding
1299 .base
1300 .parameters
1301 .get_mut("weight")
1302 .expect("operation should succeed")
1303 .tensor()
1304 .write() = weight;
1305
1306 let input = Tensor::from_vec(vec![0.0, 1.0, 2.0, 0.0], &[2, 2])?;
1310 let output = embedding.forward(&input)?;
1311
1312 assert_eq!(output.shape().dims(), &[2, 2, 2]); let output_data = output.to_vec()?;
1315
1316 assert_relative_eq!(output_data[0], 1.0, epsilon = 1e-6);
1318 assert_relative_eq!(output_data[1], 2.0, epsilon = 1e-6);
1319
1320 assert_relative_eq!(output_data[2], 3.0, epsilon = 1e-6);
1322 assert_relative_eq!(output_data[3], 4.0, epsilon = 1e-6);
1323
1324 assert_relative_eq!(output_data[4], 5.0, epsilon = 1e-6);
1326 assert_relative_eq!(output_data[5], 6.0, epsilon = 1e-6);
1327
1328 assert_relative_eq!(output_data[6], 1.0, epsilon = 1e-6);
1330 assert_relative_eq!(output_data[7], 2.0, epsilon = 1e-6);
1331
1332 Ok(())
1333 }
1334
1335 #[test]
1336 fn test_embedding_with_padding_idx() -> Result<()> {
1337 let mut embedding = Embedding::with_padding_idx(4, 3, 0);
1339
1340 let weight_data = vec![
1341 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, ];
1346 let weight = Tensor::from_vec(weight_data, &[4, 3])?;
1347 *embedding
1348 .base
1349 .parameters
1350 .get_mut("weight")
1351 .expect("operation should succeed")
1352 .tensor()
1353 .write() = weight;
1354
1355 let input = Tensor::from_vec(vec![1.0, 0.0, 2.0], &[3])?;
1357 let output = embedding.forward(&input)?;
1358
1359 let output_data = output.to_vec()?;
1360
1361 assert_relative_eq!(output_data[0], 4.0, epsilon = 1e-6);
1363 assert_relative_eq!(output_data[1], 5.0, epsilon = 1e-6);
1364 assert_relative_eq!(output_data[2], 6.0, epsilon = 1e-6);
1365
1366 assert_relative_eq!(output_data[3], 0.0, epsilon = 1e-6);
1368 assert_relative_eq!(output_data[4], 0.0, epsilon = 1e-6);
1369 assert_relative_eq!(output_data[5], 0.0, epsilon = 1e-6);
1370
1371 assert_relative_eq!(output_data[6], 7.0, epsilon = 1e-6);
1373 assert_relative_eq!(output_data[7], 8.0, epsilon = 1e-6);
1374 assert_relative_eq!(output_data[8], 9.0, epsilon = 1e-6);
1375
1376 Ok(())
1377 }
1378
1379 #[test]
1380 fn test_embedding_out_of_bounds() {
1381 let mut embedding = Embedding::new(3, 2);
1383
1384 let weight_data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1385 let weight = Tensor::from_vec(weight_data, &[3, 2]).expect("Tensor should succeed");
1386 *embedding
1387 .base
1388 .parameters
1389 .get_mut("weight")
1390 .expect("operation should succeed")
1391 .tensor()
1392 .write() = weight;
1393
1394 let input = Tensor::from_vec(vec![5.0], &[1]).expect("Tensor should succeed");
1396 let result = embedding.forward(&input);
1397
1398 assert!(result.is_err());
1399 if let Err(torsh_core::error::TorshError::InvalidArgument(msg)) = result {
1400 assert!(msg.contains("out of bounds"));
1401 } else {
1402 panic!("Expected InvalidArgument error for out-of-bounds index");
1403 }
1404 }
1405
1406 #[test]
1407 fn test_embedding_with_max_norm() -> Result<()> {
1408 let mut embedding = Embedding::with_config(
1410 3,
1411 2,
1412 None, Some(1.0), 2.0, false, false, );
1418
1419 let weight_data = vec![
1421 3.0, 4.0, 1.0, 0.0, 0.6, 0.8, ];
1425 let weight = Tensor::from_vec(weight_data, &[3, 2])?;
1426 *embedding
1427 .base
1428 .parameters
1429 .get_mut("weight")
1430 .expect("operation should succeed")
1431 .tensor()
1432 .write() = weight;
1433
1434 let input = Tensor::from_vec(vec![0.0], &[1])?;
1436 let output = embedding.forward(&input)?;
1437
1438 let output_data = output.to_vec()?;
1439
1440 assert_relative_eq!(output_data[0], 0.6, epsilon = 1e-6);
1443 assert_relative_eq!(output_data[1], 0.8, epsilon = 1e-6);
1444
1445 let norm = (output_data[0] * output_data[0] + output_data[1] * output_data[1]).sqrt();
1447 assert_relative_eq!(norm, 1.0, epsilon = 1e-6);
1448
1449 Ok(())
1450 }
1451
1452 #[test]
1453 fn test_embedding_shape_preservation() -> Result<()> {
1454 let embedding = Embedding::new(10, 5);
1456
1457 let input1d = Tensor::from_vec(vec![0.0, 1.0, 2.0], &[3])?;
1459 let output1d = embedding.forward(&input1d)?;
1460 assert_eq!(output1d.shape().dims(), &[3, 5]);
1461
1462 let input2d = Tensor::from_vec(vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], &[2, 4])?;
1464 let output2d = embedding.forward(&input2d)?;
1465 assert_eq!(output2d.shape().dims(), &[2, 4, 5]);
1466
1467 let input3d = Tensor::from_vec(
1469 vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 0.0, 1.0],
1470 &[2, 3, 2],
1471 )?;
1472 let output3d = embedding.forward(&input3d)?;
1473 assert_eq!(output3d.shape().dims(), &[2, 3, 2, 5]);
1474
1475 Ok(())
1476 }
1477
1478 #[test]
1483 fn test_sinusoidal_position_embedding_creation() -> Result<()> {
1484 let pos_emb = SinusoidalPositionEmbedding::new(64, 100)?;
1486 assert_eq!(pos_emb.d_model(), 64);
1487 assert_eq!(pos_emb.max_len(), 100);
1488
1489 let result = SinusoidalPositionEmbedding::new(63, 100);
1491 assert!(result.is_err());
1492
1493 Ok(())
1494 }
1495
1496 #[test]
1497 fn test_sinusoidal_position_embedding_forward() -> Result<()> {
1498 let pos_emb = SinusoidalPositionEmbedding::new(128, 1000)?;
1500
1501 let positions = Tensor::from_vec(vec![0.0, 1.0, 2.0, 3.0, 4.0], &[5])?;
1503 let embeddings = pos_emb.forward(&positions)?;
1504
1505 assert_eq!(embeddings.shape().dims(), &[5, 128]);
1507
1508 let data = embeddings.to_vec()?;
1510 let sum: f32 = data.iter().sum();
1511 assert!(sum.abs() > 0.1);
1512
1513 Ok(())
1514 }
1515
1516 #[test]
1517 fn test_sinusoidal_position_embedding_sequence_length() -> Result<()> {
1518 let pos_emb = SinusoidalPositionEmbedding::new(64, 200)?;
1519
1520 let embeddings = pos_emb.get_embeddings_for_length(50)?;
1522
1523 assert_eq!(embeddings.shape().dims(), &[50, 64]);
1525
1526 let emb0 = embeddings.narrow(0, 0, 1)?.squeeze(0)?;
1528 let data0 = emb0.to_vec()?;
1529
1530 assert_relative_eq!(data0[0], 0.0, epsilon = 1e-6); assert_relative_eq!(data0[1], 1.0, epsilon = 1e-6); Ok(())
1536 }
1537
1538 #[test]
1539 fn test_sinusoidal_position_embedding_mathematical_properties() -> Result<()> {
1540 let d_model = 64;
1541 let pos_emb = SinusoidalPositionEmbedding::new(d_model, 100)?;
1542
1543 let positions = Tensor::from_vec(vec![0.0, 1.0, 2.0], &[3])?;
1545 let embeddings = pos_emb.forward(&positions)?;
1546 let data = embeddings.to_vec()?;
1547
1548 assert_relative_eq!(data[0], 0.0, epsilon = 1e-6); assert_relative_eq!(data[1], 1.0, epsilon = 1e-6); let pos1_start = d_model;
1555 assert_relative_eq!(data[pos1_start], (1.0_f32).sin(), epsilon = 1e-5);
1556 assert_relative_eq!(data[pos1_start + 1], (1.0_f32).cos(), epsilon = 1e-5);
1557
1558 Ok(())
1559 }
1560
1561 #[test]
1562 fn test_sinusoidal_position_embedding_periodicity() -> Result<()> {
1563 let pos_emb = SinusoidalPositionEmbedding::new(128, 10000)?;
1564
1565 let pos1 = Tensor::from_vec(vec![0.0], &[1])?;
1567 let emb1 = pos_emb.forward(&pos1)?;
1568
1569 let pos2 = Tensor::from_vec(vec![100.0], &[1])?;
1570 let emb2 = pos_emb.forward(&pos2)?;
1571
1572 let data1 = emb1.to_vec()?;
1574 let data2 = emb2.to_vec()?;
1575
1576 let mut different_count = 0;
1577 for (v1, v2) in data1.iter().zip(data2.iter()) {
1578 if (v1 - v2).abs() > 1e-6 {
1579 different_count += 1;
1580 }
1581 }
1582
1583 assert!(different_count > 100);
1585
1586 Ok(())
1587 }
1588
1589 #[test]
1590 fn test_sinusoidal_position_embedding_batch_support() -> Result<()> {
1591 let pos_emb = SinusoidalPositionEmbedding::new(64, 100)?;
1592
1593 let positions = Tensor::from_vec(
1595 vec![
1596 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, ],
1599 &[2, 3],
1600 )?;
1601
1602 let embeddings = pos_emb.forward(&positions)?;
1603
1604 assert_eq!(embeddings.shape().dims(), &[2, 3, 64]);
1606
1607 Ok(())
1608 }
1609
1610 #[test]
1611 fn test_sinusoidal_position_embedding_bounds_checking() -> Result<()> {
1612 let pos_emb = SinusoidalPositionEmbedding::new(64, 100)?;
1613
1614 let positions = Tensor::from_vec(vec![101.0], &[1])?;
1616 let result = pos_emb.forward(&positions);
1617 assert!(result.is_err());
1618
1619 let result = pos_emb.get_embeddings_for_length(101);
1621 assert!(result.is_err());
1622
1623 Ok(())
1624 }
1625
1626 #[test]
1627 fn test_sinusoidal_position_embedding_with_learned_scale() -> Result<()> {
1628 let pos_emb = SinusoidalPositionEmbedding::with_learned_scale(64, 100)?;
1629
1630 let params = pos_emb.parameters();
1632 assert_eq!(params.len(), 1);
1633 assert!(params.contains_key("scale"));
1634
1635 let positions = Tensor::from_vec(vec![0.0, 1.0], &[2])?;
1637 let embeddings = pos_emb.forward(&positions)?;
1638
1639 assert_eq!(embeddings.shape().dims(), &[2, 64]);
1640
1641 Ok(())
1642 }
1643
1644 #[test]
1645 fn test_sinusoidal_position_embedding_add_to_tokens() -> Result<()> {
1646 let d_model = 64;
1647 let seq_len = 10;
1648 let batch_size = 2;
1649
1650 let pos_emb = SinusoidalPositionEmbedding::new(d_model, 100)?;
1651
1652 let token_data = vec![0.5_f32; batch_size * seq_len * d_model];
1654 let tokens = Tensor::from_vec(token_data, &[batch_size, seq_len, d_model])?;
1655
1656 let output = pos_emb.forward(&tokens)?;
1658
1659 assert_eq!(output.shape().dims(), &[batch_size, seq_len, d_model]);
1661
1662 let output_data = output.to_vec()?;
1664 let tokens_data = tokens.to_vec()?;
1665
1666 let mut different_count = 0;
1667 for (out, tok) in output_data.iter().zip(tokens_data.iter()) {
1668 if (out - tok).abs() > 1e-6 {
1669 different_count += 1;
1670 }
1671 }
1672
1673 assert!(different_count > d_model * seq_len);
1675
1676 Ok(())
1677 }
1678}