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};
167
169 std::string_view tensor_name;
171
172 TensorMemoryInfo split(const std::string_view new_name, size_t new_size) {
173 if (new_size > tensor_size) {
174 throw std::invalid_argument("New size exceeds available tensor size.");
175 }
178 }
179
180 // Method to merge another struct into this one
182 tensor_size += other.tensor_size;
183 }
184};
185
187
188 // ordered map with chunk_idx as key and TensorMemoryInfo as value
189 std::map<size_t, TensorMemoryInfo> total_stack;
190
191 // ordered map with chunk_idx as key and chunk_size as value
192 std::map<size_t, size_t> available_stack;
193};
194
195std::vector<Dim> ConvertShapeToDim(const std::vector<size_t> & shape);
196
197std::vector<size_t> ConvertShapeToInt(const std::vector<Dim> & shape);
198
199std::size_t ConvertShapeToLength(const std::vector<size_t> & shape);
200
201std::string ConvertShapeToString(const std::vector<size_t> & shape);
202std::string ConvertDimShapeToString(const std::vector<Dim> & shape);
203std::string ConvertShapeToString(const std::vector<Dim> & shape);
204
205
206
207std::string ConvertDimShapeToLength(const std::vector<Dim> & shape);
208std::string ConvertDynamicShapeToLength(const std::vector<Dim> & shape);
209
210
211template<class T>
212std::string ConvertValToString(T value) {
213 std::stringstream ret;
214 if (std::is_floating_point_v<T>)
215 ret << std::setprecision(std::numeric_limits<T>::max_digits10);
216 ret << value;
217 return ret.str();
218}
219
220
221// convert list of values in a string taking into account the precision
222template<class T>
223std::string ConvertValuesToString(size_t n, const T * data) {
224 std::stringstream ret;
225 ret << "{ ";
226 for (size_t i = 0; i < n; i++) {
227 if (std::is_floating_point_v<T>)
228 ret << std::setprecision(std::numeric_limits<T>::max_digits10);
229 ret << data[i];
230 if (i < n-1) ret << ", ";
231 }
232 ret << "}";
233 return ret.str();
234}
235template<class T>
236std::string ConvertValuesToString(const std::vector<T> & data) {
237 return ConvertValuesToString(data.size(), data.data());
238}
239
241public:
242 InitializedTensor() = default;
243 InitializedTensor(ETensorType type, std::span<std::size_t> shape, std::shared_ptr<void> data, bool typeConstant = false)
244 : fConstant(typeConstant), fType{type}, fShape{shape.begin(), shape.end()}, fData{data}
245 {
246 }
247
248 ETensorType const &type() const { return fType; }
249 std::vector<std::size_t> const &shape() const { return fShape; }
250 std::shared_ptr<void> const &sharedptr() const { return fData; }
251 // query if tensor comes from a Constant operator
252 bool IsConstantTensor() const { return fConstant;}
253 // query if tensor needs to be written in a weight file. Constant tensors are not written in a file
254 bool IsWeightTensor() const { return !fConstant && !fIsNotWritable;}
255 // set not writable initialized tensors - i.e. tensor that must not be written in a file
257
258 template <class T = void>
259 T const *data() const
260 {
261 return static_cast<T const *>(fData.get());
262 }
263
265 {
266 // We only calculate fSize here, because it is only used for IO to know
267 // the size of the persistent data.
268 fSize = 1;
269 for (std::size_t item : fShape) {
270 fSize *= static_cast<int>(item);
271 }
272 switch (fType) {
273 case ETensorType::FLOAT: fSize *= sizeof(float); break;
274 case ETensorType::DOUBLE: fSize *= sizeof(double); break;
275 case ETensorType::INT32: fSize *= sizeof(int32_t); break;
276 case ETensorType::INT64: fSize *= sizeof(int64_t); break;
277 case ETensorType::BOOL: fSize *= sizeof(bool); break;
278 default:
279 throw std::runtime_error("TMVA::SOFIE doesn't yet supports serialising data-type " +
281 }
282 fPersistentData = static_cast<char *>(fData.get());
283 }
285 {
286 // If there is no persistent data, do nothing
287 if (fSize == 0 || fPersistentData == nullptr) {
288 return;
289 }
290
291 // Nothing to be done if the pointed-to data is the same
292 if (fPersistentData == static_cast<char *>(fData.get())) {
293 return;
294 }
295
296 // Initialize the shared_ptr
297 fData = std::shared_ptr<void>{malloc(fSize), free};
298 std::memcpy(fData.get(), fPersistentData, fSize);
299
300 // Make sure the data read from disk doesn't leak and delete the
301 // persistent data
302 delete[] fPersistentData;
303 fPersistentData = nullptr;
304 fSize = 0;
305 }
306
307private:
308 bool fConstant = false; ///< Flag specifying if tensor is a Constant one (coming from a Constant operator)
309 bool fIsNotWritable = false; ///< Flag to indicate that tensor values do not need to be written as weight or generated code
310 ETensorType fType; ///< Encodes the type of the data
311 std::vector<std::size_t> fShape; ///< The shape of the data in terms of elements in each dimension
312 std::shared_ptr<void> fData; ///<! Transient shared data
313 int fSize = 0; ///< The size of the persistent data in bytes (not number of elements!)
314 char *fPersistentData = nullptr; ///<[fSize] Persistent version of the data
315};
316
317template <typename T>
319 if (std::is_same<T, float>::value) return ETensorType::FLOAT;
320 if (std::is_same<T, uint8_t>::value) return ETensorType::UINT8;
321 if (std::is_same<T, int8_t>::value) return ETensorType::INT8;
322 if (std::is_same<T, uint16_t>::value) return ETensorType::UINT16;
323 if (std::is_same<T, int16_t>::value) return ETensorType::INT16;
324 if (std::is_same<T, int32_t>::value) return ETensorType::INT32;
325 if (std::is_same<T, int64_t>::value) return ETensorType::INT64;
326 if (std::is_same<T, std::string>::value) return ETensorType::STRING;
327 if (std::is_same<T, bool>::value) return ETensorType::BOOL;
328 //float16 unimplemented
329 if (std::is_same<T, double>::value) return ETensorType::DOUBLE;
330 if (std::is_same<T, uint32_t>::value) return ETensorType::UINT32;
331 if (std::is_same<T, uint64_t>::value) return ETensorType::UINT64;
332 //complex 64, 28, bfloat 16 unimplemented
333}
334
335namespace UTILITY{
336
337
338
339// clean operator and tensor names
340std::string Clean_name(std::string input_tensor_name);
341
342// Check if two shapes are equal
343bool AreSameShape(const std::vector<size_t>&, const std::vector<size_t>&);
344bool AreSameShape(const std::vector<size_t>&, const std::vector<Dim>&);
345bool AreSameShape(const std::vector<Dim>&, const std::vector<Dim>&);
346
347
348// Multidirectional broadcast a list of tensors to the same shape
349std::vector<size_t> MultidirectionalBroadcastShape(std::vector<std::vector<size_t>>);
350
351// Multidirectional broadcast two shapes to the same shape
352
353std::pair<int, std::vector<size_t>> MultidirectionalBroadcastShape(std::vector<size_t> &, std::vector<size_t> &);
354std::vector<size_t> UnidirectionalBroadcastShape(std::vector<size_t> &, std::vector<size_t> &);
355
356std::pair<int, std::vector<Dim>> MultidirectionalBroadcastShape(std::vector<Dim> &, std::vector<Dim> &);
357
358
359
360template<typename T>
361T* BroadcastConvBias(const T* data, const size_t channel, const std::vector<size_t>& targetShape) {
362 size_t size = targetShape.size();
363 if (targetShape[1] != channel) {
364 std::stringstream ss;
365 ss << "TMVA::SOFIE - Error broadcasting Conv Bias of shape {";
366 ss << std::to_string(channel);
367 ss << "} to ";
369 throw
370 std::runtime_error(ss.str());
371 }
372
374 T* newData = new T[targetLength];
375
376 if (targetLength == channel) {
377 std::copy(data, data + channel, newData);
378 return newData;
379 }
380
381 // cStride = OutDepth * outHeight * outWidth
382 size_t cStride = 1;
383 for (size_t i = 2; i < size; i++)
384 cStride *= targetShape[i];
385 // Broadcast each element of the bias to a vector of size cStride and concatenate them
386 // into a vector of size channel * cStride
387 for (size_t i = 0; i < channel; i++) {
388 std::fill(newData + i * cStride, newData + (i + 1) * cStride, data[i]);
389 }
390 // Broadcast newData[0...channel * cStride) to newData[0...batch * channel * cStride)
391 size_t batch = targetShape[0];
392 size_t bStride = channel * cStride;
393 for (size_t i = 1; i < batch; i++) {
394 std::copy(newData, newData + bStride, newData + i * bStride);
395 }
396 return newData;
397}
398
399// Broadcast a tensor from shape to targetShape according to numpy broadcasting rules
400// See more at https://numpy.org/doc/stable/user/basics.broadcasting.html
401// and https://github.com/onnx/onnx/blob/main/docs/Broadcasting.md .
402template<typename T, class ConstContT = std::span<const T>, class ContT = std::span<T> >
403void BroadcastTensor(ConstContT data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, ContT broadcastedData) {
404 // Size of the shapes (tensor input here have shapes with same sizes, we have already added the needed ones )
405 size_t size = shape.size();
406 // Current length of the broadcasted tensor
407 size_t curLength = data.size();
408 size_t targetLength = broadcastedData.size();
410 // special case when broadcasting last dimensions (initial shapes must be the same)
411 if (size > 1 && shape.front() == targetShape.front() && shape.back() == 1) {
412 size_t bsize = targetShape.back();
413 // compute the size of the data to broadcast
414 for (int k = int(size)-2; k >=0; k--) {
415 if (shape[k] != 1) break;
416 bsize *= targetShape[k];
417 }
418 for (size_t i = 0; i < curLength; i++) {
419 std::fill(broadcastedData.begin() + i*bsize, broadcastedData.begin() + (i+1)*bsize , data[i]);
420 }
421 return;
422 }
423
424 std::copy(data.begin(), data.end(), broadcastedData.begin());
425 // Product of the previous dimensions of targetShape
426 size_t arrayNum = 1;
427 // New broadcasted data: is this needed?
428 std::vector<T> newData(targetLength);
429
430 for (size_t idx = 0; idx < size; idx++) {
431 size_t dim = shape[idx];
432 size_t targetDim = targetShape[idx];
433 if (dim == 1 && targetDim > 1) {
434 // Set the new length of the data
435 size_t newLength = curLength * targetDim;
436 // View the data as a list of arrayNum arrays of size arrayLength
437 size_t arrayLength = curLength / arrayNum;
438 // Broadcast each array dim times
439 if (arrayLength > 1) {
440 // If each array has at least two elements
441 for (size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
442 for (size_t targetIdx = 0; targetIdx < targetDim; targetIdx++) {
446 newData.begin() + offset);
447 }
448 }
449 } else {
450 // If each array has one element
451 for (size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
452 std::fill(newData.begin() + arrayIdx * targetDim,
454 }
455 }
456 // Update current length
458 // Update broadcasted data
460 }
461 // Update the number of arrays
463 }
464 //return broadcastedData;
465}
466
467// interface where we allocate a new array for broadcasted data
468template<typename T>
469T* CreateBroadcastTensor(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, size_t targetLength) {
470 // newShape is an array of size equal to dimension along which we are broadcasting the tensor
471 T* broadcastedData = new T[targetLength];
473 size_t curLength = ConvertShapeToLength(shape);
474 std::span<const T> inData(data, curLength);
476 return broadcastedData;
477}
478// Unidirectional broadcasting shape to targetShape// In unidirectional broadcast - only tensor B can have the shape changed not
479// tensor A - otherwise is a multidirectional broadcast
480template<typename T>
481T* UnidirectionalBroadcast(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape) {
482 // Prepend shape with ones
483 if (shape.size() < targetShape.size()) {
484 size_t targetSize = targetShape.size();
485 std::vector<size_t> newShape(targetSize, 1);
486 size_t offset = targetSize - shape.size();
487 std::copy(shape.begin(), shape.end(), newShape.begin() + offset);
489 }
491}
492
493// Unidirectional broadcasting shape to targetShape using a passed vector to avoid allocations
494template<typename T>
495void UnidirectionalBroadcast(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, std::span<T> broadcastedData) {
496 size_t curLength = ConvertShapeToLength(shape);
497 std::span<T> inData(const_cast<T*>(data), curLength);
498 // Prepend shape with ones
499 if (shape.size() < targetShape.size()) {
500 size_t targetSize = targetShape.size();
501 std::vector<size_t> newShape(targetSize, 1);
502 size_t offset = targetSize - shape.size();
503 std::copy(shape.begin(), shape.end(), newShape.begin() + offset);
505 }
507}
508
509/// compute stride of a tensor given its shape (assume layout is row-major)
510std::vector<size_t> ComputeStrideFromShape(const std::vector<size_t> & shape);
511std::vector<Dim> ComputeStrideFromShape(const std::vector<Dim> & shape);
512
513/// function to check if a >> 0 and a < MAX using a single comparison
514//// use trick casting to unsigned values so it becomes a single comparison
515inline bool is_a_ge_zero_and_a_lt_b(int a, int b) {
516 return static_cast<unsigned>(a) < static_cast<unsigned>(b);
517}
518
519
520/// im2col : efficient function to re-arrange input data of convolution to a matrix
521/// that can be used by BLAS
522/// Use trick to loop on each element of filtered region first and follow input data layout
523/// By doing this reads and writes are of consecutive data in memory and one gains in efficiency
524/// The resulting matrix will be already transposed and can be used directly in BLAS
525/// since output will be a matrix : (channels*kernel_h*kernel_w , output_h*output_w)
526/// Example: with an input matrix
527/// a1 a2 a3
528/// b1 b2 b3 and a 2x2 kernel (k1,k2,k3,k4) and padding 1 :
529/// c1 c2 c3
530/// outpout will be a matrix (4 x 16)
531/// the routine will follow output order :
532// first all elements which will be operated by k1 then k2 then k3
533/// -> ( 0 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 ) all elements for k1
534/// ( 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 ) for k2
535/// ( 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 ) for k3
536/// ( a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 0 ) for k4
537///
538
539template <typename T>
540void Im2col(const T *data_im, const int channels, const int height, const int width, const int kernel_h,
541 const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w,
542 const int dilation_h, const int dilation_w, T *data_col)
543{
544 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
545 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
546 const int channel_size = height * width;
547 for (int channel = channels; channel--; data_im += channel_size) {
548 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
549 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
554 *(data_col++) = 0;
555 }
556 } else {
558 for (int output_col = output_w; output_col; output_col--) {
561 } else {
562 *(data_col++) = 0;
563 }
565 }
566 }
568 }
569 }
570 }
571 }
572}
573
574/// 3d implementation
575template <typename T>
576void Im2col_3d(const T *data_im, const int channels,
577 const int depth, const int height, const int width,
578 const int kernel_d, const int kernel_h, const int kernel_w,
579 const int pad_d, const int pad_h, const int pad_w,
580 const int stride_d, const int stride_h, const int stride_w,
581 const int dilation_d, const int dilation_h, const int dilation_w, T *data_col)
582{
583 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
584 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
585 const int output_d = (depth + 2 * pad_d - (dilation_d * (kernel_d - 1) + 1)) / stride_d + 1;
586 const int channel_size = height * width * depth;
587 // assume data are c x d x h x w
588 for (int channel = channels; channel--; data_im += channel_size) {
589 for (int kernel_depth = 0; kernel_depth < kernel_d; kernel_depth++) {
590 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
591 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
593 for (int output_dep = output_d; output_dep; output_dep--) {
597 *(data_col++) = 0;
598 }
599 }
600 } else {
605 *(data_col++) = 0;
606 }
607 } else {
609 for (int output_col = output_w; output_col; output_col--) {
612 } else {
613 *(data_col++) = 0;
614 }
616 }
617 }
619 }
620 }
622 }
623 }
624 }
625 }
626 }
627}
628
629template <typename Dtype>
630void col2im(const Dtype* data_col, const int channels,
631 const int height, const int width, const int kernel_h, const int kernel_w,
632 const int pad_h, const int pad_w,
633 const int stride_h, const int stride_w,
634 const int dilation_h, const int dilation_w,
635 Dtype* data_im) {
636 // note that output data_im needs to be set to zero value!!!!
637 std::fill(data_im, data_im + height * width * channels, 0.);
638 //caffe_set(height * width * channels, Dtype(0), data_im);
639 // data_im must be a zero vector
640 //const Dtype * data_col_0 = data_col;
641 const int output_h = (height + 2 * pad_h -
642 (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
643 const int output_w = (width + 2 * pad_w -
644 (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
645 const int channel_size = height * width;
646 for (int channel = channels; channel--; data_im += channel_size) {
647 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
648 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
653 } else {
655 for (int output_col = output_w; output_col; output_col--) {
657 //assert(input_row*width+input_col < height * width * channels);
658 //assert(data_col - data_col_0 < output_h*output_w*channels);
659 // std::cout << "COL2IM: input_row" << " " << input_row << " " << input_col
660 // << " <---- " << data_col - data_col_0 << " values: "
661 // << data_im[input_row * width + input_col] << " <--- " << *data_col << std::endl;
663 }
664 data_col++;
666 }
667 }
669 }
670 }
671 }
672 }
673 //std::cout << "finishing col2imp" << std::endl;
674}
675
676// Used at the end of infer() to fill the return object.
677template <class T>
678void FillOutput(T const *arr, std::vector<T> &out, std::size_t n)
679{
680 out.resize(n);
681 for (std::size_t i = 0; i < n; ++i) {
682 out[i] = arr[i];
683 }
684}
685
686} // end namespace UTILITY
687
688namespace BLAS{
689extern "C" void sgemm_(const char * transa, const char * transb, const int * m, const int * n, const int * k,
690 const float * alpha, const float * A, const int * lda, const float * B, const int * ldb,
691 const float * beta, float * C, const int * ldc);
692}//BLAS
693
694
695struct GNN_Data {
696 RTensor<float> node_data; // the node feature data, tensor with shape (num_nodes, num_node_features)
697 RTensor<float> edge_data; // the edge feature data, tensor with shape (num_edges, num_edge_features)
698 RTensor<float> global_data; // the global features, tensor with shape (1, num_global_features)
699 RTensor<int> edge_index; // the edge index (receivers and senders for each edge), tensor with shape (2, num_edges)
700 // edge_index[0,:] are the receivers and edge_index[1,:] are the senders
701
702
703 // need to have default constructor since RTensor has not one
705
706};
707
708template<typename T>
710{
711 // concatenate tensor along axis. Shape must be the same except in the dimension of the concatenated axis
712 if (t1.GetMemoryLayout() != t2.GetMemoryLayout())
713 throw std::runtime_error("TMVA RTensor Concatenate - tensors have different memory layout");
714 auto & shape1 = t1.GetShape();
715 auto & shape2 = t2.GetShape();
716 if (t1.GetSize()/shape1[axis] != t2.GetSize()/shape2[axis]) {
717 std::cout << "axis " << axis << " sizes " << t1.GetSize() << " " << t2.GetSize() << " ";
718 std::cout << "shape 1 : " << ConvertShapeToString(t1.GetShape());
719 std::cout << " shape 2 : " << ConvertShapeToString(t2.GetShape()) << std::endl;
720 throw std::runtime_error("TMVA RTensor Concatenate - tensors have incompatible shapes");
721 }
722 std::vector<size_t> outShape = shape1;
723 outShape[axis] = shape1[axis] + shape2[axis];
725 if (t1.GetMemoryLayout() == TMVA::Experimental::MemoryLayout::ColumnMajor) {
726 throw std::runtime_error("TMVA RTensor Concatenate is not yet supported for column major tensors");
727 }
728
729 auto & stride1 = t1.GetStrides();
730 auto & stride2 = t2.GetStrides();
731 auto & outStride = tout.GetStrides();
732
733 size_t s1 = (axis > 0) ? stride1[axis-1] : t1.GetSize(); // block size to copy from first tensor
734 size_t s2 = (axis > 0) ? stride2[axis-1] : t2.GetSize(); // block size to copy from second tensor
735 size_t sout = (axis > 0) ? outStride[axis-1] : tout.GetSize();
736 size_t nb = t1.GetSize()/s1;
737 for (size_t i = 0; i < nb; i++) {
738 std::copy(t1.GetData() + i*s1, t1.GetData() + (i+1)*s1, tout.GetData() + i * sout );
739 std::copy(t2.GetData() + i*s2, t2.GetData() + (i+1)*s2, tout.GetData() + i * sout + s1 );
740 }
741
742 return tout;
743}
744
745
746inline GNN_Data Concatenate(GNN_Data & data1, GNN_Data & data2, int axis = 0) {
747 GNN_Data out;
748 out.node_data = Concatenate(data1.node_data,data2.node_data, axis);
749 out.edge_data = Concatenate(data1.edge_data,data2.edge_data, axis);
750 out.global_data = Concatenate<float>(data1.global_data,data2.global_data, axis-1);
751 // assume sender/receivers of data1 and data2 are the same
752 out.edge_index = data1.edge_index.Copy();
753 return out;
754}
755
756inline GNN_Data Copy(const GNN_Data & data) {
757 GNN_Data out;
758 out.node_data = RTensor<float>(data.node_data.GetShape());
759 out.edge_data = RTensor<float>(data.edge_data.GetShape());
760 out.global_data = RTensor<float>(data.global_data.GetShape());
761 out.edge_index = RTensor<int>(data.edge_index.GetShape());
762 std::copy(data.node_data.GetData(), data.node_data.GetData()+ data.node_data.GetSize(), out.node_data.GetData());
763 std::copy(data.edge_data.GetData(), data.edge_data.GetData()+ data.edge_data.GetSize(), out.edge_data.GetData());
764 std::copy(data.global_data.GetData(), data.global_data.GetData()+ data.global_data.GetSize(), out.global_data.GetData());
765 std::copy(data.edge_index.GetData(), data.edge_index.GetData()+ data.edge_index.GetSize(), out.edge_index.GetData());
766 return out;
767}
768
769inline void Gemm_Call(float *output, bool transa, bool transb, int m, int n, int k, float alpha, const float *A,
770 const float *B, float beta, const float *C)
771{
772 char ct = 't';
773 char cn = 'n';
774 const int *lda = transa ? &k : &m;
775 const int *ldb = transb ? &n : &k;
776 const int *ldc = &m;
777 if (C != nullptr) {
778 std::copy(C, C + m * n, output);
779 }
780 TMVA::Experimental::SOFIE::BLAS::sgemm_(transa ? &ct : &cn, transb ? &ct : &cn, &m, &n, &k, &alpha, A, lda, B, ldb,
781 &beta, output, ldc);
782}
783
784template <class T>
785void ReadTensorFromStream(std::istream &is, T &target, std::string const &expectedName, std::size_t expectedLength)
786{
787 std::string name;
788 std::size_t length;
789 is >> name >> length;
790 if (name != expectedName) {
791 std::string err_msg =
792 "TMVA-SOFIE failed to read the correct tensor name; expected name is " + expectedName + " , read " + name;
793 throw std::runtime_error(err_msg);
794 }
795 if (length != expectedLength) {
796 std::string err_msg = "TMVA-SOFIE failed to read the correct tensor size; expected size is " +
797 std::to_string(expectedLength) + " , read " + std::to_string(length);
798 throw std::runtime_error(err_msg);
799 }
800 for (size_t i = 0; i < length; ++i) {
801 is >> target[i];
802 }
803 if (is.fail()) {
804 throw std::runtime_error("TMVA-SOFIE failed to read the values for tensor " + expectedName);
805 }
806}
807
808} // namespace SOFIE
809} // namespace Experimental
810} // namespace TMVA
811
812#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 BroadcastTensor(ConstContT data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape, ContT broadcastedData)
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)
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)
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::string ConvertDynamicShapeToLength(const std::vector< Dim > &shape)
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()