tenflowers_dataset/dataloader/
samplers.rs1use std::collections::HashMap;
7use tenflowers_core::{Result, TensorError};
8
9pub trait Sampler: Send + Sync {
11 fn sample_indices(&self, len: usize) -> Box<dyn Iterator<Item = usize> + Send>;
13
14 fn is_random(&self) -> bool;
16
17 fn set_seed(&mut self, _seed: Option<u64>) {}
19}
20
21#[derive(Debug, Clone)]
23pub struct SequentialSampler {
24 start: usize,
25 end: Option<usize>,
26}
27
28impl SequentialSampler {
29 pub fn new() -> Self {
30 Self {
31 start: 0,
32 end: None,
33 }
34 }
35
36 pub fn with_range(start: usize, end: usize) -> Self {
37 Self {
38 start,
39 end: Some(end),
40 }
41 }
42}
43
44impl Default for SequentialSampler {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl Sampler for SequentialSampler {
51 fn sample_indices(&self, len: usize) -> Box<dyn Iterator<Item = usize> + Send> {
52 let end = self.end.unwrap_or(len).min(len);
53 Box::new(self.start..end)
54 }
55
56 fn is_random(&self) -> bool {
57 false
58 }
59}
60
61#[derive(Debug, Clone)]
63pub struct RandomSampler {
64 replacement: bool,
65 seed: Option<u64>,
66}
67
68impl RandomSampler {
69 pub fn new() -> Self {
70 Self {
71 replacement: false,
72 seed: None,
73 }
74 }
75
76 pub fn with_replacement() -> Self {
77 Self {
78 replacement: true,
79 seed: None,
80 }
81 }
82
83 pub fn with_seed(seed: u64) -> Self {
84 Self {
85 replacement: false,
86 seed: Some(seed),
87 }
88 }
89}
90
91impl Default for RandomSampler {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl Sampler for RandomSampler {
98 fn sample_indices(&self, len: usize) -> Box<dyn Iterator<Item = usize> + Send> {
99 let seed = self.seed.unwrap_or_else(|| {
101 std::time::SystemTime::now()
102 .duration_since(std::time::UNIX_EPOCH)
103 .expect("system time before UNIX_EPOCH")
104 .as_secs()
105 });
106
107 if self.replacement {
108 let mut indices = Vec::with_capacity(len);
110 let mut state = seed;
111 for _ in 0..len {
112 state = state.wrapping_mul(1103515245).wrapping_add(12345);
114 indices.push((state as usize) % len);
115 }
116 Box::new(indices.into_iter())
117 } else {
118 let mut indices: Vec<usize> = (0..len).collect();
120 let mut state = seed;
121
122 for i in (1..indices.len()).rev() {
124 state = state.wrapping_mul(1103515245).wrapping_add(12345);
125 let j = (state as usize) % (i + 1);
126 indices.swap(i, j);
127 }
128
129 Box::new(indices.into_iter())
130 }
131 }
132
133 fn is_random(&self) -> bool {
134 true
135 }
136
137 fn set_seed(&mut self, seed: Option<u64>) {
138 self.seed = seed;
139 }
140}
141
142#[derive(Debug, Clone)]
144pub struct DistributedSampler {
145 num_replicas: usize,
147 rank: usize,
149 epoch: usize,
151 shuffle: bool,
153 seed: Option<u64>,
155 drop_last: bool,
157}
158
159impl DistributedSampler {
160 pub fn new(num_replicas: usize, rank: usize) -> Result<Self> {
162 if rank >= num_replicas {
163 return Err(TensorError::invalid_argument(format!(
164 "Rank {rank} must be less than num_replicas {num_replicas}"
165 )));
166 }
167
168 Ok(Self {
169 num_replicas,
170 rank,
171 epoch: 0,
172 shuffle: true,
173 seed: None,
174 drop_last: false,
175 })
176 }
177
178 pub fn with_shuffle(mut self, shuffle: bool) -> Self {
180 self.shuffle = shuffle;
181 self
182 }
183
184 pub fn with_seed(mut self, seed: u64) -> Self {
186 self.seed = Some(seed);
187 self
188 }
189
190 pub fn with_drop_last(mut self, drop_last: bool) -> Self {
192 self.drop_last = drop_last;
193 self
194 }
195
196 pub fn set_epoch(&mut self, epoch: usize) {
198 self.epoch = epoch;
199 }
200
201 pub fn epoch(&self) -> usize {
203 self.epoch
204 }
205
206 pub fn rank(&self) -> usize {
208 self.rank
209 }
210
211 pub fn num_replicas(&self) -> usize {
213 self.num_replicas
214 }
215
216 fn samples_per_replica(&self, total_size: usize) -> usize {
218 if self.drop_last {
219 total_size / self.num_replicas
220 } else {
221 (total_size + self.num_replicas - 1) / self.num_replicas
222 }
223 }
224
225 fn padded_size(&self, total_size: usize) -> usize {
227 if self.drop_last {
228 (total_size / self.num_replicas) * self.num_replicas
229 } else {
230 self.samples_per_replica(total_size) * self.num_replicas
231 }
232 }
233}
234
235impl Sampler for DistributedSampler {
236 fn sample_indices(&self, len: usize) -> Box<dyn Iterator<Item = usize> + Send> {
237 let mut indices: Vec<usize> = (0..len).collect();
238
239 if self.shuffle {
241 let seed = self.seed.unwrap_or_else(|| {
242 std::time::SystemTime::now()
243 .duration_since(std::time::UNIX_EPOCH)
244 .expect("system time before UNIX_EPOCH")
245 .as_secs()
246 });
247
248 let effective_seed = seed.wrapping_add(self.epoch as u64);
250 let mut state = effective_seed;
251
252 for i in (1..indices.len()).rev() {
254 state = state.wrapping_mul(1103515245).wrapping_add(12345);
255 let j = (state as usize) % (i + 1);
256 indices.swap(i, j);
257 }
258 }
259
260 let samples_per_replica = self.samples_per_replica(len);
261 let padded_size = self.padded_size(len);
262
263 if !self.drop_last && padded_size > len {
265 let padding_needed = padded_size - len;
266 for i in 0..padding_needed {
267 indices.push(indices[i % len]);
268 }
269 }
270
271 let start_idx = self.rank * samples_per_replica;
273 let end_idx = ((self.rank + 1) * samples_per_replica).min(indices.len());
274
275 let rank_indices = if start_idx < indices.len() {
276 indices[start_idx..end_idx].to_vec()
277 } else {
278 Vec::new()
279 };
280
281 Box::new(rank_indices.into_iter())
282 }
283
284 fn is_random(&self) -> bool {
285 self.shuffle
286 }
287
288 fn set_seed(&mut self, seed: Option<u64>) {
289 self.seed = seed;
290 }
291}
292
293#[derive(Debug, Clone)]
295pub struct StratifiedSampler {
296 class_labels: Vec<usize>,
298 samples_per_class: Option<usize>,
300 replacement: bool,
302 seed: Option<u64>,
304 shuffle: bool,
306}
307
308impl StratifiedSampler {
309 pub fn new(class_labels: Vec<usize>) -> Self {
311 Self {
312 class_labels,
313 samples_per_class: None,
314 replacement: false,
315 seed: None,
316 shuffle: true,
317 }
318 }
319
320 pub fn with_samples_per_class(mut self, samples_per_class: usize) -> Self {
322 self.samples_per_class = Some(samples_per_class);
323 self
324 }
325
326 pub fn with_replacement(mut self) -> Self {
328 self.replacement = true;
329 self
330 }
331
332 pub fn with_seed(mut self, seed: u64) -> Self {
334 self.seed = Some(seed);
335 self
336 }
337
338 pub fn with_shuffle(mut self, shuffle: bool) -> Self {
340 self.shuffle = shuffle;
341 self
342 }
343
344 pub fn class_distribution(&self) -> HashMap<usize, usize> {
346 let mut counts = HashMap::new();
347 for &label in &self.class_labels {
348 *counts.entry(label).or_insert(0) += 1;
349 }
350 counts
351 }
352
353 pub fn num_classes(&self) -> usize {
355 self.class_distribution().len()
356 }
357}
358
359impl Sampler for StratifiedSampler {
360 fn sample_indices(&self, len: usize) -> Box<dyn Iterator<Item = usize> + Send> {
361 if self.class_labels.len() != len {
362 return Box::new((0..len).collect::<Vec<_>>().into_iter());
364 }
365
366 let mut class_indices: HashMap<usize, Vec<usize>> = HashMap::new();
368 for (idx, &class_label) in self.class_labels.iter().enumerate() {
369 class_indices.entry(class_label).or_default().push(idx);
370 }
371
372 let seed = self.seed.unwrap_or_else(|| {
373 std::time::SystemTime::now()
374 .duration_since(std::time::UNIX_EPOCH)
375 .expect("system time before UNIX_EPOCH")
376 .as_secs()
377 });
378
379 let mut result_indices = Vec::new();
380 let mut rng_state = seed;
381
382 let samples_per_class = if let Some(spc) = self.samples_per_class {
384 spc
385 } else {
386 class_indices
388 .values()
389 .map(|indices| indices.len())
390 .min()
391 .unwrap_or(0)
392 };
393
394 for (_, mut indices) in class_indices {
396 if self.shuffle {
398 for i in (1..indices.len()).rev() {
400 rng_state = rng_state.wrapping_mul(1103515245).wrapping_add(12345);
401 let j = (rng_state as usize) % (i + 1);
402 indices.swap(i, j);
403 }
404 }
405
406 if self.replacement {
407 for _ in 0..samples_per_class {
409 rng_state = rng_state.wrapping_mul(1103515245).wrapping_add(12345);
410 let idx = (rng_state as usize) % indices.len();
411 result_indices.push(indices[idx]);
412 }
413 } else {
414 let sample_count = samples_per_class.min(indices.len());
416 result_indices.extend_from_slice(&indices[..sample_count]);
417 }
418 }
419
420 if self.shuffle {
422 for i in (1..result_indices.len()).rev() {
423 rng_state = rng_state.wrapping_mul(1103515245).wrapping_add(12345);
424 let j = (rng_state as usize) % (i + 1);
425 result_indices.swap(i, j);
426 }
427 }
428
429 Box::new(result_indices.into_iter())
430 }
431
432 fn is_random(&self) -> bool {
433 self.shuffle
434 }
435
436 fn set_seed(&mut self, seed: Option<u64>) {
437 self.seed = seed;
438 }
439}
440
441#[derive(Debug, Clone)]
443pub struct ImportanceSampler {
444 weights: Vec<f64>,
446 normalize: bool,
448 seed: Option<u64>,
450 temperature: f64,
452}
453
454impl ImportanceSampler {
455 pub fn new(dataset_size: usize) -> Self {
457 Self {
458 weights: vec![1.0; dataset_size],
459 normalize: true,
460 seed: None,
461 temperature: 1.0,
462 }
463 }
464
465 pub fn with_weights(weights: Vec<f64>) -> Self {
467 Self {
468 weights,
469 normalize: true,
470 seed: None,
471 temperature: 1.0,
472 }
473 }
474
475 pub fn with_normalize(mut self, normalize: bool) -> Self {
477 self.normalize = normalize;
478 self
479 }
480
481 pub fn with_seed(mut self, seed: u64) -> Self {
483 self.seed = Some(seed);
484 self
485 }
486
487 pub fn with_temperature(mut self, temperature: f64) -> Self {
489 self.temperature = temperature;
490 self
491 }
492
493 pub fn update_weight(&mut self, index: usize, weight: f64) {
495 if index < self.weights.len() {
496 self.weights[index] = weight;
497 }
498 }
499
500 pub fn update_weights(&mut self, updates: &[(usize, f64)]) {
502 for &(index, weight) in updates {
503 self.update_weight(index, weight);
504 }
505 }
506
507 pub fn weights(&self) -> &[f64] {
509 &self.weights
510 }
511
512 fn compute_probabilities(&self) -> Vec<f64> {
514 let mut probs: Vec<f64> = self
515 .weights
516 .iter()
517 .map(|&w| (w / self.temperature).exp())
518 .collect();
519
520 if self.normalize {
521 let sum: f64 = probs.iter().sum();
522 if sum > 0.0 {
523 for p in &mut probs {
524 *p /= sum;
525 }
526 } else {
527 let uniform_prob = 1.0 / probs.len() as f64;
529 probs.fill(uniform_prob);
530 }
531 }
532
533 probs
534 }
535}
536
537impl Sampler for ImportanceSampler {
538 fn sample_indices(&self, len: usize) -> Box<dyn Iterator<Item = usize> + Send> {
539 if self.weights.len() != len {
540 return Box::new((0..len).collect::<Vec<_>>().into_iter());
542 }
543
544 let probabilities = self.compute_probabilities();
545
546 let mut cumulative = Vec::with_capacity(probabilities.len());
548 let mut sum = 0.0;
549 for &prob in &probabilities {
550 sum += prob;
551 cumulative.push(sum);
552 }
553
554 let seed = self.seed.unwrap_or_else(|| {
555 std::time::SystemTime::now()
556 .duration_since(std::time::UNIX_EPOCH)
557 .expect("system time before UNIX_EPOCH")
558 .as_secs()
559 });
560
561 let mut indices = Vec::with_capacity(len);
562 let mut rng_state = seed;
563
564 for _ in 0..len {
566 rng_state = rng_state.wrapping_mul(1103515245).wrapping_add(12345);
567 let random_val = (rng_state as f64) / (u64::MAX as f64);
568
569 let index = cumulative
571 .binary_search_by(|&x| {
572 if x < random_val {
573 std::cmp::Ordering::Less
574 } else {
575 std::cmp::Ordering::Greater
576 }
577 })
578 .unwrap_or_else(|i| i);
579
580 indices.push(index.min(len - 1));
581 }
582
583 Box::new(indices.into_iter())
584 }
585
586 fn is_random(&self) -> bool {
587 true
588 }
589
590 fn set_seed(&mut self, seed: Option<u64>) {
591 self.seed = seed;
592 }
593}
594
595#[cfg(test)]
596mod tests {
597 use super::*;
598
599 #[test]
600 fn test_sequential_sampler() {
601 let sampler = SequentialSampler::new();
602 let indices: Vec<usize> = sampler.sample_indices(5).collect();
603 assert_eq!(indices, vec![0, 1, 2, 3, 4]);
604 assert!(!sampler.is_random());
605 }
606
607 #[test]
608 fn test_sequential_sampler_with_range() {
609 let sampler = SequentialSampler::with_range(2, 5);
610 let indices: Vec<usize> = sampler.sample_indices(10).collect();
611 assert_eq!(indices, vec![2, 3, 4]);
612 }
613
614 #[test]
615 fn test_random_sampler() {
616 let sampler = RandomSampler::with_seed(42);
617 let indices: Vec<usize> = sampler.sample_indices(5).collect();
618 assert_eq!(indices.len(), 5);
619 assert!(sampler.is_random());
620
621 let sampler2 = RandomSampler::with_seed(42);
623 let indices2: Vec<usize> = sampler2.sample_indices(5).collect();
624 assert_eq!(indices, indices2);
625 }
626
627 #[test]
628 fn test_random_sampler_with_replacement() {
629 let sampler = RandomSampler::with_replacement();
630 let indices: Vec<usize> = sampler.sample_indices(3).collect();
631 assert_eq!(indices.len(), 3);
632 }
634
635 #[test]
636 fn test_distributed_sampler() {
637 let sampler = DistributedSampler::new(2, 0).expect("test: operation should succeed");
638 let indices: Vec<usize> = sampler.sample_indices(10).collect();
639 assert!(indices.len() >= 4 && indices.len() <= 6);
641 }
642
643 #[test]
644 fn test_distributed_sampler_invalid_rank() {
645 let result = DistributedSampler::new(2, 2);
646 assert!(result.is_err());
647 }
648
649 #[test]
650 fn test_stratified_sampler() {
651 let class_labels = vec![0, 0, 1, 1, 2, 2];
652 let sampler = StratifiedSampler::new(class_labels.clone());
653
654 assert_eq!(sampler.num_classes(), 3);
655
656 let distribution = sampler.class_distribution();
657 assert_eq!(distribution[&0], 2);
658 assert_eq!(distribution[&1], 2);
659 assert_eq!(distribution[&2], 2);
660 }
661
662 #[test]
663 fn test_stratified_sampler_with_samples_per_class() {
664 let class_labels = vec![0, 0, 0, 1, 1, 1];
665 let sampler = StratifiedSampler::new(class_labels)
666 .with_samples_per_class(1)
667 .with_seed(42);
668
669 let indices: Vec<usize> = sampler.sample_indices(6).collect();
670 assert_eq!(indices.len(), 2);
672 }
673
674 #[test]
675 fn test_importance_sampler() {
676 let sampler = ImportanceSampler::new(5);
677 assert_eq!(sampler.weights().len(), 5);
678 assert!(sampler.weights().iter().all(|&w| w == 1.0));
679 }
680
681 #[test]
682 fn test_importance_sampler_with_weights() {
683 let weights = vec![1.0, 2.0, 3.0];
684 let sampler = ImportanceSampler::with_weights(weights.clone());
685 assert_eq!(sampler.weights(), &weights);
686 }
687
688 #[test]
689 fn test_importance_sampler_update_weight() {
690 let mut sampler = ImportanceSampler::new(3);
691 sampler.update_weight(1, 5.0);
692 assert_eq!(sampler.weights()[1], 5.0);
693 }
694
695 #[test]
696 fn test_importance_sampler_update_weights() {
697 let mut sampler = ImportanceSampler::new(3);
698 sampler.update_weights(&[(0, 2.0), (2, 4.0)]);
699 assert_eq!(sampler.weights()[0], 2.0);
700 assert_eq!(sampler.weights()[2], 4.0);
701 }
702}