2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "FullyConnectedLayer.h"
19 #include "ir/Padding.h"
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)
37 void FullyConnectedLayer::configure(const IPortableTensor *input, const IPortableTensor *weights,
38 const IPortableTensor *bias, ir::Activation activation,
39 IPortableTensor *output)
44 _activation = activation;
47 // TODO Support not nhwc layer
48 assert(_input->layout() == ir::Layout::NHWC);
50 assert(_activation == ir::Activation::NONE || _activation == ir::Activation::RELU ||
51 _activation == ir::Activation::RELU1 || _activation == ir::Activation::RELU6);
54 void FullyConnectedLayer::run()
56 assert(_external_context && _external_context->getThreadPool());
63 if (_input->data_type() == OperandType::FLOAT32)
65 enum xnn_status status = xnn_run_operator(_kernel_op, _external_context->getThreadPool());
66 if (status != xnn_status_success)
68 throw std::runtime_error{"failed to run FP32 FullyConnected operator"};
73 throw std::runtime_error{"XNNPACK FC: unsupported data type"};
77 bool FullyConnectedLayer::create()
79 float output_activation_min = 0.f, output_activation_max = 0.f;
80 CalculateActivationRange<float>(_activation, &output_activation_min, &output_activation_max);
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);
87 const auto &input_shape = _input->getShape();
88 const auto &output_shape = _output->getShape();
90 if (input_shape.rank() != output_shape.rank())
92 flag |= XNN_FLAG_TENSORFLOW_RESHAPE_2D;
93 assert(input_shape.num_elements() % input_channels == 0);
97 assert(static_cast<uint32_t>(input_shape.dim(input_shape.rank() - 1)) == input_channels);
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;
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)
110 throw std::runtime_error{"failed to create FP32 FullyConnected operator"};
112 assert(_kernel_op != nullptr);
116 bool FullyConnectedLayer::setup()
118 if (_input->buffer() == nullptr || _output->buffer() == nullptr)
120 // it could be models's input or output
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)
130 throw std::runtime_error{"failed to create FP32 FullyConnected operator"};
136 } // namespace xnnpack
137 } // namespace backend