blob: e2cdc20532da4d0fc2426fbf99b2443b3ee9c1f0 [file] [log] [blame]
Johan Alfven90724962023-02-02 09:07:48 +01001# SPDX-FileCopyrightText: Copyright 2020-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +01002#
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.
Rickard Bolinbc6ee582022-11-04 08:24:29 +000016#
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +010017# Description:
18# Utility functions for creating Network Operations.
19from typing import Optional
Fredrik Svedberge82be7c2021-01-18 15:21:03 +010020from typing import Tuple
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +010021
Johan Alfvenc1ad80b2023-03-31 10:19:23 +020022import numpy as np
23
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +010024from .data_type import DataType
25from .high_level_command_to_npu_op import ifm_ifm2_correct_order
26from .operation import ActivationFunction
27from .operation import Op
28from .operation import Operation
Michael McGeagh16895482020-12-14 15:51:20 +000029from .operation import Padding
Fredrik Svedberg0ac08042023-04-11 22:35:04 +020030from .reader_util import clone_and_reshape_tensor
Patrik Gustavsson3a269202021-01-21 08:28:55 +010031from .shape4d import Shape4D
Johan Alfvenc1ad80b2023-03-31 10:19:23 +020032from .tensor import create_const_tensor
Fredrik Svedberg0ac08042023-04-11 22:35:04 +020033from .tensor import create_equivalence_id
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +010034from .tensor import QuantizationParameters
35from .tensor import Tensor
36
37
38def create_avgpool_nop(name: str) -> Operation:
39 op = Operation(Op.AvgPool, name)
Michael McGeagh16895482020-12-14 15:51:20 +000040 op.attrs["padding"] = Padding.VALID
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +010041 op.attrs["stride_w"] = 1
42 op.attrs["stride_h"] = 1
43 op.attrs["filter_width"] = 1
44 op.attrs["filter_height"] = 1
45 op.attrs["strides"] = [1, 1, 1, 1]
46 op.attrs["ksize"] = [1, 1, 1, 1]
47 op.attrs["skirt"] = [0, 0, 0, 0]
Patrik Gustavssonc74682c2021-08-17 14:26:38 +020048 op.attrs["explicit_padding"] = [0, 0, 0, 0] # [top, left, bottom, right]
Louis Verhaardc822d622021-03-11 14:59:06 +010049 op.run_on_npu = True
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +010050 return op
51
52
Patrik Gustavssonf1580f02021-09-01 12:43:02 +020053def create_add_nop(name: str) -> Operation:
54 op = Operation(Op.Add, name)
55 op.run_on_npu = True
56 return op
57
58
Johan Alfvenc1ad80b2023-03-31 10:19:23 +020059def create_memcpy(
60 name: str,
61 ifm: Tensor,
62 ofm: Tensor,
63) -> Operation:
Johan Alfven90724962023-02-02 09:07:48 +010064 op = Operation(Op.Memcpy, name)
65 op.run_on_npu = True
Johan Alfvenc1ad80b2023-03-31 10:19:23 +020066 op.add_input_tensor(ifm)
67 op.set_output_tensor(ofm)
68 op.set_ifm_ofm_shapes()
Johan Alfven90724962023-02-02 09:07:48 +010069 return op
70
71
Patrik Gustavssonb4936ad2021-10-05 13:53:34 +020072def create_pad_nop(name: str) -> Operation:
73 op = Operation(Op.Pad, name)
74 op.run_on_npu = True
75 return op
76
77
Johan Alfvenc1ad80b2023-03-31 10:19:23 +020078def create_cast_op(
79 name: str,
80 ifm: Tensor,
81 ofm: Tensor,
82) -> Operation:
83 op = Operation(Op.DepthwiseConv2DBias, name)
84 op_attrs = {
85 "padding": Padding.VALID,
86 "stride_h": 1,
87 "stride_w": 1,
88 "strides": (1, 1, 1, 1),
89 "depth_multiplier": 1,
90 "channel_multiplier": 1,
91 "dilation_h_factor": 1,
92 "dilation_w_factor": 1,
93 "dilation": (1, 1, 1, 1),
94 "explicit_padding": None,
95 }
96 op.attrs.update(op_attrs)
97 op.add_input_tensor(ifm)
98
99 c = ifm.shape[-1]
100
Johan Alfven7972ee82023-10-03 14:46:22 +0200101 # Weigth shape is in format [h, w, b, c] for DepthwiseConv2D
102 shape = [1, 1, 1, c]
Johan Alfvenc1ad80b2023-03-31 10:19:23 +0200103 kernel = np.dstack([1] * c)
104 identity_quant = QuantizationParameters(scale_f32=1.0, zero_point=0)
105 op.add_input_tensor(
106 create_const_tensor(
107 op.name + "_weights",
108 shape,
109 DataType.uint8,
110 np.array(kernel).reshape(shape),
111 quantization=identity_quant,
112 ),
113 )
Johan Alfven7972ee82023-10-03 14:46:22 +0200114 # Set flag to indicate that weights are already in correct order
115 # and prevent that they are transposed in reorder_depthwise_weights
116 op.inputs[1].weight_transpose_depthwise = True
Johan Alfvenc1ad80b2023-03-31 10:19:23 +0200117 bias_values = [0] * c
118 dtype = DataType.int64 if op.ifm.dtype == DataType.int16 else DataType.int32
119 op.add_input_tensor(create_const_tensor(op.name + "_bias", [c], dtype, bias_values))
120 op.set_output_tensor(ofm)
121 op.set_ifm_ofm_shapes()
122
123 return op
124
125
Fredrik Svedberg0ac08042023-04-11 22:35:04 +0200126def create_fused_activation(op_type: Op, name: str, ifm: Tensor, quantization: QuantizationParameters) -> Operation:
127 assert op_type.is_activation_op()
128 op = create_avgpool_nop(name)
129 op.activation = ActivationFunction(op_type)
130 ofm = Tensor(ifm.shape, ifm.dtype, f"{op.name}_tens0")
131 ofm.quantization = quantization
132 op.add_input_tensor(ifm)
133 op.set_output_tensor(ofm)
134 op.set_ifm_ofm_shapes()
135 return op
136
137
138def create_fullyconnected(
139 name: str,
140 ifm: Tensor,
141 weights: Tensor,
142 bias: Optional[Tensor],
143 quantization: QuantizationParameters,
144 vela_weight_order: bool = True,
145) -> Operation:
146 # Reshape weights if needed
147 if not vela_weight_order:
148 weights = clone_and_reshape_tensor(weights, (1, 0), False)
149
150 n_ofm = weights.shape[-1]
151
152 # Setup bias if needed
153 if not bias:
154 bias_values = [0] * n_ofm
155 dtype = DataType.int64 if ifm.dtype == DataType.int16 else DataType.int32
156 bias = create_const_tensor(f"{name}_bias", [n_ofm], dtype, bias_values)
157 # Set equivalence_id based on values to avoid placing duplicate data in flash
158 bias.equivalence_id = create_equivalence_id(tuple(bias_values))
159 bias.value_id = bias.equivalence_id
160
161 # Setup ofm
162 ofm = Tensor([ifm.shape[0], n_ofm], ifm.dtype, f"{name}_tens0")
163 ofm.quantization = quantization
164
165 # Create op and add tensors
166 op = Operation(Op.FullyConnected, name)
167 op.add_input_tensor(ifm)
168 op.add_input_tensor(weights)
169 op.add_input_tensor(bias)
170 op.set_output_tensor(ofm)
171 op.set_ifm_ofm_shapes()
172 return op
173
174
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100175def create_depthwise_maxpool(
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100176 name: str,
177 ifm: Tensor,
178 inp_shape: Shape4D,
179 quantization: QuantizationParameters,
180 activation: Optional[ActivationFunction] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100181) -> Operation:
182 op = Operation(Op.MaxPool, name)
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100183 height = inp_shape.height * inp_shape.width
184 width = inp_shape.depth
185 ifm_shape = Shape4D([1, height, width, 1])
186
Michael McGeagh16895482020-12-14 15:51:20 +0000187 op.attrs["padding"] = Padding.VALID
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100188 op.attrs["stride_w"] = 1
189 op.attrs["stride_h"] = 1
190 op.attrs["filter_width"] = width
191 op.attrs["filter_height"] = 1
192 op.attrs["strides"] = [1, op.attrs["stride_h"], op.attrs["stride_w"], 1]
193 op.attrs["ksize"] = [1, op.attrs["filter_height"], op.attrs["filter_width"], 1]
194 op.activation = activation
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100195 op.inputs = [ifm]
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100196 ofm = Tensor([1, height, 1, 1], ifm.dtype, op.name + "_tens0")
197 ofm.quantization = quantization
198 op.set_output_tensor(ofm)
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100199 op.ifm_shapes.append(ifm_shape)
200 op.ofm_shapes.append(Shape4D(ofm.shape))
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100201 return op
202
203
204def create_reduce_sum(
205 name: str, ifm: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None
206) -> Operation:
207 op = Operation(Op.ReduceSum, name)
Michael McGeagh16895482020-12-14 15:51:20 +0000208 op.attrs["padding"] = Padding.VALID
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100209 op.attrs["stride_w"] = 1
210 op.attrs["stride_h"] = 1
211 op.attrs["filter_width"] = 1
212 op.attrs["filter_height"] = 1
213 op.attrs["strides"] = [1, op.attrs["stride_h"], op.attrs["stride_w"], 1]
214 op.attrs["ksize"] = [1, op.attrs["filter_height"], op.attrs["filter_width"], 1]
215 op.add_input_tensor(ifm)
216 op.activation = activation
217 ofm_shape = [1, ifm.shape[1], ifm.shape[2], 1]
218 sum_of_exp = Tensor(ofm_shape, DataType.int32, op.name + "_tens0")
219 sum_of_exp.quantization = quantization
220 op.set_output_tensor(sum_of_exp)
Patrik Gustavsson2349d422020-12-01 16:02:29 +0100221 op.set_ifm_ofm_shapes()
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100222 return op
223
224
225def create_add(
226 name: str,
227 ifm: Tensor,
228 ifm2: Tensor,
229 quantization: QuantizationParameters,
230 activation: Optional[ActivationFunction] = None,
231 dtype: Optional[DataType] = None,
232 attrs: Optional[dict] = None,
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100233 ifm_shape: Optional[Shape4D] = None,
234 ifm2_shape: Optional[Shape4D] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100235) -> Operation:
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100236 return create_binary_elementwise(
237 Op.Add, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape
238 )
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100239
240
241def create_clz(
242 name: str,
243 ifm: Tensor,
244 quantization: QuantizationParameters,
245 activation: Optional[ActivationFunction] = None,
246 dtype: Optional[DataType] = None,
247 attrs: Optional[dict] = None,
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100248 ifm_shape: Optional[Shape4D] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100249) -> Operation:
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100250 return create_unary_elementwise(Op.CLZ, name, ifm, quantization, activation, dtype, attrs, ifm_shape)
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100251
252
253def create_mul(
254 name: str,
255 ifm: Tensor,
256 ifm2: Tensor,
257 quantization: QuantizationParameters,
258 activation: Optional[ActivationFunction] = None,
259 dtype: Optional[DataType] = None,
260 attrs: Optional[dict] = None,
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100261 ifm_shape: Optional[Shape4D] = None,
262 ifm2_shape: Optional[Shape4D] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100263) -> Operation:
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100264 return create_binary_elementwise(
265 Op.Mul, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape
266 )
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100267
268
269def create_shl(
270 name: str,
271 ifm: Tensor,
272 ifm2: Tensor,
273 quantization: QuantizationParameters,
274 activation: Optional[ActivationFunction] = None,
275 dtype: Optional[DataType] = None,
276 attrs: Optional[dict] = None,
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100277 ifm_shape: Optional[Shape4D] = None,
278 ifm2_shape: Optional[Shape4D] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100279) -> Operation:
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100280 return create_binary_elementwise(
281 Op.SHL, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape
282 )
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100283
284
285def create_shr(
286 name: str,
287 ifm: Tensor,
288 ifm2: Tensor,
289 quantization: QuantizationParameters,
290 activation: Optional[ActivationFunction] = None,
291 dtype: Optional[DataType] = None,
292 attrs: Optional[dict] = None,
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100293 ifm_shape: Optional[Shape4D] = None,
294 ifm2_shape: Optional[Shape4D] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100295) -> Operation:
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100296 return create_binary_elementwise(
297 Op.SHR, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape
298 )
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100299
300
301def create_sub(
302 name: str,
303 ifm: Tensor,
304 ifm2: Tensor,
305 quantization: QuantizationParameters,
306 activation: Optional[ActivationFunction] = None,
307 dtype: Optional[DataType] = None,
308 attrs: Optional[dict] = None,
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100309 ifm_shape: Optional[Shape4D] = None,
310 ifm2_shape: Optional[Shape4D] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100311) -> Operation:
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100312 return create_binary_elementwise(
313 Op.Sub, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape
314 )
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100315
316
317def create_unary_elementwise(
318 op_type: Op,
319 name: str,
320 ifm: Tensor,
321 quantization: QuantizationParameters,
322 activation: Optional[ActivationFunction] = None,
323 dtype: Optional[DataType] = None,
324 attrs: Optional[dict] = None,
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100325 ifm_shape: Optional[Shape4D] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100326) -> Operation:
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100327 return create_binary_elementwise(op_type, name, ifm, None, quantization, activation, dtype, attrs, ifm_shape, None)
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100328
329
330def create_binary_elementwise(
331 op_type: Op,
332 name: str,
333 ifm: Tensor,
Jonas Ohlsson845e2322022-03-01 12:39:55 +0100334 ifm2: Optional[Tensor],
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100335 quantization: QuantizationParameters,
336 activation: Optional[ActivationFunction] = None,
337 dtype: Optional[DataType] = None,
338 attrs: Optional[dict] = None,
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100339 ifm_shape: Optional[Shape4D] = None,
340 ifm2_shape: Optional[Shape4D] = None,
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100341) -> Operation:
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100342 if ifm_shape is None:
343 ifm_shape = Shape4D(ifm.shape)
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100344 op = Operation(op_type, name)
345 op.add_input_tensor(ifm)
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100346 op.ifm_shapes.append(ifm_shape)
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100347 if ifm2:
348 op.add_input_tensor(ifm2)
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100349 if ifm2_shape is None:
350 ifm2_shape = Shape4D(ifm2.shape)
351 op.ifm_shapes.append(ifm2_shape)
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100352 op.activation = activation
353 if not dtype:
354 dtype = ifm.dtype
355 if attrs:
356 op.attrs.update(attrs)
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100357
358 if ifm2 is None:
359 ofm_shape = ifm_shape
360 else:
Johan Alfvén56a71b02022-10-19 11:20:12 +0200361 in_shape = None if ifm.shape == [] else ifm_shape
362 in2_shape = None if ifm2.shape == [] else ifm2_shape
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100363 ofm_shape = ifm_shape if ifm_ifm2_correct_order(in_shape, in2_shape) else ifm2_shape
364
365 ofm = Tensor(ofm_shape.as_list(), dtype, f"{op.name}_tens0")
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100366 ofm.quantization = quantization
367 op.set_output_tensor(ofm)
Patrik Gustavsson3a269202021-01-21 08:28:55 +0100368 op.ofm_shapes.append(ofm_shape)
Fredrik Svedbergd9c2c422020-12-01 16:33:45 +0100369 return op
Louis Verhaardc822d622021-03-11 14:59:06 +0100370
371
372def get_pad_values_from_input(padding) -> Tuple:
373 """Returns top, left, bottom, right padding from input values in a Pad input tensor"""
374 return (padding[-3][0], padding[-2][0], padding[-3][1], padding[-2][1])