6e3fc1b7e2fa629102fecc1105cae59242fcbfff
[platform/upstream/dldt.git] / ngraph / python / src / ngraph / opset4 / ops.py
1 # ******************************************************************************
2 # Copyright 2017-2020 Intel Corporation
3 #
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
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
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 # ******************************************************************************
16
17 """! Factory functions for all ngraph ops."""
18 from typing import Callable, Iterable, List, Optional, Set, Union
19
20 import numpy as np
21 from functools import partial
22
23 from ngraph.impl import Node, Shape
24 from ngraph.impl.op import Constant, Parameter
25 from ngraph.opset_utils import _get_node_factory
26 from ngraph.utils.decorators import binary_op, nameable_op, unary_op
27 from ngraph.utils.input_validation import (
28     assert_list_of_ints,
29     check_valid_attributes,
30     is_non_negative_value,
31     is_positive_value,
32 )
33 from ngraph.utils.node_factory import NodeFactory
34 from ngraph.utils.tensor_iterator_types import (
35     GraphBody,
36     TensorIteratorSliceInputDesc,
37     TensorIteratorMergedInputDesc,
38     TensorIteratorInvariantInputDesc,
39     TensorIteratorBodyOutputDesc,
40     TensorIteratorConcatOutputDesc,
41 )
42 from ngraph.utils.types import (
43     NodeInput,
44     NumericData,
45     NumericType,
46     ScalarData,
47     TensorShape,
48     as_node,
49     as_nodes,
50     get_dtype,
51     get_element_type,
52     get_element_type_str,
53     make_constant_node,
54 )
55
56 _get_node_factory_opset4 = partial(_get_node_factory, "opset4")
57
58 # -------------------------------------------- ops ------------------------------------------------
59
60
61 @nameable_op
62 def ctc_loss(
63     logits: NodeInput,
64     logit_length: NodeInput,
65     labels: NodeInput,
66     label_length: NodeInput,
67     blank_index: Optional[NodeInput] = None,
68     preprocess_collapse_repeated: bool = False,
69     ctc_merge_repeated: bool = True,
70     unique: bool = False,
71     name: Optional[str] = None,
72 ) -> Node:
73     """! Return a node which performs CTCLoss.
74
75     @param logits:                        3-D tensor of logits.
76     @param logit_length:                  1-D tensor of lengths for each object from a batch.
77     @param labels:                        2-D tensor of labels for which likelihood is estimated using logits.
78     @param label_length:                  1-D tensor of length for each label sequence.
79     @param blank_index:                   Scalar used to mark a blank index.
80     @param preprocess_collapse_repeated:  Flag for preprocessing labels before loss calculation.
81     @param ctc_merge_repeated:            Flag for merging repeated characters in a potential alignment.
82     @param unique:                        Flag to find unique elements in a target.
83     @return The new node which performs CTCLoss
84     """
85     if blank_index is not None:
86         inputs = as_nodes(logits, logit_length, labels, label_length, blank_index)
87     else:
88         inputs = as_nodes(logits, logit_length, labels, label_length)
89
90     attributes = {
91         "preprocess_collapse_repeated": preprocess_collapse_repeated,
92         "ctc_merge_repeated": ctc_merge_repeated,
93         "unique": unique,
94     }
95
96     return _get_node_factory_opset4().create("CTCLoss", inputs, attributes)
97
98
99 @nameable_op
100 def non_max_suppression(
101     boxes: NodeInput,
102     scores: NodeInput,
103     max_output_boxes_per_class: Optional[NodeInput] = None,
104     iou_threshold: Optional[NodeInput] = None,
105     score_threshold: Optional[NodeInput] = None,
106     box_encoding: str = "corner",
107     sort_result_descending: bool = True,
108     output_type: str = "i64",
109     name: Optional[str] = None,
110 ) -> Node:
111     """! Return a node which performs NonMaxSuppression.
112
113     @param boxes: Tensor with box coordinates.
114     @param scores: Tensor with box scores.
115     @param max_output_boxes_per_class: Tensor Specifying maximum number of boxes
116                                         to be selected per class.
117     @param iou_threshold: Tensor specifying intersection over union threshold
118     @param score_threshold: Tensor specifying minimum score to consider box for the processing.
119     @param box_encoding: Format of boxes data encoding.
120     @param sort_result_descending: Flag that specifies whenever it is necessary to sort selected
121                                    boxes across batches or not.
122     @param output_type: Output element type.
123     @return The new node which performs NonMaxSuppression
124     """
125     if max_output_boxes_per_class is None:
126         max_output_boxes_per_class = make_constant_node(0, np.int64)
127     if iou_threshold is None:
128         iou_threshold = make_constant_node(0, np.float32)
129     if score_threshold is None:
130         score_threshold = make_constant_node(0, np.float32)
131
132     inputs = as_nodes(boxes, scores, max_output_boxes_per_class, iou_threshold, score_threshold)
133     attributes = {
134         "box_encoding": box_encoding,
135         "sort_result_descending": sort_result_descending,
136         "output_type": output_type,
137     }
138
139     return _get_node_factory_opset4().create("NonMaxSuppression", inputs, attributes)
140
141
142 @nameable_op
143 def softplus(data: NodeInput, name: Optional[str] = None) -> Node:
144     """! Apply SoftPlus operation on each element of input tensor.
145
146     @param data: The tensor providing input data.
147     @return The new node with SoftPlus operation applied on each element.
148     """
149     return _get_node_factory_opset4().create("SoftPlus", as_nodes(data), {})
150
151
152 @nameable_op
153 def mish(data: NodeInput, name: Optional[str] = None,) -> Node:
154     """! Return a node which performs Mish.
155
156     @param data: Tensor with input data floating point type.
157     @return The new node which performs Mish
158     """
159     return _get_node_factory_opset4().create("Mish", as_nodes(data), {})
160
161
162 @nameable_op
163 def hswish(data: NodeInput, name: Optional[str] = None,) -> Node:
164     """! Return a node which performs HSwish (hard version of Swish).
165
166     @param data: Tensor with input data floating point type.
167     @return The new node which performs HSwish
168     """
169     return _get_node_factory_opset4().create("HSwish", as_nodes(data), {})
170
171
172 @nameable_op
173 def swish(
174     data: NodeInput,
175     beta: Optional[NodeInput] = None,
176     name: Optional[str] = None,
177 ) -> Node:
178     """! Return a node which performing Swish activation function Swish(x, beta=1.0) = x * sigmoid(x * beta)).
179
180     @param data: Tensor with input data floating point type.
181     @return The new node which performs Swish
182     """
183     if beta is None:
184         beta = make_constant_node(1.0, np.float32)
185     return _get_node_factory_opset4().create("Swish", as_nodes(data, beta), {})
186
187
188 @nameable_op
189 def acosh(node: NodeInput, name: Optional[str] = None) -> Node:
190     """! Apply hyperbolic inverse cosine function on the input node element-wise.
191
192     @param node: One of: input node, array or scalar.
193     @param name: Optional new name for output node.
194     @return New node with arccosh operation applied on it.
195     """
196     return _get_node_factory_opset4().create("Acosh", [node])
197
198
199 @nameable_op
200 def asinh(node: NodeInput, name: Optional[str] = None) -> Node:
201     """! Apply hyperbolic inverse sinus function on the input node element-wise.
202
203     @param node: One of: input node, array or scalar.
204     @param name: Optional new name for output node.
205     @return New node with arcsinh operation applied on it.
206     """
207     return _get_node_factory_opset4().create("Asinh", [node])
208
209
210 @nameable_op
211 def atanh(node: NodeInput, name: Optional[str] = None) -> Node:
212     """! Apply hyperbolic inverse tangent function on the input node element-wise.
213
214     @param node: One of: input node, array or scalar.
215     @param name: Optional new name for output node.
216     @return New node with arctanh operation applied on it.
217     """
218     return _get_node_factory_opset4().create("Atanh", [node])
219
220
221 @nameable_op
222 def proposal(
223         class_probs: Node,
224         bbox_deltas: Node,
225         image_shape: NodeInput,
226         attrs: dict,
227         name: Optional[str] = None,
228 ) -> Node:
229     """! Filter bounding boxes and outputs only those with the highest prediction confidence.
230
231     @param  class_probs:        4D input floating point tensor with class prediction scores.
232     @param  bbox_deltas:        4D input floating point tensor with corrected predictions of bounding boxes
233     @param  image_shape:        The 1D input tensor with 3 or 4 elements describing image shape.
234     @param  attrs:              The dictionary containing key, value pairs for attributes.
235     @param  name:               Optional name for the output node.
236     * base_size     The size of the anchor to which scale and ratio attributes are applied.
237                     Range of values: a positive unsigned integer number
238                     Default value: None
239                     Required: yes
240     * pre_nms_topn  The number of bounding boxes before the NMS operation.
241                     Range of values: a positive unsigned integer number
242                     Default value: None
243                     Required: yes
244     * post_nms_topn The number of bounding boxes after the NMS operation.
245                     Range of values: a positive unsigned integer number
246                     Default value: None
247                     Required: yes
248     * nms_thresh    The minimum value of the proposal to be taken into consideration.
249                     Range of values: a positive floating-point number
250                     Default value: None
251                     Required: yes
252     * feat_stride   The step size to slide over boxes (in pixels).
253                     Range of values: a positive unsigned integer
254                     Default value: None
255                     Required: yes
256     * min_size      The minimum size of box to be taken into consideration.
257                     Range of values: a positive unsigned integer number
258                     Default value: None
259                     Required: yes
260     * ratio         The ratios for anchor generation.
261                     Range of values: a list of floating-point numbers
262                     Default value: None
263                     Required: yes
264     * scale         The scales for anchor generation.
265                     Range of values: a list of floating-point numbers
266                     Default value: None
267                     Required: yes
268     * clip_before_nms   The flag that specifies whether to perform clip bounding boxes before
269                         non-maximum suppression or not.
270                         Range of values: True or False
271                         Default value: True
272                         Required: no
273     * clip_after_nms    The flag that specifies whether to perform clip bounding boxes after
274                         non-maximum suppression or not.
275                         Range of values: True or False
276                         Default value: False
277                         Required: no
278     * normalize     The flag that specifies whether to perform normalization of output boxes to
279                     [0,1] interval or not.
280                     Range of values: True or False
281                     Default value: False
282                     Required: no
283     * box_size_scale    Specifies the scale factor applied to logits of box sizes before decoding.
284                         Range of values: a positive floating-point number
285                         Default value: 1.0
286                         Required: no
287     * box_coordinate_scale  Specifies the scale factor applied to logits of box coordinates
288                             before decoding.
289                             Range of values: a positive floating-point number
290                             Default value: 1.0
291                             Required: no
292     * framework     Specifies how the box coordinates are calculated.
293                     Range of values: "" (empty string) - calculate box coordinates like in Caffe*
294                                      tensorflow - calculate box coordinates like in the TensorFlow*
295                                                   Object Detection API models
296                     Default value: "" (empty string)
297                     Required: no
298     Example of attribute dictionary:
299     ~~~~~~~~~~~~~~~~~~~~~~~~{.py}
300         # just required ones
301         attrs = {
302             'base_size': 85,
303             'pre_nms_topn': 10,
304             'post_nms_topn': 20,
305             'nms_thresh': 0.34,
306             'feat_stride': 16,
307             'min_size': 32,
308             'ratio': [0.1, 1.5, 2.0, 2.5],
309             'scale': [2, 3, 3, 4],
310         }
311     ~~~~~~~~~~~~~~~~~~~~~~~~
312     Optional attributes which are absent from dictionary will be set with corresponding default.
313     @return Node representing Proposal operation.
314     """
315     requirements = [
316         ("base_size", True, np.unsignedinteger, is_positive_value),
317         ("pre_nms_topn", True, np.unsignedinteger, is_positive_value),
318         ("post_nms_topn", True, np.unsignedinteger, is_positive_value),
319         ("nms_thresh", True, np.floating, is_positive_value),
320         ("feat_stride", True, np.unsignedinteger, is_positive_value),
321         ("min_size", True, np.unsignedinteger, is_positive_value),
322         ("ratio", True, np.floating, None),
323         ("scale", True, np.floating, None),
324         ("clip_before_nms", False, np.bool_, None),
325         ("clip_after_nms", False, np.bool_, None),
326         ("normalize", False, np.bool_, None),
327         ("box_size_scale", False, np.floating, is_positive_value),
328         ("box_coordinate_scale", False, np.floating, is_positive_value),
329         ("framework", False, np.str_, None),
330     ]
331
332     check_valid_attributes("Proposal", attrs, requirements)
333
334     return _get_node_factory_opset4().create(
335         "Proposal", [class_probs, bbox_deltas, as_node(image_shape)], attrs
336     )
337
338
339 @nameable_op
340 def reduce_l1(
341     node: NodeInput, reduction_axes: NodeInput, keep_dims: bool = False, name: Optional[str] = None
342 ) -> Node:
343     """! L1-reduction operation on input tensor, eliminating the specified reduction axes.
344
345     @param node:           The tensor we want to mean-reduce.
346     @param reduction_axes: The axes to eliminate through mean operation.
347     @param keep_dims:      If set to True it holds axes that are used for reduction
348     @param name:           Optional name for output node.
349     @return The new node performing mean-reduction operation.
350     """
351     return _get_node_factory_opset4().create(
352         "ReduceL1", as_nodes(node, reduction_axes), {"keep_dims": keep_dims}
353     )
354
355
356 @nameable_op
357 def reduce_l2(
358     node: NodeInput, reduction_axes: NodeInput, keep_dims: bool = False, name: Optional[str] = None
359 ) -> Node:
360     """! L2-reduction operation on input tensor, eliminating the specified reduction axes.
361
362     @param node:           The tensor we want to mean-reduce.
363     @param reduction_axes: The axes to eliminate through mean operation.
364     @param keep_dims:      If set to True it holds axes that are used for reduction
365     @param name:           Optional name for output node.
366     @return The new node performing mean-reduction operation.
367     """
368     return _get_node_factory_opset4().create(
369         "ReduceL2", as_nodes(node, reduction_axes), {"keep_dims": keep_dims}
370     )
371
372
373 @nameable_op
374 def lstm_cell(
375     X: NodeInput,
376     initial_hidden_state: NodeInput,
377     initial_cell_state: NodeInput,
378     W: NodeInput,
379     R: NodeInput,
380     B: NodeInput,
381     hidden_size: int,
382     activations: List[str] = None,
383     activations_alpha: List[float] = None,
384     activations_beta: List[float] = None,
385     clip: float = 0.0,
386     name: Optional[str] = None,
387 ) -> Node:
388     """! Return a node which performs LSTMCell operation.
389
390     @param X: The input tensor with shape: [batch_size, input_size].
391     @param initial_hidden_state: The hidden state tensor with shape: [batch_size, hidden_size].
392     @param initial_cell_state: The cell state tensor with shape: [batch_size, hidden_size].
393     @param W: The weight tensor with shape: [4*hidden_size, input_size].
394     @param R: The recurrence weight tensor with shape: [4*hidden_size, hidden_size].
395     @param B: The bias tensor for gates with shape: [4*hidden_size].
396     @param hidden_size: Specifies hidden state size.
397     @param activations: The list of three activation functions for gates.
398     @param activations_alpha: The list of alpha parameters for activation functions.
399     @param activations_beta: The list of beta parameters for activation functions.
400     @param clip: Specifies bound values [-C, C] for tensor clipping performed before activations.
401     @param name: An optional name of the output node.
402
403     @return The new node represents LSTMCell. Node outputs count: 2.
404     """
405     if activations is None:
406         activations = ["sigmoid", "tanh", "tanh"]
407     if activations_alpha is None:
408         activations_alpha = []
409     if activations_beta is None:
410         activations_beta = []
411
412     node_inputs = as_nodes(X, initial_hidden_state, initial_cell_state, W, R, B)
413
414     attributes = {
415         "hidden_size": hidden_size,
416         "activations": activations,
417         "activations_alpha": activations_alpha,
418         "activations_beta": activations_beta,
419         "clip": clip,
420     }
421     return _get_node_factory_opset4().create("LSTMCell", node_inputs, attributes)