Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Concat.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_Concat
2 #define TMVA_SOFIE_ROPERATOR_Concat
3
4
5 #include "TMVA/SOFIE_common.hxx"
6 #include "TMVA/ROperator.hxx"
7 #include "TMVA/RModel.hxx"
8
9 #include <sstream>
10 #include <algorithm>
11 #include <iterator>
12 #include <iomanip>
13 #include <limits>
14
15 namespace TMVA{
16 namespace Experimental{
17 namespace SOFIE{
18
19 template <typename T>
20 class ROperator_Concat final : public ROperator
21 {
22 private:
23 int fAxis=0;
24 int fnewAxis=0;
25 std::vector<std::string> fInputs;
26 std::string fOutput;
27 std::vector<Dim>fOutputShape;
28 std::vector<std::vector<Dim>> fInputShapes;
29
30 public:
32 ROperator_Concat(std::vector<std::string> inputs, int axis, int newAxis, std::string output):
33 fAxis(axis), fnewAxis(newAxis), fOutput(UTILITY::Clean_name(output)) {
34 fInputs.reserve(inputs.size());
35 for (auto & name : inputs)
37 }
38
39 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input){
40 return input;
41 }
42
43 // get shape of output given inputs. It is going to be called after initialized
44 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> inputs){
45 std::vector<std::vector<size_t>> ret(1);
46 // treat negative axis case
47 if (fAxis<0) {
48 fAxis = inputs[0].size()+fAxis;
49 }
50 if (fAxis < 0 || fAxis >= (int) inputs[0].size())
51 throw std::runtime_error("TMVA SOFIE Concat Op - invalid axis value ");
52
53 int concat_dim=0;
54 if(fnewAxis == 0){
55 for (size_t i = 0; i < inputs.size(); i++) {
56 if (i > 0 && inputs[i].size() != inputs[i - 1].size())
57 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have different shapes " +
58 ConvertShapeToString(inputs[i]) + " and " + ConvertShapeToString(inputs[i - 1]));
59 for (size_t iaxis = 0; iaxis < inputs[i].size(); iaxis++) {
60 if ((int)iaxis == fAxis)
61 concat_dim += inputs[i][iaxis];
62 else if (i > 0 && inputs[i][iaxis] != inputs[i - 1][iaxis])
63 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have wrong shapes " +
64 ConvertShapeToString(inputs[i]) + " and " +
65 ConvertShapeToString(inputs[i - 1]));
66 }
67 }
68
69 // output shape
70 ret[0] = inputs[0];
71 ret[0][fAxis] = concat_dim;
72 }
73 std::vector<int> stack;
74 if(fnewAxis == 1){
75 for(size_t i = 0; i < inputs.size(); i++) {
76 if (i > 0 && inputs[i].size() != inputs[i-1].size() )
77 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have different shapes " +
78 ConvertShapeToString(inputs[i]) + " and " + ConvertShapeToString(inputs[i-1]));
79 for (size_t iaxis = 0; iaxis < inputs[i].size(); iaxis++) {
80 if ((int) iaxis == fAxis)
81 stack.push_back(inputs[i][iaxis]);
82 else
83 if (i> 0 && inputs[i][iaxis] != inputs[i-1][iaxis])
84 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have wrong shapes " +
85 ConvertShapeToString(inputs[i]) + " and " + ConvertShapeToString(inputs[i-1]));
86 }
87
88 }
89 for(auto it:stack)
90 ret[0].push_back(it);
91 }
92
93 return ret;
94 }
95
96 // get shape of output given inputs. It is going to be called after initialized
97 std::vector<std::vector<Dim>> ShapeInference(const std::vector<std::vector<Dim>> & inputs){
98 std::vector<std::vector<Dim>> ret(1);
99 // treat negative axis case
100 if (fAxis<0) {
101 fAxis = inputs[0].size()+fAxis;
102 }
103 if (fAxis < 0 || fAxis >= (int) inputs[0].size())
104 throw std::runtime_error("TMVA SOFIE Concat Op - invalid axis value ");
105
106 int concat_dim=0;
107 if(fnewAxis == 0){
108 for (size_t i = 0; i < inputs.size(); i++) {
109 if (i > 0 && inputs[i].size() != inputs[i - 1].size())
110 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have different shapes " +
111 ConvertDynamicShapeToString(inputs[i]) + " and " + ConvertDynamicShapeToString(inputs[i - 1]));
112 for (size_t iaxis = 0; iaxis < inputs[i].size(); iaxis++) {
113 if ((int)iaxis == fAxis) {
114 // support only non-params shape for the concatenation axis
115 if (inputs[i][iaxis].isParam)
116 throw std::runtime_error("TMVA SOFIE Concat Op - not supporting input param dimensions for concatenation axis. Input shape is " +
117 ConvertDynamicShapeToString(inputs[i]));
118 concat_dim += inputs[i][iaxis].dim;
119 }
120 // other dimensions must be the same
121 else if (i > 0 && inputs[i][iaxis].GetVal() != inputs[i - 1][iaxis].GetVal())
122 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have wrong shapes " +
123 ConvertDynamicShapeToString(inputs[i]) + " and " +
124 ConvertDynamicShapeToString(inputs[i - 1]));
125 }
126 }
127
128 // output shape
129 ret[0] = inputs[0];
130 ret[0][fAxis].dim = concat_dim;
131 }
132 // case of stacking (not supported yet)
133 // here we need to check that input shapes are the same
134 // for example for fAxis == 0
135 // output shapes: [inputs.size(), inputs[0][0], inputs[0][1],....]
136 if(fnewAxis == 1){
137 throw std::runtime_error("TMVA SOFIE Concat Op - stacking (i.e. COncatFromSequence with new_axis=1) is not supported ");
138 }
139 return ret;
140 }
141
142 void Initialize(RModel &model)
143 {
144 for (auto &it : fInputs) {
145 if (model.CheckIfTensorAlreadyExist(it) == false) {
146 throw std::runtime_error("TMVA SOFIE Concat Op Input Tensor " + it + " is not found in model");
147 }
148 fInputShapes.push_back(model.GetDynamicTensorShape(it));
149 }
152 }
153
154 std::string Generate(std::string OpName){
155 OpName = "op_"+OpName;
156 if(fOutputShape.empty()){
157 throw std::runtime_error("TMVA SOFIE Concat called to Generate without being initialized first");
158 }
159 std::stringstream out;
160 out<<"\n//--------- Concat\n";
161 // special case when memory is contiguous
162 bool hasShapeOnes = true;
163 for(int i = 0; i<fAxis; ++i){
164 if(fInputShapes[0][i].dim !=1){
165 hasShapeOnes = false;
166 break;
167 }
168 }
169 if (fAxis == 0 || hasShapeOnes) {
170 std::string offset;
171 for(size_t i=0; i<fInputs.size(); ++i) {
173 out << SP << "std::copy(tensor_" <<fInputs[i] << ", tensor_" <<fInputs[i] << "+" << length <<", tensor_"<<fOutput;
174 if (i > 0) out << offset;
175 offset += " + " + length;
176 out << ");\n";
177 }
178 }
179 else {
180
181 std::vector<Dim> outStride = UTILITY::ComputeStrideFromShape(fOutputShape);
182 std::vector<std::vector<Dim>> inStrides(fInputs.size());
183 int idx = 0;
184 for ( auto &s : inStrides) {
186 idx++;
187 }
188 for (int i = 0; i < fAxis; ++i) {
189 // loop on dimensions
190 out << SP << "for (size_t i" << i << " = 0; i" << i << " < " << fOutputShape[i].GetVal() << "; ++i" << i <<") {\n";
191 }
192
193 out << SP << SP << SP << "int idxOut = ";
194 for (int k = 0; k < fAxis; k++) {
195 if (k > 0) out << " + ";
196 out << outStride[k].GetVal() << "*i" << k;
197 }
198 out << ";\n";
199
200 for (size_t j = 0; j < fInputs.size(); j++) {
201 if (j>0)
202 out << SP << SP << SP << "idxOut += " << fInputShapes[j-1][fAxis].GetVal() << ";\n";
203 out << SP << SP << SP << "int idxIn" << j <<" = ";
204 for (int k = 0; k < fAxis; k++) {
205 if (k > 0) out << " + ";
206 out << inStrides[j][k].GetVal() << "*i" << k;
207 }
208 out << ";\n";
209 out << SP << SP << SP << "for (size_t iC = 0; iC < " << fInputShapes[j][fAxis].GetVal() << "; ++iC) {\n";
210 out << SP << SP << SP << SP << "tensor_" << fOutput << "[idxOut+iC] = tensor_" << fInputs[j] << "[idxIn" << j << "+iC];\n";
211 out << SP << SP << SP << "}\n";
212 // concatenate the axis values
213 }
214 for (int i = 0; i < fAxis; ++i) {
215 out << SP << "}\n";
216 }
217 }
218
219 return out.str();
220 }
221 };
222 }//SOFIE
223 }//Experimental
224 }//TMVA
225
226 #endif //TMVA_SOFIE_ROPERATOR_CONCAT
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
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 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 length
char name[80]
Definition TGX11.cxx:110
const ETensorType & GetTensorType(std::string name)
Definition RModel.cxx:91
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:187
std::vector< Dim > GetDynamicTensorShape(std::string name)
Definition RModel.cxx:79
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:116
std::vector< std::vector< Dim > > ShapeInference(const std::vector< std::vector< Dim > > &inputs)
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input)
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > inputs)
std::vector< std::vector< Dim > > fInputShapes
ROperator_Concat(std::vector< std::string > inputs, int axis, int newAxis, std::string output)
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:41
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 ConvertDynamicShapeToLength(std::vector< Dim > shape)
std::string ConvertShapeToString(std::vector< size_t > shape)
std::string ConvertDynamicShapeToString(std::vector< Dim > shape)
create variable transformations
static void output()