Publishing 2019 R1 content
[platform/upstream/dldt.git] / model-optimizer / mo / ops / convolution_test.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 unittest
18
19 import numpy as np
20
21 from mo.front.common.partial_infer.utils import int64_array
22 from mo.graph.graph import Node
23 from mo.ops.convolution import Convolution
24 from mo.utils.unittest.extractors import FakeValue
25 from mo.utils.unittest.graph import build_graph
26
27 nodes_attributes = {'conv_input': {'value': None, 'kind': 'data'},
28                     'conv_node': {'type': 'Convolution', 'kind': 'op'},
29                     'conv_weights': {'value': FakeValue(None), 'kind': 'data'},
30                     'conv_output': {'value': None, 'kind': 'data'},
31                     'output_op': { 'kind': 'op', 'op': 'OpOutput'}
32                     }
33
34
35 class TestConvolutionPartialInfer(unittest.TestCase):
36     def test_caffe_conv2d_infer(self):
37         graph = build_graph(nodes_attributes,
38                             [('conv_input', 'conv_node'),
39                              ('conv_weights', 'conv_node'),
40                              ('conv_node', 'conv_output'),
41                              ('conv_output', 'op_output')
42                              ],
43                             {'conv_output': {'shape': None},
44                              'conv_input': {'shape': np.array([1, 3, 227, 227])},
45                              'conv_weights': {'shape': np.array([64, 3, 3, 3]),
46                                               'dim_attrs': ['spatial_dims', 'channel_dims', 'batch_dims', 'axis']},
47                              'conv_node': {'pad_spatial_shape': np.array([[0, 0], [0, 0]]),
48                                            'conv_pad': np.array([[0, 0], [0, 0], [0, 0], [0, 0]]),
49                                            'dilation': np.array([1, 1, 1, 1]), 'bias_addable': True, 'bias_term': False,
50                                            'output_spatial_shape': None, 'output_shape': None,
51                                            'stride': np.array([1, 1, 1, 1]), 'group': 1,
52                                            'kernel_spatial_idx': np.array([2, 3]),
53                                            'input_feature_channel': 1,
54                                            'output_feature_channel': 0,
55                                            'output': 64, 'kernel_spatial': np.array([3, 3]),
56                                            'spatial_dims': np.array([2, 3]), 'channel_dims': np.array([1]),
57                                            'batch_dims': np.array([0])}
58                              })
59
60         conv_node = Node(graph, 'conv_node')
61         Convolution.infer(conv_node)
62         exp_shape = np.array([1, 64, 225, 225])
63         res_shape = graph.node['conv_output']['shape']
64         for i in range(0, len(exp_shape)):
65             self.assertEqual(exp_shape[i], res_shape[i])
66
67     def test_caffe_conv2d_infer_no_shape(self):
68         graph = build_graph(nodes_attributes,
69                             [('conv_input', 'conv_node'),
70                              ('conv_weights', 'conv_node'),
71                              ('conv_node', 'conv_output'),
72                              ('conv_output', 'op_output')
73                              ],
74                             {'conv_output': {'shape': None},
75                              'conv_input': {'shape': None},
76                              'conv_weights': {'shape': None,
77                                               'dim_attrs': ['spatial_dims', 'channel_dims', 'batch_dims', 'axis']},
78                              'conv_node': {'pad_spatial_shape': np.array([[0, 0], [0, 0]]),
79                                            'conv_pad': np.array([[0, 0], [0, 0], [0, 0], [0, 0]]),
80                                            'dilation': np.array([1, 1, 1, 1]), 'bias_addable': True, 'bias_term': False,
81                                            'output_spatial_shape': None, 'output_shape': None,
82                                            'stride': np.array([1, 1, 1, 1]), 'group': 1,
83                                            'output': 64, 'kernel_spatial': np.array([3, 3]),
84                                            'spatial_dims': np.array([2, 3]), 'channel_dims': np.array([1]),
85                                            'batch_dims': np.array([0])}
86                              })
87
88         conv_node = Node(graph, 'conv_node')
89         Convolution.infer(conv_node)
90         res_shape = graph.node['conv_output']['shape']
91         self.assertIsNone(res_shape)
92
93     def test_deconv_infer_ideal(self):
94         graph = build_graph(nodes_attributes,
95                             [('conv_input', 'conv_node'),
96                              ('conv_weights', 'conv_node'),
97                              ('conv_node', 'conv_output'),
98                              ('conv_output', 'op_output')
99                              ],
100                             {'conv_output': {'shape': None},
101                              'conv_input': {'shape': np.array([1, 21, 16, 16])},
102                              'conv_weights': {'shape': np.array([1, 21, 4, 4]),
103                                               'dim_attrs': ['spatial_dims', 'channel_dims', 'batch_dims', 'axis']},
104                              'conv_node': {#'spatial_dims': np.array([2, 3]), 'batch_dims': np.array([0]),
105                                            'channel_dims': np.array([1]), 'bias_addable': True, 'bias_term': False,
106                                            'batch_dims': np.array([0]),
107                                            'pad_spatial_shape': np.array([[0, 0], [0, 0]]),
108                                            'kernel_spatial': np.array([4, 4]), 'output_spatial_shape': None,
109                                            'kernel_spatial_idx': np.array([2, 3]),
110                                            'input_feature_channel': 1,
111                                            'output_feature_channel': 0,
112                                            'output_padding': np.array([0, 0, 1, 1]),
113                                            'type': 'Deconvolution', 'output': 21, 'dilation': np.array([1, 1, 1, 1]),
114                                            'group': 1, 'stride': np.array([1, 1, 2, 2]), 'output_shape': None}
115                              })
116
117         deconv_node = Node(graph, 'conv_node')
118
119         Convolution.infer(deconv_node)
120         res_shape = deconv_node['output_shape']
121         exp_shape = np.array([1, 21, 35, 35])
122
123         for i in range(0, len(exp_shape)):
124             self.assertEqual(exp_shape[i], res_shape[i])
125
126         # Check that after double infer shape and pad attrs do not changes
127         Convolution.infer(deconv_node)
128
129         for i in range(0, len(exp_shape)):
130             self.assertEqual(exp_shape[i], res_shape[i])
131
132
133     def test_deconv_infer_no_shape(self):
134         graph = build_graph(nodes_attributes,
135                             [('conv_input', 'conv_node'),
136                              ('conv_weights', 'conv_node'),
137                              ('conv_node', 'conv_output'),
138                              ('conv_output', 'op_output')
139                              ],
140                             {'conv_output': {'shape': None},
141                              'conv_input': {'shape': None},
142                              'conv_weights': {'shape': np.array([1, 21, 16, 16]),
143                                               'dim_attrs': ['spatial_dims', 'channel_dims', 'batch_dims', 'axis']},
144                              'conv_node': {'spatial_dims': np.array([2, 3]), 'batch_dims': np.array([0]),
145                                            'channel_dims': np.array([1]),
146                                            'pad_spatial_shape': np.array([[0, 0], [0, 0]]),
147                                            'kernel_spatial': np.array([4, 4]), 'output_spatial_shape': None,
148                                            'kernel_spatial_idx': np.array([2, 3]),
149                                            'input_feature_channel': 1,
150                                            'output_feature_channel': 0,
151                                            'type': 'Deconvolution', 'output': 21, 'dilation': np.array([1, 1, 1, 1]),
152                                            'group': 1, 'stride': np.array([1, 1, 2, 2]), 'output_shape': None}
153                              })
154
155         deconv_node = Node(graph, 'conv_node')
156         Convolution.infer(deconv_node)
157         res_shape = deconv_node['output_shape']
158         self.assertIsNone(res_shape)
159
160     def test_conv_infer_set_default_attrs_nchw(self):
161         graph = build_graph(nodes_attributes,
162                             [
163                                 ('conv_input', 'conv_node'),
164                                 ('conv_weights', 'conv_node'),
165                                 ('conv_node', 'conv_output'),
166                                 ('conv_output', 'op_output')
167                             ],
168                             {
169                                 'conv_output': {
170                                     'shape': None
171                                 },
172                                 'conv_input': {
173                                     'shape': int64_array([1, 3, 224, 224])
174                                 },
175                                 'conv_weights': {
176                                     'shape': int64_array([3, 64, 7, 7]),
177                                     'dim_attrs': ['spatial_dims', 'channel_dims', 'batch_dims', 'axis']
178                                 },
179                                 'conv_node': {
180                                     'type': 'Convolution',
181                                     'bias_term': None,
182                                     'stride': None,
183                                     'dilation': None,
184
185                                     'batch_dims': int64_array([0]),
186                                     'channel_dims': int64_array([1]),
187
188                                     'output_spatial_shape': None,
189
190                                     'input_feature_channel': 0,
191                                     'output_feature_channel': 1,
192
193                                     'group': 1,
194                                     'output_shape': None,
195                                     'layout': 'NCHW'
196                                 }
197                             })
198
199         conv_node = Node(graph, 'conv_node')
200         conv_output = Node(graph, 'conv_output')
201
202         Convolution.infer(conv_node)
203
204         # Check bias_term attribute
205         self.assertTrue(conv_node.has_valid('bias_term'))
206         self.assertTrue(not conv_node.bias_term)
207         # Check kernel_spatial_idx attr detection
208         self.assertTrue(conv_node.has_valid('kernel_spatial_idx'))
209         self.assertTrue(np.array_equal(int64_array([2, 3]), conv_node.kernel_spatial_idx))
210         # Check spatial_dims attr detection
211         self.assertTrue(conv_node.has_valid('spatial_dims'))
212         self.assertTrue(np.array_equal(int64_array([2, 3]), conv_node.spatial_dims))
213         # Check kernel_spatial attr detection
214         self.assertTrue(conv_node.has_valid('kernel_spatial'))
215         self.assertTrue(np.array_equal(int64_array([7, 7]), conv_node.kernel_spatial))
216         # Check output attribute
217         self.assertTrue(conv_node.has_valid('output'))
218         self.assertEqual(64, conv_node.output)
219         # Check dilation value. Should be set to default
220         self.assertTrue(conv_node.has_valid('dilation'))
221         self.assertTrue(np.array_equal(int64_array([1, 1, 1, 1]), conv_node.dilation))
222         # Check stride value. Should be set to default
223         self.assertTrue(conv_node.has_valid('stride'))
224         self.assertTrue(np.array_equal(int64_array([1, 1, 1, 1]), conv_node.stride))
225         # Check pad value. Should be set to default
226         self.assertTrue(conv_node.has_valid('pad'))
227         self.assertTrue(np.array_equal(int64_array([[0, 0], [0, 0], [0, 0], [0, 0]]), conv_node.pad))
228         # Check pad_spatial_shape
229         self.assertTrue(conv_node.has_valid('pad_spatial_shape'))
230         self.assertTrue(np.array_equal(int64_array([[0, 0], [0, 0]]), conv_node.pad_spatial_shape))
231         # Check resulting output shape
232         self.assertTrue(np.array_equal(int64_array([1, 64, 218, 218]), conv_output.shape))
233
234     def test_conv_infer_set_default_attrs_nhwc(self):
235         graph = build_graph(nodes_attributes,
236                             [
237                                 ('conv_input', 'conv_node'),
238                                 ('conv_weights', 'conv_node'),
239                                 ('conv_node', 'conv_output'),
240                                 ('conv_output', 'op_output')
241                             ],
242                             {
243                                 'conv_output': {
244                                     'shape': None
245                                 },
246                                 'conv_input': {
247                                     'shape': int64_array([1, 224, 224, 3])
248                                 },
249                                 'conv_weights': {
250                                     'shape': int64_array([3, 64, 7, 7]),
251                                     'dim_attrs': ['spatial_dims', 'channel_dims', 'batch_dims', 'axis']
252                                 },
253                                 'conv_node': {
254                                     'type': 'Convolution',
255                                     'bias_term': None,
256                                     'stride': None,
257                                     'dilation': None,
258
259                                     'batch_dims': int64_array([0]),
260                                     'channel_dims': int64_array([3]),
261
262                                     'output_spatial_shape': None,
263
264                                     'input_feature_channel': 0,
265                                     'output_feature_channel': 1,
266
267                                     'group': 1,
268                                     'output_shape': None,
269                                     'layout': 'NHWC'
270                                 }
271                             })
272
273         conv_node = Node(graph, 'conv_node')
274         conv_output = Node(graph, 'conv_output')
275
276         Convolution.infer(conv_node)
277
278         # Check bias_term attribute
279         self.assertTrue(conv_node.has_valid('bias_term'))
280         self.assertTrue(not conv_node.bias_term)
281         # Check kernel_spatial_idx attr detection
282         self.assertTrue(conv_node.has_valid('kernel_spatial_idx'))
283         self.assertTrue(np.array_equal(int64_array([2, 3]), conv_node.kernel_spatial_idx))
284         # Check spatial_dims attr detection
285         self.assertTrue(conv_node.has_valid('spatial_dims'))
286         self.assertTrue(np.array_equal(int64_array([1, 2]), conv_node.spatial_dims))
287         # Check kernel_spatial attr detection
288         self.assertTrue(conv_node.has_valid('kernel_spatial'))
289         self.assertTrue(np.array_equal(int64_array([7, 7]), conv_node.kernel_spatial))
290         # Check output attribute
291         self.assertTrue(conv_node.has_valid('output'))
292         self.assertEqual(64, conv_node.output)
293         # Check dilation value. Should be set to default
294         self.assertTrue(conv_node.has_valid('dilation'))
295         self.assertTrue(np.array_equal(int64_array([1, 1, 1, 1]), conv_node.dilation))
296         # Check stride value. Should be set to default
297         self.assertTrue(conv_node.has_valid('stride'))
298         self.assertTrue(np.array_equal(int64_array([1, 1, 1, 1]), conv_node.stride))
299         # Check pad value. Should be set to default
300         self.assertTrue(conv_node.has_valid('pad'))
301         self.assertTrue(np.array_equal(int64_array([[0, 0], [0, 0], [0, 0], [0, 0]]), conv_node.pad))
302         # Check pad_spatial_shape
303         self.assertTrue(conv_node.has_valid('pad_spatial_shape'))
304         self.assertTrue(np.array_equal(int64_array([[0, 0], [0, 0]]), conv_node.pad_spatial_shape))
305         # Check resulting output shape
306         self.assertTrue(np.array_equal(int64_array([1, 218, 218, 64]), conv_output.shape))
307
308     def test_conv_infer_3D_convolution(self):
309         graph = build_graph(nodes_attributes,
310                             [
311                                 ('conv_input', 'conv_node'),
312                                 ('conv_weights', 'conv_node'),
313                                 ('conv_node', 'conv_output'),
314                                 ('conv_output', 'op_output')
315                             ],
316                             {
317                                 'conv_output': {
318                                     'shape': None
319                                 },
320                                 'conv_input': {
321                                     'shape': int64_array([1, 3, 16, 224, 224])
322                                 },
323                                 'conv_weights': {
324                                     'shape': int64_array([3, 64, 1, 7, 7]),
325                                     'dim_attrs': ['spatial_dims', 'channel_dims', 'batch_dims', 'axis']
326                                 },
327                                 'conv_node': {
328                                     'type': 'Convolution',
329                                     'bias_term': None,
330                                     'stride': None,
331                                     'dilation': None,
332
333                                     'batch_dims': int64_array([0]),
334                                     'channel_dims': int64_array([1]),
335
336                                     'output_spatial_shape': None,
337
338                                     'input_feature_channel': 0,
339                                     'output_feature_channel': 1,
340
341                                     'group': 1,
342                                     'output_shape': None,
343                                     'layout': 'NCHW'
344                                 }
345                             })
346
347         conv_node = Node(graph, 'conv_node')
348         conv_output = Node(graph, 'conv_output')
349
350         Convolution.infer(conv_node)
351
352         # Check bias_term attribute
353         self.assertTrue(conv_node.has_valid('bias_term'))
354         self.assertTrue(not conv_node.bias_term)
355         # Check kernel_spatial_idx attr detection
356         self.assertTrue(conv_node.has_valid('kernel_spatial_idx'))
357         self.assertTrue(np.array_equal(int64_array([2, 3, 4]), conv_node.kernel_spatial_idx))
358         # Check spatial_dims attr detection
359         self.assertTrue(conv_node.has_valid('spatial_dims'))
360         self.assertTrue(np.array_equal(int64_array([2, 3, 4]), conv_node.spatial_dims))
361         # Check kernel_spatial attr detection
362         self.assertTrue(conv_node.has_valid('kernel_spatial'))
363         self.assertTrue(np.array_equal(int64_array([1, 7, 7]), conv_node.kernel_spatial))
364         # Check output attribute
365         self.assertTrue(conv_node.has_valid('output'))
366         self.assertEqual(64, conv_node.output)
367         # Check dilation value. Should be set to default
368         self.assertTrue(conv_node.has_valid('dilation'))
369         self.assertTrue(np.array_equal(int64_array([1, 1, 1, 1, 1]), conv_node.dilation))
370         # Check stride value. Should be set to default
371         self.assertTrue(conv_node.has_valid('stride'))
372         self.assertTrue(np.array_equal(int64_array([1, 1, 1, 1, 1]), conv_node.stride))
373         # Check pad value. Should be set to default
374         self.assertTrue(conv_node.has_valid('pad'))
375         self.assertTrue(np.array_equal(int64_array([[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]), conv_node.pad))
376         # Check pad_spatial_shape
377         self.assertTrue(conv_node.has_valid('pad_spatial_shape'))
378         self.assertTrue(np.array_equal(int64_array([[0, 0], [0, 0], [0, 0]]), conv_node.pad_spatial_shape))
379         # Check resulting output shape
380         self.assertTrue(np.array_equal(int64_array([1, 64, 16, 218, 218]), conv_output.shape))