Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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
60struct Dim{
61 bool isParam = false;
62 size_t dim = 0;
63 std::string param;
64
65 // default constructor (for I/O)
66 Dim() {}
67
68 // constructor for a parametric dimension with the option to pass a default dim value
69 Dim(const std::string & p, size_t d = 0) : isParam(true), dim(d), param(p) {}
70
71 // constructor for a non-parametric dimension
72 Dim(size_t d) : dim(d) {}
73
74 std::string GetVal() const {
75 return (isParam) ? param : std::to_string(dim);
76 }
77};
78
79
82 std::vector<Dim> shape;
83};
84
87 std::vector<size_t> shape;
88};
89
92 std::vector<Dim> shape;
93};
94
95// template traits for Tensor type
96template <typename T>
97struct TensorType {};
98template<>
99struct TensorType<float> {
100 static const std::string Name() { return "float"; }
101};
102template<>
104 static const std::string Name() { return "double"; }
105};
106template<>
107struct TensorType<int64_t> {
108 static const std::string Name() { return "int64_t"; }
109};
110template<>
111struct TensorType<int32_t> {
112 static const std::string Name() { return "int32_t"; }
113};
114template<>
115struct TensorType<uint32_t> {
116 static const std::string Name() { return "uint32_t"; }
117};
118template<>
119struct TensorType<uint64_t> {
120 static const std::string Name() { return "uint64_t"; }
121};
122
124 std::string_view tensor_name;
126
127 TensorMemoryInfo split(const std::string_view new_name, size_t new_size) {
128 if (new_size > tensor_size) {
129 throw std::invalid_argument("New size exceeds available tensor size.");
130 }
133 }
134
135 // Method to merge another struct into this one
137 tensor_size += other.tensor_size;
138 }
139};
140
142
143 // ordered map with chunk_idx as key and TensorMemoryInfo as value
144 std::map<size_t, TensorMemoryInfo> total_stack;
145
146 // ordered map with chunk_idx as key and chunk_size as value
147 std::map<size_t, size_t> available_stack;
148};
149
150std::vector<Dim> ConvertShapeToDim(std::vector<size_t> shape);
151
152std::vector<size_t> ConvertShapeToInt(std::vector<Dim> shape);
153
154std::size_t ConvertShapeToLength(std::vector<size_t> shape);
155
156std::string ConvertShapeToString(std::vector<size_t> shape);
157std::string ConvertDynamicShapeToString(std::vector<Dim> shape);
158// std::string ConvertShapeToString(std::vector<Dim> shape) {
159// return ConvertDynamicShapeToString(shape);
160// }
161
162std::string ConvertDynamicShapeToLength(std::vector<Dim> shape);
163
164template<class T>
165std::string ConvertValToString(T value) {
166 std::stringstream ret;
167 if (std::is_floating_point_v<T>)
168 ret << std::setprecision(std::numeric_limits<T>::max_digits10);
169 ret << value;
170 return ret.str();
171}
172
173
174// convert list of values in a string taking into account the precision
175template<class T>
176std::string ConvertValuesToString(size_t n, const T * data) {
177 std::stringstream ret;
178 ret << "{ ";
179 for (size_t i = 0; i < n; i++) {
180 if (std::is_floating_point_v<T>)
181 ret << std::setprecision(std::numeric_limits<T>::max_digits10);
182 ret << data[i];
183 if (i < n-1) ret << ", ";
184 }
185 ret << "}";
186 return ret.str();
187}
188template<class T>
189std::string ConvertValuesToString(const std::vector<T> & data) {
190 return ConvertValuesToString(data.size(), data.data());
191}
192
194public:
195 InitializedTensor() = default;
196 InitializedTensor(ETensorType type, std::span<std::size_t> shape, std::shared_ptr<void> data, bool typeConstant = false)
197 : fConstant(typeConstant), fType{type}, fShape{shape.begin(), shape.end()}, fData{data}
198 {
199 }
200
201 ETensorType const &type() const { return fType; }
202 std::vector<std::size_t> const &shape() const { return fShape; }
203 std::shared_ptr<void> const &sharedptr() const { return fData; }
204 // query if tensor comes from a Constant operator
205 bool IsConstantTensor() const { return fConstant;}
206 // query if tensor needs to be written in a weight file. Constant tensors are not written in a file
207 bool IsWeightTensor() const { return !fConstant && !fIsNotWritable;}
208 // set not writable initialized tensors - i.e. tensor that must not be written in a file
210
211 template <class T = void>
212 T const *data() const
213 {
214 return static_cast<T const *>(fData.get());
215 }
216
218 {
219 // We only calculate fSize here, because it is only used for IO to know
220 // the size of the persistent data.
221 fSize = 1;
222 for (std::size_t item : fShape) {
223 fSize *= static_cast<int>(item);
224 }
225 switch (fType) {
226 case ETensorType::FLOAT: fSize *= sizeof(float); break;
227 case ETensorType::DOUBLE: fSize *= sizeof(double); break;
228 case ETensorType::INT32: fSize *= sizeof(int32_t); break;
229 case ETensorType::INT64: fSize *= sizeof(int64_t); break;
230 case ETensorType::BOOL: fSize *= sizeof(bool); break;
231 default:
232 throw std::runtime_error("TMVA::SOFIE doesn't yet supports serialising data-type " +
234 }
235 fPersistentData = static_cast<char *>(fData.get());
236 }
238 {
239 // If there is no persistent data, do nothing
240 if (fSize == 0 || fPersistentData == nullptr) {
241 return;
242 }
243
244 // Nothing to be done if the pointed-to data is the same
245 if (fPersistentData == static_cast<char *>(fData.get())) {
246 return;
247 }
248
249 // Initialize the shared_ptr
250 fData = std::shared_ptr<void>{malloc(fSize), free};
251 std::memcpy(fData.get(), fPersistentData, fSize);
252
253 // Make sure the data read from disk doesn't leak and delete the
254 // persistent data
255 delete[] fPersistentData;
256 fPersistentData = nullptr;
257 fSize = 0;
258 }
259
260private:
261 bool fConstant = false; ///< Flag specifying if tensor is a Constant one (coming from a Constant operator)
262 bool fIsNotWritable = false; ///< Flag to indicate that tensor values do not need to be written as weight or generated code
263 ETensorType fType; ///< Encodes the type of the data
264 std::vector<std::size_t> fShape; ///< The shape of the data in terms of elements in each dimension
265 std::shared_ptr<void> fData; ///<! Transient shared data
266 int fSize = 0; ///< The size of the persistent data in bytes (not number of elements!)
267 char *fPersistentData = nullptr; ///<[fSize] Persistent version of the data
268};
269
270template <typename T>
272 if (std::is_same<T, float>::value) return ETensorType::FLOAT;
273 if (std::is_same<T, uint8_t>::value) return ETensorType::UINT8;
274 if (std::is_same<T, int8_t>::value) return ETensorType::INT8;
275 if (std::is_same<T, uint16_t>::value) return ETensorType::UINT16;
276 if (std::is_same<T, int16_t>::value) return ETensorType::INT16;
277 if (std::is_same<T, int32_t>::value) return ETensorType::INT32;
278 if (std::is_same<T, int64_t>::value) return ETensorType::INT64;
279 if (std::is_same<T, std::string>::value) return ETensorType::STRING;
280 if (std::is_same<T, bool>::value) return ETensorType::BOOL;
281 //float16 unimplemented
282 if (std::is_same<T, double>::value) return ETensorType::DOUBLE;
283 if (std::is_same<T, uint32_t>::value) return ETensorType::UINT32;
284 if (std::is_same<T, uint64_t>::value) return ETensorType::UINT64;
285 //complex 64, 28, bfloat 16 unimplemented
286}
287
288namespace UTILITY{
289// Check if two shapes are equal
290bool AreSameShape(const std::vector<size_t>&, const std::vector<size_t>&);
291bool AreSameShape(const std::vector<size_t>&, const std::vector<Dim>&);
292bool AreSameShape(const std::vector<Dim>&, const std::vector<Dim>&);
293
294
295// Multidirectional broadcast a list of tensors to the same shape
296std::vector<size_t> MultidirectionalBroadcastShape(std::vector<std::vector<size_t>>);
297
298// Unidirectional broadcast two shapes to the same shape
299std::vector<size_t> UnidirectionalBroadcastShape(std::vector<size_t>, std::vector<size_t>);
300
301std::string Clean_name(std::string input_tensor_name);
302
303template<typename T>
304T* BroadcastConvBias(const T* data, const size_t channel, const std::vector<size_t>& targetShape) {
305 size_t size = targetShape.size();
306 if (targetShape[1] != channel) {
307 std::stringstream ss;
308 ss << "TMVA::SOFIE - Error broadcasting Conv Bias of shape {";
309 ss << std::to_string(channel);
310 ss << "} to ";
312 throw
313 std::runtime_error(ss.str());
314 }
315
317 T* newData = new T[targetLength];
318
319 if (targetLength == channel) {
320 std::copy(data, data + channel, newData);
321 return newData;
322 }
323
324 // cStride = OutDepth * outHeight * outWidth
325 size_t cStride = 1;
326 for (size_t i = 2; i < size; i++)
327 cStride *= targetShape[i];
328 // Broadcast each element of the bias to a vector of size cStride and concatenate them
329 // into a vector of size channel * cStride
330 for (size_t i = 0; i < channel; i++) {
331 std::fill(newData + i * cStride, newData + (i + 1) * cStride, data[i]);
332 }
333 // Broadcast newData[0...channel * cStride) to newData[0...batch * channel * cStride)
334 size_t batch = targetShape[0];
335 size_t bStride = channel * cStride;
336 for (size_t i = 1; i < batch; i++) {
337 std::copy(newData, newData + bStride, newData + i * bStride);
338 }
339 return newData;
340}
341
342// Broadcast a tensor from shape to targetShape according to numpy broadcasting rules
343// See more at https://numpy.org/doc/stable/user/basics.broadcasting.html
344// and https://github.com/onnx/onnx/blob/main/docs/Broadcasting.md .
345template<typename T, class ConstContT = std::span<const T>, class ContT = std::span<T> >
346void BroadcastTensor(ConstContT data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, ContT broadcastedData) {
347 // Size of the shapes (tensor input here have shapes with same sizes, we have already added the needed ones )
348 size_t size = shape.size();
349 // Current length of the broadcasted tensor
350 size_t curLength = data.size();
351 size_t targetLength = broadcastedData.size();
353 // special case when broadcasting last dimensions (initial shapes must be the same)
354 if (shape.front() == targetShape.front() && shape.back() == 1 && size > 1) {
355 size_t bsize = targetShape.back();
356 // compute the size of the data to broadcast
357 for (int k = int(size)-2; k >=0; k--) {
358 if (shape[k] != 1) break;
359 bsize *= targetShape[k];
360 }
361 for (size_t i = 0; i < curLength; i++) {
362 std::fill(broadcastedData.begin() + i*bsize, broadcastedData.begin() + (i+1)*bsize , data[i]);
363 }
364 return;
365 }
366
367 std::copy(data.begin(), data.end(), broadcastedData.begin());
368 // Product of the previous dimensions of targetShape
369 size_t arrayNum = 1;
370 // New broadcasted data: is this needed?
371 std::vector<T> newData(targetLength);
372
373 for (size_t idx = 0; idx < size; idx++) {
374 size_t dim = shape[idx];
375 size_t targetDim = targetShape[idx];
376 if (dim == 1 && targetDim > 1) {
377 // Set the new length of the data
378 size_t newLength = curLength * targetDim;
379 // View the data as a list of arrayNum arrays of size arrayLength
380 size_t arrayLength = curLength / arrayNum;
381 // Broadcast each array dim times
382 if (arrayLength > 1) {
383 // If each array has at least two elements
384 for (size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
385 for (size_t targetIdx = 0; targetIdx < targetDim; targetIdx++) {
389 newData.begin() + offset);
390 }
391 }
392 } else {
393 // If each array has one element
394 for (size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
395 std::fill(newData.begin() + arrayIdx * targetDim,
397 }
398 }
399 // Update current length
401 // Update broadcasted data
403 }
404 // Update the number of arrays
406 }
407 //return broadcastedData;
408}
409
410// interface where we allocate a new array for broadcasted data
411template<typename T>
412T* CreateBroadcastTensor(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, size_t targetLength) {
413 // newShape is an array of size equal to dimension along which we are broadcasting the tensor
414 T* broadcastedData = new T[targetLength];
416 size_t curLength = ConvertShapeToLength(shape);
417 std::span<const T> inData(data, curLength);
419 return broadcastedData;
420}
421// Unidirectional broadcasting shape to targetShape// In unidirectional broadcast - only tensor B can have the shape changed not
422// tensor A - otherwise is a multidirectional broadcast
423template<typename T>
424T* UnidirectionalBroadcast(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape) {
425 // Prepend shape with ones
426 if (shape.size() < targetShape.size()) {
427 size_t targetSize = targetShape.size();
428 std::vector<size_t> newShape(targetSize, 1);
429 size_t offset = targetSize - shape.size();
430 std::copy(shape.begin(), shape.end(), newShape.begin() + offset);
432 }
434}
435
436// Unidirectional broadcasting shape to targetShape using a passed vector to avoid allocations
437template<typename T>
438void UnidirectionalBroadcast(const T* data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, std::span<T> broadcastedData) {
439 size_t curLength = ConvertShapeToLength(shape);
440 std::span<T> inData(const_cast<T*>(data), curLength);
441 // Prepend shape with ones
442 if (shape.size() < targetShape.size()) {
443 size_t targetSize = targetShape.size();
444 std::vector<size_t> newShape(targetSize, 1);
445 size_t offset = targetSize - shape.size();
446 std::copy(shape.begin(), shape.end(), newShape.begin() + offset);
448 }
450}
451// specialization for vector of boolean
452void UnidirectionalBroadcast(const std::vector<bool> & data, const std::vector<size_t>& shape, const std::vector<size_t>& targetShape, std::vector<bool> & broadcastedData);
453
454/// compute stride of a tensor given its shape (assume layout is row-major)
455std::vector<size_t> ComputeStrideFromShape(const std::vector<size_t> & shape);
456std::vector<Dim> ComputeStrideFromShape(const std::vector<Dim> & shape);
457
458/// function to check if a >> 0 and a < MAX using a single comparison
459//// use trick casting to unsigned values so it becomes a single comparison
460inline bool is_a_ge_zero_and_a_lt_b(int a, int b) {
461 return static_cast<unsigned>(a) < static_cast<unsigned>(b);
462}
463
464
465/// im2col : efficient function to re-arrange input data of convolution to a matrix
466/// that can be used by BLAS
467/// Use trick to loop on each element of filtered region first and follow input data layout
468/// By doing this reads and writes are of consecutive data in memory and one gains in efficiency
469/// The resulting matrix will be already transposed and can be used directly in BLAS
470/// since output will be a matrix : (channels*kernel_h*kernel_w , output_h*output_w)
471/// Example: with an input matrix
472/// a1 a2 a3
473/// b1 b2 b3 and a 2x2 kernel (k1,k2,k3,k4) and padding 1 :
474/// c1 c2 c3
475/// outpout will be a matrix (4 x 16)
476/// the routine will follow output order :
477// first all elements which will be operated by k1 then k2 then k3
478/// -> ( 0 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 ) all elements for k1
479/// ( 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 ) for k2
480/// ( 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 ) for k3
481/// ( a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 0 ) for k4
482///
483
484template <typename T>
485void Im2col(const T *data_im, const int channels, const int height, const int width, const int kernel_h,
486 const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w,
487 const int dilation_h, const int dilation_w, T *data_col)
488{
489 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
490 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
491 const int channel_size = height * width;
492 for (int channel = channels; channel--; data_im += channel_size) {
493 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
494 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
499 *(data_col++) = 0;
500 }
501 } else {
503 for (int output_col = output_w; output_col; output_col--) {
506 } else {
507 *(data_col++) = 0;
508 }
510 }
511 }
513 }
514 }
515 }
516 }
517}
518
519/// 3d implementation
520template <typename T>
521void Im2col_3d(const T *data_im, const int channels,
522 const int depth, const int height, const int width,
523 const int kernel_d, const int kernel_h, const int kernel_w,
524 const int pad_d, const int pad_h, const int pad_w,
525 const int stride_d, const int stride_h, const int stride_w,
526 const int dilation_d, const int dilation_h, const int dilation_w, T *data_col)
527{
528 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
529 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
530 const int output_d = (depth + 2 * pad_d - (dilation_d * (kernel_d - 1) + 1)) / stride_d + 1;
531 const int channel_size = height * width * depth;
532 // assume data are c x d x h x w
533 for (int channel = channels; channel--; data_im += channel_size) {
534 for (int kernel_depth = 0; kernel_depth < kernel_d; kernel_depth++) {
535 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
536 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
538 for (int output_dep = output_d; output_dep; output_dep--) {
542 *(data_col++) = 0;
543 }
544 }
545 } else {
550 *(data_col++) = 0;
551 }
552 } else {
554 for (int output_col = output_w; output_col; output_col--) {
557 } else {
558 *(data_col++) = 0;
559 }
561 }
562 }
564 }
565 }
567 }
568 }
569 }
570 }
571 }
572}
573
574template <typename Dtype>
575void col2im(const Dtype* data_col, const int channels,
576 const int height, const int width, const int kernel_h, const int kernel_w,
577 const int pad_h, const int pad_w,
578 const int stride_h, const int stride_w,
579 const int dilation_h, const int dilation_w,
580 Dtype* data_im) {
581 // note that output data_im needs to be set to zero value!!!!
582 std::fill(data_im, data_im + height * width * channels, 0.);
583 //caffe_set(height * width * channels, Dtype(0), data_im);
584 // data_im must be a zero vector
585 //const Dtype * data_col_0 = data_col;
586 const int output_h = (height + 2 * pad_h -
587 (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
588 const int output_w = (width + 2 * pad_w -
589 (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
590 const int channel_size = height * width;
591 for (int channel = channels; channel--; data_im += channel_size) {
592 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
593 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
598 } else {
600 for (int output_col = output_w; output_col; output_col--) {
602 //assert(input_row*width+input_col < height * width * channels);
603 //assert(data_col - data_col_0 < output_h*output_w*channels);
604 // std::cout << "COL2IM: input_row" << " " << input_row << " " << input_col
605 // << " <---- " << data_col - data_col_0 << " values: "
606 // << data_im[input_row * width + input_col] << " <--- " << *data_col << std::endl;
608 }
609 data_col++;
611 }
612 }
614 }
615 }
616 }
617 }
618 //std::cout << "finishing col2imp" << std::endl;
619}
620
621// Used at the end of infer() to fill the return object.
622template <class T>
623void FillOutput(T const *arr, std::vector<T> &out, std::size_t n)
624{
625 out.resize(n);
626 for (std::size_t i = 0; i < n; ++i) {
627 out[i] = arr[i];
628 }
629}
630
631// Special case for std::vector<bool>.
632inline void FillOutput(std::vector<bool> const &vec, std::vector<std::uint8_t> &out, std::size_t n)
633{
634 out.resize(n);
635 for (std::size_t i = 0; i < n; ++i) {
636 out[i] = vec[i];
637 }
638}
639
640} // end namespace UTILITY
641
642namespace BLAS{
643extern "C" void sgemm_(const char * transa, const char * transb, const int * m, const int * n, const int * k,
644 const float * alpha, const float * A, const int * lda, const float * B, const int * ldb,
645 const float * beta, float * C, const int * ldc);
646}//BLAS
647
648
649struct GNN_Data {
650 RTensor<float> node_data; // the node feature data, tensor with shape (num_nodes, num_node_features)
651 RTensor<float> edge_data; // the edge feature data, tensor with shape (num_edges, num_edge_features)
652 RTensor<float> global_data; // the global features, tensor with shape (1, num_global_features)
653 RTensor<int> edge_index; // the edge index (receivers and senders for each edge), tensor with shape (2, num_edges)
654 // edge_index[0,:] are the receivers and edge_index[1,:] are the senders
655
656
657 // need to have default constructor since RTensor has not one
659
660};
661
662template<typename T>
664{
665 // concatenate tensor along axis. Shape must be the same except in the dimension of the concatenated axis
666 if (t1.GetMemoryLayout() != t2.GetMemoryLayout())
667 throw std::runtime_error("TMVA RTensor Concatenate - tensors have different memory layout");
668 auto & shape1 = t1.GetShape();
669 auto & shape2 = t2.GetShape();
670 if (t1.GetSize()/shape1[axis] != t2.GetSize()/shape2[axis]) {
671 std::cout << "axis " << axis << " sizes " << t1.GetSize() << " " << t2.GetSize() << " ";
672 std::cout << "shape 1 : " << ConvertShapeToString(t1.GetShape());
673 std::cout << " shape 2 : " << ConvertShapeToString(t2.GetShape()) << std::endl;
674 throw std::runtime_error("TMVA RTensor Concatenate - tensors have incompatible shapes");
675 }
676 std::vector<size_t> outShape = shape1;
677 outShape[axis] = shape1[axis] + shape2[axis];
679 if (t1.GetMemoryLayout() == TMVA::Experimental::MemoryLayout::ColumnMajor) {
680 throw std::runtime_error("TMVA RTensor Concatenate is not yet supported for column major tensors");
681 }
682
683 auto & stride1 = t1.GetStrides();
684 auto & stride2 = t2.GetStrides();
685 auto & outStride = tout.GetStrides();
686
687 size_t s1 = (axis > 0) ? stride1[axis-1] : t1.GetSize(); // block size to copy from first tensor
688 size_t s2 = (axis > 0) ? stride2[axis-1] : t2.GetSize(); // block size to copy from second tensor
689 size_t sout = (axis > 0) ? outStride[axis-1] : tout.GetSize();
690 size_t nb = t1.GetSize()/s1;
691 for (size_t i = 0; i < nb; i++) {
692 std::copy(t1.GetData() + i*s1, t1.GetData() + (i+1)*s1, tout.GetData() + i * sout );
693 std::copy(t2.GetData() + i*s2, t2.GetData() + (i+1)*s2, tout.GetData() + i * sout + s1 );
694 }
695
696 return tout;
697}
698
699
700inline GNN_Data Concatenate(GNN_Data & data1, GNN_Data & data2, int axis = 0) {
701 GNN_Data out;
702 out.node_data = Concatenate(data1.node_data,data2.node_data, axis);
703 out.edge_data = Concatenate(data1.edge_data,data2.edge_data, axis);
704 out.global_data = Concatenate<float>(data1.global_data,data2.global_data, axis-1);
705 // assume sender/receivers of data1 and data2 are the same
706 out.edge_index = data1.edge_index.Copy();
707 return out;
708}
709
710inline GNN_Data Copy(const GNN_Data & data) {
711 GNN_Data out;
712 out.node_data = RTensor<float>(data.node_data.GetShape());
713 out.edge_data = RTensor<float>(data.edge_data.GetShape());
714 out.global_data = RTensor<float>(data.global_data.GetShape());
715 out.edge_index = RTensor<int>(data.edge_index.GetShape());
716 std::copy(data.node_data.GetData(), data.node_data.GetData()+ data.node_data.GetSize(), out.node_data.GetData());
717 std::copy(data.edge_data.GetData(), data.edge_data.GetData()+ data.edge_data.GetSize(), out.edge_data.GetData());
718 std::copy(data.global_data.GetData(), data.global_data.GetData()+ data.global_data.GetSize(), out.global_data.GetData());
719 std::copy(data.edge_index.GetData(), data.edge_index.GetData()+ data.edge_index.GetSize(), out.edge_index.GetData());
720 return out;
721}
722
723inline void Gemm_Call(float *output, bool transa, bool transb, int m, int n, int k, float alpha, const float *A,
724 const float *B, float beta, const float *C)
725{
726 char ct = 't';
727 char cn = 'n';
728 const int *lda = transa ? &k : &m;
729 const int *ldb = transb ? &n : &k;
730 const int *ldc = &m;
731 if (C != nullptr) {
732 std::copy(C, C + m * n, output);
733 }
734 TMVA::Experimental::SOFIE::BLAS::sgemm_(transa ? &ct : &cn, transb ? &ct : &cn, &m, &n, &k, &alpha, A, lda, B, ldb,
735 &beta, output, ldc);
736}
737
738}//SOFIE
739}//Experimental
740}//TMVA
741
742#endif //TMVA_SOFIE_RMODEL
#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 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
#define malloc
Definition civetweb.c:1536
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)
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::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...
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::vector< Dim > ConvertShapeToDim(std::vector< size_t > shape)
Convert shape from integer format to dynamic one (based on Dim)
std::string ConvertDynamicShapeToLength(std::vector< Dim > shape)
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::string ConvertShapeToString(std::vector< size_t > shape)
std::string ConvertTypeToString(ETensorType type)
std::string ConvertDynamicShapeToString(std::vector< Dim > shape)
ETensorType ConvertStringToType(std::string type)
TMVA::Experimental::RTensor< T > Concatenate(TMVA::Experimental::RTensor< T > &t1, TMVA::Experimental::RTensor< T > &t2, int axis=0)
std::vector< size_t > ConvertShapeToInt(std::vector< Dim > shape)
Convert shape based on Dim to integer format.
std::string ConvertValToString(T value)
std::size_t ConvertShapeToLength(std::vector< size_t > shape)
GNN_Data Copy(const GNN_Data &data)
create variable transformations
Dim(const std::string &p, size_t d=0)
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()