Skip to content

Commit

Permalink
[onert-micro] Add float L2Normalization kernel (#11590)
Browse files Browse the repository at this point in the history
This commit adds float L2Normalization kernel

ONE-DCO-1.0-Signed-off-by: Artem Balyshev <[email protected]>

Co-authored-by: Artem Balyshev <[email protected]>
  • Loading branch information
BalyshevArtem and Artem Balyshev authored Sep 26, 2023
1 parent 307d0b0 commit 48b6b90
Show file tree
Hide file tree
Showing 12 changed files with 392 additions and 233 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
*
* 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.
*/

#ifndef LUCI_INTERPRETER_TEST_MODELS_FLOAT_L2_NORMALIZATION_KERNEL_H
#define LUCI_INTERPRETER_TEST_MODELS_FLOAT_L2_NORMALIZATION_KERNEL_H

#include "TestDataL2NormalizeBase.h"

namespace luci_interpreter
{
namespace test_kernel
{
namespace l2_normalization_float
{
/*
* L2Normalization Kernel:
*
* Input(1, 4, 4, 3)
* |
* L2Normalization
* |
* Output(1, 4, 4, 3)
*/
const unsigned char test_kernel_model_circle[] = {
0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff,
0x90, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0xd4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x69, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00,
0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c,
0x65, 0x00, 0x00, 0x00};

const std::vector<float> input_data = {
9.992603, 8.346985, 22.960445, 45.584763, 26.916512, 33.256886, 12.787039, 40.30215,
32.26641, 13.645262, 36.445396, 33.06842, 37.449368, 14.05669, 17.87454, 7.8050013,
5.6068754, 17.868938, 40.134842, 24.222584, 42.0985, 26.406887, 11.48271, 33.00633,
39.676426, 46.740967, 38.20928, 45.924362, 39.70501, 32.05231, 41.742085, 29.257357,
42.27183, 35.843292, 28.056007, 31.480331, 34.84266, 34.666496, 26.273453, 33.72813,
23.426928, 14.348057, 52.57121, 17.464836, 33.1741, 29.476301, 22.09747, 32.685722};

const std::vector<float> reference_output_data = {
0.3785766, 0.31623122, 0.86987215, 0.72914726, 0.4305408, 0.53195775, 0.24041508, 0.75773954,
0.60665584, 0.26719585, 0.71365863, 0.64753205, 0.8547623, 0.32083663, 0.40797707, 0.38468635,
0.27634698, 0.8807093, 0.63699496, 0.3844456, 0.66816086, 0.6028728, 0.2621518, 0.7535389,
0.54921657, 0.6470067, 0.5289077, 0.66895926, 0.5783648, 0.46689144, 0.6303393, 0.4418098,
0.6383389, 0.6476525, 0.506944, 0.56881815, 0.6251807, 0.6220198, 0.47142372, 0.77535427,
0.53854656, 0.32983825, 0.81417507, 0.2704795, 0.5137703, 0.59851044, 0.44868472, 0.6636771};

} // namespace l2_normalization_float

class TestDataFloatL2Normalization : public TestDataL2NormalizationBase<float>
{
public:
TestDataFloatL2Normalization()
{
_input_data = l2_normalization_float::input_data;
_reference_output_data = l2_normalization_float::reference_output_data;
_test_kernel_model_circle = l2_normalization_float::test_kernel_model_circle;
}

~TestDataFloatL2Normalization() override = default;
};

} // namespace test_kernel
} // namespace luci_interpreter

#endif // LUCI_INTERPRETER_TEST_MODELS_FLOAT_L2_NORMALIZATION_KERNEL_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
*
* 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.
*/

#ifndef LUCI_INTERPRETER_TEST_MODELS_NEG_L2_NORMALIZE_KERNEL_H
#define LUCI_INTERPRETER_TEST_MODELS_NEG_L2_NORMALIZE_KERNEL_H

#include "TestDataL2NormalizeBase.h"

namespace luci_interpreter
{
namespace test_kernel
{
namespace neg_input_output_type_mismatch_l2_normalization_kernel
{
/*
* L2Normalization Kernel with input output type mismatch (should be equal):
*
* Input(1, 4, 4, 3) - Float
* |
* L2Normalization
* |
* Output(1, 4, 4, 3) - Int
*/
const unsigned char test_kernel_model_circle[] = {
0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff,
0x90, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x69, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00,
0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c,
0x65, 0x00, 0x00, 0x00};

} // namespace neg_input_output_type_mismatch_l2_normalization_kernel

class NegTestDataInputOutputTypeMismatchNegKernel : public NegTestDataBase
{
public:
NegTestDataInputOutputTypeMismatchNegKernel()
{
_test_kernel_model_circle =
neg_input_output_type_mismatch_l2_normalization_kernel::test_kernel_model_circle;
}

~NegTestDataInputOutputTypeMismatchNegKernel() override = default;

const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; }

protected:
const unsigned char *_test_kernel_model_circle;
};

} // namespace test_kernel
} // namespace luci_interpreter

#endif // LUCI_INTERPRETER_TEST_MODELS_NEG_L2_NORMALIZE_KERNEL_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
*
* 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.
*/

#ifndef LUCI_INTERPRETER_TEST_MODELS_L2_NORMALIZATION_KERNEL_BASE_H
#define LUCI_INTERPRETER_TEST_MODELS_L2_NORMALIZATION_KERNEL_BASE_H

#include "luci_interpreter/test_models/TestDataBase.h"

namespace luci_interpreter
{
namespace test_kernel
{

template <typename T> class TestDataL2NormalizationBase : public TestDataBase<T>
{
public:
TestDataL2NormalizationBase() = default;

const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; }

const std::vector<T> &get_input_data_by_index(int i) override final
{
switch (i)
{
case 0:
return _input_data;
default:
assert(false && "Wrong input index");
}
}

const std::vector<T> &get_output_data_by_index(int i) override final
{
assert(i == 0);
return _reference_output_data;
}

protected:
std::vector<T> _input_data;
std::vector<T> _reference_output_data;
const unsigned char *_test_kernel_model_circle;
};

} // namespace test_kernel
} // namespace luci_interpreter

#endif // LUCI_INTERPRETER_TEST_MODELS_L2_NORMALIZATION_KERNEL_BASE_H
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ REGISTER_KERNEL(RELU, Relu)
REGISTER_KERNEL(RELU6, Relu6)
REGISTER_KERNEL(REDUCE_PROD, ReduceCommon)
REGISTER_KERNEL(LESS, Less)
REGISTER_KERNEL(L2_NORMALIZATION, L2Normalize)
REGISTER_KERNEL(LESS_EQUAL, LessEqual)
REGISTER_KERNEL(LOGICAL_AND, LogicalAnd)
REGISTER_KERNEL(LOGICAL_OR, LogicalOr)
Expand Down
33 changes: 0 additions & 33 deletions onert-micro/luci-interpreter/pal/cmsisnn/PALL2Pool2D.h

This file was deleted.

55 changes: 55 additions & 0 deletions onert-micro/luci-interpreter/pal/common/PALL2Normalize.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
*
* 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.
*/

#ifndef LUCI_INTERPRETER_PAL_L2_NORMALIZE_COMMON_H
#define LUCI_INTERPRETER_PAL_L2_NORMALIZE_COMMON_H

#include "PALUtils.h"
#include <cmath>

namespace luci_interpreter_pal
{

inline void L2Normalization(const luci_interpreter::RuntimeShape &input_shape,
const float *input_data,
const luci_interpreter::RuntimeShape &output_shape, float *output_data,
float epsilon = 1e-6)
{
const int trailing_dim = input_shape.dimensionsCount() - 1;
const int outer_size =
flatSizeSkipDim(input_shape.dimsData(), trailing_dim, input_shape.dimensionsCount());
const int depth = MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim);
for (int i = 0; i < outer_size; ++i)
{
float squared_l2_norm = 0;
for (int c = 0; c < depth; ++c)
{
const float val = input_data[depth * i + c];
squared_l2_norm += val * val;
}
float l2_norm = std::sqrt(squared_l2_norm);
l2_norm = std::fmax(l2_norm, epsilon);
for (int c = 0; c < depth; ++c)
{
output_data[depth * i + c] = input_data[depth * i + c] / l2_norm;
}
}
}

} // namespace luci_interpreter_pal

#endif // LUCI_INTERPRETER_PAL_L2_NORMALIZE_COMMON_H
13 changes: 13 additions & 0 deletions onert-micro/luci-interpreter/pal/common/PALUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,19 @@ inline int MatchingDim(const luci_interpreter::RuntimeShape &shape1, int index1,
return shape1.dims(index1);
}

// Data is required to be contiguous, and so many operators can use either the
// full array flat size or the flat size with one dimension skipped (commonly
// the depth).
inline int flatSizeSkipDim(const int32_t *dims_data, int skip_dim, int num_dims)
{
int flat_size = 1;
for (int i = 0; i < num_dims; ++i)
{
flat_size *= (i == skip_dim) ? 1 : dims_data[i];
}
return flat_size;
}

inline int offset(const int32_t *dims_data, int i0, int i1, int i2, int i3)
{
return ((i0 * dims_data[1] + i1) * dims_data[2] + i2) * dims_data[3] + i3;
Expand Down
1 change: 1 addition & 0 deletions onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ REGISTER_KERNEL(RELU, Relu)
REGISTER_KERNEL(RELU6, Relu6)
REGISTER_KERNEL(REDUCE_PROD, ReduceCommon)
REGISTER_KERNEL(LESS, Less)
REGISTER_KERNEL(L2_NORMALIZATION, L2Normalize)
REGISTER_KERNEL(LESS_EQUAL, LessEqual)
REGISTER_KERNEL(LOGICAL_AND, LogicalAnd)
REGISTER_KERNEL(LOGICAL_OR, LogicalOr)
Expand Down
Loading

0 comments on commit 48b6b90

Please sign in to comment.