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
20 {
21 private:
22 int fAxis=0;
23 int fnewAxis=0;
24 std::vector<std::string> fInputs;
25 std::string fOutput;
26 std::vector<Dim>fOutputShape;
27 std::vector<std::vector<Dim>> fInputShapes;
28
29 public:
31 ROperator_Concat(std::vector<std::string> inputs, int axis, int newAxis, std::string output):
32 fAxis(axis), fnewAxis(newAxis), fOutput(UTILITY::Clean_name(output)) {
33 fInputs.reserve(inputs.size());
34 for (auto & name : inputs)
36
37 fInputTensorNames.resize(fInputs.size());
38 std::transform(fInputs.begin(), fInputs.end(), fInputTensorNames.begin(),
39 [](const std::string& s) -> std::string_view { return s; });
41 }
42
43 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override {
44 return input;
45 }
46
47 // get shape of output given inputs. It is going to be called after initialized
48 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> inputs) override {
49 std::vector<std::vector<size_t>> ret(1);
50 // treat negative axis case
51 if (fAxis<0) {
52 fAxis = inputs[0].size()+fAxis;
53 }
54 if (fAxis < 0 || fAxis >= (int) inputs[0].size())
55 throw std::runtime_error("TMVA SOFIE Concat Op - invalid axis value ");
56
57 int concat_dim=0;
58 if(fnewAxis == 0){
59 for (size_t i = 0; i < inputs.size(); i++) {
60 if (i > 0 && inputs[i].size() != inputs[i - 1].size())
61 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have different shapes " +
63 for (size_t iaxis = 0; iaxis < inputs[i].size(); iaxis++) {
64 if ((int)iaxis == fAxis)
65 concat_dim += inputs[i][iaxis];
66 else if (i > 0 && inputs[i][iaxis] != inputs[i - 1][iaxis])
67 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have wrong shapes " +
68 ConvertShapeToString(inputs[i]) + " and " +
70 }
71 }
72
73 // output shape
74 ret[0] = inputs[0];
75 ret[0][fAxis] = concat_dim;
76 }
77 std::vector<int> stack;
78 if(fnewAxis == 1){
79 for(size_t i = 0; i < inputs.size(); i++) {
80 if (i > 0 && inputs[i].size() != inputs[i-1].size() )
81 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have different shapes " + fInputs[i] + " : " +
82 ConvertShapeToString(inputs[i]) + " and " + fInputs[i-1] + " : " + ConvertShapeToString(inputs[i-1]));
83 for (size_t iaxis = 0; iaxis < inputs[i].size(); iaxis++) {
84 if ((int) iaxis == fAxis)
85 stack.push_back(inputs[i][iaxis]);
86 else
87 if (i> 0 && inputs[i][iaxis] != inputs[i-1][iaxis])
88 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have wrong shapes " +
90 }
91
92 }
93 for(auto it:stack)
94 ret[0].push_back(it);
95 }
96
97 return ret;
98 }
99
100 // get shape of output given inputs. It is going to be called after initialized
101 std::vector<std::vector<Dim>> ShapeInference(const std::vector<std::vector<Dim>> & inputs) {
102 std::vector<std::vector<Dim>> ret(1);
103 // treat negative axis case
104 if (fAxis<0) {
105 fAxis = inputs[0].size()+fAxis;
106 }
107 if (fAxis < 0 || fAxis >= (int) inputs[0].size())
108 throw std::runtime_error("TMVA SOFIE Concat Op - invalid axis value ");
109
110 int concat_dim=0;
111 if(fnewAxis == 0){
112 for (size_t i = 0; i < inputs.size(); i++) {
113 if (i > 0 && inputs[i].size() != inputs[i - 1].size())
114 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have different shapes " + fInputs[i] + " : " +
115 ConvertDynamicShapeToString(inputs[i]) + " and " + fInputs[i-1] + " : " + ConvertDynamicShapeToString(inputs[i - 1]));
116 for (size_t iaxis = 0; iaxis < inputs[i].size(); iaxis++) {
117 if ((int)iaxis == fAxis) {
118 // support only non-params shape for the concatenation axis
119 if (inputs[i][iaxis].isParam)
120 throw std::runtime_error("TMVA SOFIE Concat Op - not supporting input param dimensions for concatenation axis. Input shape is " +
122 concat_dim += inputs[i][iaxis].dim;
123 }
124 // other dimensions must be the same
125 else if (i > 0 && inputs[i][iaxis].GetVal() != inputs[i - 1][iaxis].GetVal())
126 throw std::runtime_error("TMVA SOFIE Concat Op - input tensors have wrong shapes " +
127 ConvertDynamicShapeToString(inputs[i]) + " and " +
129 }
130 }
131
132 // output shape
133 ret[0] = inputs[0];
134 ret[0][fAxis].dim = concat_dim;
135 }
136 // case of stacking (not supported yet)
137 // here we need to check that input shapes are the same
138 // for example for fAxis == 0
139 // output shapes: [inputs.size(), inputs[0][0], inputs[0][1],....]
140 if(fnewAxis == 1){
141 throw std::runtime_error("TMVA SOFIE Concat Op - stacking (i.e. COncatFromSequence with new_axis=1) is not supported ");
142 }
143 return ret;
144 }
145
146 void Initialize(RModel& model) override {
147 for (auto &it : fInputs) {
148 if (model.CheckIfTensorAlreadyExist(it) == false) {
149 throw std::runtime_error("TMVA SOFIE Concat Op Input Tensor " + it + " is not found in model");
150 }
151 fInputShapes.push_back(model.GetDynamicTensorShape(it));
152 }
154 if (model.Verbose())
155 std::cout << "Output of concat operator has shape " << ConvertDynamicShapeToString(fOutputShape) << std::endl;
156
157 // check if concat has constant inputs , axis 0(concat contigous memory and type is integer)
158 if (model.GetTensorType(fInputs[0]) == ETensorType::INT64 && fAxis == 0) {
159 fIsOutputConstant = true;
160 for ( auto & input : fInputs) {
161 if (!model.IsInitializedTensor(input)) {
162 fIsOutputConstant = false;
163 break;
164 }
165 }
166 if (fIsOutputConstant) {
167 auto outputShape = ConvertShapeToInt(fOutputShape); // conversion must be possible
168 std::vector<int64_t> outputData(ConvertShapeToLength(outputShape));
169 size_t offset = 0;
170 for ( auto & input : fInputs) {
171 auto inputData = static_cast<int64_t*>(model.GetInitializedTensorData(input).get());
172 auto inputShape = model.GetTensorShape(input); // shape is not dynamic if it is constant
176 // data do not need to be written as a weight
178 }
179 model.AddConstantTensor<int64_t>(fOutput, outputShape, outputData.data());
180 if (model.Verbose()) {
181 std::cout << "output of Concat is a constant tensor " << ConvertShapeToString(outputShape) << " : "
182 << ConvertValuesToString(outputData) << std::endl;
183 }
184 }
185 }
186 if (!fIsOutputConstant) {
188 if (model.Verbose()) {
189 std::cout << "Concat ---> " << fOutput << " " << ConvertDynamicShapeToString(fOutputShape) << std::endl;
190 }
191 }
192 }
193
194 std::string Generate(std::string OpName) override {
195 if (fIsOutputConstant) return "";
196 OpName = "op_"+OpName;
197 if(fOutputShape.empty()){
198 throw std::runtime_error("TMVA SOFIE Concat called to Generate without being initialized first");
199 }
200 std::stringstream out;
201 out<<"\n//--------- Concat\n";
202 // special case when memory is contiguous
203 bool hasShapeOnes = true;
204 for(int i = 0; i<fAxis; ++i){
205 if(fInputShapes[0][i].dim !=1){
206 hasShapeOnes = false;
207 break;
208 }
209 }
210 if (fAxis == 0 || hasShapeOnes) {
211 std::string offset;
212 for(size_t i=0; i<fInputs.size(); ++i) {
214 out << SP << "std::copy(tensor_" <<fInputs[i] << ", tensor_" <<fInputs[i] << "+" << length <<", tensor_"<<fOutput;
215 if (i > 0) out << offset;
216 offset += " + " + length;
217 out << ");\n";
218 }
219 }
220 else {
221
223 std::vector<std::vector<Dim>> inStrides(fInputs.size());
224 int idx = 0;
225 for ( auto &s : inStrides) {
227 idx++;
228 }
229 for (int i = 0; i < fAxis; ++i) {
230 // loop on dimensions
231 out << SP << "for (size_t i" << i << " = 0; i" << i << " < " << fOutputShape[i].GetVal() << "; ++i" << i <<") {\n";
232 }
233
234 out << SP << SP << SP << "int idxOut = ";
235 for (int k = 0; k < fAxis; k++) {
236 if (k > 0) out << " + ";
237 out << outStride[k].GetVal() << "*i" << k;
238 }
239 out << ";\n";
240
241 for (size_t j = 0; j < fInputs.size(); j++) {
242 if (j>0)
243 out << SP << SP << SP << "idxOut += " << fInputShapes[j-1][fAxis].GetVal() << ";\n";
244 out << SP << SP << SP << "int idxIn" << j <<" = ";
245 for (int k = 0; k < fAxis; k++) {
246 if (k > 0) out << " + ";
247 out << inStrides[j][k].GetVal() << "*i" << k;
248 }
249 out << ";\n";
250 out << SP << SP << SP << "for (size_t iC = 0; iC < " << fInputShapes[j][fAxis].GetVal() << "; ++iC) {\n";
251 out << SP << SP << SP << SP << "tensor_" << fOutput << "[idxOut+iC] = tensor_" << fInputs[j] << "[idxIn" << j << "+iC];\n";
252 out << SP << SP << SP << "}\n";
253 // concatenate the axis values
254 }
255 for (int i = 0; i < fAxis; ++i) {
256 out << SP << "}\n";
257 }
258 }
259
260 return out.str();
261 }
262 };
263 }//SOFIE
264 }//Experimental
265 }//TMVA
266
267 #endif //TMVA_SOFIE_ROPERATOR_CONCAT
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 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_iterator begin() const
const ETensorType & GetTensorType(std::string name)
Definition RModel.cxx:94
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:227
std::vector< Dim > GetDynamicTensorShape(std::string name)
Definition RModel.cxx:82
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:122
void AddConstantTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition RModel.cxx:192
bool IsInitializedTensor(const std::string &name) const
Definition RModel.cxx:202
const std::vector< size_t > & GetTensorShape(std::string name)
Definition RModel.cxx:56
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition RModel.cxx:288
void SetNotWritableInitializedTensor(const std::string &tensor_name)
Definition RModel.cxx:297
std::vector< std::vector< Dim > > fInputShapes
ROperator_Concat(std::vector< std::string > inputs, int axis, int newAxis, std::string output)
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
std::string Generate(std::string OpName) override
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > inputs) override
std::vector< std::vector< Dim > > ShapeInference(const std::vector< std::vector< Dim > > &inputs)
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:46
bool fIsOutputConstant
flag to identify if operator has a constant output (no need to generate code)
Definition ROperator.hxx:44
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 ConvertDynamicShapeToLength(std::vector< Dim > shape)
std::string ConvertValuesToString(size_t n, const T *data)
std::string ConvertShapeToString(std::vector< size_t > shape)
std::string ConvertDynamicShapeToString(std::vector< Dim > shape)
std::vector< size_t > ConvertShapeToInt(std::vector< Dim > shape)
Convert shape based on Dim to integer format.
std::size_t ConvertShapeToLength(std::vector< size_t > shape)
create variable transformations
static void output()