Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CudaTensor.h
Go to the documentation of this file.
1// @(#)root/tmva/tmva/dnn:$Id$
2// Author: Simon Pfreundschuh 13/07/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// Contains the TCudaMatrix class for the representation of matrices //
14// on CUDA devices as well as the TCudaDeviceReference class which //
15// is a helper class to emulate lvalue references to floating point //
16// values on the device. //
17///////////////////////////////////////////////////////////////////////
18
19#ifndef TMVA_DNN_ARCHITECTURES_CUDA_CUDATENSOR
20#define TMVA_DNN_ARCHITECTURES_CUDA_CUDATENSOR
21
22
23#include <vector>
24#include <cstring>
25#include <cassert>
26#include <iostream>
27
28#include "CudaMatrix.h"
29#include "TMatrixT.h"
30#include "CudaBuffers.h"
31
32#ifdef R__HAS_CUDNN
33#include "cudnn.h"
34#define CUDNNCHECK(ans) {cudnnError((ans), __FILE__, __LINE__); }
35#endif
36
37namespace TMVA {
38
39namespace DNN {
40
41#ifndef TMVA_DNN_ARCHITECTURES_CPU_CPUTENSOR
42
43/// Memory layout type
44enum class MemoryLayout : uint8_t {
45 RowMajor = 0x01,
46 ColumnMajor = 0x02
47};
48
49#endif
50
51#ifdef R__HAS_CUDNN
52/**
53 * Function to handle the status output of cuDNN function calls. See also
54 * CUDACHECK in CudaMatrix.h.
55 */
56inline void cudnnError(cudnnStatus_t status, const char *file, int line, bool abort=true)
57{
58 if (status != CUDNN_STATUS_SUCCESS) {
59 fprintf(stderr, "CUDNN Error: %s %s %d\n", cudnnGetErrorString(status), file, line);
60 if (abort)
61 exit(status);
62 }
63}
64#endif
65//____________________________________________________________________________
66//
67// Cuda Tensor
68//____________________________________________________________________________
69
70/** TCudaTensor Class
71 *
72 * The TCudaTensor class extends the TCudaMatrix class for dimensions > 2.
73 *
74 */
75template<typename AFloat>
77{
78public:
79
80 using Shape_t = std::vector<size_t>;
82 using Scalar_t = AFloat;
83
84
85private:
86
87#ifdef R__HAS_CUDNN
88 struct TensorDescriptor {
90 };
91
92 static std::vector<cudnnHandle_t> fCudnnHandle; ///< Holds the cuddn library context (one for every CUDA stream)
93
94 static cudnnDataType_t fDataType; ///< Cudnn datatype used for the tensor
95#else
97 };
98#endif
99
100/** For each GPU device keep the CUDA streams in which tensors are used.
101 * Instances belonging to the same stream on the same deviceshare a
102 * cudnn library handel to keep cudnn contexts separated */
103 //static std::vector<std::vector<int> > fInstances;
104 static std::vector<int> fInstances;
105
106 /** The shape vector (size of dimensions) needs to be ordered as no. channels,
107 * image dimensions.
108 */
109 Shape_t fShape; ///< spatial subdimensions
110 Shape_t fStrides; ///< Strides between tensor dimensions (always assume dense, non overlapping tensor)
111 size_t fNDim; ///< Dimension of the tensor (first dimension is the batch size, second is the no. channels)
112 size_t fSize; ///< No. of elements
113 int fDevice; ///< Device associated with current tensor instance
114 int fStreamIndx; ///< Cuda stream associated with current instance
115
116 std::shared_ptr<TensorDescriptor> fTensorDescriptor;
118
120
121
122
123public:
124
125
126 //static AFloat * GetOnes() {return fOnes;}
127
128 TCudaTensor();
129
130 TCudaTensor(const AFloat * data,
131 const std::vector<size_t> & shape,
133 int deviceIndx = 0, int streamIndx = 0);
135 const std::vector<size_t> & shape,
137 int deviceIndx = 0, int streamIndx = 0);
138 TCudaTensor(const std::vector<size_t> & shape,
140 int deviceIndx = 0, int streamIndx = 0);
141
146
154
156 // TCudaTensor( {n,m}, memlayout, deviceIndx, streamIndx) :
158 {}
159
160 TCudaTensor(const TCudaMatrix<AFloat> & m, size_t dim = 2);
161
162 TCudaTensor(const TMatrixT<AFloat> & m, size_t dim = 2) :
163 TCudaTensor( TCudaMatrix<AFloat>(m), dim)
164 {}
165
166 TCudaTensor(TCudaDeviceBuffer<AFloat> buffer, size_t n, size_t m) :
167 TCudaTensor( buffer, {n,m}, MemoryLayout::ColumnMajor ,0,0) {}
168
169 TCudaTensor(const TCudaTensor &) = default;
171 TCudaTensor & operator=(const TCudaTensor &) = default;
173 ~TCudaTensor();
174
175 /** Convert cuda matrix to Root TMatrix. Performs synchronous data transfer. */
176 operator TMatrixT<AFloat>() const;
177
178
180
181 const Shape_t & GetShape() const {return fShape;}
182 const Shape_t & GetStrides() const {return fStrides;}
183 size_t GetDimAt(size_t i) const {return fShape[i];}
184 size_t GetNDim() const {return fNDim;}
185 size_t GetSize() const {return fSize;}
186
187 const AFloat * GetDataPointer() const {return fElementBuffer.data();}
188 AFloat * GetDataPointer() {return fElementBuffer.data();}
189 const AFloat * GetData() const {return fElementBuffer.data();}
190 AFloat * GetData() {return fElementBuffer.data();}
191
192 const AFloat * GetDataPointerAt(size_t i ) const {
193 return const_cast<TCudaDeviceBuffer<AFloat>&>(fElementBuffer).GetSubBuffer(i * GetFirstStride(), GetFirstStride() ).data(); }
194 AFloat * GetDataPointerAt(size_t i ) {return fElementBuffer.GetSubBuffer(i * GetFirstStride(), GetFirstStride() ).data(); }
195
196
199
200#ifdef R__HAS_CUDNN
201 const cudnnHandle_t & GetCudnnHandle() const {return fCudnnHandle[fStreamIndx];}
202 const cudnnTensorDescriptor_t & GetTensorDescriptor() const {return fTensorDescriptor->fCudnnDesc;}
203 static cudnnDataType_t GetDataType() { return fDataType; }
204#endif
205
206 cudaStream_t GetComputeStream() const {
207 return fElementBuffer.GetComputeStream();
208 }
209 void SetComputeStream(cudaStream_t stream) {
210 fElementBuffer.SetComputeStream(stream);
211 }
212
214
215 if (fSize != other.GetSize()) return false;
216
217
218 std::unique_ptr<AFloat[]> hostBufferThis(new AFloat[fSize]);
219 std::unique_ptr<AFloat[]> hostBufferOther(new AFloat[fSize]);
220 cudaMemcpy(hostBufferThis.get(), fElementBuffer.data(), fSize * sizeof(AFloat),
222 cudaMemcpy(hostBufferOther.get(), other.GetDeviceBuffer().data(), fSize * sizeof(AFloat),
224
225 for (size_t i = 0; i < fSize; i++) {
226 if (hostBufferThis[i] != hostBufferOther[i]) return false;
227 }
228 return true;
229 }
230
231 bool isEqual (const AFloat * hostBufferOther, size_t otherSize) {
232 if (fSize != otherSize) return false;
233
234
235 std::unique_ptr<AFloat[]> hostBufferThis(new AFloat[fSize]);
236 cudaMemcpy(hostBufferThis.get(), fElementBuffer.data(), fSize * sizeof(AFloat),
238
239 for (size_t i = 0; i < fSize; i++) {
240 if (hostBufferThis[i] != hostBufferOther[i]) return false;
241 }
242
243 return true;
244 }
245
246 void Print(const char * name = "Tensor", bool truncate = false) const;
247
248 void PrintShape(const char * name="Tensor") const;
249
250 void Zero() {
251 cudaMemset(GetDataPointer(), 0, sizeof(AFloat) * GetSize());
252 }
253
254 void SetConstVal(const AFloat constVal) {
256 hostBuffer.SetConstVal(constVal);
257 fElementBuffer.CopyFrom(hostBuffer);
258 }
259
260 // have this tensor representations
261 // 2-dimensional tensors : NW where N is batch size W is the feature size . Memory layout should be column wise in this case
262 // 3 -dimensional tensor : representation is NHWC , tensor should be column wise storage
263 // 4 -dimensional tensor : representation is NCHW ande tensor should be row wise
264 // a rowmajor tensor with dimension less than three should not exist but in case consider as a N, (CHW) for 2d, N, C, (HW) for 3d
265 // a columnmajor tensor for dimension >=4 should not exist but in case consider as a N,H,W,C (i.e. with shape C,W,H,N)
266
267 size_t GetFirstSize() const {
268 return (GetLayout() == MemoryLayout::ColumnMajor ) ? fShape.back() : fShape.front(); } // CM order
269 size_t GetFirstStride() const {
270 return (GetLayout() == MemoryLayout::ColumnMajor ) ? fStrides.back() : fStrides.front(); } // CM order
271
272 size_t GetCSize() const {
273 if (fNDim == 2) return 1;
274 return (GetLayout() == MemoryLayout::ColumnMajor ) ? fShape.front() : fShape[1] ; //assume NHWC
275 }
276 size_t GetHSize() const {
277 if (fNDim == 2) return fShape[0];
278 if (fNDim == 3) return (GetLayout() == MemoryLayout::ColumnMajor ) ? fShape[0] : fShape[1] ;// same as C
279 if (fNDim >= 4) return (GetLayout() == MemoryLayout::ColumnMajor ) ? fShape[2] : fShape[2] ;
280 return 0;
281 }
282 size_t GetWSize() const {
283 if (fNDim == 2) return fShape[1];
284 if (fNDim == 3) return (GetLayout() == MemoryLayout::ColumnMajor ) ? fShape[1] : fShape[2] ;
285 if (fNDim == 4) return (GetLayout() == MemoryLayout::ColumnMajor ) ? fShape[3] : fShape[3] ;
286 return 0;
287 }
288
289 // for backward compatibility (assume column-major
290 // for backward compatibility : for CM tensor (n1,n2,n3,n4) -> ( n1*n2*n3, n4)
291 // for RM tensor (n1,n2,n3,n4) -> ( n2*n3*n4, n1 ) ???
292 size_t GetNrows() const { return (GetLayout() == MemoryLayout::ColumnMajor ) ? fStrides.back() : fShape.front();}
293 size_t GetNcols() const { return (GetLayout() == MemoryLayout::ColumnMajor ) ? fShape.back() : fStrides.front(); }
294
295
296 // Matrix conversion for tensors of shape 2
298 // remember TCudaMatrix is always column-major
300 (fNDim == 2 || (fNDim == 3 && GetFirstSize() == 1) ) )
302
303
304 //case of N,M,1,1,..
305 bool caseNM11 = true;
306 for (size_t i = 2; i < fNDim; ++i) caseNM11 &= fShape[i] == 1;
307 if (caseNM11) {
308 return (GetLayout() == MemoryLayout::ColumnMajor ) ?
311 }
312 bool case11NM = true;
313 for (size_t i = 0; i < fNDim-2; ++i) case11NM &= fShape[i] == 1;
314 if (case11NM) {
315 return (GetLayout() == MemoryLayout::ColumnMajor ) ?
318 }
319
320 assert(false);
321 return TCudaMatrix<AFloat>();
322 }
323
324 // for backward compatibility with old tensor
326 //assert(GetLayout() == MemoryLayout::ColumnMajor );
327 return At(i).GetMatrix();
328 }
329
330
331
332 static inline std::vector<std::size_t> ComputeStridesFromShape(const std::vector<std::size_t> &shape,
333 bool rowmajorLayout);
334
338 fNDim = fShape.size();
339 // in principle reshape should not change tensor size
340 size_t newSize = (fMemoryLayout == MemoryLayout::RowMajor) ? fStrides.front() * fShape.front() : fStrides.back() * fShape.back();
342 fSize = newSize;
343 // reset the descritor for Cudnn
345 }
346
349 return tmp;
350 }
351
352 void SetTensorDescriptor();
353
354 // return slice of tensor
355 // return slices in the first dimension (if row wise) or last dimension if column wise
356 // so single event slides
357 TCudaTensor<AFloat> At(size_t i) const {
359 ? Shape_t(fShape.begin() + 1, fShape.end()) :
360 Shape_t(fShape.begin(), fShape.end() - 1);
361
362
364 fStrides.front() : fStrides.back();
365
366 size_t offset = i * buffsize;
367
369 }
370
371
372 // element access ( for debugging)
374 {
375 // like this works also for multi-dim tensors
376 // and consider the tensor as a multidim one
377 size_t nrows = GetNrows();
378 size_t ncols = GetNcols();
379
380 size_t offset = (GetLayout() == MemoryLayout::RowMajor) ?
381 i * ncols + j : j * nrows + i;
382
383 AFloat * elementPointer = fElementBuffer.data() + offset;
385 }
386 // element access ( for debugging)
387 TCudaDeviceReference<AFloat> operator()(size_t i, size_t j, size_t k) const
388 {
389 // k is B, i is C, j is HW :
390 assert( fNDim >= 3); // || ( k==0 && fNDim == 2 ) );
391 //note for larger dimension k is all other dims collapsed !!!
392
393 size_t offset = (GetLayout() == MemoryLayout::RowMajor) ?
394 i * fStrides[0] + j * fStrides[1] + k :
395 i * fStrides[2] + k * fStrides[1] + j;
396
397 AFloat * elementPointer = fElementBuffer.data() + offset;
398
400 }
401
402 TCudaDeviceReference<AFloat> operator()(size_t i, size_t j, size_t k, size_t l) const
403 {
404 // for row wise
405 //assert(GetLayout() == MemoryLayout::RowMajor);
406 assert( fNDim == 4); // || ( k==0 && fNDim == 2 ) );
407
408 size_t offset = (GetLayout() == MemoryLayout::RowMajor) ?
409 i * fStrides[0] + j * fStrides[1] + k * fStrides[2] + l:
410 l * fStrides[3] + k * fStrides[2] + j * fStrides[1] + i;
411
412 AFloat * elementPointer = fElementBuffer.data() + offset;
413
415 }
416
417private:
418
419 /** Initializes all shared devices resource and makes sure that a sufficient
420 * number of curand states are allocated on the device and initialized as
421 * well as that the one-vector for the summation over columns has the right
422 * size. */
423 void InitializeCuda();
425
426};
427
428
429
430
431} // namespace DNN
432} // namespace TMVA
433
434#endif
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:130
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
char name[80]
Definition TGX11.cxx:142
TCudaMatrix Class.
Definition CudaMatrix.h:103
TCudaTensor Class.
Definition CudaTensor.h:77
TCudaTensor< AFloat > At(size_t i) const
Definition CudaTensor.h:357
const AFloat * GetDataPointerAt(size_t i) const
Definition CudaTensor.h:192
const Shape_t & GetShape() const
Definition CudaTensor.h:181
size_t GetWSize() const
Definition CudaTensor.h:282
AFloat * GetDataPointer()
Definition CudaTensor.h:188
std::vector< size_t > Shape_t
Definition CudaTensor.h:80
TCudaTensor(const TMatrixT< AFloat > &m, size_t dim=2)
Definition CudaTensor.h:162
const AFloat * GetData() const
Definition CudaTensor.h:189
size_t GetDimAt(size_t i) const
Definition CudaTensor.h:183
Shape_t fStrides
Strides between tensor dimensions (always assume dense, non overlapping tensor)
Definition CudaTensor.h:110
int fDevice
Device associated with current tensor instance.
Definition CudaTensor.h:113
bool isEqual(TCudaTensor< AFloat > &other)
Definition CudaTensor.h:213
TCudaTensor & operator=(TCudaTensor &&)=default
TCudaDeviceReference< AFloat > operator()(size_t i, size_t j) const
Definition CudaTensor.h:373
TCudaMatrix< AFloat > operator[](size_t i) const
Definition CudaTensor.h:325
TCudaTensor(size_t bsize, size_t csize, size_t hsize, size_t wsize, MemoryLayout memlayout=MemoryLayout::ColumnMajor, int deviceIndx=0, int streamIndx=0)
Definition CudaTensor.h:147
size_t GetNrows() const
Definition CudaTensor.h:292
size_t fNDim
Dimension of the tensor (first dimension is the batch size, second is the no. channels)
Definition CudaTensor.h:111
TCudaTensor & operator=(const TCudaTensor &)=default
cudaStream_t GetComputeStream() const
Definition CudaTensor.h:206
void InitializeCuda()
Initializes all shared devices resource and makes sure that a sufficient number of curand states are ...
MemoryLayout GetLayout() const
Definition CudaTensor.h:179
static std::vector< int > fInstances
For each GPU device keep the CUDA streams in which tensors are used.
Definition CudaTensor.h:104
TCudaDeviceBuffer< AFloat > & GetDeviceBuffer()
Definition CudaTensor.h:198
size_t GetNcols() const
Definition CudaTensor.h:293
TCudaTensor(TCudaTensor &&)=default
TCudaTensor(size_t bsize, size_t csize, size_t hwsize, MemoryLayout memlayout=MemoryLayout::ColumnMajor, int deviceIndx=0, int streamIndx=0)
Definition CudaTensor.h:142
TCudaTensor(const TCudaTensor &)=default
Shape_t fShape
The shape vector (size of dimensions) needs to be ordered as no.
Definition CudaTensor.h:109
bool isEqual(const AFloat *hostBufferOther, size_t otherSize)
Definition CudaTensor.h:231
AFloat * GetDataPointerAt(size_t i)
Definition CudaTensor.h:194
size_t GetCSize() const
Definition CudaTensor.h:272
TCudaTensor(TCudaDeviceBuffer< AFloat > buffer, size_t n, size_t m)
Definition CudaTensor.h:166
void PrintShape(const char *name="Tensor") const
TCudaTensor< AFloat > Reshape(const Shape_t &newShape) const
Definition CudaTensor.h:347
size_t fSize
No. of elements.
Definition CudaTensor.h:112
TCudaMatrix< AFloat > GetMatrix() const
Definition CudaTensor.h:297
TCudaTensor(size_t n, size_t m, MemoryLayout memlayout=MemoryLayout::ColumnMajor, int deviceIndx=0, int streamIndx=0)
Definition CudaTensor.h:155
size_t GetNDim() const
Definition CudaTensor.h:184
const AFloat * GetDataPointer() const
Definition CudaTensor.h:187
const Shape_t & GetStrides() const
Definition CudaTensor.h:182
static std::vector< std::size_t > ComputeStridesFromShape(const std::vector< std::size_t > &shape, bool rowmajorLayout)
This information is needed for the multi-dimensional indexing.
Definition CudaTensor.cu:43
void ReshapeInPlace(const Shape_t &newShape)
Definition CudaTensor.h:335
size_t GetHSize() const
Definition CudaTensor.h:276
TCudaDeviceBuffer< AFloat > fElementBuffer
Definition CudaTensor.h:117
size_t GetFirstStride() const
Definition CudaTensor.h:269
const TCudaDeviceBuffer< AFloat > & GetDeviceBuffer() const
Definition CudaTensor.h:197
MemoryLayout fMemoryLayout
Definition CudaTensor.h:119
TCudaDeviceReference< AFloat > operator()(size_t i, size_t j, size_t k, size_t l) const
Definition CudaTensor.h:402
void SetComputeStream(cudaStream_t stream)
Definition CudaTensor.h:209
TCudaDeviceReference< AFloat > operator()(size_t i, size_t j, size_t k) const
Definition CudaTensor.h:387
size_t GetFirstSize() const
Definition CudaTensor.h:267
void SetConstVal(const AFloat constVal)
Definition CudaTensor.h:254
size_t GetSize() const
Definition CudaTensor.h:185
int fStreamIndx
Cuda stream associated with current instance.
Definition CudaTensor.h:114
void Print(const char *name="Tensor", bool truncate=false) const
std::shared_ptr< TensorDescriptor > fTensorDescriptor
Definition CudaTensor.h:116
TLine * line
const Int_t n
Definition legend1.C:16
MemoryLayout
Memory layout type (row- or column-major storage of the tensor elements)
Definition CpuTensor.h:37
create variable transformations
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4