Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Gather.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_GATHER
2#define TMVA_SOFIE_ROPERATOR_GATHER
3
5#include "TMVA/ROperator.hxx"
6#include "TMVA/RModel.hxx"
7
8#include <sstream>
9#include <stdexcept>
10#include <string>
11
12namespace TMVA{
13namespace Experimental{
14namespace SOFIE{
15
16class ROperator_Gather final : public ROperator
17{
18private:
19
20 int64_t fAttrAxis = 0;
21
22 std::string fNX;
23 std::string fNIndices;
24 std::string fNY;
25
26 std::vector<size_t> fShapeX;
27 std::vector<size_t> fShapeIndices;
28 std::vector<size_t> fShapeY;
29
30 std::vector<int64_t> fIndices; // indices vector in case they are known at initialization
31
32 std::string fType;
33
34public:
36 ROperator_Gather(int64_t attrAxis, std::string nameX, std::string nameIndices, std::string nameY):
37 fAttrAxis(attrAxis), fNX(UTILITY::Clean_name(nameX)), fNIndices(UTILITY::Clean_name(nameIndices)), fNY(UTILITY::Clean_name(nameY)) {
38 }
39
40 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input){
41 return input;
42 }
43
44 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input){
45 auto ret = input;
46 return ret;
47 }
48
49 void Initialize(RModel& model) {
50 if (!model.CheckIfTensorAlreadyExist(fNX)) {
51 throw std::runtime_error("TMVA SOFIE Gather Op Input Tensor " + fNX + " is not found in model");
52 }
53 fShapeX = model.GetTensorShape(fNX);
55 size_t q = fShapeIndices.size();
56 // Axis in range [0, r) where r=rank(X)
57 size_t r = fShapeX.size();
58 // Set the axis
59 if (fAttrAxis < 0) {
60 fAttrAxis = fAttrAxis + int64_t(r);
61 }
62 // empty fShapeIndices is a scalar value for the indices
63 size_t indicesLength = ConvertShapeToLength(fShapeIndices);
64
65 // case indices tensor is initialized
66 if (model.IsInitializedTensor(fNIndices)) {
67 int64_t* indicesData = static_cast<int64_t*>(model.GetInitializedTensorData(fNIndices).get());
68 //flag index tensor as not writable (not sure this is needed since index tensor might be used in generated code)
70 // update indices data in case of negative dim values
71 for (size_t i = 0; i < indicesLength; i++) {
72 if (indicesData[i] < 0) {
73 indicesData[i] += fShapeX[fAttrAxis];
74 }
75 }
76 // Save in a vector gather Indices of size q
77 fIndices = std::vector<int64_t>(indicesData, indicesData + indicesLength);
78 }
79 // Output shape
80 if (model.Verbose())
81 std::cout << "Gather: q and r " << q << " " << r << " shape indices " << ConvertShapeToString(fShapeIndices) << std::endl;
82
83 if (fShapeY.empty()) {
84 fShapeY.resize(q + r - 1);
85 if (fAttrAxis > 0) {
86 // Copy shape of X[0, ..., axis) to Shape of Y[0, ..., axis)
87 std::copy(fShapeX.begin(), fShapeX.begin() + fAttrAxis, fShapeY.begin());
88 }
89 // Set shape of Y[axis, ..., axis + q)
90 for (size_t i = 0; i < q; i++) {
92 }
93 // Copy shape of X[axis + 1, ..., axis + r) to shape of Y[axis + q, ... q + r - 1)
94 std::copy(fShapeX.begin() + fAttrAxis + 1, fShapeX.end(), fShapeY.begin() + fAttrAxis + q);
95 }
96 // case input is known (type is an integer) and input indices is a scalar
97 if (model.IsInitializedTensor(fNX) && q == 0 && r == 1 && fIndices.size() > 0) {
98 if (model.GetTensorType(fNX) == ETensorType::INT64) {
99 auto inputData = static_cast<int64_t*>(model.GetInitializedTensorData(fNX).get());
100 // if q =0 and r = 1 output length = 1 (it is a scalar)
101 std::vector<int64_t> outputData(ConvertShapeToLength(fShapeY));
102 outputData[0] = inputData[fIndices[0]];
103 model.AddConstantTensor(fNY, fShapeY, outputData.data());
104 if (model.Verbose())
105 std::cout << "Gather: " << fNX << " " << ConvertShapeToString(fShapeX) << " -> " << fNY << " with shape " << ConvertShapeToString(fShapeY)
106 << " and values " << ConvertValuesToString(outputData) << " (constant) " << std::endl;
107 fIsOutputConstant = true;
108 }
109 }
110 if (!fIsOutputConstant) {
111 // Add output tensor
114 if (model.Verbose())
115 std::cout << "Gather: " << fNX << " " << ConvertShapeToString(fShapeX) << " -> " << fNY << " with shape " << ConvertShapeToString(fShapeY)
116 << std::endl;
117 }
118 }
119
120 std::string Generate(std::string OpName) {
121 if (fIsOutputConstant) {
122 // no code to generate here for constant output. Tensor output is defined in Session constructor
123 return "//---------------------------------------\n";
124 }
125 OpName = "op_" + OpName;
126 std::stringstream out;
127 out << "//--------- Gather operator \n";
128 // The shape of the output is q + r - 1
129 size_t r = fShapeX.size();
130 // Indices of shape q
131 size_t q = fShapeIndices.size();
132 // Strides
133 std::vector<size_t> stridesX = UTILITY::ComputeStrideFromShape(fShapeX);
134 std::vector<size_t> stridesY = UTILITY::ComputeStrideFromShape(fShapeY);
135 std::vector<size_t> stridesIndices = UTILITY::ComputeStrideFromShape(fShapeIndices);
136
137 // case fIndices is not known we need to correct for negative axis indices at run-time
138 if (fIndices.empty()) {
139 size_t indicesLength = ConvertShapeToLength(fShapeIndices);
140 out << SP << "// correct in case of negative gather indices\n";
141 out << SP << "for (size_t i = 0; i < " << indicesLength << "; i++){\n";
142 out << SP << SP << "if (tensor_" << fNIndices << "[i] < 0)\n";
143 out << SP << SP << SP << "tensor_" << fNIndices << "[i] += " << fShapeX[fAttrAxis] << ";\n";
144 out << SP << "}\n";
145 }
146
147
148 // Fill the output Y[j_0, j_1, ..., j_{axis - 1}, i_0, i_1, ..., i_{q - 1}, j_{axis + 1}, ..., j_{r - 1}]
149 // [0 ... axis) [axis ... axis + q) [axis + q ... q + r - 1)
150 // iterate in [0 ... axis) [0 ... q) [axis ... r - 1)
151 // for j_0, j_1, ..., j_{axis-1}
152 for (size_t j = 0; j < size_t(fAttrAxis); j++) {
153 std::string index = "j_" + std::to_string(j);
154 out << SP << "for (size_t " << index << " = 0; " << index << " < " << fShapeY[j] << "; " << index << "++) {\n";
155 }
156 // for i_0, i_1, ..., i_{q - 1}
157 if (q == 0)
158 out << SP << SP << "{\n"; // add a scope for local variables
159 for (size_t i = 0; i < q; i++) {
160 std::string index = "i_" + std::to_string(i);
161 out << SP << SP << "for (size_t " << index << " = " << 0 << "; " << index << " < " << fShapeIndices[i] << "; " << index << "++) {\n";
162 }
163 // for j_axis, j_{axis + 1}, ..., j_{r - 1}
164 for (size_t j = fAttrAxis; j + 1 < r; j++) {
165 std::string index = "j_" + std::to_string(j);
166 out << SP << SP << SP << "for (size_t " << index << " = 0; " << index << " < " << fShapeY[q + j] << "; " << index << "++) {\n";
167 }
168
169 out << SP << SP << SP << "size_t y_index = 0;\n";
170 for (size_t j = 0; j < size_t(fAttrAxis); j++) {
171 out << SP << SP << SP << "y_index += j_" + std::to_string(j) + " * " << stridesY[j] << ";\n";
172 }
173 for (size_t i = 0; i < q; i++) {
174 out << SP << SP << SP << "y_index += i_" + std::to_string(i) + " * " << stridesY[fAttrAxis + i] << ";\n";
175 }
176 for (size_t j = fAttrAxis; j + 1 < r; j++) {
177 out << SP << SP << SP << "y_index += j_" + std::to_string(j) + " * " << stridesY[q + j] << ";\n";
178 }
179 // Indices
180 out << SP << SP << SP << "size_t i_index = 0;\n";
181 for (size_t i = 0; i < q; i++) {
182 out << SP << SP << SP << "i_index += i_" + std::to_string(i) + " * " << stridesIndices[i] << ";\n";
183 }
184 // K
185 out << SP << SP << SP << "size_t k = static_cast<size_t>(" << "tensor_" << fNIndices << "[i_index]" << ");\n";
186 // Input
187 out << SP << SP << SP << "size_t x_index = k * " << stridesX[fAttrAxis] << ";\n";
188 for (size_t j = 0; j < size_t(fAttrAxis); j++) {
189 out << SP << SP << SP << "x_index += j_" + std::to_string(j) + " * " << stridesX[j] << ";\n";
190 }
191 for (size_t j = fAttrAxis + 1; j < r; j++) {
192 out << SP << SP << SP << "x_index += j_" + std::to_string(j - 1) + " * " << stridesX[j] << ";\n";
193 }
194 out << SP << SP << SP << "tensor_" << fNY << "[y_index] = tensor_" << fNX << "[x_index];\n";
195
196 // end loops j_k, j_{k + 1}, ..., j_{r - 2}
197 for (size_t j = fAttrAxis; j + 1 < r; j++) {
198 out << SP << SP << SP << "}\n";
199 }
200 // end loops i_0, i_1, ..., i_{q - 1}
201 if (q == 0)
202 out << SP << SP << "}\n"; // end of scope for q = 0
203 for (size_t i = 0; i < q; i++) {
204 out << SP << SP << "}\n";
205 }
206 // end loops j_0, j_1, ..., j_{axis - 1}
207 for (size_t j = 0; j < size_t(fAttrAxis); j++) {
208 out << SP << "}\n";
209 }
210
211 return out.str();
212 }
213
214};
215
216}//SOFIE
217}//Experimental
218}//TMVA
219
220
221#endif //TMVA_SOFIE_ROPERATOR_RELU
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 r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
float * q
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:203
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:178
bool IsInitializedTensor(const std::string &name) const
Definition RModel.cxx:188
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:264
void SetNotWritableInitializedTensor(const std::string &tensor_name)
Definition RModel.cxx:273
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input)
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input)
ROperator_Gather(int64_t attrAxis, std::string nameX, std::string nameIndices, std::string nameY)
bool fIsOutputConstant
flag to identify if operator has a constant output (no need to generate code)
Definition ROperator.hxx:43
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:41
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 ConvertValuesToString(size_t n, const T *data)
std::string ConvertShapeToString(std::vector< size_t > shape)
std::string ConvertTypeToString(ETensorType type)
std::size_t ConvertShapeToLength(std::vector< size_t > shape)
create variable transformations