Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_InstanceNormalization.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_INSTANCENORMALIZATION
2#define TMVA_SOFIE_ROPERATOR_INSTANCENORMALIZATION
3
4#include "TMVA/ROperator.hxx"
5#include "TMVA/RModel.hxx"
7
8#include <sstream>
9#include <stdexcept>
10
11namespace TMVA {
12namespace Experimental {
13namespace SOFIE {
14
15/*! \class ROperator_InstanceNormalization
16 \brief Implementation of the ONNX InstanceNormalization operator.
17
18 The input X has shape (N, C, D1, ..., Dn). For every sample n and channel c,
19 the elements over the spatial dimensions D1, ..., Dn are normalized to zero
20 mean and unit variance, and then scaled and shifted with the per-channel
21 scale and B tensors, which both have shape (C):
22
23 Y[n, c, ...] = scale[c] * (X[n, c, ...] - mean[n, c]) / sqrt(var[n, c] + epsilon) + B[c]
24*/
25template <typename T>
27private:
28 float fEpsilon;
29 std::string fNInput;
30 std::string fNScale;
31 std::string fNBias;
32 std::string fNOutput;
33 std::vector<size_t> fShape;
34 std::string fType;
35
36public:
38
39 ROperator_InstanceNormalization(float epsilon, std::string nameInput, std::string nameScale, std::string nameBias,
40 std::string nameOutput)
41 : fEpsilon(epsilon),
42 fNInput(UTILITY::Clean_name(nameInput)),
43 fNScale(UTILITY::Clean_name(nameScale)),
44 fNBias(UTILITY::Clean_name(nameBias)),
45 fNOutput(UTILITY::Clean_name(nameOutput))
46 {
49 }
50
51 void Initialize(RModel &model) override
52 {
53 for (const std::string &name : {fNInput, fNScale, fNBias}) {
54 if (!model.CheckIfTensorAlreadyExist(name)) {
55 throw std::runtime_error("TMVA::SOFIE - InstanceNormalization - Tensor " + name + " not found.");
56 }
57 }
58
59 fShape = model.GetTensorShape(fNInput);
60 if (fShape.size() < 3) {
61 throw std::runtime_error("TMVA::SOFIE - InstanceNormalization - Input tensor " + fNInput + " has rank " +
62 std::to_string(fShape.size()) + " but at least rank 3 (N, C, D1, ...) is required.");
63 }
64
65 // scale and B are 1D tensors of length C
66 const size_t channels = fShape[1];
67 for (const std::string &name : {fNScale, fNBias}) {
68 auto shape = model.GetTensorShape(name);
69 if (shape.size() != 1 || shape[0] != channels) {
70 throw std::runtime_error("TMVA::SOFIE - InstanceNormalization - Tensor " + name + " has invalid shape " +
71 ConvertShapeToString(shape) + ", expected " +
72 ConvertShapeToString(std::vector<size_t>{channels}) + ".");
73 }
74 }
75
76 fType = ConvertTypeToString(model.GetTensorType(fNInput));
77 model.AddIntermediateTensor(fNOutput, model.GetTensorType(fNInput), fShape);
78 }
79
80 std::string Generate(std::string) override
81 {
82 if (fShape.empty()) {
83 throw std::runtime_error("TMVA::SOFIE - InstanceNormalization called to generate without being initialized.");
84 }
85
86 const size_t batchSize = fShape[0];
87 const size_t channels = fShape[1];
88 size_t spatialSize = 1;
89 for (size_t i = 2; i < fShape.size(); ++i)
90 spatialSize *= fShape[i];
91
92 std::stringstream out;
93 out << "\n" << SP << "//---- InstanceNormalization " << fNOutput << "\n";
94 out << SP << "for (size_t n = 0; n < " << batchSize << "; n++) {\n";
95 out << SP << SP << "for (size_t c = 0; c < " << channels << "; c++) {\n";
96 out << SP << SP << SP << "const size_t offset = n * " << channels * spatialSize << " + c * " << spatialSize
97 << ";\n";
98
99 // Compute the mean over the spatial dimensions
100 out << SP << SP << SP << fType << " mean = 0.;\n";
101 out << SP << SP << SP << "for (size_t i = 0; i < " << spatialSize << "; i++) {\n";
102 out << SP << SP << SP << SP << "mean += tensor_" << fNInput << "[offset + i];\n";
103 out << SP << SP << SP << "}\n";
104 out << SP << SP << SP << "mean /= " << fType << "(" << spatialSize << ");\n";
105
106 // Compute the inverse standard deviation from the deviations around the mean
107 out << SP << SP << SP << fType << " sum = 0.;\n";
108 out << SP << SP << SP << "for (size_t i = 0; i < " << spatialSize << "; i++) {\n";
109 out << SP << SP << SP << SP << fType << " tmp = tensor_" << fNInput << "[offset + i] - mean;\n";
110 out << SP << SP << SP << SP << "sum += tmp * tmp;\n";
111 out << SP << SP << SP << "}\n";
112 out << SP << SP << SP << fType << " invStdDev = 1 / std::sqrt(sum / " << fType << "(" << spatialSize << ") + "
113 << std::to_string(fEpsilon) << ");\n";
114
115 // Y = scale o invStdDev (X - mean) + B
116 out << SP << SP << SP << fType << " scale = tensor_" << fNScale << "[c];\n";
117 out << SP << SP << SP << fType << " bias = tensor_" << fNBias << "[c];\n";
118 out << SP << SP << SP << "for (size_t i = 0; i < " << spatialSize << "; i++) {\n";
119 out << SP << SP << SP << SP << "tensor_" << fNOutput << "[offset + i] = scale * (tensor_" << fNInput
120 << "[offset + i] - mean) * invStdDev + bias;\n";
121 out << SP << SP << SP << "}\n";
122
123 out << SP << SP << "}\n";
124 out << SP << "}\n";
125 return out.str();
126 }
127};
128
129} // namespace SOFIE
130} // namespace Experimental
131} // namespace TMVA
132#endif
#define e(i)
Definition RSha256.hxx:103
char name[80]
Definition TGX11.cxx:142
Implementation of the ONNX InstanceNormalization operator.
ROperator_InstanceNormalization(float epsilon, std::string nameInput, std::string nameScale, std::string nameBias, std::string nameOutput)
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:44
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:40
std::vector< std::string_view > fOutputTensorNames
Definition ROperator.hxx:45
std::string ConvertTypeToString(ETensorType type)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
create variable transformations