/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ /*! * \brief local response normalization op constructions * \file nn/local_response_norm.h */ #ifndef TVM_TOPI_NN_LOCAL_RESPONSE_NORM_H_ #define TVM_TOPI_NN_LOCAL_RESPONSE_NORM_H_ #include #include #include namespace tvm { namespace topi { namespace nn { using namespace tvm::te; /*! * \brief Local response normalization inference operator * * \param data The input tensor. 4-D shape NCHW or NHWC * \param size Integer to define normalisation window size * \param axis Input data layout channel axis * \param alpha Float scaling factor * \param beta Exponent value * \param bias Offset to avoid dividing by zero * \param name The name of the operation * \param tag The tag to mark the operation * * \return A Tensor whose op member is the Local response normalization operation */ inline Tensor lrn(const Tensor& data, int size, int axis = 1, float alpha = 0.0001, float beta = 0.75, float bias = 2, std::string name = "tensor", std::string tag = kBroadcast) { TVM_FFI_ICHECK_EQ(data->shape.size(), 4) << "LRN requires 4-D input"; TVM_FFI_ICHECK_EQ(size % 2, 1) << "size should be odd number"; TVM_FFI_ICHECK(axis == 1 || axis == 3) << "axis should be 1 or 3 for NCHW and NHWC"; // LRN only requires a floating-point element kind; lane encoding is irrelevant here. TVM_FFI_ICHECK_EQ(data->dtype.code(), DLDataTypeCode::kDLFloat) << "datatype should be float"; auto input_shape = data->shape; ffi::Array pad_before{0, 0, 0, 0}; ffi::Array pad_after{0, 0, 0, 0}; pad_before.Set(axis, static_cast(size / 2)); pad_after.Set(axis, static_cast(size / 2)); auto pad_data = pad(data, pad_before, pad_after, 0, "pad_data"); auto rxs = tvm::te::reduce_axis(Range(0, size), "rxs"); Tensor sqr_sum; if (axis == 1) { sqr_sum = tvm::te::compute( input_shape, [&](PrimVar i, PrimVar l, PrimVar j, PrimVar k) { return tvm::sum(pad_data(i, l + rxs, j, k) * pad_data(i, l + rxs, j, k), {rxs}); }, "tensor", "sqr_sum"); } else if (axis == 3) { sqr_sum = tvm::te::compute( input_shape, [&](PrimVar i, PrimVar l, PrimVar j, PrimVar k) { return tvm::sum(pad_data(i, l, j, k + rxs) * pad_data(i, l, j, k + rxs), {rxs}); }, "tensor", "sqr_sum"); } PrimExpr alpha_imm = tvm::te::MakeConst(PrimType(data->dtype), alpha); PrimExpr beta_imm = tvm::te::MakeConst(PrimType(data->dtype), beta); PrimExpr bias_imm = tvm::te::MakeConst(PrimType(data->dtype), bias); auto sqrt_sum_up = tvm::te::compute( input_shape, [&](PrimVar i, PrimVar j, PrimVar k, PrimVar l) { return tvm::pow(bias_imm + (div(alpha_imm * sqr_sum(i, j, k, l), size)), beta_imm); }, "tensor", kElementWise); return topi::divide(data, sqrt_sum_up); } } // namespace nn } // namespace topi } // namespace tvm #endif // TVM_TOPI_NN_LOCAL_RESPONSE_NORM_H_