burn_core/data/dataloader/
builder.rs1use super::{
2 BatchDataLoader, BatchStrategy, DataLoader, FixBatchStrategy, MultiThreadDataLoader,
3 batcher::Batcher,
4};
5use burn_dataset::Dataset;
6use burn_tensor::Device;
7use rand::{SeedableRng, rngs::StdRng};
8use std::sync::Arc;
9
10pub struct DataLoaderBuilder<I, O> {
12 strategy: Option<Box<dyn BatchStrategy<I>>>,
13 batcher: Arc<dyn Batcher<I, O>>,
14 num_threads: Option<usize>,
15 shuffle: Option<u64>,
16 device: Option<Device>,
17}
18
19impl<I, O> DataLoaderBuilder<I, O>
20where
21 I: Send + Sync + Clone + std::fmt::Debug + 'static,
22 O: Send + Clone + std::fmt::Debug + 'static,
23{
24 pub fn new<Bt>(batcher: Bt) -> Self
34 where
35 Bt: Batcher<I, O> + 'static,
36 {
37 Self {
38 batcher: Arc::new(batcher),
39 strategy: None,
40 num_threads: None,
41 shuffle: None,
42 device: None,
43 }
44 }
45
46 pub fn batch_size(mut self, batch_size: usize) -> Self {
58 self.strategy = Some(Box::new(FixBatchStrategy::new(batch_size)));
59 self
60 }
61
62 pub fn shuffle(mut self, seed: u64) -> Self {
74 self.shuffle = Some(seed);
75 self
76 }
77
78 pub fn num_workers(mut self, num_workers: usize) -> Self {
94 self.num_threads = Some(num_workers);
95 self
96 }
97
98 pub fn set_device(mut self, device: Device) -> Self {
108 self.device = Some(device);
109 self
110 }
111
112 pub fn build<D>(self, dataset: D) -> Arc<dyn DataLoader<O>>
122 where
123 D: Dataset<I> + 'static,
124 {
125 let dataset = Arc::new(dataset);
126
127 let device = self.device.unwrap_or_default();
128 let rng = self.shuffle.map(StdRng::seed_from_u64);
129 let strategy = match self.strategy {
130 Some(strategy) => strategy,
131 None => Box::new(FixBatchStrategy::new(1)),
132 };
133
134 if let Some(num_threads) = self.num_threads
135 && num_threads > 0
136 {
137 return Arc::new(MultiThreadDataLoader::new(
138 strategy,
139 dataset,
140 self.batcher,
141 num_threads,
142 device,
143 rng,
144 ));
145 }
146
147 Arc::new(BatchDataLoader::new(
148 strategy,
149 dataset,
150 self.batcher,
151 device,
152 rng,
153 ))
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 #[cfg(test)]
160 use burn_tensor::Device;
161
162 use super::*;
163 use crate::data::dataset::FakeDataset;
164
165 #[derive(new, Clone)]
166 struct TestBatcherDevice;
167
168 #[cfg(test)]
169 impl<I> Batcher<I, Device> for TestBatcherDevice {
170 fn batch(&self, _items: Vec<I>, device: &Device) -> Device {
171 device.clone()
172 }
173 }
174
175 #[test]
176 fn test_dataloader_no_workers() {
177 let default_device = Device::default();
178 let dataloader = DataLoaderBuilder::new(TestBatcherDevice::new())
179 .batch_size(1)
180 .build(FakeDataset::<String>::new(9));
181
182 assert_eq!(dataloader.num_items(), 9);
183
184 for device in dataloader.iter().map(Result::unwrap) {
185 assert_eq!(device, default_device)
186 }
187 }
188
189 #[test]
190 fn test_dataloader_default_device() {
191 let default_device = Device::default();
192 let dataloader = DataLoaderBuilder::new(TestBatcherDevice::new())
193 .batch_size(1)
194 .num_workers(1)
195 .build(FakeDataset::<String>::new(9));
196
197 assert_eq!(dataloader.num_items(), 9);
198
199 for device in dataloader.iter().map(Result::unwrap) {
200 assert_eq!(device, default_device)
201 }
202 }
203
204 #[test]
205 fn test_dataloader_slice_multi_device() {
206 let dataloader = DataLoaderBuilder::new(TestBatcherDevice::new())
207 .batch_size(1)
208 .num_workers(1)
209 .build(FakeDataset::<String>::new(11));
210
211 #[cfg(all(test, not(feature = "tch"), not(feature = "cuda")))]
212 let (device1, device2) = (Device::flex(), Device::flex());
214
215 #[cfg(all(test, feature = "tch"))]
216 let (device1, device2) = (Device::libtorch_cuda(0), Device::libtorch_cuda(1));
217
218 #[cfg(all(test, feature = "cuda"))]
219 let (device1, device2) = (Device::cuda(0), Device::cuda(1));
220
221 assert_eq!(dataloader.num_items(), 11);
222 let dataloader_1 = dataloader.slice(0, 5).to_device(&device1);
223 let dataloader_2 = dataloader.slice(5, 11).to_device(&device2);
224
225 assert_eq!(dataloader_1.num_items(), 5);
226 assert_eq!(dataloader_2.num_items(), 6);
227
228 let (mut iterator_1, mut iterator_2) = (dataloader_1.iter(), dataloader_2.iter());
229
230 for _ in 0..5 {
231 assert_eq!(iterator_1.next().unwrap().unwrap(), device1);
232 assert_eq!(iterator_2.next().unwrap().unwrap(), device2);
233 }
234
235 assert!(iterator_1.next().is_none());
236 assert_eq!(iterator_2.next().unwrap().unwrap(), device2);
238 assert!(iterator_2.next().is_none());
239 }
240}