Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
DataLoader.h
Go to the documentation of this file.
1 // @(#)root/tmva/tmva/dnn:$Id$
2 // Author: Simon Pfreundschuh 08/08/16
3 
4 /*************************************************************************
5  * Copyright (C) 2016, Simon Pfreundschuh *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /////////////////////////////////////////////////////////////////////
13 // Generic data loader for neural network input data. Provides a //
14 // high level abstraction for the transfer of training data to the //
15 // device. //
16 /////////////////////////////////////////////////////////////////////
17 
18 #ifndef TMVA_DNN_DATALOADER
19 #define TMVA_DNN_DATALOADER
20 
21 #include "TMatrix.h"
22 #include "TMVA/Event.h"
23 
24 #include <algorithm>
25 #include <iostream>
26 #include <random>
27 #include <vector>
28 
29 namespace TMVA {
30 
31 class DataSetInfo;
32 
33 namespace DNN {
34 
35 //
36 // Input Data Types
37 //______________________________________________________________________________
38 using MatrixInput_t = std::tuple<const TMatrixT<Double_t> &, const TMatrixT<Double_t> &, const TMatrixT<Double_t> &>;
39 using TMVAInput_t =
40  std::tuple<const std::vector<Event *> &, const DataSetInfo &>;
41 
42 using IndexIterator_t = typename std::vector<size_t>::iterator;
43 
44 /** TBatch
45  *
46  * Class representing training batches consisting of a matrix of input data
47  * and a matrix of output data. The input and output data can be accessed using
48  * the GetInput() and GetOutput() member functions.
49  *
50  * \tparam AArchitecture The underlying architecture.
51  */
52 //______________________________________________________________________________
53 template <typename AArchitecture>
54 class TBatch
55 {
56 private:
57 
58  using Matrix_t = typename AArchitecture::Matrix_t;
59 
60  Matrix_t fInputMatrix;
61  Matrix_t fOutputMatrix;
62  Matrix_t fWeightMatrix;
63 
64 public:
65  TBatch(Matrix_t &, Matrix_t &, Matrix_t &);
66  TBatch(const TBatch &) = default;
67  TBatch( TBatch &&) = default;
68  TBatch & operator=(const TBatch &) = default;
69  TBatch & operator=( TBatch &&) = default;
70 
71  /** Return the matrix representing the input data. */
72  Matrix_t &GetInput() { return fInputMatrix; }
73  /** Return the matrix representing the output data. */
74  Matrix_t &GetOutput() { return fOutputMatrix; }
75  /** Return the matrix holding the event weights. */
76  Matrix_t &GetWeights() { return fWeightMatrix; }
77 };
78 
79 template<typename Data_t, typename AArchitecture> class TDataLoader;
80 
81 /** TBatchIterator
82  *
83  * Simple iterator class for the iterations over the training batches in
84  * a given data set represented by a TDataLoader object.
85  *
86  * \tparam AData The input data type.
87  * \tparam AArchitecture The underlying architecture type.
88  */
89 template<typename Data_t, typename AArchitecture>
90 class TBatchIterator
91 {
92 private:
93 
94  TDataLoader<Data_t, AArchitecture> & fDataLoader;
95  size_t fBatchIndex;
96 
97 public:
98 
99 TBatchIterator(TDataLoader<Data_t, AArchitecture> & dataLoader, size_t index = 0)
100 : fDataLoader(dataLoader), fBatchIndex(index)
101 {
102  // Nothing to do here.
103 }
104 
105  TBatch<AArchitecture> operator*() {return fDataLoader.GetBatch();}
106  TBatchIterator operator++() {fBatchIndex++; return *this;}
107  bool operator!=(const TBatchIterator & other) {
108  return fBatchIndex != other.fBatchIndex;
109  }
110 };
111 
112 /** TDataLoader
113  *
114  * Service class managing the streaming of the training data from the input data
115  * type to the accelerator device or the CPU. A TDataLoader object manages a number
116  * of host and device buffer pairs that are used in a round-robin manner for the
117  * transfer of batches to the device.
118  *
119  * Each TDataLoader object has an associated batch size and a number of total
120  * samples in the dataset. One epoch is the number of buffers required to transfer
121  * the complete training set. Using the begin() and end() member functions allows
122  * the user to iterate over the batches in one epoch.
123  *
124  * \tparam AData The input data type.
125  * \tparam AArchitecture The achitecture class of the underlying architecture.
126  */
127 template<typename Data_t, typename AArchitecture>
128 class TDataLoader
129 {
130 private:
131 
132  using HostBuffer_t = typename AArchitecture::HostBuffer_t;
133  using DeviceBuffer_t = typename AArchitecture::DeviceBuffer_t;
134  using Matrix_t = typename AArchitecture::Matrix_t;
135  using BatchIterator_t = TBatchIterator<Data_t, AArchitecture>;
136 
137  const Data_t &fData;
138 
139  size_t fNSamples;
140  size_t fBatchSize;
141  size_t fNInputFeatures;
142  size_t fNOutputFeatures;
143  size_t fBatchIndex;
144 
145  size_t fNStreams; ///< Number of buffer pairs.
146  std::vector<DeviceBuffer_t> fDeviceBuffers;
147  std::vector<HostBuffer_t> fHostBuffers;
148 
149  std::vector<size_t> fSampleIndices; ///< Ordering of the samples in the epoch.
150 
151 public:
152 
153  TDataLoader(const Data_t & data, size_t nSamples, size_t batchSize,
154  size_t nInputFeatures, size_t nOutputFeatures, size_t nStreams = 1);
155  TDataLoader(const TDataLoader &) = default;
156  TDataLoader( TDataLoader &&) = default;
157  TDataLoader & operator=(const TDataLoader &) = default;
158  TDataLoader & operator=( TDataLoader &&) = default;
159 
160  /** Copy input matrix into the given host buffer. Function to be specialized by
161  * the architecture-specific backend. */
162  void CopyInput(HostBuffer_t &buffer, IndexIterator_t begin, size_t batchSize);
163  /** Copy output matrix into the given host buffer. Function to be specialized
164  * by the architecture-spcific backend. */
165  void CopyOutput(HostBuffer_t &buffer, IndexIterator_t begin, size_t batchSize);
166  /** Copy weight matrix into the given host buffer. Function to be specialized
167  * by the architecture-spcific backend. */
168  void CopyWeights(HostBuffer_t &buffer, IndexIterator_t begin, size_t batchSize);
169 
170  BatchIterator_t begin() {return TBatchIterator<Data_t, AArchitecture>(*this);}
171  BatchIterator_t end()
172  {
173  return TBatchIterator<Data_t, AArchitecture>(*this, fNSamples / fBatchSize);
174  }
175 
176  /** Shuffle the order of the samples in the batch. The shuffling is indirect,
177  * i.e. only the indices are shuffled. No input data is moved by this
178  * routine. */
179  void Shuffle();
180 
181  /** Return the next batch from the training set. The TDataLoader object
182  * keeps an internal counter that cycles over the batches in the training
183  * set. */
184  TBatch<AArchitecture> GetBatch();
185 
186 };
187 
188 //
189 // TBatch Class.
190 //______________________________________________________________________________
191 template <typename AArchitecture>
192 TBatch<AArchitecture>::TBatch(Matrix_t &inputMatrix, Matrix_t &outputMatrix, Matrix_t &weightMatrix)
193  : fInputMatrix(inputMatrix), fOutputMatrix(outputMatrix), fWeightMatrix(weightMatrix)
194 {
195  // Nothing to do here.
196 }
197 
198 //
199 // TDataLoader Class.
200 //______________________________________________________________________________
201 template<typename Data_t, typename AArchitecture>
202 TDataLoader<Data_t, AArchitecture>::TDataLoader(
203  const Data_t & data, size_t nSamples, size_t batchSize,
204  size_t nInputFeatures, size_t nOutputFeatures, size_t nStreams)
205  : fData(data), fNSamples(nSamples), fBatchSize(batchSize),
206  fNInputFeatures(nInputFeatures), fNOutputFeatures(nOutputFeatures),
207  fBatchIndex(0), fNStreams(nStreams), fDeviceBuffers(), fHostBuffers(),
208  fSampleIndices()
209 {
210  size_t inputMatrixSize = fBatchSize * fNInputFeatures;
211  size_t outputMatrixSize = fBatchSize * fNOutputFeatures;
212  size_t weightMatrixSize = fBatchSize;
213 
214  for (size_t i = 0; i < fNStreams; i++)
215  {
216  fHostBuffers.push_back(HostBuffer_t(inputMatrixSize + outputMatrixSize + weightMatrixSize));
217  fDeviceBuffers.push_back(DeviceBuffer_t(inputMatrixSize + outputMatrixSize + weightMatrixSize));
218  }
219 
220  fSampleIndices.reserve(fNSamples);
221  for (size_t i = 0; i < fNSamples; i++) {
222  fSampleIndices.push_back(i);
223  }
224 }
225 
226 //______________________________________________________________________________
227 template<typename Data_t, typename AArchitecture>
228 TBatch<AArchitecture> TDataLoader<Data_t, AArchitecture>::GetBatch()
229 {
230  fBatchIndex %= (fNSamples / fBatchSize); // Cycle through samples.
231 
232 
233  size_t inputMatrixSize = fBatchSize * fNInputFeatures;
234  size_t outputMatrixSize = fBatchSize * fNOutputFeatures;
235  size_t weightMatrixSize = fBatchSize;
236 
237  size_t streamIndex = fBatchIndex % fNStreams;
238  HostBuffer_t & hostBuffer = fHostBuffers[streamIndex];
239  DeviceBuffer_t & deviceBuffer = fDeviceBuffers[streamIndex];
240 
241  HostBuffer_t inputHostBuffer = hostBuffer.GetSubBuffer(0, inputMatrixSize);
242  HostBuffer_t outputHostBuffer = hostBuffer.GetSubBuffer(inputMatrixSize,
243  outputMatrixSize);
244  HostBuffer_t weightHostBuffer = hostBuffer.GetSubBuffer(inputMatrixSize + outputMatrixSize, weightMatrixSize);
245 
246  DeviceBuffer_t inputDeviceBuffer = deviceBuffer.GetSubBuffer(0, inputMatrixSize);
247  DeviceBuffer_t outputDeviceBuffer = deviceBuffer.GetSubBuffer(inputMatrixSize,
248  outputMatrixSize);
249  DeviceBuffer_t weightDeviceBuffer = deviceBuffer.GetSubBuffer(inputMatrixSize + outputMatrixSize, weightMatrixSize);
250 
251  size_t sampleIndex = fBatchIndex * fBatchSize;
252  IndexIterator_t sampleIndexIterator = fSampleIndices.begin() + sampleIndex;
253 
254  CopyInput(inputHostBuffer, sampleIndexIterator, fBatchSize);
255  CopyOutput(outputHostBuffer, sampleIndexIterator, fBatchSize);
256  CopyWeights(weightHostBuffer, sampleIndexIterator, fBatchSize);
257 
258  deviceBuffer.CopyFrom(hostBuffer);
259  Matrix_t inputMatrix(inputDeviceBuffer, fBatchSize, fNInputFeatures);
260  Matrix_t outputMatrix(outputDeviceBuffer, fBatchSize, fNOutputFeatures);
261  Matrix_t weightMatrix(weightDeviceBuffer, fBatchSize, fNOutputFeatures);
262 
263  fBatchIndex++;
264  return TBatch<AArchitecture>(inputMatrix, outputMatrix, weightMatrix);
265 }
266 
267 //______________________________________________________________________________
268 template<typename Data_t, typename AArchitecture>
269 void TDataLoader<Data_t, AArchitecture>::Shuffle()
270 {
271  std::shuffle(fSampleIndices.begin(), fSampleIndices.end(), std::default_random_engine{});
272 }
273 
274 } // namespace DNN
275 } // namespace TMVA
276 
277 #endif