diff options
author | Usama Arif <usama.arif@arm.com> | 2019-05-14 10:22:36 +0100 |
---|---|---|
committer | Usama Arif <usama.arif@arm.com> | 2019-05-15 17:09:25 +0000 |
commit | 52c54f61b97bcedab309bfa761e193939e12e739 (patch) | |
tree | e99186abb3c6a69ef26b17e8fb57817ee56efe53 | |
parent | eb312ef6c20e8548c43eb9d4a3edf7265bc6777b (diff) | |
download | ComputeLibrary-52c54f61b97bcedab309bfa761e193939e12e739.tar.gz |
COMPMID-2270: Implement POW operator for CL
Change-Id: Id14ecdc62439d90eb247bb75990d6593637cb42e
Signed-off-by: Usama Arif <usama.arif@arm.com>
Reviewed-on: https://review.mlplatform.org/c/1129
Comments-Addressed: Arm Jenkins <bsgcomp@arm.com>
Reviewed-by: Gian Marco Iodice <gianmarco.iodice@arm.com>
Tested-by: Arm Jenkins <bsgcomp@arm.com>
-rw-r--r-- | arm_compute/runtime/CL/functions/CLElementwiseOperations.h | 28 | ||||
-rw-r--r-- | src/core/CL/CLKernelLibrary.cpp | 1 | ||||
-rw-r--r-- | src/core/CL/cl_kernels/elementwise_operation.cl | 3 | ||||
-rw-r--r-- | src/core/CL/kernels/CLElementwiseOperationKernel.cpp | 19 | ||||
-rw-r--r-- | src/runtime/CL/functions/CLElementwiseOperations.cpp | 16 | ||||
-rw-r--r-- | tests/validation/CL/ElementwisePower.cpp | 129 | ||||
-rw-r--r-- | utils/TypePrinter.h | 3 |
7 files changed, 188 insertions, 11 deletions
diff --git a/arm_compute/runtime/CL/functions/CLElementwiseOperations.h b/arm_compute/runtime/CL/functions/CLElementwiseOperations.h index 1740bb0e4d..27215e81c1 100644 --- a/arm_compute/runtime/CL/functions/CLElementwiseOperations.h +++ b/arm_compute/runtime/CL/functions/CLElementwiseOperations.h @@ -202,5 +202,33 @@ public: */ static Status validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output); }; + +/** Basic function to run @ref CLArithmeticOperationKernel for power + * + * @note The tensor data type for the inputs must be F16/F32. + * @note The function performs an elementwise power of in1 to in2 (i.e., out[i] = in1[i] ^ in2[i]) + */ +class CLElementwisePower : public ICLSimpleFunction +{ +public: + /** Initialise the kernel's inputs, output and conversion policy. + * + * @param[in, out] input1 First tensor input. Data types supported: F16/F32. + * The input tensor is [in, out] because its TensorInfo might be modified inside the kernel in case of broadcasting of dimension 0. + * @param[in, out] input2 Second tensor input. Data types supported: F16/F32. + * The input tensor is [in, out] because its TensorInfo might be modified inside the kernel in case of broadcasting of dimension 0. + * @param[out] output Output tensor. Data types supported:F16/F32. + */ + void configure(ICLTensor *input1, ICLTensor *input2, ICLTensor *output); + /** Static function to check if given info will lead to a valid configuration of @ref CLArithmeticOperationKernel for power + * + * @param[in] input1 First tensor input info. Data types supported: F16/F32. + * @param[in] input2 Second tensor input info. Data types supported: F16/F32. + * @param[in] output Output tensor info. Data types supported: F16/F32. + * + * @return a status + */ + static Status validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output); +}; } // namespace arm_compute #endif /* __ARM_COMPUTE_CLELEMENTWISEOPERATIONS_H__ */ diff --git a/src/core/CL/CLKernelLibrary.cpp b/src/core/CL/CLKernelLibrary.cpp index b2d7e23624..e102f44b88 100644 --- a/src/core/CL/CLKernelLibrary.cpp +++ b/src/core/CL/CLKernelLibrary.cpp @@ -252,6 +252,7 @@ const std::map<std::string, std::string> CLKernelLibrary::_kernel_program_map = { "elementwise_operation_MIN", "elementwise_operation.cl" }, { "elementwise_operation_DIV", "elementwise_operation.cl" }, { "elementwise_operation_SQUARED_DIFF", "elementwise_operation.cl" }, + { "elementwise_operation_POWER", "elementwise_operation.cl" }, { "elementwise_operation_ADD_quantized", "elementwise_operation_quantized.cl" }, { "elementwise_operation_SUB_quantized", "elementwise_operation_quantized.cl" }, { "elementwise_operation_MAX_quantized", "elementwise_operation_quantized.cl" }, diff --git a/src/core/CL/cl_kernels/elementwise_operation.cl b/src/core/CL/cl_kernels/elementwise_operation.cl index 00d7ed3ba1..0b660e4012 100644 --- a/src/core/CL/cl_kernels/elementwise_operation.cl +++ b/src/core/CL/cl_kernels/elementwise_operation.cl @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited. + * Copyright (c) 2018-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -37,6 +37,7 @@ #define MIN(x, y) min(x, y) #define SQUARED_DIFF(x, y) (x - y) * (x - y) #define DIV(x, y) (x / y) +#define POWER(x, y) pow(x, y) #define OP_FUN_NAME_STR(op) elementwise_operation_##op #define OP_FUN_NAME(op) OP_FUN_NAME_STR(op) diff --git a/src/core/CL/kernels/CLElementwiseOperationKernel.cpp b/src/core/CL/kernels/CLElementwiseOperationKernel.cpp index 63c9244961..ce0c51dac5 100644 --- a/src/core/CL/kernels/CLElementwiseOperationKernel.cpp +++ b/src/core/CL/kernels/CLElementwiseOperationKernel.cpp @@ -42,6 +42,7 @@ std::map<ArithmeticOperation, std::string> supported_arithmetic_ops = { ArithmeticOperation::SQUARED_DIFF, "SQUARED_DIFF" }, { ArithmeticOperation::MIN, "MIN" }, { ArithmeticOperation::MAX, "MAX" }, + { ArithmeticOperation::POWER, "POWER" }, }; std::map<ArithmeticOperation, std::string> supported_sat_arithmetic_ops = @@ -64,7 +65,7 @@ std::string generate_id_for_tuning_common(const std::string &kernel_name, const return config_id; } -Status validate_arguments_with_division_rules(const ITensorInfo &input1, const ITensorInfo &input2, const ITensorInfo &output) +Status validate_arguments_with_float_only_supported_rules(const ITensorInfo &input1, const ITensorInfo &input2, const ITensorInfo &output) { ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(&input1, &input2, &output); ARM_COMPUTE_RETURN_ERROR_ON_F16_UNSUPPORTED(&input1); @@ -344,10 +345,10 @@ void CLArithmeticOperationKernel::configure(ArithmeticOperation op, const ICLTen Status CLArithmeticOperationKernel::validate(ArithmeticOperation op, const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output) { ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input1, input2, output); - if(op == ArithmeticOperation::DIV) + if(op == ArithmeticOperation::DIV || op == ArithmeticOperation::POWER) { - // Division doesn't support integer arithmetic - ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments_with_division_rules(*input1, *input2, *output)); + // Division and Power operators don't support integer arithmetic + ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments_with_float_only_supported_rules(*input1, *input2, *output)); ARM_COMPUTE_RETURN_ON_ERROR(validate_and_configure_window_for_division(*input1->clone(), *input2->clone(), *output->clone()).first); } else @@ -360,9 +361,9 @@ Status CLArithmeticOperationKernel::validate(ArithmeticOperation op, const ITens } std::pair<Status, Window> CLArithmeticOperationKernel::validate_and_configure_window(ITensorInfo &input1, ITensorInfo &input2, ITensorInfo &output) { - if(_op == ArithmeticOperation::DIV) + if(_op == ArithmeticOperation::DIV || _op == ArithmeticOperation::POWER) { - // Division doesn't support integer arithmetic + // Division and Power operators don't support integer arithmetic return validate_and_configure_window_for_division(input1, input2, output); } else @@ -372,10 +373,10 @@ std::pair<Status, Window> CLArithmeticOperationKernel::validate_and_configure_wi } Status CLArithmeticOperationKernel::validate_arguments(const ITensorInfo &input1, const ITensorInfo &input2, const ITensorInfo &output) { - if(_op == ArithmeticOperation::DIV) + if(_op == ArithmeticOperation::DIV || _op == ArithmeticOperation::POWER) { - // Division doesn't support integer arithmetic - return validate_arguments_with_division_rules(input1, input2, output); + // Division and Power operators don't support integer arithmetic + return validate_arguments_with_float_only_supported_rules(input1, input2, output); } else { diff --git a/src/runtime/CL/functions/CLElementwiseOperations.cpp b/src/runtime/CL/functions/CLElementwiseOperations.cpp index 28f4b13f22..15de56d24a 100644 --- a/src/runtime/CL/functions/CLElementwiseOperations.cpp +++ b/src/runtime/CL/functions/CLElementwiseOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited. + * Copyright (c) 2018-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -124,4 +124,18 @@ Status CLElementwiseSquaredDiff::validate(const ITensorInfo *input1, const ITens { return CLArithmeticOperationKernel::validate(ArithmeticOperation::SQUARED_DIFF, input1, input2, output); } + +void CLElementwisePower::configure(ICLTensor *input1, ICLTensor *input2, ICLTensor *output) +{ + auto k = arm_compute::support::cpp14::make_unique<CLArithmeticOperationKernel>(); + k->configure(ArithmeticOperation::POWER, input1, input2, output); + _kernel = std::move(k); + configure_border_handler(_border_handler, _kernel->border_size(), input1, input2, output); +} + +Status CLElementwisePower::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output) +{ + return CLArithmeticOperationKernel::validate(ArithmeticOperation::POWER, input1, input2, output); +} + } // namespace arm_compute diff --git a/tests/validation/CL/ElementwisePower.cpp b/tests/validation/CL/ElementwisePower.cpp new file mode 100644 index 0000000000..af36e1768b --- /dev/null +++ b/tests/validation/CL/ElementwisePower.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2019 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/CLTensor.h" +#include "arm_compute/runtime/CL/CLTensorAllocator.h" +#include "arm_compute/runtime/CL/functions/CLElementwiseOperations.h" +#include "tests/CL/CLAccessor.h" +#include "tests/PaddingCalculator.h" +#include "tests/datasets/ShapeDatasets.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/framework/datasets/Datasets.h" +#include "tests/validation/Validation.h" +#include "tests/validation/fixtures/ElementwiseOperationsFixture.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace +{ +RelativeTolerance<float> tolerance_fp32(0.000001f); +RelativeTolerance<float> tolerance_fp16(0.001f); + +constexpr unsigned int num_elems_processed_per_iteration = 16; +/** Input data sets **/ +const auto ElementwisePowerFP16Dataset = combine(combine(framework::dataset::make("DataType", DataType::F16), framework::dataset::make("DataType", DataType::F16)), + framework::dataset::make("DataType", DataType::F16)); +const auto ElementwisePowerFP32Dataset = combine(combine(framework::dataset::make("DataType", DataType::F32), framework::dataset::make("DataType", DataType::F32)), + framework::dataset::make("DataType", DataType::F32)); +} // namespace + +TEST_SUITE(CL) +TEST_SUITE(ElementwisePower) + +// *INDENT-OFF* +// clang-format off +DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip( + framework::dataset::make("Input1Info", { TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::F32), + TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::F16), + TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Window shrink + TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::U8), // Invalid data type combination + TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::F32), // Mismatching shapes + }), + framework::dataset::make("Input2Info",{ TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::F32), + TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::F16), + TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), + TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::S16), + TensorInfo(TensorShape(48U, 11U, 2U), 1, DataType::F32), + })), + framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::F32), + TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::F16), + TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), + TensorInfo(TensorShape(32U, 13U, 2U), 1, DataType::U8), + TensorInfo(TensorShape(48U, 11U, 2U), 1, DataType::F32), + })), + framework::dataset::make("Expected", { true, true, false, false, false})), + input1_info, input2_info, output_info, expected) +{ + ARM_COMPUTE_EXPECT(bool(CLElementwisePower::validate(&input1_info.clone()->set_is_resizable(false), &input2_info.clone()->set_is_resizable(false), &output_info.clone()->set_is_resizable(false))) == expected, framework::LogLevel::ERRORS); +} +// clang-format on +// *INDENT-ON* + +template <typename T> +using CLElementwisePowerFixture = ElementwisePowerValidationFixture<CLTensor, CLAccessor, CLElementwisePower, T>; + +template <typename T> +using CLElementwisePowerBroadcastFixture = ElementwisePowerBroadcastValidationFixture<CLTensor, CLAccessor, CLElementwisePower, T>; + +TEST_SUITE(Float) +TEST_SUITE(FP16) +FIXTURE_DATA_TEST_CASE(RunSmall, CLElementwisePowerFixture<half>, framework::DatasetMode::ALL, combine(datasets::SmallShapes(), ElementwisePowerFP16Dataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_fp16, 0.01); +} + +FIXTURE_DATA_TEST_CASE(RunSmallBroadcast, CLElementwisePowerBroadcastFixture<half>, framework::DatasetMode::ALL, combine(datasets::SmallShapesBroadcast(), + ElementwisePowerFP16Dataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_fp16, 0.01); +} +TEST_SUITE_END() //FP16 + +TEST_SUITE(FP32) +FIXTURE_DATA_TEST_CASE(RunSmall, CLElementwisePowerFixture<float>, framework::DatasetMode::ALL, combine(datasets::SmallShapes(), ElementwisePowerFP32Dataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_fp32); +} + +FIXTURE_DATA_TEST_CASE(RunSmallBroadcast, CLElementwisePowerBroadcastFixture<float>, framework::DatasetMode::ALL, combine(datasets::SmallShapesBroadcast(), + ElementwisePowerFP32Dataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_fp32); +} +TEST_SUITE_END() // FP32 +TEST_SUITE_END() // Float +TEST_SUITE_END() // ElementwisePower +TEST_SUITE_END() // CL +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/utils/TypePrinter.h b/utils/TypePrinter.h index 62edea344a..2f9f8cba68 100644 --- a/utils/TypePrinter.h +++ b/utils/TypePrinter.h @@ -1394,6 +1394,9 @@ inline ::std::ostream &operator<<(::std::ostream &os, const ArithmeticOperation case ArithmeticOperation::SQUARED_DIFF: os << "SQUARED_DIFF"; break; + case ArithmeticOperation::POWER: + os << "POWER"; + break; default: ARM_COMPUTE_ERROR("NOT_SUPPORTED!"); } |