Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CpuTensor.h
Go to the documentation of this file.
1// @(#)root/tmva/tmva/dnn:$Id$
2// Authors: Sitong An, Lorenzo Moneta 10/2019
3
4/*************************************************************************
5 * Copyright (C) 2019, ROOT *
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// Definition of the CpuTensor class used to represent //
14// tensor data in deep neural nets (CNN, RNN, etc..) //
15//////////////////////////////////////////////////////////
16
17#ifndef TMVA_DNN_ARCHITECTURES_CPU_CPUTENSOR
18#define TMVA_DNN_ARCHITECTURES_CPU_CPUTENSOR
19
20#include <cstddef>
21
22
23#include "TMatrix.h"
24#include "TMVA/Config.h"
25#include "CpuBuffer.h"
26#include "CpuMatrix.h"
27#include <TMVA/RTensor.hxx>
28
29namespace TMVA {
30namespace DNN {
31
32// CPU Tensor Class
33// It is a simple wrapper for TMVA RTensor based on
34// memory owned by CPU Buffer
35// We need to keep a pointer for CPUBuffer for fast conversion
36// without copying to TCpuMatrix
37// also provides compatibility with old interface
38
39template <typename AFloat>
40class TCpuTensor : public TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>> {
41
42private:
43 //TCpuTensor will have no extra private members than RTensor
44public:
45 friend class TCpuMatrix<AFloat>;
46
50 using Scalar_t = AFloat;
51
52 // default constructor
53 TCpuTensor(): TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>>(std::make_shared<TCpuBuffer<AFloat>>(0), {0})
54 {}
55
56 /** constructors from n m */
57 TCpuTensor(size_t n, size_t m, MemoryLayout memlayout = MemoryLayout::ColumnMajor)
58 : TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>>(std::make_shared<TCpuBuffer<AFloat>>(n * m), {n, m}, memlayout)
59 {}
60
61 /** constructors from batch size, depth, height*width */
62 TCpuTensor(size_t bsize, size_t depth, size_t hw, MemoryLayout memlayout = MemoryLayout::ColumnMajor)
63 : TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>>(std::make_shared<TCpuBuffer<AFloat>>(bsize * depth * hw), {depth, hw, bsize}, memlayout)
64 {
65 if (memlayout == MemoryLayout::RowMajor)
66 this->ReshapeInplace({bsize, depth, hw});
67 }
68
69 /** constructors from batch size, depth, height, width */
70 TCpuTensor(size_t bsize, size_t depth, size_t height, size_t width,
71 MemoryLayout memlayout = MemoryLayout::ColumnMajor)
72 : TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>>(std::make_shared<TCpuBuffer<AFloat>>(bsize * depth * height * width),
73 {depth, height, width, bsize}, memlayout)
74 {
75 if (memlayout == MemoryLayout::RowMajor)
76 this->ReshapeInplace({bsize, depth, height, width});
77 }
78
79 /** constructors from a shape.*/
80 TCpuTensor(Shape_t shape, MemoryLayout memlayout = MemoryLayout::ColumnMajor)
81 : TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>>(std::make_shared<TCpuBuffer<AFloat>>(TMVA::Experimental::Internal::GetSizeFromShape(shape)),
82 shape, memlayout)
83 {}
84
85 /* constructors from a AFloat pointer and a shape. This is a copy */
86
87 TCpuTensor(AFloat *data, const Shape_t &shape,
88 MemoryLayout memlayout = MemoryLayout::ColumnMajor)
89 : TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>>(std::make_shared<TCpuBuffer<AFloat>>(TMVA::Experimental::Internal::GetSizeFromShape(shape)), shape, memlayout)
90 {
91 auto& container = *(this->GetContainer());
92 for (size_t i = 0; i < this->GetSize(); ++i) container[i] = data[i];
93 }
94
95
96
97 /** constructors from a TCpuBuffer and a shape */
98 //unsafe method for backwards compatibility, const not promised. A view.
99 TCpuTensor(const TCpuBuffer<AFloat>& buffer, Shape_t shape, MemoryLayout memlayout = MemoryLayout::ColumnMajor)
100 : TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>>(std::make_shared<TCpuBuffer<AFloat>>(buffer), shape, memlayout) {
101 R__ASSERT(this->GetSize() <= this->GetContainer()->GetSize());
102 }
103
104
105
106 /** constructors from a TCpuMatrix. Memory layout is forced to be same as matrix (i.e. columnlayout) */
107 //unsafe method for backwards compatibility, const not promised. A view of underlying data.
108 TCpuTensor(const TCpuMatrix<AFloat> &matrix, size_t dim = 3, MemoryLayout memlayout = MemoryLayout::ColumnMajor)
109 : TMVA::Experimental::RTensor<AFloat, TCpuBuffer<AFloat>>(std::make_shared<TCpuBuffer<AFloat>>(matrix.GetBuffer()),{matrix.GetNrows(), matrix.GetNcols()}, memlayout)
110 {
111
112 if (dim > 2) {
113 Shape_t shape = this->GetShape();
114
115 if (this->GetLayout() == MemoryLayout::ColumnMajor) {
116 shape.insert(shape.end(),dim-2, 1);
117 } else {
118 shape.insert(shape.begin(), dim - 2, 1);
119 }
120 this->ReshapeInplace(shape);
121 }
122 }
123
124
125 /** Convert to a TMatrixT<AFloat_t> object. Performs a deep copy of the matrix
126 * elements. */
127
128 operator TMatrixT<AFloat>() const {
129 // this should work only for size 2 or 4 tensors
130 if (this->GetShape().size() == 2 || (this->GetShape().size() == 3 && GetFirstSize() == 1)) {
132 return temp;
133 }
134 // convert as a flat vector
135 return TMatrixT<AFloat>(1, this->GetSize(), this->GetData());
136 }
137
138
139 /** Return raw pointer to the elements stored contiguously in column-major
140 * order. */
141 AFloat *GetRawDataPointer() { return *(this->GetContainer()); }
142 const AFloat *GetRawDataPointer() const { return *(this->GetContainer()); }
143
144 // for same API as CudaTensor (device buffer is the CpuBuffer)
145 const TCpuBuffer<AFloat> & GetDeviceBuffer() const {return *(this->GetContainer());}
147
148
149 size_t GetNoElements() const { return this->GetSize(); }
150
151 // return the size of the first dimension (if in row order) or last dimension if in column order
152 // Tensor is F x H x W x...for row order layout FHWC
153 // or H x W x ... x F for column order layout CHWF
154 // logic copied from TCudaTensor
155 size_t GetFirstSize() const
156 {
157 auto& shape = this->GetShape();
158 return (this->GetMemoryLayout() == MemoryLayout::ColumnMajor) ? shape.back() : shape.front();
159 }
160
161 size_t GetCSize() const
162 {
163 auto& shape = this->GetShape();
164 if (shape.size() == 2) return 1;
165 return (this->GetMemoryLayout() == MemoryLayout::ColumnMajor) ? shape.front() : shape[1]; // assume NHWC
166 }
167 //
168 size_t GetHSize() const
169 {
170 auto& shape = this->GetShape();
171 if (shape.size() == 2) return shape[0];
172 if (shape.size() == 3) return (this->GetMemoryLayout() == MemoryLayout::ColumnMajor) ? shape[0] : shape[1] ;
173 if (shape.size() >= 4) return shape[2] ;
174 return 0;
175
176 }
177 size_t GetWSize() const
178 {
179 auto& shape = this->GetShape();
180 if (shape.size() == 2) return shape[1];
181 if (shape.size() == 3) return (this->GetMemoryLayout() == MemoryLayout::ColumnMajor) ? shape[1] : shape[2] ;
182 if (shape.size() >= 4) return shape[3] ;
183 return 0;
184
185 }
186
187 // for backward compatibility (assume column-major
188 // for backward compatibility : for CM tensor (n1,n2,n3,n4) -> ( n1*n2*n3, n4)
189 // for RM tensor (n1,n2,n3,n4) -> ( n2*n3*n4, n1 ) ???
190 size_t GetNrows() const { return (GetLayout() == MemoryLayout::ColumnMajor ) ? this->GetStrides().back() : this->GetShape().front();}
191 size_t GetNcols() const { return (GetLayout() == MemoryLayout::ColumnMajor ) ? this->GetShape().back() : this->GetStrides().front(); }
192
193
194 MemoryLayout GetLayout() const { return this->GetMemoryLayout(); }
195
196 //this will be an unsafe view. Method exists for backwards compatibility only
198 {
199 size_t ndims = 0;
200 auto& shape = this->GetShape();
201 //check if squeezable but do not actually squeeze
202 for (auto& shape_i : shape){
203 if (shape_i != 1) {
204 ndims++;
205 }
206 }
207 assert(ndims <= 2 && shape.size() > 1); // to support shape cases {n,1}
208 (void) ndims; // avoid warning about unused variable
209 return TCpuMatrix<AFloat>(*(this->GetContainer()), GetHSize(), GetWSize());
210 }
211
212 // Create copy, replace and return
214 {
215 TCpuTensor<AFloat> x(*this);
216 x.ReshapeInplace(shape);
217 return x;
218 }
219
220 // return a view of slices in the first dimension (if row wise) or last dimension if column wise
221 // so single event slices
223 {
224 auto &shape = this->GetShape();
225 auto layout = this->GetMemoryLayout();
226 Shape_t sliced_shape = (layout == MemoryLayout::RowMajor) ? Shape_t(shape.begin() + 1, shape.end())
227 : Shape_t(shape.begin(), shape.end() - 1);
228
229 size_t buffsize = (layout == MemoryLayout::RowMajor) ? this->GetStrides().front() : this->GetStrides().back();
230 size_t offset = i * buffsize;
231
232 return TCpuTensor<AFloat>(this->GetContainer()->GetSubBuffer(offset, buffsize), sliced_shape, layout);
233 }
234
235 TCpuTensor<AFloat> At(size_t i) const { return (const_cast<TCpuTensor<AFloat> &>(*this)).At(i); }
236
237 // for compatibility with old tensor (std::vector<matrix>)
239 assert(this->GetMemoryLayout() == MemoryLayout::ColumnMajor );
240 return At(i).GetMatrix();
241 }
242
243 // set all the tensor contents to zero
244 void Zero()
245 {
246 AFloat *data = *(this->GetContainer());
247 for (size_t i = 0; i < this->GetSize(); ++i)
248 data[i] = 0;
249 }
250
251 // access single element - assume tensor dim is 2
252 AFloat &operator()(size_t i, size_t j)
253 {
254 auto &shape = this->GetShape();
255 assert(shape.size() == 2);
256 return (this->GetMemoryLayout() == MemoryLayout::RowMajor) ? (*(this->GetContainer()))[i * shape[1] + j]
257 : (*(this->GetContainer()))[j * shape[0] + i];
258 }
259
260 // access single element - assume tensor dim is 3. First index i is always the major independent of row-major or
261 // column major row- major I - J - K . Column- major is J - K - I
262 AFloat &operator()(size_t i, size_t j, size_t k)
263 {
264 auto &shape = this->GetShape();
265 assert(shape.size() == 3);
266
267 return (this->GetMemoryLayout() == MemoryLayout::RowMajor)
268 ? (*(this->GetContainer()))[i * shape[1] * shape[2] + j * shape[2] + k]
269 : (*(this->GetContainer()))[i * shape[0] * shape[1] + k * shape[0] + j]; // note that is J-K-I
270 }
271
272 // access single element - assume tensor dim is 2
273 AFloat operator()(size_t i, size_t j) const
274 {
275 auto &shape = this->GetShape();
276 assert(shape.size() == 2);
277 return (this->GetMemoryLayout() == MemoryLayout::RowMajor) ? (this->GetData())[i * shape[1] + j]
278 : (this->GetData())[j * shape[0] + i];
279 }
280
281 AFloat operator()(size_t i, size_t j, size_t k) const
282 {
283 auto &shape = this->GetShape();
284 assert(shape.size() == 3);
285
286 return (this->GetMemoryLayout() == MemoryLayout::RowMajor)
287 ? (this->GetData())[i * shape[1] * shape[2] + j * shape[2] + k]
288 : (this->GetData())[i * shape[0] * shape[1] + k * shape[0] + j]; // note that is J-K-I
289 }
290
291 /** Map the given function over the matrix elements. Executed in parallel
292 * using TThreadExecutor. */
293 template <typename Function_t>
294 void Map(Function_t & f);
295
296 /** Same as maps but takes the input values from the tensor \p A and writes
297 * the results in this tensor. */
298 template <typename Function_t>
299 void MapFrom(Function_t & f, const TCpuTensor<AFloat> &A);
300
301 size_t GetBufferUseCount() const { return this->GetContainer()->GetUseCount(); }
302
303 void Print(const char *name = "Tensor") const
304 {
306
307 for (size_t i = 0; i < this->GetSize(); i++)
308 std::cout << (this->GetData())[i] << " ";
309 std::cout << std::endl;
310 }
311 void PrintShape(const char *name = "Tensor") const
312 {
313 std::string memlayout = (GetLayout() == MemoryLayout::RowMajor) ? "RowMajor" : "ColMajor";
314 std::cout << name << " shape : { ";
315 auto &shape = this->GetShape();
316 for (size_t i = 0; i < shape.size() - 1; ++i)
317 std::cout << shape[i] << " , ";
318 std::cout << shape.back() << " } "
319 << " Layout : " << memlayout << std::endl;
320 }
321};
322
323//______________________________________________________________________________
324template <typename AFloat>
325template <typename Function_t>
326inline void TCpuTensor<AFloat>::Map(Function_t &f)
327{
328 AFloat *data = GetRawDataPointer();
329 size_t nelements = GetNoElements();
330 size_t nsteps = TCpuMatrix<AFloat>::GetNWorkItems(nelements);
331
332 auto ff = [data, &nsteps, &nelements, &f](UInt_t workerID) {
333 size_t jMax = std::min(workerID + nsteps, nelements);
334 for (size_t j = workerID; j < jMax; ++j) {
335 data[j] = f(data[j]);
336 }
337 return 0;
338 };
339
340 if (nsteps < nelements) {
341 TMVA::Config::Instance().GetThreadExecutor().Foreach(ff, ROOT::TSeqI(0, nelements, nsteps));
342
343 // for (size_t i = 0; i < nelements; i+=nsteps)
344 // ff(i);
345
346 } else {
347 R__ASSERT(nelements == nsteps);
348 ff(0);
349 }
350}
351
352//______________________________________________________________________________
353template <typename AFloat>
354template <typename Function_t>
355inline void TCpuTensor<AFloat>::MapFrom(Function_t &f, const TCpuTensor<AFloat> &A)
356{
357 AFloat *dataB = GetRawDataPointer();
358 const AFloat *dataA = A.GetRawDataPointer();
359
360 size_t nelements = GetNoElements();
361 R__ASSERT(nelements == A.GetNoElements());
362 size_t nsteps = TCpuMatrix<AFloat>::GetNWorkItems(nelements);
363
364 auto ff = [&dataB, &dataA, &nsteps, &nelements, &f](UInt_t workerID) {
365 size_t jMax = std::min(workerID + nsteps, nelements);
366 for (size_t j = workerID; j < jMax; ++j) {
367 dataB[j] = f(dataA[j]);
368 }
369 return 0;
370 };
371 if (nsteps < nelements) {
372 TMVA::Config::Instance().GetThreadExecutor().Foreach(ff, ROOT::TSeqI(0, nelements, nsteps));
373 // for (size_t i = 0; i < nelements; i+=nsteps)
374 // ff(i);
375
376 } else {
377 R__ASSERT(nelements == nsteps);
378 ff(0);
379 }
380}
381
382
383} // namespace DNN
384} // namespace TMVA
385
386#endif
#define f(i)
Definition RSha256.hxx:104
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define R__ASSERT(e)
Definition TError.h:117
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t width
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
char name[80]
Definition TGX11.cxx:110
A pseudo container class which is a generator of indices.
Definition TSeq.hxx:67
Executor & GetThreadExecutor()
Get executor class for multi-thread usage In case when MT is not enabled will return a serial executo...
Definition Config.h:81
static Config & Instance()
static function: returns TMVA instance
Definition Config.cxx:98
The TCpuMatrix class.
Definition CpuMatrix.h:86
size_t GetNcols() const
Definition CpuMatrix.h:156
static size_t GetNWorkItems(size_t nelements)
Definition CpuMatrix.h:191
size_t GetNrows() const
Definition CpuMatrix.h:155
size_t GetBufferUseCount() const
Definition CpuTensor.h:301
AFloat operator()(size_t i, size_t j, size_t k) const
Definition CpuTensor.h:281
TCpuTensor(size_t n, size_t m, MemoryLayout memlayout=MemoryLayout::ColumnMajor)
constructors from n m
Definition CpuTensor.h:57
TCpuTensor(size_t bsize, size_t depth, size_t height, size_t width, MemoryLayout memlayout=MemoryLayout::ColumnMajor)
constructors from batch size, depth, height, width
Definition CpuTensor.h:70
AFloat * GetRawDataPointer()
Return raw pointer to the elements stored contiguously in column-major order.
Definition CpuTensor.h:141
size_t GetNoElements() const
Definition CpuTensor.h:149
size_t GetWSize() const
Definition CpuTensor.h:177
void Map(Function_t &f)
Map the given function over the matrix elements.
Definition CpuTensor.h:326
const TCpuBuffer< AFloat > & GetDeviceBuffer() const
Definition CpuTensor.h:145
TCpuTensor(size_t bsize, size_t depth, size_t hw, MemoryLayout memlayout=MemoryLayout::ColumnMajor)
constructors from batch size, depth, height*width
Definition CpuTensor.h:62
TCpuMatrix< AFloat > operator[](size_t i) const
Definition CpuTensor.h:238
const AFloat * GetRawDataPointer() const
Definition CpuTensor.h:142
TCpuBuffer< AFloat > & GetDeviceBuffer()
Definition CpuTensor.h:146
size_t GetCSize() const
Definition CpuTensor.h:161
AFloat & operator()(size_t i, size_t j, size_t k)
Definition CpuTensor.h:262
TCpuTensor(const TCpuBuffer< AFloat > &buffer, Shape_t shape, MemoryLayout memlayout=MemoryLayout::ColumnMajor)
constructors from a TCpuBuffer and a shape
Definition CpuTensor.h:99
void MapFrom(Function_t &f, const TCpuTensor< AFloat > &A)
Same as maps but takes the input values from the tensor A and writes the results in this tensor.
Definition CpuTensor.h:355
AFloat operator()(size_t i, size_t j) const
Definition CpuTensor.h:273
TCpuTensor(const TCpuMatrix< AFloat > &matrix, size_t dim=3, MemoryLayout memlayout=MemoryLayout::ColumnMajor)
constructors from a TCpuMatrix.
Definition CpuTensor.h:108
TCpuMatrix< AFloat > GetMatrix() const
Definition CpuTensor.h:197
TCpuTensor< AFloat > At(size_t i) const
Definition CpuTensor.h:235
size_t GetNcols() const
Definition CpuTensor.h:191
TCpuTensor(Shape_t shape, MemoryLayout memlayout=MemoryLayout::ColumnMajor)
constructors from a shape.
Definition CpuTensor.h:80
size_t GetFirstSize() const
Definition CpuTensor.h:155
size_t GetNrows() const
Definition CpuTensor.h:190
void PrintShape(const char *name="Tensor") const
Definition CpuTensor.h:311
AFloat & operator()(size_t i, size_t j)
Definition CpuTensor.h:252
TCpuTensor< AFloat > At(size_t i)
Definition CpuTensor.h:222
friend class TCpuMatrix< AFloat >
Definition CpuTensor.h:45
MemoryLayout GetLayout() const
Definition CpuTensor.h:194
void Print(const char *name="Tensor") const
Definition CpuTensor.h:303
TCpuTensor< AFloat > Reshape(Shape_t shape) const
Definition CpuTensor.h:213
typename TMVA::Experimental::RTensor< AFloat >::Shape_t Shape_t
Definition CpuTensor.h:47
TCpuTensor(AFloat *data, const Shape_t &shape, MemoryLayout memlayout=MemoryLayout::ColumnMajor)
Definition CpuTensor.h:87
size_t GetHSize() const
Definition CpuTensor.h:168
void Foreach(Function func, unsigned int nTimes, unsigned nChunks=0)
wrap TExecutor::Foreach
Definition Executor.h:111
RTensor is a container with contiguous memory and shape information.
Definition RTensor.hxx:162
void ReshapeInplace(const Shape_t &shape)
Reshape tensor in place.
Definition RTensor.hxx:316
RTensor(Value_t *data, Shape_t shape, MemoryLayout layout=MemoryLayout::RowMajor)
Construct a tensor as view on data.
Definition RTensor.hxx:189
std::vector< std::size_t > Shape_t
Definition RTensor.hxx:166
TMatrixT.
Definition TMatrixT.h:39
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
MemoryLayout
Memory layout type (copy from RTensor.hxx)
Definition CudaTensor.h:47
create variable transformations
TMarker m
Definition textangle.C:8