Compute Library
 21.02
SoftmaxLayer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2020 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "SoftmaxLayer.h"
25 
27 #include "arm_compute/core/Types.h"
28 #include "utils/TypePrinter.h"
29 
30 namespace arm_compute
31 {
32 namespace test
33 {
34 namespace validation
35 {
36 namespace reference
37 {
38 template <typename T, typename std::enable_if<is_floating_point<T>::value, int>::type>
39 SimpleTensor<T> softmax_layer_generic(const SimpleTensor<T> &src, float beta, int32_t axis, bool is_log)
40 {
41  // Create reference
42  SimpleTensor<T> dst{ src.shape(), src.data_type(), 1 };
43 
44  const int32_t n_dims = static_cast<int32_t>(src.shape().num_dimensions());
45  ARM_COMPUTE_ERROR_ON(axis < -n_dims || axis >= n_dims);
46 
47  const unsigned int actual_axis = static_cast<unsigned int>(wrap_around(axis, n_dims));
48  Window window;
49  window.use_tensor_dimensions(src.shape());
50  const unsigned int axis_dimension = src.shape()[actual_axis];
51  window.set(actual_axis, Window::Dimension(0, 1, 1));
52 
53  execute_window_loop(window, [&](const Coordinates & id)
54  {
55  // Find max along axis
56  Coordinates offset(id);
57  offset.set(actual_axis, 0);
58  T max = *reinterpret_cast<const T *>(src(offset));
59  for(unsigned int axis_id = 1; axis_id < axis_dimension; ++axis_id)
60  {
61  offset.set(actual_axis, axis_id);
62  const T val = *reinterpret_cast<const T *>(src(offset));
63  if(val > max)
64  {
65  max = val;
66  }
67  }
68 
69  // Regularize
70  T sum(0.f);
71  for(unsigned int axis_id = 0; axis_id < axis_dimension; ++axis_id)
72  {
73  offset.set(actual_axis, axis_id);
74  const T val = *reinterpret_cast<const T *>(src(offset));
75  T res{ (val - max) *beta };
76  if(is_log)
77  {
78  sum += std::exp(res);
79  }
80  else
81  {
82  res = std::exp(res);
83  sum += res;
84  }
85  *reinterpret_cast<T *>(dst(offset)) = res;
86  }
87 
88  // Normalize
89  for(unsigned int axis_id = 0; axis_id < axis_dimension; ++axis_id)
90  {
91  offset.set(actual_axis, axis_id);
92  const T val = *reinterpret_cast<const T *>(dst(offset));
93  if(is_log)
94  {
95  *reinterpret_cast<T *>(dst(offset)) = val - static_cast<T>(std::log(sum));
96  }
97  else
98  {
99  *reinterpret_cast<T *>(dst(offset)) = val / sum;
100  }
101  }
102  });
103  return dst;
104 }
105 
106 template SimpleTensor<float> softmax_layer_generic(const SimpleTensor<float> &src, float beta, int32_t axis, bool is_log);
107 template SimpleTensor<half> softmax_layer_generic(const SimpleTensor<half> &src, float beta, int32_t axis, bool is_log);
108 
109 template <typename T, typename std::enable_if<is_floating_point<T>::value, int>::type>
110 SimpleTensor<T> softmax_layer(const SimpleTensor<T> &src, float beta, int32_t axis, bool is_log)
111 {
112  return softmax_layer_generic<T>(src, beta, axis, is_log);
113 }
114 
115 template < typename T, typename std::enable_if < std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value, int >::type >
116 SimpleTensor<T> softmax_layer(const SimpleTensor<T> &src, float beta, int32_t axis, bool is_log)
117 {
118  const QuantizationInfo output_quantization_info = arm_compute::get_softmax_output_quantization_info(src.data_type(), is_log);
119 
121  SimpleTensor<float> dst_tmp = softmax_layer<float>(src_tmp, beta, axis, is_log);
122  SimpleTensor<T> dst = convert_to_asymmetric<T>(dst_tmp, output_quantization_info);
123  return dst;
124 }
125 
126 template SimpleTensor<float> softmax_layer(const SimpleTensor<float> &src, float beta, int32_t axis, bool is_log);
127 template SimpleTensor<half> softmax_layer(const SimpleTensor<half> &src, float beta, int32_t axis, bool is_log);
128 template SimpleTensor<uint8_t> softmax_layer(const SimpleTensor<uint8_t> &src, float beta, int32_t axis, bool is_log);
129 template SimpleTensor<int8_t> softmax_layer(const SimpleTensor<int8_t> &src, float beta, int32_t axis, bool is_log);
130 
131 } // namespace reference
132 } // namespace validation
133 } // namespace test
134 } // namespace arm_compute
void set(size_t dimension, T value, bool increase_dim_unit=true)
Accessor to set the value of one of the dimensions.
Definition: Dimensions.h:76
__global uchar * offset(const Image *img, int x, int y)
Get the pointer position of a Image.
Definition: helpers.h:846
DATA_TYPE sum(__global const DATA_TYPE *input)
Calculate sum of a vector.
DataType data_type() const override
Data type of the tensor.
Definition: SimpleTensor.h:357
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
SimpleTensor< float > convert_from_asymmetric(const SimpleTensor< uint8_t > &src)
Definition: Helpers.cpp:112
QuantizationInfo get_softmax_output_quantization_info(DataType input_type, bool is_log)
Returns output quantization information for softmax layer.
Definition: Utils.cpp:462
Describe one of the image&#39;s dimensions with a start, end and step.
Definition: Window.h:77
TensorShape shape() const override
Shape of the tensor.
Definition: SimpleTensor.h:320
decltype(strategy::transforms) typedef type
void use_tensor_dimensions(const TensorShape &shape, size_t first_dimension=Window::DimX)
Use the tensor&#39;s dimensions to fill the window dimensions.
Definition: Window.inl:276
SimpleTensor< float > src
Definition: DFT.cpp:155
Copyright (c) 2017-2021 Arm Limited.
T wrap_around(T x, T m)
Wrap-around a number within the range 0 <= x < m.
Definition: Helpers.h:231
Quantization information.
SimpleTensor< T > softmax_layer_generic(const SimpleTensor< T > &src, float beta, int32_t axis, bool is_log)
Coordinates of an item.
Definition: Coordinates.h:37
void set(size_t dimension, const Dimension &dim)
Set the values of a given dimension.
Definition: Window.inl:49
SimpleTensor< T > softmax_layer(const SimpleTensor< T > &src, float beta, int32_t axis, bool is_log)
Simple tensor object that stores elements in a consecutive chunk of memory.
Definition: SimpleTensor.h:58
void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators)
Iterate through the passed window, automatically adjusting the iterators and calling the lambda_funct...
Definition: Helpers.inl:77
Describe a multidimensional execution window.
Definition: Window.h:39