use burn_tensor::Device;
pub use crate::data::dataset::{Dataset, DatasetIterator};
use burn_dataset::DatasetError;
use core::iter::Iterator;
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct Progress {
pub items_processed: usize,
pub total: Option<usize>,
pub unit: Option<String>,
}
impl Progress {
pub fn new(
items_processed: usize,
total: impl Into<Option<usize>>,
unit: Option<String>,
) -> Self {
Self {
items_processed,
total: total.into(),
unit,
}
}
pub fn resolve_total(&mut self) {
if self.total.is_none() {
self.total = Some(self.items_processed);
}
}
pub fn aggregate<P: core::borrow::Borrow<Self>>(
progresses: impl IntoIterator<Item = P>,
) -> Self {
let mut iter = progresses.into_iter();
let Some(first) = iter.next() else {
return Self::new(0, Some(0), None);
};
iter.fold(first.borrow().clone(), |mut result, progress| {
let progress = progress.borrow();
result.items_processed += progress.items_processed;
result.total = [result.total, progress.total].into_iter().sum();
result
})
}
}
impl core::fmt::Display for Progress {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.items_processed)?;
if let Some(total) = self.total {
write!(f, "/{total}")?;
}
Ok(())
}
}
pub trait DataLoaderIterator<O>: Iterator<Item = Result<O, DatasetError>> {
fn progress(&self) -> Progress;
}
pub trait DataLoader<O>: Send + Sync {
fn iter<'a>(&'a self) -> Box<dyn DataLoaderIterator<O> + 'a>;
fn num_items(&self) -> usize;
fn expected_num_items(&self) -> Option<usize> {
None
}
fn to_device(&self, device: &Device) -> Arc<dyn DataLoader<O>>;
fn slice(&self, start: usize, end: usize) -> Arc<dyn DataLoader<O>>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolves_unknown_total_to_processed_count() {
let mut progress = Progress::new(2, None, None);
progress.resolve_total();
assert_eq!(progress.total, Some(2));
}
#[test]
fn preserves_known_total_when_resolving() {
let mut progress = Progress::new(2, 3, None);
progress.resolve_total();
assert_eq!(progress.total, Some(3));
}
#[test]
fn aggregates_known_totals() {
let parts = [Progress::new(2, 4, None), Progress::new(3, 6, None)];
let progress = Progress::aggregate(&parts);
assert_eq!(progress.items_processed, 5);
assert_eq!(progress.total, Some(10));
}
#[test]
fn aggregate_preserves_unknown_totals() {
let progress =
Progress::aggregate([Progress::new(2, 4, None), Progress::new(3, None, None)]);
assert_eq!(progress.items_processed, 5);
assert_eq!(progress.total, None);
}
}