Warning, file /include/root/TMVA/ROperator_Reshape.hxx was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 #ifndef TMVA_SOFIE_ROPERATOR_RESHAPE
0002 #define TMVA_SOFIE_ROPERATOR_RESHAPE
0003
0004 #include "TMVA/SOFIE_common.hxx"
0005 #include "TMVA/ROperator.hxx"
0006 #include "TMVA/RModel.hxx"
0007
0008 #include <cassert>
0009 #include <cctype>
0010 #include <sstream>
0011 #include <algorithm>
0012
0013 namespace TMVA{
0014 namespace Experimental{
0015 namespace SOFIE{
0016
0017 enum ReshapeOpMode { Reshape, Flatten, Squeeze, Unsqueeze };
0018
0019
0020 class ROperator_Reshape final : public ROperator
0021 {
0022
0023 private:
0024
0025 bool fVerbose = false;
0026 bool fDimInput = false;
0027 bool fDynamicShape = false;
0028 ReshapeOpMode fOpMode = Reshape;
0029
0030 int fAllowZero = 0;
0031 int fAxis = 1;
0032
0033 std::string fNData;
0034 std::string fNInput2;
0035 std::string fNOutput;
0036 std::vector<Dim> fShapeInput;
0037 std::vector<Dim> fShapeOutput;
0038 std::vector<int64_t> fAttrAxes;
0039 std::vector<int64_t> fShape;
0040
0041 public:
0042
0043 std::string Name() const {
0044 if (fOpMode == Reshape) return "Reshape";
0045 if (fOpMode == Flatten) return "Flatten";
0046 if (fOpMode == Squeeze) return "Squeeze";
0047 if (fOpMode == Unsqueeze) return "Unsqueeze";
0048 return "";
0049 }
0050
0051 ROperator_Reshape(){}
0052 ROperator_Reshape(ReshapeOpMode opMode, int attr_value, std::string nameData, std::string nameInput2, std::string nameOutput)
0053 : fOpMode(opMode), fNData(UTILITY::Clean_name(nameData)), fNInput2(UTILITY::Clean_name(nameInput2)),
0054 fNOutput(UTILITY::Clean_name(nameOutput))
0055 {
0056 if (opMode == Reshape) fAllowZero = attr_value;
0057 if (opMode == Flatten) fAxis = attr_value;
0058
0059 fInputTensorNames = { fNData };
0060 if(!fNInput2.empty()){
0061 fInputTensorNames.emplace_back(fNInput2);
0062 }
0063 fOutputTensorNames = { fNOutput };
0064 }
0065
0066
0067
0068 ROperator_Reshape(ReshapeOpMode opMode, std::vector<int64_t> attrAxes, std::string nameData, std::string nameOutput)
0069 : fOpMode(opMode), fNData(UTILITY::Clean_name(nameData)), fNOutput(UTILITY::Clean_name(nameOutput)),
0070 fAttrAxes(attrAxes)
0071 {
0072 assert(fOpMode == Squeeze || fOpMode == Unsqueeze);
0073 fInputTensorNames = { fNData };
0074 fOutputTensorNames = { fNOutput };
0075 }
0076
0077
0078 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override {
0079 auto ret = std::vector<ETensorType>(1, input[0]);
0080 return ret;
0081 }
0082 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input) override {
0083 return input;
0084 }
0085
0086
0087 std::vector<std::vector<Dim>> ShapeInference(const std::vector<std::vector<Dim>> & input) {
0088 std::vector<std::vector<Dim>> ret;
0089 auto & input_shape = input[0];
0090 if (fOpMode == Reshape) {
0091
0092 std::vector<Dim> output_shape(fShape.size());
0093 assert(!fShape.empty() && !fDynamicShape);
0094 for (size_t i = 0; i < output_shape.size(); i++) {
0095 if (fShape[i] > 0 || (fAllowZero && fShape[i] >= 0))
0096 output_shape[i] = Dim{ static_cast<size_t>(fShape[i]) };
0097 else if (!fAllowZero && fShape[i] == 0)
0098 output_shape[i] = input_shape[i];
0099 }
0100
0101 for (size_t i = 0; i < output_shape.size(); i++) {
0102 if (fShape[i] == -1) {
0103 auto tmp = output_shape;
0104 tmp.erase(tmp.begin() + i);
0105 auto tmp_length = ConvertDimShapeToLength(tmp);
0106 auto input_length = ConvertDimShapeToLength(input_shape);
0107 if (fVerbose)
0108 std::cout << "reshape- try simplifying " << ConvertDimShapeToString(input_shape) << " with length "
0109 << input_length << " to " << tmp_length << std::endl;
0110
0111 if (IsInteger(tmp_length) && IsInteger(input_length))
0112 output_shape[i] = Dim{static_cast<size_t>(std::stoi(input_length) / std::stoi(tmp_length))};
0113 else if (IsInteger(tmp_length) && std::stoi(tmp_length) == 1) {
0114 output_shape[i] = Dim{input_length, static_cast<size_t>(-1)};
0115 }
0116 else {
0117
0118
0119 bool canSimplify = false;
0120 std::vector <Dim> reduced_input;
0121 if (IsInteger(tmp_length)) {
0122
0123
0124
0125 std::stringstream ss(input_length);
0126
0127 std::string token;
0128
0129
0130 while(getline(ss, token, '*'))
0131 {
0132
0133 token.erase(std::remove_if(token.begin(), token.end(),
0134 [](unsigned char x) { return std::isspace(x); }), token.end());
0135 if (token != tmp_length) {
0136 if (IsInteger(token)) {
0137 size_t il = static_cast<size_t>(std::stoi(input_length));
0138 size_t tl = static_cast<size_t>(std::stoi(tmp_length));
0139 if ((il % tl) == 0) {
0140 canSimplify = true;
0141 reduced_input.push_back(Dim{il / tl});
0142 }
0143 } else {
0144 reduced_input.push_back(Dim{token});
0145 }
0146 } else {
0147
0148 canSimplify = true;
0149 }
0150 }
0151 }
0152 if (canSimplify) {
0153
0154 std::string res_shape = ConvertDimShapeToLength(reduced_input);
0155 if (res_shape.find('*') != std::string::npos)
0156 output_shape[i] = Dim{std::string("(") + res_shape + ")", static_cast<size_t>(-1)};
0157 else
0158 output_shape[i] = Dim{res_shape};
0159 }
0160 if (!canSimplify)
0161 output_shape[i] = Dim{std::string("(") + input_length + " / (" + tmp_length + "))", static_cast<size_t>(-1)};
0162 }
0163
0164 break;
0165 }
0166
0167
0168 }
0169
0170 if (fVerbose)
0171 std::cout << "Reshape: correct output shape to " << ConvertDimShapeToString(output_shape) << std::endl;
0172
0173 if (!fDimInput && ConvertDimShapeToLength(output_shape) != ConvertDimShapeToLength(input_shape)) {
0174 throw std::runtime_error("TMVA Reshape Op : Invalid shapes : " + ConvertDimShapeToString(input_shape) +
0175 ConvertDimShapeToString(output_shape));
0176 }
0177 ret.push_back(output_shape);
0178
0179 } else if (fOpMode == Flatten) {
0180
0181 if (fAxis < 0)
0182 fAxis += input_shape.size();
0183 auto s1 = std::vector<Dim>(input_shape.begin(), input_shape.begin() + fAxis);
0184 auto s2 = std::vector<Dim>(input_shape.begin() + fAxis, input_shape.end());
0185 auto l1 = ConvertDimShapeToLength(s1);
0186 auto l2 = ConvertDimShapeToLength(s2);
0187 std::vector<Dim> newShape = {Dim{l1}, Dim{l2}};
0188 ret.push_back(newShape);
0189 } else if (fOpMode == Squeeze) {
0190
0191
0192 auto output_shape = input_shape;
0193 if (fAttrAxes.empty()) {
0194 size_t i = 0;
0195 while (i < output_shape.size()) {
0196 if (output_shape[i] == Dim{1}) {
0197 output_shape.erase(output_shape.begin() + i);
0198 } else {
0199 i++;
0200 }
0201 }
0202 } else {
0203 std::cout << "getting shape for Squeeze...from attribute\n";
0204 auto axes = fAttrAxes;
0205 for (size_t i = 0; i < axes.size(); i++) {
0206 std::cout << i << " " << axes[i] << std::endl;
0207 if (axes[i] < 0)
0208 axes[i] += input_shape.size();
0209 if (!(output_shape[axes[i]] == Dim{1}))
0210 throw std::runtime_error("TMVA Squeeze Op : Invalid axis value " + std::to_string(axes[i]) +
0211 " for " + ConvertDimShapeToString(output_shape));
0212 }
0213
0214 std::sort(axes.begin(), axes.end(), std::greater<int>());
0215 for (auto & axis : axes) {
0216 std::cout << "erase give axis " << axis << " -> ";
0217 for (auto & o : output_shape) std::cout << o << " , ";
0218 std::cout << std::endl;
0219 output_shape.erase(output_shape.begin() + axis);
0220 }
0221 }
0222 ret.push_back(output_shape);
0223 }
0224 else if (fOpMode == Unsqueeze) {
0225
0226 assert(!fAttrAxes.empty());
0227 auto output_shape = input_shape;
0228 auto &axes = fAttrAxes;
0229
0230 int64_t r = input[0].size() + axes.size();
0231 for (auto &a : axes) {
0232 int64_t i = static_cast<int64_t>(a);
0233 if (i < -r || i > r - 1)
0234 throw std::runtime_error("TMVA Unsqueeze Op - axes input is not in correct range");
0235 if (i >= 0)
0236 output_shape.insert(output_shape.begin() + i, Dim{1});
0237 else
0238
0239 output_shape.insert(output_shape.end() + i + 1, Dim{1});
0240 }
0241 ret.push_back(output_shape);
0242 }
0243 return ret;
0244 }
0245
0246 void Initialize(RModel& model) override {
0247
0248 fVerbose = model.Verbose();
0249 if (fVerbose)
0250 std::cout << "initialize reshape op type " << fOpMode << " - " << fNInput2 << " " << fNData << std::endl;
0251
0252 if (model.CheckIfTensorAlreadyExist(fNData) == false) {
0253
0254 throw std::runtime_error("TMVA Reshape Op Input Tensor " + fNData + " is not found in model");
0255 }
0256 fShapeInput = model.GetDimTensorShape(fNData);
0257 fDimInput = model.IsDynamicTensor(fNData);
0258
0259 if (!fNInput2.empty()) {
0260 if (model.CheckIfTensorAlreadyExist(fNInput2)) {
0261 if (model.IsInitializedTensor(fNInput2)) {
0262
0263 auto dptr = model.GetInitializedTensorData(fNInput2);
0264 auto values = static_cast<int64_t *>(dptr.get());
0265 auto vec = model.GetTensorShape(fNInput2);
0266 size_t n = 1;
0267 if (vec.size() > 0)
0268 n = vec[0];
0269
0270 if (fOpMode == Reshape)
0271 fShape = std::vector<int64_t>(values, values + n);
0272 else
0273 fAttrAxes = std::vector<int64_t>(values, values + n);
0274
0275 fShapeOutput = ShapeInference({fShapeInput})[0];
0276
0277 model.SetNotWritableInitializedTensor(fNInput2);
0278 } else if (model.IsShapeTensor(fNInput2)) {
0279 auto shapeData = model.GetShapeTensorValues(fNInput2);
0280 fShapeOutput = shapeData;
0281 } else {
0282
0283 fDynamicShape = true;
0284
0285 auto shapeInput2 = model.GetTensorShape(fNInput2);
0286 fShapeOutput.resize(shapeInput2[0]);
0287 for (size_t i = 0; i < fShapeOutput.size(); i++) {
0288 fShapeOutput[i] = Dim{ std::string("s_") + fNOutput + "_" + std::to_string(i)};
0289 }
0290 }
0291 } else {
0292 throw std::runtime_error("TMVA Reshape Op 2nd input Tensor " + fNInput2 + " is not found in model");
0293 }
0294 } else if (!fAttrAxes.empty()) {
0295
0296 std::cout << "attribute axes exists\n";
0297 fShapeOutput = ShapeInference({fShapeInput})[0];
0298 } else if (fOpMode == Flatten || fOpMode == Squeeze) {
0299 fShapeOutput = ShapeInference({fShapeInput})[0];
0300 } else {
0301 throw std::runtime_error("TMVA Reshape Op : Invalid Input/Attribute data");
0302 }
0303
0304 if (model.IsInitializedTensor(fNData) && model.GetTensorType(fNData) == ETensorType::INT64) {
0305 fIsOutputConstant = true;
0306 auto inputData = static_cast<int64_t*>(model.GetInitializedTensorData(fNData).get());
0307 auto o_shape = ConvertShapeToInt(fShapeOutput);
0308 if (ConvertShapeToLength(ConvertShapeToInt(fShapeInput)) != ConvertShapeToLength(o_shape) )
0309 throw std::runtime_error("TMVA Reshape Op : Invalid Input/Output lengths");
0310 model.AddConstantTensor<int64_t>(fNOutput, o_shape, inputData);
0311 if (model.Verbose()) {
0312 std::cout << Name() << " : " << fNData << " " << ConvertDimShapeToString(fShapeInput) << " --> " << fNOutput << " (constant) " << ConvertDimShapeToString(fShapeOutput) << " : " <<
0313 ConvertValuesToString(ConvertShapeToLength(o_shape), inputData) << std::endl;
0314 }
0315 }
0316
0317 else if (model.IsShapeTensor(fNData) && fShapeOutput.size() <=1) {
0318 fIsOutputConstant = true;
0319 auto inputData = model.GetShapeTensorValues(fNData);
0320 model.AddShapeTensor(fNOutput, inputData);
0321 if (model.Verbose()) {
0322 std::cout << Name() << " : " << fNData << " " << ConvertDimShapeToString(fShapeInput) << " --> " << fNOutput << " (shape) " << ConvertDimShapeToString(fShapeOutput) << " : " <<
0323 ConvertDimShapeToString(inputData) << std::endl;
0324 }
0325 }
0326 else {
0327
0328 model.AddIntermediateTensor(fNOutput, model.GetTensorType(fNData), fShapeOutput);
0329 if (model.Verbose())
0330 std::cout << Name() << " : " << fNData << " " << ConvertDimShapeToString(fShapeInput) << " --> "<< fNOutput << " " << ConvertDimShapeToString(fShapeOutput) << std::endl;
0331 }
0332 }
0333
0334 std::string Generate(std::string opName) override {
0335 if (fIsOutputConstant) return "";
0336
0337 std::stringstream out;
0338 std::string opType = "Reshape";
0339 if (fOpMode == Flatten)
0340 opType = "Flatten";
0341 else if (fOpMode == Squeeze)
0342 opType = "Squeeze";
0343 else if (fOpMode == Unsqueeze)
0344 opType = "Unsquueze";
0345
0346 out << SP << "///--------" << opType << " operator " << opName << " --> " << ConvertDimShapeToString(fShapeOutput) << "\n";
0347
0348
0349
0350 if (fDynamicShape) {
0351 for (size_t i = 0; i < fShapeOutput.size(); i++) {
0352
0353 out << SP << "size_t " << fShapeOutput[i].param << " = " << "tensor_" << fNInput2 << "[" << i << "];\n";
0354 if (!fAllowZero)
0355 out << SP << "if (tensor_" << fNInput2 << "[" << i << "] <= 0 ) "
0356 << fShapeOutput[i].param << " = " << fShapeInput[i] << ";\n";
0357 }
0358 }
0359
0360
0361 auto lengthOut = ConvertDimShapeToLength(fShapeOutput);
0362 auto lengthIn = ConvertDimShapeToLength(fShapeInput);
0363 if (lengthOut != lengthIn) {
0364
0365 out << SP << "if (" << lengthOut << "!=" << lengthIn << ")\n";
0366 out << "throw std::runtime_error(\"TMVA SOFIE Reshape Op : output lengths is different than input one\");\n";
0367 }
0368
0369
0370 out << SP << "std::copy( tensor_" << fNData << ", tensor_" << fNData << " + " << lengthIn << ", " << "tensor_" << fNOutput
0371 << ");\n";
0372 return out.str();
0373 }
0374 };
0375
0376 }
0377 }
0378 }
0379
0380
0381 #endif