a0075c3d0a2508b1d648b48a7e9693ae9f481f0f
[platform/core/ml/nnfw.git] / compute / cker / include / cker / operation / L2Normalize.h
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3  * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #ifndef __NNFW_CKER_L2NORMALIZE_H__
19 #define __NNFW_CKER_L2NORMALIZE_H__
20
21 #include "cker/Shape.h"
22 #include "cker/Utils.h"
23 #include "cker/Types.h"
24
25 namespace nnfw
26 {
27 namespace cker
28 {
29
30 void L2NormalizeFloat32(const Shape &input_shape, const float *input_data,
31                         const Shape &output_shape, float *output_data)
32 {
33   float epsilon = 1e-6;
34   const int trailing_dim = input_shape.DimensionsCount() - 1;
35   const int outer_size = MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape);
36   const int depth = MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim);
37   for (int i = 0; i < outer_size; ++i)
38   {
39     float squared_l2_norm = 0;
40     for (int c = 0; c < depth; ++c)
41     {
42       const float val = input_data[c];
43       squared_l2_norm += val * val;
44     }
45     float l2_norm = std::sqrt(squared_l2_norm);
46     l2_norm = std::max(l2_norm, epsilon);
47     for (int c = 0; c < depth; ++c)
48     {
49       *output_data = *input_data / l2_norm;
50       ++output_data;
51       ++input_data;
52     }
53   }
54 }
55
56 void L2NormalizeQuant8(L2NormParams &params, const Shape &input_shape, const uint8_t *input_data,
57                        const Shape &output_shape, uint8_t *output_data)
58 {
59   const int trailing_dim = input_shape.DimensionsCount() - 1;
60   const int depth = MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim);
61   const int outer_size = MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape);
62   const int32_t input_zero_point = params.input_zero_point;
63
64   for (int i = 0; i < outer_size; ++i)
65   {
66     int32_t square_l2_norm = 0;
67     for (int c = 0; c < depth; c++)
68     {
69       // Note that input_data advances by depth in the second pass below.
70       int32_t diff = input_data[c] - input_zero_point;
71       square_l2_norm += diff * diff;
72     }
73     int32_t inv_l2norm_multiplier;
74     int inv_l2norm_shift;
75     GetInvSqrtQuantizedMultiplierExp(square_l2_norm, -1, &inv_l2norm_multiplier, &inv_l2norm_shift);
76     for (int c = 0; c < depth; c++)
77     {
78       int32_t diff = *input_data - input_zero_point;
79       int32_t rescaled_diff = MultiplyByQuantizedMultiplierSmallerThanOneExp(
80           128 * diff, inv_l2norm_multiplier, inv_l2norm_shift);
81       int32_t unclamped_output_val = 128 + rescaled_diff;
82       int32_t output_val = std::min(static_cast<int32_t>(255),
83                                     std::max(static_cast<int32_t>(0), unclamped_output_val));
84       *output_data = static_cast<uint8_t>(output_val);
85       ++input_data;
86       ++output_data;
87     }
88   }
89 }
90
91 } // namespace cker
92 } // namespace nnfw
93
94 #endif // __NNFW_CKER_L2NORMALIZE_H__