1 //*****************************************************************************
2 // Copyright 2017-2020 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //*****************************************************************************
21 #include "ngraph/builder/split.hpp"
22 #include "ngraph/shape.hpp"
23 #include "onnx_import/core/null_node.hpp"
24 #include "onnx_import/default_opset.hpp"
25 #include "onnx_import/utils/recurrent.hpp"
37 struct GRUInputMap : public recurrent::OpInputMap
39 GRUInputMap(const Node& node, std::size_t gates_count)
40 : OpInputMap(node, gates_count)
42 bool linear_before_reset = static_cast<bool>(
43 node.get_attribute_value<std::int64_t>("linear_before_reset", 0));
45 // Override bias, since we need separated W and R biases for `h` gate.
46 if (linear_before_reset)
48 const auto& ng_inputs = node.get_ng_inputs();
49 const auto el_type = ng_inputs.at(0).get_element_type();
51 if (ng_inputs.size() > 3 && !ngraph::op::is_null(ng_inputs.at(3)))
53 NGRAPH_SUPPRESS_DEPRECATED_START
55 auto bias = ng_inputs.at(3);
56 // gates_count * 2 since B is: [Wb, Rb]
57 const int split_parts = 2 * 3;
58 const auto split_bias =
59 builder::opset1::split(bias, split_parts, 1);
60 const auto wr_z_bias = split_bias.at(0) + split_bias.at(3);
61 const auto wr_r_bias = split_bias.at(1) + split_bias.at(4);
62 // The result has shape: [num_directions, 4 * hidden_size]
69 // // num_directions times
71 m_map[recurrent::OpInput::B] =
72 std::make_shared<default_opset::Concat>(
73 OutputVector{wr_z_bias,
78 NGRAPH_SUPPRESS_DEPRECATED_END
82 const std::size_t hidden_size =
83 m_map[recurrent::OpInput::R].get_shape().back();
84 const std::size_t num_directions =
85 m_map[recurrent::OpInput::W].get_shape().front();
87 m_map[recurrent::OpInput::B] =
88 std::make_shared<default_opset::Constant>(
90 Shape{num_directions, (gates_count + 1) * hidden_size},
96 virtual ~GRUInputMap() = default;
99 struct GRUAttributes : public recurrent::OpAttributes
101 GRUAttributes(const Node& node)
103 , m_linear_before_reset{static_cast<bool>(
104 node.get_attribute_value<std::int64_t>("linear_before_reset", 0))}
106 m_activations = node.get_attribute_value<std::vector<std::string>>(
107 "activations", {"sigmoid", "tanh"});
110 virtual ~GRUAttributes() = default;
112 bool m_linear_before_reset;
116 OutputVector gru(const Node& node)
118 constexpr std::size_t gates_count = 3;
119 GRUInputMap input_map{node, gates_count};
120 GRUAttributes attributes{node};
122 recurrent::RecurrentSequence sequence_op(input_map, attributes.m_direction);
124 sequence_op.run_sequence([&attributes](const recurrent::OpInputMap& args,
125 const Output<ngraph::Node>& in_Xt,
126 const Output<ngraph::Node> H_t) {
128 const GRUInputMap& gru_args = dynamic_cast<const GRUInputMap&>(args);
130 return std::make_shared<default_opset::GRUCell>(
133 gru_args.at(recurrent::OpInput::W),
134 gru_args.at(recurrent::OpInput::R),
135 gru_args.at(recurrent::OpInput::B),
136 attributes.m_hidden_size,
137 attributes.m_activations,
138 attributes.m_activations_alpha,
139 attributes.m_activations_beta,
140 attributes.m_clip_threshold,
141 attributes.m_linear_before_reset);
150 } // namespace onnx_import
152 } // namespace ngraph