# Copyright (C) 2020 Arm Limited or its affiliates. All rights reserved. # # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the License); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an AS IS BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Description: # Utility functions for creating Network Operations. from typing import Optional from .data_type import DataType from .high_level_command_to_npu_op import ifm_ifm2_correct_order from .operation import ActivationFunction from .operation import Op from .operation import Operation from .operation import Padding from .tensor import create_reshape_tensor from .tensor import QuantizationParameters from .tensor import Tensor def create_avgpool_nop(name: str) -> Operation: op = Operation(Op.AvgPool, name) op.attrs["padding"] = Padding.VALID op.attrs["stride_w"] = 1 op.attrs["stride_h"] = 1 op.attrs["filter_width"] = 1 op.attrs["filter_height"] = 1 op.attrs["strides"] = [1, 1, 1, 1] op.attrs["ksize"] = [1, 1, 1, 1] op.attrs["skirt"] = [0, 0, 0, 0] op.attrs["explicit_padding"] = [0, 0, 0, 0] return op def create_depthwise_maxpool( name: str, ifm: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None ) -> Operation: op = Operation(Op.MaxPool, name) height = ifm.shape[1] * ifm.shape[2] width = ifm.shape[3] ifm_shape = [1, height, width, 1] op.attrs["padding"] = Padding.VALID op.attrs["stride_w"] = 1 op.attrs["stride_h"] = 1 op.attrs["filter_width"] = width op.attrs["filter_height"] = 1 op.attrs["strides"] = [1, op.attrs["stride_h"], op.attrs["stride_w"], 1] op.attrs["ksize"] = [1, op.attrs["filter_height"], op.attrs["filter_width"], 1] op.activation = activation op.inputs = [create_reshape_tensor(ifm, ifm_shape)] ofm = Tensor([1, height, 1, 1], ifm.dtype, op.name + "_tens0") ofm.quantization = quantization op.set_output_tensor(ofm) op.set_ifm_ofm_shapes() return op def create_reduce_sum( name: str, ifm: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None ) -> Operation: op = Operation(Op.ReduceSum, name) op.attrs["padding"] = Padding.VALID op.attrs["stride_w"] = 1 op.attrs["stride_h"] = 1 op.attrs["filter_width"] = 1 op.attrs["filter_height"] = 1 op.attrs["strides"] = [1, op.attrs["stride_h"], op.attrs["stride_w"], 1] op.attrs["ksize"] = [1, op.attrs["filter_height"], op.attrs["filter_width"], 1] op.add_input_tensor(ifm) op.activation = activation ofm_shape = [1, ifm.shape[1], ifm.shape[2], 1] sum_of_exp = Tensor(ofm_shape, DataType.int32, op.name + "_tens0") sum_of_exp.quantization = quantization op.set_output_tensor(sum_of_exp) op.set_ifm_ofm_shapes() return op def create_add( name: str, ifm: Tensor, ifm2: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None, dtype: Optional[DataType] = None, attrs: Optional[dict] = None, ) -> Operation: return create_binary_elementwise(Op.Add, name, ifm, ifm2, quantization, activation, dtype, attrs) def create_clz( name: str, ifm: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None, dtype: Optional[DataType] = None, attrs: Optional[dict] = None, ) -> Operation: return create_unary_elementwise(Op.CLZ, name, ifm, quantization, activation, dtype, attrs) def create_mul( name: str, ifm: Tensor, ifm2: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None, dtype: Optional[DataType] = None, attrs: Optional[dict] = None, ) -> Operation: return create_binary_elementwise(Op.Mul, name, ifm, ifm2, quantization, activation, dtype, attrs) def create_shl( name: str, ifm: Tensor, ifm2: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None, dtype: Optional[DataType] = None, attrs: Optional[dict] = None, ) -> Operation: return create_binary_elementwise(Op.SHL, name, ifm, ifm2, quantization, activation, dtype, attrs) def create_shr( name: str, ifm: Tensor, ifm2: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None, dtype: Optional[DataType] = None, attrs: Optional[dict] = None, ) -> Operation: return create_binary_elementwise(Op.SHR, name, ifm, ifm2, quantization, activation, dtype, attrs) def create_sub( name: str, ifm: Tensor, ifm2: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None, dtype: Optional[DataType] = None, attrs: Optional[dict] = None, ) -> Operation: return create_binary_elementwise(Op.Sub, name, ifm, ifm2, quantization, activation, dtype, attrs) def create_unary_elementwise( op_type: Op, name: str, ifm: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None, dtype: Optional[DataType] = None, attrs: Optional[dict] = None, ) -> Operation: return create_binary_elementwise(op_type, name, ifm, None, quantization, activation, dtype, attrs) def create_binary_elementwise( op_type: Op, name: str, ifm: Tensor, ifm2: Tensor, quantization: QuantizationParameters, activation: Optional[ActivationFunction] = None, dtype: Optional[DataType] = None, attrs: Optional[dict] = None, ) -> Operation: op = Operation(op_type, name) op.add_input_tensor(ifm) if ifm2: op.add_input_tensor(ifm2) op.activation = activation if not dtype: dtype = ifm.dtype if attrs: op.attrs.update(attrs) ofm_shape = ifm.shape if ifm2 is None or ifm_ifm2_correct_order(ifm.shape, ifm2.shape) else ifm2.shape ofm = Tensor(ofm_shape, dtype, f"{op.name}_tens0") ofm.quantization = quantization op.set_output_tensor(ofm) op.set_ifm_ofm_shapes() return op