Johan Alfven | 9072496 | 2023-02-02 09:07:48 +0100 | [diff] [blame] | 1 | # SPDX-FileCopyrightText: Copyright 2020-2023 Arm Limited and/or its affiliates <open-source-office@arm.com> |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 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. |
Rickard Bolin | bc6ee58 | 2022-11-04 08:24:29 +0000 | [diff] [blame] | 16 | # |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 17 | # Description: |
| 18 | # Utility functions for creating Network Operations. |
| 19 | from typing import Optional |
Fredrik Svedberg | e82be7c | 2021-01-18 15:21:03 +0100 | [diff] [blame] | 20 | from typing import Tuple |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 21 | |
Johan Alfven | c1ad80b | 2023-03-31 10:19:23 +0200 | [diff] [blame] | 22 | import numpy as np |
| 23 | |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 24 | from .data_type import DataType |
| 25 | from .high_level_command_to_npu_op import ifm_ifm2_correct_order |
| 26 | from .operation import ActivationFunction |
| 27 | from .operation import Op |
| 28 | from .operation import Operation |
Michael McGeagh | 1689548 | 2020-12-14 15:51:20 +0000 | [diff] [blame] | 29 | from .operation import Padding |
Fredrik Svedberg | 0ac0804 | 2023-04-11 22:35:04 +0200 | [diff] [blame] | 30 | from .reader_util import clone_and_reshape_tensor |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 31 | from .shape4d import Shape4D |
Johan Alfven | c1ad80b | 2023-03-31 10:19:23 +0200 | [diff] [blame] | 32 | from .tensor import create_const_tensor |
Fredrik Svedberg | 0ac0804 | 2023-04-11 22:35:04 +0200 | [diff] [blame] | 33 | from .tensor import create_equivalence_id |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 34 | from .tensor import QuantizationParameters |
| 35 | from .tensor import Tensor |
| 36 | |
| 37 | |
| 38 | def create_avgpool_nop(name: str) -> Operation: |
| 39 | op = Operation(Op.AvgPool, name) |
Michael McGeagh | 1689548 | 2020-12-14 15:51:20 +0000 | [diff] [blame] | 40 | op.attrs["padding"] = Padding.VALID |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 41 | 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 Gustavsson | c74682c | 2021-08-17 14:26:38 +0200 | [diff] [blame] | 48 | op.attrs["explicit_padding"] = [0, 0, 0, 0] # [top, left, bottom, right] |
Louis Verhaard | c822d62 | 2021-03-11 14:59:06 +0100 | [diff] [blame] | 49 | op.run_on_npu = True |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 50 | return op |
| 51 | |
| 52 | |
Patrik Gustavsson | f1580f0 | 2021-09-01 12:43:02 +0200 | [diff] [blame] | 53 | def create_add_nop(name: str) -> Operation: |
| 54 | op = Operation(Op.Add, name) |
| 55 | op.run_on_npu = True |
| 56 | return op |
| 57 | |
| 58 | |
Johan Alfven | c1ad80b | 2023-03-31 10:19:23 +0200 | [diff] [blame] | 59 | def create_memcpy( |
| 60 | name: str, |
| 61 | ifm: Tensor, |
| 62 | ofm: Tensor, |
| 63 | ) -> Operation: |
Johan Alfven | 9072496 | 2023-02-02 09:07:48 +0100 | [diff] [blame] | 64 | op = Operation(Op.Memcpy, name) |
| 65 | op.run_on_npu = True |
Johan Alfven | c1ad80b | 2023-03-31 10:19:23 +0200 | [diff] [blame] | 66 | op.add_input_tensor(ifm) |
| 67 | op.set_output_tensor(ofm) |
| 68 | op.set_ifm_ofm_shapes() |
Johan Alfven | 9072496 | 2023-02-02 09:07:48 +0100 | [diff] [blame] | 69 | return op |
| 70 | |
| 71 | |
Patrik Gustavsson | b4936ad | 2021-10-05 13:53:34 +0200 | [diff] [blame] | 72 | def create_pad_nop(name: str) -> Operation: |
| 73 | op = Operation(Op.Pad, name) |
| 74 | op.run_on_npu = True |
| 75 | return op |
| 76 | |
| 77 | |
Johan Alfven | c1ad80b | 2023-03-31 10:19:23 +0200 | [diff] [blame] | 78 | def 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 Alfven | 7972ee8 | 2023-10-03 14:46:22 +0200 | [diff] [blame] | 101 | # Weigth shape is in format [h, w, b, c] for DepthwiseConv2D |
| 102 | shape = [1, 1, 1, c] |
Johan Alfven | c1ad80b | 2023-03-31 10:19:23 +0200 | [diff] [blame] | 103 | 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 Alfven | 7972ee8 | 2023-10-03 14:46:22 +0200 | [diff] [blame] | 114 | # 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 Alfven | c1ad80b | 2023-03-31 10:19:23 +0200 | [diff] [blame] | 117 | 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 Svedberg | 0ac0804 | 2023-04-11 22:35:04 +0200 | [diff] [blame] | 126 | def 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 | |
| 138 | def 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 Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 175 | def create_depthwise_maxpool( |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 176 | name: str, |
| 177 | ifm: Tensor, |
| 178 | inp_shape: Shape4D, |
| 179 | quantization: QuantizationParameters, |
| 180 | activation: Optional[ActivationFunction] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 181 | ) -> Operation: |
| 182 | op = Operation(Op.MaxPool, name) |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 183 | height = inp_shape.height * inp_shape.width |
| 184 | width = inp_shape.depth |
| 185 | ifm_shape = Shape4D([1, height, width, 1]) |
| 186 | |
Michael McGeagh | 1689548 | 2020-12-14 15:51:20 +0000 | [diff] [blame] | 187 | op.attrs["padding"] = Padding.VALID |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 188 | 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 Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 195 | op.inputs = [ifm] |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 196 | ofm = Tensor([1, height, 1, 1], ifm.dtype, op.name + "_tens0") |
| 197 | ofm.quantization = quantization |
| 198 | op.set_output_tensor(ofm) |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 199 | op.ifm_shapes.append(ifm_shape) |
| 200 | op.ofm_shapes.append(Shape4D(ofm.shape)) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 201 | return op |
| 202 | |
| 203 | |
| 204 | def create_reduce_sum( |
| 205 | name: str, ifm: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None |
| 206 | ) -> Operation: |
| 207 | op = Operation(Op.ReduceSum, name) |
Michael McGeagh | 1689548 | 2020-12-14 15:51:20 +0000 | [diff] [blame] | 208 | op.attrs["padding"] = Padding.VALID |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 209 | 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 Gustavsson | 2349d42 | 2020-12-01 16:02:29 +0100 | [diff] [blame] | 221 | op.set_ifm_ofm_shapes() |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 222 | return op |
| 223 | |
| 224 | |
| 225 | def 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 Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 233 | ifm_shape: Optional[Shape4D] = None, |
| 234 | ifm2_shape: Optional[Shape4D] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 235 | ) -> Operation: |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 236 | return create_binary_elementwise( |
| 237 | Op.Add, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape |
| 238 | ) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 239 | |
| 240 | |
| 241 | def 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 Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 248 | ifm_shape: Optional[Shape4D] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 249 | ) -> Operation: |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 250 | return create_unary_elementwise(Op.CLZ, name, ifm, quantization, activation, dtype, attrs, ifm_shape) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 251 | |
| 252 | |
| 253 | def 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 Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 261 | ifm_shape: Optional[Shape4D] = None, |
| 262 | ifm2_shape: Optional[Shape4D] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 263 | ) -> Operation: |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 264 | return create_binary_elementwise( |
| 265 | Op.Mul, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape |
| 266 | ) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 267 | |
| 268 | |
| 269 | def 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 Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 277 | ifm_shape: Optional[Shape4D] = None, |
| 278 | ifm2_shape: Optional[Shape4D] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 279 | ) -> Operation: |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 280 | return create_binary_elementwise( |
| 281 | Op.SHL, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape |
| 282 | ) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 283 | |
| 284 | |
| 285 | def 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 Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 293 | ifm_shape: Optional[Shape4D] = None, |
| 294 | ifm2_shape: Optional[Shape4D] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 295 | ) -> Operation: |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 296 | return create_binary_elementwise( |
| 297 | Op.SHR, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape |
| 298 | ) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 299 | |
| 300 | |
| 301 | def 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 Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 309 | ifm_shape: Optional[Shape4D] = None, |
| 310 | ifm2_shape: Optional[Shape4D] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 311 | ) -> Operation: |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 312 | return create_binary_elementwise( |
| 313 | Op.Sub, name, ifm, ifm2, quantization, activation, dtype, attrs, ifm_shape, ifm2_shape |
| 314 | ) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 315 | |
| 316 | |
| 317 | def 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 Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 325 | ifm_shape: Optional[Shape4D] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 326 | ) -> Operation: |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 327 | return create_binary_elementwise(op_type, name, ifm, None, quantization, activation, dtype, attrs, ifm_shape, None) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 328 | |
| 329 | |
| 330 | def create_binary_elementwise( |
| 331 | op_type: Op, |
| 332 | name: str, |
| 333 | ifm: Tensor, |
Jonas Ohlsson | 845e232 | 2022-03-01 12:39:55 +0100 | [diff] [blame] | 334 | ifm2: Optional[Tensor], |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 335 | quantization: QuantizationParameters, |
| 336 | activation: Optional[ActivationFunction] = None, |
| 337 | dtype: Optional[DataType] = None, |
| 338 | attrs: Optional[dict] = None, |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 339 | ifm_shape: Optional[Shape4D] = None, |
| 340 | ifm2_shape: Optional[Shape4D] = None, |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 341 | ) -> Operation: |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 342 | if ifm_shape is None: |
| 343 | ifm_shape = Shape4D(ifm.shape) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 344 | op = Operation(op_type, name) |
| 345 | op.add_input_tensor(ifm) |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 346 | op.ifm_shapes.append(ifm_shape) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 347 | if ifm2: |
| 348 | op.add_input_tensor(ifm2) |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 349 | if ifm2_shape is None: |
| 350 | ifm2_shape = Shape4D(ifm2.shape) |
| 351 | op.ifm_shapes.append(ifm2_shape) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 352 | op.activation = activation |
| 353 | if not dtype: |
| 354 | dtype = ifm.dtype |
| 355 | if attrs: |
| 356 | op.attrs.update(attrs) |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 357 | |
| 358 | if ifm2 is None: |
| 359 | ofm_shape = ifm_shape |
| 360 | else: |
Johan Alfvén | 56a71b0 | 2022-10-19 11:20:12 +0200 | [diff] [blame] | 361 | in_shape = None if ifm.shape == [] else ifm_shape |
| 362 | in2_shape = None if ifm2.shape == [] else ifm2_shape |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 363 | 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 Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 366 | ofm.quantization = quantization |
| 367 | op.set_output_tensor(ofm) |
Patrik Gustavsson | 3a26920 | 2021-01-21 08:28:55 +0100 | [diff] [blame] | 368 | op.ofm_shapes.append(ofm_shape) |
Fredrik Svedberg | d9c2c42 | 2020-12-01 16:33:45 +0100 | [diff] [blame] | 369 | return op |
Louis Verhaard | c822d62 | 2021-03-11 14:59:06 +0100 | [diff] [blame] | 370 | |
| 371 | |
| 372 | def 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]) |