Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
SOFIE_common.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_SOFIE_COMMON
2#define TMVA_SOFIE_SOFIE_COMMON
3
4// #include "TMVA/RTensor.hxx"
5// #include "TMVA/Types.h"
6
7#include <stdexcept>
8#include <type_traits>
9#include <cstdint>
10#include <cstring>
11#include <string>
12#include <vector>
13#include <memory>
14#include <regex>
15#include <sstream>
16#include <iostream>
17
18namespace TMVA{
19namespace Experimental{
20namespace SOFIE{
21
22//typedef RTensor tensor_t;
23
24enum class ETensorType{
25 UNDEFINED = 0, FLOAT = 1, UNINT8 = 2, INT8 = 3, UINT16 = 4, INT16 = 5, INT32 = 6, INT64 = 7, STRING = 8, BOOL = 9, //order sensitive
26 FLOAT16 = 10, DOUBLE = 11, UINT32 = 12, UINT64 = 13, COMPLEX64 = 14, COMPLEX28 = 15, BFLOAT16 = 16
27};
28
29typedef std::int64_t int_t;
30
33
34struct Dim{
35 bool isParam = false;
36 size_t dim;
37 std::string param;
38};
39
40std::vector<Dim> ConvertShapeToDim(std::vector<size_t> shape);
41
42
45 std::vector<Dim> shape;
46};
47
50 std::vector<size_t> shape;
51};
52
53std::size_t ConvertShapeToLength(std::vector<size_t> shape);
54
55std::string ConvertShapeToString(std::vector<size_t> shape);
56
59 std::vector<std::size_t> fShape;
60 std::shared_ptr<void> fData; //! Transient
61 int fSize=1;
62 char* fPersistentData=nullptr; //[fSize] Persistent
63
65 for(auto item:fShape){
66 fSize*=(int)item;
67 }
68 switch(fType){
69 case ETensorType::FLOAT: fSize*=sizeof(float); break;
70 case ETensorType::DOUBLE: fSize*=sizeof(double); break;
71 case ETensorType::INT32: fSize*=sizeof(int32_t); break;
72 case ETensorType::INT64: fSize*=sizeof(int64_t); break;
73 default:
74 throw std::runtime_error("TMVA::SOFIE doesn't yet supports serialising data-type " + ConvertTypeToString(fType));
75 }
76 fPersistentData=(char*)fData.get();
77 }
79 switch (fType) {
80 case ETensorType::FLOAT: {
81 std::shared_ptr<void> tData(malloc(fSize * sizeof(float)), free);
82 std::memcpy(tData.get(), fPersistentData, fSize * sizeof(float));
83 fData = tData;
84 break;
85 }
87 std::shared_ptr<void> tData(malloc(fSize * sizeof(double)), free);
88 std::memcpy(tData.get(), fPersistentData, fSize * sizeof(double));
89 fData = tData;
90 break;
91 }
92 case ETensorType::INT32: {
93 std::shared_ptr<void> tData(malloc(fSize * sizeof(int32_t)), free);
94 std::memcpy(tData.get(), fPersistentData, fSize * sizeof(int32_t));
95 fData = tData;
96 break;
97 }
98 case ETensorType::INT64: {
99 std::shared_ptr<void> tData(malloc(fSize * sizeof(int64_t)), free);
100 std::memcpy(tData.get(), fPersistentData, fSize * sizeof(int64_t));
101 fData = tData;
102 break;
103 }
104 default: {
105 throw std::runtime_error("TMVA::SOFIE doesn't yet supports serialising data-type " +
107 }
108 }
109 }
110};
111
112template <typename T>
114 if (std::is_same<T, float>::value) return ETensorType::FLOAT;
115 if (std::is_same<T, uint8_t>::value) return ETensorType::UNINT8;
116 if (std::is_same<T, int8_t>::value) return ETensorType::INT8;
117 if (std::is_same<T, uint16_t>::value) return ETensorType::UINT16;
118 if (std::is_same<T, int16_t>::value) return ETensorType::INT16;
119 if (std::is_same<T, int32_t>::value) return ETensorType::INT32;
120 if (std::is_same<T, int64_t>::value) return ETensorType::INT64;
121 if (std::is_same<T, std::string>::value) return ETensorType::STRING;
122 if (std::is_same<T, bool>::value) return ETensorType::BOOL;
123 //float16 unimplemented
124 if (std::is_same<T, double>::value) return ETensorType::DOUBLE;
125 if (std::is_same<T, uint32_t>::value) return ETensorType::UINT32;
126 if (std::is_same<T, uint64_t>::value) return ETensorType::UINT64;
127 //complex 64, 28, bfloat 16 unimplemented
128}
129
130namespace UTILITY{
131// Check if two shapes are equal
132bool AreSameShape(const std::vector<size_t>&, const std::vector<size_t>&);
133
134// Multidirectional broadcast a list of tensors to the same shape
135std::vector<size_t> MultidirectionalBroadcastShape(std::vector<std::vector<size_t>>);
136
137// Unidirectional broadcast two shapes to the same shape
138std::vector<size_t> UnidirectionalBroadcastShape(std::vector<size_t>, std::vector<size_t>);
139
140std::string Clean_name(std::string input_tensor_name);
141
142template<typename T>
143T* BroadcastConvBias(const T* data, const size_t channel, const std::vector<size_t>& targetShape) {
144 size_t size = targetShape.size();
145 if (targetShape[1] != channel) {
146 std::stringstream ss;
147 ss << "TMVA::SOFIE - Error broadcasting Conv Bias of shape {";
148 ss << std::to_string(channel);
149 ss << "} to ";
150 ss << ConvertShapeToString(targetShape);
151 throw
152 std::runtime_error(ss.str());
153 }
154
155 size_t targetLength = ConvertShapeToLength(targetShape);
156 T* newData = new T[targetLength];
157
158 if (targetLength == channel) {
159 std::copy(data, data + channel, newData);
160 return newData;
161 }
162
163 // cStride = OutDepth * outHeight * outWidth
164 size_t cStride = 1;
165 for (size_t i = 2; i < size; i++)
166 cStride *= targetShape[i];
167 // Broadcast each element of the bias to a vector of size cStride and concatenate them
168 // into a vector of size channel * cStride
169 for (size_t i = 0; i < channel; i++) {
170 std::fill(newData + i * cStride, newData + (i + 1) * cStride, data[i]);
171 }
172 // Broadcast newData[0...channel * cStride) to newData[0...batch * channel * cStride)
173 size_t batch = targetShape[0];
174 size_t bStride = channel * cStride;
175 for (size_t i = 1; i < batch; i++) {
176 std::copy(newData, newData + bStride, newData + i * bStride);
177 }
178 return newData;
179}
180
181// Broadcast a tensor from shape to targetShape according to numpy broadcasting rules
182// See more at https://numpy.org/doc/stable/user/basics.broadcasting.html
183// and https://github.com/onnx/onnx/blob/main/docs/Broadcasting.md .
184template<typename T>
185T* BroadcastTensor(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape) {
186 // Size of the shapes
187 size_t size = shape.size();
188 // Current length of the broadcasted tensor
189 size_t curLength = ConvertShapeToLength(shape);
190 size_t targetLength = ConvertShapeToLength(targetShape);
191 // newShape is an aray of size equal to dimension along which we are broadcasting the tensor
192 T* broadcastedData = new T[targetLength];
193 std::copy(data, data + curLength, broadcastedData);
194 // Product of the previous dimensions of targetShape
195 size_t arrayNum = 1;
196 // New broadcasted data
197 std::vector<T> newData(targetLength);
198
199 for (size_t idx = 0; idx < size; idx++) {
200 size_t dim = shape[idx];
201 size_t targetDim = targetShape[idx];
202 if (dim == 1 && targetDim > 1) {
203 // Set the new length of the data
204 size_t newLength = curLength * targetDim;
205 // View the data as a list of arrayNum arrays of size arrayLength
206 size_t arrayLength = curLength / arrayNum;
207 // Broadcast each array dim times
208 if (arrayLength > 1) {
209 // If each array has at least two elements
210 for (size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
211 for (size_t targetIdx = 0; targetIdx < targetDim; targetIdx++) {
212 size_t offset = arrayIdx * arrayLength * targetDim + targetIdx * arrayLength;
213 std::copy(broadcastedData + arrayIdx * arrayLength,
214 broadcastedData + (arrayIdx + 1) * arrayLength,
215 newData.begin() + offset);
216 }
217 }
218 } else {
219 // If each array has one element
220 for (size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
221 std::fill(newData.begin() + arrayIdx * targetDim,
222 newData.begin() + (arrayIdx + 1) * targetDim, broadcastedData[arrayIdx]);
223 }
224 }
225 // Update current length
226 curLength = newLength;
227 // Update broadcasted data
228 std::copy(newData.begin(), newData.begin() + newLength, broadcastedData);
229 }
230 // Update the number of arrays
231 arrayNum *= targetDim;
232 }
233 return broadcastedData;
234}
235
236// Unidirectional broadcasting shape to targetShape
237template<typename T>
238T* UnidirectionalBroadcast(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape) {
239 // Prepend shape with ones
240 if (shape.size() < targetShape.size()) {
241 size_t targetSize = targetShape.size();
242 std::vector<size_t> newShape(targetSize, 1);
243 size_t offset = targetSize - shape.size();
244 std::copy(shape.begin(), shape.end(), newShape.begin() + offset);
245 return BroadcastTensor<T>(data, newShape, targetShape);
246 }
247 return BroadcastTensor<T>(data, shape, targetShape);
248}
249
250/// compute stride of a tensor given its shape (assume layout is row-major)
251std::vector<size_t> ComputeStrideFromShape(const std::vector<size_t> & shape);
252
253/// function to check if a >> 0 and a < MAX using a single comparison
254//// use trick casting to unsigned values so it becomes a single comparison
255inline bool is_a_ge_zero_and_a_lt_b(int a, int b) {
256 return static_cast<unsigned>(a) < static_cast<unsigned>(b);
257}
258
259
260/// im2col : efficient function to re-arrange input data of convolution to a matrix
261/// that can be used by BLAS
262/// Use trick to loop on each element of filtered region first and follow input data layout
263/// By doing this reads and writes are of consecutive data in memory and one gains in efficiency
264/// The resulting matrix will be already transposed and can be used directly in BLAS
265/// since output will be a matrix : (channels*kernel_h*kernel_w , output_h*output_w)
266/// Example: with an input matrix
267/// a1 a2 a3
268/// b1 b2 b3 and a 2x2 kernel (k1,k2,k3,k4) and padding 1 :
269/// c1 c2 c3
270/// outpout will be a matrix (4 x 16)
271/// the routine will follow output order :
272// first all elements which will be operated by k1 then k2 then k3
273/// -> ( 0 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 ) all elements for k1
274/// ( 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 ) for k2
275/// ( 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 ) for k3
276/// ( a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 0 ) for k4
277///
278
279template <typename T>
280void Im2col(const T *data_im, const int channels, const int height, const int width, const int kernel_h,
281 const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w,
282 const int dilation_h, const int dilation_w, T *data_col)
283{
284 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
285 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
286 const int channel_size = height * width;
287 for (int channel = channels; channel--; data_im += channel_size) {
288 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
289 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
290 int input_row = -pad_h + kernel_row * dilation_h;
291 for (int output_rows = output_h; output_rows; output_rows--) {
292 if (!is_a_ge_zero_and_a_lt_b(input_row, height)) {
293 for (int output_cols = output_w; output_cols; output_cols--) {
294 *(data_col++) = 0;
295 }
296 } else {
297 int input_col = -pad_w + kernel_col * dilation_w;
298 for (int output_col = output_w; output_col; output_col--) {
299 if (is_a_ge_zero_and_a_lt_b(input_col, width)) {
300 *(data_col++) = data_im[input_row * width + input_col];
301 } else {
302 *(data_col++) = 0;
303 }
304 input_col += stride_w;
305 }
306 }
307 input_row += stride_h;
308 }
309 }
310 }
311 }
312}
313
314/// 3d implementation
315template <typename T>
316void Im2col_3d(const T *data_im, const int channels,
317 const int depth, const int height, const int width,
318 const int kernel_d, const int kernel_h, const int kernel_w,
319 const int pad_d, const int pad_h, const int pad_w,
320 const int stride_d, const int stride_h, const int stride_w,
321 const int dilation_d, const int dilation_h, const int dilation_w, T *data_col)
322{
323 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
324 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
325 const int output_d = (depth + 2 * pad_d - (dilation_d * (kernel_d - 1) + 1)) / stride_d + 1;
326 const int channel_size = height * width * depth;
327 // assume data are c x d x h x w
328 for (int channel = channels; channel--; data_im += channel_size) {
329 for (int kernel_depth = 0; kernel_depth < kernel_d; kernel_depth++) {
330 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
331 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
332 int input_dep = -pad_d + kernel_depth * dilation_d;
333 for (int output_dep = output_d; output_dep; output_dep--) {
334 if (!is_a_ge_zero_and_a_lt_b(input_dep, depth)) {
335 for (int output_rows = output_h; output_rows; output_rows--) {
336 for (int output_cols = output_w; output_cols; output_cols--) {
337 *(data_col++) = 0;
338 }
339 }
340 } else {
341 int input_row = -pad_h + kernel_row * dilation_h;
342 for (int output_rows = output_h; output_rows; output_rows--) {
343 if (!is_a_ge_zero_and_a_lt_b(input_row, height)) {
344 for (int output_cols = output_w; output_cols; output_cols--) {
345 *(data_col++) = 0;
346 }
347 } else {
348 int input_col = -pad_w + kernel_col * dilation_w;
349 for (int output_col = output_w; output_col; output_col--) {
350 if (is_a_ge_zero_and_a_lt_b(input_col, width)) {
351 *(data_col++) = data_im[input_dep * width * height + input_row * width + input_col];
352 } else {
353 *(data_col++) = 0;
354 }
355 input_col += stride_w;
356 }
357 }
358 input_row += stride_h;
359 }
360 }
361 input_dep += stride_d;
362 }
363 }
364 }
365 }
366 }
367}
368
369template <typename Dtype>
370void col2im(const Dtype* data_col, const int channels,
371 const int height, const int width, const int kernel_h, const int kernel_w,
372 const int pad_h, const int pad_w,
373 const int stride_h, const int stride_w,
374 const int dilation_h, const int dilation_w,
375 Dtype* data_im) {
376 // note that output data_im needs to be set to zero value!!!!
377 std::fill(data_im, data_im + height * width * channels, 0.);
378 //caffe_set(height * width * channels, Dtype(0), data_im);
379 // data_im must be a zero vector
380 //const Dtype * data_col_0 = data_col;
381 const int output_h = (height + 2 * pad_h -
382 (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
383 const int output_w = (width + 2 * pad_w -
384 (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
385 const int channel_size = height * width;
386 for (int channel = channels; channel--; data_im += channel_size) {
387 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
388 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
389 int input_row = -pad_h + kernel_row * dilation_h;
390 for (int output_rows = output_h; output_rows; output_rows--) {
391 if (!is_a_ge_zero_and_a_lt_b(input_row, height)) {
392 data_col += output_w;
393 } else {
394 int input_col = -pad_w + kernel_col * dilation_w;
395 for (int output_col = output_w; output_col; output_col--) {
396 if (is_a_ge_zero_and_a_lt_b(input_col, width)) {
397 //assert(input_row*width+input_col < height * width * channels);
398 //assert(data_col - data_col_0 < output_h*output_w*channels);
399 // std::cout << "COL2IM: input_row" << " " << input_row << " " << input_col
400 // << " <---- " << data_col - data_col_0 << " values: "
401 // << data_im[input_row * width + input_col] << " <--- " << *data_col << std::endl;
402 data_im[input_row * width + input_col] += *data_col;
403 }
404 data_col++;
405 input_col += stride_w;
406 }
407 }
408 input_row += stride_h;
409 }
410 }
411 }
412 }
413 //std::cout << "finishing col2imp" << std::endl;
414}
415
416
417
418} // end namespace UTILITY
419
420namespace BLAS{
421extern "C" void sgemm_(const char * transa, const char * transb, const int * m, const int * n, const int * k,
422 const float * alpha, const float * A, const int * lda, const float * B, const int * ldb,
423 const float * beta, float * C, const int * ldc);
424}//BLAS
425}//SOFIE
426}//Experimental
427}//TMVA
428
429#endif //TMVA_SOFIE_RMODEL
#define b(i)
Definition RSha256.hxx:100
#define a(i)
Definition RSha256.hxx:99
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
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 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 Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
#define free
Definition civetweb.c:1539
#define malloc
Definition civetweb.c:1536
const Int_t n
Definition legend1.C:16
void sgemm_(const char *transa, const char *transb, const int *m, const int *n, const int *k, const float *alpha, const float *A, const int *lda, const float *B, const int *ldb, const float *beta, float *C, const int *ldc)
bool AreSameShape(const std::vector< size_t > &, const std::vector< size_t > &)
void Im2col_3d(const T *data_im, const int channels, const int depth, const int height, const int width, const int kernel_d, const int kernel_h, const int kernel_w, const int pad_d, const int pad_h, const int pad_w, const int stride_d, const int stride_h, const int stride_w, const int dilation_d, const int dilation_h, const int dilation_w, T *data_col)
3d implementation
T * BroadcastConvBias(const T *data, const size_t channel, const std::vector< size_t > &targetShape)
void col2im(const Dtype *data_col, const int channels, const int height, const int width, const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w, const int dilation_h, const int dilation_w, Dtype *data_im)
T * BroadcastTensor(const T *data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape)
std::vector< size_t > UnidirectionalBroadcastShape(std::vector< size_t >, std::vector< size_t >)
std::string Clean_name(std::string input_tensor_name)
bool is_a_ge_zero_and_a_lt_b(int a, int b)
function to check if a >> 0 and a < MAX using a single comparison / use trick casting to unsigned val...
std::vector< size_t > MultidirectionalBroadcastShape(std::vector< std::vector< size_t > >)
T * UnidirectionalBroadcast(const T *data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape)
void Im2col(const T *data_im, const int channels, const int height, const int width, const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w, const int dilation_h, const int dilation_w, T *data_col)
im2col : efficient function to re-arrange input data of convolution to a matrix that can be used by B...
std::vector< size_t > ComputeStrideFromShape(const std::vector< size_t > &shape)
compute stride of a tensor given its shape (assume layout is row-major)
std::vector< Dim > ConvertShapeToDim(std::vector< size_t > shape)
ETensorType GetTemplatedType(T)
std::string ConvertShapeToString(std::vector< size_t > shape)
std::string ConvertTypeToString(ETensorType type)
ETensorType ConvertStringToType(std::string type)
std::size_t ConvertShapeToLength(std::vector< size_t > shape)
create variable transformations
TMarker m
Definition textangle.C:8