Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Tile.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_Tile
2#define TMVA_SOFIE_ROPERATOR_Tile
3
5#include "TMVA/ROperator.hxx"
6#include "TMVA/RModel.hxx"
7
8#include <sstream>
9
10namespace TMVA{
11namespace Experimental{
12namespace SOFIE{
13
14template <typename T>
16{
17
18private:
19
20 std::string fNRepeats;
21 std::string fNInput;
22 std::string fNY;
23 std::vector<Dim>fShapeInput;
24 std::vector<Dim> fShapeY;
25
26public:
28 ROperator_Tile(std::string nameRepeat, std::string nameInput, std::string nameY):
29 fNRepeats(UTILITY::Clean_name(nameRepeat)),fNInput(UTILITY::Clean_name(nameInput)), fNY(UTILITY::Clean_name(nameY)){
30 // the repeats tensor is only used at generation time, so it is not a runtime input
33 }
34
35 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override {
36 return input;
37 }
38
39 std::vector<Dim> DoShapeInference(const std::vector<Dim> & input, const std::vector<size_t> repeat) {
40 std::vector<Dim> ret = input;
41 for(size_t i=0; i < repeat.size(); i++) {
42 if (repeat[i] != 1) {
43 if (ret[i].isParam) {
44 // parenthesize in case the dimension is a compound expression (e.g. "bsize + 1")
45 ret[i] = Dim{ std::string("(" + ret[i].GetVal() + ")*" + std::to_string(repeat[i])), static_cast<size_t>(-1) };
46 } else {
47 ret[i]=Dim { ret[i].dim *repeat[i] };
48 }
49 }
50 }
51 return ret;
52 }
53
54 void Initialize(RModel& model) override {
55 //input must be a graph input, or already initialized intermediate tensor
56 if (model.CheckIfTensorAlreadyExist(fNInput) == false){
57 throw std::runtime_error("TMVA SOFIE Tile Op Input Tensor is not found in model");
58 }
59 if (model.CheckIfTensorAlreadyExist(fNRepeats) == false){
60 throw std::runtime_error("TMVA SOFIE Tile Op Input Tensor is not found in model");
61 }
63
64 // if repeats vector is not initialized we cannot deduce shape of output
65 // not support for time being this case
66 if (!model.IsInitializedTensor(fNRepeats)) {
67 throw std::runtime_error("TMVA SOFIE Tile Op: non-initialized repeats input is not supported");
68 }
69
70 // Retrieve the data pointer for the repeats tensor
72 // Cast the raw pointer to the appropriate type (size_t*)
73 auto repeats_data = static_cast<int64_t*>(repptr.get());
74 if (repeats_data == nullptr) {
75 throw std::runtime_error("Failed to retrieve the data for the repeats tensor.");
76 }
77 // Get the shape of the repeats tensor to determine the number of elements
79 // Ensure the repeats tensor is 1D and get the number of elements
80 if (repeats_shape.size() != 1) {
81 throw std::runtime_error("Repeats tensor is not 1D.");
82 }
83 size_t num_elements = repeats_shape[0];
84 // Convert the data to a vector of size_t
85 std::vector<size_t> repeats_vector(num_elements);
87
88
90
91 // the repeats are baked into the generated code, so the tensor is not
92 // needed at runtime and must not be written in the weight file
94
96
97 if (model.Verbose())
98 std::cout << "Tile: " << fNInput << " " << ConvertDimShapeToString(fShapeInput) << " -> " << fNY << " with shape " << ConvertDimShapeToString(fShapeY)
99 << " given repeats " << ConvertShapeToString(repeats_vector) << std::endl;
100 }
101
102 std::string Generate(std::string OpName) override {
103 OpName = "op_" + OpName;
104 if (fShapeInput.empty() || fShapeY.empty()) {
105 throw std::runtime_error("TMVA SOFIE Tile Op called to Generate without being initialized first");
106 }
107
108 std::stringstream out;
109 out << "///-------- Tile operator " << OpName << "\n";
110 out << "{\n";
111
112 const int rank = fShapeInput.size();
113
114 // shapes can contain dynamic (parametric) dimensions, so they are emitted
115 // as expressions evaluated at runtime in the generated code
116 out << SP << "const size_t input_shape[" << rank << "] = " << ConvertDimShapeToString(fShapeInput) << ";\n";
117 out << SP << "const size_t output_shape[" << rank << "] = " << ConvertDimShapeToString(fShapeY) << ";\n\n";
118
119 // Pre-calculating the input strides to find element positions (the output
120 // index just advances sequentially in the loop nest below).
121 out << SP << "size_t input_strides[" << rank << "];\n";
122 out << SP << "input_strides[" << rank - 1 << "] = 1;\n";
123 out << SP << "for (int i = " << rank - 2 << "; i >= 0; --i) {\n";
124 out << SP << SP << "input_strides[i] = input_strides[i+1] * input_shape[i+1];\n";
125 out << SP << "}\n\n";
126
127 // One loop per output axis: o<i> is the output coordinate and ic<i> the
128 // corresponding input coordinate, kept in sync via a wrap-around counter
129 // so no division or modulo is needed per element.
130 out << SP << "size_t out_idx = 0;\n";
131 std::string indent = SP;
132 for (int i = 0; i < rank; ++i) {
133 out << indent << "for (size_t o" << i << " = 0, ic" << i << " = 0; o" << i
134 << " < output_shape[" << i << "]; ++o" << i << ") {\n";
135 indent += SP;
136 out << indent << "const size_t in_off" << i << " = "
137 << (i == 0 ? std::string() : "in_off" + std::to_string(i - 1) + " + ")
138 << "ic" << i << " * input_strides[" << i << "];\n";
139 }
140 out << indent << "tensor_" << fNY << "[out_idx++] = tensor_" << fNInput << "[in_off" << rank - 1 << "];\n";
141 for (int i = rank - 1; i >= 0; --i) {
142 out << indent << "if (++ic" << i << " == input_shape[" << i << "]) ic" << i << " = 0;\n";
143 indent.resize(indent.size() - SP.size());
144 out << indent << "}\n";
145 }
146
147 out << "}\n"; // End of scope
148 return out.str();
149 }
150};
151
152}//SOFIE
153}//Experimental
154}//TMVA
155
156#endif //TMVA_SOFIE_ROPERATOR_Tile
static void indent(ostringstream &buf, int indent_level)
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
const_iterator begin() const
std::vector< size_t > GetTensorShape(const std::string &name) const
Definition RModel.cxx:64
std::vector< Dim > GetDimTensorShape(const std::string &name) const
Definition RModel.cxx:100
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:311
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:157
bool IsInitializedTensor(const std::string &name) const
Definition RModel.cxx:283
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition RModel.cxx:376
void SetNotWritableInitializedTensor(const std::string &tensor_name)
Definition RModel.cxx:385
ETensorType GetTensorType(std::string name) const
Definition RModel.cxx:125
ROperator_Tile(std::string nameRepeat, std::string nameInput, std::string nameY)
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
std::vector< Dim > DoShapeInference(const std::vector< Dim > &input, const std::vector< size_t > repeat)
std::string Generate(std::string OpName) override
void Initialize(RModel &model) override
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:50
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:45
std::vector< std::string_view > fOutputTensorNames
Definition ROperator.hxx:51
std::string ConvertDimShapeToString(const std::vector< Dim > &shape)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
create variable transformations