Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RBatchLoader.cxx
Go to the documentation of this file.
1
2#include "RBatchLoader.hxx"
3
4#include <algorithm>
5#include <numeric>
6#include <utility>
7
9
11
12RBatchLoader::RBatchLoader(std::size_t batchSize, const std::vector<std::string> &cols, std::mutex &sharedMutex,
13 std::condition_variable &sharedCV, const std::vector<std::size_t> &vecSizes,
14 std::size_t numEntries, bool dropRemainder)
15 : fBatchSize(batchSize),
16 fCols(cols),
17 fLock(sharedMutex),
18 fCV(sharedCV),
19 fVecSizes(vecSizes),
20 fNumEntries(numEntries),
21 fDropRemainder(dropRemainder)
22{
23 fSumVecSizes = std::accumulate(fVecSizes.begin(), fVecSizes.end(), 0);
24 fNumColumns = fCols.size() + fSumVecSizes - fVecSizes.size();
25
26 RecalculateBatchCounts(numEntries);
27
28 fPrimaryLeftoverBatch = std::make_unique<RFlat2DMatrix>();
29}
30
31/// \brief Activate the batchloader. This means that batches can be created and loaded.
33{
34 {
35 std::lock_guard<std::mutex> lock(fLock);
36 if (fIsActive)
37 return;
38 fIsActive = true;
39 fProducerDone = false;
40 }
41
42 fCV.notify_all();
43}
44
45/// \brief DeActivate the batchloader. This means that no more batches are created.
46/// Batches can still be returned if they are already loaded.
48{
49 {
50 std::lock_guard<std::mutex> lock(fLock);
51 if (!fIsActive)
52 return;
53 fIsActive = false;
54 }
55
56 fCV.notify_all();
57}
58
59/// \brief Reset the batchloader state.
61{
62 {
63 std::lock_guard<std::mutex> lock(fLock);
64
65 while (!fBatchQueue.empty()) {
66 fBatchQueue.pop();
67 }
68
69 fCurrentBatch.reset();
70 fPrimaryLeftoverBatch = std::make_unique<RFlat2DMatrix>();
71 }
72
73 fCV.notify_all();
74}
75
76/// \brief Signal that the producer has finished pushing all batches for this epoch.
78{
79 fProducerDone = true;
80 fCV.notify_all();
81}
82
83/// \brief Return a batch of data as a unique pointer.
84/// After the batch has been processed, it should be destroyed.
85/// \param[in] chunkTensor Tensor with the data from the chunk
86/// \param[in] permutation Order in which to read the rows of the chunk, empty to read them in order
87/// \param[in] firstRow First row of the batch in the chunk
88/// \return Batch
89std::unique_ptr<RFlat2DMatrix> RBatchLoader::CreateBatch(const RFlat2DMatrix &chunkTensor,
90 const std::vector<std::size_t> &permutation,
91 std::size_t firstRow)
92{
93 auto batch = std::make_unique<RFlat2DMatrix>();
94 batch->Reserve(fBatchSize, fNumColumns);
95 RFlat2DMatrixOperators::AppendRows(*batch, chunkTensor, permutation, firstRow, firstRow + fBatchSize);
96
97 return batch;
98}
99
100/// \brief Loading the batch from the queue.
101/// \return Batch
103{
104 std::unique_lock<std::mutex> lock(fLock);
105
106 // Wait until:
107 // - there is data in the queue
108 // - or producer declares "done"
109 // - or we are deactivated
110 fCV.wait(lock, [&] { return !fBatchQueue.empty() || fProducerDone || !fIsActive; });
111
112 if (fBatchQueue.empty()) {
113 // producer done and no queued data -> end-of-epoch signal
114 fCurrentBatch = std::make_unique<RFlat2DMatrix>();
115 return *fCurrentBatch;
116 }
117
118 fCurrentBatch = std::move(fBatchQueue.front());
119 fBatchQueue.pop();
120 // Notify the loading thread that the queue has drained
121 fCV.notify_all();
122
123 // move the buffer over to the caller
124 return std::move(*fCurrentBatch);
125}
126
127/// \brief Creating the batches from a chunk and add them to the queue.
128/// \param[in] chunkTensor Tensor with the data from the chunk
129/// \param[in] permutation Order in which to read the rows of the chunk, empty to read them in order
130/// \param[in] beginRow First row of the chunk to create batches from
131/// \param[in] endRow End of the rows of the chunk to create batches from
132/// \param[in] isLastBatch Check if the batch in the chunk is the last one
133void RBatchLoader::CreateBatches(const RFlat2DMatrix &chunkTensor, const std::vector<std::size_t> &permutation,
134 std::size_t beginRow, std::size_t endRow, bool isLastBatch)
135{
136 std::size_t chunkSize = endRow - beginRow;
137 std::size_t numBatches = chunkSize / fBatchSize;
138
139 // create a vector of batches
140 std::vector<std::unique_ptr<RFlat2DMatrix>> batches;
141
142 // fill the full batches from the chunk into a vector
143 for (std::size_t i = 0; i < numBatches; i++) {
144 batches.emplace_back(CreateBatch(chunkTensor, permutation, beginRow + i * fBatchSize));
145 }
146
147 // append the remaining entries of the chunk to fPrimaryLeftoverBatch, and add it to the batches once it is full
148 for (std::size_t row = beginRow + numBatches * fBatchSize; row < endRow;) {
149 const std::size_t numRows = std::min(endRow - row, fBatchSize - fPrimaryLeftoverBatch->GetRows());
151 RFlat2DMatrixOperators::AppendRows(*fPrimaryLeftoverBatch, chunkTensor, permutation, row, row + numRows);
152 row += numRows;
153
154 if (fPrimaryLeftoverBatch->GetRows() == fBatchSize) {
155 batches.emplace_back(std::move(fPrimaryLeftoverBatch));
156 fPrimaryLeftoverBatch = std::make_unique<RFlat2DMatrix>();
157 }
158 }
159
160 // add the content of fPrimaryLeftoverBatch as the leftover batch of the last chunk
161 if (isLastBatch) {
164 batches.emplace_back(std::move(fPrimaryLeftoverBatch));
165 }
166
167 fPrimaryLeftoverBatch = std::make_unique<RFlat2DMatrix>();
168 }
169
170 {
171 std::lock_guard<std::mutex> lock(fLock);
172 for (auto &batch : batches) {
173 fBatchQueue.push(std::move(batch));
174 }
175 }
176
177 fCV.notify_all();
178}
179
180/// \brief Recalculate batch counts from the given number of entries.
181/// Used at construction or when the true entry count is discovered lazily (filtered case).
182void RBatchLoader::RecalculateBatchCounts(std::size_t numEntries)
183{
184 fNumEntries = numEntries;
185
186 if (fBatchSize == 0) {
188 }
189
192
193 const std::size_t numLeftoverBatches = fLeftoverBatchSize == 0 ? 0 : 1;
195}
196} // namespace ROOT::Experimental::Internal::ML
RFlat2DMatrix GetBatch()
Loading the batch from the queue.
std::queue< std::unique_ptr< RFlat2DMatrix > > fBatchQueue
std::unique_ptr< RFlat2DMatrix > CreateBatch(const RFlat2DMatrix &chunkTensor, const std::vector< std::size_t > &permutation, std::size_t firstRow)
Return a batch of data as a unique pointer.
void CreateBatches(const RFlat2DMatrix &chunkTensor, const std::vector< std::size_t > &permutation, std::size_t beginRow, std::size_t endRow, bool isLastBatch)
Creating the batches from a chunk and add them to the queue.
void RecalculateBatchCounts(std::size_t numEntries)
Recalculate batch counts from the given number of entries.
void Reset()
Reset the batchloader state.
void Activate()
Activate the batchloader. This means that batches can be created and loaded.
void MarkProducerDone()
Signal that the producer has finished pushing all batches for this epoch.
void DeActivate()
DeActivate the batchloader.
std::unique_ptr< RFlat2DMatrix > fPrimaryLeftoverBatch
std::unique_ptr< RFlat2DMatrix > fCurrentBatch
RBatchLoader(std::size_t batchSize, const std::vector< std::string > &cols, std::mutex &sharedMutex, std::condition_variable &sharedCV, const std::vector< std::size_t > &vecSizes={}, std::size_t numEntries=0, bool dropRemainder=false)
static void AppendRows(RFlat2DMatrix &Dest, const RFlat2DMatrix &Tensor, const std::vector< std::size_t > &permutation, std::size_t begin, std::size_t end)
Wrapper around ROOT::RVec<float> representing a 2D matrix.