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
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
452/// compute stride of a tensor given its shape (assume layout is row-major)
453std::vector<size_t> ComputeStrideFromShape(const std::vector<size_t> & shape);
454std::vector<Dim> ComputeStrideFromShape(const std::vector<Dim> & shape);
455
456/// function to check if a >> 0 and a < MAX using a single comparison
457//// use trick casting to unsigned values so it becomes a single comparison
458inline bool is_a_ge_zero_and_a_lt_b(int a, int b) {
459 return static_cast<unsigned>(a) < static_cast<unsigned>(b);
460}
461
462
463/// im2col : efficient function to re-arrange input data of convolution to a matrix
464/// that can be used by BLAS
465/// Use trick to loop on each element of filtered region first and follow input data layout
466/// By doing this reads and writes are of consecutive data in memory and one gains in efficiency
467/// The resulting matrix will be already transposed and can be used directly in BLAS
468/// since output will be a matrix : (channels*kernel_h*kernel_w , output_h*output_w)
469/// Example: with an input matrix
470/// a1 a2 a3
471/// b1 b2 b3 and a 2x2 kernel (k1,k2,k3,k4) and padding 1 :
472/// c1 c2 c3
473/// outpout will be a matrix (4 x 16)
474/// the routine will follow output order :
475// first all elements which will be operated by k1 then k2 then k3
476/// -> ( 0 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 ) all elements for k1
477/// ( 0 0 0 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 ) for k2
478/// ( 0 a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 ) for k3
479/// ( a1 a2 a3 0 b1 b2 b3 0 c1 c2 c3 0 0 0 0 0 ) for k4
480///
481
482template <typename T>
483void Im2col(const T *data_im, const int channels, const int height, const int width, const int kernel_h,
484 const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w,
485 const int dilation_h, const int dilation_w, T *data_col)
486{
487 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
488 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
489 const int channel_size = height * width;
490 for (int channel = channels; channel--; data_im += channel_size) {
491 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
492 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
497 *(data_col++) = 0;
498 }
499 } else {
501 for (int output_col = output_w; output_col; output_col--) {
504 } else {
505 *(data_col++) = 0;
506 }
508 }
509 }
511 }
512 }
513 }
514 }
515}
516
517/// 3d implementation
518template <typename T>
519void Im2col_3d(const T *data_im, const int channels,
520 const int depth, const int height, const int width,
521 const int kernel_d, const int kernel_h, const int kernel_w,
522 const int pad_d, const int pad_h, const int pad_w,
523 const int stride_d, const int stride_h, const int stride_w,
524 const int dilation_d, const int dilation_h, const int dilation_w, T *data_col)
525{
526 const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
527 const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
528 const int output_d = (depth + 2 * pad_d - (dilation_d * (kernel_d - 1) + 1)) / stride_d + 1;
529 const int channel_size = height * width * depth;
530 // assume data are c x d x h x w
531 for (int channel = channels; channel--; data_im += channel_size) {
532 for (int kernel_depth = 0; kernel_depth < kernel_d; kernel_depth++) {
533 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
534 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
536 for (int output_dep = output_d; output_dep; output_dep--) {
540 *(data_col++) = 0;
541 }
542 }
543 } else {
548 *(data_col++) = 0;
549 }
550 } else {
552 for (int output_col = output_w; output_col; output_col--) {
555 } else {
556 *(data_col++) = 0;
557 }
559 }
560 }
562 }
563 }
565 }
566 }
567 }
568 }
569 }
570}
571
572template <typename Dtype>
573void col2im(const Dtype* data_col, const int channels,
574 const int height, const int width, const int kernel_h, const int kernel_w,
575 const int pad_h, const int pad_w,
576 const int stride_h, const int stride_w,
577 const int dilation_h, const int dilation_w,
578 Dtype* data_im) {
579 // note that output data_im needs to be set to zero value!!!!
580 std::fill(data_im, data_im + height * width * channels, 0.);
581 //caffe_set(height * width * channels, Dtype(0), data_im);
582 // data_im must be a zero vector
583 //const Dtype * data_col_0 = data_col;
584 const int output_h = (height + 2 * pad_h -
585 (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
586 const int output_w = (width + 2 * pad_w -
587 (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
588 const int channel_size = height * width;
589 for (int channel = channels; channel--; data_im += channel_size) {
590 for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
591 for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
596 } else {
598 for (int output_col = output_w; output_col; output_col--) {
600 //assert(input_row*width+input_col < height * width * channels);
601 //assert(data_col - data_col_0 < output_h*output_w*channels);
602 // std::cout << "COL2IM: input_row" << " " << input_row << " " << input_col
603 // << " <---- " << data_col - data_col_0 << " values: "
604 // << data_im[input_row * width + input_col] << " <--- " << *data_col << std::endl;
606 }
607 data_col++;
609 }
610 }
612 }
613 }
614 }
615 }
616 //std::cout << "finishing col2imp" << std::endl;
617}
618
619// Used at the end of infer() to fill the return object.
620template <class T>
621void FillOutput(T const *arr, std::vector<T> &out, std::size_t n)
622{
623 out.resize(n);
624 for (std::size_t i = 0; i < n; ++i) {
625 out[i] = arr[i];
626 }
627}
628
629} // end namespace UTILITY
630
631namespace BLAS{
632extern "C" void sgemm_(const char * transa, const char * transb, const int * m, const int * n, const int * k,
633 const float * alpha, const float * A, const int * lda, const float * B, const int * ldb,
634 const float * beta, float * C, const int * ldc);
635}//BLAS
636
637
638struct GNN_Data {
639 RTensor<float> node_data; // the node feature data, tensor with shape (num_nodes, num_node_features)
640 RTensor<float> edge_data; // the edge feature data, tensor with shape (num_edges, num_edge_features)
641 RTensor<float> global_data; // the global features, tensor with shape (1, num_global_features)
642 RTensor<int> edge_index; // the edge index (receivers and senders for each edge), tensor with shape (2, num_edges)
643 // edge_index[0,:] are the receivers and edge_index[1,:] are the senders
644
645
646 // need to have default constructor since RTensor has not one
648
649};
650
651template<typename T>
653{
654 // concatenate tensor along axis. Shape must be the same except in the dimension of the concatenated axis
655 if (t1.GetMemoryLayout() != t2.GetMemoryLayout())
656 throw std::runtime_error("TMVA RTensor Concatenate - tensors have different memory layout");
657 auto & shape1 = t1.GetShape();
658 auto & shape2 = t2.GetShape();
659 if (t1.GetSize()/shape1[axis] != t2.GetSize()/shape2[axis]) {
660 std::cout << "axis " << axis << " sizes " << t1.GetSize() << " " << t2.GetSize() << " ";
661 std::cout << "shape 1 : " << ConvertShapeToString(t1.GetShape());
662 std::cout << " shape 2 : " << ConvertShapeToString(t2.GetShape()) << std::endl;
663 throw std::runtime_error("TMVA RTensor Concatenate - tensors have incompatible shapes");
664 }
665 std::vector<size_t> outShape = shape1;
666 outShape[axis] = shape1[axis] + shape2[axis];
668 if (t1.GetMemoryLayout() == TMVA::Experimental::MemoryLayout::ColumnMajor) {
669 throw std::runtime_error("TMVA RTensor Concatenate is not yet supported for column major tensors");
670 }
671
672 auto & stride1 = t1.GetStrides();
673 auto & stride2 = t2.GetStrides();
674 auto & outStride = tout.GetStrides();
675
676 size_t s1 = (axis > 0) ? stride1[axis-1] : t1.GetSize(); // block size to copy from first tensor
677 size_t s2 = (axis > 0) ? stride2[axis-1] : t2.GetSize(); // block size to copy from second tensor
678 size_t sout = (axis > 0) ? outStride[axis-1] : tout.GetSize();
679 size_t nb = t1.GetSize()/s1;
680 for (size_t i = 0; i < nb; i++) {
681 std::copy(t1.GetData() + i*s1, t1.GetData() + (i+1)*s1, tout.GetData() + i * sout );
682 std::copy(t2.GetData() + i*s2, t2.GetData() + (i+1)*s2, tout.GetData() + i * sout + s1 );
683 }
684
685 return tout;
686}
687
688
689inline GNN_Data Concatenate(GNN_Data & data1, GNN_Data & data2, int axis = 0) {
690 GNN_Data out;
691 out.node_data = Concatenate(data1.node_data,data2.node_data, axis);
692 out.edge_data = Concatenate(data1.edge_data,data2.edge_data, axis);
693 out.global_data = Concatenate<float>(data1.global_data,data2.global_data, axis-1);
694 // assume sender/receivers of data1 and data2 are the same
695 out.edge_index = data1.edge_index.Copy();
696 return out;
697}
698
699inline GNN_Data Copy(const GNN_Data & data) {
700 GNN_Data out;
701 out.node_data = RTensor<float>(data.node_data.GetShape());
702 out.edge_data = RTensor<float>(data.edge_data.GetShape());
703 out.global_data = RTensor<float>(data.global_data.GetShape());
704 out.edge_index = RTensor<int>(data.edge_index.GetShape());
705 std::copy(data.node_data.GetData(), data.node_data.GetData()+ data.node_data.GetSize(), out.node_data.GetData());
706 std::copy(data.edge_data.GetData(), data.edge_data.GetData()+ data.edge_data.GetSize(), out.edge_data.GetData());
707 std::copy(data.global_data.GetData(), data.global_data.GetData()+ data.global_data.GetSize(), out.global_data.GetData());
708 std::copy(data.edge_index.GetData(), data.edge_index.GetData()+ data.edge_index.GetSize(), out.edge_index.GetData());
709 return out;
710}
711
712inline void Gemm_Call(float *output, bool transa, bool transb, int m, int n, int k, float alpha, const float *A,
713 const float *B, float beta, const float *C)
714{
715 char ct = 't';
716 char cn = 'n';
717 const int *lda = transa ? &k : &m;
718 const int *ldb = transb ? &n : &k;
719 const int *ldc = &m;
720 if (C != nullptr) {
721 std::copy(C, C + m * n, output);
722 }
723 TMVA::Experimental::SOFIE::BLAS::sgemm_(transa ? &ct : &cn, transb ? &ct : &cn, &m, &n, &k, &alpha, A, lda, B, ldb,
724 &beta, output, ldc);
725}
726
727template <class T>
728void ReadTensorFromStream(std::istream &is, T &target, std::string const &expectedName, std::size_t expectedLength)
729{
730 std::string name;
731 std::size_t length;
732 is >> name >> length;
733 if (name != expectedName) {
734 std::string err_msg =
735 "TMVA-SOFIE failed to read the correct tensor name; expected name is " + expectedName + " , read " + name;
736 throw std::runtime_error(err_msg);
737 }
738 if (length != expectedLength) {
739 std::string err_msg = "TMVA-SOFIE failed to read the correct tensor size; expected size is " +
740 std::to_string(expectedLength) + " , read " + std::to_string(length);
741 throw std::runtime_error(err_msg);
742 }
743 for (size_t i = 0; i < length; ++i) {
744 is >> target[i];
745 }
746 if (is.fail()) {
747 throw std::runtime_error("TMVA-SOFIE failed to read the values for tensor " + expectedName);
748 }
749}
750
751} // namespace SOFIE
752} // namespace Experimental
753} // namespace TMVA
754
755#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 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: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)
void ReadTensorFromStream(std::istream &is, T &target, std::string const &expectedName, std::size_t expectedLength)
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()