use std::time::Instant;
use webdataset::filters::{SampleIteratorExt, TupleIteratorExt};
use webdataset::{Result, WebDataset, handlers};
const BATCH_SIZE: usize = 32;
const EPOCH_SAMPLES: usize = 512;
const WORKERS: usize = 4;
fn main() -> Result<()> {
let shards: Vec<String> = std::env::args().skip(1).collect();
if shards.is_empty() {
eprintln!("usage: training_loop <shard-pattern>...");
return Ok(());
}
let dataset = WebDataset::builder_from(&shards)
.resampled(true)
.shard_shuffle(100)
.seed(0)
.handler(handlers::warn_and_continue())
.build()?
.shuffle(1000)
.decode_basic()
.with_epoch(EPOCH_SAMPLES / WORKERS);
let loader = dataset.loader().with_workers(WORKERS).with_prefetch(16);
for epoch in 0..3 {
let started = Instant::now();
let mut samples = 0usize;
let mut batches = 0usize;
for batch in loader.iter().to_tuple(["jpg;png", "cls"]).batched(BATCH_SIZE, false) {
let batch = batch?;
let (_images, labels) = (&batch[0], &batch[1]);
samples += labels.as_tensor().map(|t| t.shape()[0]).unwrap_or(BATCH_SIZE);
batches += 1;
}
let elapsed = started.elapsed();
println!(
"epoch {epoch}: {batches} batches, {samples} samples in {:.2?} ({:.0} samples/s)",
elapsed,
samples as f64 / elapsed.as_secs_f64()
);
}
Ok(())
}