Imported Upstream version 1.9.0
[platform/core/ml/nnfw.git] / compiler / locomotiv / src / Node / Softmax.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "NodeExecution.h"
18
19 #include "NodeDataImpl.h"
20 #include "NodeDomain.h"
21 #include "Validation.h"
22
23 #include <nncc/core/ADT/tensor/Shape.h>
24 #include <nncc/core/ADT/tensor/Buffer.h>
25 #include <nncc/core/ADT/tensor/Index.h>
26 #include <nncc/core/ADT/tensor/IndexEnumerator.h>
27 #include <nncc/core/ADT/tensor/LexicalLayout.h>
28
29 using nncc::core::ADT::tensor::Index;
30 using nncc::core::ADT::tensor::IndexEnumerator;
31 using nncc::core::ADT::tensor::LexicalLayout;
32 using nncc::core::ADT::tensor::make_buffer;
33 using nncc::core::ADT::tensor::Shape;
34
35 #include <cassert>
36 #include <stdexcept>
37 #include <cmath>
38
39 namespace
40 {
41
42 Index reduce_index(const Index &index, uint32_t axis)
43 {
44   Index r_index;
45
46   r_index.resize(index.rank());
47   for (uint32_t i = 0; i < index.rank(); ++i)
48     r_index.at(i) = index.at(i);
49   r_index.at(axis) = 0;
50
51   return r_index;
52 }
53
54 Shape reduce_shape(const Shape &shape, uint32_t axis)
55 {
56   Shape r_shape;
57
58   r_shape.resize(shape.rank());
59   for (uint32_t i = 0; i < shape.rank(); ++i)
60     r_shape.dim(i) = shape.dim(i);
61   r_shape.dim(axis) = 1;
62
63   return r_shape;
64 }
65
66 } // namespace
67
68 namespace
69 {
70
71 using namespace locomotiv;
72
73 void execute_node(loco::TensorSoftmax *softmax)
74 {
75   auto input_data = annot_data(softmax->input());
76
77   validate(input_data, "Input not ready");
78   validate(annot_domain(softmax->input()) == loco::Domain::Tensor,
79            "Input domain of TensorSoftmax is not Tensor");
80
81   std::unique_ptr<NodeData> softmax_data = nullptr;
82
83   switch (input_data->dtype())
84   {
85     case loco::DataType::FLOAT32:
86     {
87       auto axis = softmax->axis();
88
89       auto *input_shape = input_data->shape();
90       auto input_bufptr = input_data->as_f32_bufptr();
91       auto softmax_buf = make_buffer<float, LexicalLayout>(*input_data->shape());
92
93       auto reduce_sum_shape = reduce_shape(*input_shape, axis);
94       auto reduce_sum_bufptr = make_buffer<float, LexicalLayout>(reduce_sum_shape);
95
96       for (IndexEnumerator e{*input_shape}; e.valid(); e.advance())
97       {
98         const auto &index = e.current();
99         const auto r_index = reduce_index(index, axis);
100
101         reduce_sum_bufptr.at(r_index) += exp(input_bufptr->at(index));
102       }
103
104       for (IndexEnumerator e{*input_shape}; e.valid(); e.advance())
105       {
106         const auto &index = e.current();
107         const auto r_index = reduce_index(index, axis);
108
109         softmax_buf.at(index) = exp(input_bufptr->at(index)) / reduce_sum_bufptr.at(r_index);
110       }
111
112       softmax_data = make_data(softmax_buf);
113       break;
114     }
115     default:
116       throw std::runtime_error("NYI for this DataType");
117   }
118
119   assert(softmax_data != nullptr);
120   annot_data(softmax, std::move(softmax_data));
121   annot_domain(softmax, annot_domain(softmax->input()));
122 }
123
124 } // namespace
125
126 namespace locomotiv
127 {
128
129 void NodeExecution::execute(loco::TensorSoftmax *softmax) { execute_node(softmax); }
130
131 } // namespace locomotiv