blob: 4f37c473aca8ba41fa6aa085cf882a781d7cde7f [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',
195 'AddComparisonLayer',
196 'AddConcatLayer',
197 'AddConstantLayer',
198 'AddConvolution2dLayer',
199 'AddDepthToSpaceLayer',
200 'AddDepthwiseConvolution2dLayer',
201 'AddDequantizeLayer',
202 'AddDetectionPostProcessLayer',
203 'AddDivisionLayer',
204 'AddElementwiseUnaryLayer',
205 'AddFloorLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100206 'AddFillLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100207 'AddFullyConnectedLayer',
208 'AddGatherLayer',
209 'AddInputLayer',
210 'AddInstanceNormalizationLayer',
211 'AddLogSoftmaxLayer',
212 'AddL2NormalizationLayer',
213 'AddLstmLayer',
214 'AddMaximumLayer',
215 'AddMeanLayer',
216 'AddMergeLayer',
217 'AddMinimumLayer',
218 'AddMultiplicationLayer',
219 'AddNormalizationLayer',
220 'AddOutputLayer',
221 'AddPadLayer',
222 'AddPermuteLayer',
223 'AddPooling2dLayer',
224 'AddPreluLayer',
225 'AddQuantizeLayer',
226 'AddQuantizedLstmLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100227 'AddRankLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100228 'AddReshapeLayer',
229 'AddResizeLayer',
230 'AddSliceLayer',
231 'AddSoftmaxLayer',
232 'AddSpaceToBatchNdLayer',
233 'AddSpaceToDepthLayer',
234 'AddSplitterLayer',
235 'AddStackLayer',
236 'AddStandInLayer',
237 'AddStridedSliceLayer',
238 'AddSubtractionLayer',
239 'AddSwitchLayer',
240 'AddTransposeConvolution2dLayer'
241])
242def test_network_method_exists(method):
243 assert getattr(ann.INetwork, method, None)
244
245
246def test_fullyconnected_layer_optional_none():
247 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000248 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
249 ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100250
251 assert layer
252
253
254def test_fullyconnected_layer_optional_provided():
255 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000256 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
257 ann.ConstTensor(),
258 ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100259
260 assert layer
261
262
263def test_fullyconnected_layer_all_args():
264 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000265 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
266 ann.ConstTensor(),
267 ann.ConstTensor(),
268 'NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100269
270 assert layer
271 assert 'NAME1' == layer.GetName()
272
273
274def test_DepthwiseConvolution2d_layer_optional_none():
275 net = ann.INetwork()
276 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000277 weights=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100278
279 assert layer
280
281
282def test_DepthwiseConvolution2d_layer_optional_provided():
283 net = ann.INetwork()
284 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000285 weights=ann.ConstTensor(),
286 biases=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100287
288 assert layer
289
290
291def test_DepthwiseConvolution2d_layer_all_args():
292 net = ann.INetwork()
293 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000294 weights=ann.ConstTensor(),
295 biases=ann.ConstTensor(),
296 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100297
298 assert layer
299 assert 'NAME1' == layer.GetName()
300
301
302def test_Convolution2d_layer_optional_none():
303 net = ann.INetwork()
304 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000305 weights=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100306
307 assert layer
308
309
310def test_Convolution2d_layer_optional_provided():
311 net = ann.INetwork()
312 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000313 weights=ann.ConstTensor(),
314 biases=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100315
316 assert layer
317
318
319def test_Convolution2d_layer_all_args():
320 net = ann.INetwork()
321 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000322 weights=ann.ConstTensor(),
323 biases=ann.ConstTensor(),
324 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100325
326 assert layer
327 assert 'NAME1' == layer.GetName()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000328
329
330def test_add_constant_layer_to_fully_connected():
331
332 inputWidth = 1
333 inputHeight = 1
334 inputChannels = 5
335 inputNum = 2
336
337 outputChannels = 3
338 outputNum = 2
339
340 inputShape = ( inputNum, inputChannels, inputHeight, inputWidth )
341 outputShape = ( outputNum, outputChannels )
342 weightsShape = ( inputChannels, outputChannels )
343 biasShape = ( outputChannels, )
344
345 input = np.array([
346 [1.0, 2.0, 3.0, 4.0, 5.0],
347 [5.0, 4.0, 3.0, 2.0, 1.0]
348 ], dtype=np.float32)
349
350 weights = np.array([
351 [.5, 2., .5],
352 [.5, 2., 1.],
353 [.5, 2., 2.],
354 [.5, 2., 3.],
355 [.5, 2., 4.]
356 ], dtype=np.float32)
357
358 biasValues = np.array([10, 20, 30], dtype=np.float32)
359
360 expectedOutput = np.array([
361 [0.5 + 1.0 + 1.5 + 2.0 + 2.5 + biasValues[0],
362 2.0 + 4.0 + 6.0 + 8.0 + 10. + biasValues[1],
363 0.5 + 2.0 + 6.0 + 12. + 20. + biasValues[2]],
364 [2.5 + 2.0 + 1.5 + 1.0 + 0.5 + biasValues[0],
365 10.0 + 8.0 + 6.0 + 4.0 + 2. + biasValues[1],
366 2.5 + 4.0 + 6.0 + 6. + 4. + biasValues[2]]
367 ], dtype=np.float32)
368
369 network = ann.INetwork()
370
371 input_info = ann.TensorInfo(ann.TensorShape(inputShape), ann.DataType_Float32, 0, 0, True)
372 input_tensor = ann.ConstTensor(input_info, input)
373 input_layer = network.AddInputLayer(0, "input")
374
375 w_info = ann.TensorInfo(ann.TensorShape(weightsShape), ann.DataType_Float32, 0, 0, True)
376 w_tensor = ann.ConstTensor(w_info, weights)
377 w_layer = network.AddConstantLayer(w_tensor, "weights")
378
379 b_info = ann.TensorInfo(ann.TensorShape(biasShape), ann.DataType_Float32, 0, 0, True)
380 b_tensor = ann.ConstTensor(b_info, biasValues)
381 b_layer = network.AddConstantLayer(b_tensor, "bias")
382
383 fc_descriptor = ann.FullyConnectedDescriptor()
384 fc_descriptor.m_BiasEnabled = True
385 fc_descriptor.m_ConstantWeights = True
386 fully_connected = network.AddFullyConnectedLayer(fc_descriptor, "fc")
387
388 output_info = ann.TensorInfo(ann.TensorShape(outputShape), ann.DataType_Float32)
389 output_tensor = ann.Tensor(output_info, np.zeros([1, 1], dtype=np.float32))
390 output = network.AddOutputLayer(0, "output")
391
392 input_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(0))
393 w_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(1))
394 b_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(2))
395 fully_connected.GetOutputSlot(0).Connect(output.GetInputSlot(0))
396
397 input_layer.GetOutputSlot(0).SetTensorInfo(input_info)
398 w_layer.GetOutputSlot(0).SetTensorInfo(w_info)
399 b_layer.GetOutputSlot(0).SetTensorInfo(b_info)
400 fully_connected.GetOutputSlot(0).SetTensorInfo(output_info)
401
402 preferred_backends = [ann.BackendId('CpuRef')]
403 options = ann.CreationOptions()
404 runtime = ann.IRuntime(options)
405 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
406 net_id, messages = runtime.LoadNetwork(opt_network)
407
408 input_tensors = [(0, input_tensor)]
409 output_tensors = [(0, output_tensor)]
410 runtime.EnqueueWorkload(net_id, input_tensors, output_tensors)
411
412 output_vectors = ann.workload_tensors_to_ndarray(output_tensors)
413
414 assert (output_vectors==expectedOutput).all()