Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / runtime / onert / backend / xnnpack / ops / FullyConnectedLayer.cc
1 /*
2  * Copyright (c) 2020 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 "FullyConnectedLayer.h"
18
19 #include "ir/Padding.h"
20
21 namespace onert
22 {
23 namespace backend
24 {
25 namespace xnnpack
26 {
27 namespace ops
28 {
29
30 FullyConnectedLayer::FullyConnectedLayer(const std::shared_ptr<ExternalContext> external_context)
31     : Layer(external_context), _input(nullptr), _kernel(nullptr), _bias(nullptr), _output(nullptr),
32       _activation(ir::Activation::NONE)
33 {
34   // DO NOTHING
35 }
36
37 void FullyConnectedLayer::configure(const IPortableTensor *input, const IPortableTensor *weights,
38                                     const IPortableTensor *bias, ir::Activation activation,
39                                     IPortableTensor *output)
40 {
41   _input = input;
42   _kernel = weights;
43   _bias = bias;
44   _activation = activation;
45   _output = output;
46
47   // TODO Support not nhwc layer
48   assert(_input->layout() == ir::Layout::NHWC);
49
50   assert(_activation == ir::Activation::NONE || _activation == ir::Activation::RELU ||
51          _activation == ir::Activation::RELU1 || _activation == ir::Activation::RELU6);
52 }
53
54 void FullyConnectedLayer::run()
55 {
56   assert(_external_context && _external_context->getThreadPool());
57   if (!_setup)
58   {
59     _setup = setup();
60     assert(_setup);
61   }
62
63   if (_input->data_type() == OperandType::FLOAT32)
64   {
65     enum xnn_status status = xnn_run_operator(_kernel_op, _external_context->getThreadPool());
66     if (status != xnn_status_success)
67     {
68       throw std::runtime_error{"failed to run FP32 FullyConnected operator"};
69     }
70   }
71   else
72   {
73     throw std::runtime_error{"XNNPACK FC: unsupported data type"};
74   }
75 }
76
77 bool FullyConnectedLayer::create()
78 {
79   float output_activation_min = 0.f, output_activation_max = 0.f;
80   CalculateActivationRange<float>(_activation, &output_activation_min, &output_activation_max);
81
82   const auto &kernel_shape = _kernel->getShape();
83   assert(kernel_shape.rank() == 2);
84   uint32_t output_channels = kernel_shape.dim(0);
85   uint32_t input_channels = kernel_shape.dim(1);
86
87   const auto &input_shape = _input->getShape();
88   const auto &output_shape = _output->getShape();
89   uint32_t flag = 0;
90   if (input_shape.rank() != output_shape.rank())
91   {
92     flag |= XNN_FLAG_TENSORFLOW_RESHAPE_2D;
93     assert(input_shape.num_elements() % input_channels == 0);
94   }
95   else
96   {
97     assert(static_cast<uint32_t>(input_shape.dim(input_shape.rank() - 1)) == input_channels);
98   }
99
100   assert(_kernel && _kernel->buffer());
101   const float *kernel_buffer = reinterpret_cast<const float *>(_kernel->buffer());
102   const float *bias_buffer = (_bias) ? reinterpret_cast<const float *>(_bias->buffer()) : nullptr;
103
104   enum xnn_status status = xnn_create_fully_connected_nc_f32(
105       input_channels, output_channels, input_channels /* input stride */,
106       output_channels /* output stride */, kernel_buffer, bias_buffer, output_activation_min,
107       output_activation_max, flag, &_kernel_op);
108   if (status != xnn_status_success)
109   {
110     throw std::runtime_error{"failed to create FP32 FullyConnected operator"};
111   }
112   assert(_kernel_op != nullptr);
113   return true;
114 }
115
116 bool FullyConnectedLayer::setup()
117 {
118   if (_input->buffer() == nullptr || _output->buffer() == nullptr)
119   {
120     // it could be models's input or output
121     return false;
122   }
123
124   uint32_t batch_size = _input->getShape().num_elements() / _kernel->getShape().dim(1);
125   enum xnn_status status = xnn_setup_fully_connected_nc_f32(
126       _kernel_op, batch_size, reinterpret_cast<const float *>(_input->buffer()),
127       reinterpret_cast<float *>(_output->buffer()), _external_context->getThreadPool());
128   if (status != xnn_status_success)
129   {
130     throw std::runtime_error{"failed to create FP32 FullyConnected operator"};
131   }
132   return true;
133 }
134
135 } // namespace ops
136 } // namespace xnnpack
137 } // namespace backend
138 } // namespace onert