352598b27f6ef3ce7a1061614150bec1bd0de887
[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 locomotiv
69 {
70
71 void NodeExecution::execute(loco::TensorSoftmax *softmax)
72 {
73   auto input_data = annot_data(softmax->input());
74
75   validate(input_data, "Input not ready");
76   validate(annot_domain(softmax->input()) == loco::Domain::Tensor,
77            "Input domain of TensorSoftmax is not Tensor");
78
79   std::unique_ptr<NodeData> softmax_data = nullptr;
80
81   switch (input_data->dtype())
82   {
83     case loco::DataType::FLOAT32:
84     {
85       auto axis = softmax->axis();
86
87       auto *input_shape = input_data->shape();
88       auto input_bufptr = input_data->as_f32_bufptr();
89       auto softmax_buf = make_buffer<float, LexicalLayout>(*input_data->shape());
90
91       auto reduce_sum_shape = reduce_shape(*input_shape, axis);
92       auto reduce_sum_bufptr = make_buffer<float, LexicalLayout>(reduce_sum_shape);
93
94       for (IndexEnumerator e{*input_shape}; e.valid(); e.advance())
95       {
96         const auto &index = e.current();
97         const auto r_index = reduce_index(index, axis);
98
99         reduce_sum_bufptr.at(r_index) += exp(input_bufptr->at(index));
100       }
101
102       for (IndexEnumerator e{*input_shape}; e.valid(); e.advance())
103       {
104         const auto &index = e.current();
105         const auto r_index = reduce_index(index, axis);
106
107         softmax_buf.at(index) = exp(input_bufptr->at(index)) / reduce_sum_bufptr.at(r_index);
108       }
109
110       softmax_data = make_data(softmax_buf);
111       break;
112     }
113     default:
114       throw std::runtime_error("NYI for this DataType");
115   }
116
117   assert(softmax_data != nullptr);
118   annot_data(softmax, std::move(softmax_data));
119   annot_domain(softmax, annot_domain(softmax->input()));
120 }
121
122 } // namespace locomotiv