blob: d734f619f782ba205f2e18f78a7abdde4284454b [file] [log] [blame]
Richard Burtondc0c6ed2020-04-08 16:39:05 +01001# Copyright © 2020 Arm Ltd. All rights reserved.
2# SPDX-License-Identifier: MIT
3import os
4import stat
Cathal Corbett9f184c42021-11-10 12:14:39 +00005import numpy as np
Richard Burtondc0c6ed2020-04-08 16:39:05 +01006
7import pytest
8import pyarmnn as ann
9
alexander73010782021-10-18 19:17:24 +010010
Jan Eilers841aca12020-08-12 14:59:06 +010011def test_optimizer_options_default_values():
12 opt = ann.OptimizerOptions()
13 assert opt.m_ReduceFp32ToFp16 == False
14 assert opt.m_Debug == False
15 assert opt.m_ReduceFp32ToBf16 == False
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010016 assert opt.m_ImportEnabled == False
alexander73010782021-10-18 19:17:24 +010017 assert opt.m_shapeInferenceMethod == ann.ShapeInferenceMethod_ValidateOnly
18
Jan Eilers841aca12020-08-12 14:59:06 +010019
20def test_optimizer_options_set_values1():
21 opt = ann.OptimizerOptions(True, True)
22 assert opt.m_ReduceFp32ToFp16 == True
23 assert opt.m_Debug == True
24 assert opt.m_ReduceFp32ToBf16 == False
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010025 assert opt.m_ImportEnabled == False
alexander73010782021-10-18 19:17:24 +010026 assert opt.m_shapeInferenceMethod == ann.ShapeInferenceMethod_ValidateOnly
27
Jan Eilers841aca12020-08-12 14:59:06 +010028
29def test_optimizer_options_set_values2():
30 opt = ann.OptimizerOptions(False, False, True)
31 assert opt.m_ReduceFp32ToFp16 == False
32 assert opt.m_Debug == False
33 assert opt.m_ReduceFp32ToBf16 == True
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010034 assert opt.m_ImportEnabled == False
alexander73010782021-10-18 19:17:24 +010035 assert opt.m_shapeInferenceMethod == ann.ShapeInferenceMethod_ValidateOnly
36
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010037
38def test_optimizer_options_set_values3():
alexander73010782021-10-18 19:17:24 +010039 opt = ann.OptimizerOptions(False, False, True, ann.ShapeInferenceMethod_InferAndValidate, True)
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010040 assert opt.m_ReduceFp32ToFp16 == False
41 assert opt.m_Debug == False
42 assert opt.m_ReduceFp32ToBf16 == True
43 assert opt.m_ImportEnabled == True
alexander73010782021-10-18 19:17:24 +010044 assert opt.m_shapeInferenceMethod == ann.ShapeInferenceMethod_InferAndValidate
45
Richard Burtondc0c6ed2020-04-08 16:39:05 +010046
47@pytest.fixture(scope="function")
48def get_runtime(shared_data_folder, network_file):
49 parser= ann.ITfLiteParser()
50 preferred_backends = [ann.BackendId('CpuAcc'), ann.BackendId('CpuRef')]
51 network = parser.CreateNetworkFromBinaryFile(os.path.join(shared_data_folder, network_file))
52 options = ann.CreationOptions()
53 runtime = ann.IRuntime(options)
54
55 yield preferred_backends, network, runtime
56
57
58@pytest.mark.parametrize("network_file",
59 [
60 'mock_model.tflite',
61 ],
62 ids=['mock_model'])
63def test_optimize_executes_successfully(network_file, get_runtime):
64 preferred_backends = [ann.BackendId('CpuRef')]
65 network = get_runtime[1]
66 runtime = get_runtime[2]
67
68 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
69
70 assert len(messages) == 0, 'With only CpuRef, there should be no warnings irrelevant of architecture.'
71 assert opt_network
72
73
74@pytest.mark.parametrize("network_file",
75 [
76 'mock_model.tflite',
77 ],
78 ids=['mock_model'])
79def test_optimize_owned_by_python(network_file, get_runtime):
80 preferred_backends = get_runtime[0]
81 network = get_runtime[1]
82 runtime = get_runtime[2]
83
84 opt_network, _ = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
85 assert opt_network.thisown
86
87
88@pytest.mark.aarch64
89@pytest.mark.parametrize("network_file",
90 [
91 'mock_model.tflite'
92 ],
93 ids=['mock_model'])
94def test_optimize_executes_successfully_for_neon_backend_only(network_file, get_runtime):
95 preferred_backends = [ann.BackendId('CpuAcc')]
96 network = get_runtime[1]
97 runtime = get_runtime[2]
98
99 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
100 assert 0 == len(messages)
101 assert opt_network
102
103
104@pytest.mark.parametrize("network_file",
105 [
106 'mock_model.tflite'
107 ],
108 ids=['mock_model'])
109def test_optimize_fails_for_invalid_backends(network_file, get_runtime):
110 invalid_backends = [ann.BackendId('Unknown')]
111 network = get_runtime[1]
112 runtime = get_runtime[2]
113
114 with pytest.raises(RuntimeError) as err:
115 ann.Optimize(network, invalid_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
116
117 expected_error_message = "None of the preferred backends [Unknown ] are supported."
118 assert expected_error_message in str(err.value)
119
120
121@pytest.mark.parametrize("network_file",
122 [
123 'mock_model.tflite'
124 ],
125 ids=['mock_model'])
126def test_optimize_fails_for_no_backends_specified(network_file, get_runtime):
127 empty_backends = []
128 network = get_runtime[1]
129 runtime = get_runtime[2]
130
131 with pytest.raises(RuntimeError) as err:
132 ann.Optimize(network, empty_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
133
134 expected_error_message = "Invoked Optimize with no backends specified"
135 assert expected_error_message in str(err.value)
136
137
138@pytest.mark.parametrize("network_file",
139 [
140 'mock_model.tflite'
141 ],
142 ids=['mock_model'])
143def test_serialize_to_dot(network_file, get_runtime, tmpdir):
144 preferred_backends = get_runtime[0]
145 network = get_runtime[1]
146 runtime = get_runtime[2]
147 opt_network, _ = ann.Optimize(network, preferred_backends,
148 runtime.GetDeviceSpec(), ann.OptimizerOptions())
149 dot_file_path = os.path.join(tmpdir, 'mock_model.dot')
150 """Check that serialized file does not exist at the start, gets created after SerializeToDot and is not empty"""
151 assert not os.path.exists(dot_file_path)
152 opt_network.SerializeToDot(dot_file_path)
153
154 assert os.path.exists(dot_file_path)
155
156 with open(dot_file_path) as res_file:
157 expected_data = res_file.read()
158 assert len(expected_data) > 1
159 assert '[label=< [1,28,28,1] >]' in expected_data
160
161
162@pytest.mark.x86_64
163@pytest.mark.parametrize("network_file",
164 [
165 'mock_model.tflite'
166 ],
167 ids=['mock_model'])
168def test_serialize_to_dot_mode_readonly(network_file, get_runtime, tmpdir):
169 preferred_backends = get_runtime[0]
170 network = get_runtime[1]
171 runtime = get_runtime[2]
172 opt_network, _ = ann.Optimize(network, preferred_backends,
173 runtime.GetDeviceSpec(), ann.OptimizerOptions())
174 """Create file, write to it and change mode to read-only"""
175 dot_file_path = os.path.join(tmpdir, 'mock_model.dot')
176 f = open(dot_file_path, "w+")
177 f.write("test")
178 f.close()
179 os.chmod(dot_file_path, stat.S_IREAD)
180 assert os.path.exists(dot_file_path)
181
182 with pytest.raises(RuntimeError) as err:
183 opt_network.SerializeToDot(dot_file_path)
184
185 expected_error_message = "Failed to open dot file"
186 assert expected_error_message in str(err.value)
187
188
189@pytest.mark.parametrize("method", [
190 'AddActivationLayer',
191 'AddAdditionLayer',
192 'AddArgMinMaxLayer',
193 'AddBatchNormalizationLayer',
194 'AddBatchToSpaceNdLayer',
Teresa Charlin87dc8122021-11-22 15:34:26 +0000195 'AddCastLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100196 'AddComparisonLayer',
197 'AddConcatLayer',
198 'AddConstantLayer',
199 'AddConvolution2dLayer',
200 'AddDepthToSpaceLayer',
201 'AddDepthwiseConvolution2dLayer',
202 'AddDequantizeLayer',
203 'AddDetectionPostProcessLayer',
204 'AddDivisionLayer',
205 'AddElementwiseUnaryLayer',
206 'AddFloorLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100207 'AddFillLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100208 'AddFullyConnectedLayer',
209 'AddGatherLayer',
210 'AddInputLayer',
211 'AddInstanceNormalizationLayer',
Cathal Corbettf0836e02021-11-18 18:17:38 +0000212 'AddLogicalBinaryLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100213 'AddLogSoftmaxLayer',
214 'AddL2NormalizationLayer',
215 'AddLstmLayer',
216 'AddMaximumLayer',
217 'AddMeanLayer',
218 'AddMergeLayer',
219 'AddMinimumLayer',
220 'AddMultiplicationLayer',
221 'AddNormalizationLayer',
222 'AddOutputLayer',
223 'AddPadLayer',
224 'AddPermuteLayer',
225 'AddPooling2dLayer',
226 'AddPreluLayer',
227 'AddQuantizeLayer',
228 'AddQuantizedLstmLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100229 'AddRankLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100230 'AddReshapeLayer',
231 'AddResizeLayer',
Ryan OSheaaeee9ad2021-11-18 17:43:55 +0000232 'AddShapeLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100233 'AddSliceLayer',
234 'AddSoftmaxLayer',
235 'AddSpaceToBatchNdLayer',
236 'AddSpaceToDepthLayer',
237 'AddSplitterLayer',
238 'AddStackLayer',
239 'AddStandInLayer',
240 'AddStridedSliceLayer',
241 'AddSubtractionLayer',
242 'AddSwitchLayer',
Cathal Corbett2b4182f2021-11-18 10:28:47 +0000243 'AddTransposeConvolution2dLayer',
244 'AddTransposeLayer'
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100245])
246def test_network_method_exists(method):
247 assert getattr(ann.INetwork, method, None)
248
249
250def test_fullyconnected_layer_optional_none():
251 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000252 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
253 ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100254
255 assert layer
256
257
258def test_fullyconnected_layer_optional_provided():
259 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000260 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
261 ann.ConstTensor(),
262 ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100263
264 assert layer
265
266
267def test_fullyconnected_layer_all_args():
268 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000269 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
270 ann.ConstTensor(),
271 ann.ConstTensor(),
272 'NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100273
274 assert layer
275 assert 'NAME1' == layer.GetName()
276
277
278def test_DepthwiseConvolution2d_layer_optional_none():
279 net = ann.INetwork()
280 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000281 weights=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100282
283 assert layer
284
285
286def test_DepthwiseConvolution2d_layer_optional_provided():
287 net = ann.INetwork()
288 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000289 weights=ann.ConstTensor(),
290 biases=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100291
292 assert layer
293
294
295def test_DepthwiseConvolution2d_layer_all_args():
296 net = ann.INetwork()
297 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000298 weights=ann.ConstTensor(),
299 biases=ann.ConstTensor(),
300 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100301
302 assert layer
303 assert 'NAME1' == layer.GetName()
304
305
306def test_Convolution2d_layer_optional_none():
307 net = ann.INetwork()
308 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000309 weights=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100310
311 assert layer
312
313
314def test_Convolution2d_layer_optional_provided():
315 net = ann.INetwork()
316 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000317 weights=ann.ConstTensor(),
318 biases=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100319
320 assert layer
321
322
323def test_Convolution2d_layer_all_args():
324 net = ann.INetwork()
325 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000326 weights=ann.ConstTensor(),
327 biases=ann.ConstTensor(),
328 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100329
330 assert layer
331 assert 'NAME1' == layer.GetName()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000332
333
334def test_add_constant_layer_to_fully_connected():
335
336 inputWidth = 1
337 inputHeight = 1
338 inputChannels = 5
339 inputNum = 2
340
341 outputChannels = 3
342 outputNum = 2
343
344 inputShape = ( inputNum, inputChannels, inputHeight, inputWidth )
345 outputShape = ( outputNum, outputChannels )
346 weightsShape = ( inputChannels, outputChannels )
347 biasShape = ( outputChannels, )
348
349 input = np.array([
350 [1.0, 2.0, 3.0, 4.0, 5.0],
351 [5.0, 4.0, 3.0, 2.0, 1.0]
352 ], dtype=np.float32)
353
354 weights = np.array([
355 [.5, 2., .5],
356 [.5, 2., 1.],
357 [.5, 2., 2.],
358 [.5, 2., 3.],
359 [.5, 2., 4.]
360 ], dtype=np.float32)
361
362 biasValues = np.array([10, 20, 30], dtype=np.float32)
363
364 expectedOutput = np.array([
365 [0.5 + 1.0 + 1.5 + 2.0 + 2.5 + biasValues[0],
366 2.0 + 4.0 + 6.0 + 8.0 + 10. + biasValues[1],
367 0.5 + 2.0 + 6.0 + 12. + 20. + biasValues[2]],
368 [2.5 + 2.0 + 1.5 + 1.0 + 0.5 + biasValues[0],
369 10.0 + 8.0 + 6.0 + 4.0 + 2. + biasValues[1],
370 2.5 + 4.0 + 6.0 + 6. + 4. + biasValues[2]]
371 ], dtype=np.float32)
372
373 network = ann.INetwork()
374
375 input_info = ann.TensorInfo(ann.TensorShape(inputShape), ann.DataType_Float32, 0, 0, True)
376 input_tensor = ann.ConstTensor(input_info, input)
377 input_layer = network.AddInputLayer(0, "input")
378
379 w_info = ann.TensorInfo(ann.TensorShape(weightsShape), ann.DataType_Float32, 0, 0, True)
380 w_tensor = ann.ConstTensor(w_info, weights)
381 w_layer = network.AddConstantLayer(w_tensor, "weights")
382
383 b_info = ann.TensorInfo(ann.TensorShape(biasShape), ann.DataType_Float32, 0, 0, True)
384 b_tensor = ann.ConstTensor(b_info, biasValues)
385 b_layer = network.AddConstantLayer(b_tensor, "bias")
386
387 fc_descriptor = ann.FullyConnectedDescriptor()
388 fc_descriptor.m_BiasEnabled = True
389 fc_descriptor.m_ConstantWeights = True
390 fully_connected = network.AddFullyConnectedLayer(fc_descriptor, "fc")
391
392 output_info = ann.TensorInfo(ann.TensorShape(outputShape), ann.DataType_Float32)
393 output_tensor = ann.Tensor(output_info, np.zeros([1, 1], dtype=np.float32))
394 output = network.AddOutputLayer(0, "output")
395
396 input_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(0))
397 w_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(1))
398 b_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(2))
399 fully_connected.GetOutputSlot(0).Connect(output.GetInputSlot(0))
400
401 input_layer.GetOutputSlot(0).SetTensorInfo(input_info)
402 w_layer.GetOutputSlot(0).SetTensorInfo(w_info)
403 b_layer.GetOutputSlot(0).SetTensorInfo(b_info)
404 fully_connected.GetOutputSlot(0).SetTensorInfo(output_info)
405
406 preferred_backends = [ann.BackendId('CpuRef')]
407 options = ann.CreationOptions()
408 runtime = ann.IRuntime(options)
409 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
410 net_id, messages = runtime.LoadNetwork(opt_network)
411
412 input_tensors = [(0, input_tensor)]
413 output_tensors = [(0, output_tensor)]
414 runtime.EnqueueWorkload(net_id, input_tensors, output_tensors)
415
416 output_vectors = ann.workload_tensors_to_ndarray(output_tensors)
417
418 assert (output_vectors==expectedOutput).all()