blob: 6e640b51ca71d62e17d8d352216971c8c2bf8847 [file] [log] [blame]
Louis Verhaardfa2f92a2020-09-21 11:56:18 +02001# Copyright (C) 2020 Arm Limited or its affiliates. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
4#
5# Licensed under the Apache License, Version 2.0 (the License); you may
6# not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an AS IS BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17# Description:
18# Unit tests for support_operators
Michael McGeagh37ded342020-10-01 15:37:44 +010019import numpy as np
20
Louis Verhaardfa2f92a2020-09-21 11:56:18 +020021from ethosu.vela.data_type import DataType
Louis Verhaardaee5d752020-09-30 09:01:52 +020022from ethosu.vela.operation import Op
Louis Verhaardfa2f92a2020-09-21 11:56:18 +020023from ethosu.vela.supported_operators import SupportedOperators
24from ethosu.vela.tensor import create_const_tensor
Michael McGeagh37ded342020-10-01 15:37:44 +010025from ethosu.vela.tensor import QuantizationParameters
Louis Verhaardfa2f92a2020-09-21 11:56:18 +020026from ethosu.vela.tensor import Tensor
27from ethosu.vela.test import testutil
28
29support = SupportedOperators()
30
31
32def create_strided_slice_op(in_shape, out_shape, start_offsets, end_offsets):
Dwight Lidman8359a472020-09-28 15:53:40 +020033 qp = QuantizationParameters()
Louis Verhaardfa2f92a2020-09-21 11:56:18 +020034 in0 = Tensor(in_shape, DataType.uint8, "in")
Dwight Lidman8359a472020-09-28 15:53:40 +020035 in0.quantization = qp
36 in1 = create_const_tensor("begin", [len(start_offsets)], DataType.uint8, start_offsets, quantization=qp)
37 in2 = create_const_tensor("end", [len(end_offsets)], DataType.uint8, end_offsets, quantization=qp)
38 in3 = create_const_tensor("strides", [len(end_offsets)], DataType.uint8, len(end_offsets) * [1], quantization=qp)
Louis Verhaardfa2f92a2020-09-21 11:56:18 +020039 out = Tensor(out_shape, DataType.uint8, "out")
Dwight Lidman8359a472020-09-28 15:53:40 +020040 out.quantization = qp
Louis Verhaardfa2f92a2020-09-21 11:56:18 +020041 attrs = {"ellipsis_mask": 0, "new_axis_mask": 0, "shrink_axis_mask": 0, "begin_mask": 0, "end_mask": 0}
Louis Verhaardaee5d752020-09-30 09:01:52 +020042 return testutil.create_op(Op.StridedSlice, [in0, in1, in2, in3], out, attrs=attrs)
Louis Verhaardfa2f92a2020-09-21 11:56:18 +020043
44
45def create_strided_slice():
46 # Creates a valid strided slice operator with some valid inputs/outputs
47 op = create_strided_slice_op([1, 10, 10, 10], [1, 5, 5, 10], [127, 2, 2, 0], [0, 7, -3, 0])
48 op.attrs["begin_mask"] = 1
49 op.attrs["end_mask"] = 9
50 assert support.is_operator_supported(op)
51 return op
52
53
54def test_strided_slice():
55 # Tests support for StridedSlice operator
56 op = create_strided_slice()
57 # Setting one of new_axis_mask/shrink_axis_mask to non-zero is ok
58 op.attrs["new_axis_mask"] = 2
59 assert support.is_operator_supported(op)
60 op = create_strided_slice()
61 op.attrs["shrink_axis_mask"] = 3
62 assert support.is_operator_supported(op)
63 # But setting both to non-zero is not supported
64 op.attrs["new_axis_mask"] = 2
65 assert not support.is_operator_supported(op)
66 # begin values must not be None
67 op.inputs[1].values = None
68 assert not support.is_operator_supported(op)
69 # Unsupported strides
70 op = create_strided_slice()
71 op.inputs[3].values = [1, 1, 2, 1]
72 assert not support.is_operator_supported(op)
73 # Wrong number of input tensors
74 op = create_strided_slice()
75 op.add_input_tensor(op.inputs[0].clone())
76 assert not support.is_operator_supported(op)
77 # Unsupported ellipsis mask
78 op = create_strided_slice()
79 op.attrs["ellipsis_mask"] = 1
80 assert not support.is_operator_supported(op)
81 # Examples where end offset <= begin offset
82 op = create_strided_slice()
83 op.inputs[1].values = [0, 7, 2, 0]
84 assert not support.is_operator_supported(op)
85 op = create_strided_slice()
86 op.inputs[2].values = [0, 7, 2, 0]
87 assert not support.is_operator_supported(op)
88 op = create_strided_slice()
89 op.attrs["begin_mask"] = 0
90 assert not support.is_operator_supported(op)
91 op = create_strided_slice()
92 op.attrs["end_mask"] = 0
93 assert not support.is_operator_supported(op)
Michael McGeagh37ded342020-10-01 15:37:44 +010094
95
96def test_constraint_tens_defined_shape():
97 # Tensors cannot have None in them
98 inp = Tensor([1, 8, None, 8], DataType.uint8, "in")
99 out = Tensor([1, 8, 8, 8], DataType.uint8, "out")
Louis Verhaardaee5d752020-09-30 09:01:52 +0200100 op = testutil.create_op(Op.Relu, [inp], out)
Michael McGeagh37ded342020-10-01 15:37:44 +0100101 assert not support.is_operator_supported(op)
102
103
Michael McGeagh184b2502020-10-09 17:19:52 +0100104def test_constraint_tens_output_shapeless():
Michael McGeagh37ded342020-10-01 15:37:44 +0100105 # Shapeless output is not allowed at all:
Louis Verhaardaee5d752020-09-30 09:01:52 +0200106 op = testutil.create_elemwise_op(Op.Mul, "scalar_mul", [1, 8, 8, 8], [1, 8, 8, 8], [])
Michael McGeagh37ded342020-10-01 15:37:44 +0100107 assert not support.is_operator_supported(op)
Michael McGeagh184b2502020-10-09 17:19:52 +0100108
109
110def test_constraint_tens_input_shapeless():
111 # Shapeless input is allowed if its of a certain type:
112 op = testutil.create_elemwise_op(Op.Mul, "scalar_mul", [1, 8, 8, 8], [], [1, 8, 8, 8])
113 assert support.is_operator_supported(op)
Michael McGeagh37ded342020-10-01 15:37:44 +0100114 # Invalid shapeless input due to op type:
115 inp = Tensor([], DataType.uint8, "in")
116 out = Tensor([1, 8, 8, 8], DataType.uint8, "out")
Louis Verhaardaee5d752020-09-30 09:01:52 +0200117 op = testutil.create_op(Op.Relu, [inp], out)
Michael McGeagh37ded342020-10-01 15:37:44 +0100118 assert not support.is_operator_supported(op)
119
120
121def test_constraint_tens_shape_size():
122 # Tensors cannot be > 4D
123 inp = Tensor([1, 1, 8, 8, 8], DataType.uint8, "in")
124 out = Tensor([1, 1, 8, 8, 8], DataType.uint8, "out")
Louis Verhaardaee5d752020-09-30 09:01:52 +0200125 op = testutil.create_op(Op.Relu, [inp], out)
Michael McGeagh37ded342020-10-01 15:37:44 +0100126 assert not support.is_operator_supported(op)
127
128
129def test_constraint_tens_dtype():
Michael McGeagh184b2502020-10-09 17:19:52 +0100130 # Tensors can only be of type uint8, int8, int16 and int32
Michael McGeagh37ded342020-10-01 15:37:44 +0100131 inp = Tensor([1, 8, 8, 8], DataType.float32, "in")
132 out = Tensor([1, 8, 8, 8], DataType.float32, "out")
Louis Verhaardaee5d752020-09-30 09:01:52 +0200133 op = testutil.create_op(Op.Relu, [inp], out)
Michael McGeagh37ded342020-10-01 15:37:44 +0100134 assert not support.is_operator_supported(op)
Michael McGeagh184b2502020-10-09 17:19:52 +0100135
136
137def test_constraint_tens_int32_ops():
Michael McGeagh37ded342020-10-01 15:37:44 +0100138 # For int32, only select op types are allowed:
Louis Verhaardaee5d752020-09-30 09:01:52 +0200139 op = testutil.create_elemwise_op(Op.Mul, "scalar_mul", [1, 8, 8, 8], [], [1, 8, 8, 8], DataType.int32)
Michael McGeagh37ded342020-10-01 15:37:44 +0100140 assert support.is_operator_supported(op)
141 inp = Tensor([1, 8, 8, 8], DataType.int32, "in")
142 out = Tensor([1, 8, 8, 8], DataType.int32, "out")
Louis Verhaardaee5d752020-09-30 09:01:52 +0200143 op = testutil.create_op(Op.Relu, [inp], out)
Michael McGeagh37ded342020-10-01 15:37:44 +0100144 assert not support.is_operator_supported(op)
145
146
147def test_constraint_tens_dimension():
148 # Tensors can only have values in the inclusive range of 1-65535
149 inp = Tensor([1, 8, 8, 0], DataType.uint8, "in")
150 out = Tensor([1, 8, 8, 0], DataType.uint8, "out")
Louis Verhaardaee5d752020-09-30 09:01:52 +0200151 op = testutil.create_op(Op.Relu, [inp], out)
Michael McGeagh37ded342020-10-01 15:37:44 +0100152 assert not support.is_operator_supported(op)
153 inp = Tensor([1, 8, 8, 65536], DataType.uint8, "in")
154 out = Tensor([1, 8, 8, 65536], DataType.uint8, "out")
Louis Verhaardaee5d752020-09-30 09:01:52 +0200155 op = testutil.create_op(Op.Relu, [inp], out)
Michael McGeagh37ded342020-10-01 15:37:44 +0100156 assert not support.is_operator_supported(op)
157
158
Michael McGeagh184b2502020-10-09 17:19:52 +0100159def test_constraint_tens_quant_none_check():
160 # Tensors must have quantization parameters
161 op = testutil.create_elemwise_op(Op.Mul, "scalar_mul", [1, 8, 8, 8], [], [1, 8, 8, 8], ifm2_quant=None)
162 assert not support.is_operator_supported(op)
163
164
165def test_constraint_tens_quant_scale():
166 # Quantization scale cannot be infinit
167 qp = QuantizationParameters()
168 qp.scale_f32 = np.inf
169 op = testutil.create_elemwise_op(Op.Mul, "scalar_mul", [1, 8, 8, 8], [], [1, 8, 8, 8], ifm_quant=qp)
170 assert not support.is_operator_supported(op)
171
172
Michael McGeagh37ded342020-10-01 15:37:44 +0100173def test_constraint_faf():
174 # Fused activation functions, if set, must be a valid op type
175 inp = Tensor([1, 8, 8, 8], DataType.uint8, "in")
176 out = Tensor([1, 8, 8, 8], DataType.uint8, "out")
Louis Verhaardaee5d752020-09-30 09:01:52 +0200177 op = testutil.create_op(Op.Relu, [inp], out)
178 op.activation = Op.Conv2D
Michael McGeagh37ded342020-10-01 15:37:44 +0100179 assert not support.is_operator_supported(op)