#!/usr/bin/env python3 # coding: utf-8 # Copyright 2019 Huawei Technologies Co., Ltd # # 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 # # http://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. """operator dsl function: mean""" import akg.topi import akg.tvm from akg.ops.math import sum from akg.utils import format_transform as ft_util from akg.utils import validation_check as vc_util from akg.utils import custom_tiling as ct_util from akg.utils.dynamic_shape import shape_is_dynamic INT16_MAX = 65536 def get_attrs(tensor): """generate default attrs.""" if shape_is_dynamic(tensor): return {"enable_double_buffer": 0, "enable_divide_var": 1} return {} def mean_dynamic_tiling_strategy(tensor, axis): """custom tiling for mean with dynamic shape""" strategy = list() inner_most_to_full = True resnet_inner_most_axis_pos = 4 reduce_axis_to_1 = True reduce_axis_to_no_iso = False multicore_axis_to_1 = True resnet_outer_most_axis_pos = 0 if inner_most_to_full: strategy += ct_util.create_constraint_on_tensor(tensor=tensor, values="FULL", constraints=ct_util.TileConstraint.MAX, tensor_pos=resnet_inner_most_axis_pos) if reduce_axis_to_1: strategy += ct_util.create_constraint_on_tensor(tensor=tensor, values=[1 for _ in axis], constraints=ct_util.TileConstraint.FACTOR, tensor_pos=axis) elif reduce_axis_to_no_iso: strategy += ct_util.create_constraint_on_tensor(tensor=tensor, values=[1 for _ in axis], constraints=ct_util.TileConstraint.FORBID_ISOLATE, tensor_pos=axis) if multicore_axis_to_1: strategy += ct_util.create_constraint_on_tensor(tensor=tensor, values=1, constraints=ct_util.TileConstraint.FACTOR, tensor_pos=resnet_outer_most_axis_pos) return strategy @vc_util.check_input_type(akg.tvm.tensor.Tensor, (list, tuple, int, type(None)), (bool, type(None))) def mean(data, axis=None, keepdims=False): """ Computes the mean of the values of a Tensor over the whole dataset. Note: If the tuple's elements are unsorted, this function will call preprocess_axis firstly to let these elements sorted. if tuple is empty, this function will compute all elements' sum. if the data type is folat 16 and the whole dim not less than 65536, this function will compute the mean by divide 65535 first to avoid whole dim too large. Args: data (tvm.tensor.Tensor): Tensor of type float16, float32. axis (Union[list, tuple, int, None]): If the tuple is empty, the axis equal to None. keepdims (bool): If keepdims equal to True, the result shape length is same to input shape length. Returns: tvm.tensor.Tensor, has the same type as data. If keepdims equal to True, all reduced dimensions are retained with length 1. else these reduced axis will be eliminate. """ # Check types vc_util.ops_dtype_check(data.dtype, vc_util.DtypeForDavinci.ALL_FLOAT) # Check shape shape = ft_util.get_shape(data) vc_util.reduce_axis_check(shape, axis) axis = ft_util.refine_reduce_axis(data, axis) count = 1 for i in axis: count *= shape[i] output, _ = sum.sum_value(data, axis, keepdims) if shape_is_dynamic(data): res = akg.tvm.compute(output.shape, lambda *i: akg.lang.cce.divide_var(output(*i), count), name="res") else: res = akg.topi.divide(output, count) attrs = get_attrs(data) if shape_is_dynamic(data): attrs["custom_tiling"] = mean_dynamic_tiling_strategy(data, axis) return res, attrs @vc_util.check_input_type(akg.tvm.tensor.Tensor, (list, tuple, int, type(None)), (bool, type(None))) def mean_v2(data, axis=None, keepdims=False): """Simple implementation of mean.""" # Check types vc_util.ops_dtype_check(data.dtype, vc_util.DtypeForDavinci.ALL_FLOAT) # Check shape shape = [x.value for x in data.shape] vc_util.reduce_axis_check(shape, axis) axis = ft_util.refine_reduce_axis(data, axis) dtype = data.dtype count = 1 for i in axis: count *= shape[i] count_rec = 1 / count output, _ = sum.sum_v2(data, axis, keepdims) res = output * akg.tvm.const(count_rec, dtype) attrs = get_attrs(data) if shape_is_dynamic(data): attrs["custom_tiling"] = mean_dynamic_tiling_strategy(data, axis) return res, attrs