From 78155c63024c33d31e3b66e8e198fd5f93837df1 Mon Sep 17 00:00:00 2001 From: Won Jeon Date: Sat, 10 Jun 2023 00:20:04 +0000 Subject: Add support for ERF operator to reference model Signed-off-by: Won Jeon Change-Id: Ib42b867287b83a183a0d0fb1f1eb29974f58fae4 --- reference_model/include/operators.h | 4 +- reference_model/src/operators.cc | 33 ++++++++++- reference_model/src/ops/activation_funcs.cc | 29 ++++++++++ reference_model/src/ops/activation_funcs.h | 14 +++++ reference_model/src/ops/op_factory.cc | 6 ++ thirdparty/serialization_lib | 2 +- verif/conformance/test_select.py | 6 ++ .../tosa_base_profile_framework_ops_info.json | 13 ++++- verif/conformance/tosa_main_profile_ops_info.json | 65 ++++++++++++++++++++++ verif/frameworks/test_builder.py | 9 +++ verif/frameworks/tosa_verif_framework_generator.py | 7 +++ verif/generator/tosa_test_gen.py | 48 ++++++++++++++++ 12 files changed, 231 insertions(+), 5 deletions(-) diff --git a/reference_model/include/operators.h b/reference_model/include/operators.h index 6efb655..b12604f 100644 --- a/reference_model/include/operators.h +++ b/reference_model/include/operators.h @@ -1,5 +1,5 @@ -// Copyright (c) 2022, ARM Limited. +// Copyright (c) 2022-2023, ARM Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -150,6 +150,8 @@ extern "C" tosa_status_t tosa_run_tanh(tosa_tensor_t client_input, tosa_tensor_t client_output); + tosa_status_t tosa_run_erf(tosa_tensor_t client_input, tosa_tensor_t client_output); + tosa_status_t tosa_run_add(tosa_tensor_t client_input1, tosa_tensor_t client_input2, tosa_tensor_t client_output); tosa_status_t tosa_run_arithmetic_right_shift(tosa_tensor_t client_input1, diff --git a/reference_model/src/operators.cc b/reference_model/src/operators.cc index a0b5013..5796129 100644 --- a/reference_model/src/operators.cc +++ b/reference_model/src/operators.cc @@ -580,6 +580,37 @@ extern "C" return tosa_status_valid; } + tosa_status_t tosa_run_erf(tosa_tensor_t client_input, tosa_tensor_t client_output) + { + // Create operator attributes + TosaNoneAttribute attr; + + // Create tensors + tosa::TosaSerializationTensor* input = translate_client_tensor(client_input, "input"); + tosa::TosaSerializationTensor* output = translate_client_tensor(client_output, "output"); + + // Create operator + auto op = new tosa::TosaSerializationOperator(tosa::Op::Op_ERF, tosa::Attribute::Attribute_NONE, &attr, + { input->GetName() }, { output->GetName() }); + + // Create a tosa single-op basic block + tosa::TosaSerializationBasicBlock block("erf", "main", { op }, { input, output }, { input->GetName() }, + { output->GetName() }); + + // Setup model + TosaReference::ModelRunnerImpl runner; + TOSA_RETURN_ON_GRAPH_STATUS_ERROR(runner.initialize(block)); + TOSA_RETURN_ON_ERROR(runner.setInput(input->GetName(), client_input.data, client_input.size)); + + // Execute + TOSA_RETURN_ON_GRAPH_STATUS_ERROR(runner.run()); + + // Extract outputs + TOSA_RETURN_ON_ERROR(runner.getOutput(output->GetName(), client_output.data, client_output.size)); + + return tosa_status_valid; + } + tosa_status_t tosa_run_add(tosa_tensor_t client_input1, tosa_tensor_t client_input2, tosa_tensor_t client_output) { // Create operator attributes @@ -2324,4 +2355,4 @@ extern "C" return tosa_status_valid; } -} // extern "C" \ No newline at end of file +} // extern "C" diff --git a/reference_model/src/ops/activation_funcs.cc b/reference_model/src/ops/activation_funcs.cc index 6681d6d..12d0697 100644 --- a/reference_model/src/ops/activation_funcs.cc +++ b/reference_model/src/ops/activation_funcs.cc @@ -124,6 +124,30 @@ int OpTanh::register_fcn() return 0; } +template +int OpErf::register_fcn() +{ + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be similar than or equal to MAX_RANK"); + + switch (Dtype) + { + case TOSA_REF_TYPE_FP16: + case TOSA_REF_TYPE_BF16: + case TOSA_REF_TYPE_FP32: + this->fcn = [](InEigenType a) -> OutEigenType { return fpTrunc(erff(a)); }; + break; + case TOSA_REF_TYPE_FP64: + this->fcn = [](InEigenType a) -> OutEigenType { return erf(a); }; + break; + default: + ERROR_IF(true, "unsupported TOSA_REF_TYPE %s", EnumNameTOSAREFTYPE(Dtype)); + } + + return 0; +} + // template explicit instantiation DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpClamp, FP16); DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpClamp, BF16); @@ -141,3 +165,8 @@ DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTanh, BF16); DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTanh, FP16); DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTanh, FP32); DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpTanh, FP64); + +DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpErf, BF16); +DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpErf, FP16); +DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpErf, FP32); +DEF_INSTANTIATE_RANK0_6_ONE_RANK_ONE_TYPE(OpErf, FP64); diff --git a/reference_model/src/ops/activation_funcs.h b/reference_model/src/ops/activation_funcs.h index 2372fcb..a7e1275 100644 --- a/reference_model/src/ops/activation_funcs.h +++ b/reference_model/src/ops/activation_funcs.h @@ -77,6 +77,20 @@ public: virtual int register_fcn(); }; +template +class OpErf : public UnaryNode +{ +public: + OpErf(SubgraphTraverser* sgt_, TosaAttributeBase* attribute_, uint64_t id_) + : UnaryNode(sgt_, Op_ERF, id_) + { + register_fcn(); + } + using InEigenType = typename GetEigenType::type; + using OutEigenType = typename GetEigenType::type; + virtual int register_fcn(); +}; + }; // namespace TosaReference #endif diff --git a/reference_model/src/ops/op_factory.cc b/reference_model/src/ops/op_factory.cc index 0a78884..a3069dc 100644 --- a/reference_model/src/ops/op_factory.cc +++ b/reference_model/src/ops/op_factory.cc @@ -161,6 +161,12 @@ GraphNode* OpFactory::newOp(SubgraphTraverser* sgt, DEF_FACTORY_RANK0_6_ONE_RANK_ONE_TYPE(OpTanh, FP32); DEF_FACTORY_RANK0_6_ONE_RANK_ONE_TYPE(OpTanh, FP64); break; + case Op_ERF: + DEF_FACTORY_RANK0_6_ONE_RANK_ONE_TYPE(OpErf, FP16); + DEF_FACTORY_RANK0_6_ONE_RANK_ONE_TYPE(OpErf, BF16); + DEF_FACTORY_RANK0_6_ONE_RANK_ONE_TYPE(OpErf, FP32); + DEF_FACTORY_RANK0_6_ONE_RANK_ONE_TYPE(OpErf, FP64); + break; // ewise_binary case Op_ADD: diff --git a/thirdparty/serialization_lib b/thirdparty/serialization_lib index 8a27043..3acb1cb 160000 --- a/thirdparty/serialization_lib +++ b/thirdparty/serialization_lib @@ -1 +1 @@ -Subproject commit 8a2704330c18532d79a65ad2733458a80bf9c5b8 +Subproject commit 3acb1cbfdd492ab4f657799ed0c2279a5e390248 diff --git a/verif/conformance/test_select.py b/verif/conformance/test_select.py index 9868a7f..f4e2a61 100644 --- a/verif/conformance/test_select.py +++ b/verif/conformance/test_select.py @@ -518,6 +518,12 @@ class ExpOperator(Operator): name = "exp" +class ErfOperator(Operator): + """Test selector for the ERF operator.""" + + name = "erf" + + class FFT2DOperator(Operator): """Test selector for the FFT2D operator.""" diff --git a/verif/conformance/tosa_base_profile_framework_ops_info.json b/verif/conformance/tosa_base_profile_framework_ops_info.json index 24a23b5..5d7e4a3 100644 --- a/verif/conformance/tosa_base_profile_framework_ops_info.json +++ b/verif/conformance/tosa_base_profile_framework_ops_info.json @@ -85,6 +85,16 @@ "tosa-mi" ] }, + "erf": { + "tests": [ + "erf_13x21x3_qu8", + "erf_14x19_qi8", + "erf_1x8x4x17_qi16" + ], + "profile": [ + "tosa-mi" + ] + }, "fully_connected": { "alternate_names": [ "matmul" @@ -257,8 +267,7 @@ "tanh_1x8x4x17_qi16" ], "profile": [ - "tosa-bi", "tosa-mi" ] } -} \ No newline at end of file +} diff --git a/verif/conformance/tosa_main_profile_ops_info.json b/verif/conformance/tosa_main_profile_ops_info.json index 5df89d6..07b6af3 100644 --- a/verif/conformance/tosa_main_profile_ops_info.json +++ b/verif/conformance/tosa_main_profile_ops_info.json @@ -2925,5 +2925,70 @@ ] } } + }, + "erf": { + "group": "activation", + "profile": [ + "tosa-mi" + ], + "generation": { + "standard": { + "generator_args": [ + [ + "--target-dtype", + "fp32", + "--target-dtype", + "fp16", + "--target-dtype", + "bf16", + "--fp-values-range", + "-2.0,2.0", + "--tensor-dim-range", + "18,60", + "--target-rank", + "1", + "--target-rank", + "2", + "--target-rank", + "3" + ], + [ + "--target-dtype", + "fp32", + "--target-dtype", + "fp16", + "--target-dtype", + "bf16", + "--fp-values-range", + "-2.0,2.0", + "--tensor-dim-range", + "1,24", + "--target-rank", + "4", + "--target-rank", + "5" + ], + [ + "--target-dtype", + "fp32", + "--fp-values-range", + "-2.0,2.0", + "--target-shape", + "1,65535,2,1,1", + "--target-shape", + "1,65540,1,2" + ] + ] + } + }, + "selection": { + "default": { + "params": {}, + "permutes": [ + "shape", + "type" + ] + } + } } } \ No newline at end of file diff --git a/verif/frameworks/test_builder.py b/verif/frameworks/test_builder.py index 1b681d2..fcd72a3 100644 --- a/verif/frameworks/test_builder.py +++ b/verif/frameworks/test_builder.py @@ -348,6 +348,15 @@ class TBuilder: def eval(self, a): return tf.math.tanh(a, name=self.result_name) + class Erf: + # tfl.ops cannot be generated right now. + # https://github.com/tensorflow/tensorflow/issues/60809 + def __init__(self, name): + self.result_name = name + + def eval(self, a): + return tf.math.erf(a, name=self.result_name) + class Sin: def __init__(self, name): self.result_name = name diff --git a/verif/frameworks/tosa_verif_framework_generator.py b/verif/frameworks/tosa_verif_framework_generator.py index ccbe742..02ab8aa 100755 --- a/verif/frameworks/tosa_verif_framework_generator.py +++ b/verif/frameworks/tosa_verif_framework_generator.py @@ -338,6 +338,13 @@ TF_OP_LIST = { ), }, }, + "erf": { + "operands": (1, 0), + "build_fcn": (TBuilder.Erf, TGen.tgBasic, ArgGen.agNone), + "types": { + "tf": TYPE_F, + }, + }, "sin": { "operands": (1, 0), "build_fcn": (TBuilder.Sin, TGen.tgBasic, ArgGen.agNone), diff --git a/verif/generator/tosa_test_gen.py b/verif/generator/tosa_test_gen.py index 66084b4..bd371eb 100644 --- a/verif/generator/tosa_test_gen.py +++ b/verif/generator/tosa_test_gen.py @@ -1177,6 +1177,37 @@ class TosaTestGen: self.ser.addOperator(op["op"], input_list, output_list) return result_tens + def build_erf(self, op, a, validator_fcns=None, error_name=None): + result_tens = OutputShaper.unaryOp(self.ser, self.rng, a, error_name) + + # Invalidate Input/Output list for error if checks. + input_list = [a.name] + output_list = [result_tens.name] + pCount, cCount = op["operands"] + num_operands = pCount + cCount + input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( + self, error_name, input_list, output_list + ) + + if not TosaErrorValidator.evValidateErrorIfs( + self.ser, + validator_fcns, + error_name, + op=op, + input_shape=a.shape, + output_shape=result_tens.shape, + input_dtype=a.dtype, + output_dtype=result_tens.dtype, + result_tensors=[result_tens], + input_list=input_list, + output_list=output_list, + num_operands=num_operands, + ): + return None + + self.ser.addOperator(op["op"], input_list, output_list) + return result_tens + def build_concat(self, op, *a, validator_fcns=None, error_name=None): if error_name != ErrorIf.WrongInputType: assert type(a[-1]) == int @@ -2907,6 +2938,23 @@ class TosaTestGen: TosaErrorValidator.evWrongOutputList, ), }, + "erf": { + "op": Op.ERF, + "operands": (1, 0), + "build_fcn": ( + build_erf, + TosaTensorGen.tgBasic, + TosaTensorValuesGen.tvgDefault, + None, + ), + "types": TYPE_FP, + "error_if_validators": ( + TosaErrorValidator.evWrongInputType, + TosaErrorValidator.evWrongOutputType, + TosaErrorValidator.evWrongInputList, + TosaErrorValidator.evWrongOutputList, + ), + }, # Elementwise Binary Operators "add": { "op": Op.ADD, -- cgit v1.2.1