Skip to content

Commit 0431ee7

Browse files
committed
refactor: separate DataLoader changes from launcher
1 parent 513a57b commit 0431ee7

7 files changed

Lines changed: 60 additions & 208 deletions

File tree

example/gpt2/main.cc

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -372,19 +372,15 @@ void Train(const nn::parallel::Rank &rank) {
372372
start_step = resume_result.global_step;
373373
size_t consumed_batches = resume_result.consumed_batches;
374374

375-
// consumed_batches is the number of global dataloader batches consumed across cyclic epochs.
376-
train_iter.SeekGlobalBatch(consumed_batches % train_loader.NumGlobalBatches());
377-
auto next_train_batch = [&]() {
378-
auto batch = *train_iter;
379-
// if we are trying to overfit a single batch, we reset the loader here by commenting out the line below
380-
// TODO(dcj): support dataloader.reset() later
381-
++train_iter;
382-
if (train_iter == train_loader.end()) {
383-
train_iter = train_loader.begin();
384-
}
385-
++consumed_batches;
386-
return batch;
387-
};
375+
// TODO(jym): Replace with Sampler abstraction when available.
376+
// Skip dataloader to resume from the correct batch position.
377+
if (consumed_batches > 0) {
378+
size_t start = train_iter.BatchIndex();
379+
// Each rank processes every ddp_world_size-th batch starting from its own rank.
380+
// num_skips calculates how many ++ iterations to reach the saved batch position.
381+
size_t num_skips = (consumed_batches - start) / ddp_world_size;
382+
for (size_t i = 0; i < num_skips; ++i) { ++train_iter; }
383+
}
388384

389385
auto save_checkpoint = [&](const std::filesystem::path &save_dir, int64_t global_step) {
390386
SaveCheckpoint({
@@ -458,7 +454,11 @@ void Train(const nn::parallel::Rank &rank) {
458454
infini_train::AutocastGuard autocast_guard(device.type(), dtype);
459455

460456
// (bs, seq_len), (bs, seq_len)
461-
auto [x, y] = next_train_batch();
457+
auto [x, y] = *train_iter;
458+
// if we are trying to overfit a single batch, we reset the loader here by commenting out the line below
459+
// TODO(dcj): support dataloader.reset() later
460+
++train_iter;
461+
consumed_batches = train_iter.BatchIndex();
462462
x = std::make_shared<Tensor>(x->To(device));
463463
y = std::make_shared<Tensor>(y->To(device));
464464

@@ -488,7 +488,11 @@ void Train(const nn::parallel::Rank &rank) {
488488
scheduler->Step();
489489
}
490490
} else {
491-
auto [x, y] = next_train_batch();
491+
auto [x, y] = *train_iter;
492+
// if we are trying to overfit a single batch, we reset the loader here by commenting out the line below
493+
// TODO(dcj): support dataloader.reset() later
494+
++train_iter;
495+
consumed_batches = train_iter.BatchIndex();
492496
x = std::make_shared<Tensor>(x->To(device));
493497
y = std::make_shared<Tensor>(y->To(device));
494498

example/llama3/main.cc

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -354,19 +354,15 @@ void Train(const nn::parallel::Rank &rank) {
354354
start_step = resume_result.global_step;
355355
size_t consumed_batches = resume_result.consumed_batches;
356356

357-
// consumed_batches is the number of global dataloader batches consumed across cyclic epochs.
358-
train_iter.SeekGlobalBatch(consumed_batches % train_loader.NumGlobalBatches());
359-
auto next_train_batch = [&]() {
360-
auto batch = *train_iter;
361-
// if we are trying to overfit a single batch, we reset the loader here by commenting out the line below
362-
// TODO(dcj): support dataloader.reset() later
363-
++train_iter;
364-
if (train_iter == train_loader.end()) {
365-
train_iter = train_loader.begin();
366-
}
367-
++consumed_batches;
368-
return batch;
369-
};
357+
// TODO(jym): Replace with Sampler abstraction when available.
358+
// Skip dataloader to resume from the correct batch position.
359+
if (consumed_batches > 0) {
360+
size_t start = train_iter.BatchIndex();
361+
// Each rank processes every ddp_world_size-th batch starting from its own rank.
362+
// num_skips calculates how many ++ iterations to reach the saved batch position.
363+
size_t num_skips = (consumed_batches - start) / ddp_world_size;
364+
for (size_t i = 0; i < num_skips; ++i) { ++train_iter; }
365+
}
370366

371367
auto save_checkpoint = [&](const std::filesystem::path &save_dir, int64_t global_step) {
372368
SaveCheckpoint({
@@ -438,7 +434,11 @@ void Train(const nn::parallel::Rank &rank) {
438434
infini_train::AutocastGuard autocast_guard(device.type(), dtype);
439435

440436
// (bs, seq_len), (bs, seq_len)
441-
auto [x, y] = next_train_batch();
437+
auto [x, y] = *train_iter;
438+
// if we are trying to overfit a single batch, we reset the loader here by commenting out the line below
439+
// TODO(dcj): support dataloader.reset() later
440+
++train_iter;
441+
consumed_batches = train_iter.BatchIndex();
442442
x = std::make_shared<Tensor>(x->To(device));
443443
y = std::make_shared<Tensor>(y->To(device));
444444

@@ -467,7 +467,11 @@ void Train(const nn::parallel::Rank &rank) {
467467
scheduler->Step();
468468
}
469469
} else {
470-
auto [x, y] = next_train_batch();
470+
auto [x, y] = *train_iter;
471+
// if we are trying to overfit a single batch, we reset the loader here by commenting out the line below
472+
// TODO(dcj): support dataloader.reset() later
473+
++train_iter;
474+
consumed_batches = train_iter.BatchIndex();
471475
x = std::make_shared<Tensor>(x->To(device));
472476
y = std::make_shared<Tensor>(y->To(device));
473477

infini_train/include/dataloader.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Tensor;
1212
namespace infini_train {
1313
class DataLoaderIterator {
1414
public:
15-
DataLoaderIterator(const Dataset &dataset, size_t batch_size, size_t global_batch_idx, size_t num_global_batches,
15+
DataLoaderIterator(const Dataset &dataset, size_t batch_size, size_t batch_idx, size_t max_batch_idx,
1616
size_t ddp_rank = 0, size_t ddp_world_size = 1);
1717

1818
std::pair<std::shared_ptr<Tensor>, std::shared_ptr<Tensor>> operator*() const;
@@ -24,14 +24,13 @@ class DataLoaderIterator {
2424
friend bool operator!=(const DataLoaderIterator &lhs, const DataLoaderIterator &rhs);
2525
friend bool operator==(const DataLoaderIterator &lhs, const DataLoaderIterator &rhs);
2626

27-
size_t GlobalBatchIndex() const;
28-
DataLoaderIterator &SeekGlobalBatch(size_t global_batch_idx);
27+
size_t BatchIndex() const;
2928

3029
private:
3130
const Dataset *dataset_ = nullptr; // not owned
3231
size_t batch_size_ = 0;
33-
size_t global_batch_idx_ = 0;
34-
size_t num_global_batches_ = 0;
32+
size_t batch_idx_ = 0;
33+
size_t max_batch_idx_ = 0;
3534
size_t ddp_rank_ = 0;
3635
size_t ddp_world_size_ = 1;
3736
};
@@ -43,12 +42,10 @@ class DataLoader {
4342
virtual DataLoaderIterator begin() const;
4443
virtual DataLoaderIterator end() const;
4544

46-
size_t NumGlobalBatches() const;
47-
4845
protected:
4946
std::shared_ptr<Dataset> dataset_;
5047
size_t batch_size_ = 0;
51-
size_t num_global_batches_ = 0;
48+
size_t max_batch_idx_ = 0;
5249
};
5350

5451
class DistributedDataLoader : public DataLoader {

infini_train/src/dataloader.cc

Lines changed: 17 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include <algorithm>
44
#include <cstddef>
55
#include <cstring>
6-
#include <functional>
76
#include <numeric>
87
#include <utility>
98

@@ -14,14 +13,8 @@
1413

1514
namespace infini_train {
1615
namespace {
17-
size_t CheckedCeilDiv(size_t numerator, size_t denominator) {
18-
CHECK_GT(denominator, 0);
19-
return (numerator + denominator - 1) / denominator;
20-
}
21-
2216
// TODO(dcj): Use official stack implementation later.
2317
std::shared_ptr<Tensor> Stack(const std::vector<std::shared_ptr<Tensor>> &tensors) {
24-
CHECK(!tensors.empty()) << "Cannot stack an empty batch. Check DataLoader iterator end handling.";
2518
const int batch_size = tensors.size();
2619
const auto &dims = tensors[0]->Dims();
2720
const int stacked_dim = std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<int64_t>());
@@ -42,31 +35,21 @@ std::shared_ptr<Tensor> Stack(const std::vector<std::shared_ptr<Tensor>> &tensor
4235
}
4336
} // namespace
4437

45-
DataLoaderIterator::DataLoaderIterator(const Dataset &dataset, size_t batch_size, size_t global_batch_idx,
46-
size_t num_global_batches, size_t ddp_rank, size_t ddp_world_size)
47-
: dataset_(&dataset), batch_size_(batch_size), global_batch_idx_(global_batch_idx),
48-
num_global_batches_(num_global_batches), ddp_rank_(ddp_rank), ddp_world_size_(ddp_world_size){};
38+
DataLoaderIterator::DataLoaderIterator(const Dataset &dataset, size_t batch_size, size_t batch_idx,
39+
size_t max_batch_idx, size_t ddp_rank, size_t ddp_world_size)
40+
: dataset_(&dataset), batch_size_(batch_size), batch_idx_(batch_idx), max_batch_idx_(max_batch_idx),
41+
ddp_rank_(ddp_rank), ddp_world_size_(ddp_world_size){};
4942

5043
std::pair<std::shared_ptr<Tensor>, std::shared_ptr<Tensor>> DataLoaderIterator::operator*() const {
5144
/*
5245
0, 1, ..., x, ...
5346
[0, bs-1], [bs, 2*bs-1], ..., [x*bs, (x+1)*bs-1], ...
5447
^
55-
global_batch_idx
48+
batch_idx
5649
*/
5750
std::vector<std::shared_ptr<Tensor>> data_vec;
5851
std::vector<std::shared_ptr<Tensor>> label_vec;
59-
CHECK_LT(global_batch_idx_, num_global_batches_)
60-
<< "Cannot dereference DataLoader end iterator. global_batch_idx=" << global_batch_idx_
61-
<< ", num_global_batches=" << num_global_batches_ << ", ddp_rank=" << ddp_rank_
62-
<< ", ddp_world_size=" << ddp_world_size_;
63-
const size_t start_idx = (global_batch_idx_ * ddp_world_size_ + ddp_rank_) * batch_size_;
64-
CHECK_LT(start_idx, dataset_->Size())
65-
<< "DataLoader batch starts past dataset end. global_batch_idx=" << global_batch_idx_
66-
<< ", start_idx=" << start_idx << ", dataset_size=" << dataset_->Size() << ", batch_size=" << batch_size_
67-
<< ", ddp_rank=" << ddp_rank_ << ", ddp_world_size=" << ddp_world_size_;
68-
const size_t end_idx = std::min(start_idx + batch_size_, dataset_->Size());
69-
for (size_t idx = start_idx; idx < end_idx; ++idx) {
52+
for (int idx = batch_idx_ * batch_size_; idx < (batch_idx_ + 1) * batch_size_ && idx < dataset_->Size(); ++idx) {
7053
auto &&[data, label] = dataset_->operator[](idx);
7154
data_vec.push_back(std::move(data));
7255
label_vec.push_back(std::move(label));
@@ -75,7 +58,7 @@ std::pair<std::shared_ptr<Tensor>, std::shared_ptr<Tensor>> DataLoaderIterator::
7558
}
7659

7760
DataLoaderIterator &DataLoaderIterator::operator++() {
78-
global_batch_idx_ = std::min(global_batch_idx_ + 1, num_global_batches_);
61+
batch_idx_ = std::min(batch_idx_ + ddp_world_size_, max_batch_idx_);
7962
return *this;
8063
}
8164

@@ -85,60 +68,36 @@ DataLoaderIterator DataLoaderIterator::operator++(int) {
8568
return tmp;
8669
}
8770

88-
bool operator<(const DataLoaderIterator &lhs, const DataLoaderIterator &rhs) {
89-
return lhs.global_batch_idx_ < rhs.global_batch_idx_;
90-
}
71+
bool operator<(const DataLoaderIterator &lhs, const DataLoaderIterator &rhs) { return lhs.batch_idx_ < rhs.batch_idx_; }
9172

9273
bool operator!=(const DataLoaderIterator &lhs, const DataLoaderIterator &rhs) {
93-
return lhs.global_batch_idx_ != rhs.global_batch_idx_;
74+
return lhs.batch_idx_ != rhs.batch_idx_;
9475
}
9576

9677
bool operator==(const DataLoaderIterator &lhs, const DataLoaderIterator &rhs) {
97-
return lhs.global_batch_idx_ == rhs.global_batch_idx_;
78+
return lhs.batch_idx_ == rhs.batch_idx_;
9879
}
9980

100-
size_t DataLoaderIterator::GlobalBatchIndex() const { return global_batch_idx_; }
101-
102-
DataLoaderIterator &DataLoaderIterator::SeekGlobalBatch(size_t global_batch_idx) {
103-
CHECK_LE(global_batch_idx, num_global_batches_)
104-
<< "Cannot seek past DataLoader end. global_batch_idx=" << global_batch_idx
105-
<< ", num_global_batches=" << num_global_batches_;
106-
global_batch_idx_ = global_batch_idx;
107-
return *this;
108-
}
81+
size_t DataLoaderIterator::BatchIndex() const { return batch_idx_; }
10982

11083
DataLoader::DataLoader(const std::shared_ptr<Dataset> &dataset, size_t batch_size)
111-
: dataset_(dataset), batch_size_(batch_size), num_global_batches_(CheckedCeilDiv(dataset_->Size(), batch_size_)) {}
84+
: dataset_(dataset), batch_size_(batch_size), max_batch_idx_((dataset_->Size() + batch_size_ - 1) / batch_size_) {}
11285

113-
DataLoaderIterator DataLoader::begin() const {
114-
return DataLoaderIterator(*dataset_, batch_size_, 0, num_global_batches_);
115-
}
86+
DataLoaderIterator DataLoader::begin() const { return DataLoaderIterator(*dataset_, batch_size_, 0, max_batch_idx_); }
11687

11788
DataLoaderIterator DataLoader::end() const {
118-
return DataLoaderIterator(*dataset_, batch_size_, num_global_batches_, num_global_batches_);
89+
return DataLoaderIterator(*dataset_, batch_size_, max_batch_idx_, max_batch_idx_);
11990
}
12091

121-
size_t DataLoader::NumGlobalBatches() const { return num_global_batches_; }
122-
12392
DistributedDataLoader::DistributedDataLoader(const std::shared_ptr<Dataset> &dataset, size_t batch_size,
12493
size_t ddp_rank, size_t ddp_world_size)
125-
: DataLoader(dataset, batch_size), ddp_rank_(ddp_rank), ddp_world_size_(ddp_world_size) {
126-
CHECK_GT(ddp_world_size_, 0);
127-
CHECK_LT(ddp_rank_, ddp_world_size_);
128-
const size_t global_batch_size = ddp_world_size_ * batch_size_;
129-
CHECK_GE(dataset_->Size(), global_batch_size)
130-
<< "DistributedDataLoader needs at least one full global batch. dataset_size=" << dataset_->Size()
131-
<< ", global_batch_size=" << global_batch_size << " (" << batch_size_ << " per rank * " << ddp_world_size_
132-
<< " ranks). Reduce batch size/world size or use a larger dataset.";
133-
num_global_batches_ = dataset_->Size() / global_batch_size;
134-
}
94+
: DataLoader(dataset, batch_size), ddp_rank_(ddp_rank), ddp_world_size_(ddp_world_size) {}
13595

13696
DataLoaderIterator DistributedDataLoader::begin() const {
137-
return DataLoaderIterator(*dataset_, batch_size_, 0, num_global_batches_, ddp_rank_, ddp_world_size_);
97+
return DataLoaderIterator(*dataset_, batch_size_, ddp_rank_, max_batch_idx_, ddp_rank_, ddp_world_size_);
13898
}
13999

140100
DataLoaderIterator DistributedDataLoader::end() const {
141-
return DataLoaderIterator(*dataset_, batch_size_, num_global_batches_, num_global_batches_, ddp_rank_,
142-
ddp_world_size_);
101+
return DataLoaderIterator(*dataset_, batch_size_, max_batch_idx_, max_batch_idx_, ddp_rank_, ddp_world_size_);
143102
}
144103
} // namespace infini_train

tests/CMakeLists.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ add_subdirectory(common)
1010
# Distributed tests
1111
add_subdirectory(distributed)
1212

13-
# DataLoader tests
14-
add_subdirectory(dataloader)
15-
1613
# Tensor tests
1714
add_subdirectory(tensor)
1815

tests/dataloader/CMakeLists.txt

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)