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
6#include "ROOT/RSpan.hxx"
7
8#include <stdexcept>
9#include <type_traits>
10#include <cstdint>
11#include <cstring>
12#include <complex>
13#include <string>
14#include <vector>
15#include <map>
16#include <memory>
17#include <regex>
18#include <sstream>
19#include <iostream>
20#include <iomanip>
21#include <cassert>
22#include <limits>
23
24namespace TMVA {
25namespace Experimental {
26namespace SOFIE {
27
28enum class ETensorType{
29 UNDEFINED = 0, FLOAT = 1, UINT8 = 2, INT8 = 3, UINT16 = 4, INT16 = 5, INT32 = 6, INT64 = 7, STRING = 8, BOOL = 9, //order sensitive
30 FLOAT16 = 10, DOUBLE = 11, UINT32 = 12, UINT64 = 13, COMPLEX64 = 14, COMPLEX28 = 15, BFLOAT16 = 16
31};
32
33enum class EActivationType{
34 UNDEFINED = 0, RELU = 1, SOFTMAX = 2, SIGMOID = 3, LEAKYRELU = 4, TANH = 5, ELU = 6
35};
36
37constexpr size_t GetTypeSize(ETensorType type) {
38 switch (type) {
39 case ETensorType::FLOAT: return sizeof(float);
40 case ETensorType::DOUBLE: return sizeof(double);
41 case ETensorType::UINT8: return sizeof(uint8_t);
42 case ETensorType::INT8: return sizeof(int8_t);
43 case ETensorType::UINT16: return sizeof(uint16_t);
44 case ETensorType::INT16: return sizeof(int16_t);
45 case ETensorType::INT32: return sizeof(int32_t);
46 case ETensorType::INT64: return sizeof(int64_t);
47 case ETensorType::UINT32: return sizeof(uint32_t);
48 case ETensorType::UINT64: return sizeof(uint64_t);
49 case ETensorType::BOOL: return sizeof(bool);
50 case ETensorType::STRING: return sizeof(std::string);
51 default: return 0;
52 }
53}
54
55typedef std::int64_t int_t;
56
59
60// find if a string represents a number
61bool IsInteger(const std::string & s);
62
63struct Dim{
64 bool isParam = false;
65 size_t dim = 0;
66 std::string param;
67
68 // default constructor (for I/O)
69 Dim() {}
70
71 // constructor for a parametric dimension with the option to pass a default dim value
72 // We use -1 for dim to indicate that the param dimension is an expression (e.g. "d1+d2")
73 // in case the string represents a number make Dim not parametric
74 Dim(const std::string & p, size_t d = 0) : isParam(true), dim(d), param(p)
75 {
76 if (IsInteger(p)) {
77 isParam = false;
78 dim = std::stoi(p);
79 }
80 }
81
82 // constructor for a non-parametric dimension
83 Dim(size_t d) : dim(d) {}
84
85 std::string GetVal() const {
86 // cast to int64_t for negative shape values
87 return (isParam) ? param : std::to_string(static_cast<int64_t>(dim));
88 }
89
90 std::ostream& operator<< (std::ostream& os) const {
91 os << GetVal();
92 return os;
93 }
94
95 bool operator==(const Dim& rhs) const {
96 return (isParam && rhs.isParam) ? param == rhs.param : dim == rhs.dim;
97 }
98 bool operator!=(const Dim& rhs) const {
99 return !(*this == rhs);
100 }
101};
102
103//bool operator==(const Dim& lhs, const Dim& rhs);
104inline std::ostream & operator<< (std::ostream &os, const Dim &d) {
105 os << d.GetVal();
106 return os;
107}
108
111 std::vector<Dim> shape;
112};
113
116 std::vector<size_t> shape;
117};
118
121 std::vector<Dim> shape;
122};
123
124// template traits for Tensor Shape
125template <typename T>
126struct TensorShape {};
127template<>
129 static bool IsDim() { return true; }
130};
131template<>
132struct TensorShape<size_t> {
133 static bool IsDim() { return false; }
134};
135
136// template traits for Tensor type
137template <typename T>
138struct TensorType {};
139template<>
140struct TensorType<float> {
141 static const std::string Name() { return "float"; }
142};
143template<>
145 static const std::string Name() { return "double"; }
146};
147template<>
148struct TensorType<int64_t> {
149 static const std::string Name() { return "int64_t"; }
150};
151template<>
152struct TensorType<int32_t> {
153 static const std::string Name() { return "int32_t"; }
154};
155template<>
156struct TensorType<uint32_t> {
157 static const std::string Name() { return "uint32_t"; }
158};
159template<>
160struct TensorType<uint64_t> {
161 static const std::string Name() { return "uint64_t"; }
162};
163template<>
165 static const std::string Name() { return "bool"; }
166};
167template<>
168struct TensorType<int8_t> {
169 static const std::string Name() { return "int8_t"; }
170};
171template<>
172struct TensorType<uint8_t> {
173 static const std::string Name() { return "uint8_t"; }
174};
175
177 std::string_view tensor_name;
179
180 TensorMemoryInfo split(const std::string_view new_name, size_t new_size) {
181 if (new_size > tensor_size) {
182 throw std::invalid_argument("New size exceeds available tensor size.");
183 }
186 }
187
188 // Method to merge another struct into this one
190 tensor_size += other.tensor_size;
191 }
192};
193
195
196 // ordered map with chunk_idx as key and TensorMemoryInfo as value
197 std::map<size_t, TensorMemoryInfo> total_stack;
198
199 // ordered map with chunk_idx as key and chunk_size as value
200 std::map<size_t, size_t> available_stack;
201};
202
203std::vector<Dim> ConvertShapeToDim(const std::vector<size_t> & shape);
204
205std::vector<size_t> ConvertShapeToInt(const std::vector<Dim> & shape);
206
207std::size_t ConvertShapeToLength(const std::vector<size_t> & shape);
208
209std::string ConvertShapeToString(const std::vector<size_t> & shape);
210std::string ConvertDimShapeToString(const std::vector<Dim> & shape);
211
212std::string ConvertDimShapeToLength(const std::vector<Dim> & shape);
213
214
215template<class T>
216std::string ConvertValToString(T value) {
217 std::stringstream ret;
218 if (std::is_floating_point_v<T>)
219 ret << std::setprecision(std::numeric_limits<T>::max_digits10);
220 ret << value;
221 return ret.str();
222}
223
224
225// convert list of values in a string taking into account the precision
226template<class T>
227std::string ConvertValuesToString(size_t n, const T * data) {
228 std::stringstream ret;
229 ret << "{ ";
230 for (size_t i = 0; i < n; i++) {
231 if (std::is_floating_point_v<T>)
232 ret << std::setprecision(std::numeric_limits<T>::max_digits10) << data[i];
233 else
234 // cast in case of boolean (int8)
235 ret << (int64_t) data[i];
236
237 if (i < n-1) ret << ", ";
238 }
239 ret << "}";
240 return ret.str();
241}
242template<class T>
243std::string ConvertValuesToString(const std::vector<T> & data) {
244 return ConvertValuesToString(data.size(), data.data());
245}
246
248public:
249 InitializedTensor() = default;
250 InitializedTensor(ETensorType type, std::span<std::size_t> shape, std::shared_ptr<void> data, bool typeConstant = false)
251 : fConstant(typeConstant), fType{type}, fShape{shape.begin(), shape.end()}, fData{data}
252 {
253 }
254
255 ETensorType const &type() const { return fType; }
256 std::vector<std::size_t> const &shape() const { return fShape; }
257 std::shared_ptr<void> const &sharedptr() const { return fData; }
258 // query if tensor comes from a Constant operator
259 bool IsConstantTensor() const { return fConstant;}
260 // query if tensor needs to be written in a weight file. Constant tensors are not written in a file
261 bool IsWeightTensor() const { return !fConstant && !fIsNotWritable;}
262 // check if a Tensor is Writable (need to be written in the file or in the generated code (e.g. as a constant tensor)
263 // if an initialized tensors is used in a constant operator at compile time does not need to be written and can be omitted in
264 // the generated code
265 bool IsNotWritable() const { return fIsNotWritable; }
266 // set not writable initialized tensors - i.e. tensor that must not be written in a file
268 // set as constant (needed for non-float initialized tensors)
269 void SetConstant() { fConstant = true;}
270
271 template <class T = void>
272 T const *data() const
273 {
274 return static_cast<T const *>(fData.get());
275 }
276
278 {
279 // We only calculate fSize here, because it is only used for IO to know
280 // the size of the persistent data.
281 fSize = 1;
282 for (std::size_t item : fShape) {
283 fSize *= static_cast<int>(item);
284 }
285 switch (fType) {
286 case ETensorType::FLOAT: fSize *= sizeof(float); break;
287 case ETensorType::DOUBLE: fSize *= sizeof(double); break;
288 case ETensorType::INT32: fSize *= sizeof(int32_t); break;
289 case ETensorType::INT64: fSize *= sizeof(int64_t); break;
290 case ETensorType::BOOL: fSize *= sizeof(bool); break;
291 default:
292 throw std::runtime_error("TMVA::SOFIE doesn't yet supports serialising data-type " +
294 }
295 fPersistentData = static_cast<char *>(fData.get());
296 }
298 {
299 // If there is no persistent data, do nothing
300 if (fSize == 0 || fPersistentData == nullptr) {
301 return;
302 }
303
304 // Nothing to be done if the pointed-to data is the same
305 if (fPersistentData == static_cast<char *>(fData.get())) {
306 return;
307 }
308
309 // Initialize the shared_ptr
310 fData = std::shared_ptr<void>{malloc(fSize), free};
311 std::memcpy(fData.get(), fPersistentData, fSize);
312
313 // Make sure the data read from disk doesn't leak and delete the
314 // persistent data
315 delete[] fPersistentData;
316 fPersistentData = nullptr;
317 fSize = 0;
318 }
319
320private:
321 bool fConstant = false; ///< Flag specifying if tensor is a Constant one (coming from a Constant operator)
322 bool fIsNotWritable = false; ///< Flag to indicate that tensor values do not need to be written as weight or generated code
323 ETensorType fType; ///< Encodes the type of the data
324 std::vector<std::size_t> fShape; ///< The shape of the data in terms of elements in each dimension
325 std::shared_ptr<void> fData; ///<! Transient shared data
326 int fSize = 0; ///< The size of the persistent data in bytes (not number of elements!)
327 char *fPersistentData = nullptr; ///<[fSize] Persistent version of the data
328};
329
330template <typename T>
332 if (std::is_same<T, float>::value) return ETensorType::FLOAT;
333 if (std::is_same<T, uint8_t>::value) return ETensorType::UINT8;
334 if (std::is_same<T, int8_t>::value) return ETensorType::INT8;
335 if (std::is_same<T, uint16_t>::value) return ETensorType::UINT16;
336 if (std::is_same<T, int16_t>::value) return ETensorType::INT16;
337 if (std::is_same<T, int32_t>::value) return ETensorType::INT32;
338 if (std::is_same<T, int64_t>::value) return ETensorType::INT64;
339 if (std::is_same<T, std::string>::value) return ETensorType::STRING;
340 if (std::is_same<T, bool>::value) return ETensorType::BOOL;
341 //float16 unimplemented
342 if (std::is_same<T, double>::value) return ETensorType::DOUBLE;
343 if (std::is_same<T, uint32_t>::value) return ETensorType::UINT32;
344 if (std::is_same<T, uint64_t>::value) return ETensorType::UINT64;
345 //complex 64, 28, bfloat 16 unimplemented
346}
347
348namespace UTILITY{
349
350
351
352// clean operator and tensor names
353std::string Clean_name(std::string input_tensor_name);
354
355// Check if two shapes are equal
356bool AreSameShape(const std::vector<size_t>&, const std::vector<size_t>&);
357bool AreSameShape(const std::vector<size_t>&, const std::vector<Dim>&);
358bool AreSameShape(const std::vector<Dim>&, const std::vector<Dim>&);
359
360
361// Multidirectional broadcast a list of tensors to the same shape
362std::vector<size_t> MultidirectionalBroadcastShape(std::vector<std::vector<size_t>>);
363
364// Multidirectional broadcast two shapes to the same shape
365
366std::pair<int, std::vector<size_t>> MultidirectionalBroadcastShape(std::vector<size_t> &, std::vector<size_t> &);
367std::vector<size_t> UnidirectionalBroadcastShape(std::vector<size_t> &, std::vector<size_t> &);
368
369std::pair<int, std::vector<Dim>> MultidirectionalBroadcastShape(std::vector<Dim> &, std::vector<Dim> &);
370
371
372
373template<typename T>
374T* BroadcastConvBias(const T* data, const size_t channel, const std::vector<size_t>& targetShape) {
375 size_t size = targetShape.size();
376 if (targetShape[1] != channel) {
377 std::stringstream ss;
378 ss << "TMVA::SOFIE - Error broadcasting Conv Bias of shape {";
379 ss << std::to_string(channel);
380 ss << "} to ";
382 throw
383 std::runtime_error(ss.str());
384 }
385
387 T* newData = new T[targetLength];
388
389 if (targetLength == channel) {
390 std::copy(data, data + channel, newData);
391 return newData;
392 }
393
394 // cStride = OutDepth * outHeight * outWidth
395 size_t cStride = 1;
396 for (size_t i = 2; i < size; i++)
397 cStride *= targetShape[i];
398 // Broadcast each element of the bias to a vector of size cStride and concatenate them
399 // into a vector of size channel * cStride
400 for (size_t i = 0; i < channel; i++) {
401 std::fill(newData + i * cStride, newData + (i + 1) * cStride, data[i]);
402 }
403 // Broadcast newData[0...channel * cStride) to newData[0...batch * channel * cStride)
404 size_t batch = targetShape[0];
405 size_t bStride = channel * cStride;
406 for (size_t i = 1; i < batch; i++) {
407 std::copy(newData, newData + bStride, newData + i * bStride);
408 }
409 return newData;
410}
411
412// Broadcast a tensor from shape to targetShape according to numpy broadcasting rules
413// See more at https://numpy.org/doc/stable/user/basics.broadcasting.html
414// and https://github.com/onnx/onnx/blob/main/docs/Broadcasting.md .
415template<typename T, class ConstContT = std::span<const T>>
416void BroadcastTensor(ConstContT data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, T *broadcastedData) {
417 // Size of the shapes (tensor input here have shapes with same sizes, we have already added the needed ones )
418 size_t size = shape.size();
419 // Current length of the broadcasted tensor
420 size_t curLength = data.size();
421 // special case when broadcasting last dimensions (initial shapes must be the same)
422 if (size > 1 && shape.front() == targetShape.front() && shape.back() == 1) {
423 size_t bsize = targetShape.back();
424 // compute the size of the data to broadcast
425 for (int k = int(size)-2; k >=0; k--) {
426 if (shape[k] != 1) break;
427 bsize *= targetShape[k];
428 }
429 for (size_t i = 0; i < curLength; i++) {
430 std::fill(broadcastedData + i*bsize, broadcastedData + (i+1)*bsize , data[i]);
431 }
432 return;
433 }
434
435 std::copy(data.begin(), data.end(), broadcastedData);
436 // Product of the previous dimensions of targetShape
437 size_t arrayNum = 1;
438 // New broadcasted data: is this needed?
440
441 for (size_t idx = 0; idx < size; idx++) {
442 size_t dim = shape[idx];
443 size_t targetDim = targetShape[idx];
444 if (dim == 1 && targetDim > 1) {
445 // Set the new length of the data
446 size_t newLength = curLength * targetDim;
447 // View the data as a list of arrayNum arrays of size arrayLength
448 size_t arrayLength = curLength / arrayNum;
449 // Broadcast each array dim times
450 if (arrayLength > 1) {
451 // If each array has at least two elements
452 for (size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
453 for (size_t targetIdx = 0; targetIdx < targetDim; targetIdx++) {
457 newData.begin() + offset);
458 }
459 }
460 } else {
461 // If each array has one element
462 for (size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
463 std::fill(newData.begin() + arrayIdx * targetDim,
465 }
466 }
467 // Update current length
469 // Update broadcasted data
471 }
472 // Update the number of arrays
474 }
475}
476
477// interface where we allocate a new array for broadcasted data
478template<typename T>
479T* CreateBroadcastTensor(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, size_t targetLength) {
480 // newShape is an array of size equal to dimension along which we are broadcasting the tensor
481 T* broadcastedData = new T[targetLength];
482 size_t curLength = ConvertShapeToLength(shape);
484 return broadcastedData;
485}
486// Unidirectional broadcasting shape to targetShape// In unidirectional broadcast - only tensor B can have the shape changed not
487// tensor A - otherwise is a multidirectional broadcast
488template<typename T>
489T* UnidirectionalBroadcast(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape) {
490 // Prepend shape with ones
491 if (shape.size() < targetShape.size()) {
492 size_t targetSize = targetShape.size();
493 std::vector<size_t> newShape(targetSize, 1);
494 size_t offset = targetSize - shape.size();
495 std::copy(shape.begin(), shape.end(), newShape.begin() + offset);
497 }
499}
500
501// Unidirectional broadcasting shape to targetShape using a passed vector to avoid allocations
502template<typename T>
503void UnidirectionalBroadcast(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, T *broadcastedData) {
504 size_t curLength = ConvertShapeToLength(shape);
505 std::span<T> inData(const_cast<T*>(data), curLength);
506 // Prepend shape with ones
507 if (shape.size() < targetShape.size()) {
508 size_t targetSize = targetShape.size();
509 std::vector<size_t> newShape(targetSize, 1);
510 size_t offset = targetSize - shape.size();
511 std::copy(shape.begin(), shape.end(), newShape.begin() + offset);
513 }
515}
516
517/// compute stride of a tensor given its shape (assume layout is row-major)
518std::vector<size_t> ComputeStrideFromShape(const std::vector<size_t> & shape);
519std::vector<Dim> ComputeStrideFromShape(const std::vector<Dim> & shape);
520
521/// function to check if a >> 0 and a < MAX using a single comparison
522//// use trick casting to unsigned values so it becomes a single comparison
523inline bool is_a_ge_zero_and_a_lt_b(int a, int b) {
524 return static_cast<unsigned>(a) < static_cast<unsigned>(b);
525}
526
527
528/// im2col : efficient function to re-arrange input data of convolution to a matrix
529/// that can be used by BLAS
530/// Use trick to loop on each element of filtered region first and follow input data layout
531/// By doing this reads and writes are of consecutive data in memory and one gains in efficiency
532/// The resulting matrix will be already transposed and can be used directly in BLAS
533/// since output will be a matrix : (channels*kernel_h*kernel_w , output_h*output_w)
534/// Example: with an input matrix
535/// a1 a2 a3
536/// b1 b2 b3 and a 2x2 kernel (k1,k2,k3,k4) and padding 1 :
537/// c1 c2 c3
538/// outpout will be a matrix (4 x 16)
539/// the routine will follow output order :
540// first all elements which will be operated by k1 then k2 then k3
541/// -> ( 0 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 ) all elements for k1
542/// ( 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 ) for k2
543/// ( 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 ) for k3
544/// ( a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 0 ) for k4
545///
546
547template <typename T>
548void Im2col(const T *data_im, const int channels, const int height, const int width, const int kernel_h,
549 const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w,
550 const int dilation_h, const int dilation_w, T *data_col)
551{
552 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
553 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
554 const int channel_size = height * width;
555 for (int channel = channels; channel--; data_im += channel_size) {
556 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
557 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
562 *(data_col++) = 0;
563 }
564 } else {
566 for (int output_col = output_w; output_col; output_col--) {
569 } else {
570 *(data_col++) = 0;
571 }
573 }
574 }
576 }
577 }
578 }
579 }
580}
581
582/// 3d implementation
583template <typename T>
584void Im2col_3d(const T *data_im, const int channels,
585 const int depth, const int height, const int width,
586 const int kernel_d, const int kernel_h, const int kernel_w,
587 const int pad_d, const int pad_h, const int pad_w,
588 const int stride_d, const int stride_h, const int stride_w,
589 const int dilation_d, const int dilation_h, const int dilation_w, T *data_col)
590{
591 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
592 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
593 const int output_d = (depth + 2 * pad_d - (dilation_d * (kernel_d - 1) + 1)) / stride_d + 1;
594 const int channel_size = height * width * depth;
595 // assume data are c x d x h x w
596 for (int channel = channels; channel--; data_im += channel_size) {
597 for (int kernel_depth = 0; kernel_depth < kernel_d; kernel_depth++) {
598 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
599 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
601 for (int output_dep = output_d; output_dep; output_dep--) {
605 *(data_col++) = 0;
606 }
607 }
608 } else {
613 *(data_col++) = 0;
614 }
615 } else {
617 for (int output_col = output_w; output_col; output_col--) {
620 } else {
621 *(data_col++) = 0;
622 }
624 }
625 }
627 }
628 }
630 }
631 }
632 }
633 }
634 }
635}
636
637template <typename Dtype>
638void col2im(const Dtype* data_col, const int channels,
639 const int height, const int width, const int kernel_h, const int kernel_w,
640 const int pad_h, const int pad_w,
641 const int stride_h, const int stride_w,
642 const int dilation_h, const int dilation_w,
643 Dtype* data_im) {
644 // note that output data_im needs to be set to zero value!!!!
645 std::fill(data_im, data_im + height * width * channels, 0.);
646 //caffe_set(height * width * channels, Dtype(0), data_im);
647 // data_im must be a zero vector
648 //const Dtype * data_col_0 = data_col;
649 const int output_h = (height + 2 * pad_h -
650 (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
651 const int output_w = (width + 2 * pad_w -
652 (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
653 const int channel_size = height * width;
654 for (int channel = channels; channel--; data_im += channel_size) {
655 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
656 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
661 } else {
663 for (int output_col = output_w; output_col; output_col--) {
665 //assert(input_row*width+input_col < height * width * channels);
666 //assert(data_col - data_col_0 < output_h*output_w*channels);
667 // std::cout << "COL2IM: input_row" << " " << input_row << " " << input_col
668 // << " <---- " << data_col - data_col_0 << " values: "
669 // << data_im[input_row * width + input_col] << " <--- " << *data_col << std::endl;
671 }
672 data_col++;
674 }
675 }
677 }
678 }
679 }
680 }
681 //std::cout << "finishing col2imp" << std::endl;
682}
683
684// Used at the end of infer() to fill the return object.
685template <class T>
686void FillOutput(T const *arr, std::vector<T> &out, std::size_t n)
687{
688 out.resize(n);
689 for (std::size_t i = 0; i < n; ++i) {
690 out[i] = arr[i];
691 }
692}
693
694} // end namespace UTILITY
695
696namespace BLAS{
697extern "C" void sgemm_(const char * transa, const char * transb, const int * m, const int * n, const int * k,
698 const float * alpha, const float * A, const int * lda, const float * B, const int * ldb,
699 const float * beta, float * C, const int * ldc);
700}//BLAS
701
702
703struct GNN_Data {
704 RTensor<float> node_data; // the node feature data, tensor with shape (num_nodes, num_node_features)
705 RTensor<float> edge_data; // the edge feature data, tensor with shape (num_edges, num_edge_features)
706 RTensor<float> global_data; // the global features, tensor with shape (1, num_global_features)
707 RTensor<int> edge_index; // the edge index (receivers and senders for each edge), tensor with shape (2, num_edges)
708 // edge_index[0,:] are the receivers and edge_index[1,:] are the senders
709
710
711 // need to have default constructor since RTensor has not one
713
714};
715
716template<typename T>
718{
719 // concatenate tensor along axis. Shape must be the same except in the dimension of the concatenated axis
720 if (t1.GetMemoryLayout() != t2.GetMemoryLayout())
721 throw std::runtime_error("TMVA RTensor Concatenate - tensors have different memory layout");
722 auto & shape1 = t1.GetShape();
723 auto & shape2 = t2.GetShape();
724 if (t1.GetSize()/shape1[axis] != t2.GetSize()/shape2[axis]) {
725 std::cout << "axis " << axis << " sizes " << t1.GetSize() << " " << t2.GetSize() << " ";
726 std::cout << "shape 1 : " << ConvertShapeToString(t1.GetShape());
727 std::cout << " shape 2 : " << ConvertShapeToString(t2.GetShape()) << std::endl;
728 throw std::runtime_error("TMVA RTensor Concatenate - tensors have incompatible shapes");
729 }
730 std::vector<size_t> outShape = shape1;
731 outShape[axis] = shape1[axis] + shape2[axis];
733 if (t1.GetMemoryLayout() == TMVA::Experimental::MemoryLayout::ColumnMajor) {
734 throw std::runtime_error("TMVA RTensor Concatenate is not yet supported for column major tensors");
735 }
736
737 auto & stride1 = t1.GetStrides();
738 auto & stride2 = t2.GetStrides();
739 auto & outStride = tout.GetStrides();
740
741 size_t s1 = (axis > 0) ? stride1[axis-1] : t1.GetSize(); // block size to copy from first tensor
742 size_t s2 = (axis > 0) ? stride2[axis-1] : t2.GetSize(); // block size to copy from second tensor
743 size_t sout = (axis > 0) ? outStride[axis-1] : tout.GetSize();
744 size_t nb = t1.GetSize()/s1;
745 for (size_t i = 0; i < nb; i++) {
746 std::copy(t1.GetData() + i*s1, t1.GetData() + (i+1)*s1, tout.GetData() + i * sout );
747 std::copy(t2.GetData() + i*s2, t2.GetData() + (i+1)*s2, tout.GetData() + i * sout + s1 );
748 }
749
750 return tout;
751}
752
753
754inline GNN_Data Concatenate(GNN_Data & data1, GNN_Data & data2, int axis = 0) {
755 GNN_Data out;
756 out.node_data = Concatenate(data1.node_data,data2.node_data, axis);
757 out.edge_data = Concatenate(data1.edge_data,data2.edge_data, axis);
758 out.global_data = Concatenate<float>(data1.global_data,data2.global_data, axis-1);
759 // assume sender/receivers of data1 and data2 are the same
760 out.edge_index = data1.edge_index.Copy();
761 return out;
762}
763
764inline GNN_Data Copy(const GNN_Data & data) {
765 GNN_Data out;
766 out.node_data = RTensor<float>(data.node_data.GetShape());
767 out.edge_data = RTensor<float>(data.edge_data.GetShape());
768 out.global_data = RTensor<float>(data.global_data.GetShape());
769 out.edge_index = RTensor<int>(data.edge_index.GetShape());
770 std::copy(data.node_data.GetData(), data.node_data.GetData()+ data.node_data.GetSize(), out.node_data.GetData());
771 std::copy(data.edge_data.GetData(), data.edge_data.GetData()+ data.edge_data.GetSize(), out.edge_data.GetData());
772 std::copy(data.global_data.GetData(), data.global_data.GetData()+ data.global_data.GetSize(), out.global_data.GetData());
773 std::copy(data.edge_index.GetData(), data.edge_index.GetData()+ data.edge_index.GetSize(), out.edge_index.GetData());
774 return out;
775}
776
777inline void Gemm_Call(float *output, bool transa, bool transb, int m, int n, int k, float alpha, const float *A,
778 const float *B, float beta, const float *C)
779{
780 char ct = 't';
781 char cn = 'n';
782 const int *lda = transa ? &k : &m;
783 const int *ldb = transb ? &n : &k;
784 const int *ldc = &m;
785 if (C != nullptr) {
786 std::copy(C, C + m * n, output);
787 }
788 TMVA::Experimental::SOFIE::BLAS::sgemm_(transa ? &ct : &cn, transb ? &ct : &cn, &m, &n, &k, &alpha, A, lda, B, ldb,
789 &beta, output, ldc);
790}
791
792template <class T>
793void ReadTensorFromStream(std::istream &is, T &target, std::string const &expectedName, std::size_t expectedLength)
794{
795 std::string name;
796 std::size_t length;
797 is >> name >> length;
798 if (name != expectedName) {
799 std::string err_msg =
800 "TMVA-SOFIE failed to read the correct tensor name; expected name is " + expectedName + " , read " + name;
801 throw std::runtime_error(err_msg);
802 }
803 if (length != expectedLength) {
804 std::string err_msg = "TMVA-SOFIE failed to read the correct tensor size; expected size is " +
805 std::to_string(expectedLength) + " , read " + std::to_string(length);
806 throw std::runtime_error(err_msg);
807 }
808 for (size_t i = 0; i < length; ++i) {
809 is >> target[i];
810 }
811 if (is.fail()) {
812 throw std::runtime_error("TMVA-SOFIE failed to read the values for tensor " + expectedName);
813 }
814}
815
816
817// code for the memory greeding allocations
819 int begin; // start time (op index) lifetime
820 int end; // end time lifetime
821 size_t size; // size of tensors in bytes
822};
823
825 std::size_t total_bytes = 0; // total memory needed
826 std::vector<size_t> offsets; // resulted offsets for each tensor
827};
828
829/// Greedy best-fit planner with coalescing free list.
830MemoryResult OrganizeMemory(const std::vector<TensorLifeInfo> & tensorsInfo );
831
832} // namespace SOFIE
833} // namespace Experimental
834} // namespace TMVA
835
836#endif //TMVA_SOFIE_COMMON
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define a(i)
Definition RSha256.hxx:99
#define s1(x)
Definition RSha256.hxx:91
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
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 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 target
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 length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
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
char name[80]
Definition TGX11.cxx:110
#define malloc
Definition civetweb.c:1575
const_iterator begin() const
RTensor is a container with contiguous memory and shape information.
Definition RTensor.hxx:163
std::shared_ptr< void > const & sharedptr() const
std::shared_ptr< void > fData
! Transient shared data
ETensorType fType
Encodes the type of the data.
std::vector< std::size_t > const & shape() const
char * fPersistentData
[fSize] Persistent version of the data
std::vector< std::size_t > fShape
The shape of the data in terms of elements in each dimension.
bool fIsNotWritable
Flag to indicate that tensor values do not need to be written as weight or generated code.
bool fConstant
Flag specifying if tensor is a Constant one (coming from a Constant operator)
InitializedTensor(ETensorType type, std::span< std::size_t > shape, std::shared_ptr< void > data, bool typeConstant=false)
int fSize
The size of the persistent data in bytes (not number of elements!)
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
void FillOutput(T const *arr, std::vector< T > &out, std::size_t n)
T * BroadcastConvBias(const T *data, const size_t channel, const std::vector< size_t > &targetShape)
std::vector< size_t > UnidirectionalBroadcastShape(std::vector< size_t > &, std::vector< size_t > &)
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)
void BroadcastTensor(ConstContT data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape, T *broadcastedData)
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...
T * CreateBroadcastTensor(const T *data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape, size_t targetLength)
std::vector< size_t > ComputeStrideFromShape(const std::vector< size_t > &shape)
compute stride of a tensor given its shape (assume layout is row-major)
MemoryResult OrganizeMemory(const std::vector< TensorLifeInfo > &tensorsInfo)
Greedy best-fit planner with coalescing free list.
std::string ConvertDimShapeToString(const std::vector< Dim > &shape)
std::size_t ConvertShapeToLength(const std::vector< size_t > &shape)
void ReadTensorFromStream(std::istream &is, T &target, std::string const &expectedName, std::size_t expectedLength)
std::vector< Dim > ConvertShapeToDim(const std::vector< size_t > &shape)
Convert shape from integer format to dynamic one (based on Dim)
constexpr size_t GetTypeSize(ETensorType type)
ETensorType GetTemplatedType(T)
std::string ConvertValuesToString(size_t n, const T *data)
void Gemm_Call(float *output, bool transa, bool transb, int m, int n, int k, float alpha, const float *A, const float *B, float beta, const float *C)
std::vector< size_t > ConvertShapeToInt(const std::vector< Dim > &shape)
Convert shape based on Dim to integer format.
std::string ConvertTypeToString(ETensorType type)
ETensorType ConvertStringToType(std::string type)
TMVA::Experimental::RTensor< T > Concatenate(TMVA::Experimental::RTensor< T > &t1, TMVA::Experimental::RTensor< T > &t2, int axis=0)
std::ostream & operator<<(std::ostream &os, const Dim &d)
std::string ConvertDimShapeToLength(const std::vector< Dim > &shape)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
std::string ConvertValToString(T value)
bool IsInteger(const std::string &s)
GNN_Data Copy(const GNN_Data &data)
create variable transformations
bool operator!=(const Dim &rhs) const
bool operator==(const Dim &rhs) const
Dim(const std::string &p, size_t d=0)
std::ostream & operator<<(std::ostream &os) const
std::map< size_t, TensorMemoryInfo > total_stack
std::map< size_t, size_t > available_stack
void merge(const TensorMemoryInfo &other)
TensorMemoryInfo split(const std::string_view new_name, size_t new_size)
TMarker m
Definition textangle.C:8
auto * t1
Definition textangle.C:20
static void output()