#!/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: softmax""" import akg.topi import akg.tvm import akg from akg.utils import kernel_exec as utils from akg.utils import format_transform as ft_util from akg.utils import validation_check as vc_util from akg.utils import dynamic_shape as ds from akg.utils import custom_tiling as ct def softmax_build(shape, dtype, axis): """build softmax.""" data = akg.tvm.placeholder(shape, name="data", dtype=dtype) # compute out = softmax(data, axis) return out @vc_util.check_input_type(akg.tvm.tensor.Tensor, (list, tuple, int)) def softmax(data, axis): """ Map all element of data to (0,1) and sum to 1. Args: data (tvm.tensor.Tensor): input. axis (int): along which normalization is applied. Return: tvm.tensor.Tensor, output. """ vc_util.check_shape(data.shape) shape = data.shape vc_util.ops_dtype_check(data.dtype, vc_util.DtypeForDavinci.ALL_FLOAT) vc_util.reduce_axis_check(shape, axis) axis = ft_util.refine_reduce_axis(data, axis) if isinstance(axis, (list, tuple)): if len(axis) != 1: raise RuntimeError("Reduce axis for softmax op must be 1-dimension, while current is %d-dimension" % (len(axis))) axis = axis[0] output = softmax_op(data, axis, shape) attr_map = {} if ds.shape_is_dynamic(data): # For shifted loops, should have: # dynamic_shape_bound mod tile_size_prime == 2 # This aims to ensure that the shift constant is a multiple of tile_size_prime. # So the generated IR will not have complicated head and tail for shifted blocks. attr_map = { "pragma_modshift": 1, "pragma_outerband_need_split": 1, "enable_post_poly_loop_partition": False, "dynamic_shape": ds.set_dynamic_shape_limit_for_tensor( output, 2048, axis) + ds.set_poly_upper_bound_for_tensor( output, 2048, axis), "custom_tiling": ct.create_constraint_on_tensor( tensor=output, values=[ 1 for i, _ in enumerate(shape) if i != axis], constraints=ct.TileConstraint.FACTOR, tensor_pos=[ i for i, _ in enumerate(shape) if i != axis])} return output, attr_map def softmax_op(data, axis, shape): """core computation of softmax op.""" max_data = akg.lang.cce.reduce_max(data, axis=axis, keepdims=True) max_broadcast = akg.lang.cce.broadcast(max_data, shape) data_sub = akg.lang.cce.vsub(data, max_broadcast) if data.dtype == "float32" and utils.product_is_mini(): data16 = akg.topi.cast(data_sub, "float16") data_exp = akg.lang.cce.vexp(data16) data_exp = akg.topi.cast(data_exp, "float32") else: data_exp = akg.lang.cce.vexp(data_sub) data_expsum = akg.lang.cce.sum(data_exp, axis, keepdims=True) data_expsum_broadcast = akg.lang.cce.broadcast(data_expsum, shape) output = data_exp / data_expsum_broadcast return output