Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / onert-micro / luci-interpreter / src / kernels / Sub.test.cpp
index 9abafd4..ff267b1 100644 (file)
  * limitations under the License.
  */
 
-#include "kernels/Sub.h"
 #include "kernels/TestUtils.h"
-#include "luci_interpreter/TestMemoryManager.h"
+#include "luci_interpreter/test_models/sub/FloatSubKernel.h"
+#include "luci_interpreter/test_models/sub/IntSubKernel.h"
+#include "luci_interpreter/test_models/sub/NegSubKernel.h"
 
-#include <algorithm>
+#include "loader/ModuleLoader.h"
 
 namespace luci_interpreter
 {
-namespace kernels
-{
 namespace
 {
 
 using namespace testing;
-using std::pair;
-using std::vector;
-using std::transform;
-using std::initializer_list;
 
 class SubTest : public ::testing::Test
 {
-protected:
-  void SetUp() override { _memory_manager = std::make_unique<TestMemoryManager>(); }
-
-  std::unique_ptr<IMemoryManager> _memory_manager;
+  // Do nothing
 };
 
-// for quantized Add, the error shouldn't exceed step
-float GetTolerance(float min, float max)
-{
-  float kQuantizedStep = (max - min) / 255.0;
-  return kQuantizedStep;
-}
-
-TEST_F(SubTest, Uint8)
+template <typename T> std::vector<T> checkSubKernel(test_kernel::TestDataBase<T> *test_data_base)
 {
-  Shape base_shape = {2, 3, 1, 2};
-  vector<float> base_data = {-0.3f, 2.3f, 0.9f,  0.5f, 0.8f, -1.1f,
-                             1.2f,  2.8f, -1.6f, 0.0f, 0.7f, -2.2f};
-  vector<Shape> test_shapes = {{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}};
-  vector<float> test_data = {0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f};
-  vector<vector<int32_t>> output_shapes = {{2, 3, 3, 2}, {2, 3, 1, 2}, {2, 3, 3, 2}, {2, 3, 1, 2}};
-  vector<vector<float>> output_data = {
-    {-0.5f, 2.0f,  0.1f,  1.8f,  -1.3f, 1.4f,  0.7f, 0.2f,  1.3f, 0.0f,  -0.1f, -0.4f,
-     0.6f,  -1.4f, 1.2f,  -1.6f, -0.2f, -2.0f, 1.0f, 2.5f,  1.6f, 2.3f,  0.2f,  1.9f,
-     -1.8f, -0.3f, -1.2f, -0.5f, -2.6f, -0.9f, 0.5f, -2.5f, 1.1f, -2.7f, -0.3f, -3.0f},
-    {-0.5f, 2.0f, 1.3f, 0.0f, -0.2f, -2.0f, 1.0f, 2.5f, -1.2f, -0.5f, -0.3f, -3.0f},
-    {-0.5f, 2.1f,  -0.6f, 2.0f,  0.1f,  2.7f,  0.7f, 0.3f,  0.6f,  0.2f,  1.3f,  0.9f,
-     0.6f,  -1.3f, 0.5f,  -1.4f, 1.2f,  -0.7f, 0.7f, 2.3f,  0.2f,  1.8f,  0.3f,  1.9f,
-     -2.1f, -0.5f, -2.6f, -1.0f, -2.5f, -0.9f, 0.2f, -2.7f, -0.3f, -3.0f, -0.2f, -3.0f},
-    {-0.5f, 2.1f, 0.6f, 0.2f, 1.2f, -0.7f, 0.7f, 2.3f, -2.6f, -1.0f, -0.2f, -3.0f}};
+  MemoryManager memory_manager{};
+  RuntimeModule runtime_module{};
+  bool dealloc_input = true;
 
-  float kQuantizedTolerance = GetTolerance(-3.f, 3.f);
-  pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-3.f, 3.f);
-  for (size_t i = 0; i < output_data.size(); ++i)
-  {
-    Tensor input1_tensor = makeInputTensor<DataType::U8>(
-      base_shape, quant_param.first, quant_param.second, base_data, _memory_manager.get());
-    Tensor input2_tensor = makeInputTensor<DataType::U8>(
-      test_shapes[i], quant_param.first, quant_param.second, test_data, _memory_manager.get());
-    Tensor output_tensor =
-      makeOutputTensor(getElementType<uint8_t>(), quant_param.first, quant_param.second);
-
-    SubParams params{};
-    params.activation = Activation::NONE;
+  // Load model with single op
+  auto *model_data_raw = reinterpret_cast<const char *>(test_data_base->get_model_ptr());
+  ModuleLoader::load(&runtime_module, &memory_manager, model_data_raw, dealloc_input);
 
-    Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
-    kernel.configure();
-    _memory_manager->allocate_memory(output_tensor);
-    kernel.execute();
+  auto *main_runtime_graph = runtime_module.getMainGraph();
+  assert(main_runtime_graph->getNumOfInputTensors() == 2);
 
-    EXPECT_THAT(dequantizeTensorData(output_tensor),
-                FloatArrayNear(output_data[i], kQuantizedTolerance));
-    EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shapes[i]));
+  // set left input data
+  {
+    auto *input_tensor_data = reinterpret_cast<T *>(main_runtime_graph->configureGraphInput(0));
+    std::copy(test_data_base->get_input_data_by_index(0).begin(),
+              test_data_base->get_input_data_by_index(0).end(), input_tensor_data);
   }
 
-  // Inversion step for output_data, because subtract is not commutative operation
-  auto multiply = [](auto &i) {
-    transform(i.begin(), i.end(), i.begin(), [](auto &value) { return value * -1.0f; });
-  };
-  for_each(output_data.begin(), output_data.end(), multiply);
-
-  // Re-run with exchanged inputs.
-  for (size_t i = 0; i < output_data.size(); ++i)
+  // set right input data
   {
-    Tensor input1_tensor = makeInputTensor<DataType::U8>(
-      test_shapes[i], quant_param.first, quant_param.second, test_data, _memory_manager.get());
-    Tensor input2_tensor = makeInputTensor<DataType::U8>(
-      base_shape, quant_param.first, quant_param.second, base_data, _memory_manager.get());
-    Tensor output_tensor =
-      makeOutputTensor(getElementType<uint8_t>(), quant_param.first, quant_param.second);
+    auto *input_tensor_data = reinterpret_cast<T *>(main_runtime_graph->configureGraphInput(1));
+    std::copy(test_data_base->get_input_data_by_index(1).begin(),
+              test_data_base->get_input_data_by_index(1).end(), input_tensor_data);
+  }
 
-    SubParams params{};
-    params.activation = Activation::NONE;
+  runtime_module.execute();
 
-    Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
-    kernel.configure();
-    _memory_manager->allocate_memory(output_tensor);
-    kernel.execute();
+  assert(main_runtime_graph->getNumOfOutputTensors() == 1);
 
-    EXPECT_THAT(dequantizeTensorData(output_tensor),
-                FloatArrayNear(output_data[i], kQuantizedTolerance));
-    EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shapes[i]));
-  }
+  T *output_data = reinterpret_cast<T *>(main_runtime_graph->getOutputDataByIndex(0));
+  const size_t num_elements = (main_runtime_graph->getOutputDataSizeByIndex(0) / sizeof(T));
+  std::vector<T> output_data_vector(output_data, output_data + num_elements);
+  return output_data_vector;
 }
 
-TEST_F(SubTest, Float)
+TEST_F(SubTest, Float_P)
 {
-  Shape base_shape = {2, 3, 1, 2};
-  vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}};
-  vector<vector<int32_t>> output_shapes{{2, 3, 3, 2}, {2, 3, 1, 2}, {2, 3, 3, 2}, {2, 3, 1, 2}};
-  vector<vector<float>> test_outputs = {
-    {0.0f, 2.0f, 0.1f, 1.8f, 0.0f, 1.4f, 0.7f, 0.2f, 1.3f, 0.0f, 0.0f, 0.0f,
-     0.6f, 0.0f, 1.2f, 0.0f, 0.0f, 0.0f, 1.0f, 2.5f, 1.6f, 2.3f, 0.2f, 1.9f,
-     0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.1f, 0.0f, 0.0f, 0.0f},
-    {0.0f, 2.0f, 1.3f, 0.0f, 0.0f, 0.0f, 1.0f, 2.5f, 0.0f, 0.0f, 0.0f, 0.0f},
-    {0.0f, 2.1f, 0.0f, 2.0f, 0.1f, 2.7f, 0.7f, 0.3f, 0.6f, 0.2f, 1.3f, 0.9f,
-     0.6f, 0.0f, 0.5f, 0.0f, 1.2f, 0.0f, 0.7f, 2.3f, 0.2f, 1.8f, 0.3f, 1.9f,
-     0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
-    {0.0f, 2.1f, 0.6f, 0.2f, 1.2f, 0.0f, 0.7f, 2.3f, 0.0f, 0.0f, 0.0f, 0.0f}};
-
-  vector<float> input1_data{-0.3f, 2.3f, 0.9f,  0.5f, 0.8f, -1.1f,
-                            1.2f,  2.8f, -1.6f, 0.0f, 0.7f, -2.2f};
-  vector<float> input2_data{0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f};
-  for (size_t i = 0; i < test_shapes.size(); ++i)
+  // No broadcast
   {
-    Tensor input1_tensor =
-      makeInputTensor<DataType::FLOAT32>(base_shape, input1_data, _memory_manager.get());
-    Tensor input2_tensor =
-      makeInputTensor<DataType::FLOAT32>(test_shapes[i], input2_data, _memory_manager.get());
-    Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
-
-    SubParams params{};
-    params.activation = Activation::RELU;
-
-    Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
-    kernel.configure();
-    _memory_manager->allocate_memory(output_tensor);
-    kernel.execute();
-
-    EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs[i], 0.0001f))
-      << "With shape number " << i;
-
-    EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shapes[i]));
+    const bool is_with_broadcast = false;
+    test_kernel::TestDataFloatSub test_data_float_kernel(is_with_broadcast);
+    std::vector<float> output_data_vector = checkSubKernel(&test_data_float_kernel);
+    EXPECT_THAT(output_data_vector, kernels::testing::FloatArrayNear(
+                                      test_data_float_kernel.get_output_data_by_index(0), 0.0001f));
   }
-}
-
-template <loco::DataType DType> void CheckInteger(luci_interpreter::IMemoryManager *memory_manager)
-{
-  using dtype = typename loco::DataTypeImpl<DType>::Type;
-  Shape base_shape = {2, 3, 1, 2};
-  std::vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}};
-  std::vector<std::vector<dtype>> test_outputs = {
-    {0, 1, 2, 3, 0, 0, 0, 0, 4,  1, 0, 0, 0, 0, 7,  0, 3, 0,
-     0, 2, 4, 4, 0, 0, 3, 0, 10, 0, 6, 0, 3, 0, 10, 2, 6, 0},
-    {0, 1, 4, 1, 3, 0, 0, 2, 10, 0, 6, 0},
-    {0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 4, 3, 0, 0, 3, 0, 7, 0,
-     2, 4, 0, 2, 0, 0, 8, 0, 6, 0, 1, 0, 8, 2, 6, 0, 1, 0},
-    {0, 0, 0, 0, 7, 0, 2, 4, 6, 0, 1, 0}};
-  std::vector<dtype> input1_data{-1, 2, 1, 0, 4, -5, 1, 3, 7, -1, 7, 1};
-  std::vector<dtype> input2_data{4, 1, -3, -1, 1, 6};
-  for (size_t i = 0; i < test_shapes.size(); ++i)
+  // With broadcast
   {
-    Tensor input1_tensor = makeInputTensor<DType>(base_shape, input1_data, memory_manager);
-    Tensor input2_tensor = makeInputTensor<DType>(test_shapes[i], input2_data, memory_manager);
-    Tensor output_tensor = makeOutputTensor(DType);
-
-    SubParams params{};
-    params.activation = Activation::RELU;
-
-    Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
-    kernel.configure();
-    memory_manager->allocate_memory(output_tensor);
-    kernel.execute();
-
-    EXPECT_THAT(extractTensorData<dtype>(output_tensor), test_outputs[i])
-      << "With shape number " << i;
+    const bool is_with_broadcast = true;
+    test_kernel::TestDataFloatSub test_data_float_kernel(is_with_broadcast);
+    std::vector<float> output_data_vector = checkSubKernel(&test_data_float_kernel);
+    EXPECT_THAT(output_data_vector, kernels::testing::FloatArrayNear(
+                                      test_data_float_kernel.get_output_data_by_index(0), 0.0001f));
   }
-};
-
-TEST_F(SubTest, SInt32)
-{
-  CheckInteger<loco::DataType::S32>(_memory_manager.get());
-  SUCCEED();
 }
 
-TEST_F(SubTest, SInt64)
+TEST_F(SubTest, INT_P)
 {
-  CheckInteger<loco::DataType::S64>(_memory_manager.get());
-  SUCCEED();
+  // No broadcast
+  {
+    const bool is_with_broadcast = false;
+    test_kernel::TestDataIntSub test_data_kernel(is_with_broadcast);
+    const auto output_data_vector = checkSubKernel<int32_t>(&test_data_kernel);
+    EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0));
+  }
+  // With broadcast
+  {
+    const bool is_with_broadcast = true;
+    test_kernel::TestDataIntSub test_data_kernel(is_with_broadcast);
+    const auto output_data_vector = checkSubKernel<int32_t>(&test_data_kernel);
+    EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0));
+  }
 }
 
-TEST_F(SubTest, Input_Output_Type_NEG)
+TEST_F(SubTest, Inputs_type_mismatch_NEG)
 {
-  Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}, _memory_manager.get());
-  Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {2}, _memory_manager.get());
-  Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
-
-  SubParams params{};
-  params.activation = Activation::RELU;
-
-  Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
-  EXPECT_ANY_THROW(kernel.configure());
+  test_kernel::NegTestDataInputsTypeMismatchSubKernel test_data_kernel;
+  MemoryManager memory_manager{};
+  RuntimeModule runtime_module{};
+  bool dealloc_input = true;
+  // Load model with single op
+  auto *model_data_raw = reinterpret_cast<const char *>(test_data_kernel.get_model_ptr());
+  EXPECT_DEATH(ModuleLoader::load(&runtime_module, &memory_manager, model_data_raw, dealloc_input),
+               "");
 }
 
-TEST_F(SubTest, Invalid_Output_Type_NEG)
+TEST_F(SubTest, Input_output_type_mismatch_NEG)
 {
-  Tensor input1_tensor = makeInputTensor<DataType::S64>({1}, {1}, _memory_manager.get());
-  Tensor input2_tensor = makeInputTensor<DataType::S64>({1}, {2}, _memory_manager.get());
-  Tensor output_tensor = makeOutputTensor(DataType::S32);
-
-  SubParams params{};
-  params.activation = Activation::RELU;
-
-  Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
-  EXPECT_ANY_THROW(kernel.configure());
+  test_kernel::NegTestDataInputOutputTypeMismatchSubKernel test_data_kernel;
+  MemoryManager memory_manager{};
+  RuntimeModule runtime_module{};
+  bool dealloc_input = true;
+  // Load model with single op
+  auto *model_data_raw = reinterpret_cast<const char *>(test_data_kernel.get_model_ptr());
+  EXPECT_DEATH(ModuleLoader::load(&runtime_module, &memory_manager, model_data_raw, dealloc_input),
+               "");
 }
 
-TEST_F(SubTest, Invalid_Input_Type_NEG)
+TEST_F(SubTest, No_quant_params_NEG)
 {
-  Tensor input1_tensor = makeInputTensor<DataType::U64>({1}, {1}, _memory_manager.get());
-  Tensor input2_tensor = makeInputTensor<DataType::U64>({1}, {2}, _memory_manager.get());
-  Tensor output_tensor = makeOutputTensor(DataType::U64);
-
-  SubParams params{};
-  params.activation = Activation::RELU;
-
-  Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
-  kernel.configure();
-  _memory_manager->allocate_memory(output_tensor);
-  EXPECT_ANY_THROW(kernel.execute());
+  test_kernel::NegTestDataNoQuantParamsSubKernel test_data_kernel;
+  MemoryManager memory_manager{};
+  RuntimeModule runtime_module{};
+  bool dealloc_input = true;
+  // Load model with single op
+  auto *model_data_raw = reinterpret_cast<const char *>(test_data_kernel.get_model_ptr());
+  EXPECT_DEATH(ModuleLoader::load(&runtime_module, &memory_manager, model_data_raw, dealloc_input),
+               "");
 }
 
-TEST_F(SubTest, Mismatching_Input_Int_Types_NEG)
-{
-  Tensor input1_tensor = makeInputTensor<DataType::S32>({1}, {1}, _memory_manager.get());
-  Tensor input2_tensor = makeInputTensor<DataType::S64>({1}, {2}, _memory_manager.get());
-  Tensor output_tensor = makeOutputTensor(DataType::S32);
-
-  SubParams params{};
-  params.activation = Activation::NONE;
-
-  Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
-  EXPECT_ANY_THROW(kernel.configure());
-}
+// TODO: add tests for U8 and S16
+// TODO: add tests for inplace optimizations for all types
 
 } // namespace
-} // namespace kernels
 } // namespace luci_interpreter