1 /*
2 * SPDX-FileCopyrightText: <text>Copyright 2010-2020, 2022, 2024 Arm Limited and/or its affiliates
3 * <open-source-office@arm.com></text>
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the License); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 /* ----------------------------------------------------------------------
21 * Project: CMSIS NN Library
22 * Title: arm_nn_activation_s16.c
23 * Description: Q15 neural network activation function using direct table look-up
24 *
25 * $Date: 19 January 2024
26 * $Revision: V.2.0.0
27 *
28 * Target Processor: Cortex-M cores
29 *
30 * -------------------------------------------------------------------- */
31
32 #include "arm_nn_tables.h"
33 #include "arm_nnfunctions.h"
34
35 /**
36 * @ingroup groupNN
37 */
38
39 /**
40 * @addtogroup Acti
41 * @{
42 */
43
44 /*
45 * @brief Neural network activation function using direct table look-up
46 *
47 * @note Refer header file for details.
48 *
49 */
50
arm_nn_activation_s16(const int16_t * input,int16_t * output,const int32_t size,const int32_t left_shift,const arm_nn_activation_type type)51 arm_cmsis_nn_status arm_nn_activation_s16(const int16_t *input,
52 int16_t *output,
53 const int32_t size,
54 const int32_t left_shift,
55 const arm_nn_activation_type type)
56 {
57 uint32_t abs_input_shift, max_saturation;
58 switch (type)
59 {
60 case ARM_SIGMOID:
61 abs_input_shift = 9;
62 max_saturation = 0x7FFF << 10;
63 break;
64 case ARM_TANH:
65 default:
66 abs_input_shift = 8;
67 max_saturation = 0xFFFF << 8;
68 break;
69 }
70
71 const int32_t input_multiplier = (left_shift < 0) ? 3 : 3 << left_shift;
72 const int32_t abs_left_shift = (left_shift < 0) ? -left_shift : 0;
73 const int32_t rounding = (abs_left_shift > 0) ? 1 << (abs_left_shift - 1) : 0;
74 // Use the LUT for sigmoid and take into account, that
75 // tanh(x) = 2*sigmoid(2*x) - 1
76
77 for (int i = 0; i < size; ++i, input++, output++)
78 {
79 const int32_t input_data = ((*input) * input_multiplier + rounding) >> abs_left_shift;
80 const uint32_t abs_input_data = input_data > 0 ? input_data : -input_data;
81 const uint32_t uh = abs_input_data >> abs_input_shift;
82 uint32_t result;
83
84 if (uh >= 255)
85 {
86 result = max_saturation;
87 }
88 else
89 {
90 const uint32_t ua = sigmoid_table_uint16[uh];
91 const uint32_t ub = sigmoid_table_uint16[uh + 1];
92 uint32_t ut;
93 if (type == ARM_SIGMOID)
94 {
95 ut = abs_input_data & 0x1ff;
96 }
97 else
98 {
99 ut = abs_input_data & 0x0ff;
100 }
101 result = (ua << abs_input_shift) + ut * (ub - ua);
102 }
103 if (type == ARM_SIGMOID)
104 {
105 result = (input_data >= 0) ? (result + (1 << 9)) : ((1 << 25) - result + (1 << 9) - 1);
106 result >>= 10;
107 }
108 else
109 {
110 result = (input_data >= 0) ? (result - (1 << 23)) + (1 << 7) : ((-result + (1 << 23)) + (1 << 7) - 1);
111 result >>= 8;
112 }
113 *output = (int16_t)result;
114 }
115
116 return ARM_CMSIS_NN_SUCCESS;
117 }
118
119 /**
120 * @} end of Acti group
121 */
122