Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Split.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_Split
2#define TMVA_SOFIE_ROPERATOR_Split
3
5#include "TMVA/ROperator.hxx"
6#include "TMVA/RModel.hxx"
7
8#include <sstream>
9
10namespace TMVA{
11namespace Experimental{
12namespace SOFIE{
13
14
16{
17
18private:
19
20 int fAxis = 0;
21 std::string fNX;
22 std::string fNSplit;
23 std::vector<std::string> fNYs;
24 std::vector<size_t> fInputShape;
25 std::vector<int64_t> fSplit;
26 std::vector<std::vector<size_t>> fOutputShapes;
27
28
29
30public:
32 ROperator_Split(const std::string & nameX, const std::string & nameS, int axis, const std::vector<std::string> & namesY):
33 fAxis(axis), fNX(UTILITY::Clean_name(nameX)), fNSplit(UTILITY::Clean_name(nameS)) {
34 fNYs.reserve(namesY.size());
35 for (auto & name : namesY)
36 fNYs.push_back(UTILITY::Clean_name(name));
37
39 fOutputTensorNames.resize(fNYs.size());
40 std::transform(fNYs.begin(), fNYs.end(), fOutputTensorNames.begin(),
41 [](const std::string& s) -> std::string_view { return s; });
42 }
43
44 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override {
45 return input;
46 }
47
48 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input) override {
49 auto ret = input; //suggest copy to compiler
50 return ret;
51 }
52
53 void Initialize(RModel& model) override {
54 if (model.CheckIfTensorAlreadyExist(fNX) == false){ //input must be a graph input, or already initialized intermediate tensor
55 throw std::runtime_error("TMVA SOFIE Split Op Input Tensor is not found in model");
56 }
58
59 // correct for negative axis
60 if (fAxis < 0) fAxis += fInputShape.size();
61 if (fAxis < 0 || fAxis >= static_cast<int>(fInputShape.size()) )
62 throw std::runtime_error("TMVA SOFIE Split - invalid axis " + std::to_string(fAxis));
63
64 // compute output shapes
65 size_t nsplit = fNYs.size();
66 // case split tensor is empty
67 if (fNSplit.empty()) {
68 int64_t splitValue = 0;
69 if (fInputShape[fAxis] % nsplit == 0) {
71 fSplit = std::vector<int64_t>(nsplit, splitValue);
72 } else {
73 // case of not equal splitting
74 splitValue = std::ceil(double(fInputShape[fAxis])/nsplit);
75 fSplit = std::vector<int64_t>(nsplit-1, splitValue);
76 fSplit.push_back(fInputShape[fAxis] % splitValue);
77 }
78 } else {
79 // get split tensor values
80 if (!model.IsInitializedTensor(fNSplit))
81 throw std::runtime_error("TMVA SOFIE Split - non-initialized split tensors are not supported");
82 auto splitShape = model.GetTensorShape(fNSplit);
83 if (splitShape.size() != 1 || splitShape[0] != nsplit)
84 throw std::runtime_error("TMVA SOFIE Split - split input tensor has invalid shape");
85 auto split_data = static_cast<int64_t *>(model.GetInitializedTensorData(fNSplit).get());
86 fSplit = std::vector<int64_t>(split_data, split_data + nsplit);
87 }
88 // compute now the output shapes
89 size_t tot_split = 0;
90 for (size_t i = 0; i < fNYs.size(); i++) {
91 std::vector<size_t> outputShape = fInputShape;
93 tot_split += fSplit[i];
95 fOutputShapes.push_back(outputShape);
96 }
98 throw std::runtime_error("TMVA SOFIE Split - Sum of split sizes must match the input dimension along the axis");
99
100
101 if (model.Verbose()) {
102 std::cout << "Split - input shape " << ConvertShapeToString(fInputShape) << " --> ";
103 for (auto & s : fOutputShapes)
104 std::cout << ConvertShapeToString(s) << " ";
105 std::cout << std::endl;
106 }
107 }
108
109
110 std::string Generate(std::string OpName) override {
111 OpName = "op_" + OpName;
112 if (fOutputShapes.empty()){
113 throw std::runtime_error("TMVA SOFIE Operator Split called to Generate without being initialized first");
114 }
115
117
118 // generate now the code for split
119 std::stringstream out;
120 out << "\n" << SP << "//------ Split\n";
121 out << SP << "size_t " << OpName << "_axis_offset = 0;\n";
122 // unroll the loop on split outputs
123 for (size_t i = 0; i < fNYs.size(); i++) {
126
127 out << SP << "for (int id = 0; id < " << length << " ; id++){\n";
128 // convert output index to input index
129 out << SP << SP << "int input_index = 0;\n";
130 out << SP << SP << "int remaining = id;\n";
131 // loop on dimensions to compute the input indices(unroll this loop)
132 for (size_t k = 0; k < fOutputShapes[i].size(); ++k) {
133 out << SP << SP << "// dim " << k << "\n";
134 if (k < fOutputShapes[i].size()-1) {
135 out << SP << SP << "input_index += (int(remaining / " << output_strides[k] << ")";
136 // for the split axis we need to consider the offset in the splits when converting to input coordinates
137 if (k == static_cast<size_t>(fAxis) && i > 0)
138 out << " + " << OpName << "_axis_offset";
139 out << ") * " << input_strides[k] << ";\n";
140 out << SP << SP << "remaining %= " << output_strides[k] << ";\n";
141 } else {
142 // for last dims all strides are one
143 out << SP << SP << "input_index += remaining";
144 if (k == static_cast<size_t>(fAxis) && i > 0)
145 out << " + " << OpName << "_axis_offset";
146 out << ";\n\n";
147 }
148 }
149
150 out << SP << SP << "tensor_" << fNYs[i] << "[id] = tensor_" << fNX <<"[input_index];\n";
151 out << SP << "}\n";
152 if (i < fNYs.size()-1) out << SP << OpName << "_axis_offset += " << fSplit[i] << ";\n";
153 }
154 return out.str();
155 }
156
157};
158
159}//SOFIE
160}//Experimental
161}//TMVA
162
163
164#endif //TMVA_SOFIE_ROPERATOR_Swish
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.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
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
char name[80]
Definition TGX11.cxx:110
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:200
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:95
const ETensorType & GetTensorType(std::string name) const
Definition RModel.cxx:67
bool IsInitializedTensor(const std::string &name) const
Definition RModel.cxx:175
const std::vector< size_t > & GetTensorShape(std::string name) const
Definition RModel.cxx:29
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition RModel.cxx:261
std::string Generate(std::string OpName) override
ROperator_Split(const std::string &nameX, const std::string &nameS, int axis, const std::vector< std::string > &namesY)
std::vector< std::vector< size_t > > fOutputShapes
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input) override
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:46
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:42
std::vector< std::string_view > fOutputTensorNames
Definition ROperator.hxx:47
std::string Clean_name(std::string input_tensor_name)
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 ConvertShapeToString(std::vector< size_t > shape)
std::size_t ConvertShapeToLength(std::vector< size_t > shape)
create variable transformations