Publishing 2019 R1 content
[platform/upstream/dldt.git] / model-optimizer / mo / front / caffe / extractors / utils.py
1 """
2  Copyright (c) 2018-2019 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 import numpy as np
18
19
20 def dim_to_shape(dim):
21     """
22     Extracts proto message with shape dimensions to shape expressed as np.array.
23     Args:
24         dim: proto message with shape dimensions
25
26     Returns:
27         shape of the layer as np.array
28     """
29     return np.array(dim, dtype=np.int64)
30
31
32 def embed_input(attrs: dict, port: int, name: str, value: np.array, bin_name: str = None):
33     """
34     Appends port information to the given set of attributes of the current layer.
35     Mutates passed attributes.
36     Args:
37         attrs: dictionary of existing attributes
38         port: relative number of the port for the layer
39         name: name of the input
40         value: np.array of values
41         bin_name: optional, representing the specific behavior of the blob,
42          either 'weights' or 'biases'
43
44     Returns:
45         mutated attributes dictionary with new properties under 'embedded_inputs' key
46
47     """
48     assert name not in attrs
49     attrs[name] = np.array(value)
50
51     if 'embedded_inputs' not in attrs:
52         attrs['embedded_inputs'] = []
53     if not bin_name:
54         bin_name = name
55     input_val = (port, name, {'bin': bin_name})
56     # (input index, input name, future edge attributes)
57     attrs['embedded_inputs'].append(input_val)  # pylint: disable=not-callable
58
59
60 def weights_biases(bias_term: bool, model_layer, start_index: int = 1, proto={}):
61     """
62     Creates object with configured inputs in the following order: 0: weights, 1: biases
63     Args:
64         bias_term: flag to whether include biases in the final input or not
65         model_layer: caffemodel layer containing values in blobs
66
67     Returns:
68         dictionary with set up inputs or empty dictionary
69     """
70     attrs = {}
71     if not model_layer:
72         if proto != {}:
73             if proto.weight_filler:
74                 if proto.weight_filler.type == "diagonal":
75                     data_len = proto.kernel_size[0] * proto.kernel_size[0] * proto.num_output
76                     data = np.zeros(data_len * data_len, dtype=np.float32)
77                     for i in range(0, data_len):
78                         data[i * (data_len + 1)] = proto.weight_filler.diag_val[i]
79
80                     bias = np.zeros(proto.num_output, np.float32)
81                     embed_input(attrs, start_index, 'weights', data)
82                     if bias_term:
83                         embed_input(attrs, start_index + 1, 'biases', bias)
84
85         return attrs
86
87     blobs = model_layer.blobs
88     embed_input(attrs, start_index, 'weights', blobs[0].data)
89     if bias_term:
90         embed_input(attrs, start_index + 1, 'biases', blobs[1].data)
91     return attrs
92
93
94 def get_list_from_container(param, prop: str, t):
95     """
96     Takes proto parameter and extracts a value it stores.
97     Args:
98         param: proto parameter
99         prop: name of the property to take
100         t: type of the value (int, float etc.) - only primitive ones
101
102     Returns:
103         If it is a container, returns the list with values.
104         If it is a single value of the given type - a list of single value.
105         If neither or property does not exist for param - empty list.
106     """
107     if not param or (param and not hasattr(param, prop)):
108         return []
109
110     prop_val = getattr(param, prop)
111
112     if not prop_val:
113         return []
114     elif isinstance(prop_val, t):
115         return [prop_val]
116     elif len(prop_val) > 0:
117         return prop_val
118     return []
119
120
121 def get_spatial_attr(default: list, single_name: str, name: str, param):
122     attr_h = default[1]
123     attr_w = default[0]
124     if hasattr(param, '{}_h'.format(name)):
125         if getattr(param, '{}_h'.format(name)) != default[1] and getattr(param, '{}_h'.format(name)) != 0:
126             attr_h = getattr(param, '{}_h'.format(name))
127     if hasattr(param, '{}_w'.format(name)):
128         if getattr(param, '{}_w'.format(name)) != default[0] and getattr(param, '{}_w'.format(name)) != 0:
129             attr_w = getattr(param, '{}_w'.format(name))
130     if (not attr_h or not attr_w) or (attr_h == attr_w == default[0]):
131         attrs = get_list_from_container(param, single_name, int)
132         if len(attrs) > 0 and attrs != default:
133             attr_w = attr_h = attrs[0]
134     return attr_w, attr_h
135
136
137 def merge_attrs(all_attrs: dict, update_attrs: dict):
138     mandatory_attrs = set(all_attrs.keys()).intersection(set(update_attrs.keys()))
139     return {value: update_attrs[value] for value in mandatory_attrs}
140
141
142 def get_canonical_axis_index(shape, axis):
143     return len(shape) + axis if axis < 0 else axis