File indexing completed on 2026-09-18 09:29:24
0001 #ifndef TMVA_SOFIE_ROPERATOR_LSTM
0002 #define TMVA_SOFIE_ROPERATOR_LSTM
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 <string>
0011 #include <vector>
0012
0013 namespace TMVA::Experimental::SOFIE {
0014
0015
0016
0017
0018
0019
0020
0021 template <typename T> class ROperator_LSTM final : public ROperator {
0022 private:
0023 std::vector<float> fAttrActivationAlpha;
0024 std::vector<float> fAttrActivationBeta;
0025 std::vector<std::string> fAttrActivations;
0026 float fAttrClip;
0027 std::string fAttrDirection;
0028 size_t fAttrHiddenSize;
0029 size_t fAttrInputForget;
0030 size_t fAttrLayout;
0031
0032 std::string fNX;
0033 std::string fNW;
0034 std::string fNR;
0035 std::string fNB;
0036 std::string fNSequence_lens;
0037 std::string fNInitial_h;
0038 std::string fNInitial_c;
0039 std::string fNP;
0040 std::string fNY;
0041 std::string fNY_h;
0042 std::string fNY_c;
0043
0044 std::vector<size_t> fShapeX;
0045 std::vector<size_t> fShapeW;
0046 std::vector<size_t> fShapeR;
0047 std::vector<size_t> fShapeB;
0048 std::vector<size_t> fShapeSequence_lens;
0049 std::vector<size_t> fShapeInitial_h;
0050 std::vector<size_t> fShapeInitial_c;
0051 std::vector<size_t> fShapeP;
0052 std::vector<size_t> fShapeY;
0053 std::vector<size_t> fShapeY_h;
0054 std::vector<size_t> fShapeY_c;
0055
0056 std::string fType;
0057
0058 public:
0059
0060 ROperator_LSTM() {}
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 ROperator_LSTM(std::vector<float> activation_alpha,
0085 std::vector<float> activation_beta,
0086 std::vector<std::string> activations, float clip,
0087 std::string direction, size_t hidden_size,
0088 size_t input_forget, size_t layout,
0089 std::string nameX, std::string nameW, std::string nameR,
0090 std::string nameB, std::string nameSequence_lens,
0091 std::string nameInitial_h, std::string nameInitial_c, std::string nameP,
0092 std::string nameY, std::string nameY_h, std::string nameY_c)
0093 : fAttrActivationAlpha(activation_alpha),
0094 fAttrActivationBeta(activation_beta), fAttrActivations(activations),
0095 fAttrClip(clip), fAttrDirection(direction), fAttrHiddenSize(hidden_size),
0096 fAttrInputForget(input_forget), fAttrLayout(layout),
0097 fNX(UTILITY::Clean_name(nameX)), fNW(UTILITY::Clean_name(nameW)),
0098 fNR(UTILITY::Clean_name(nameR)), fNB(UTILITY::Clean_name(nameB)),
0099 fNSequence_lens(UTILITY::Clean_name(nameSequence_lens)),
0100 fNInitial_h(UTILITY::Clean_name(nameInitial_h)),
0101 fNInitial_c(UTILITY::Clean_name(nameInitial_c)), fNP(UTILITY::Clean_name(nameP)),
0102 fNY(UTILITY::Clean_name(nameY)), fNY_h(UTILITY::Clean_name(nameY_h)),
0103 fNY_c(UTILITY::Clean_name(nameY_c)) {
0104 if (std::is_same<T, float>::value) {
0105 fType = "float";
0106 } else {
0107 throw std::runtime_error(
0108 "TMVA SOFIE Encountered unsupported type parsing a LSTM operator");
0109 }
0110
0111 fInputTensorNames = { fNX, fNW, fNR };
0112 if (!fNB.empty()){
0113 fInputTensorNames.emplace_back(fNB);
0114 }
0115 if (!fNSequence_lens.empty()){
0116 fInputTensorNames.emplace_back(fNSequence_lens);
0117 }
0118 if (!fNInitial_h.empty()){
0119 fInputTensorNames.emplace_back(fNInitial_h);
0120 }
0121 if (!fNInitial_c.empty()){
0122 fInputTensorNames.emplace_back(fNInitial_c);
0123 }
0124 if (!fNP.empty()){
0125 fInputTensorNames.emplace_back(fNP);
0126 }
0127
0128 fOutputTensorNames = { };
0129 if (!fNY.empty()){
0130 fOutputTensorNames.emplace_back(fNY);
0131 }
0132 if (!fNY_h.empty()){
0133 fOutputTensorNames.emplace_back(fNY_h);
0134 }
0135 if (!fNY_c.empty()){
0136 fOutputTensorNames.emplace_back(fNY_c);
0137 }
0138 }
0139
0140
0141
0142
0143
0144 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override;
0145
0146
0147
0148
0149
0150 std::vector<std::vector<size_t>>
0151 ShapeInference(std::vector<std::vector<size_t>> input) override;
0152
0153
0154
0155
0156
0157 void Initialize(RModel &) override;
0158
0159
0160
0161
0162
0163 std::string Generate(std::string OpName) override;
0164
0165
0166
0167
0168
0169 std::string GenerateSessionMembersCode(std::string opName) override;
0170
0171
0172
0173 std::vector<std::string> GetBlasRoutines() override { return { std::string("Gemm"), std::string("Axpy") }; }
0174 };
0175
0176 template <typename T>
0177 auto ROperator_LSTM<T>::TypeInference(std::vector<ETensorType> input) -> std::vector<ETensorType>
0178 {
0179 ETensorType out = input[0];
0180 return {out, out};
0181 }
0182
0183 template <typename T>
0184 auto ROperator_LSTM<T>::ShapeInference(std::vector<std::vector<size_t>> input) -> std::vector<std::vector<size_t>>
0185 {
0186 size_t num_directions = input[1][0];
0187 size_t hidden_size = input[1][1] / 4;
0188 if (fAttrLayout == 0) {
0189 size_t seq_length = input[0][0];
0190 size_t batch_size = input[0][1];
0191 std::vector<std::vector<size_t>> ret({{seq_length, num_directions, batch_size, hidden_size},
0192 {num_directions, batch_size, hidden_size},
0193 {num_directions, batch_size, hidden_size}});
0194 return ret;
0195 } else {
0196 size_t batch_size = input[0][0];
0197 size_t seq_length = input[0][1];
0198 std::vector<std::vector<size_t>> ret({{batch_size, seq_length, num_directions, hidden_size},
0199 {batch_size, num_directions, hidden_size},
0200 {batch_size, num_directions, hidden_size}});
0201 return ret;
0202 }
0203 }
0204
0205 template <typename T>
0206 auto ROperator_LSTM<T>::Initialize(RModel &model) -> void
0207 {
0208 fUseSession = model.UseSession();
0209
0210 if (!model.CheckIfTensorAlreadyExist(fNX)) {
0211 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNX + " is not found in model.");
0212 }
0213 fShapeX = model.GetTensorShape(fNX);
0214 if (fShapeX.size() != 3) {
0215 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNX + " is not of 3 dimensions.");
0216 }
0217 if (!model.CheckIfTensorAlreadyExist(fNW)) {
0218 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNW + " is not found in model.");
0219 }
0220 fShapeW = model.GetTensorShape(fNW);
0221 if (fShapeW.size() != 3) {
0222 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNW + " is not of 3 dimensions.");
0223 }
0224 if (!model.CheckIfTensorAlreadyExist(fNR)) {
0225 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNR + " is not found in model.");
0226 }
0227 fShapeR = model.GetTensorShape(fNR);
0228 if (fShapeR.size() != 3) {
0229 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNR + " is not of 3 dimensions.");
0230 }
0231 if (!fNB.empty()) {
0232 if (!model.CheckIfTensorAlreadyExist(fNB)) {
0233 throw std::runtime_error("TMVA SOFIE LSTM op input tensor " + fNB + " is not found in model.");
0234 }
0235 fShapeB = model.GetTensorShape(fNB);
0236 if (fShapeB.size() != 2 && fShapeB.size() != 5) {
0237 throw std::runtime_error("TMVA SOFIE LSTM op input tensor " + fNB + " is not of 2 or 5 dimensions.");
0238 }
0239 if (fShapeB.size() == 2) {
0240
0241 auto original_data = model.GetInitializedTensorData(fNB);
0242 size_t num_directions = fShapeW[0];
0243 size_t seq_length = (fAttrLayout == 0) ? fShapeX[0] : fShapeX[1];
0244 size_t batch_size = (fAttrLayout == 0) ? fShapeX[1] : fShapeX[0];
0245 if (fType == "float") {
0246 float *original_bias = static_cast<float *>(original_data.get());
0247 float *new_bias = new float[4 * num_directions * seq_length * batch_size * fAttrHiddenSize];
0248 for (size_t gate = 0; gate < 4; gate++) {
0249 std::vector<float> sum(fAttrHiddenSize);
0250 for (size_t direction = 0; direction < num_directions; direction++) {
0251 size_t offset = direction * 8 * fAttrHiddenSize + gate * fAttrHiddenSize;
0252 for (size_t h = 0; h < fAttrHiddenSize; h++) {
0253 sum[h] = original_bias[offset + h] + original_bias[offset + h + 4 * fAttrHiddenSize];
0254 }
0255 for (size_t seq = 0; seq < seq_length; seq++) {
0256 for (size_t batch = 0; batch < batch_size; batch++) {
0257 size_t bias_offset = gate * num_directions * seq_length * batch_size * fAttrHiddenSize +
0258 direction * seq_length * batch_size * fAttrHiddenSize +
0259 seq * batch_size * fAttrHiddenSize + batch * fAttrHiddenSize;
0260 std::copy(sum.begin(), sum.end(), new_bias + bias_offset);
0261 }
0262 }
0263 }
0264 }
0265 std::vector<size_t> new_bias_shape = {4, num_directions, seq_length, batch_size, fAttrHiddenSize};
0266 std::shared_ptr<void> new_bias_ptr(new_bias, std::default_delete<float[]>());
0267 model.UpdateInitializedTensor(fNB, model.GetTensorType(fNB), new_bias_shape, new_bias_ptr);
0268 fShapeB = model.GetTensorShape(fNB);
0269 }
0270 }
0271 }
0272 if (!fNSequence_lens.empty()) {
0273 if (!model.CheckIfTensorAlreadyExist(fNSequence_lens)) {
0274 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNSequence_lens + "is not found in model.");
0275 }
0276 fShapeSequence_lens = model.GetTensorShape(fNSequence_lens);
0277 if (fShapeSequence_lens.size() != 1) {
0278 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNSequence_lens + " is not of 1 dimension.");
0279 }
0280 }
0281 if (!fNInitial_h.empty()) {
0282 if (!model.CheckIfTensorAlreadyExist(fNInitial_h)) {
0283 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNInitial_h + " is not found in model.");
0284 }
0285 fShapeInitial_h = model.GetTensorShape(fNInitial_h);
0286 if (fShapeInitial_h.size() != 3) {
0287 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNInitial_h + " is not of 3 dimensions.");
0288 }
0289 }
0290 if (!fNInitial_c.empty()) {
0291 if (!model.CheckIfTensorAlreadyExist(fNInitial_c)) {
0292 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNInitial_c + " is not found in model.");
0293 }
0294 fShapeInitial_c = model.GetTensorShape(fNInitial_c);
0295 if (fShapeInitial_c.size() != 3) {
0296 throw std::runtime_error("TMVA SOFIE LSTM Op input tensor " + fNInitial_c + " is not of 3 dimensions.");
0297 }
0298 }
0299 if (!fNP.empty()) {
0300 if (!model.CheckIfTensorAlreadyExist(fNP)) {
0301 throw std::runtime_error("TMVA SOFIE LSTM op input tensor " + fNP + " is not found in model.");
0302 }
0303 fShapeP = model.GetTensorShape(fNP);
0304 if (fShapeP.size() != 2 && fShapeP.size() != 4) {
0305 throw std::runtime_error("TMVA SOFIE LSTM op input tensor " + fNP + " is not of 2 or 4 dimensions.");
0306 }
0307 if (fShapeP.size() == 2) {
0308
0309 auto original_data = model.GetInitializedTensorData(fNP);
0310 size_t num_directions = fShapeW[0];
0311 size_t batch_size = (fAttrLayout == 0) ? fShapeX[1] : fShapeX[0];
0312 if (fType == "float") {
0313 float *original_p = static_cast<float *>(original_data.get());
0314 float *new_p = new float[num_directions * 3 * batch_size * fAttrHiddenSize];
0315 for (size_t direction = 0; direction < num_directions; direction++) {
0316 for (size_t gate = 0; gate < 3; gate++) {
0317 size_t p_offset = direction * 3 * fAttrHiddenSize + gate * fAttrHiddenSize;
0318 for (size_t batch = 0; batch < batch_size; batch++) {
0319 size_t offset = direction * 3 * batch_size * fAttrHiddenSize +
0320 gate * batch_size * fAttrHiddenSize + batch * fAttrHiddenSize;
0321 std::copy(original_p + p_offset, original_p + p_offset + fAttrHiddenSize, new_p + offset);
0322 }
0323 }
0324 }
0325 std::vector<size_t> new_p_shape = {num_directions, 3, batch_size, fAttrHiddenSize};
0326 std::shared_ptr<void> new_p_ptr(new_p, std::default_delete<float[]>());
0327 model.UpdateInitializedTensor(fNP, model.GetTensorType(fNP), new_p_shape, new_p_ptr);
0328 fShapeP = model.GetTensorShape(fNP);
0329 }
0330 }
0331 }
0332 if (!fNY.empty()) {
0333 fShapeY = ShapeInference({fShapeX, fShapeW})[0];
0334 if (!model.CheckIfTensorAlreadyExist(fNY)) {
0335 model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShapeY);
0336 }
0337 }
0338 if (!fNY_h.empty()) {
0339 fShapeY_h = ShapeInference({fShapeX, fShapeW})[1];
0340 if (!model.CheckIfTensorAlreadyExist(fNY_h)) {
0341 model.AddIntermediateTensor(fNY_h, model.GetTensorType(fNX), fShapeY_h);
0342 }
0343 }
0344 if (!fNY_c.empty()) {
0345 fShapeY_c = ShapeInference({fShapeX, fShapeW})[2];
0346 if (!model.CheckIfTensorAlreadyExist(fNY_c)) {
0347 model.AddIntermediateTensor(fNY_c, model.GetTensorType(fNX), fShapeY_c);
0348 }
0349 }
0350
0351 for (auto &activation : fAttrActivations) {
0352 if (activation != "Relu" && activation != "Tanh" && activation != "Sigmoid" && activation != "Affine" &&
0353 activation != "LeakyRelu" && activation != "ThresholdRelu" && activation != "ScaledTanh" &&
0354 activation != "HardSigmoid" && activation != "Elu" && activation != "Softsign" && activation != "Softplus") {
0355 throw std::runtime_error("TMVA SOFIE - Activation function " + activation + " not implemented");
0356 }
0357 }
0358 if (fAttrDirection != "forward" && fAttrDirection != "backward" && fAttrDirection != "bidirectional") {
0359 throw std::runtime_error("TMVA SOFIE - Invalid LSTM direction fAttrDirection = " + fAttrDirection);
0360 }
0361 if (4 * fAttrHiddenSize != fShapeW[1]) {
0362 throw std::runtime_error("TMVA SOFIE - fAttrHiddenSize must be equal to " + std::to_string(fShapeW[1] / 4));
0363 }
0364 if (fAttrInputForget > 1) {
0365 throw std::runtime_error("TMVA SOFIE - fAttrInputForget = " + std::to_string(fAttrInputForget) +
0366 " must be 0 or 1.");
0367 }
0368 if (fAttrLayout > 1) {
0369 throw std::runtime_error("TMVA SOFIE - Layout fAttrLayout = " + std::to_string(fAttrLayout) +
0370 " must be 0 (timewise) or 1 (batchwise)");
0371 }
0372 if (fAttrActivations.empty()) {
0373 if (fAttrDirection == "bidirectional") {
0374 fAttrActivations = {"Sigmoid", "Tanh", "Tanh", "Sigmoid", "Tanh", "Tanh"};
0375 } else {
0376 fAttrActivations = {"Sigmoid", "Tanh", "Tanh"};
0377 }
0378 }
0379 }
0380
0381
0382 template <typename T>
0383 std::string ROperator_LSTM<T>::GenerateSessionMembersCode(std::string opName)
0384 {
0385 opName = "op_" + opName;
0386 std::stringstream out;
0387
0388 size_t num_directions = fShapeW[0];
0389 size_t seq_length = (fAttrLayout == 0) ? fShapeX[0] : fShapeX[1];
0390 size_t batch_size = (fAttrLayout == 0) ? fShapeX[1] : fShapeX[0];
0391 size_t input_size = fShapeX[2];
0392
0393 struct Block {
0394 std::string name;
0395 size_t size;
0396 };
0397
0398 std::vector<Block> blocks;
0399
0400 size_t ff_size = seq_length * batch_size * fAttrHiddenSize;
0401 size_t hs_size = seq_length * num_directions * batch_size * fAttrHiddenSize;
0402
0403
0404 if (fAttrLayout != 0) {
0405 blocks.push_back({"input", seq_length * batch_size * input_size});
0406 blocks.push_back({"initial_hidden_state", num_directions * batch_size * fAttrHiddenSize});
0407 blocks.push_back({"initial_cell_state", num_directions * batch_size * fAttrHiddenSize});
0408 }
0409
0410
0411 blocks.push_back({"ff_input_gate", ff_size});
0412 blocks.push_back({"ff_output_gate", ff_size});
0413 blocks.push_back({"ff_cell_gate", ff_size});
0414 if (fAttrInputForget == 0)
0415 blocks.push_back({"ff_forget_gate", ff_size});
0416
0417
0418 blocks.push_back({"input_gate", hs_size});
0419 blocks.push_back({"output_gate", hs_size});
0420 blocks.push_back({"cell_gate", hs_size});
0421 if (fAttrInputForget == 0)
0422 blocks.push_back({"forget_gate", hs_size});
0423
0424
0425 blocks.push_back({"cell_state", hs_size});
0426 blocks.push_back({"new_cell_state", hs_size});
0427
0428
0429 if (fAttrLayout != 0 || fNY.empty()) {
0430 blocks.push_back({"hidden_state", hs_size});
0431 }
0432
0433
0434 size_t total_size = 0;
0435 for (const auto &b : blocks) {
0436 total_size += b.size;
0437 }
0438
0439
0440 out << "std::vector<" << fType << "> fVec_" << opName << "_buffer = std::vector<" << fType << ">(" << total_size
0441 << ");\n";
0442
0443
0444 std::size_t offset = 0;
0445 for (const auto &b : blocks) {
0446 out << fType << "* fVec_" << opName << "_" << b.name << " = fVec_" << opName << "_buffer.data() + " << offset
0447 << ";\n";
0448 offset += b.size;
0449 }
0450
0451 out << "\n";
0452
0453 return out.str();
0454 }
0455
0456 template <typename T>
0457 auto ROperator_LSTM<T>::Generate(std::string OpName) -> std::string
0458 {
0459 OpName = "op_" + OpName;
0460 std::stringstream out;
0461
0462 size_t seq_length = (fAttrLayout == 0) ? fShapeX[0] : fShapeX[1];
0463 size_t batch_size = (fAttrLayout == 0) ? fShapeX[1] : fShapeX[0];
0464 size_t input_size = fShapeX[2];
0465 size_t num_directions = fShapeW[0];
0466
0467
0468 if (fAttrLayout == 0) {
0469 out << SP << fType << " const *" << OpName << "_input = tensor_" << fNX << ";\n";
0470 } else {
0471 if (fUseSession)
0472 out << SP << fType << " * " << OpName << "_input = this->fVec_" << OpName << "_input;\n";
0473 else
0474 out << SP << fType << " " << OpName << "_input[" << seq_length * batch_size * input_size << "] = {0};\n";
0475
0476 out << SP << "for(size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
0477 out << SP << SP << "for(size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0478 out << SP << SP << SP << "for(size_t i = 0; i < " << input_size << "; i++) {\n";
0479 out << SP << SP << SP << SP << OpName << "_input[seq * " << batch_size * input_size << " + batch * " << input_size
0480 << " + i] = " << "tensor_" << fNX << "[batch * " << seq_length * input_size << " + seq * " << input_size
0481 << " + i];\n";
0482 out << SP << SP << SP << "}\n";
0483 out << SP << SP << "}\n";
0484 out << SP << "}\n";
0485 }
0486
0487
0488 if (!fNInitial_h.empty()) {
0489 if (fAttrLayout == 0) {
0490 out << SP << fType << " const*" << OpName << "_initial_hidden_state = " << " tensor_" << fNInitial_h << ";\n";
0491 } else {
0492 if (fUseSession)
0493 out << SP << fType << " const* " << OpName << "_initial_hidden_state = this->fVec_" << OpName
0494 << "_initial_hidden_state;\n";
0495 else
0496 out << SP << fType << " " << OpName << "_initial_hidden_state["
0497 << num_directions * batch_size * fAttrHiddenSize << "] = {0};\n";
0498
0499 for (size_t direction = 0; direction < num_directions; direction++) {
0500 out << SP << "for(size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0501 out << SP << SP << "for(size_t h = 0; h < " << fAttrHiddenSize << "; h++) {\n";
0502 out << SP << SP << SP << OpName << "_initial_hidden_state[" << direction * batch_size * fAttrHiddenSize
0503 << " + batch * " << fAttrHiddenSize << " + h] = tensor_" << fNInitial_h << "[batch * "
0504 << num_directions * fAttrHiddenSize << " + " << direction * fAttrHiddenSize << " + h];\n";
0505 out << SP << SP << "}\n";
0506 out << SP << "}\n";
0507 }
0508 }
0509 }
0510
0511
0512 if (!fNInitial_c.empty()) {
0513 if (fAttrLayout == 0) {
0514 out << SP << fType << " const*" << OpName << "_initial_cell_state = " << " tensor_" << fNInitial_c << ";\n";
0515 } else {
0516 if (fUseSession)
0517 out << SP << fType << " const* " << OpName << "_initial_cell_state = this->fVec_" << OpName
0518 << "_initial_cell_state;\n";
0519 else
0520 out << SP << fType << " " << OpName << "_initial_cell_state["
0521 << num_directions * batch_size * fAttrHiddenSize << "] = {0};\n";
0522
0523 for (size_t direction = 0; direction < num_directions; direction++) {
0524 out << SP << "for(size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
0525 out << SP << SP << "for(size_t h = 0; h < " << fAttrHiddenSize << "; h++) {\n";
0526 out << SP << SP << SP << OpName << "_initial_cell_state[" << direction * batch_size * fAttrHiddenSize
0527 << " + batch * " << fAttrHiddenSize << " + h] = tensor_" << fNInitial_c << "[batch * "
0528 << num_directions * fAttrHiddenSize << " + " << direction * fAttrHiddenSize << " + h];\n";
0529 out << SP << SP << "}\n";
0530 out << SP << "}\n";
0531 }
0532 }
0533 }
0534
0535
0536 size_t ff_size = seq_length * batch_size * fAttrHiddenSize;
0537 if (fUseSession) {
0538 out << SP << fType << " * " << OpName << "_ff_input_gate = this->fVec_" << OpName << "_ff_input_gate;\n";
0539 out << SP << fType << " * " << OpName << "_ff_output_gate = this->fVec_" << OpName << "_ff_output_gate;\n";
0540 out << SP << fType << " * " << OpName << "_ff_cell_gate = this->fVec_" << OpName << "_ff_cell_gate;\n";
0541 if (fAttrInputForget == 0) {
0542 out << SP << fType << " * " << OpName << "_ff_forget_gate = this->fVec_" << OpName
0543 << "_ff_forget_gate;\n";
0544 }
0545 } else {
0546 out << SP << fType << " " << OpName << "_ff_input_gate[" << ff_size << "] = {0};\n";
0547 out << SP << fType << " " << OpName << "_ff_output_gate[" << ff_size << "] = {0};\n";
0548 out << SP << fType << " " << OpName << "_ff_cell_gate[" << ff_size << "] = {0};\n";
0549 if (fAttrInputForget == 0) {
0550 out << SP << fType << " " << OpName << "_ff_forget_gate[" << ff_size << "] = {0};\n";
0551 }
0552 }
0553
0554 size_t hidden_state_size = seq_length * num_directions * batch_size * fAttrHiddenSize;
0555 if (fUseSession) {
0556 out << SP << fType << " * " << OpName << "_input_gate = this->fVec_" << OpName << "_input_gate;\n";
0557 out << SP << fType << " * " << OpName << "_output_gate = this->fVec_" << OpName << "_output_gate;\n";
0558 out << SP << fType << " * " << OpName << "_cell_gate = this->fVec_" << OpName << "_cell_gate;\n";
0559 if (fAttrInputForget == 0) {
0560 out << SP << fType << " * " << OpName << "_forget_gate = this->fVec_" << OpName << "_forget_gate;\n";
0561 }
0562 } else {
0563 out << SP << fType << " " << OpName << "_input_gate[" << hidden_state_size << "] = {0};\n";
0564 out << SP << fType << " " << OpName << "_output_gate[" << hidden_state_size << "] = {0};\n";
0565 out << SP << fType << " " << OpName << "_cell_gate[" << hidden_state_size << "] = {0};\n";
0566 if (fAttrInputForget == 0) {
0567 out << SP << fType << " " << OpName << "_forget_gate[" << hidden_state_size << "] = {0};\n";
0568 }
0569 }
0570
0571 if (fUseSession) {
0572 out << SP << fType << " * " << OpName << "_cell_state = this->fVec_" << OpName << "_cell_state;\n";
0573 out << SP << fType << " * " << OpName << "_new_cell_state = this->fVec_" << OpName << "_new_cell_state;\n";
0574 } else {
0575 out << SP << fType << " " << OpName << "_cell_state[" << hidden_state_size << "] = {0};\n";
0576 out << SP << fType << " " << OpName << "_new_cell_state[" << hidden_state_size << "] = {0};\n";
0577 }
0578
0579
0580 if (fAttrLayout == 0 && !fNY.empty()) {
0581 out << SP << fType << " *" << OpName << "_hidden_state = tensor_" << fNY << ";\n";
0582 } else {
0583 if (fUseSession) {
0584 out << SP << fType << " * " << OpName << "_hidden_state = this->fVec_" << OpName << "_hidden_state;\n";
0585 } else {
0586 out << SP << fType << " " << OpName << "_hidden_state[" << hidden_state_size << "] = {0};\n";
0587 }
0588 }
0589
0590 out << SP << "char " << OpName << "_transA = 'N';\n";
0591 out << SP << "char " << OpName << "_transB = 'T';\n";
0592 out << SP << "int " << OpName << "_m = " << seq_length * batch_size << ";\n";
0593 out << SP << "int " << OpName << "_n = " << fAttrHiddenSize << ";\n";
0594 out << SP << "int " << OpName << "_k = " << input_size << ";\n";
0595 if (fType == "float") {
0596 out << SP << fType << " " << OpName << "_alpha = 1.;\n";
0597 out << SP << fType << " " << OpName << "_beta = 0.;\n";
0598 }
0599 if (!fNB.empty()) {
0600 out << SP << "int " << OpName << "_bias_size = " << seq_length * batch_size * fAttrHiddenSize << ";\n";
0601 out << SP << "int " << OpName << "_incx = 1;\n";
0602 out << SP << "int " << OpName << "_incy = 1;\n";
0603 }
0604
0605 auto emit_sgemm = [&](const std::string &out_name, size_t offset) -> std::string {
0606 std::stringstream ss;
0607 ss << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName << "_n, &" << OpName
0608 << "_m, &" << OpName << "_k, &" << OpName << "_alpha, tensor_" << fNW;
0609
0610 if (offset != 0)
0611 ss << " + " << offset;
0612
0613 ss << ", &" << OpName << "_k, " << OpName << "_input, &" << OpName << "_k, &" << OpName << "_beta, " << OpName
0614 << "_" << out_name << ", &" << OpName << "_n);\n";
0615 return ss.str();
0616 };
0617
0618 for (size_t direction = 0; direction < num_directions; direction++) {
0619 if (direction == 0) {
0620 if (fType == "float") {
0621
0622 out << SP << emit_sgemm("ff_input_gate", 0);
0623
0624 size_t wo_offset = fAttrHiddenSize * input_size;
0625 out << SP << emit_sgemm("ff_output_gate", wo_offset);
0626
0627 size_t wc_offset = 3 * fAttrHiddenSize * input_size;
0628 out << SP << emit_sgemm("ff_cell_gate", wc_offset);
0629 }
0630 } else {
0631 if (fType == "float") {
0632
0633 out << SP << emit_sgemm("ff_input_gate", 4 * fAttrHiddenSize * input_size);
0634
0635 size_t wo_offset = 4 * fAttrHiddenSize * input_size + 1 * fAttrHiddenSize * input_size;
0636 out << SP << emit_sgemm("ff_output_gate", wo_offset);
0637
0638 size_t wc_offset = 4 * fAttrHiddenSize * input_size + 3 * fAttrHiddenSize * input_size;
0639 out << SP << emit_sgemm("ff_cell_gate", wc_offset);
0640 }
0641 }
0642 if (fAttrInputForget == 0) {
0643
0644 if (direction == 0) {
0645 if (fType == "float") {
0646 size_t wf_offset = 2 * fAttrHiddenSize * input_size;
0647 out << SP << emit_sgemm("ff_forget_gate", wf_offset);
0648 }
0649 } else {
0650 if (fType == "float") {
0651 size_t wf_offset = 4 * fAttrHiddenSize * input_size + 2 * fAttrHiddenSize * input_size;
0652 out << SP << emit_sgemm("ff_forget_gate", wf_offset);
0653 }
0654 }
0655 }
0656
0657
0658 if (!fNB.empty()) {
0659 if (direction == 0) {
0660 if (fType == "float") {
0661
0662 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB << ", &"
0663 << OpName << "_incx, " << OpName << "_ff_input_gate, &" << OpName << "_incy);\n";
0664
0665 size_t bo_offset = seq_length * batch_size * fAttrHiddenSize;
0666 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB << " + "
0667 << bo_offset << ", &" << OpName << "_incx, " << OpName << "_ff_output_gate, &" << OpName
0668 << "_incy);\n";
0669
0670 size_t bc_offset = 3 * seq_length * batch_size * fAttrHiddenSize;
0671 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB << " + "
0672 << bc_offset << ", &" << OpName << "_incx, " << OpName << "_ff_cell_gate, &" << OpName
0673 << "_incy);\n";
0674 }
0675 } else {
0676 if (fType == "float") {
0677
0678 size_t bi_offset = 4 * seq_length * batch_size * fAttrHiddenSize;
0679 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB << " + "
0680 << bi_offset << ", &" << OpName << "_incx, " << OpName << "_ff_input_gate, &" << OpName
0681 << "_incy);\n";
0682
0683 size_t bo_offset =
0684 4 * seq_length * batch_size * fAttrHiddenSize + seq_length * batch_size * fAttrHiddenSize;
0685 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB << " + "
0686 << bo_offset << ", &" << OpName << "_incx, " << OpName << "_ff_output_gate, &" << OpName
0687 << "_incy);\n";
0688
0689 size_t bc_offset = 4 * num_directions * seq_length * batch_size * fAttrHiddenSize +
0690 3 * seq_length * batch_size * fAttrHiddenSize;
0691 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB << " + "
0692 << bc_offset << ", &" << OpName << "_incx, " << OpName << "_ff_cell_gate, &" << OpName
0693 << "_incy);\n";
0694 }
0695 }
0696 if (fAttrInputForget == 0) {
0697
0698 if (direction == 0) {
0699 if (fType == "float") {
0700 size_t bo_offset = 2 * seq_length * batch_size * fAttrHiddenSize;
0701 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB
0702 << " + " << bo_offset << ", &" << OpName << "_incx, " << OpName << "_ff_forget_gate, &" << OpName
0703 << "_incy);\n";
0704 }
0705 } else {
0706 if (fType == "float") {
0707 size_t bo_offset =
0708 4 * seq_length * batch_size * fAttrHiddenSize + 2 * seq_length * batch_size * fAttrHiddenSize;
0709 out << SP << "BLAS::saxpy_(&" << OpName << "_bias_size, &" << OpName << "_alpha, tensor_" << fNB
0710 << " + " << bo_offset << ", &" << OpName << "_incx, " << OpName << "_ff_forget_gate, &" << OpName
0711 << "_incy);\n";
0712 }
0713 }
0714 }
0715 }
0716
0717
0718
0719 out << SP << "for (size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
0720 out << SP << SP << "size_t ff_offset = seq * " << batch_size * fAttrHiddenSize << ";\n";
0721 if (direction == 0) {
0722 out << SP << SP << "size_t gate_offset = seq * " << num_directions * batch_size * fAttrHiddenSize << ";\n";
0723 } else {
0724 out << SP << SP << "size_t gate_offset = seq * " << num_directions * batch_size * fAttrHiddenSize << " + "
0725 << batch_size * fAttrHiddenSize << ";\n";
0726 }
0727 size_t ff_seq_size = batch_size * fAttrHiddenSize;
0728 out << SP << SP << "std::copy(" << OpName << "_ff_input_gate + ff_offset, " << OpName
0729 << "_ff_input_gate + ff_offset + " << ff_seq_size << ", " << OpName << "_input_gate + gate_offset);\n";
0730 out << SP << SP << "std::copy(" << OpName << "_ff_output_gate + ff_offset, " << OpName
0731 << "_ff_output_gate + ff_offset + " << ff_seq_size << ", " << OpName << "_output_gate + gate_offset);\n";
0732 out << SP << SP << "std::copy(" << OpName << "_ff_cell_gate + ff_offset, " << OpName
0733 << "_ff_cell_gate + ff_offset + " << ff_seq_size << ", " << OpName << "_cell_gate + gate_offset);\n";
0734 if (fAttrInputForget == 0) {
0735 out << SP << SP << "std::copy(" << OpName << "_ff_forget_gate + ff_offset, " << OpName
0736 << "_ff_forget_gate + ff_offset + " << ff_seq_size << ", " << OpName << "_forget_gate + gate_offset);\n";
0737 }
0738 out << SP << "}\n";
0739
0740 out << SP << "for (size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
0741 if (fAttrDirection == "backward" || direction == 1) {
0742 out << SP << SP << "size_t index = " << seq_length - 1 << " - seq;\n";
0743 } else {
0744 out << SP << SP << "size_t index = seq;\n";
0745 }
0746 out << SP << SP << "int m2 = " << batch_size << ";\n";
0747 if (direction == 0) {
0748 out << SP << SP << "size_t offset = index * " << num_directions * batch_size * fAttrHiddenSize << ";\n";
0749 } else {
0750 out << SP << SP << "size_t offset = index * " << num_directions * batch_size * fAttrHiddenSize << " + "
0751 << batch_size * fAttrHiddenSize << ";\n";
0752 }
0753 size_t size = batch_size * fAttrHiddenSize;
0754
0755 out << SP << SP << "if (seq == 0) {\n";
0756 if (!fNInitial_h.empty()) {
0757 if (direction == 0) {
0758 if (fType == "float") {
0759 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0760 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << ", &" << OpName
0761 << "_n, " << OpName << "_initial_hidden_state, &" << OpName << "_n, &" << OpName << "_alpha, "
0762 << OpName << "_input_gate + offset, &" << OpName << "_n);\n";
0763 size_t ro_offset = fAttrHiddenSize * fAttrHiddenSize;
0764 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0765 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << ro_offset
0766 << ", &" << OpName << "_n, " << OpName << "_initial_hidden_state, &" << OpName << "_n, &" << OpName
0767 << "_alpha, " << OpName << "_output_gate + offset, &" << OpName << "_n);\n";
0768 size_t rc_offset = 3 * fAttrHiddenSize * fAttrHiddenSize;
0769 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0770 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << rc_offset
0771 << ", &" << OpName << "_n, " << OpName << "_initial_hidden_state, &" << OpName << "_n, &" << OpName
0772 << "_alpha, " << OpName << "_cell_gate + offset, &" << OpName << "_n);\n";
0773 if (fAttrInputForget == 0) {
0774 size_t rf_offset = 2 * fAttrHiddenSize * fAttrHiddenSize;
0775 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &"
0776 << OpName << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + "
0777 << rf_offset << ", &" << OpName << "_n, " << OpName << "_initial_hidden_state, &" << OpName
0778 << "_n, &" << OpName << "_alpha, " << OpName << "_forget_gate + offset, &" << OpName << "_n);\n";
0779 }
0780 }
0781 } else {
0782 if (fType == "float") {
0783 size_t ri_offset = 4 * fAttrHiddenSize * fAttrHiddenSize;
0784 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0785 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << ri_offset
0786 << ", &" << OpName << "_n, " << OpName << "_initial_hidden_state, &" << OpName << "_n, &" << OpName
0787 << "_alpha, " << OpName << "_input_gate + offset, &" << OpName << "_n);\n";
0788 size_t ro_offset = 4 * fAttrHiddenSize * fAttrHiddenSize + 1 * fAttrHiddenSize * fAttrHiddenSize;
0789 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0790 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << ro_offset
0791 << ", &" << OpName << "_n, " << OpName << "_initial_hidden_state, &" << OpName << "_n, &" << OpName
0792 << "_alpha, " << OpName << "_output_gate + offset, &" << OpName << "_n);\n";
0793 size_t rc_offset = 4 * fAttrHiddenSize * fAttrHiddenSize + 3 * fAttrHiddenSize * fAttrHiddenSize;
0794 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0795 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << rc_offset
0796 << ", &" << OpName << "_n, " << OpName << "_initial_hidden_state, &" << OpName << "_n, &" << OpName
0797 << "_alpha, " << OpName << "_cell_gate + offset, &" << OpName << "_n);\n";
0798 if (fAttrInputForget == 0) {
0799 size_t rf_offset = 4 * fAttrHiddenSize * fAttrHiddenSize + 2 * fAttrHiddenSize * fAttrHiddenSize;
0800 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &"
0801 << OpName << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + "
0802 << rf_offset << ", &" << OpName << "_n, " << OpName << "_initial_hidden_state, &" << OpName
0803 << "_n, &" << OpName << "_alpha, " << OpName << "_forget_gate + offset, &" << OpName << "_n);\n";
0804 }
0805 }
0806 }
0807 }
0808 out << SP << SP << "} else {\n";
0809
0810 if (direction == 0) {
0811 if (fAttrDirection == "backward") {
0812 out << SP << SP << SP << "size_t previous_offset = (index + 1) * "
0813 << num_directions * batch_size * fAttrHiddenSize << ";\n";
0814 } else {
0815 out << SP << SP << SP << "size_t previous_offset = (seq - 1) * "
0816 << num_directions * batch_size * fAttrHiddenSize << ";\n";
0817 }
0818 if (fType == "float") {
0819 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0820 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << ", &" << OpName << "_n, "
0821 << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &" << OpName << "_alpha, " << OpName
0822 << "_input_gate + offset, &" << OpName << "_n);\n";
0823 size_t ro_offset = 1 * fAttrHiddenSize * fAttrHiddenSize;
0824 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0825 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << ro_offset
0826 << ", &" << OpName << "_n, " << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &"
0827 << OpName << "_alpha, " << OpName << "_output_gate + offset, &" << OpName << "_n);\n";
0828 size_t rc_offset = 3 * fAttrHiddenSize * fAttrHiddenSize;
0829 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0830 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << rc_offset
0831 << ", &" << OpName << "_n, " << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &"
0832 << OpName << "_alpha, " << OpName << "_cell_gate + offset, &" << OpName << "_n);\n";
0833 if (fAttrInputForget == 0) {
0834 size_t rf_offset = 2 * fAttrHiddenSize * fAttrHiddenSize;
0835 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0836 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << rf_offset
0837 << ", &" << OpName << "_n, " << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &"
0838 << OpName << "_alpha, " << OpName << "_forget_gate + offset, &" << OpName << "_n);\n";
0839 }
0840 }
0841 } else {
0842 out << SP << SP << SP << "size_t previous_offset = (index + 1) * "
0843 << num_directions * batch_size * fAttrHiddenSize << " + " << batch_size * fAttrHiddenSize << ";\n";
0844 if (fType == "float") {
0845 size_t ri_offset = 4 * fAttrHiddenSize * fAttrHiddenSize;
0846 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0847 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << ri_offset
0848 << ", &" << OpName << "_n, " << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &"
0849 << OpName << "_alpha, " << OpName << "_input_gate + offset, &" << OpName << "_n);\n";
0850 size_t ro_offset = 4 * fAttrHiddenSize * fAttrHiddenSize + fAttrHiddenSize * fAttrHiddenSize;
0851 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0852 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << ro_offset
0853 << ", &" << OpName << "_n, " << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &"
0854 << OpName << "_alpha, " << OpName << "_output_gate + offset, &" << OpName << "_n);\n";
0855 size_t rc_offset = 4 * fAttrHiddenSize * fAttrHiddenSize + 3 * fAttrHiddenSize * fAttrHiddenSize;
0856 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0857 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << rc_offset
0858 << ", &" << OpName << "_n, " << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &"
0859 << OpName << "_alpha, " << OpName << "_cell_gate + offset, &" << OpName << "_n);\n";
0860 if (fAttrInputForget == 0) {
0861 size_t rf_offset = 4 * fAttrHiddenSize * fAttrHiddenSize + 2 * fAttrHiddenSize * fAttrHiddenSize;
0862 out << SP << SP << SP << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName
0863 << "_n, &m2, &" << OpName << "_n, &" << OpName << "_alpha, tensor_" << fNR << " + " << rf_offset
0864 << ", &" << OpName << "_n, " << OpName << "_hidden_state + previous_offset, &" << OpName << "_n, &"
0865 << OpName << "_alpha, " << OpName << "_forget_gate + offset, &" << OpName << "_n);\n";
0866 }
0867 }
0868 }
0869 out << SP << SP << "}\n";
0870
0871
0872 if (fAttrClip > .0) {
0873 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0874 if (fType == "float") {
0875 out << SP << SP << SP << "float x = (" << OpName << "_cell_gate[i] > " << -fAttrClip << ") ? " << OpName
0876 << "_cell_gate[i] : " << -fAttrClip << ";\n";
0877 }
0878 out << SP << SP << SP << OpName << "_cell_gate[i] = (x < " << fAttrClip << ") ? x : " << fAttrClip << ";\n";
0879 out << SP << SP << "}\n";
0880 }
0881
0882 if (fAttrActivations[direction * 3 + 1] == "Relu") {
0883 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0884 out << SP << SP << SP << "if (" << OpName << "_cell_gate[i] < 0.)\n";
0885 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = 0.;\n";
0886 out << SP << SP << "}\n";
0887 } else if (fAttrActivations[direction * 3 + 1] == "Tanh") {
0888 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0889 if (fType == "float") {
0890 out << SP << SP << SP << "float ex = exp(-2 * " << OpName << "_cell_gate[i]);\n";
0891 }
0892 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = (1. - ex) / (1. + ex);\n";
0893 out << SP << SP << "}\n";
0894 } else if (fAttrActivations[direction * 3 + 1] == "Sigmoid") {
0895 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0896 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = 1. / (1. + exp(-" << OpName << "_cell_gate[i]));\n";
0897 out << SP << SP << "}\n";
0898 } else if (fAttrActivations[direction * 3 + 1] == "Affine") {
0899 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0900 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = " << fAttrActivationAlpha[direction * 3 + 1] << " * "
0901 << OpName << "_cell_gate[i] + " << fAttrActivationBeta[direction * 3 + 1] << ";\n";
0902 out << SP << SP << "}\n";
0903 } else if (fAttrActivations[direction * 3 + 1] == "ScaledTanh") {
0904 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0905 if (fType == "float") {
0906 out << SP << SP << SP << "float ex = exp(-2 * " << fAttrActivationBeta[direction * 3 + 1] << " * " << OpName
0907 << "_cell_gate[i]);\n";
0908 }
0909 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = " << fAttrActivationAlpha[direction * 3 + 1]
0910 << " * (1. - ex) / (1. + ex);\n";
0911 out << SP << SP << "}\n";
0912 } else if (fAttrActivations[direction * 3 + 1] == "HardSigmoid") {
0913 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0914 if (fType == "float") {
0915 out << SP << SP << SP << "float a = " << fAttrActivationAlpha[direction * 3 + 1] << " * " << OpName
0916 << "_cell_gate[i] + " << fAttrActivationBeta[direction * 3 + 1] << ";\n";
0917 out << SP << SP << SP << "float b = (a > 0.) ? a : 0.;\n";
0918 }
0919 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = (b < 1.) ? b : 1.;\n";
0920 out << SP << SP << "}\n";
0921 } else if (fAttrActivations[direction * 3 + 1] == "LeakyRelu") {
0922 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0923 out << SP << SP << SP << "if (" << OpName << "_cell_gate[i] < 0.)\n";
0924 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = " << fAttrActivationAlpha[direction * 3 + 1] << " * "
0925 << OpName << "_cell_gate[i];\n";
0926 out << SP << SP << "}\n";
0927 } else if (fAttrActivations[direction * 3 + 1] == "ThresholdRelu") {
0928 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0929 out << SP << SP << SP << "if (" << OpName << "_cell_gate[i] < " << fAttrActivationAlpha[direction * 3 + 1]
0930 << ")\n";
0931 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = 0.;\n";
0932 out << SP << SP << "}";
0933 } else if (fAttrActivations[direction * 3 + 1] == "Elu") {
0934 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0935 out << SP << SP << SP << "if (" << OpName << "_cell_gate[i] < 0.)\n";
0936 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = " << fAttrActivationAlpha[direction * 3 + 1]
0937 << " * exp(" << OpName << "_cell_gate[i] - 1.);\n";
0938 out << SP << SP << "}\n";
0939 } else if (fAttrActivations[direction * 3 + 1] == "Softsign") {
0940 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0941 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = " << OpName << "_cell_gate[i] / (1. + abs(" << OpName
0942 << "_cell_gate[i]));\n";
0943 out << SP << SP << "}\n";
0944 } else {
0945 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
0946 out << SP << SP << SP << SP << OpName << "_cell_gate[i] = log(1. + exp(" << OpName << "_cell_gate[i]));\n";
0947 out << SP << SP << "}\n";
0948 }
0949
0950
0951 if (!fNP.empty()) {
0952
0953 out << SP << SP << "if (seq == 0) {\n";
0954 if (!fNInitial_c.empty()) {
0955 if (direction == 0) {
0956 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
0957 out << SP << SP << SP << SP << OpName << "_input_gate[i + offset] += tensor_" << fNP << "[i] * "
0958 << OpName << "_initial_cell_state[i];\n";
0959 out << SP << SP << SP << "}\n";
0960 if (fAttrInputForget == 0) {
0961 size_t pf_offset = batch_size * fAttrHiddenSize;
0962 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
0963 out << SP << SP << SP << SP << OpName << "_forget_gate[i + offset] += tensor_" << fNP << "[i + "
0964 << pf_offset << "] * " << OpName << "_initial_cell_state[i];\n";
0965 out << SP << SP << SP << "}\n";
0966 }
0967 } else {
0968 size_t pi_offset = 3 * batch_size * fAttrHiddenSize;
0969 size_t initial_c_offset = batch_size * fAttrHiddenSize;
0970 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
0971 out << SP << SP << SP << SP << OpName << "_input_gate[i + offset] += tensor_" << fNP << "[i + "
0972 << pi_offset << "] * " << OpName << "_initial_cell_state[i + " << initial_c_offset << "];\n";
0973 out << SP << SP << SP << "}\n";
0974 if (fAttrInputForget == 0) {
0975 size_t pf_offset = 3 * batch_size * fAttrHiddenSize + batch_size * fAttrHiddenSize;
0976 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
0977 out << SP << SP << SP << SP << OpName << "_forget_gate[i + offset] += tensor_" << fNP << "[i + "
0978 << pf_offset << "] * " << OpName << "_initial_cell_state[i + " << initial_c_offset << "];\n";
0979 out << SP << SP << SP << "}\n";
0980 }
0981 }
0982 }
0983 out << SP << SP << "} else {\n";
0984 if (direction == 0) {
0985 if (fAttrDirection == "backward") {
0986 out << SP << SP << SP << "size_t c_offset = (index + 1) * "
0987 << num_directions * batch_size * fAttrHiddenSize << ";\n";
0988 } else {
0989 out << SP << SP << SP << "size_t c_offset = (seq - 1) * "
0990 << num_directions * batch_size * fAttrHiddenSize << ";\n";
0991 }
0992 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
0993 out << SP << SP << SP << SP << OpName << "_input_gate[i + offset] += tensor_" << fNP << "[i] * " << OpName
0994 << "_cell_state[i + c_offset];\n";
0995 out << SP << SP << SP << "}\n";
0996 if (fAttrInputForget == 0) {
0997 size_t pf_offset = batch_size * fAttrHiddenSize;
0998 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
0999 out << SP << SP << SP << SP << OpName << "_forget_gate[i + offset] += tensor_" << fNP << "[i + "
1000 << pf_offset << "] * " << OpName << "_cell_state[i + c_offset];\n";
1001 out << SP << SP << SP << "}\n";
1002 }
1003 } else {
1004 size_t pi_offset = 3 * batch_size * fAttrHiddenSize;
1005 out << SP << SP << SP << "size_t c_offset = (index + 1) * " << num_directions * batch_size * fAttrHiddenSize
1006 << " + " << batch_size * fAttrHiddenSize << ";\n";
1007 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
1008 out << SP << SP << SP << SP << OpName << "_input_gate[i + offset] += tensor_" << fNP << "[i + " << pi_offset
1009 << "] * " << OpName << "_cell_state[i + c_offset];\n";
1010 out << SP << SP << SP << "}\n";
1011 if (fAttrInputForget == 0) {
1012 size_t pf_offset = 3 * batch_size * fAttrHiddenSize + batch_size * fAttrHiddenSize;
1013 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
1014 out << SP << SP << SP << SP << OpName << "_forget_gate[i + offset] += tensor_" << fNP << "[i + "
1015 << pf_offset << "] * " << OpName << "_cell_state[i + c_offset];\n";
1016 out << SP << SP << SP << "}\n";
1017 }
1018 }
1019 out << SP << SP << "}\n";
1020 }
1021
1022
1023 if (fAttrClip > .0) {
1024 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1025 if (fType == "float") {
1026 out << SP << SP << SP << "float x = (" << OpName << "_input_gate[i] > " << -fAttrClip << ") ? " << OpName
1027 << "_input_gate[i] : " << -fAttrClip << ";\n";
1028 }
1029 out << SP << SP << SP << OpName << "_input_gate[i] = (x < " << fAttrClip << ") ? x : " << fAttrClip << ";\n";
1030 out << SP << SP << "}\n";
1031 }
1032
1033 if (fAttrActivations[direction * 3] == "Relu") {
1034 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1035 out << SP << SP << SP << "if (" << OpName << "_input_gate[i] < 0.)\n";
1036 out << SP << SP << SP << SP << OpName << "_input_gate[i] = 0.;\n";
1037 out << SP << SP << "}\n";
1038 } else if (fAttrActivations[direction * 3] == "Tanh") {
1039 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1040 if (fType == "float") {
1041 out << SP << SP << SP << "float ex = exp(-2 * " << OpName << "_input_gate[i]);\n";
1042 }
1043 out << SP << SP << SP << SP << OpName << "_input_gate[i] = (1. - ex) / (1. + ex);\n";
1044 out << SP << SP << "}\n";
1045 } else if (fAttrActivations[direction * 3] == "Sigmoid") {
1046 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1047 out << SP << SP << SP << SP << OpName << "_input_gate[i] = 1. / (1. + exp(-" << OpName
1048 << "_input_gate[i]));\n";
1049 out << SP << SP << "}\n";
1050 } else if (fAttrActivations[direction * 3] == "Affine") {
1051 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1052 out << SP << SP << SP << SP << OpName << "_input_gate[i] = " << fAttrActivationAlpha[direction * 3] << " * "
1053 << OpName << "_input_gate[i] + " << fAttrActivationBeta[direction * 3] << ";\n";
1054 out << SP << SP << "}\n";
1055 } else if (fAttrActivations[direction * 3] == "ScaledTanh") {
1056 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1057 if (fType == "float") {
1058 out << SP << SP << SP << "float ex = exp(-2 * " << fAttrActivationBeta[direction * 3] << " * " << OpName
1059 << "_input_gate[i]);\n";
1060 }
1061 out << SP << SP << SP << SP << OpName << "_input_gate[i] = " << fAttrActivationAlpha[direction * 3]
1062 << " * (1. - ex) / (1. + ex);\n";
1063 out << SP << SP << "}\n";
1064 } else if (fAttrActivations[direction * 3] == "HardSigmoid") {
1065 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1066 if (fType == "float") {
1067 out << SP << SP << SP << "float a = " << fAttrActivationAlpha[direction * 3] << " * " << OpName
1068 << "_input_gate[i] + " << fAttrActivationBeta[direction * 3] << ";\n";
1069 out << SP << SP << SP << "float b = (a > 0.) ? a : 0.;\n";
1070 }
1071 out << SP << SP << SP << SP << OpName << "_input_gate[i] = (b < 1.) ? b : 1.;\n";
1072 out << SP << SP << "}\n";
1073 } else if (fAttrActivations[direction * 3] == "LeakyRelu") {
1074 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1075 out << SP << SP << SP << "if (" << OpName << "_input_gate[i] < 0.)\n";
1076 out << SP << SP << SP << SP << OpName << "_input_gate[i] = " << fAttrActivationAlpha[direction * 3] << " * "
1077 << OpName << "_input_gate[i];\n";
1078 out << SP << SP << "}\n";
1079 } else if (fAttrActivations[direction * 3] == "ThresholdRelu") {
1080 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1081 out << SP << SP << SP << "if (" << OpName << "_input_gate[i] < " << fAttrActivationAlpha[direction * 3]
1082 << ")\n";
1083 out << SP << SP << SP << SP << OpName << "_input_gate[i] = 0.;\n";
1084 out << SP << SP << "}";
1085 } else if (fAttrActivations[direction * 3] == "Elu") {
1086 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1087 out << SP << SP << SP << "if (" << OpName << "_input_gate[i] < 0.)\n";
1088 out << SP << SP << SP << SP << OpName << "_input_gate[i] = " << fAttrActivationAlpha[direction * 3]
1089 << " * exp(" << OpName << "_input_gate[i] - 1.);\n";
1090 out << SP << SP << "}\n";
1091 } else if (fAttrActivations[direction * 3] == "Softsign") {
1092 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1093 out << SP << SP << SP << SP << OpName << "_input_gate[i] = " << OpName << "_input_gate[i] / (1. + abs("
1094 << OpName << "_input_gate[i]));\n";
1095 out << SP << SP << "}\n";
1096 } else {
1097 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1098 out << SP << SP << SP << SP << OpName << "_input_gate[i] = log(1. + exp(" << OpName << "_input_gate[i]));\n";
1099 out << SP << SP << "}\n";
1100 }
1101
1102 if (fAttrInputForget == 0) {
1103
1104 if (fAttrClip > .0) {
1105 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1106 if (fType == "float") {
1107 out << SP << SP << SP << "float x = (" << OpName << "_forget_gate[i] > " << -fAttrClip << ") ? "
1108 << OpName << "_forget_gate[i] : " << -fAttrClip << ";\n";
1109 }
1110 out << SP << SP << SP << OpName << "_forget_gate[i] = (x < " << fAttrClip << ") ? x : " << fAttrClip
1111 << ";\n";
1112 out << SP << SP << "}\n";
1113 }
1114
1115 if (fAttrActivations[direction * 3] == "Relu") {
1116 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1117 out << SP << SP << SP << "if (" << OpName << "_forget_gate[i] < 0.)\n";
1118 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = 0.;\n";
1119 out << SP << SP << "}\n";
1120 } else if (fAttrActivations[direction * 3] == "Tanh") {
1121 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1122 if (fType == "float") {
1123 out << SP << SP << SP << "float ex = exp(-2 * " << OpName << "_forget_gate[i]);\n";
1124 }
1125 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = (1. - ex) / (1. + ex);\n";
1126 out << SP << SP << "}\n";
1127 } else if (fAttrActivations[direction * 3] == "Sigmoid") {
1128 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1129 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = 1. / (1. + exp(-" << OpName
1130 << "_forget_gate[i]));\n";
1131 out << SP << SP << "}\n";
1132 } else if (fAttrActivations[direction * 3] == "Affine") {
1133 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1134 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = " << fAttrActivationAlpha[direction * 3]
1135 << " * " << OpName << "_forget_gate[i] + " << fAttrActivationBeta[direction * 3] << ";\n";
1136 out << SP << SP << "}\n";
1137 } else if (fAttrActivations[direction * 3] == "ScaledTanh") {
1138 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1139 if (fType == "float") {
1140 out << SP << SP << SP << "float ex = exp(-2 * " << fAttrActivationBeta[direction * 3] << " * " << OpName
1141 << "_forget_gate[i]);\n";
1142 }
1143 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = " << fAttrActivationAlpha[direction * 3]
1144 << " * (1. - ex) / (1. + ex);\n";
1145 out << SP << SP << "}\n";
1146 } else if (fAttrActivations[direction * 3] == "HardSigmoid") {
1147 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1148 if (fType == "float") {
1149 out << SP << SP << SP << "float a = " << fAttrActivationAlpha[direction * 3] << " * " << OpName
1150 << "_forget_gate[i] + " << fAttrActivationBeta[direction * 3] << ";\n";
1151 out << SP << SP << SP << "float b = (a > 0.) ? a : 0.;\n";
1152 }
1153 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = (b < 1.) ? b : 1.;\n";
1154 out << SP << SP << "}\n";
1155 } else if (fAttrActivations[direction * 3] == "LeakyRelu") {
1156 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1157 out << SP << SP << SP << "if (" << OpName << "_forget_gate[i] < 0.)\n";
1158 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = " << fAttrActivationAlpha[direction * 3]
1159 << " * " << OpName << "_forget_gate[i];\n";
1160 out << SP << SP << "}\n";
1161 } else if (fAttrActivations[direction * 3] == "ThresholdRelu") {
1162 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1163 out << SP << SP << SP << "if (" << OpName << "_forget_gate[i] < " << fAttrActivationAlpha[direction * 3]
1164 << ")\n";
1165 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = 0.;\n";
1166 out << SP << SP << "}";
1167 } else if (fAttrActivations[direction * 3] == "Elu") {
1168 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1169 out << SP << SP << SP << "if (" << OpName << "_forget_gate[i] < 0.)\n";
1170 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = " << fAttrActivationAlpha[direction * 3]
1171 << " * exp(" << OpName << "_forget_gate[i] - 1.);\n";
1172 out << SP << SP << "}\n";
1173 } else if (fAttrActivations[direction * 3] == "Softsign") {
1174 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1175 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = " << OpName << "_forget_gate[i] / (1. + abs("
1176 << OpName << "_forget_gate[i]));\n";
1177 out << SP << SP << "}\n";
1178 } else {
1179 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1180 out << SP << SP << SP << SP << OpName << "_forget_gate[i] = log(1. + exp(" << OpName
1181 << "_forget_gate[i]));\n";
1182 out << SP << SP << "}\n";
1183 }
1184 }
1185
1186
1187 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1188 out << SP << SP << SP << OpName << "_cell_state[i] = " << OpName << "_input_gate[i] * " << OpName
1189 << "_cell_gate[i];\n";
1190 out << SP << SP << "}\n";
1191
1192 if (fAttrInputForget == 0) {
1193 out << SP << SP << "if (seq == 0) {\n";
1194 if (!fNInitial_c.empty()) {
1195
1196 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
1197 out << SP << SP << SP << SP << OpName << "_cell_state[i + offset] += " << OpName
1198 << "_forget_gate[i + offset] * " << OpName << "_initial_cell_state[i];\n";
1199 out << SP << SP << SP << "}\n";
1200 }
1201 out << SP << SP << "} else {\n";
1202
1203 if (direction == 0) {
1204 if (fAttrDirection == "backward") {
1205 out << SP << SP << SP << "size_t previous_offset = (index + 1) * "
1206 << num_directions * batch_size * fAttrHiddenSize << ";\n";
1207 } else {
1208 out << SP << SP << SP << "size_t previous_offset = (seq - 1) * "
1209 << num_directions * batch_size * fAttrHiddenSize << ";\n";
1210 }
1211 } else {
1212 out << SP << SP << SP << "size_t previous_offset = (index + 1) * "
1213 << num_directions * batch_size * fAttrHiddenSize << " + " << batch_size * fAttrHiddenSize << ";\n";
1214 }
1215 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
1216 out << SP << SP << SP << SP << OpName << "_cell_state[i + offset] += " << OpName
1217 << "_forget_gate[i + offset] * " << OpName << "_cell_state[i + previous_offset];\n";
1218 out << SP << SP << SP << "}\n";
1219 out << SP << SP << "}\n";
1220 }
1221
1222 if (!fNP.empty()) {
1223
1224 if (direction == 0) {
1225 size_t p_offset = 2 * batch_size * fAttrHiddenSize;
1226 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
1227 out << SP << SP << SP << SP << OpName << "_output_gate[i + offset] += tensor_" << fNP << "[i + " << p_offset
1228 << "] * " << OpName << "_cell_state[i + offset];\n";
1229 out << SP << SP << SP << "}\n";
1230 } else {
1231 size_t p_offset = 3 * batch_size * fAttrHiddenSize + 2 * batch_size * fAttrHiddenSize;
1232 out << SP << SP << SP << "for (size_t i = 0; i < " << size << "; i++) {\n";
1233 out << SP << SP << SP << SP << OpName << "_output_gate[i + offset] += tensor_" << fNP << "[i + " << p_offset
1234 << "] * " << OpName << "_cell_state[i + offset];\n";
1235 out << SP << SP << SP << "}\n";
1236 }
1237 }
1238
1239
1240 if (fAttrClip > .0) {
1241 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1242 if (fType == "float") {
1243 out << SP << SP << SP << "float x = (" << OpName << "_output_gate[i] > " << -fAttrClip << ") ? " << OpName
1244 << "_output_gate[i] : " << -fAttrClip << ";\n";
1245 }
1246 out << SP << SP << SP << OpName << "_output_gate[i] = (x < " << fAttrClip << ") ? x : " << fAttrClip << ";\n";
1247 out << SP << SP << "}\n";
1248 }
1249
1250 if (fAttrActivations[direction * 3] == "Relu") {
1251 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1252 out << SP << SP << SP << "if (" << OpName << "_output_gate[i] < 0.)\n";
1253 out << SP << SP << SP << SP << OpName << "_output_gate[i] = 0.;\n";
1254 out << SP << SP << "}\n";
1255 } else if (fAttrActivations[direction * 3] == "Tanh") {
1256 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1257 if (fType == "float") {
1258 out << SP << SP << SP << "float ex = exp(-2 * " << OpName << "_output_gate[i]);\n";
1259 }
1260 out << SP << SP << SP << SP << OpName << "_output_gate[i] = (1. - ex) / (1. + ex);\n";
1261 out << SP << SP << "}\n";
1262 } else if (fAttrActivations[direction * 3] == "Sigmoid") {
1263 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1264 out << SP << SP << SP << SP << OpName << "_output_gate[i] = 1. / (1. + exp(-" << OpName
1265 << "_output_gate[i]));\n";
1266 out << SP << SP << "}\n";
1267 } else if (fAttrActivations[direction * 3] == "Affine") {
1268 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1269 out << SP << SP << SP << SP << OpName << "_output_gate[i] = " << fAttrActivationAlpha[direction * 3] << " * "
1270 << OpName << "_output_gate[i] + " << fAttrActivationBeta[direction * 3] << ";\n";
1271 out << SP << SP << "}\n";
1272 } else if (fAttrActivations[direction * 3] == "ScaledTanh") {
1273 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1274 if (fType == "float") {
1275 out << SP << SP << SP << "float ex = exp(-2 * " << fAttrActivationBeta[direction * 3] << " * " << OpName
1276 << "_output_gate[i]);\n";
1277 }
1278 out << SP << SP << SP << SP << OpName << "_output_gate[i] = " << fAttrActivationAlpha[direction * 3]
1279 << " * (1. - ex) / (1. + ex);\n";
1280 out << SP << SP << "}\n";
1281 } else if (fAttrActivations[direction * 3] == "HardSigmoid") {
1282 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1283 if (fType == "float") {
1284 out << SP << SP << SP << "float a = " << fAttrActivationAlpha[direction * 3] << " * " << OpName
1285 << "_output_gate[i] + " << fAttrActivationBeta[direction * 3] << ";\n";
1286 out << SP << SP << SP << "float b = (a > 0.) ? a : 0.;\n";
1287 }
1288 out << SP << SP << SP << SP << OpName << "_output_gate[i] = (b < 1.) ? b : 1.;\n";
1289 out << SP << SP << "}\n";
1290 } else if (fAttrActivations[direction * 3] == "LeakyRelu") {
1291 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1292 out << SP << SP << SP << "if (" << OpName << "_output_gate[i] < 0.)\n";
1293 out << SP << SP << SP << SP << OpName << "_output_gate[i] = " << fAttrActivationAlpha[direction * 3] << " * "
1294 << OpName << "_output_gate[i];\n";
1295 out << SP << SP << "}\n";
1296 } else if (fAttrActivations[direction * 3] == "ThresholdRelu") {
1297 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1298 out << SP << SP << SP << "if (" << OpName << "_output_gate[i] < " << fAttrActivationAlpha[direction * 3]
1299 << ")\n";
1300 out << SP << SP << SP << SP << OpName << "_output_gate[i] = 0.;\n";
1301 out << SP << SP << "}";
1302 } else if (fAttrActivations[direction * 3] == "Elu") {
1303 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1304 out << SP << SP << SP << "if (" << OpName << "_output_gate[i] < 0.)\n";
1305 out << SP << SP << SP << SP << OpName << "_output_gate[i] = " << fAttrActivationAlpha[direction * 3]
1306 << " * exp(" << OpName << "_output_gate[i] - 1.);\n";
1307 out << SP << SP << "}\n";
1308 } else if (fAttrActivations[direction * 3] == "Softsign") {
1309 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1310 out << SP << SP << SP << SP << OpName << "_output_gate[i] = " << OpName << "_output_gate[i] / (1. + abs("
1311 << OpName << "_output_gate[i]));\n";
1312 out << SP << SP << "}\n";
1313 } else {
1314 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1315 out << SP << SP << SP << SP << OpName << "_output_gate[i] = log(1. + exp(" << OpName << "_output_gate[i]));\n";
1316 out << SP << SP << "}\n";
1317 }
1318
1319
1320 out << SP << SP << "std::copy(" << OpName << "_cell_state + offset, " << OpName << "_cell_state + offset + "
1321 << size << ", " << OpName << "_new_cell_state + offset);\n";
1322
1323 if (fAttrClip > .0) {
1324 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1325 if (fType == "float") {
1326 out << SP << SP << SP << "float x = (" << OpName << "_new_cell_state[i] > " << -fAttrClip << ") ? "
1327 << OpName << "_new_cell_state[i] : " << -fAttrClip << ";\n";
1328 }
1329 out << SP << SP << SP << OpName << "_new_cell_state[i] = (x < " << fAttrClip << ") ? x : " << fAttrClip
1330 << ";\n";
1331 out << SP << SP << "}\n";
1332 }
1333
1334 if (fAttrActivations[direction * 3 + 2] == "Relu") {
1335 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1336 out << SP << SP << SP << "if (" << OpName << "_new_cell_state[i] < 0.)\n";
1337 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = 0.;\n";
1338 out << SP << SP << "}\n";
1339 } else if (fAttrActivations[direction * 3 + 2] == "Tanh") {
1340 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1341 if (fType == "float") {
1342 out << SP << SP << SP << "float ex = exp(-2 * " << OpName << "_new_cell_state[i]);\n";
1343 }
1344 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = (1. - ex) / (1. + ex);\n";
1345 out << SP << SP << "}\n";
1346 } else if (fAttrActivations[direction * 3 + 2] == "Sigmoid") {
1347 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1348 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = 1. / (1. + exp(-" << OpName
1349 << "_new_cell_state[i]));\n";
1350 out << SP << SP << "}\n";
1351 } else if (fAttrActivations[direction * 3 + 2] == "Affine") {
1352 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1353 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = " << fAttrActivationAlpha[direction * 3 + 2]
1354 << " * " << OpName << "_new_cell_state[i] + " << fAttrActivationBeta[direction * 3 + 2] << ";\n";
1355 out << SP << SP << "}\n";
1356 } else if (fAttrActivations[direction * 3 + 2] == "ScaledTanh") {
1357 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1358 if (fType == "float") {
1359 out << SP << SP << SP << "float ex = exp(-2 * " << fAttrActivationBeta[direction * 3 + 2] << " * " << OpName
1360 << "_new_cell_state[i]);\n";
1361 }
1362 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = " << fAttrActivationAlpha[direction * 3 + 2]
1363 << " * (1. - ex) / (1. + ex);\n";
1364 out << SP << SP << "}\n";
1365 } else if (fAttrActivations[direction * 3 + 2] == "HardSigmoid") {
1366 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1367 if (fType == "float") {
1368 out << SP << SP << SP << "float a = " << fAttrActivationAlpha[direction * 3 + 2] << " * " << OpName
1369 << "_new_cell_state[i] + " << fAttrActivationBeta[direction * 3 + 2] << ";\n";
1370 out << SP << SP << SP << "float b = (a > 0.) ? a : 0.;\n";
1371 }
1372 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = (b < 1.) ? b : 1.;\n";
1373 out << SP << SP << "}\n";
1374 } else if (fAttrActivations[direction * 3 + 2] == "LeakyRelu") {
1375 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1376 out << SP << SP << SP << "if (" << OpName << "_new_cell_state[i] < 0.)\n";
1377 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = " << fAttrActivationAlpha[direction * 3 + 2]
1378 << " * " << OpName << "_new_cell_state[i];\n";
1379 out << SP << SP << "}\n";
1380 } else if (fAttrActivations[direction * 3 + 2] == "ThresholdRelu") {
1381 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1382 out << SP << SP << SP << "if (" << OpName << "_new_cell_state[i] < " << fAttrActivationAlpha[direction * 3 + 2]
1383 << ")\n";
1384 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = 0.;\n";
1385 out << SP << SP << "}";
1386 } else if (fAttrActivations[direction * 3 + 2] == "Elu") {
1387 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1388 out << SP << SP << SP << "if (" << OpName << "_new_cell_state[i] < 0.)\n";
1389 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = " << fAttrActivationAlpha[direction * 3 + 2]
1390 << " * exp(" << OpName << "_new_cell_state[i] - 1.);\n";
1391 out << SP << SP << "}\n";
1392 } else if (fAttrActivations[direction * 3 + 2] == "Softsign") {
1393 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1394 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = " << OpName << "_new_cell_state[i] / (1. + abs("
1395 << OpName << "_new_cell_state[i]));\n";
1396 out << SP << SP << "}\n";
1397 } else {
1398 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1399 out << SP << SP << SP << SP << OpName << "_new_cell_state[i] = log(1. + exp(" << OpName
1400 << "_new_cell_state[i]));\n";
1401 out << SP << SP << "}\n";
1402 }
1403
1404
1405 out << SP << SP << "for (size_t i = offset; i < offset + " << size << "; i++) {\n";
1406 out << SP << SP << SP << OpName << "_hidden_state[i] = " << OpName << "_output_gate[i] * " << OpName
1407 << "_new_cell_state[i];\n";
1408 out << SP << SP << "}\n";
1409 out << SP << "}\n";
1410 }
1411
1412
1413 if (!fNSequence_lens.empty()) {
1414 out << SP << "for (size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
1415 out << SP << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1416 out << SP << SP << SP << "if (seq >= tensor_" << fNSequence_lens << "[batch]) {\n";
1417 for (size_t direction = 0; direction < num_directions; direction++) {
1418 out << SP << SP << SP << SP << SP << "for (size_t h = 0; h < " << fAttrHiddenSize << "; h++) {\n";
1419 out << SP << SP << SP << SP << SP << SP << "size_t idx = seq * "
1420 << num_directions * batch_size * fAttrHiddenSize + direction * batch_size * fAttrHiddenSize
1421 << " + batch * " << fAttrHiddenSize << " + h;\n";
1422 out << SP << SP << SP << SP << SP << SP << OpName << "_cell_state[idx] = 0.;\n";
1423 out << SP << SP << SP << SP << SP << SP << OpName << "_hidden_state[idx] = 0.;\n";
1424 out << SP << SP << SP << SP << SP << "}\n";
1425 }
1426 out << SP << SP << SP << "}\n";
1427 out << SP << SP << "}\n";
1428 out << SP << "}\n";
1429 }
1430
1431
1432 if (fAttrLayout == 0) {
1433 if (!fNY_h.empty()) {
1434
1435 if (fNSequence_lens.empty()) {
1436 size_t y_h_size = batch_size * fAttrHiddenSize;
1437 if (fAttrDirection == "backward") {
1438 out << SP << "std::copy(" << OpName << "_hidden_state, " << OpName << "_hidden_state + " << y_h_size
1439 << ", tensor_" << fNY_h << ");\n";
1440 } else {
1441 size_t offset = (seq_length - 1) * num_directions * batch_size * fAttrHiddenSize;
1442 out << SP << "std::copy(" << OpName << "_hidden_state + " << offset << ", " << OpName
1443 << "_hidden_state + " << offset << " + " << y_h_size << ", tensor_" << fNY_h << ");\n";
1444 }
1445 if (num_directions == 2) {
1446 out << SP << "std::copy(" << OpName << "_hidden_state + " << y_h_size << ", " << OpName
1447 << "_hidden_state + " << 2 * y_h_size << ", tensor_" << fNY_h << " + " << y_h_size << ");\n";
1448 }
1449 } else {
1450 if (fAttrDirection == "backward") {
1451 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1452 out << SP << SP << "size_t offset = batch * " << fAttrHiddenSize << ";\n";
1453 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
1454 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + offset);\n";
1455 out << SP << "}\n";
1456 } else {
1457 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1458 out << SP << SP << "size_t seq = " << "tensor_" << fNSequence_lens << "[batch] - 1;\n";
1459 out << SP << SP << "size_t offset = seq * " << num_directions * batch_size * fAttrHiddenSize
1460 << " + batch * " << fAttrHiddenSize << ";\n";
1461 out << SP << SP << "size_t y_h_offset = batch * " << fAttrHiddenSize << ";\n";
1462 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
1463 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + y_h_offset);\n";
1464 out << SP << "}\n";
1465 }
1466 if (num_directions == 2) {
1467 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1468 out << SP << SP << "size_t offset = " << batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize
1469 << ";\n";
1470 out << SP << SP << "size_t y_h_offset = " << batch_size * fAttrHiddenSize << " + batch * "
1471 << fAttrHiddenSize << ";\n";
1472 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
1473 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + y_h_offset);\n";
1474 out << SP << "}\n";
1475 }
1476 }
1477 }
1478 if (!fNY_c.empty()) {
1479
1480 if (fNSequence_lens.empty()) {
1481 size_t y_h_size = batch_size * fAttrHiddenSize;
1482 if (fAttrDirection == "backward") {
1483 out << SP << "std::copy(" << OpName << "_cell_state, " << OpName << "_hidden_state + " << y_h_size
1484 << ", tensor_" << fNY_c << ");\n";
1485 } else {
1486 size_t offset = (seq_length - 1) * num_directions * batch_size * fAttrHiddenSize;
1487 out << SP << "std::copy(" << OpName << "_cell_state + " << offset << ", " << OpName << "_cell_state + "
1488 << offset << " + " << y_h_size << ", tensor_" << fNY_c << ");\n";
1489 }
1490 if (num_directions == 2) {
1491 out << SP << "std::copy(" << OpName << "_cell_state + " << y_h_size << ", " << OpName << "_cell_state + "
1492 << 2 * y_h_size << ", tensor_" << fNY_c << " + " << y_h_size << ");\n";
1493 }
1494 } else {
1495 if (fAttrDirection == "backward") {
1496 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1497 out << SP << SP << "size_t offset = batch * " << fAttrHiddenSize << ";\n";
1498 out << SP << SP << "std::copy(" << OpName << "_cell_state + offset, " << OpName
1499 << "_cell_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_c << " + offset);\n";
1500 out << SP << "}\n";
1501 } else {
1502 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1503 out << SP << SP << "size_t seq = " << "tensor_" << fNSequence_lens << "[batch] - 1;\n";
1504 out << SP << SP << "size_t offset = seq * " << num_directions * batch_size * fAttrHiddenSize
1505 << " + batch * " << fAttrHiddenSize << ";\n";
1506 out << SP << SP << "size_t y_h_offset = batch * " << fAttrHiddenSize << ";\n";
1507 out << SP << SP << "std::copy(" << OpName << "_cell_state + offset, " << OpName
1508 << "_cell_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_c << " + y_h_offset);\n";
1509 out << SP << "}\n";
1510 }
1511 if (num_directions == 2) {
1512 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1513 out << SP << SP << "size_t offset = " << batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize
1514 << ";\n";
1515 out << SP << SP << "size_t y_h_offset = " << batch_size * fAttrHiddenSize << " + batch * "
1516 << fAttrHiddenSize << ";\n";
1517 out << SP << SP << "std::copy(" << OpName << "_cell_state + offset, " << OpName
1518 << "_cell_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_c << " + y_h_offset);\n";
1519 out << SP << "}\n";
1520 }
1521 }
1522 }
1523 } else {
1524 if (!fNY.empty()) {
1525
1526 for (size_t direction = 0; direction < num_directions; direction++) {
1527 out << SP << "for (size_t seq = 0; seq < " << seq_length << "; seq++) {\n";
1528 out << SP << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1529 out << SP << SP << SP << "size_t offset = seq * " << num_directions * batch_size * fAttrHiddenSize << " + "
1530 << direction * batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize << ";\n";
1531 out << SP << SP << SP << "size_t y_offset = batch * " << seq_length * num_directions * fAttrHiddenSize
1532 << " + seq * " << num_directions * fAttrHiddenSize << " + " << direction * fAttrHiddenSize << ";\n";
1533 out << SP << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
1534 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY << " + y_offset);\n";
1535 out << SP << SP << "}\n";
1536 out << SP << "}\n";
1537 }
1538 }
1539 if (!fNY_h.empty()) {
1540
1541 if (fAttrDirection == "backward") {
1542 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1543 out << SP << SP << "size_t offset = batch * " << fAttrHiddenSize << ";\n";
1544 out << SP << SP << "size_t y_h_offset = batch * " << num_directions * fAttrHiddenSize << ";\n";
1545 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
1546 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + y_h_offset);\n";
1547 out << SP << "}\n";
1548 } else {
1549 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1550 if (fNSequence_lens.empty()) {
1551 out << SP << SP << "size_t seq = " << seq_length - 1 << ";\n";
1552 } else {
1553 out << SP << SP << "size_t seq = " << "tensor_" << fNSequence_lens << "[batch] - 1;\n";
1554 }
1555 out << SP << SP << "size_t offset = seq * " << num_directions * batch_size * fAttrHiddenSize
1556 << " + batch * " << fAttrHiddenSize << ";\n";
1557 out << SP << SP << "size_t y_h_offset = batch * " << num_directions * fAttrHiddenSize << ";\n";
1558 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
1559 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + y_h_offset);\n";
1560 out << SP << "}\n";
1561 }
1562 if (num_directions == 2) {
1563 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1564 out << SP << SP << "size_t offset = " << batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize
1565 << ";\n";
1566 out << SP << SP << "size_t y_h_offset = batch * " << num_directions * fAttrHiddenSize << " + "
1567 << fAttrHiddenSize << ";\n";
1568 out << SP << SP << "std::copy(" << OpName << "_hidden_state + offset, " << OpName
1569 << "_hidden_state + offset + " << fAttrHiddenSize << ", tensor_" << fNY_h << " + y_h_offset);\n";
1570 out << SP << "}\n";
1571 }
1572 }
1573
1574 if (!fNY_c.empty()) {
1575
1576 if (fAttrDirection == "backward") {
1577 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1578 out << SP << SP << "size_t offset = batch * " << fAttrHiddenSize << ";\n";
1579 out << SP << SP << "size_t y_h_offset = batch * " << num_directions * fAttrHiddenSize << ";\n";
1580 out << SP << SP << "std::copy(" << OpName << "_cell_state + offset, " << OpName << "_cell_state + offset + "
1581 << fAttrHiddenSize << ", tensor_" << fNY_c << " + y_h_offset);\n";
1582 out << SP << "}\n";
1583 } else {
1584 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1585 if (fNSequence_lens.empty()) {
1586 out << SP << SP << "size_t seq = " << seq_length - 1 << ";\n";
1587 } else {
1588 out << SP << SP << "size_t seq = " << "tensor_" << fNSequence_lens << "[batch] - 1;\n";
1589 }
1590 out << SP << SP << "size_t offset = seq * " << num_directions * batch_size * fAttrHiddenSize
1591 << " + batch * " << fAttrHiddenSize << ";\n";
1592 out << SP << SP << "size_t y_h_offset = batch * " << num_directions * fAttrHiddenSize << ";\n";
1593 out << SP << SP << "std::copy(" << OpName << "_cell_state + offset, " << OpName << "_cell_state + offset + "
1594 << fAttrHiddenSize << ", tensor_" << fNY_c << " + y_h_offset);\n";
1595 out << SP << "}\n";
1596 }
1597 if (num_directions == 2) {
1598 out << SP << "for (size_t batch = 0; batch < " << batch_size << "; batch++) {\n";
1599 out << SP << SP << "size_t offset = " << batch_size * fAttrHiddenSize << " + batch * " << fAttrHiddenSize
1600 << ";\n";
1601 out << SP << SP << "size_t y_h_offset = batch * " << num_directions * fAttrHiddenSize << " + "
1602 << fAttrHiddenSize << ";\n";
1603 out << SP << SP << "std::copy(" << OpName << "_cell_state + offset, " << OpName << "_cell_state + offset + "
1604 << fAttrHiddenSize << ", tensor_" << fNY_c << " + y_h_offset);\n";
1605 out << SP << "}\n";
1606 }
1607 }
1608 }
1609
1610 return out.str();
1611 }
1612
1613 }
1614
1615 #endif