File indexing completed on 2026-08-14 09:29:39
0001 #ifndef TMVA_SOFIE_ROPERATOR_RNN
0002 #define TMVA_SOFIE_ROPERATOR_RNN
0003
0004 #include "TMVA/RModel.hxx"
0005 #include "TMVA/ROperator.hxx"
0006 #include "TMVA/SOFIE_common.hxx"
0007
0008 #include <memory>
0009 #include <sstream>
0010 #include <vector>
0011
0012 namespace TMVA::Experimental::SOFIE {
0013
0014
0015
0016
0017
0018
0019
0020 template <typename T> class ROperator_RNN final : public ROperator {
0021 private:
0022 std::vector<float> fAttrActivationAlpha;
0023 std::vector<float> fAttrActivationBeta;
0024 std::vector<std::string> fAttrActivations;
0025 float fAttrClip;
0026 std::string fAttrDirection;
0027 size_t fAttrHiddenSize;
0028 size_t fAttrLayout;
0029
0030 std::string fNX;
0031 std::string fNW;
0032 std::string fNR;
0033 std::string fNB;
0034 std::string fNSequence_lens;
0035 std::string fNInitial_h;
0036 std::string fNY;
0037 std::string fNY_h;
0038
0039 std::vector<size_t> fShapeX;
0040 std::vector<size_t> fShapeW;
0041 std::vector<size_t> fShapeR;
0042 std::vector<size_t> fShapeB;
0043 std::vector<size_t> fShapeSequence_lens;
0044 std::vector<size_t> fShapeInitial_h;
0045 std::vector<size_t> fShapeY;
0046 std::vector<size_t> fShapeY_h;
0047
0048 std::string fType;
0049
0050 public:
0051
0052 ROperator_RNN() {}
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072 ROperator_RNN(std::vector<float> activation_alpha,
0073 std::vector<float> activation_beta,
0074 std::vector<std::string> activations, float clip,
0075 std::string direction, size_t hidden_size, size_t layout,
0076 std::string nameX, std::string nameW, std::string nameR,
0077 std::string nameB, std::string nameSequence_lens,
0078 std::string nameInitial_h, std::string nameY,
0079 std::string nameY_h)
0080 : fAttrActivationAlpha(activation_alpha),
0081 fAttrActivationBeta(activation_beta), fAttrActivations(activations),
0082 fAttrClip(clip), fAttrDirection(direction),
0083 fAttrHiddenSize(hidden_size), fAttrLayout(layout),
0084 fNX(UTILITY::Clean_name(nameX)), fNW(UTILITY::Clean_name(nameW)),
0085 fNR(UTILITY::Clean_name(nameR)), fNB(UTILITY::Clean_name(nameB)),
0086 fNSequence_lens(UTILITY::Clean_name(nameSequence_lens)),
0087 fNInitial_h(UTILITY::Clean_name(nameInitial_h)),
0088 fNY(UTILITY::Clean_name(nameY)), fNY_h(UTILITY::Clean_name(nameY_h)) {
0089 if (std::is_same<T, float>::value) {
0090 fType = "float";
0091 } else {
0092 throw std::runtime_error(
0093 "TMVA SOFIE Encountered unsupported type parsing a RNN operator");
0094 }
0095
0096 fInputTensorNames = { fNX, fNW, fNR };
0097 if(!fNB.empty()){
0098 fInputTensorNames.emplace_back(fNB);
0099 }
0100 if(!fNSequence_lens.empty()){
0101 fInputTensorNames.emplace_back(fNSequence_lens);
0102 }
0103 if(!fNInitial_h.empty()){
0104 fInputTensorNames.emplace_back(fNInitial_h);
0105 }
0106
0107 fOutputTensorNames = { };
0108 if(!fNY.empty()){
0109 fOutputTensorNames.emplace_back(fNY);
0110 }
0111 if(!fNY_h.empty()){
0112 fOutputTensorNames.emplace_back(fNY_h);
0113 }
0114 }
0115
0116
0117
0118
0119
0120 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override;
0121
0122
0123
0124
0125
0126 std::vector<std::vector<size_t>>
0127 ShapeInference(std::vector<std::vector<size_t>> input) override;
0128
0129
0130
0131
0132
0133 void Initialize(RModel &) override;
0134
0135
0136
0137
0138
0139 std::string Generate(std::string OpName) override;
0140
0141
0142 std::string GenerateSessionMembersCode(std::string opName) override;
0143
0144
0145
0146 std::vector<std::string> GetBlasRoutines() override { return { std::string("Gemm"), std::string("Axpy") }; }
0147 };
0148
0149 template <typename T>
0150 auto ROperator_RNN<T>::TypeInference(std::vector<ETensorType> input) -> std::vector<ETensorType>
0151 {
0152 ETensorType out = input[0];
0153 return {out, out};
0154 }
0155
0156 template <typename T>
0157 auto ROperator_RNN<T>::ShapeInference(std::vector<std::vector<size_t>> input) -> std::vector<std::vector<size_t>>
0158 {
0159 size_t num_directions = input[1][0];
0160 size_t hidden_size = input[1][1];
0161 if (fAttrLayout == 0) {
0162 size_t seq_length = input[0][0];
0163 size_t batch_size = input[0][1];
0164 std::vector<std::vector<size_t>> ret(
0165 {{seq_length, num_directions, batch_size, hidden_size}, {num_directions, batch_size, hidden_size}});
0166 return ret;
0167 } else {
0168 size_t batch_size = input[0][0];
0169 size_t seq_length = input[0][1];
0170 std::vector<std::vector<size_t>> ret(
0171 {{batch_size, seq_length, num_directions, hidden_size}, {batch_size, num_directions, hidden_size}});
0172 return ret;
0173 }
0174 }
0175
0176 template <typename T>
0177 auto ROperator_RNN<T>::Initialize(RModel &model) -> void
0178 {
0179 fUseSession = model.UseSession();
0180
0181 if (!model.CheckIfTensorAlreadyExist(fNX)) {
0182 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNX + " is not found in model.");
0183 }
0184 fShapeX = model.GetTensorShape(fNX);
0185 if (fShapeX.size() != 3) {
0186 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNX + " is not of 3 dimensions.");
0187 }
0188 if (!model.CheckIfTensorAlreadyExist(fNW)) {
0189 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNW + " is not found in model.");
0190 }
0191 fShapeW = model.GetTensorShape(fNW);
0192 if (fShapeW.size() != 3) {
0193 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNW + " is not of 3 dimensions.");
0194 }
0195 if (!model.CheckIfTensorAlreadyExist(fNR)) {
0196 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNR + " is not found in model.");
0197 }
0198 fShapeR = model.GetTensorShape(fNR);
0199 if (fShapeR.size() != 3) {
0200 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNR + " is not of 3 dimensions.");
0201 }
0202 if (!fNB.empty()) {
0203 if (!model.CheckIfTensorAlreadyExist(fNB)) {
0204 throw std::runtime_error("TMVA SOFIE RNN op input tensor " + fNB + " is not found in model.");
0205 }
0206 fShapeB = model.GetTensorShape(fNB);
0207 if (fShapeB.size() != 2 && fShapeB.size() != 4) {
0208 throw std::runtime_error("TMVA SOFIE RNN op input tensor " + fNB + " is not of 2 or 4 dimensions.");
0209 }
0210 if (fShapeB.size() == 2) {
0211
0212 auto original_data = model.GetInitializedTensorData(fNB);
0213 size_t num_directions = fShapeW[0];
0214 size_t seq_length = (fAttrLayout == 0) ? fShapeX[0] : fShapeX[1];
0215 size_t batch_size = (fAttrLayout == 0) ? fShapeX[1] : fShapeX[0];
0216 if (fType == "float") {
0217 float *original_bias = static_cast<float *>(original_data.get());
0218 float *new_bias = new float[num_directions * seq_length * batch_size * fAttrHiddenSize];
0219 std::vector<float> sum(fAttrHiddenSize);
0220 for (size_t direction = 0; direction < num_directions; direction++) {
0221 for (size_t h = 0; h < fAttrHiddenSize; h++) {
0222 sum[h] = original_bias[direction * 2 * fAttrHiddenSize + h] +
0223 original_bias[(2 * direction + 1) * fAttrHiddenSize + h];
0224 }
0225 for (size_t seq = 0; seq < seq_length; seq++) {
0226 for (size_t batch = 0; batch < batch_size; batch++) {
0227 size_t bias_offset = direction * seq_length * batch_size * fAttrHiddenSize +
0228 seq * batch_size * fAttrHiddenSize + batch * fAttrHiddenSize;
0229 std::copy(sum.begin(), sum.end(), new_bias + bias_offset);
0230 }
0231 }
0232 }
0233 std::vector<size_t> new_bias_shape = {num_directions, seq_length, batch_size, fAttrHiddenSize};
0234 std::shared_ptr<void> new_bias_ptr(new_bias, std::default_delete<float[]>());
0235 model.UpdateInitializedTensor(fNB, model.GetTensorType(fNB), new_bias_shape, new_bias_ptr);
0236 fShapeB = model.GetTensorShape(fNB);
0237 }
0238 }
0239 }
0240 if (!fNSequence_lens.empty()) {
0241 if (!model.CheckIfTensorAlreadyExist(fNSequence_lens)) {
0242 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNSequence_lens + "is not found in model.");
0243 }
0244 fShapeSequence_lens = model.GetTensorShape(fNSequence_lens);
0245 if (fShapeSequence_lens.size() != 1) {
0246 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNSequence_lens + " is not of 1 dimension.");
0247 }
0248 }
0249 if (!fNInitial_h.empty()) {
0250 if (!model.CheckIfTensorAlreadyExist(fNInitial_h)) {
0251 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNInitial_h + " is not found in model.");
0252 }
0253 fShapeInitial_h = model.GetTensorShape(fNInitial_h);
0254 if (fShapeInitial_h.size() != 3) {
0255 throw std::runtime_error("TMVA SOFIE RNN Op input tensor " + fNInitial_h + " is not of 3 dimensions.");
0256 }
0257 }
0258 if (!fNY.empty()) {
0259 fShapeY = ShapeInference({fShapeX, fShapeW})[0];
0260 if (!model.CheckIfTensorAlreadyExist(fNY)) {
0261 model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY);
0262 }
0263 }
0264 if (!fNY_h.empty()) {
0265 fShapeY_h = ShapeInference({fShapeX, fShapeW})[1];
0266 if (!model.CheckIfTensorAlreadyExist(fNY_h)) {
0267 model.AddIntermediateTensor(fNY_h, model.GetTensorType(fNX), fShapeY_h);
0268 }
0269 }
0270
0271 for (auto &activation : fAttrActivations) {
0272 if (activation != "Relu" && activation != "Tanh" && activation != "Sigmoid" && activation != "Affine" &&
0273 activation != "LeakyRelu" && activation != "ThresholdRelu" && activation != "ScaledTanh" &&
0274 activation != "HardSigmoid" && activation != "Elu" && activation != "Softsign" && activation != "Softplus") {
0275 throw std::runtime_error("TMVA SOFIE - Activation function " + activation + " not implemented");
0276 }
0277 }
0278 if (fAttrDirection != "forward" && fAttrDirection != "backward" && fAttrDirection != "bidirectional") {
0279 throw std::runtime_error("TMVA SOFIE - Invalid RNN direction fAttrDirection = " + fAttrDirection);
0280 }
0281 if (fAttrHiddenSize != fShapeW[1]) {
0282 throw std::runtime_error("TMVA SOFIE - fAttrHiddenSize must be equal to " + std::to_string(fShapeW[1]));
0283 }
0284 if (fAttrLayout > 1) {
0285 throw std::runtime_error("TMVA SOFIE - Layout fAttrLayout = " + std::to_string(fAttrLayout) +
0286 " must be 0 (timewise) or 1 (batchwise)");
0287 }
0288 if (fAttrActivations.empty()) {
0289 if (fAttrDirection == "bidirectional") {
0290 fAttrActivations = {"Tanh", "Tanh"};
0291 } else {
0292 fAttrActivations = {"Tanh"};
0293 }
0294 }
0295
0296 model.AddNeededStdLib("cmath");
0297 }
0298
0299
0300 template <typename T>
0301 std::string ROperator_RNN<T>::GenerateSessionMembersCode(std::string opName)
0302 {
0303 opName = "op_" + opName;
0304 std::stringstream out;
0305
0306 size_t num_directions = fShapeW[0];
0307 size_t seq_length = (fAttrLayout == 0) ? fShapeX[0] : fShapeX[1];
0308 size_t batch_size = (fAttrLayout == 0) ? fShapeX[1] : fShapeX[0];
0309 size_t input_size = fShapeX[2];
0310
0311 struct Block {
0312 std::string name;
0313 size_t size;
0314 };
0315
0316 std::vector<Block> blocks;
0317
0318 if (fAttrLayout != 0) {
0319 blocks.push_back({"input", seq_length * batch_size * input_size});
0320 blocks.push_back({"initial_hidden_state", num_directions * batch_size * fAttrHiddenSize});
0321 }
0322 blocks.push_back({"feedforward", seq_length * batch_size * fAttrHiddenSize});
0323 if (fAttrLayout != 0 || fNY.empty()) {
0324 blocks.push_back({"hidden_state", seq_length * num_directions * batch_size * fAttrHiddenSize});
0325 }
0326
0327
0328 size_t total_size = 0;
0329 for (const auto &b : blocks) {
0330 total_size += b.size;
0331 }
0332
0333
0334 out << "std::vector<" << fType << "> fVec_" << opName << "_buffer = std::vector<" << fType << ">(" << total_size
0335 << ");\n";
0336
0337
0338 std::size_t offset = 0;
0339 for (const auto &b : blocks) {
0340 out << fType << "* fVec_" << opName << "_" << b.name << " = fVec_" << opName << "_buffer.data() + " << offset
0341 << ";\n";
0342 offset += b.size;
0343 }
0344
0345 out << "\n";
0346
0347 return out.str();
0348 }
0349
0350
0351 template <typename T>
0352 auto ROperator_RNN<T>::Generate(std::string OpName) -> std::string
0353 {
0354 OpName = "op_" + OpName;
0355 std::stringstream out;
0356
0357 size_t seq_length = (fAttrLayout == 0) ? fShapeX[0] : fShapeX[1];
0358 size_t batch_size = (fAttrLayout == 0) ? fShapeX[1] : fShapeX[0];
0359 size_t input_size = fShapeX[2];
0360 size_t num_directions = fShapeW[0];
0361
0362
0363 if (fAttrLayout == 0) {
0364 if (fType == "float") {
0365 out << SP << "float const*" << OpName << "_input = tensor_" << fNX << ";\n";
0366 }
0367 } else {
0368 if (fUseSession)
0369 out << SP << fType << " * " << OpName << "_input = this->fVec_" << OpName << "_input;\n";
0370 else
0371 out << SP << fType << " " << OpName << "_input[" << seq_length * batch_size * input_size << "];\n";
0372 out << SP << "for(size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
0373 out << SP << SP << "for(size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0374 out << SP << SP << SP << "for(size_t i = 0; i < " << input_size << "; i++) {\n";
0375 out << SP << SP << SP << SP << OpName << "_input[seq * " << batch_size * input_size << " + batch * " << input_size
0376 << " + i] = " << "tensor_" << fNX << "[batch * " << seq_length * input_size << " + seq * " << input_size
0377 << " + i];\n";
0378 out << SP << SP << SP << "}\n";
0379 out << SP << SP << "}\n";
0380 out << SP << "}\n";
0381 }
0382
0383
0384 if (!fNInitial_h.empty()) {
0385 if (fAttrLayout == 0) {
0386 out << SP << fType << " *" << OpName << "_initial_hidden_state = " << " tensor_" << fNInitial_h << ";\n";
0387 } else {
0388 if (fUseSession)
0389 out << SP << fType << " * " << OpName << "_initial_hidden_state = this->fVec_" << OpName
0390 << "_initial_hidden_state;\n";
0391 else
0392 out << fType << " " << OpName << "_initial_hidden_state[" << num_directions * batch_size * fAttrHiddenSize
0393 << "] = {0};\n";
0394
0395 for (size_t direction = 0; direction < num_directions; direction++) {
0396 out << SP << "for(size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0397 out << SP << SP << "for(size_t h = 0; h < " << fAttrHiddenSize << "; h++) {\n";
0398 out << SP << SP << SP << OpName << "_initial_hidden_state[" << direction * batch_size * fAttrHiddenSize
0399 << " + batch * " << fAttrHiddenSize << " + h] = tensor_" << fNInitial_h << "[batch * "
0400 << num_directions * fAttrHiddenSize << " + " << direction * fAttrHiddenSize << " + h];\n";
0401 out << SP << SP << "}\n";
0402 out << SP << "}\n";
0403 }
0404 }
0405 }
0406
0407 if (fUseSession)
0408 out << SP << fType << " * " << OpName << "_feedforward = this->fVec_" << OpName << "_feedforward;\n";
0409 else
0410 out << SP << fType << " " << OpName << "_feedforward[" << seq_length * batch_size * fAttrHiddenSize
0411 << "] = {0};\n";
0412
0413
0414 if (fAttrLayout == 0 && !fNY.empty()) {
0415 out << SP << fType << " *" << OpName << "_hidden_state = tensor_" << fNY << ";\n";
0416 } else {
0417 if (fUseSession)
0418 out << SP << fType << " * " << OpName << "_hidden_state = this->fVec_" << OpName << "_hidden_state;\n";
0419 else
0420 out << SP << fType << " " << OpName << "_hidden_state["
0421 << seq_length * num_directions * batch_size * fAttrHiddenSize << "] = {0};\n";
0422 }
0423
0424 out << SP << "char " << OpName << "_transA = 'N';\n";
0425 out << SP << "char " << OpName << "_transB = 'T';\n";
0426 out << SP << "int " << OpName << "_m = " << seq_length * batch_size << ";\n";
0427 out << SP << "int " << OpName << "_n = " << fAttrHiddenSize << ";\n";
0428 out << SP << "int " << OpName << "_k = " << input_size << ";\n";
0429 if (fType == "float") {
0430 out << SP << "float " << OpName << "_alpha = 1.;\n";
0431 out << SP << "float " << OpName << "_beta = .0;\n";
0432 }
0433 if (!fNB.empty()) {
0434 out << SP << "int " << OpName << "_bias_size = " << seq_length * batch_size * fAttrHiddenSize << ";\n";
0435 out << SP << "int " << OpName << "_incx = 1;\n";
0436 out << SP << "int " << OpName << "_incy = 1;\n";
0437 }
0438
0439 for (size_t direction = 0; direction < num_directions; direction++) {
0440
0441 if (fType == "float") {
0442 if (direction == 0) {
0443 out << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName << "_n, &"
0444 << OpName << "_m, &" << OpName << "_k, &" << OpName << "_alpha, tensor_" << fNW << ", &" << OpName
0445 << "_k, " << OpName << "_input, &" << OpName << "_k, &" << OpName << "_beta, " << OpName
0446 << "_feedforward, &" << OpName << "_n);\n";
0447 } else {
0448 out << SP << "size_t " << OpName << "_w_offset = " << fAttrHiddenSize * input_size << ";\n";
0449 out << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName << "_n, &"
0450 << OpName << "_m, &" << OpName << "_k, &" << OpName << "_alpha, tensor_" << fNW << " + " << OpName
0451 << "_w_offset, &" << OpName << "_k, " << OpName << "_input, &" << OpName << "_k, &" << OpName
0452 << "_beta, " << OpName << "_feedforward, &" << OpName << "_n);\n";
0453 }
0454 }
0455
0456 if (!fNB.empty()) {
0457 if (fType == "float") {
0458 if (direction == 0) {
0459 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB << ", &"
0460 << OpName << "_incx, " << OpName << "_feedforward, &" << OpName << "_incy);\n";
0461 } else {
0462 out << SP << "size_t " << OpName << "_bias_offset = " << seq_length * batch_size * fAttrHiddenSize
0463 << ";\n";
0464 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB << " + "
0465 << OpName << "_bias_offset, &" << OpName << "_incx, " << OpName << "_feedforward, &" << OpName
0466 << "_incy);\n";
0467 }
0468 }
0469 }
0470
0471
0472 out << SP << "for (size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
0473 out << SP << SP << "size_t offset = seq * " << batch_size * fAttrHiddenSize << ";\n";
0474 out << SP << SP << "size_t size = " << batch_size * fAttrHiddenSize << ";\n";
0475 out << SP << SP << "size_t h_offset = seq * " << num_directions * batch_size * fAttrHiddenSize << " + "
0476 << direction * batch_size * fAttrHiddenSize << ";\n";
0477 out << SP << SP << "std::copy(" << OpName << "_feedforward + offset, " << OpName
0478 << "_feedforward + offset + size, " << OpName << "_hidden_state + h_offset);\n";
0479 out << SP << "}\n";
0480
0481 out << SP << "for (size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
0482 if (fAttrDirection == "backward" || direction == 1) {
0483 out << SP << SP << "size_t index = " << seq_length - 1 << " - seq;\n";
0484 } else {
0485 out << SP << SP << "size_t index = seq;\n";
0486 }
0487
0488 out << SP << SP << "int m2 = " << batch_size << ";\n";
0489 out << SP << SP << "size_t offset = index * " << num_directions * batch_size * fAttrHiddenSize << " + "
0490 << direction * batch_size * fAttrHiddenSize << ";\n";
0491 out << SP << SP << "size_t size = " << batch_size * fAttrHiddenSize << ";\n";
0492 out << SP << SP << "if (seq == 0) {\n";
0493 if (!fNInitial_h.empty()) {
0494
0495 out << SP << SP << SP << "size_t r_offset = " << direction * fAttrHiddenSize * fAttrHiddenSize << ";\n";
0496 out << SP << SP << SP << "size_t initial_hidden_state_offset = " << direction * batch_size * fAttrHiddenSize
0497 << ";\n";
0498 if (fType == "float") {
0499 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0500 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + r_offset, &" << OpName
0501 << "_n, " << OpName << "_initial_hidden_state + initial_hidden_state_offset, &" << OpName << "_n, &"
0502 << OpName << "_alpha, " << OpName << "_hidden_state + offset, &" << OpName << "_n);\n";
0503 }
0504 }
0505 out << SP << SP << "} else {\n";
0506
0507 out << SP << SP << SP << "size_t r_offset = " << direction * fAttrHiddenSize * fAttrHiddenSize << ";\n";
0508 if (fAttrDirection == "backward" || direction == 1) {
0509 out << SP << SP << SP << "size_t previous_offset = (index + 1) * "
0510 << num_directions * batch_size * fAttrHiddenSize << " + " << direction * batch_size * fAttrHiddenSize
0511 << ";\n";
0512 } else {
0513 out << SP << SP << SP << "size_t previous_offset = (seq - 1) * "
0514 << num_directions * batch_size * fAttrHiddenSize << " + " << direction * batch_size * fAttrHiddenSize
0515 << ";\n";
0516 }
0517 if (fType == "float") {
0518 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0519 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + r_offset, &" << OpName
0520 << "_n, " << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &" << OpName << "_alpha, "
0521 << OpName << "_hidden_state + offset, &" << OpName << "_n);\n";
0522 }
0523 out << SP << SP << "}\n";
0524
0525
0526 if (fAttrClip > .0) {
0527 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0528 if (fType == "float") {
0529 out << SP << SP << SP << "float x = (" << OpName << "_hidden_state[i] > " << -fAttrClip << ") ? " << OpName
0530 << "_hidden_state[i] : " << -fAttrClip << ";\n";
0531 }
0532 out << SP << SP << SP << OpName << "_hidden_state[i] = (x < " << fAttrClip << ") ? x : " << fAttrClip << ";\n";
0533 out << SP << SP << "}\n";
0534 }
0535
0536
0537 if (fAttrActivations[direction] == "Relu") {
0538 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0539 out << SP << SP << SP << "if (" << OpName << "_hidden_state[i] < 0.)\n";
0540 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = 0.;\n";
0541 out << SP << SP << "}\n";
0542 } else if (fAttrActivations[direction] == "Tanh") {
0543 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0544 if (fType == "float") {
0545 out << SP << SP << SP << "float ex = std::exp(-2 * " << OpName << "_hidden_state[i]);\n";
0546 }
0547 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = (1. - ex) / (1. + ex);\n";
0548 out << SP << SP << "}\n";
0549 } else if (fAttrActivations[direction] == "Sigmoid") {
0550 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0551 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = 1. / (1. + std::exp(-" << OpName
0552 << "_hidden_state[i]));\n";
0553 out << SP << SP << "}\n";
0554 } else if (fAttrActivations[direction] == "Affine") {
0555 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0556 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = " << fAttrActivationAlpha[direction] << " * "
0557 << OpName << "_hidden_state[i] + " << fAttrActivationBeta[direction] << ";\n";
0558 out << SP << SP << "}\n";
0559 } else if (fAttrActivations[direction] == "ScaledTanh") {
0560 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0561 if (fType == "float") {
0562 out << SP << SP << SP << "float ex = std::exp(-2 * " << fAttrActivationBeta[direction] << " * " << OpName
0563 << "_hidden_state[i]);\n";
0564 }
0565 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = " << fAttrActivationAlpha[direction]
0566 << " * (1. - ex) / (1. + ex);\n";
0567 out << SP << SP << "}\n";
0568 } else if (fAttrActivations[direction] == "HardSigmoid") {
0569 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0570 if (fType == "float") {
0571 out << SP << SP << SP << "float a = " << fAttrActivationAlpha[direction] << " * " << OpName
0572 << "_hidden_state[i] + " << fAttrActivationBeta[direction] << ";\n";
0573 out << SP << SP << SP << "float b = (a > 0.) ? a : 0.;\n";
0574 }
0575 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = (b < 1.) ? b : 1.;\n";
0576 out << SP << SP << "}\n";
0577 } else if (fAttrActivations[direction] == "LeakyRelu") {
0578 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0579 out << SP << SP << SP << "if (" << OpName << "_hidden_state[i] < 0.)\n";
0580 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = " << fAttrActivationAlpha[direction] << " * "
0581 << OpName << "_hidden_state[i];\n";
0582 out << SP << SP << "}\n";
0583 } else if (fAttrActivations[direction] == "ThresholdRelu") {
0584 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0585 out << SP << SP << SP << "if (" << OpName << "_hidden_state[i] < " << fAttrActivationAlpha[direction] << ")\n";
0586 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = 0.;\n";
0587 out << SP << SP << "}";
0588 } else if (fAttrActivations[direction] == "Elu") {
0589 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0590 out << SP << SP << SP << "if (" << OpName << "_hidden_state[i] < 0.)\n";
0591 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = " << fAttrActivationAlpha[direction]
0592 << " * std::exp(" << OpName << "_hidden_state[i] - 1.);\n";
0593 out << SP << SP << "}\n";
0594 } else if (fAttrActivations[direction] == "Softsign") {
0595 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0596 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = " << OpName << "_hidden_state[i] / (1. + abs("
0597 << OpName << "_hidden_state[i]));\n";
0598 out << SP << SP << "}\n";
0599 } else {
0600 out << SP << SP << "for (size_t i = offset; i < offset + size; i++) {\n";
0601 out << SP << SP << SP << SP << OpName << "_hidden_state[i] = log(1. + std::exp(" << OpName
0602 << "_hidden_state[i]));\n";
0603 out << SP << SP << "}\n";
0604 out << SP << "}\n";
0605 }
0606 out << SP << "}\n";
0607 }
0608
0609
0610 if (!fNSequence_lens.empty()) {
0611 out << SP << "for (size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
0612 out << SP << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0613 out << SP << SP << SP << "if (seq >= tensor_" << fNSequence_lens << "[batch]) {\n";
0614 out << SP << SP << SP << SP << "for (size_t h = 0; h < " << fAttrHiddenSize << "; h++) {\n";
0615 if (num_directions == 1) {
0616 out << SP << SP << SP << SP << SP << OpName << "_hidden_state[seq * "
0617 << num_directions * batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize << " + h] = 0.;\n";
0618 } else {
0619 out << SP << SP << SP << SP << SP << OpName << "_hidden_state[seq * "
0620 << num_directions * batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize << " + h] = 0.;\n";
0621 out << SP << SP << SP << SP << SP << OpName << "_hidden_state[seq * "
0622 << num_directions * batch_size * fAttrHiddenSize << " + " << batch_size * fAttrHiddenSize << " + batch * "
0623 << fAttrHiddenSize << " + h] = 0.;\n";
0624 }
0625 out << SP << SP << SP << SP << "}\n";
0626 out << SP << SP << SP << "}\n";
0627 out << SP << SP << "}\n";
0628 out << SP << "}\n";
0629 }
0630
0631
0632 if (fAttrLayout == 0) {
0633 if (!fNY_h.empty()) {
0634 if (fNSequence_lens.empty()) {
0635 size_t yh_size = batch_size * fAttrHiddenSize;
0636 if (fAttrDirection == "backward") {
0637 out << SP << "std::copy(" << OpName << "_hidden_state, " << OpName << "_hidden_state + " << yh_size
0638 << ", tensor_" << fNY_h << ");\n";
0639 } else {
0640 size_t offset = (seq_length - 1) * num_directions * batch_size * fAttrHiddenSize;
0641 out << SP << "std::copy(" << OpName << "_hidden_state + " << offset << ", " << OpName
0642 << "_hidden_state + " << offset << " + " << yh_size << ", tensor_" << fNY_h << ");\n";
0643 }
0644 if (num_directions == 2) {
0645 out << SP << "std::copy(" << OpName << "_hidden_state + " << yh_size << ", " << OpName
0646 << "_hidden_state + " << 2 * yh_size << ", tensor_" << fNY_h << " + " << yh_size << ");\n";
0647 }
0648 } else {
0649 if (fAttrDirection == "backward") {
0650 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0651 out << SP << SP << "size_t offset = batch * " << fAttrHiddenSize << ";\n";
0652 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
0653 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + offset);\n";
0654 out << SP << "}\n";
0655 } else {
0656 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0657 out << SP << SP << "size_t seq = " << "tensor_" << fNSequence_lens << "[batch] - 1;\n";
0658 out << SP << SP << "size_t offset = seq * " << num_directions * batch_size * fAttrHiddenSize
0659 << " + batch * " << fAttrHiddenSize << ";\n";
0660 out << SP << SP << "size_t yh_offset = batch * " << fAttrHiddenSize << ";\n";
0661 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
0662 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + yh_offset);\n";
0663 out << SP << "}\n";
0664 }
0665 if (num_directions == 2) {
0666 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0667 out << SP << SP << "size_t offset = " << batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize
0668 << ";\n";
0669 out << SP << SP << "size_t yh_offset = " << batch_size * fAttrHiddenSize << " + batch * "
0670 << fAttrHiddenSize << ";\n";
0671 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
0672 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + yh_offset);\n";
0673 out << SP << "}\n";
0674 }
0675 }
0676 }
0677 } else {
0678 if (!fNY.empty()) {
0679 for (size_t direction = 0; direction < num_directions; direction++) {
0680 out << SP << "for (size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
0681 out << SP << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0682 out << SP << SP << SP << "size_t offset = seq * " << num_directions * batch_size * fAttrHiddenSize << " + "
0683 << direction * batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize << ";\n";
0684 out << SP << SP << SP << "size_t y_offset = batch * " << seq_length * num_directions * fAttrHiddenSize
0685 << " + seq * " << num_directions * fAttrHiddenSize << " + " << direction * fAttrHiddenSize << ";\n";
0686 out << SP << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
0687 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY << " + y_offset);\n";
0688 out << SP << SP << "}\n";
0689 out << SP << "}\n";
0690 }
0691 }
0692 if (!fNY_h.empty()) {
0693 if (fAttrDirection == "backward") {
0694 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0695 out << SP << SP << "size_t offset = batch * " << fAttrHiddenSize << ";\n";
0696 out << SP << SP << "size_t yh_offset = batch * " << num_directions * fAttrHiddenSize << ";\n";
0697 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
0698 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + yh_offset);\n";
0699 out << SP << "}\n";
0700 } else {
0701 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0702 if (fNSequence_lens.empty()) {
0703 out << SP << SP << "size_t seq = " << seq_length - 1 << ";\n";
0704 } else {
0705 out << SP << SP << "size_t seq = " << "tensor_" << fNSequence_lens << "[batch] - 1;\n";
0706 }
0707 out << SP << SP << "size_t offset = seq * " << num_directions * batch_size * fAttrHiddenSize
0708 << " + batch * " << fAttrHiddenSize << ";\n";
0709 out << SP << SP << "size_t yh_offset = batch * " << num_directions * fAttrHiddenSize << ";\n";
0710 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
0711 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + yh_offset);\n";
0712 out << SP << "}\n";
0713 }
0714 if (num_directions == 2) {
0715 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0716 out << SP << SP << "size_t offset = " << batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize
0717 << ";\n";
0718 out << SP << SP << "size_t yh_offset = batch * " << num_directions * fAttrHiddenSize << " + "
0719 << fAttrHiddenSize << ";\n";
0720 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
0721 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + yh_offset);\n";
0722 out << SP << "}\n";
0723 }
0724 }
0725 }
0726
0727 return out.str();
0728 }
0729
0730 }
0731
0732 #endif