diff options
Diffstat (limited to 'compiler/luci-interpreter')
186 files changed, 0 insertions, 20171 deletions
diff --git a/compiler/luci-interpreter/CMakeLists.txt b/compiler/luci-interpreter/CMakeLists.txt deleted file mode 100644 index 33fdc52aa..000000000 --- a/compiler/luci-interpreter/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(LUCI_INTERPRETER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") -set(LUCI_INTERPRETER_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src") - -add_subdirectory(src) diff --git a/compiler/luci-interpreter/include/luci_interpreter/Interpreter.h b/compiler/luci-interpreter/include/luci_interpreter/Interpreter.h deleted file mode 100644 index 7a14bf6f8..000000000 --- a/compiler/luci-interpreter/include/luci_interpreter/Interpreter.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_INTERPRETER_H -#define LUCI_INTERPRETER_INTERPRETER_H - -#include "luci_interpreter/core/Tensor.h" - -#include <luci/IR/Nodes/CircleInput.h> -#include <luci/IR/Nodes/CircleOutput.h> - -#include <luci/IR/Module.h> - -#include <memory> -#include <vector> -#include <unordered_map> - -namespace luci_interpreter -{ - -class ExecutionObserver -{ -public: - virtual ~ExecutionObserver(); - - // Called when the value of a tensor has been updated during execution. - virtual void postTensorWrite(const luci::CircleNode *node, const Tensor *tensor); - - // Called before / after executing an operator. - // Note that these methods are not called for auxiliary operators (CircleInput, CircleOutput, - // CircleConst and Circle*Out). - virtual void preOperatorExecute(const luci::CircleNode *node); - virtual void postOperatorExecute(const luci::CircleNode *node); -}; - -class Interpreter -{ -public: - explicit Interpreter(const luci::Module *module); - - ~Interpreter(); - - void writeInputTensor(const luci::CircleInput *input_node, const void *data, size_t data_size); - - void readOutputTensor(const luci::CircleOutput *output_node, void *data, size_t data_size); - - void interpret(); - - void attachObserver(ExecutionObserver *observer); - - const Tensor *getTensor(const loco::Node *node) { return _node_to_tensor[node]; } - -private: - std::unique_ptr<class RuntimeModule> _runtime_module; - - // Observer functionality support. - std::unique_ptr<struct RuntimeToIR> _runtime_to_ir; - std::unordered_map<const loco::Node *, Tensor *> _node_to_tensor; - std::unique_ptr<class EventNotifier> _event_notifier; - std::vector<ExecutionObserver *> _observers; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_INTERPRETER_H diff --git a/compiler/luci-interpreter/include/luci_interpreter/core/DataType.h b/compiler/luci-interpreter/include/luci_interpreter/core/DataType.h deleted file mode 100644 index 27bf719b5..000000000 --- a/compiler/luci-interpreter/include/luci_interpreter/core/DataType.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_CORE_DATATYPE_H -#define LUCI_INTERPRETER_CORE_DATATYPE_H - -#include <loco/IR/DataType.h> -#include <loco/IR/DataTypeTraits.h> - -#include <cstddef> - -namespace luci_interpreter -{ - -using DataType = loco::DataType; - -template <DataType DT> using DataTypeImpl = loco::DataTypeImpl<DT>; - -inline size_t getDataTypeSize(DataType data_type) { return loco::size(data_type); } - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_CORE_DATATYPE_H diff --git a/compiler/luci-interpreter/include/luci_interpreter/core/Tensor.h b/compiler/luci-interpreter/include/luci_interpreter/core/Tensor.h deleted file mode 100644 index 4ac3d8660..000000000 --- a/compiler/luci-interpreter/include/luci_interpreter/core/Tensor.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_CORE_TENSOR_H -#define LUCI_INTERPRETER_CORE_TENSOR_H - -#include "luci_interpreter/core/DataType.h" - -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <memory> -#include <string> -#include <vector> - -namespace luci_interpreter -{ - -class Shape -{ -public: - explicit Shape(int rank) : _dims(rank, 0) {} - - Shape(std::initializer_list<int32_t> dims) : _dims(dims.begin(), dims.end()) {} - - int num_dims() const { return _dims.size(); } - - int32_t dim(int i) const - { - assert(i >= 0 && i < static_cast<int>(_dims.size())); - return _dims[i]; - } - - int32_t &dim(int i) - { - assert(i >= 0 && i < static_cast<int>(_dims.size())); - return _dims[i]; - } - - int32_t num_elements() const - { - int32_t result = 1; - for (const int32_t dim : _dims) - { - result *= dim; - } - return result; - } - - bool operator==(const Shape &other) const { return _dims == other._dims; } - - bool operator!=(const Shape &other) const { return !operator==(other); } - -private: - std::vector<int32_t> _dims; -}; - -// Tensor affine quantization parameters. -// -// The relationship between real and quantized values: -// real_value = (quantized_value - zero_point) * scale -// -// In per-tensor case, 'scale' and 'zero_point' are one element each. -// In per-channel case, 'scale' and 'zero_point' are N elements each, where N is the size -// of the quantized dimension. -// -// Note that due to historical and performance reasons, per-tensor quantization uses unsigned -// integer types, while per-channel uses signed types assuming 'zero_point' == 0. -struct AffineQuantization -{ - std::vector<float> scale; - std::vector<int32_t> zero_point; - int32_t quantized_dimension; -}; - -class Tensor -{ -public: - Tensor(DataType element_type, Shape shape, AffineQuantization quantization, std::string name); - - DataType element_type() const { return _element_type; } - - const Shape &shape() const { return _shape; } - - float scale() const - { - assert(_quantization.scale.size() == 1); - return _quantization.scale[0]; - } - - float zero_point() const - { - assert(_quantization.zero_point.size() == 1); - return _quantization.zero_point[0]; - } - - const std::vector<float> &scales() const { return _quantization.scale; } - - const std::vector<int32_t> &zero_points() const { return _quantization.zero_point; } - - int32_t quantized_dimension() const { return _quantization.quantized_dimension; } - - template <typename T> const T *data() const { return reinterpret_cast<const T *>(_data.get()); } - - template <typename T> T *data() { return reinterpret_cast<T *>(_data.get()); } - - const std::string &name() const { return _name; } - - void readData(void *data_ptr, size_t data_size) const; - - void writeData(const void *data_ptr, size_t data_size); - - void resize(const Shape &new_shape); - -private: - DataType _element_type; - Shape _shape; - AffineQuantization _quantization; - std::unique_ptr<uint8_t[]> _data; - std::string _name; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_CORE_TENSOR_H diff --git a/compiler/luci-interpreter/requires.cmake b/compiler/luci-interpreter/requires.cmake deleted file mode 100644 index f411f387a..000000000 --- a/compiler/luci-interpreter/requires.cmake +++ /dev/null @@ -1 +0,0 @@ -require(luci) diff --git a/compiler/luci-interpreter/src/CMakeLists.txt b/compiler/luci-interpreter/src/CMakeLists.txt deleted file mode 100644 index 47b68fa40..000000000 --- a/compiler/luci-interpreter/src/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -nnas_find_package(TensorFlowSource EXACT 2.3.0 QUIET) -nnas_find_package(TensorFlowGEMMLowpSource EXACT 2.3.0 QUIET) -nnas_find_package(TensorFlowEigenSource EXACT 2.3.0 QUIET) -nnas_find_package(TensorFlowRuySource EXACT 2.3.0 QUIET) - -if (NOT TensorFlowSource_FOUND) - message(STATUS "Skipping luci-interpreter: TensorFlow not found") - return() -endif () - -if (NOT TensorFlowGEMMLowpSource_FOUND) - message(STATUS "Skipping luci-interpreter: gemmlowp not found") - return() -endif () - -if (NOT TensorFlowEigenSource_FOUND) - message(STATUS "Skipping luci-interpreter: Eigen not found") - return() -endif () - -if (NOT TensorFlowRuySource_FOUND) - message(STATUS "Skipping luci-interpreter: Ruy not found") - return() -endif () - -add_subdirectory(core) -add_subdirectory(kernels) -add_subdirectory(loader) - -set(SOURCES - "${LUCI_INTERPRETER_INCLUDE_DIR}/luci_interpreter/Interpreter.h" - Interpreter.cpp) - -add_library(luci_interpreter SHARED ${SOURCES}) -target_include_directories(luci_interpreter PUBLIC "${LUCI_INTERPRETER_INCLUDE_DIR}") -target_include_directories(luci_interpreter PRIVATE "${LUCI_INTERPRETER_SOURCE_DIR}") -target_link_libraries(luci_interpreter - PUBLIC luci_lang luci_interpreter_loader luci_interpreter_core - PRIVATE nncc_common) - -install(TARGETS luci_interpreter DESTINATION lib) diff --git a/compiler/luci-interpreter/src/Interpreter.cpp b/compiler/luci-interpreter/src/Interpreter.cpp deleted file mode 100644 index 639ffc1f0..000000000 --- a/compiler/luci-interpreter/src/Interpreter.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "luci_interpreter/Interpreter.h" - -#include "loader/ModuleLoader.h" - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace -{ - -class EventNotifierImpl final : public EventNotifier -{ -public: - EventNotifierImpl(const RuntimeToIR &runtime_to_ir, - const std::vector<ExecutionObserver *> &observers) - : _runtime_to_ir(runtime_to_ir), _observers(observers) - { - } - - void postTensorWrite(const Tensor *tensor) override - { - assert(tensor != nullptr); - for (const auto &observer : _observers) - { - observer->postTensorWrite(_runtime_to_ir.tensor_to_node.at(tensor), tensor); - } - } - - void preOperatorExecute(const Kernel *kernel) override - { - assert(kernel != nullptr); - for (const auto &observer : _observers) - { - observer->preOperatorExecute(_runtime_to_ir.kernel_to_node.at(kernel)); - } - } - - void postOperatorExecute(const Kernel *kernel) override - { - assert(kernel != nullptr); - for (const auto &observer : _observers) - { - observer->postOperatorExecute(_runtime_to_ir.kernel_to_node.at(kernel)); - } - } - -private: - const RuntimeToIR &_runtime_to_ir; - const std::vector<ExecutionObserver *> &_observers; -}; - -} // namespace - -Interpreter::Interpreter(const luci::Module *module) -{ - _runtime_to_ir = std::make_unique<RuntimeToIR>(); - _event_notifier = std::make_unique<EventNotifierImpl>(*_runtime_to_ir, _observers); - _runtime_module = std::make_unique<RuntimeModule>(_event_notifier.get()); - ModuleLoader loader(module, _runtime_module.get(), *_runtime_to_ir, _node_to_tensor); - loader.load(); -} - -Interpreter::~Interpreter() = default; - -void Interpreter::writeInputTensor(const luci::CircleInput *input_node, const void *data, - size_t data_size) -{ - Tensor *tensor = _runtime_module->getInputTensors()[input_node->index()]; - if (tensor == nullptr) - { - const std::string &name = input_node->name(); - throw std::runtime_error("Cannot find tensor for input node named \"" + name + "\"."); - } - if (data != nullptr) - tensor->writeData(data, data_size); -} - -void Interpreter::readOutputTensor(const luci::CircleOutput *output_node, void *data, - size_t data_size) -{ - Tensor *tensor = _runtime_module->getOutputTensors()[output_node->index()]; - if (tensor == nullptr) - { - const std::string &name = output_node->name(); - throw std::runtime_error("Cannot find tensor for output node named \"" + name + "\"."); - } - if (data != nullptr) - tensor->readData(data, data_size); -} - -void Interpreter::interpret() { _runtime_module->execute(); } - -void Interpreter::attachObserver(ExecutionObserver *observer) -{ - if (std::find(_observers.cbegin(), _observers.cend(), observer) != _observers.cend()) - throw std::runtime_error("Observer is already attached."); - _observers.push_back(observer); -} - -ExecutionObserver::~ExecutionObserver() = default; - -void ExecutionObserver::postTensorWrite(const luci::CircleNode *, const Tensor *) {} - -void ExecutionObserver::preOperatorExecute(const luci::CircleNode *) {} - -void ExecutionObserver::postOperatorExecute(const luci::CircleNode *) {} - -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/core/CMakeLists.txt b/compiler/luci-interpreter/src/core/CMakeLists.txt deleted file mode 100644 index e576dbd94..000000000 --- a/compiler/luci-interpreter/src/core/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(SOURCES - "${LUCI_INTERPRETER_INCLUDE_DIR}/luci_interpreter/core/DataType.h" - "${LUCI_INTERPRETER_INCLUDE_DIR}/luci_interpreter/core/Tensor.h" - EventNotifier.h - Kernel.h - KernelParams.h - RuntimeGraph.h - RuntimeGraph.cpp - RuntimeModule.h - Tensor.cpp) - -add_library(luci_interpreter_core STATIC ${SOURCES}) -set_target_properties(luci_interpreter_core PROPERTIES POSITION_INDEPENDENT_CODE ON) -target_include_directories(luci_interpreter_core PUBLIC "${LUCI_INTERPRETER_INCLUDE_DIR}") -target_include_directories(luci_interpreter_core PUBLIC "${LUCI_INTERPRETER_SOURCE_DIR}") -target_link_libraries(luci_interpreter_core PUBLIC luci_lang) -target_link_libraries(luci_interpreter_core PRIVATE nncc_common) diff --git a/compiler/luci-interpreter/src/core/EventNotifier.h b/compiler/luci-interpreter/src/core/EventNotifier.h deleted file mode 100644 index 5c4fbd3be..000000000 --- a/compiler/luci-interpreter/src/core/EventNotifier.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_CORE_EVENTNOTIFIER_H -#define LUCI_INTERPRETER_CORE_EVENTNOTIFIER_H - -namespace luci_interpreter -{ - -// Used at execution stage to tell the interpreter that the runtime state has changed in some way. -class EventNotifier -{ -public: - virtual ~EventNotifier() = default; - - virtual void postTensorWrite(const Tensor *tensor) = 0; - virtual void preOperatorExecute(const Kernel *kernel) = 0; - virtual void postOperatorExecute(const Kernel *kernel) = 0; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_CORE_EVENTNOTIFIER_H diff --git a/compiler/luci-interpreter/src/core/Kernel.h b/compiler/luci-interpreter/src/core/Kernel.h deleted file mode 100644 index 5f5efb219..000000000 --- a/compiler/luci-interpreter/src/core/Kernel.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_CORE_KERNEL_H -#define LUCI_INTERPRETER_CORE_KERNEL_H - -#include "luci_interpreter/core/Tensor.h" - -#include <vector> - -namespace luci_interpreter -{ - -// Base class for all kernels. -class Kernel -{ -protected: - Kernel(std::vector<const Tensor *> inputs, std::vector<Tensor *> outputs) - : _inputs(std::move(inputs)), _outputs(std::move(outputs)) - { - } - -public: - virtual ~Kernel() = default; - - std::vector<const Tensor *> getInputTensors() const { return _inputs; } - std::vector<Tensor *> getOutputTensors() const { return _outputs; } - - // Configures the kernel. - // This function is currently called once for each kernel during interpreter construction, - // which makes it a convenient place for preparing (resizing) output tensors. - virtual void configure() = 0; - - // Executes the kernel. - virtual void execute() const = 0; - -protected: - // NOTE Prefer not to use these in derived classes. - const std::vector<const Tensor *> _inputs; - const std::vector<Tensor *> _outputs; -}; - -// Base class for kernels with parameters. -template <typename Params> class KernelWithParams : public Kernel -{ -protected: - KernelWithParams(std::vector<const Tensor *> inputs, std::vector<Tensor *> outputs, - const Params ¶ms) - : Kernel(std::move(inputs), std::move(outputs)), _params(params) - { - } - -public: - const Params ¶ms() const { return _params; } - -protected: - const Params _params; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_CORE_KERNEL_H diff --git a/compiler/luci-interpreter/src/core/KernelParams.h b/compiler/luci-interpreter/src/core/KernelParams.h deleted file mode 100644 index 06926cdc1..000000000 --- a/compiler/luci-interpreter/src/core/KernelParams.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_CORE_KERNELPARAMS_H -#define LUCI_INTERPRETER_CORE_KERNELPARAMS_H - -#include <luci/IR/AttrPadding.h> -#include <luci/IR/AttrFusedActFunc.h> -#include <luci_interpreter/core/DataType.h> - -#include <cstdint> -#include <vector> - -namespace luci_interpreter -{ - -// Inject commonly used types into `luci_interpreter` namespace for convenience. -using Activation = luci::FusedActFunc; -using Padding = luci::Padding; - -struct AddParams -{ - Activation activation; -}; - -struct ArgMaxParams -{ - DataType output_type; -}; - -struct ConcatenationParams -{ - int axis; -}; - -struct Conv2DParams -{ - Padding padding; - int32_t stride_height; - int32_t stride_width; - int32_t dilation_height_factor; - int32_t dilation_width_factor; - Activation activation; -}; - -struct DepthToSpaceParams -{ - int block_size; -}; - -struct DepthwiseConv2DParams -{ - Padding padding; - int32_t depth_multiplier; // TODO Remove, as it can be calculated. - int32_t stride_height; - int32_t stride_width; - int32_t dilation_height_factor; - int32_t dilation_width_factor; - Activation activation; -}; - -struct DivParams -{ - Activation activation; -}; - -struct FullyConnectedParams -{ - Activation activation; -}; - -struct L2NormParams -{ - Activation activation; -}; - -struct LeakyReluParams -{ - float alpha; -}; - -struct LocalResponseNormalizationParams -{ - int32_t radius; - float bias; - float alpha; - float beta; -}; - -struct MulParams -{ - Activation activation; -}; - -struct Pool2DParams -{ - Padding padding; - int32_t filter_height; - int32_t filter_width; - int32_t stride_height; - int32_t stride_width; - Activation activation; -}; - -struct ReducerParams -{ - bool keep_dims; -}; - -struct ResizeBilinearParams -{ - bool align_corners; - bool half_pixel_centers; -}; - -struct ResizeNearestNeighborParams -{ - bool align_corners; - bool half_pixel_centers; -}; - -struct SubParams -{ - Activation activation; -}; - -struct SpaceToDepthParams -{ - int block_size; -}; - -struct SoftmaxParams -{ - float beta; -}; - -struct StridedSliceParams -{ - int32_t begin_mask; - int32_t end_mask; - int32_t ellipsis_mask; - int32_t new_axis_mask; - int32_t shrink_axis_mask; -}; - -struct SqueezeParams -{ - std::vector<int32_t> squeeze_dims; -}; - -struct TransposeConvParams -{ - Padding padding; - int32_t stride_height; - int32_t stride_width; -}; - -struct UnpackParams -{ - int axis; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_CORE_KERNELPARAMS_H diff --git a/compiler/luci-interpreter/src/core/RuntimeGraph.cpp b/compiler/luci-interpreter/src/core/RuntimeGraph.cpp deleted file mode 100644 index 06f0fed15..000000000 --- a/compiler/luci-interpreter/src/core/RuntimeGraph.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "core/RuntimeGraph.h" - -#include "core/RuntimeModule.h" - -#include <algorithm> - -namespace luci_interpreter -{ - -Tensor *RuntimeGraph::addTensor(std::unique_ptr<Tensor> &&tensor) -{ - assert(tensor != nullptr); - _tensors.push_back(std::move(tensor)); - return _tensors.back().get(); -} - -void RuntimeGraph::setInputTensors(const std::vector<Tensor *> &input_tensors) -{ - assert(std::all_of(input_tensors.cbegin(), input_tensors.cend(), - [](Tensor *tensor) { return tensor != nullptr; })); - _input_tensors = input_tensors; -} - -void RuntimeGraph::setOutputTensors(const std::vector<Tensor *> &output_tensors) -{ - assert(std::all_of(output_tensors.cbegin(), output_tensors.cend(), - [](Tensor *tensor) { return tensor != nullptr; })); - _output_tensors = output_tensors; -} - -void RuntimeGraph::addKernel(std::unique_ptr<Kernel> &&kernel) -{ - assert(kernel != nullptr); - _kernels.push_back(std::move(kernel)); -} - -void RuntimeGraph::execute() const -{ - EventNotifier *event_notifier = _owning_module->getEventNotifier(); - - // Notify the observers that the input tensors have changed. - if (event_notifier != nullptr) - { - for (const Tensor *input_tensor : getInputTensors()) - { - event_notifier->postTensorWrite(input_tensor); - } - } - - for (const auto &kernel : _kernels) - { - if (event_notifier != nullptr) - { - event_notifier->preOperatorExecute(kernel.get()); - } - - // TODO The `configure` method should only be called if the outputs of an operator need to be - // resized. - kernel->configure(); - kernel->execute(); - - if (event_notifier != nullptr) - { - event_notifier->postOperatorExecute(kernel.get()); - } - - for (const Tensor *tensor : kernel->getOutputTensors()) - { - if (event_notifier != nullptr) - { - event_notifier->postTensorWrite(tensor); - } - } - } -} - -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/core/RuntimeGraph.h b/compiler/luci-interpreter/src/core/RuntimeGraph.h deleted file mode 100644 index 6ddbea4e9..000000000 --- a/compiler/luci-interpreter/src/core/RuntimeGraph.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_CORE_RUNTIMEGRAPH_H -#define LUCI_INTERPRETER_CORE_RUNTIMEGRAPH_H - -#include "luci_interpreter/core/Tensor.h" -#include "core/Kernel.h" - -#include <memory> -#include <vector> - -namespace luci_interpreter -{ - -class RuntimeModule; - -class RuntimeGraph -{ -public: - explicit RuntimeGraph(RuntimeModule *owning_module) : _owning_module(owning_module) {} - - Tensor *addTensor(std::unique_ptr<Tensor> &&tensor); - - void setInputTensors(const std::vector<Tensor *> &input_tensors); - void setOutputTensors(const std::vector<Tensor *> &output_tensors); - - const std::vector<Tensor *> &getInputTensors() const { return _input_tensors; } - const std::vector<Tensor *> &getOutputTensors() const { return _output_tensors; } - - void addKernel(std::unique_ptr<Kernel> &&kernel); - - void execute() const; - -private: - RuntimeModule *_owning_module; - std::vector<std::unique_ptr<Tensor>> _tensors; - std::vector<Tensor *> _input_tensors; - std::vector<Tensor *> _output_tensors; - - // Kernels in execution order. - std::vector<std::unique_ptr<Kernel>> _kernels; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_CORE_RUNTIMEGRAPH_H diff --git a/compiler/luci-interpreter/src/core/RuntimeModule.h b/compiler/luci-interpreter/src/core/RuntimeModule.h deleted file mode 100644 index dccc3a173..000000000 --- a/compiler/luci-interpreter/src/core/RuntimeModule.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_CORE_RUNTIMEMODULE_H -#define LUCI_INTERPRETER_CORE_RUNTIMEMODULE_H - -#include "core/RuntimeGraph.h" -#include "core/EventNotifier.h" - -#include <memory> -#include <vector> - -namespace luci_interpreter -{ - -class RuntimeModule -{ -public: - explicit RuntimeModule(EventNotifier *event_notifier) : _event_notifier(event_notifier) {} - - EventNotifier *getEventNotifier() const { return _event_notifier; } - - RuntimeGraph *addGraph() - { - _graphs.push_back(std::make_unique<RuntimeGraph>(this)); - return _graphs.back().get(); - } - - const std::vector<Tensor *> &getInputTensors() const { return getMainGraph()->getInputTensors(); } - const std::vector<Tensor *> &getOutputTensors() const - { - return getMainGraph()->getOutputTensors(); - } - - void execute() const { getMainGraph()->execute(); } - -private: - RuntimeGraph *getMainGraph() const { return _graphs[0].get(); } - - EventNotifier *const _event_notifier; - std::vector<std::unique_ptr<RuntimeGraph>> _graphs; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_CORE_RUNTIMEMODULE_H diff --git a/compiler/luci-interpreter/src/core/Tensor.cpp b/compiler/luci-interpreter/src/core/Tensor.cpp deleted file mode 100644 index 4fe7479e5..000000000 --- a/compiler/luci-interpreter/src/core/Tensor.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "luci_interpreter/core/Tensor.h" - -#include <cstring> -#include <stdexcept> - -namespace luci_interpreter -{ - -Tensor::Tensor(DataType element_type, Shape shape, AffineQuantization quantization, - std::string name) - : _element_type(element_type), _shape(std::move(shape)), _quantization(std::move(quantization)), - _name(std::move(name)) -{ - const size_t element_size = getDataTypeSize(_element_type); - const int32_t num_elements = _shape.num_elements(); - _data = std::make_unique<uint8_t[]>(num_elements * element_size); -} - -void Tensor::readData(void *data_ptr, size_t data_size) const -{ - const size_t element_size = getDataTypeSize(element_type()); - const int32_t num_elements = shape().num_elements(); - if (data_size != num_elements * element_size) - { - throw std::invalid_argument("Invalid data size."); - } - assert(data_ptr != nullptr); - std::memcpy(data_ptr, data<void>(), data_size); -} - -void Tensor::writeData(const void *data_ptr, size_t data_size) -{ - const size_t element_size = getDataTypeSize(element_type()); - const int32_t num_elements = shape().num_elements(); - if (data_size != num_elements * element_size) - { - throw std::invalid_argument("Invalid data size."); - } - assert(data_ptr != nullptr); - std::memcpy(data<void>(), data_ptr, data_size); -} - -void Tensor::resize(const Shape &new_shape) -{ - _shape = new_shape; - const size_t element_size = getDataTypeSize(_element_type); - const int32_t num_elements = _shape.num_elements(); - // NOTE: _data can be nullptr for empty tensors - _data = std::make_unique<uint8_t[]>(num_elements * element_size); -} - -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Add.cpp b/compiler/luci-interpreter/src/kernels/Add.cpp deleted file mode 100644 index 8d119d516..000000000 --- a/compiler/luci-interpreter/src/kernels/Add.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Add.h" - -#include "kernels/BinaryOpCommon.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/add.h> -#include <tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h> - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -Add::Add(const Tensor *input1, const Tensor *input2, Tensor *output, const AddParams ¶ms) - : KernelWithParams<AddParams>({input1, input2}, {output}, params) -{ -} - -void Add::configure() -{ - LUCI_INTERPRETER_CHECK(input1()->element_type() == input2()->element_type()); - if (input1()->element_type() == DataType::S16) - { - LUCI_INTERPRETER_CHECK(input1()->zero_point() == 0 && input2()->zero_point() == 0 && - output()->zero_point() == 0); - } - - output()->resize(calculateShapeForBroadcast(input1()->shape(), input2()->shape())); -} - -void Add::execute() const -{ - switch (input1()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - case DataType::S16: - evalQuantizedS16(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Add::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::ArithmeticParams params{}; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - - const bool need_broadcast = tflite::reference_ops::ProcessBroadcastShapes( - getTensorShape(input1()), getTensorShape(input2()), ¶ms); - - if (need_broadcast) - { - tflite::reference_ops::BroadcastAdd4DSlow( - params, getTensorShape(input1()), getTensorData<float>(input1()), getTensorShape(input2()), - getTensorData<float>(input2()), getTensorShape(output()), getTensorData<float>(output())); - } - else - { - tflite::reference_ops::Add(params, getTensorShape(input1()), getTensorData<float>(input1()), - getTensorShape(input2()), getTensorData<float>(input2()), - getTensorShape(output()), getTensorData<float>(output())); - } -} - -void Add::evalQuantized() const -{ - const auto input1_scale = static_cast<double>(input1()->scale()); - const auto input2_scale = static_cast<double>(input2()->scale()); - const auto output_scale = static_cast<double>(output()->scale()); - - const int left_shift = 20; - const double twice_max_input_scale = 2 * std::max(input1_scale, input2_scale); - const double real_input1_multiplier = input1_scale / twice_max_input_scale; - const double real_input2_multiplier = input2_scale / twice_max_input_scale; - const double real_output_multiplier = twice_max_input_scale / ((1 << left_shift) * output_scale); - - int32_t input1_multiplier{}, input2_multiplier{}, output_multiplier{}; - int input1_shift{}, input2_shift{}, output_shift{}; - quantizeMultiplierSmallerThanOneExp(real_input1_multiplier, &input1_multiplier, &input1_shift); - quantizeMultiplierSmallerThanOneExp(real_input2_multiplier, &input2_multiplier, &input2_shift); - quantizeMultiplierSmallerThanOneExp(real_output_multiplier, &output_multiplier, &output_shift); - - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::ArithmeticParams params{}; - params.left_shift = left_shift; - // The kernel expects inputs' zero points to be negated. - params.input1_offset = -input1()->zero_point(); // Note the '-'. - params.input1_multiplier = input1_multiplier; - params.input1_shift = input1_shift; - params.input2_offset = -input2()->zero_point(); // Note the '-'. - params.input2_multiplier = input2_multiplier; - params.input2_shift = input2_shift; - params.output_offset = output()->zero_point(); - params.output_multiplier = output_multiplier; - params.output_shift = output_shift; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - const bool need_broadcast = tflite::reference_ops::ProcessBroadcastShapes( - getTensorShape(input1()), getTensorShape(input2()), ¶ms); - - if (need_broadcast) - { - tflite::reference_ops::BroadcastAdd4DSlow( - params, getTensorShape(input1()), getTensorData<uint8_t>(input1()), - getTensorShape(input2()), getTensorData<uint8_t>(input2()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - } - else - { - tflite::reference_ops::Add(params, getTensorShape(input1()), getTensorData<uint8_t>(input1()), - getTensorShape(input2()), getTensorData<uint8_t>(input2()), - getTensorShape(output()), getTensorData<uint8_t>(output())); - } -} - -void Add::evalQuantizedS16() const -{ - const auto input1_scale = static_cast<double>(input1()->scale()); - const auto input2_scale = static_cast<double>(input2()->scale()); - const auto output_scale = static_cast<double>(output()->scale()); - - constexpr int left_shift = 12; - const double twice_max_input_scale = 2 * std::max(input1_scale, input2_scale); - const double real_input1_multiplier = input1_scale / twice_max_input_scale; - const double real_input2_multiplier = input2_scale / twice_max_input_scale; - const double real_output_multiplier = twice_max_input_scale / ((1 << left_shift) * output_scale); - - int32_t input1_multiplier{}, input2_multiplier{}, output_multiplier{}; - int input1_shift{}, input2_shift{}, output_shift{}; - quantizeMultiplierSmallerThanOneExp(real_input1_multiplier, &input1_multiplier, &input1_shift); - quantizeMultiplierSmallerThanOneExp(real_input2_multiplier, &input2_multiplier, &input2_shift); - quantizeMultiplierSmallerThanOneExp(real_output_multiplier, &output_multiplier, &output_shift); - - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - auto fn = [input1_multiplier, input1_shift, // - input2_multiplier, input2_shift, // - output_multiplier, output_shift, // - activation_min, activation_max](int16_t input1_val, int16_t input2_val) { - const int32_t shifted_input1_val = static_cast<int32_t>(input1_val) << left_shift; - const int32_t shifted_input2_val = static_cast<int32_t>(input2_val) << left_shift; - const int32_t scaled_input1_val = tflite::MultiplyByQuantizedMultiplierSmallerThanOneExp( - shifted_input1_val, input1_multiplier, input1_shift); - const int32_t scaled_input2_val = tflite::MultiplyByQuantizedMultiplierSmallerThanOneExp( - shifted_input2_val, input2_multiplier, input2_shift); - const int32_t raw_sum = scaled_input1_val + scaled_input2_val; - const int32_t raw_output = tflite::MultiplyByQuantizedMultiplierSmallerThanOneExp( - raw_sum, output_multiplier, output_shift); - const int32_t clamped_output = std::min(activation_max, std::max(activation_min, raw_output)); - return static_cast<int16_t>(clamped_output); - }; - - BinaryOpBroadcastSlow(getTensorShape(input1()), getTensorData<int16_t>(input1()), - getTensorShape(input2()), getTensorData<int16_t>(input2()), - getTensorShape(output()), getTensorData<int16_t>(output()), fn); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Add.h b/compiler/luci-interpreter/src/kernels/Add.h deleted file mode 100644 index 79518845d..000000000 --- a/compiler/luci-interpreter/src/kernels/Add.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_ADD_H -#define LUCI_INTERPRETER_KERNELS_ADD_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Add : public KernelWithParams<AddParams> -{ -public: - Add(const Tensor *input1, const Tensor *input2, Tensor *output, const AddParams ¶ms); - - const Tensor *input1() const { return _inputs[0]; } - const Tensor *input2() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void evalQuantizedS16() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_ADD_H diff --git a/compiler/luci-interpreter/src/kernels/Add.test.cpp b/compiler/luci-interpreter/src/kernels/Add.test.cpp deleted file mode 100644 index de8a3bbb0..000000000 --- a/compiler/luci-interpreter/src/kernels/Add.test.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Add.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -// for quantized Add, the error shouldn't exceed step -float GetTolerance(float min, float max) -{ - float kQuantizedStep = (max - min) / 255.0; - return kQuantizedStep; -} - -TEST(AddTest, Uint8) -{ - std::initializer_list<int32_t> base_shape = {2, 3, 1, 2}; - std::initializer_list<float> base_data = {-0.3f, 2.3f, 0.9f, 0.5f, 0.8f, -1.1f, - 1.2f, 2.8f, -1.6f, 0.0f, 0.7f, -2.2f}; - std::initializer_list<int32_t> test_shapes[] = { - {1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}}; - std::initializer_list<float> test_data = {0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f}; - std::initializer_list<int32_t> output_shapes[] = { - {2, 3, 3, 2}, {2, 3, 1, 2}, {2, 3, 3, 2}, {2, 3, 1, 2}}; - std::vector<std::vector<float>> output_data = { - {-0.1f, 2.6f, -0.7f, 2.8f, 0.7f, 3.0f, 1.1f, 0.8f, 0.5f, 1.0f, 1.9f, 1.4f, - 1.0f, -0.8f, 0.4f, -0.6f, 1.8f, -0.2f, 1.4f, 3.0f, 0.8f, 3.0f, 2.2f, 3.0f, - -1.4f, 0.3f, -2.0f, 0.5f, -0.6f, 0.9f, 0.9f, -1.9f, 0.3f, -1.7f, 1.7f, -1.3f}, - {-0.1f, 2.6f, 0.5f, 1.0f, 1.8f, -0.2f, 1.4f, 3.0f, -2.0f, 0.5f, 1.7f, -1.3f}, - {-0.1f, 2.5f, 0.0f, 2.6f, -0.7f, 1.9f, 1.1f, 0.7f, 1.2f, 0.8f, 0.5f, 0.1f, - 1.0f, -0.9f, 1.1f, -0.8f, 0.4f, -1.5f, 1.7f, 3.0f, 2.2f, 3.0f, 2.1f, 3.0f, - -1.1f, 0.5f, -0.6f, 1.0f, -0.7f, 0.9f, 1.2f, -1.7f, 1.7f, -1.2f, 1.6f, -1.3f}, - {-0.1f, 2.5f, 1.2f, 0.8f, 0.4f, -1.5f, 1.7f, 3.0f, -0.6f, 1.0f, 1.6f, -1.3f}}; - float kQuantizedTolerance = GetTolerance(-3.f, 3.f); - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-3.f, 3.f); - for (int i = 0; i < output_data.size(); i++) - { - Tensor input1_tensor = - makeInputTensor<DataType::U8>(base_shape, quant_param.first, quant_param.second, base_data); - Tensor input2_tensor = makeInputTensor<DataType::U8>(test_shapes[i], quant_param.first, - quant_param.second, test_data); - Tensor output_tensor = - makeOutputTensor(getElementType<uint8_t>(), quant_param.first, quant_param.second); - - AddParams params{}; - params.activation = Activation::NONE; - - Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data[i], kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shapes[i])); - } - // Re-run with exchanged inputs. - for (int i = 0; i < output_data.size(); i++) - { - Tensor input1_tensor = makeInputTensor<DataType::U8>(test_shapes[i], quant_param.first, - quant_param.second, test_data); - Tensor input2_tensor = - makeInputTensor<DataType::U8>(base_shape, quant_param.first, quant_param.second, base_data); - Tensor output_tensor = - makeOutputTensor(getElementType<uint8_t>(), quant_param.first, quant_param.second); - - AddParams params{}; - params.activation = Activation::NONE; - - Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data[i], kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shapes[i])); - } -} - -TEST(AddTest, Float) -{ - Shape base_shape = {2, 3, 1, 2}; - std::vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}}; - std::vector<std::vector<float>> test_outputs = { - {0.0f, 2.6f, 0.0f, 2.8f, 0.7f, 3.2f, 1.1f, 0.8f, 0.5f, 1.0f, 1.9f, 1.4f, - 1.0f, 0.0f, 0.4f, 0.0f, 1.8f, 0.0f, 1.4f, 3.1f, 0.8f, 3.3f, 2.2f, 3.7f, - 0.0f, 0.3f, 0.0f, 0.5f, 0.0f, 0.9f, 0.9f, 0.0f, 0.3f, 0.0f, 1.7f, 0.0f}, - {0.0f, 2.6f, 0.5f, 1.0f, 1.8f, 0.0f, 1.4f, 3.1f, 0.0f, 0.5f, 1.7f, 0.0f}, - {0.0f, 2.5f, 0.0f, 2.6f, 0.0f, 1.9f, 1.1f, 0.7f, 1.2f, 0.8f, 0.5f, 0.1f, - 1.0f, 0.0f, 1.1f, 0.0f, 0.4f, 0.0f, 1.7f, 3.3f, 2.2f, 3.8f, 2.1f, 3.7f, - 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.9f, 1.2f, 0.0f, 1.7f, 0.0f, 1.6f, 0.0f}, - {0.0f, 2.5f, 1.2f, 0.8f, 0.4f, 0.0f, 1.7f, 3.3f, 0.0f, 1.0f, 1.6f, 0.0f}}; - std::vector<float> input1_data{-0.3f, 2.3f, 0.9f, 0.5f, 0.8f, -1.1f, - 1.2f, 2.8f, -1.6f, 0.0f, 0.7f, -2.2f}; - std::vector<float> input2_data{0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f}; - for (size_t i = 0; i < test_shapes.size(); ++i) - { - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(test_shapes[i], input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - AddParams params{}; - params.activation = Activation::RELU; - - Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs[i], 0.0001f)) - << "With shape number " << i; - } - // Re-run with exchanged inputs. - for (size_t i = 0; i < test_shapes.size(); ++i) - { - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(test_shapes[i], input2_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input1_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - AddParams params{}; - params.activation = Activation::RELU; - - Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs[i], 0.0001f)) - << "With shape number " << i; - } -} - -TEST(AddTest, SInt16) -{ - Shape base_shape = {2, 3, 1, 2}; - std::vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}}; - std::vector<std::vector<int32_t>> ref_output_shapes{ - {2, 3, 3, 2}, {2, 3, 1, 2}, {2, 3, 3, 2}, {2, 3, 1, 2}}; - - std::vector<float> input1_data{-0.3f, 2.3f, 0.9f, 0.5f, 0.8f, -1.1f, - 1.2f, 2.8f, -1.6f, 0.0f, 0.7f, -2.2f}; - std::vector<float> input2_data{0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f}; - std::vector<std::vector<float>> ref_outputs = { - {0.0f, 2.6f, 0.0f, 2.8f, 0.7f, 3.2f, 1.1f, 0.8f, 0.5f, 1.0f, 1.9f, 1.4f, - 1.0f, 0.0f, 0.4f, 0.0f, 1.8f, 0.0f, 1.4f, 3.1f, 0.8f, 3.3f, 2.2f, 3.7f, - 0.0f, 0.3f, 0.0f, 0.5f, 0.0f, 0.9f, 0.9f, 0.0f, 0.3f, 0.0f, 1.7f, 0.0f}, - {0.0f, 2.6f, 0.5f, 1.0f, 1.8f, 0.0f, 1.4f, 3.1f, 0.0f, 0.5f, 1.7f, 0.0f}, - {0.0f, 2.5f, 0.0f, 2.6f, 0.0f, 1.9f, 1.1f, 0.7f, 1.2f, 0.8f, 0.5f, 0.1f, - 1.0f, 0.0f, 1.1f, 0.0f, 0.4f, 0.0f, 1.7f, 3.3f, 2.2f, 3.8f, 2.1f, 3.7f, - 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.9f, 1.2f, 0.0f, 1.7f, 0.0f, 1.6f, 0.0f}, - {0.0f, 2.5f, 1.2f, 0.8f, 0.4f, 0.0f, 1.7f, 3.3f, 0.0f, 1.0f, 1.6f, 0.0f}}; - - for (size_t i = 0; i < test_shapes.size(); ++i) - { - Tensor input1_tensor = makeInputTensor<DataType::S16>(base_shape, 3.0 / 32767, 0, input1_data); - Tensor input2_tensor = - makeInputTensor<DataType::S16>(test_shapes[i], 1.0 / 32767, 0, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::S16, 4.0 / 32767, 0); - const float tolerance = output_tensor.scale(); - - AddParams params{}; - params.activation = Activation::RELU; - - Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), - ::testing::ElementsAreArray(ref_output_shapes[i])) - << "With shape number " << i; - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_outputs[i], tolerance)) - << "With shape number " << i; - } - // Re-run with exchanged inputs and different scales. - for (size_t i = 0; i < test_shapes.size(); ++i) - { - Tensor input1_tensor = - makeInputTensor<DataType::S16>(test_shapes[i], 2.0 / 32767, 0, input2_data); - Tensor input2_tensor = makeInputTensor<DataType::S16>(base_shape, 4.0 / 32767, 0, input1_data); - Tensor output_tensor = makeOutputTensor(DataType::S16, 5.0 / 32767, 0); - const float tolerance = output_tensor.scale(); - - AddParams params{}; - params.activation = Activation::RELU; - - Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), - ::testing::ElementsAreArray(ref_output_shapes[i])) - << "With shape number " << i; - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_outputs[i], tolerance)) - << "With shape number " << i; - } -} - -TEST(AddTest, Input_Output_Type_NEG) -{ - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {2}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - AddParams params{}; - params.activation = Activation::RELU; - - Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(AddTest, Invalid_Input_Type_NEG) -{ - Tensor input1_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor input2_tensor = makeInputTensor<DataType::S64>({1}, {2}); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - AddParams params{}; - params.activation = Activation::RELU; - - Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/ArgMax.cpp b/compiler/luci-interpreter/src/kernels/ArgMax.cpp deleted file mode 100644 index 5c464ed09..000000000 --- a/compiler/luci-interpreter/src/kernels/ArgMax.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/ArgMax.h" -#include "kernels/Utils.h" -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -ArgMax::ArgMax(const Tensor *input, const Tensor *axis, Tensor *output, const ArgMaxParams ¶ms) - : KernelWithParams<ArgMaxParams>({input, axis}, {output}, params) -{ -} - -void ArgMax::configure() -{ - assert(axis()->element_type() == DataType::S32 || axis()->element_type() == DataType::S64); - assert(input()->shape().num_dims() >= 1); - const Shape &input_shape = input()->shape(); - const int num_dims = input_shape.num_dims(); - Shape output_shape(num_dims - 1); - - // If axis value is negative, then update by adding input_shape's num_dims. - // If updated value also negative, then assert. - assert(axis()->shape().num_elements() == 1); - int axis_value = getTensorData<int32_t>(axis())[0]; - if (axis_value < 0) - axis_value = axis_value + num_dims; - assert(axis_value >= 0); - - int j = 0; - for (int i = 0; i < num_dims; i++) - { - if (i == axis_value) - continue; - output_shape.dim(j++) = input_shape.dim(i); - } - - assert(output()->element_type() == _params.output_type); - - output()->resize(output_shape); -} - -void ArgMax::execute() const -{ - -#define TF_LITE_ARG_MAX(data_type, axis_type, output_type) \ - tflite::optimized_ops::ArgMinMax(getTensorShape(input()), getTensorData<data_type>(input()), \ - getTensorData<axis_type>(axis()), getTensorShape(output()), \ - getTensorData<output_type>(output()), \ - std::greater<data_type>()) - if (axis()->element_type() == DataType::S32) - { - switch (_params.output_type) - { - case DataType::S32: - switch (input()->element_type()) - { - case DataType::FLOAT32: - TF_LITE_ARG_MAX(float, int32_t, int32_t); - break; - case DataType::U8: - TF_LITE_ARG_MAX(uint8_t, int32_t, int32_t); - break; - default: - throw std::runtime_error("Unsupported input type."); - } - break; - case DataType::S64: - switch (input()->element_type()) - { - case DataType::FLOAT32: - TF_LITE_ARG_MAX(float, int32_t, int64_t); - break; - case DataType::U8: - TF_LITE_ARG_MAX(uint8_t, int32_t, int64_t); - break; - default: - throw std::runtime_error("Unsupported input type."); - } - break; - default: - throw std::runtime_error("Unsupported output type."); - } - } - else - { - switch (_params.output_type) - { - case DataType::S32: - switch (input()->element_type()) - { - case DataType::FLOAT32: - TF_LITE_ARG_MAX(float, int64_t, int32_t); - break; - case DataType::U8: - TF_LITE_ARG_MAX(uint8_t, int64_t, int32_t); - break; - default: - throw std::runtime_error("Unsupported input type."); - } - break; - case DataType::S64: - switch (input()->element_type()) - { - case DataType::FLOAT32: - TF_LITE_ARG_MAX(float, int64_t, int64_t); - break; - case DataType::U8: - TF_LITE_ARG_MAX(uint8_t, int64_t, int64_t); - break; - default: - throw std::runtime_error("Unsupported input type."); - } - break; - default: - throw std::runtime_error("Unsupported output type."); - } - } -#undef TF_LITE_ARG_MAX -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/ArgMax.h b/compiler/luci-interpreter/src/kernels/ArgMax.h deleted file mode 100644 index c851b5891..000000000 --- a/compiler/luci-interpreter/src/kernels/ArgMax.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_ARGMAX_H -#define LUCI_INTERPRETER_KERNELS_ARGMAX_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class ArgMax : public KernelWithParams<ArgMaxParams> -{ -public: - ArgMax(const Tensor *input, const Tensor *axis, Tensor *output, const ArgMaxParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *axis() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_ARGMAX_H diff --git a/compiler/luci-interpreter/src/kernels/ArgMax.test.cpp b/compiler/luci-interpreter/src/kernels/ArgMax.test.cpp deleted file mode 100644 index c6734a114..000000000 --- a/compiler/luci-interpreter/src/kernels/ArgMax.test.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/ArgMax.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T1, typename T2> -void Check(std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> dimension_shape, - std::initializer_list<int32_t> output_shape, std::initializer_list<T1> input_data, - std::initializer_list<int32_t> dimension_data, std::initializer_list<T2> output_data) -{ - constexpr DataType element_type = getElementType<T1>(); - Tensor input_tensor = makeInputTensor<element_type>(input_shape, input_data); - Tensor dimension_tensor = makeInputTensor<DataType::S32>(dimension_shape, dimension_data); - Tensor output_tensor = makeOutputTensor(getElementType<T2>()); - - ArgMaxParams params{}; - params.output_type = getElementType<T2>(); - ArgMax kernel(&input_tensor, &dimension_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<T2>(output_tensor), ::testing::ElementsAreArray(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), output_shape); -} - -template <typename T> class ArgMaxTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(ArgMaxTest, DataTypes); - -TYPED_TEST(ArgMaxTest, Simple) -{ - Check<TypeParam, int32_t>(/*input_shape=*/{1, 1, 1, 4}, /*dimension_shape=*/{}, - /*output_shape=*/{1, 1, 1}, - /*input_data=*/ - { - 1, 9, 7, 3, - }, - /*dimension_data=*/{3}, /*output_data=*/{1}); - Check<TypeParam, int64_t>(/*input_shape=*/{1, 1, 1, 4}, /*dimension_shape=*/{}, - /*output_shape=*/{1, 1, 1}, - /*input_data=*/ - { - 1, 9, 7, 3, - }, - /*dimension_data=*/{3}, /*output_data=*/{1}); -} - -TYPED_TEST(ArgMaxTest, MultiDimensions) -{ - Check<TypeParam, int32_t>(/*input_shape=*/{1, 1, 2, 4}, /*dimension_shape=*/{}, - /*output_shape=*/{1, 1, 2}, - /*input_data=*/ - { - 1, 2, 7, 8, 1, 9, 7, 3, - }, - /*dimension_data=*/{3}, /*output_data=*/{3, 1}); - Check<TypeParam, int64_t>(/*input_shape=*/{1, 1, 2, 4}, /*dimension_shape=*/{}, - /*output_shape=*/{1, 1, 2}, - /*input_data=*/ - { - 1, 2, 7, 8, 1, 9, 7, 3, - }, - /*dimension_data=*/{3}, /*output_data=*/{3, 1}); -} - -TEST(ArgMaxTest, UnsupportedType_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1, 1, 2, 4}, { - 1, 2, 7, 8, 1, 9, 7, 3, - }); - Tensor dimension_tensor = makeInputTensor<DataType::S32>({}, {3}); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - ArgMaxParams params{}; - params.output_type = DataType::U8; - ArgMax kernel(&input_tensor, &dimension_tensor, &output_tensor, params); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/AveragePool2D.cpp b/compiler/luci-interpreter/src/kernels/AveragePool2D.cpp deleted file mode 100644 index df54f9786..000000000 --- a/compiler/luci-interpreter/src/kernels/AveragePool2D.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/AveragePool2D.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h> -#include <tensorflow/lite/kernels/internal/reference/pooling.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -AveragePool2D::AveragePool2D(const Tensor *input, Tensor *output, const Pool2DParams ¶ms) - : KernelWithParams<Pool2DParams>({input}, {output}, params) -{ -} - -void AveragePool2D::configure() -{ - if (input()->element_type() != output()->element_type()) - { - throw std::runtime_error("Input Tensor and Output Tensor Type must be same"); - } - if (input()->shape().num_dims() != 4) - { - throw std::runtime_error("Input Tensor Shape must be 4-D"); - } - const Shape &input_shape = input()->shape(); - - const int32_t batches = input_shape.dim(0); - const int32_t input_height = input_shape.dim(1); - const int32_t input_width = input_shape.dim(2); - const int32_t depth = input_shape.dim(3); - - const int32_t output_height = computeOutputSize(_params.padding, input_height, - _params.filter_height, _params.stride_height); - const int32_t output_width = - computeOutputSize(_params.padding, input_width, _params.filter_width, _params.stride_width); - - _padding_height = - computePadding(_params.stride_height, 1, input_height, _params.filter_height, output_height); - _padding_width = - computePadding(_params.stride_width, 1, input_width, _params.filter_width, output_width); - if (input()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6); - LUCI_INTERPRETER_CHECK(output()->zero_point() == input()->zero_point()); - } - else if (input()->element_type() == DataType::S16) - { - LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6); - LUCI_INTERPRETER_CHECK(input()->zero_point() == 0 && output()->zero_point() == 0); - } - output()->resize({batches, output_height, output_width, depth}); -} - -void AveragePool2D::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - case DataType::S16: - evalSInt16(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void AveragePool2D::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - - tflite::reference_ops::AveragePool(params, getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); -} - -void AveragePool2D::evalQuantized() const -{ - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - tflite::reference_ops::AveragePool(params, getTensorShape(input()), - getTensorData<uint8_t>(input()), getTensorShape(output()), - getTensorData<uint8_t>(output())); -} - -void AveragePool2D::evalSInt16() const -{ - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - tflite::reference_integer_ops::AveragePool( - params, getTensorShape(input()), getTensorData<int16_t>(input()), // - getTensorShape(output()), getTensorData<int16_t>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/AveragePool2D.h b/compiler/luci-interpreter/src/kernels/AveragePool2D.h deleted file mode 100644 index 282a58797..000000000 --- a/compiler/luci-interpreter/src/kernels/AveragePool2D.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_AVERAGEPOOL2D_H -#define LUCI_INTERPRETER_KERNELS_AVERAGEPOOL2D_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class AveragePool2D : public KernelWithParams<Pool2DParams> -{ -public: - AveragePool2D(const Tensor *input, Tensor *output, const Pool2DParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void evalSInt16() const; - -private: - int32_t _padding_height{}; - int32_t _padding_width{}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_AVERAGEPOOL2D_H diff --git a/compiler/luci-interpreter/src/kernels/AveragePool2D.test.cpp b/compiler/luci-interpreter/src/kernels/AveragePool2D.test.cpp deleted file mode 100644 index 83e48c89d..000000000 --- a/compiler/luci-interpreter/src/kernels/AveragePool2D.test.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/AveragePool2D.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(AveragePool2DTest, Float) -{ - Shape input_shape{1, 3, 5, 1}; - std::vector<float> input_data{ - -4, -3, -2, -1, 0, // - 1, 2, 3, 4, 5, // - 6, 7, 8, 9, 10, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 0, 1.5, // - 4.5, 6, // - }; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 2, 1})); -} - -TEST(AveragePool2DTest, Uint8_0) -{ - std::vector<float> input_data{ - 0, -6, 12, 4, // - -3, -2, 10, 7, // - }; - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-15.9375f, 15.9375f); - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, - quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear({0.0, 6.0})); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 1, 2, 1})); -} - -TEST(AveragePool2DTest, Uint8_1) -{ - std::vector<float> input_data{ - 0, 6, 12, 4, // - 3, 2, 10, 7, // - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-15.9375f, 15.9375f); - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, - quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear({2.75, 6.0})); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 1, 2, 1})); -} - -TEST(AveragePool2DTest, SInt16) -{ - Shape input_shape{1, 3, 5, 1}; - std::vector<int32_t> ref_output_shape{1, 2, 2, 1}; - std::vector<float> input_data{ - -4, -3, -2, -1, 0, // - 1, 2, 3, 4, 5, // - 6, 7, 8, 9, 10, // - }; - std::vector<float> ref_output_data{ - 0, 1.5, // - 4.5, 6, // - }; - Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, 0.5, 0, input_data); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(AveragePool2DTest, Invalid_Input_Shape_NEG) -{ - Shape input_shape{1, 3, 5}; - std::vector<float> input_data{ - -4, -3, -2, -1, 0, // - 1, 2, 3, 4, 5, // - 6, 7, 8, 9, 10, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(AveragePool2DTest, In_Out_Type_NEG) -{ - Shape input_shape{1, 3, 5, 1}; - std::vector<float> input_data{ - -4, -3, -2, -1, 0, // - 1, 2, 3, 4, 5, // - 6, 7, 8, 9, 10, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(AveragePool2DTest, Quant_Param_NEG) -{ - std::vector<float> input_data{ - 0, -6, 12, 4, // - -3, -2, 10, 7, // - }; - - std::pair<float, int32_t> quant_param1 = quantizationParams<uint8_t>(-15.9375f, 15.9375f); - std::pair<float, int32_t> quant_param2 = quantizationParams<uint8_t>(-7.875f, 7.875f); - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param1.first, - quant_param1.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param2.first, quant_param2.second); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/BinaryOpCommon.h b/compiler/luci-interpreter/src/kernels/BinaryOpCommon.h deleted file mode 100644 index 62bd4158e..000000000 --- a/compiler/luci-interpreter/src/kernels/BinaryOpCommon.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_BINARYOPUTILS_H -#define LUCI_INTERPRETER_KERNELS_BINARYOPUTILS_H - -#include "tensorflow/lite/kernels/internal/common.h" -#include "tensorflow/lite/kernels/internal/types.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -// Derived from tensorflow/lite/kernels/internal/reference/maximum_minimum.h (v2.3.0). -template <typename T, typename Op, int N = 5> -void BinaryOpBroadcastSlow(const tflite::RuntimeShape &unextended_input1_shape, - const T *input1_data, - const tflite::RuntimeShape &unextended_input2_shape, - const T *input2_data, - const tflite::RuntimeShape &unextended_output_shape, T *output_data, - Op op) -{ - if (unextended_input1_shape == unextended_input2_shape) - { - const int flat_size = tflite::MatchingElementsSize( - unextended_input1_shape, unextended_input2_shape, unextended_output_shape); - for (int i = 0; i < flat_size; ++i) - { - output_data[i] = op(input1_data[i], input2_data[i]); - } - } - else - { - assert(unextended_input1_shape.DimensionsCount() <= N); - assert(unextended_input2_shape.DimensionsCount() <= N); - assert(unextended_output_shape.DimensionsCount() <= N); - - tflite::NdArrayDesc<N> desc1{}; - tflite::NdArrayDesc<N> desc2{}; - tflite::NdArrayDesc<N> output_desc{}; - tflite::NdArrayDescsForElementwiseBroadcast(unextended_input1_shape, unextended_input2_shape, - &desc1, &desc2); - tflite::CopyDimsToDesc(tflite::RuntimeShape::ExtendedShape(N, unextended_output_shape), - &output_desc); - - auto fn = [&](int indexes[N]) { - output_data[SubscriptToIndex(output_desc, indexes)] = - op(input1_data[SubscriptToIndex(desc1, indexes)], - input2_data[SubscriptToIndex(desc2, indexes)]); - }; - tflite::NDOpsHelper<N>(output_desc, fn); - } -} - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_BINARYOPUTILS_H diff --git a/compiler/luci-interpreter/src/kernels/CMakeLists.txt b/compiler/luci-interpreter/src/kernels/CMakeLists.txt deleted file mode 100644 index b460321bd..000000000 --- a/compiler/luci-interpreter/src/kernels/CMakeLists.txt +++ /dev/null @@ -1,186 +0,0 @@ -find_package(Threads REQUIRED) -nnas_find_package(GTest REQUIRED) - -set(SOURCES - Add.h - Add.cpp - ArgMax.h - ArgMax.cpp - AveragePool2D.h - AveragePool2D.cpp - Concatenation.h - Concatenation.cpp - Conv2D.h - Conv2D.cpp - DepthToSpace.h - DepthToSpace.cpp - DepthwiseConv2D.h - DepthwiseConv2D.cpp - Div.h - Div.cpp - Elu.h - Elu.cpp - Floor.h - Floor.cpp - FloorDiv.h - FloorDiv.cpp - Equal.h - Equal.cpp - FullyConnected.h - FullyConnected.cpp - Greater.h - Greater.cpp - GreaterEqual.h - GreaterEqual.cpp - If.h - If.cpp - L2Normalize.h - L2Normalize.cpp - L2Pool2D.h - L2Pool2D.cpp - LeakyRelu.h - LeakyRelu.cpp - Less.h - Less.cpp - LessEqual.h - LessEqual.cpp - LocalResponseNormalization.h - LocalResponseNormalization.cpp - Logistic.h - Logistic.cpp - LogSoftmax.h - LogSoftmax.cpp - Maximum.h - Maximum.cpp - MaxPool2D.h - MaxPool2D.cpp - Mean.h - Mean.cpp - Minimum.h - Minimum.cpp - Mul.h - Mul.cpp - NotEqual.h - NotEqual.cpp - Pad.h - Pad.cpp - Pow.h - Pow.cpp - Prelu.h - Prelu.cpp - Relu.h - Relu.cpp - Relu6.h - Relu6.cpp - Reshape.h - Reshape.cpp - ResizeBilinear.h - ResizeBilinear.cpp - ResizeNearestNeighbor.h - ResizeNearestNeighbor.cpp - Reverse.h - Reverse.cpp - Rsqrt.h - Rsqrt.cpp - Slice.h - Slice.cpp - Softmax.h - Softmax.cpp - SpaceToDepth.h - SpaceToDepth.cpp - Split.h - Split.cpp - StridedSlice.h - StridedSlice.cpp - Sqrt.h - Sqrt.cpp - Squeeze.h - Squeeze.cpp - Sub.h - Sub.cpp - Tanh.h - Tanh.cpp - Transpose.h - Transpose.cpp - TransposeConv.h - TransposeConv.cpp - Unpack.h - Unpack.cpp) - -list(APPEND SOURCES - BinaryOpCommon.h - Utils.h - Utils.cpp - ${TensorFlowSource_DIR}/tensorflow/lite/kernels/internal/quantization_util.cc) - -add_library(luci_interpreter_kernels STATIC ${SOURCES}) -set_target_properties(luci_interpreter_kernels PROPERTIES POSITION_INDEPENDENT_CODE ON) -target_include_directories(luci_interpreter_kernels PUBLIC ${LUCI_INTERPRETER_SOURCE_DIR}) -target_include_directories(luci_interpreter_kernels SYSTEM PRIVATE - "${TensorFlowRuySource_DIR}" - "${TensorFlowGEMMLowpSource_DIR}" - "${TensorFlowEigenSource_DIR}" - "${TensorFlowSource_DIR}") -target_link_libraries(luci_interpreter_kernels - PUBLIC luci_interpreter_core - PRIVATE nncc_common Threads::Threads) - - -set(TEST_SOURCES - Add.test.cpp - ArgMax.test.cpp - AveragePool2D.test.cpp - Concatenation.test.cpp - Conv2D.test.cpp - DepthToSpace.test.cpp - DepthwiseConv2D.test.cpp - Div.test.cpp - Elu.test.cpp - Floor.test.cpp - FloorDiv.test.cpp - Equal.test.cpp - FullyConnected.test.cpp - Greater.test.cpp - GreaterEqual.test.cpp - If.test.cpp - L2Normalize.test.cpp - L2Pool2D.test.cpp - LeakyRelu.test.cpp - Less.test.cpp - LessEqual.test.cpp - LocalResponseNormalization.test.cpp - Logistic.test.cpp - LogSoftmax.test.cpp - Maximum.test.cpp - MaxPool2D.test.cpp - Mean.test.cpp - Minimum.test.cpp - Mul.test.cpp - NotEqual.test.cpp - Pad.test.cpp - Pow.test.cpp - Prelu.test.cpp - Relu.test.cpp - Relu6.test.cpp - Reshape.test.cpp - ResizeBilinear.test.cpp - ResizeNearestNeighbor.test.cpp - Reverse.test.cpp - Rsqrt.test.cpp - Slice.test.cpp - Softmax.test.cpp - SpaceToDepth.test.cpp - Split.test.cpp - StridedSlice.test.cpp - Sqrt.test.cpp - Squeeze.test.cpp - Sub.test.cpp - Tanh.test.cpp - Transpose.test.cpp - TransposeConv.test.cpp - Unpack.test.cpp) - -list(APPEND TEST_SOURCES TestUtils.h TestUtils.cpp) - -GTest_AddTest(luci_interpreter_kernels_test ${TEST_SOURCES}) -target_link_libraries(luci_interpreter_kernels_test luci_interpreter_kernels) diff --git a/compiler/luci-interpreter/src/kernels/Concatenation.cpp b/compiler/luci-interpreter/src/kernels/Concatenation.cpp deleted file mode 100644 index 6f8820446..000000000 --- a/compiler/luci-interpreter/src/kernels/Concatenation.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Concatenation.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -Concatenation::Concatenation(std::vector<const Tensor *> inputs, Tensor *output, - const ConcatenationParams ¶ms) - : KernelWithParams<ConcatenationParams>(std::move(inputs), {output}, params) -{ -} - -void Concatenation::configure() -{ - const int num_inputs = _inputs.size(); - LUCI_INTERPRETER_CHECK(num_inputs > 0); - const Tensor *t0 = _inputs[0]; - - int axis = _params.axis; - if (axis < 0) - axis += t0->shape().num_dims(); - LUCI_INTERPRETER_CHECK(axis >= 0 && axis < t0->shape().num_dims()); - - int32_t sum_axis = t0->shape().dim(axis); - for (int i = 1; i < num_inputs; ++i) - { - const Tensor *tensor = _inputs[i]; - LUCI_INTERPRETER_CHECK(tensor->element_type() == t0->element_type()); - LUCI_INTERPRETER_CHECK(tensor->shape().num_dims() == t0->shape().num_dims()); - for (int d = 0; d < t0->shape().num_dims(); ++d) - { - if (d == axis) - { - sum_axis += tensor->shape().dim(axis); - } - else - { - LUCI_INTERPRETER_CHECK(tensor->shape().dim(d) == t0->shape().dim(d)); - } - } - } - - Shape output_shape = t0->shape(); - output_shape.dim(axis) = sum_axis; - - // TODO S8 type needs more checking: quantization parameters of all input tensors and the output - // tensor should be the same. Note that there is no such requirement for U8 type. - if (t0->element_type() == DataType::S8) - throw std::runtime_error("Unsupported type."); - - output()->resize(output_shape); -} - -void Concatenation::execute() const -{ - switch (_inputs[0]->element_type()) - { - case DataType::FLOAT32: - evalGeneric<float>(); - break; - case DataType::U8: - evalQuantized(); - break; - case DataType::S8: - evalGeneric<int8_t>(); - break; - case DataType::S32: - evalGeneric<int32_t>(); - break; - case DataType::S64: - evalGeneric<int64_t>(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -template <typename T> void Concatenation::evalGeneric() const -{ - int axis = _params.axis; - if (axis < 0) - axis += output()->shape().num_dims(); - - VectorOfTensors<T, true> inputs(_inputs); - tflite::ConcatenationParams params{}; - params.axis = axis; - params.inputs_count = _inputs.size(); - tflite::reference_ops::Concatenation(params, inputs.shapes(), inputs.data(), - getTensorShape(output()), getTensorData<T>(output())); -} - -void Concatenation::evalQuantized() const -{ - int axis = _params.axis; - if (axis < 0) - axis += output()->shape().num_dims(); - - VectorOfQuantizedTensors<true> inputs(_inputs); - tflite::ConcatenationParams params{}; - params.axis = axis; - params.input_zeropoint = inputs.zero_point(); - params.input_scale = inputs.scale(); - params.inputs_count = _inputs.size(); - params.output_zeropoint = output()->zero_point(); - params.output_scale = output()->scale(); - - tflite::reference_ops::ConcatenationWithScaling(params, inputs.shapes(), inputs.data(), - getTensorShape(output()), - getTensorData<uint8_t>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Concatenation.h b/compiler/luci-interpreter/src/kernels/Concatenation.h deleted file mode 100644 index b48c8ed1e..000000000 --- a/compiler/luci-interpreter/src/kernels/Concatenation.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_CONCATENATION_H -#define LUCI_INTERPRETER_KERNELS_CONCATENATION_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Concatenation : public KernelWithParams<ConcatenationParams> -{ -public: - Concatenation(std::vector<const Tensor *> inputs, Tensor *output, - const ConcatenationParams ¶ms); - - const Tensor *input(int index) const { return _inputs[index]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - template <typename T> void evalGeneric() const; - void evalQuantized() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_CONCATENATION_H diff --git a/compiler/luci-interpreter/src/kernels/Concatenation.test.cpp b/compiler/luci-interpreter/src/kernels/Concatenation.test.cpp deleted file mode 100644 index 91707a256..000000000 --- a/compiler/luci-interpreter/src/kernels/Concatenation.test.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Concatenation.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(ConcatenationTest, Float) -{ - std::vector<float> input1_data{1, 2, 3, 4, 5, 6}; - std::vector<float> input2_data{7, 8, 9, 10, 11, 12}; - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - ConcatenationParams params{}; - - // Try different 'axis' and expect different results. - { - params.axis = 0; - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - FloatArrayNear({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})); - } - { - params.axis = -2; // Same as '0'. - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - FloatArrayNear({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})); - } - { - params.axis = 1; - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - FloatArrayNear({1, 2, 3, 7, 8, 9, 4, 5, 6, 10, 11, 12})); - } - { - params.axis = -1; // Same as '1'. - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - FloatArrayNear({1, 2, 3, 7, 8, 9, 4, 5, 6, 10, 11, 12})); - } -} - -TEST(ConcatenationTest, Input_Number_Check_NEG) -{ - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - ConcatenationParams params{}; - - params.axis = -1; - - Concatenation kernel({}, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ConcatenationTest, Invalid_Axis_NEG) -{ - std::vector<float> input1_data{1, 2, 3, 4, 5, 6}; - std::vector<float> input2_data{7, 8, 9, 10, 11, 12}; - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - ConcatenationParams params{}; - - params.axis = -3; - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ConcatenationTest, Mismatching_Input_Type_NEG) -{ - std::vector<float> input1_data{1, 2, 3, 4, 5, 6}; - std::vector<uint8_t> input2_data{7, 8, 9, 10, 11, 12}; - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::U8>({2, 3}, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - ConcatenationParams params{}; - - params.axis = -1; - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ConcatenationTest, Mismatching_Input_Dimension_Num_NEG) -{ - std::vector<float> input1_data{1, 2, 3, 4, 5, 6}; - std::vector<float> input2_data{7, 8, 9, 10, 11, 12}; - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>({1, 2, 3}, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - ConcatenationParams params{}; - - params.axis = -1; - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ConcatenationTest, Mismatching_Input_Dimension_NEG) -{ - std::vector<float> input1_data{1, 2, 3, 4, 5, 6}; - std::vector<float> input2_data{7, 8, 9, 10, 11, 12, 13, 14, 15}; - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>({3, 3}, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - ConcatenationParams params{}; - - params.axis = -1; - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ConcatenationTest, Unsupported_Configure_Type_NEG) -{ - std::vector<int8_t> input1_data{1, 2, 3, 4, 5, 6}; - std::vector<int8_t> input2_data{7, 8, 9, 10, 11, 12}; - Tensor input1_tensor = makeInputTensor<DataType::S8>({2, 3}, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::S8>({2, 3}, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::S8); - ConcatenationParams params{}; - - params.axis = -1; - - Concatenation kernel({&input1_tensor, &input2_tensor}, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Conv2D.cpp b/compiler/luci-interpreter/src/kernels/Conv2D.cpp deleted file mode 100644 index a51fb4afc..000000000 --- a/compiler/luci-interpreter/src/kernels/Conv2D.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Conv2D.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/legacy_optimized_ops.h> - -#include <stdexcept> -#include <thread> - -namespace luci_interpreter -{ -namespace kernels -{ - -Conv2D::Conv2D(const Tensor *input, const Tensor *filter, const Tensor *bias, Tensor *output, - const Conv2DParams ¶ms) - : KernelWithParams<Conv2DParams>({input, filter, bias}, {output}, params) -{ -} - -void Conv2D::configure() -{ - // TensorFlow Lite (as of v2.2.0) supports the following combinations of types: - // | input filter bias output | - // ----+---------------------------+ - // (1) | float float float float | - // (2) | float int8 float float | hybrid - // (3) | uint8 uint8 int32 uint8 | quantized - // (4) | int8 int8 int32 int8 | quantized per channel - // - // We only support (1) and (3) for now. - if (input()->element_type() == DataType::FLOAT32 && filter()->element_type() == DataType::FLOAT32) - { - LUCI_INTERPRETER_CHECK(bias() == nullptr || bias()->element_type() == DataType::FLOAT32); - } - else if (input()->element_type() == DataType::U8 && filter()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(bias() == nullptr || bias()->element_type() == DataType::S32); - } - else - { - throw std::runtime_error("Unsupported type."); - } - LUCI_INTERPRETER_CHECK(output()->element_type() == input()->element_type()); - - const Shape &input_shape = input()->shape(); - const Shape &filter_shape = filter()->shape(); - LUCI_INTERPRETER_CHECK(input_shape.num_dims() == 4 && filter_shape.num_dims() == 4); - - const int32_t batches = input_shape.dim(0); - const int32_t input_height = input_shape.dim(1); - const int32_t input_width = input_shape.dim(2); - const int32_t output_depth = filter_shape.dim(0); - const int32_t filter_height = filter_shape.dim(1); - const int32_t filter_width = filter_shape.dim(2); - LUCI_INTERPRETER_CHECK(filter_shape.dim(3) == input_shape.dim(3)); - - LUCI_INTERPRETER_CHECK(bias() == nullptr || (bias()->shape().num_dims() == 1 && - bias()->shape().dim(0) == output_depth)); - - const int32_t output_height = - computeOutputSize(_params.padding, input_height, filter_height, _params.stride_height, - _params.dilation_height_factor); - const int32_t output_width = - computeOutputSize(_params.padding, input_width, filter_width, _params.stride_width, - _params.dilation_width_factor); - - _padding_height = computePadding(_params.stride_height, _params.dilation_height_factor, - input_height, filter_height, output_height); - _padding_width = computePadding(_params.stride_width, _params.dilation_width_factor, input_width, - filter_width, output_width); - - output()->resize({batches, output_height, output_width, output_depth}); - - // Allocate tensor for Im2Col, if needed. - // The checks here should be aligned with the actual implementation. - const bool need_dilated_im2col = - _params.dilation_height_factor != 1 || _params.dilation_width_factor != 1; - const bool need_non_dilated_im2col = _params.stride_height != 1 || _params.stride_width != 1 || - filter_height != 1 || filter_width != 1; - const bool need_im2col = need_dilated_im2col || need_non_dilated_im2col; - if (need_im2col) - { - const int input_depth = input_shape.dim(3); - Shape im2col_shape{batches, output_height, output_width, - input_depth * filter_height * filter_width}; - _im2col = - std::make_unique<Tensor>(input()->element_type(), im2col_shape, AffineQuantization{}, ""); - } -} - -void Conv2D::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - if (filter()->element_type() == DataType::FLOAT32) - { - evalFloat(); - break; - } - throw std::runtime_error("Unsupported type."); - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Conv2D::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::ConvParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.dilation_height_factor = _params.dilation_height_factor; - params.dilation_width_factor = _params.dilation_width_factor; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - - tflite::optimized_ops::Conv(params, getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(filter()), getTensorData<float>(filter()), - getTensorShape(bias()), getTensorData<float>(bias()), - getTensorShape(output()), getTensorData<float>(output()), - getTensorShape(_im2col.get()), getTensorData<float>(_im2col.get())); -} - -void Conv2D::evalQuantized() const -{ - const auto input_scale = static_cast<double>(input()->scale()); - const auto filter_scale = static_cast<double>(filter()->scale()); - const auto output_scale = static_cast<double>(output()->scale()); - - const double real_multiplier = input_scale * filter_scale / output_scale; - int32_t output_multiplier{}; - int output_shift{}; - quantizeMultiplier(real_multiplier, &output_multiplier, &output_shift); - - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::ConvParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.dilation_height_factor = _params.dilation_height_factor; - params.dilation_width_factor = _params.dilation_width_factor; - // The kernel expects input and filter zero points to be negated. - params.input_offset = -input()->zero_point(); // Note the '-'. - params.weights_offset = -filter()->zero_point(); // Note the '-'. - params.output_offset = output()->zero_point(); - params.output_multiplier = output_multiplier; - params.output_shift = output_shift; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - // TODO This should only be done once (although it takes only a few microseconds). - // Also, the user should be able to adjust the number of threads. - auto gemmlowp_context = std::make_unique<gemmlowp::GemmContext>(); - gemmlowp_context->set_max_num_threads(static_cast<int>(std::thread::hardware_concurrency())); - - tflite::optimized_ops::Conv( - params, getTensorShape(input()), getTensorData<uint8_t>(input()), getTensorShape(filter()), - getTensorData<uint8_t>(filter()), getTensorShape(bias()), getTensorData<int32_t>(bias()), - getTensorShape(output()), getTensorData<uint8_t>(output()), getTensorShape(_im2col.get()), - getTensorData<uint8_t>(_im2col.get()), gemmlowp_context.get()); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Conv2D.h b/compiler/luci-interpreter/src/kernels/Conv2D.h deleted file mode 100644 index 69e309852..000000000 --- a/compiler/luci-interpreter/src/kernels/Conv2D.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_CONV2D_H -#define LUCI_INTERPRETER_KERNELS_CONV2D_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -#include <memory> - -namespace luci_interpreter -{ -namespace kernels -{ - -class Conv2D : public KernelWithParams<Conv2DParams> -{ -public: - Conv2D(const Tensor *input, const Tensor *filter, const Tensor *bias, Tensor *output, - const Conv2DParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *filter() const { return _inputs[1]; } - const Tensor *bias() const { return _inputs[2]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - std::unique_ptr<Tensor> _im2col; - int32_t _padding_height{}; - int32_t _padding_width{}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_CONV2D_H diff --git a/compiler/luci-interpreter/src/kernels/Conv2D.test.cpp b/compiler/luci-interpreter/src/kernels/Conv2D.test.cpp deleted file mode 100644 index be8364528..000000000 --- a/compiler/luci-interpreter/src/kernels/Conv2D.test.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Conv2D.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(Conv2DTest, Float) -{ - Shape input_shape{1, 4, 3, 2}; - Shape filter_shape{2, 2, 2, 2}; - Shape bias_shape{2}; - std::vector<float> input_data{ - 1, 2, 3, 4, 5, 6, // row = 0 - 7, 8, 9, 10, 11, 12, // row = 1 - 13, 14, 15, 16, 17, 18, // row = 2 - 19, 20, 21, 22, 23, 24, // row = 3 - }; - std::vector<float> filter_data{ - 1, 2, -3, -4, // out = 0, row = 0 - -5, 6, -7, 8, // out = 1, row = 0 - 4, -2, 3, -1, // out = 0, row = 1 - -8, -6, 7, 5, // out = 1, row = 1 - }; - std::vector<float> bias_data{1, 2}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Conv2DParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 11, 16, 7, 20, // row = 0 - 0, 40, 0, 44, // row = 1 - }; - std::vector<int32_t> ref_output_shape{1, 2, 2, 2}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(Conv2DTest, FloatCheck) -{ - Shape input_shape{2, 2, 4, 1}; - Shape filter_shape{3, 2, 2, 1}; - Shape bias_shape{3}; - std::vector<float> input_data{ - // First batch - 1, 1, 1, 1, // row = 1 - 2, 2, 2, 2, // row = 2 - // Second batch - 1, 2, 3, 4, // row = 1 - 1, 2, 3, 4, // row = 2 - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // first 2x2 filter - -1, 1, -1, 1, // second 2x2 filter - -1, -1, 1, 1, // third 2x2 filter - }; - std::vector<float> bias_data{1, 2, 3}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Conv2DParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 2; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::NONE; - - Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 18, 2, 5, // first batch, left - 18, 2, 5, // first batch, right - 17, 4, 3, // second batch, left - 37, 4, 3, // second batch, right - }; - std::vector<int32_t> ref_output_shape{2, 1, 2, 3}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(Conv2DTest, Uint8) -{ - std::vector<float> input_data{ - // First batch - 1, 1, 1, 1, // row = 1 - 2, 2, 2, 2, // row = 2 - // Second batch - 1, 2, 3, 4, // row = 1 - 1, 2, 3, 4, // row = 2 - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // first 2x2 filter - -1, 1, -1, 1, // second 2x2 filter - -1, -1, 1, 1, // third 2x2 filter - }; - std::vector<float> bias_data{1, 2, 3}; - - std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(-63.5, 64); - std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(-127, 128); - - Tensor input_tensor = makeInputTensor<DataType::U8>({2, 2, 4, 1}, input_quant_param.first, - input_quant_param.second, input_data); - Tensor filter_tensor = makeInputTensor<DataType::U8>({3, 2, 2, 1}, input_quant_param.first, - input_quant_param.second, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::S32>( - {3}, input_quant_param.first * input_quant_param.first, 0, bias_data); - Tensor output_tensor = - makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second); - - Conv2DParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 2; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::NONE; - - Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 18, 2, 5, // first batch, left - 18, 2, 5, // first batch, right - 17, 4, 3, // second batch, left - 37, 4, 3, // second batch, right - }; - std::vector<int32_t> ref_output_shape{2, 1, 2, 3}; - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(Conv2DTest, Unsupported_Type_Configure_NEG) -{ - Shape input_shape{1, 4, 3, 2}; - Shape filter_shape{2, 2, 2, 2}; - Shape bias_shape{2}; - std::vector<int32_t> input_data{ - 1, 2, 3, 4, 5, 6, // row = 0 - 7, 8, 9, 10, 11, 12, // row = 1 - 13, 14, 15, 16, 17, 18, // row = 2 - 19, 20, 21, 22, 23, 24, // row = 3 - }; - std::vector<float> filter_data{ - 1, 2, -3, -4, // out = 0, row = 0 - -5, 6, -7, 8, // out = 1, row = 0 - 4, -2, 3, -1, // out = 0, row = 1 - -8, -6, 7, 5, // out = 1, row = 1 - }; - std::vector<float> bias_data{1, 2}; - Tensor input_tensor = makeInputTensor<DataType::S32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Conv2DParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(Conv2DTest, Invalid_Bias_Type_NEG) -{ - Shape input_shape{1, 4, 3, 2}; - Shape filter_shape{2, 2, 2, 2}; - Shape bias_shape{2}; - std::vector<float> input_data{ - 1, 2, 3, 4, 5, 6, // row = 0 - 7, 8, 9, 10, 11, 12, // row = 1 - 13, 14, 15, 16, 17, 18, // row = 2 - 19, 20, 21, 22, 23, 24, // row = 3 - }; - std::vector<float> filter_data{ - 1, 2, -3, -4, // out = 0, row = 0 - -5, 6, -7, 8, // out = 1, row = 0 - 4, -2, 3, -1, // out = 0, row = 1 - -8, -6, 7, 5, // out = 1, row = 1 - }; - std::vector<uint8_t> bias_data{1, 2}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::U8>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Conv2DParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(Conv2DTest, Invalid_Bias_Data_NEG) -{ - Shape input_shape{1, 4, 3, 2}; - Shape filter_shape{2, 2, 2, 2}; - Shape bias_shape{3}; - std::vector<float> input_data{ - 1, 2, 3, 4, 5, 6, // row = 0 - 7, 8, 9, 10, 11, 12, // row = 1 - 13, 14, 15, 16, 17, 18, // row = 2 - 19, 20, 21, 22, 23, 24, // row = 3 - }; - std::vector<float> filter_data{ - 1, 2, -3, -4, // out = 0, row = 0 - -5, 6, -7, 8, // out = 1, row = 0 - 4, -2, 3, -1, // out = 0, row = 1 - -8, -6, 7, 5, // out = 1, row = 1 - }; - std::vector<float> bias_data{1, 2, 3}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Conv2DParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(Conv2DTest, Invalid_Input_Shape_NEG) -{ - Shape input_shape{1, 4, 6, 1}; - Shape filter_shape{2, 2, 2, 2}; - Shape bias_shape{2}; - std::vector<float> input_data{ - 1, 2, 3, 4, 5, 6, // row = 0 - 7, 8, 9, 10, 11, 12, // row = 1 - 13, 14, 15, 16, 17, 18, // row = 2 - 19, 20, 21, 22, 23, 24, // row = 3 - }; - std::vector<float> filter_data{ - 1, 2, -3, -4, // out = 0, row = 0 - -5, 6, -7, 8, // out = 1, row = 0 - 4, -2, 3, -1, // out = 0, row = 1 - -8, -6, 7, 5, // out = 1, row = 1 - }; - std::vector<float> bias_data{1, 2}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Conv2DParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/DepthToSpace.cpp b/compiler/luci-interpreter/src/kernels/DepthToSpace.cpp deleted file mode 100644 index 57238313c..000000000 --- a/compiler/luci-interpreter/src/kernels/DepthToSpace.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "DepthToSpace.h" -#include "Utils.h" -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -DepthToSpace::DepthToSpace(const Tensor *input, Tensor *output, const DepthToSpaceParams ¶ms) - : KernelWithParams<DepthToSpaceParams>({input}, {output}, params) -{ -} - -void DepthToSpace::configure() -{ - LUCI_INTERPRETER_CHECK(input()->shape().num_dims() == 4); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::FLOAT32 || - output()->element_type() == DataType::U8) - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()) - const int block_size = params().block_size; - const int32_t input_height = input()->shape().dim(1); - const int32_t input_width = input()->shape().dim(2); - const int32_t input_channels = input()->shape().dim(3); - int32_t output_height = input_height * block_size; - int32_t output_width = input_width * block_size; - int32_t output_channels = input_channels / block_size / block_size; - - LUCI_INTERPRETER_CHECK(input_height == output_height / block_size); - LUCI_INTERPRETER_CHECK(input_width == output_width / block_size); - LUCI_INTERPRETER_CHECK(input_channels == output_channels * block_size * block_size); - - Shape output_shape(4); - output_shape.dim(0) = input()->shape().dim(0); - output_shape.dim(1) = output_height; - output_shape.dim(2) = output_width; - output_shape.dim(3) = output_channels; - - output()->resize(output_shape); -} - -void DepthToSpace::execute() const -{ - tflite::DepthToSpaceParams op_params; - op_params.block_size = params().block_size; - switch (input()->element_type()) - { - case DataType::FLOAT32: - tflite::optimized_ops::DepthToSpace(op_params, getTensorShape(input()), - getTensorData<float>(input()), getTensorShape(output()), - getTensorData<float>(output())); - break; - case DataType::U8: - tflite::optimized_ops::DepthToSpace(op_params, getTensorShape(input()), - getTensorData<uint8_t>(input()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - break; - default: - throw std::runtime_error("Unsupported Type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/DepthToSpace.h b/compiler/luci-interpreter/src/kernels/DepthToSpace.h deleted file mode 100644 index 63ce37610..000000000 --- a/compiler/luci-interpreter/src/kernels/DepthToSpace.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_DEPTHTOSPACE_H -#define LUCI_INTERPRETER_KERNELS_DEPTHTOSPACE_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -#include <vector> - -namespace luci_interpreter -{ -namespace kernels -{ - -class DepthToSpace : public KernelWithParams<DepthToSpaceParams> -{ -public: - DepthToSpace(const Tensor *input, Tensor *output, const DepthToSpaceParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_DEPTHTOSPACE_H diff --git a/compiler/luci-interpreter/src/kernels/DepthToSpace.test.cpp b/compiler/luci-interpreter/src/kernels/DepthToSpace.test.cpp deleted file mode 100644 index 3dee4ad36..000000000 --- a/compiler/luci-interpreter/src/kernels/DepthToSpace.test.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/DepthToSpace.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> class DepthToSpaceTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(DepthToSpaceTest, DataTypes); - -TYPED_TEST(DepthToSpaceTest, SimpleCase) -{ - std::vector<TypeParam> input_data{1, 2, 3, 4, 5, 6, 7, 8}; - Shape input_shape{1, 1, 2, 4}; - std::vector<TypeParam> output_data{1, 2, 5, 6, 3, 4, 7, 8}; - std::vector<int32_t> output_shape{1, 2, 4, 1}; - - Tensor input_tensor = makeInputTensor<getElementType<TypeParam>()>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(getElementType<TypeParam>()); - - DepthToSpaceParams params{}; - params.block_size = 2; - - DepthToSpace kernel = DepthToSpace(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<TypeParam>(output_tensor), - ::testing::ElementsAreArray(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -TEST(DepthToSpaceTest, InvalidInputShape_NEG) -{ - std::vector<float> input_data{1, 2, 3, 4, 5, 6, 7, 8}; - Shape input_shape{1, 2, 4}; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DepthToSpaceParams params{}; - params.block_size = 2; - - DepthToSpace kernel = DepthToSpace(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(DepthToSpaceTest, InOutTypeMismatch_NEG) -{ - std::vector<float> input_data{1, 2, 3, 4, 5, 6, 7, 8}; - Shape input_shape{1, 1, 2, 4}; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - DepthToSpaceParams params{}; - params.block_size = 2; - - DepthToSpace kernel = DepthToSpace(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(DepthToSpaceTest, InvalidBlockSize_NEG) -{ - std::vector<float> input_data{1, 2, 3, 4, 5, 6, 7, 8}; - Shape input_shape{1, 1, 2, 4}; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DepthToSpaceParams params{}; - params.block_size = 3; - - DepthToSpace kernel = DepthToSpace(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.cpp b/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.cpp deleted file mode 100644 index 99d52715b..000000000 --- a/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/DepthwiseConv2D.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h> -#include <tensorflow/lite/kernels/internal/reference/depthwiseconv_uint8.h> - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -DepthwiseConv2D::DepthwiseConv2D(const Tensor *input, const Tensor *filter, const Tensor *bias, - Tensor *output, const DepthwiseConv2DParams ¶ms) - : KernelWithParams<DepthwiseConv2DParams>({input, filter, bias}, {output}, params) -{ -} - -void DepthwiseConv2D::configure() -{ - // TensorFlow Lite (as of v2.2.0) supports the following combinations of types: - // | input filter bias output | - // ----+---------------------------+ - // (1) | float float float float | - // (2) | float int8 float float | hybrid - // (3) | uint8 uint8 int32 uint8 | quantized - // (4) | int8 int8 int32 int8 | quantized per channel - // (5) | int16 int8 int64 int16 | quantized per channel 16x8 - // - // We only support (1) and (3) for now. - if (input()->element_type() == DataType::FLOAT32 && filter()->element_type() == DataType::FLOAT32) - { - LUCI_INTERPRETER_CHECK(bias() == nullptr || bias()->element_type() == DataType::FLOAT32); - } - else if (input()->element_type() == DataType::U8 && filter()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(bias() == nullptr || bias()->element_type() == DataType::S32); - } - else - { - throw std::runtime_error("Unsupported type."); - } - LUCI_INTERPRETER_CHECK(output()->element_type() == input()->element_type()); - - const Shape &input_shape = input()->shape(); - const Shape &filter_shape = filter()->shape(); - LUCI_INTERPRETER_CHECK(input_shape.num_dims() == 4 && filter_shape.num_dims() == 4); - - const int32_t batches = input_shape.dim(0); - const int32_t input_height = input_shape.dim(1); - const int32_t input_width = input_shape.dim(2); - // Filter format: [1, H, W, O]. - LUCI_INTERPRETER_CHECK(filter_shape.dim(0) == 1); - const int32_t filter_height = filter_shape.dim(1); - const int32_t filter_width = filter_shape.dim(2); - const int32_t channels_out = filter_shape.dim(3); - - LUCI_INTERPRETER_CHECK(bias() == nullptr || (bias()->shape().num_dims() == 1 && - bias()->shape().dim(0) == channels_out)); - - const int32_t output_height = - computeOutputSize(_params.padding, input_height, filter_height, _params.stride_height, - _params.dilation_height_factor); - const int32_t output_width = - computeOutputSize(_params.padding, input_width, filter_width, _params.stride_width, - _params.dilation_width_factor); - - _padding_height = computePadding(_params.stride_height, _params.dilation_height_factor, - input_height, filter_height, output_height); - _padding_width = computePadding(_params.stride_width, _params.dilation_width_factor, input_width, - filter_width, output_width); - - output()->resize({batches, output_height, output_width, channels_out}); -} - -void DepthwiseConv2D::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - if (filter()->element_type() == DataType::FLOAT32) - { - evalFloat(); - break; - } - throw std::runtime_error("Unsupported type."); - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void DepthwiseConv2D::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::DepthwiseParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.dilation_height_factor = _params.dilation_height_factor; - params.dilation_width_factor = _params.dilation_width_factor; - params.depth_multiplier = _params.depth_multiplier; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - - tflite::reference_ops::DepthwiseConv( - params, getTensorShape(input()), getTensorData<float>(input()), getTensorShape(filter()), - getTensorData<float>(filter()), getTensorShape(bias()), getTensorData<float>(bias()), - getTensorShape(output()), getTensorData<float>(output())); -} - -void DepthwiseConv2D::evalQuantized() const -{ - const auto input_scale = static_cast<double>(input()->scale()); - const auto filter_scale = static_cast<double>(filter()->scale()); - const auto output_scale = static_cast<double>(output()->scale()); - - const double real_multiplier = input_scale * filter_scale / output_scale; - int32_t output_multiplier{}; - int output_shift{}; - quantizeMultiplier(real_multiplier, &output_multiplier, &output_shift); - - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::DepthwiseParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.dilation_height_factor = _params.dilation_height_factor; - params.dilation_width_factor = _params.dilation_width_factor; - params.depth_multiplier = _params.depth_multiplier; - // The kernel expects input and filter zero points to be negated. - params.input_offset = -input()->zero_point(); // Note the '-'. - params.weights_offset = -filter()->zero_point(); // Note the '-'. - params.output_offset = output()->zero_point(); - params.output_multiplier = output_multiplier; - params.output_shift = output_shift; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - tflite::reference_ops::DepthwiseConv( - params, getTensorShape(input()), getTensorData<uint8_t>(input()), getTensorShape(filter()), - getTensorData<uint8_t>(filter()), getTensorShape(bias()), getTensorData<int32_t>(bias()), - getTensorShape(output()), getTensorData<uint8_t>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.h b/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.h deleted file mode 100644 index 62f4bff0e..000000000 --- a/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_DEPTHWISECONV2D_H -#define LUCI_INTERPRETER_KERNELS_DEPTHWISECONV2D_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class DepthwiseConv2D : public KernelWithParams<DepthwiseConv2DParams> -{ -public: - DepthwiseConv2D(const Tensor *input, const Tensor *filter, const Tensor *bias, Tensor *output, - const DepthwiseConv2DParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *filter() const { return _inputs[1]; } - const Tensor *bias() const { return _inputs[2]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _padding_height{}; - int32_t _padding_width{}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_DEPTHWISECONV2D_H diff --git a/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.test.cpp b/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.test.cpp deleted file mode 100644 index a5128289f..000000000 --- a/compiler/luci-interpreter/src/kernels/DepthwiseConv2D.test.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/DepthwiseConv2D.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(DepthwiseConv2DTest, Float) -{ - Shape input_shape{1, 4, 2, 2}; - Shape filter_shape{1, 2, 2, 4}; - Shape bias_shape{4}; - std::vector<float> input_data{ - 1, 2, 7, 8, // - 3, 4, 9, 10, // - 5, 6, 11, 12, // - 13, 14, 15, 16, // - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // - -9, 10, -11, 12, // - 5, 6, 7, 8, // - 13, -14, 15, -16, // - }; - std::vector<float> bias_data{1, 2, 3, 4}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DepthwiseConv2DParams params{}; - params.padding = Padding::VALID; - params.depth_multiplier = 2; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 71, 0, 99, 0, // - 167, 0, 227, 28, // - }; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 1, 4})); -} - -TEST(DepthwiseConv2DTest, Uint8) -{ - std::vector<float> input_data{ - 1, 2, 7, 8, // column 1 - 3, 4, 9, 10, // column 2 - 5, 6, 11, 12, // column 3 - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // - -9, 10, -11, 12, // - 5, 6, 7, 8, // - 13, -14, 15, -16, // - }; - std::vector<float> bias_data{1, 2, 3, 4}; - - std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(-63.5, 64); - std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(-127, 128); - - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 3, 2, 2}, input_quant_param.first, - input_quant_param.second, input_data); - Tensor filter_tensor = makeInputTensor<DataType::U8>({1, 2, 2, 4}, input_quant_param.first, - input_quant_param.second, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::S32>( - {4}, input_quant_param.first * input_quant_param.first, 0, bias_data); - Tensor output_tensor = - makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second); - - DepthwiseConv2DParams params{}; - params.padding = Padding::VALID; - params.depth_multiplier = 2; - params.stride_height = 1; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::NONE; - - DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 71, -34, 99, -20, // - 91, -26, 127, -4, // - }; - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 1, 4})); -} - -TEST(DepthwiseConv2DTest, InvalidBiasType_NEG) -{ - Shape input_shape{1, 4, 2, 2}; - Shape filter_shape{1, 2, 2, 4}; - Shape bias_shape{4}; - std::vector<float> input_data{ - 1, 2, 7, 8, // - 3, 4, 9, 10, // - 5, 6, 11, 12, // - 13, 14, 15, 16, // - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // - -9, 10, -11, 12, // - 5, 6, 7, 8, // - 13, -14, 15, -16, // - }; - std::vector<int32_t> bias_data{1, 2, 3, 4}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::S32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DepthwiseConv2DParams params{}; - params.padding = Padding::VALID; - params.depth_multiplier = 2; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(DepthwiseConv2DTest, InOutTypeMismatch_NEG) -{ - Shape input_shape{1, 4, 2, 2}; - Shape filter_shape{1, 2, 2, 4}; - Shape bias_shape{4}; - std::vector<float> input_data{ - 1, 2, 7, 8, // - 3, 4, 9, 10, // - 5, 6, 11, 12, // - 13, 14, 15, 16, // - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // - -9, 10, -11, 12, // - 5, 6, 7, 8, // - 13, -14, 15, -16, // - }; - std::vector<float> bias_data{1, 2, 3, 4}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - DepthwiseConv2DParams params{}; - params.padding = Padding::VALID; - params.depth_multiplier = 2; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(DepthwiseConv2DTest, InvalidInputShape_NEG) -{ - Shape input_shape{4, 2, 2}; - Shape filter_shape{2, 2, 4}; - Shape bias_shape{4}; - std::vector<float> input_data{ - 1, 2, 7, 8, // - 3, 4, 9, 10, // - 5, 6, 11, 12, // - 13, 14, 15, 16, // - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // - -9, 10, -11, 12, // - 5, 6, 7, 8, // - 13, -14, 15, -16, // - }; - std::vector<float> bias_data{1, 2, 3, 4}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DepthwiseConv2DParams params{}; - params.padding = Padding::VALID; - params.depth_multiplier = 2; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(DepthwiseConv2DTest, InvalidFilterShape_NEG) -{ - Shape input_shape{1, 4, 2, 2}; - Shape filter_shape{2, 1, 2, 4}; - Shape bias_shape{4}; - std::vector<float> input_data{ - 1, 2, 7, 8, // - 3, 4, 9, 10, // - 5, 6, 11, 12, // - 13, 14, 15, 16, // - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // - -9, 10, -11, 12, // - 5, 6, 7, 8, // - 13, -14, 15, -16, // - }; - std::vector<float> bias_data{1, 2, 3, 4}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DepthwiseConv2DParams params{}; - params.padding = Padding::VALID; - params.depth_multiplier = 2; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(DepthwiseConv2DTest, InvalidBiasDim_NEG) -{ - Shape input_shape{1, 4, 2, 2}; - Shape filter_shape{1, 2, 4, 2}; - Shape bias_shape{4}; - std::vector<float> input_data{ - 1, 2, 7, 8, // - 3, 4, 9, 10, // - 5, 6, 11, 12, // - 13, 14, 15, 16, // - }; - std::vector<float> filter_data{ - 1, 2, 3, 4, // - -9, 10, -11, 12, // - 5, 6, 7, 8, // - 13, -14, 15, -16, // - }; - std::vector<float> bias_data{1, 2, 3, 4}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DepthwiseConv2DParams params{}; - params.padding = Padding::VALID; - params.depth_multiplier = 2; - params.stride_height = 2; - params.stride_width = 1; - params.dilation_height_factor = 1; - params.dilation_width_factor = 1; - params.activation = Activation::RELU; - - DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Div.cpp b/compiler/luci-interpreter/src/kernels/Div.cpp deleted file mode 100644 index e75876b3a..000000000 --- a/compiler/luci-interpreter/src/kernels/Div.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Div.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -Div::Div(const Tensor *input1, const Tensor *input2, Tensor *output, const DivParams ¶ms) - : KernelWithParams<DivParams>({input1, input2}, {output}, params) -{ -} - -void Div::configure() -{ - LUCI_INTERPRETER_CHECK(input1()->element_type() == input2()->element_type()); - LUCI_INTERPRETER_CHECK(input1()->element_type() == output()->element_type()); - - output()->resize(calculateShapeForBroadcast(input1()->shape(), input2()->shape())); -} - -void Div::execute() const -{ - switch (input1()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Div::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::ArithmeticParams params{}; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - const bool need_broadcast = tflite::reference_ops::ProcessBroadcastShapes( - getTensorShape(input1()), getTensorShape(input2()), ¶ms); - - if (need_broadcast) - { - tflite::reference_ops::BroadcastDivSlow( - params, getTensorShape(input1()), getTensorData<float>(input1()), getTensorShape(input2()), - getTensorData<float>(input2()), getTensorShape(output()), getTensorData<float>(output())); - } - else - { - tflite::reference_ops::Div(params, getTensorShape(input1()), getTensorData<float>(input1()), - getTensorShape(input2()), getTensorData<float>(input2()), - getTensorShape(output()), getTensorData<float>(output())); - } -} - -void Div::evalQuantized() const -{ - const auto input1_scale = static_cast<double>(input1()->scale()); - const auto input2_scale = static_cast<double>(input2()->scale()); - const auto output_scale = static_cast<double>(output()->scale()); - - const double real_output_multiplier = input1_scale / (input2_scale * output_scale); - - int32_t output_multiplier{}; - int output_shift{}; - - quantizeMultiplier(real_output_multiplier, &output_multiplier, &output_shift); - - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::ArithmeticParams params{}; - - params.input1_offset = -input1()->zero_point(); // Note the '-'. - params.input2_offset = -input2()->zero_point(); // Note the '-'. - params.output_offset = output()->zero_point(); - params.output_multiplier = output_multiplier; - params.output_shift = output_shift; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - const bool need_broadcast = tflite::reference_ops::ProcessBroadcastShapes( - getTensorShape(input1()), getTensorShape(input2()), ¶ms); - - if (need_broadcast) - { - tflite::reference_ops::BroadcastDivSlow( - params, getTensorShape(input1()), getTensorData<uint8_t>(input1()), - getTensorShape(input2()), getTensorData<uint8_t>(input2()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - } - else - { - tflite::reference_ops::Div(params, getTensorShape(input1()), getTensorData<uint8_t>(input1()), - getTensorShape(input2()), getTensorData<uint8_t>(input2()), - getTensorShape(output()), getTensorData<uint8_t>(output())); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Div.h b/compiler/luci-interpreter/src/kernels/Div.h deleted file mode 100644 index 6040cdd02..000000000 --- a/compiler/luci-interpreter/src/kernels/Div.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_DIV_H -#define LUCI_INTERPRETER_KERNELS_DIV_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Div : public KernelWithParams<DivParams> -{ -public: - Div(const Tensor *input1, const Tensor *input2, Tensor *output, const DivParams ¶ms); - - const Tensor *input1() const { return _inputs[0]; } - const Tensor *input2() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_DIV_H diff --git a/compiler/luci-interpreter/src/kernels/Div.test.cpp b/compiler/luci-interpreter/src/kernels/Div.test.cpp deleted file mode 100644 index 77eb2e9c1..000000000 --- a/compiler/luci-interpreter/src/kernels/Div.test.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Div.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -float GetTolerance(float min, float max) -{ - const float kQuantizedStep = (max - min) / 255.0f; - const float kQuantizedTolerance = 2.0f * kQuantizedStep + kQuantizedStep * kQuantizedStep; - return kQuantizedTolerance; -} - -TEST(DivTest, Float) -{ - Shape base_shape = {2, 3, 1, 1}; - - std::vector<int32_t> output_shape = {2, 3, 1, 1}; - - std::vector<float> input1_data{0.3f, 2.3f, 0.9f, 0.5f, 0.8f, 1.1f}; - std::vector<float> input2_data{0.2f, 1.6f, 0.5f, 0.4f, 1.6f, 0.4f}; - std::vector<float> test_outputs{1.5f, 1.4375f, 1.8f, 1.25f, 0.5f, 2.75f}; - - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input2_data); - - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DivParams params{}; - params.activation = Activation::RELU; - - Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs, 0.0001f)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -TEST(DivTest, FloatBroadcast) -{ - Shape input1_shape = {1, 3}; - Shape input2_shape = {3, 1}; - - std::vector<float> input1_data{-0.3f, 2.3f, 0.9f}; - std::vector<float> input2_data{0.2f, 1.6f, 0.5f}; - std::vector<float> test_outputs{0.f, 11.5f, 4.5f, 0.f, 1.4375f, 0.5625f, 0.f, 4.6f, 1.8f}; - - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(input1_shape, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(input2_shape, input2_data); - - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DivParams params{}; - params.activation = Activation::RELU; - - Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs, 0.0001f)); -} - -TEST(DivTest, Uint8) -{ - Shape base_shape = {1, 2, 2, 1}; - - std::vector<int32_t> output_shape = {1, 2, 2, 1}; - - std::vector<float> input1_data = {-0.8f, -0.2f, 0.3f, 0.7f}; - std::vector<float> input2_data = {-0.8f, 0.4f, 0.8f, 1.0f}; - std::vector<float> test_outputs{1.0f, 0.f, 0.375f, 0.7f}; - - const float kQuantizedTolerance = GetTolerance(-1.0, 1.0); - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-1.f, 1.f); - - Tensor input1_tensor = - makeInputTensor<DataType::U8>(base_shape, quant_param.first, quant_param.second, input1_data); - Tensor input2_tensor = - makeInputTensor<DataType::U8>(base_shape, quant_param.first, quant_param.second, input2_data); - - Tensor output_tensor = - makeOutputTensor(getElementType<uint8_t>(), quant_param.first, quant_param.second); - - DivParams params{}; - params.activation = Activation::RELU; - - Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(test_outputs, kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -TEST(DivTest, Input_Output_Type_NEG) -{ - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {2}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - DivParams params{}; - params.activation = Activation::RELU; - - Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(DivTest, Invalid_Input_Type_NEG) -{ - Tensor input1_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor input2_tensor = makeInputTensor<DataType::S64>({1}, {2}); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - DivParams params{}; - params.activation = Activation::RELU; - - Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Elu.cpp b/compiler/luci-interpreter/src/kernels/Elu.cpp deleted file mode 100644 index 456396055..000000000 --- a/compiler/luci-interpreter/src/kernels/Elu.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Elu.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Elu::Elu(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Elu::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - output()->resize(input()->shape()); -} - -void Elu::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - tflite::optimized_ops::Elu(getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Elu.h b/compiler/luci-interpreter/src/kernels/Elu.h deleted file mode 100644 index c844ab57f..000000000 --- a/compiler/luci-interpreter/src/kernels/Elu.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_ELU_H -#define LUCI_INTERPRETER_KERNELS_ELU_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Elu : public Kernel -{ -public: - Elu(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_ELU_H diff --git a/compiler/luci-interpreter/src/kernels/Elu.test.cpp b/compiler/luci-interpreter/src/kernels/Elu.test.cpp deleted file mode 100644 index 0235d6552..000000000 --- a/compiler/luci-interpreter/src/kernels/Elu.test.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Elu.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> output_data) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Elu kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - (void)output_shape; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(output_data)); -} - -TEST(EluTest, SimpleElu) -{ - Check( - /*input_shape=*/{1, 2, 4, 1}, /*output_shape=*/{1, 2, 4, 1}, - /*input_data=*/ - { - 0, -6, 2, -4, // - 3, -2, 10, -0.1, // - }, - /*output_data=*/ - { - 0.0, -0.997521, 2.0, -0.981684, // - 3.0, -0.864665, 10.0, -0.0951626, // - }); -} - -TEST(EluTest, InOutTypeMismatch_NEG) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - 0, -6, 2, -4, // - 3, -2, 10, -0.1, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - Elu kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Equal.cpp b/compiler/luci-interpreter/src/kernels/Equal.cpp deleted file mode 100644 index f58de1250..000000000 --- a/compiler/luci-interpreter/src/kernels/Equal.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Equal.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/comparisons.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Equal::Equal(const Tensor *x, const Tensor *y, Tensor *output) : Kernel({x, y}, {output}) {} - -void Equal::configure() -{ - LUCI_INTERPRETER_CHECK(x()->element_type() == y()->element_type()); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::BOOL); - - if (x()->element_type() == DataType::U8) - { - quantizeMultiplierSmallerThanOneExp(x()->scale(), &_x_multiplier, &_x_shift); - quantizeMultiplierSmallerThanOneExp(y()->scale(), &_y_multiplier, &_y_shift); - } - output()->resize(calculateShapeForBroadcast(x()->shape(), y()->shape())); -} - -void Equal::execute() const -{ - switch (x()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Equal::evalFloat() const -{ - const auto x_data = getTensorData<float>(x()); - const auto y_data = getTensorData<float>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowEqual(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::Equal(op_params, getTensorShape(x()), x_data, getTensorShape(y()), - y_data, getTensorShape(output()), output_data); - } -} - -void Equal::evalQuantized() const -{ - const auto x_data = getTensorData<uint8_t>(x()); - const auto y_data = getTensorData<uint8_t>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.left_shift = 8; - op_params.input1_offset = -x()->zero_point(); // Note the '-' - op_params.input1_shift = _x_shift; - op_params.input1_multiplier = _x_multiplier; - op_params.input2_offset = -y()->zero_point(); // Note the '-' - op_params.input2_shift = _y_shift; - op_params.input2_multiplier = _y_multiplier; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowEqualWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::EqualWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, getTensorShape(output()), - output_data); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Equal.h b/compiler/luci-interpreter/src/kernels/Equal.h deleted file mode 100644 index 69b3be774..000000000 --- a/compiler/luci-interpreter/src/kernels/Equal.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_EQUAL_H -#define LUCI_INTERPRETER_KERNELS_EQUAL_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Equal : public Kernel -{ -public: - Equal(const Tensor *x, const Tensor *y, Tensor *output); - - const Tensor *x() const { return _inputs[0]; } - const Tensor *y() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _x_multiplier = 0; - int32_t _x_shift = 0; - int32_t _y_multiplier = 0; - int32_t _y_shift = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_EQUAL_H diff --git a/compiler/luci-interpreter/src/kernels/Equal.test.cpp b/compiler/luci-interpreter/src/kernels/Equal.test.cpp deleted file mode 100644 index fb0de8bbf..000000000 --- a/compiler/luci-interpreter/src/kernels/Equal.test.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Equal.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(EqualTest, FloatSimple) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - -1, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - false, true, false, // Row 1 - false, true, false, // Row 2 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Equal kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 3})); -} - -TEST(EqualTest, FloatBroardcast) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - -1, 0, 1, // Row 3 - 0.9, 0.7, 0.5, // Row 4 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - }; - - std::vector<bool> ref_output_data{ - false, true, false, // Row 1 - false, false, false, // Row 2 - false, false, false, // Row 3 - true, true, true, // Row 4 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({4, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Equal kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({4, 3})); -} - -// Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. -const float F_MIN = -128.0 / 128.0; -const float F_MAX = 127.0 / 128.0; - -TEST(EqualTest, Uint8Quantized) -{ - std::vector<float> x_data{ - 0.5, 0.5, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.5, 0.55, 0.5, // Row 1 - -1, 0, 0.05, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - false, true, false, false, // Row 1 - false, true, true, false, // Row 2 - }; - - std::pair<float, int32_t> x_quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, x_quant_param.first, - x_quant_param.second, x_data); - - std::pair<float, int32_t> y_quant_param = quantizationParams<uint8_t>(F_MIN * 2, F_MAX * 2); - Tensor y_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, y_quant_param.first, - y_quant_param.second, y_data); - - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Equal kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(EqualTest, Uint8QuantizedBroadcast) -{ - std::vector<float> x_data{ - 0.4, -0.8, 0.7, 0.3, // Row 1 - -0.5, 0.1, 0, 0.5, // Row 2 - 1, 0, 0.05, -1, // Row 3 - -1, 0.05, 0, 1, // Row 4 - }; - - std::vector<float> y_data{ - -1, 0.05, 0, 1, // Row 1 - }; - - std::vector<bool> ref_output_data{ - false, false, false, false, // Row 1 - false, false, true, false, // Row 2 - false, false, false, false, // Row 3 - true, true, true, true, // Row 4 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 4, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 1, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Equal kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 4, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(EqualTest, Input_Type_Mismatch_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::U8>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Equal kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(EqualTest, Input_Output_Type_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Equal kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Floor.cpp b/compiler/luci-interpreter/src/kernels/Floor.cpp deleted file mode 100644 index e3c4246cc..000000000 --- a/compiler/luci-interpreter/src/kernels/Floor.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Floor.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/floor.h> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Floor::Floor(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Floor::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - output()->resize(input()->shape()); -} - -void Floor::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Floor::evalFloat() const -{ - tflite::reference_ops::Floor(getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Floor.h b/compiler/luci-interpreter/src/kernels/Floor.h deleted file mode 100644 index ca3ad5997..000000000 --- a/compiler/luci-interpreter/src/kernels/Floor.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_FLOOR_H -#define LUCI_INTERPRETER_KERNELS_FLOOR_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Floor : public Kernel -{ -public: - Floor(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_FLOOR_H diff --git a/compiler/luci-interpreter/src/kernels/Floor.test.cpp b/compiler/luci-interpreter/src/kernels/Floor.test.cpp deleted file mode 100644 index 3e1ab6f3a..000000000 --- a/compiler/luci-interpreter/src/kernels/Floor.test.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Floor.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(FloorTest, SimpleFloat) -{ - std::initializer_list<int32_t> input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - 0.2, 8.6, 2.4, 4.3, // Row 1 - 3, 7.1, 10.5, -0.9, // Row 2 - }; - - std::initializer_list<int32_t> ref_output_shape{1, 2, 4, 1}; - std::vector<float> ref_output_data{ - 0, 8, 2, 4, // Row 1 - 3, 7, 10, -1, // Row 2 - }; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Floor kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(FloorTest, Input_Output_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::S32); - - Floor kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/FloorDiv.cpp b/compiler/luci-interpreter/src/kernels/FloorDiv.cpp deleted file mode 100644 index b6f36cea3..000000000 --- a/compiler/luci-interpreter/src/kernels/FloorDiv.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/FloorDiv.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/binary_function.h> -#include <cmath> - -namespace luci_interpreter -{ - -namespace kernels -{ - -FloorDiv::FloorDiv(const Tensor *input, const Tensor *alpha, Tensor *output) - : Kernel({input, alpha}, {output}) -{ -} - -void FloorDiv::configure() -{ - LUCI_INTERPRETER_CHECK(x()->element_type() == output()->element_type()); - LUCI_INTERPRETER_CHECK(y()->element_type() == output()->element_type()); - - output()->resize(calculateShapeForBroadcast(x()->shape(), y()->shape())); -} - -void FloorDiv::execute() const -{ - switch (x()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void FloorDiv::evalFloat() const -{ - auto FloorDivFunc = [](float x, float y) -> float { - return std::floor(static_cast<double>(x) / static_cast<double>(y)); - }; - - const auto x_data = getTensorData<float>(x()); - const auto y_data = getTensorData<float>(y()); - - // Check the denominator - for (int i = 0; i < getTensorShape(y()).FlatSize(); ++i) - { - LUCI_INTERPRETER_CHECK(y_data[i] != 0); - } - - if (x()->shape() != y()->shape()) - { - tflite::reference_ops::BroadcastBinaryFunction4DSlow<float, float, float>( - getTensorShape(x()), x_data, getTensorShape(y()), y_data, getTensorShape(output()), - getTensorData<float>(output()), FloorDivFunc); - } - else - { - tflite::reference_ops::BinaryFunction<float, float, float>( - getTensorShape(x()), x_data, getTensorShape(y()), y_data, getTensorShape(output()), - getTensorData<float>(output()), FloorDivFunc); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/FloorDiv.h b/compiler/luci-interpreter/src/kernels/FloorDiv.h deleted file mode 100644 index e9c47d81a..000000000 --- a/compiler/luci-interpreter/src/kernels/FloorDiv.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_FLOOR_DIV_H -#define LUCI_INTERPRETER_KERNELS_FLOOR_DIV_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class FloorDiv : public Kernel -{ -public: - FloorDiv(const Tensor *x, const Tensor *y, Tensor *output); - - const Tensor *x() const { return _inputs[0]; } - const Tensor *y() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_FLOOR_DIV_H diff --git a/compiler/luci-interpreter/src/kernels/FloorDiv.test.cpp b/compiler/luci-interpreter/src/kernels/FloorDiv.test.cpp deleted file mode 100644 index a5bc700f7..000000000 --- a/compiler/luci-interpreter/src/kernels/FloorDiv.test.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/FloorDiv.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(FloorDivTest, FloatSimple) -{ - Shape x_shape{2, 3}; - std::vector<float> x_data{ - 0.5, 2.4, 3.1, // Row 1 - 1.9, -1.9, -2.8, // Row 2 - }; - - Shape y_shape = x_shape; - std::vector<float> y_data{ - 2.0, 0.5, 3.0, // Row 1 - 1.0, -1.0, -2.0, // Row 2 - }; - - std::vector<int32_t> ref_output_shape{2, 3}; - std::vector<float> ref_output_data{ - 0, 4, 1, // Row 1 - 1, 1, 1, // Row 2 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>(x_shape, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>(y_shape, y_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - FloorDiv kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(FloorDivTest, FloatBroadcast) -{ - Shape x_shape{1, 3}; - std::vector<float> x_data{ - 0.5, 2.4, -3.1, // Row 1 - }; - - Shape y_shape{3, 3}; - std::vector<float> y_data{ - 1.0, 1.0, 1.0, // Row 1 - 2.0, -0.5, -2.0, // Row 2 - 0.3, 0.7, 0.9, // Row 3 - }; - - std::vector<int32_t> ref_output_shape{3, 3}; - std::vector<float> ref_output_data{ - 0, 2, -4, // Row 1 - 0, -5, 1, // Row 2 - 1, 3, -4, // Row 3 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>(x_shape, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>(y_shape, y_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - FloorDiv kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(FloorDivTest, DivByZero_NEG) -{ - Shape shape{3}; - std::vector<float> x_data{1, 0, -1}; - std::vector<float> y_data{0, 0, 0}; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>(shape, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>(shape, y_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - FloorDiv kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - - EXPECT_ANY_THROW(kernel.execute()); -} - -TEST(FloorDivTest, Input_Output_Type_Mismatch_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - FloorDiv kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(FloorDivTest, Input_Type_Mismatch_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1}); - Tensor y_tensor = makeInputTensor<DataType::U8>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - FloorDiv kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/FullyConnected.cpp b/compiler/luci-interpreter/src/kernels/FullyConnected.cpp deleted file mode 100644 index 7fa76d5e7..000000000 --- a/compiler/luci-interpreter/src/kernels/FullyConnected.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/FullyConnected.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/fully_connected.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -FullyConnected::FullyConnected(const Tensor *input, const Tensor *weights, const Tensor *bias, - Tensor *output, const FullyConnectedParams ¶ms) - : KernelWithParams<FullyConnectedParams>({input, weights, bias}, {output}, params) -{ -} - -void FullyConnected::configure() -{ - if (weights()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(input()->element_type() == DataType::U8); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::U8); - LUCI_INTERPRETER_CHECK(!bias() || bias()->element_type() == DataType::S32) - } - else if (weights()->element_type() == DataType::FLOAT32) - { - LUCI_INTERPRETER_CHECK(input()->element_type() == DataType::FLOAT32); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::FLOAT32); - LUCI_INTERPRETER_CHECK(!bias() || bias()->element_type() == DataType::FLOAT32) - } - else - { - throw std::runtime_error("Unsupported type."); - } - - const Shape &input_shape = input()->shape(); - const Shape &weights_shape = weights()->shape(); - - LUCI_INTERPRETER_CHECK(weights_shape.num_dims() == 2); - LUCI_INTERPRETER_CHECK(bias() == nullptr || - bias()->shape().num_elements() == weights_shape.dim(0)); - - LUCI_INTERPRETER_CHECK(input_shape.num_elements() % weights_shape.dim(1) == 0); - const int32_t batch_size = input_shape.num_elements() / weights_shape.dim(1); - const int32_t num_units = weights_shape.dim(0); - - if (bias()) - LUCI_INTERPRETER_CHECK(bias()->shape().num_elements() == weights()->shape().dim(0)); - - output()->resize({batch_size, num_units}); -} - -void FullyConnected::execute() const -{ - switch (input()->element_type()) - { - case DataType::U8: - evalQuantized(); - break; - case DataType::FLOAT32: - evalFloat(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void FullyConnected::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::FullyConnectedParams params{}; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - params.weights_format = tflite::FullyConnectedWeightsFormat::kDefault; - - tflite::reference_ops::FullyConnected( - params, getTensorShape(input()), getTensorData<float>(input()), getTensorShape(weights()), - getTensorData<float>(weights()), getTensorShape(bias()), getTensorData<float>(bias()), - getTensorShape(output()), getTensorData<float>(output())); -} - -void FullyConnected::evalQuantized() const -{ - double real_multiplier = 0.0; - int output_shift; - int32_t output_activation_min; - int32_t output_activation_max; - int32_t output_multiplier; - real_multiplier = - getQuantizedConvolutionMultipler(input()->scale(), weights()->scale(), output()->scale()); - quantizeMultiplier(real_multiplier, &output_multiplier, &output_shift); - calculateActivationRangeQuantized(params().activation, output(), &output_activation_min, - &output_activation_max); - - int32_t input_offset = -input()->zero_point(); - int32_t filter_offset = -weights()->zero_point(); - int32_t output_offset = output()->zero_point(); - - tflite::FullyConnectedParams op_params{}; - op_params.input_offset = input_offset; - op_params.weights_offset = filter_offset; - op_params.output_offset = output_offset; - op_params.output_multiplier = output_multiplier; - op_params.output_shift = output_shift; - op_params.quantized_activation_min = output_activation_min; - op_params.quantized_activation_max = output_activation_max; - op_params.lhs_cacheable = false; - op_params.rhs_cacheable = false; - tflite::reference_ops::FullyConnected( - op_params, getTensorShape(input()), getTensorData<uint8_t>(input()), - getTensorShape(weights()), getTensorData<uint8_t>(weights()), getTensorShape(bias()), - getTensorData<int32_t>(bias()), getTensorShape(output()), getTensorData<uint8_t>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/FullyConnected.h b/compiler/luci-interpreter/src/kernels/FullyConnected.h deleted file mode 100644 index 204f11ebb..000000000 --- a/compiler/luci-interpreter/src/kernels/FullyConnected.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_FULLYCONNECTED_H -#define LUCI_INTERPRETER_KERNELS_FULLYCONNECTED_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class FullyConnected : public KernelWithParams<FullyConnectedParams> -{ -public: - FullyConnected(const Tensor *input, const Tensor *weights, const Tensor *bias, Tensor *output, - const FullyConnectedParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *weights() const { return _inputs[1]; } - const Tensor *bias() const { return _inputs[2]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_FULLYCONNECTED_H diff --git a/compiler/luci-interpreter/src/kernels/FullyConnected.test.cpp b/compiler/luci-interpreter/src/kernels/FullyConnected.test.cpp deleted file mode 100644 index d194ce1a0..000000000 --- a/compiler/luci-interpreter/src/kernels/FullyConnected.test.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/FullyConnected.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> weights_shape, - std::initializer_list<int32_t> bias_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> weights_data, - std::initializer_list<float> bias_data, std::initializer_list<float> output_data) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor weights_tensor = makeInputTensor<DataType::FLOAT32>(weights_shape, weights_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - FullyConnectedParams params{}; - params.activation = Activation::RELU; - - FullyConnected kernel(&input_tensor, &weights_tensor, &bias_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(extractTensorData<T>(output_tensor), FloatArrayNear(output_data)); -} - -template <> -void Check<uint8_t>( - std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> weights_shape, - std::initializer_list<int32_t> bias_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> weights_data, - std::initializer_list<float> bias_data, std::initializer_list<float> output_data) -{ - const float quantized_tolerance = getTolerance(-127, 128, 255); - std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(-63.5, 64); - std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(-127, 128); - Tensor input_tensor = makeInputTensor<DataType::U8>(input_shape, input_quant_param.first, - input_quant_param.second, input_data); - Tensor weights_tensor = makeInputTensor<DataType::U8>(weights_shape, input_quant_param.first, - input_quant_param.second, weights_data); - Tensor bias_tensor = makeInputTensor<DataType::S32>( - bias_shape, input_quant_param.first * input_quant_param.first, 0, bias_data); - Tensor output_tensor = - makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second); - - FullyConnectedParams params{}; - params.activation = Activation::RELU; - - FullyConnected kernel(&input_tensor, &weights_tensor, &bias_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data, quantized_tolerance)); -} - -template <typename T> class FullyConnectedTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(FullyConnectedTest, DataTypes); - -TYPED_TEST(FullyConnectedTest, Simple) -{ - Check<TypeParam>({3, 2, 2, 1}, {3, 6}, {3}, {2, 3}, - { - -3, -5, 5, 4, 9, -2, // batch = 0 - -3, -2, -4, 9, -8, 1, // batch = 1 - }, - { - -3, -7, 4, -4, -6, 4, // unit = 0 - 3, 5, 2, 3, -3, -8, // unit = 1 - -3, 7, 4, 9, 0, -5, // unit = 2 - }, - {-1, -5, -8}, { - 0, 0, 32, // batch = 0 - 22, 11, 47, // batch = 1 - }); -} - -TEST(FullyConnectedTest, InvalidBiasType_NEG) -{ - Shape input_shape{3, 2, 2, 1}; - std::vector<float> input_data{ - -3, -5, 5, 4, 9, -2, // batch = 0 - -3, -2, -4, 9, -8, 1, // batch = 1 - }; - Shape weights_shape{3, 6}; - std::vector<float> weights_data{ - -3, -7, 4, -4, -6, 4, // unit = 0 - 3, 5, 2, 3, -3, -8, // unit = 1 - -3, 7, 4, 9, 0, -5, // unit = 2 - }; - Shape bias_shape{3}; - std::vector<int32_t> bias_data{-1, -5, -8}; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor weights_tensor = makeInputTensor<DataType::FLOAT32>(weights_shape, weights_data); - Tensor bias_tensor = makeInputTensor<DataType::S32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - FullyConnectedParams params{}; - params.activation = Activation::RELU; - - FullyConnected kernel(&input_tensor, &weights_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(FullyConnectedTest, InvalidWeightShapeDim_NEG) -{ - Shape input_shape{3, 2, 2, 1}; - std::vector<float> input_data{ - -3, -5, 5, 4, 9, -2, // batch = 0 - -3, -2, -4, 9, -8, 1, // batch = 1 - }; - Shape weights_shape{1, 3, 6}; - std::vector<float> weights_data{ - -3, -7, 4, -4, -6, 4, // unit = 0 - 3, 5, 2, 3, -3, -8, // unit = 1 - -3, 7, 4, 9, 0, -5, // unit = 2 - }; - Shape bias_shape{3}; - std::vector<float> bias_data{-1, -5, -8}; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor weights_tensor = makeInputTensor<DataType::FLOAT32>(weights_shape, weights_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - FullyConnectedParams params{}; - params.activation = Activation::RELU; - - FullyConnected kernel(&input_tensor, &weights_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(FullyConnectedTest, BiasElementNumWeightDimMismatch_NEG) -{ - Shape input_shape{3, 2, 2, 1}; - std::vector<float> input_data{ - -3, -5, 5, 4, 9, -2, // batch = 0 - -3, -2, -4, 9, -8, 1, // batch = 1 - }; - Shape weights_shape{6, 3}; - std::vector<float> weights_data{ - -3, -7, 4, // unit = 0 - -4, -6, 4, // unit = 1 - 3, 5, 2, // unit = 2 - 3, -3, -8, // unit = 3 - -3, 7, 4, // unit = 4 - 9, 0, -5, // unit = 5 - }; - Shape bias_shape{3}; - std::vector<float> bias_data{-1, -5, -8}; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor weights_tensor = makeInputTensor<DataType::FLOAT32>(weights_shape, weights_data); - Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - FullyConnectedParams params{}; - params.activation = Activation::RELU; - - FullyConnected kernel(&input_tensor, &weights_tensor, &bias_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Greater.cpp b/compiler/luci-interpreter/src/kernels/Greater.cpp deleted file mode 100644 index f0dd2db36..000000000 --- a/compiler/luci-interpreter/src/kernels/Greater.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Greater.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/comparisons.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Greater::Greater(const Tensor *x, const Tensor *y, Tensor *output) : Kernel({x, y}, {output}) {} - -void Greater::configure() -{ - LUCI_INTERPRETER_CHECK(x()->element_type() == y()->element_type()); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::BOOL); - - if (x()->element_type() == DataType::U8) - { - quantizeMultiplierSmallerThanOneExp(x()->scale(), &_x_multiplier, &_x_shift); - quantizeMultiplierSmallerThanOneExp(y()->scale(), &_y_multiplier, &_y_shift); - } - output()->resize(calculateShapeForBroadcast(x()->shape(), y()->shape())); -} - -void Greater::execute() const -{ - switch (x()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Greater::evalFloat() const -{ - const auto x_data = getTensorData<float>(x()); - const auto y_data = getTensorData<float>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowGreater(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::Greater(op_params, getTensorShape(x()), x_data, getTensorShape(y()), - y_data, getTensorShape(output()), output_data); - } -} - -void Greater::evalQuantized() const -{ - const auto x_data = getTensorData<uint8_t>(x()); - const auto y_data = getTensorData<uint8_t>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.left_shift = 8; - op_params.input1_offset = -x()->zero_point(); // Note the '-' - op_params.input1_shift = _x_shift; - op_params.input1_multiplier = _x_multiplier; - op_params.input2_offset = -y()->zero_point(); // Note the '-' - op_params.input2_shift = _y_shift; - op_params.input2_multiplier = _y_multiplier; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowGreaterWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::GreaterWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, getTensorShape(output()), - output_data); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Greater.h b/compiler/luci-interpreter/src/kernels/Greater.h deleted file mode 100644 index a65d29f5c..000000000 --- a/compiler/luci-interpreter/src/kernels/Greater.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_GREATER_H -#define LUCI_INTERPRETER_KERNELS_GREATER_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Greater : public Kernel -{ -public: - Greater(const Tensor *x, const Tensor *y, Tensor *output); - - const Tensor *x() const { return _inputs[0]; } - const Tensor *y() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _x_multiplier = 0; - int32_t _x_shift = 0; - int32_t _y_multiplier = 0; - int32_t _y_shift = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_GREATER_H diff --git a/compiler/luci-interpreter/src/kernels/Greater.test.cpp b/compiler/luci-interpreter/src/kernels/Greater.test.cpp deleted file mode 100644 index 3122fa840..000000000 --- a/compiler/luci-interpreter/src/kernels/Greater.test.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Greater.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(GreaterTest, FloatSimple) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - -1, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - false, false, true, // Row 1 - true, false, false, // Row 2 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Greater kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 3})); -} - -TEST(GreaterTest, FloatBroardcast) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - -1, 0, 1, // Row 3 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - }; - - std::vector<bool> ref_output_data{ - false, false, true, // Row 1 - true, false, false, // Row 2 - false, false, true, // Row 3 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({3, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Greater kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({3, 3})); -} - -// Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. -const float F_MIN = -128.0 / 128.0; -const float F_MAX = 127.0 / 128.0; - -TEST(GreaterTest, Uint8Quantized) -{ - std::vector<float> x_data{ - 0.5, 0.6, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.6, 0.6, 0.5, // Row 1 - -1, 0.05, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - false, false, true, true, // Row 1 - true, false, true, false, // Row 2 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Greater kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(GreaterTest, Uint8QuantizedRescale) -{ - std::vector<float> x_data{ - 0.5, 0.6, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.6, 0.6, 0.5, // Row 1 - -1, 0.05, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - false, false, true, true, // Row 1 - true, false, true, false, // Row 2 - }; - - std::pair<float, int32_t> x_quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - std::pair<float, int32_t> y_quant_param = quantizationParams<uint8_t>(F_MIN * 2, F_MAX * 3); - - Tensor x_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, x_quant_param.first, - x_quant_param.second, x_data); - Tensor y_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, y_quant_param.first, - y_quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Greater kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(GreaterTest, Uint8QuantizedBroadcast) -{ - std::vector<float> x_data{ - 0.4, -0.8, 0.7, 0.3, // Row 1 - -0.5, 0.1, 0, 0.5, // Row 2 - 1, 0, 0.05, -1, // Row 3 - }; - - std::vector<float> y_data{ - -1, 0.05, 0, 1, // Row 1 - }; - - std::vector<bool> ref_output_data{ - true, false, true, false, // Row 1 - true, true, false, false, // Row 2 - true, false, true, false, // Row 3 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 3, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 1, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Greater kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 3, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(GreaterTest, Input_Type_Mismatch_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::U8>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Greater kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(GreaterTest, Input_Output_Type_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Greater kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/GreaterEqual.cpp b/compiler/luci-interpreter/src/kernels/GreaterEqual.cpp deleted file mode 100644 index 68135e27c..000000000 --- a/compiler/luci-interpreter/src/kernels/GreaterEqual.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/GreaterEqual.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/comparisons.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -GreaterEqual::GreaterEqual(const Tensor *x, const Tensor *y, Tensor *output) - : Kernel({x, y}, {output}) -{ -} - -void GreaterEqual::configure() -{ - LUCI_INTERPRETER_CHECK(x()->element_type() == y()->element_type()); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::BOOL); - - if (x()->element_type() == DataType::U8) - { - quantizeMultiplierSmallerThanOneExp(x()->scale(), &_x_multiplier, &_x_shift); - quantizeMultiplierSmallerThanOneExp(y()->scale(), &_y_multiplier, &_y_shift); - } - output()->resize(calculateShapeForBroadcast(x()->shape(), y()->shape())); -} - -void GreaterEqual::execute() const -{ - switch (x()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void GreaterEqual::evalFloat() const -{ - const auto x_data = getTensorData<float>(x()); - const auto y_data = getTensorData<float>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowGreaterEqual(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::GreaterEqual(op_params, getTensorShape(x()), x_data, getTensorShape(y()), - y_data, getTensorShape(output()), output_data); - } -} - -void GreaterEqual::evalQuantized() const -{ - const auto x_data = getTensorData<uint8_t>(x()); - const auto y_data = getTensorData<uint8_t>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.left_shift = 8; - op_params.input1_offset = -x()->zero_point(); // Note the '-' - op_params.input1_shift = _x_shift; - op_params.input1_multiplier = _x_multiplier; - op_params.input2_offset = -y()->zero_point(); // Note the '-' - op_params.input2_shift = _y_shift; - op_params.input2_multiplier = _y_multiplier; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowGreaterEqualWithScaling( - op_params, getTensorShape(x()), x_data, getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::GreaterEqualWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/GreaterEqual.h b/compiler/luci-interpreter/src/kernels/GreaterEqual.h deleted file mode 100644 index e948d698f..000000000 --- a/compiler/luci-interpreter/src/kernels/GreaterEqual.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_GREATER_EQUAL_H -#define LUCI_INTERPRETER_KERNELS_GREATER_EQUAL_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class GreaterEqual : public Kernel -{ -public: - GreaterEqual(const Tensor *x, const Tensor *y, Tensor *output); - - const Tensor *x() const { return _inputs[0]; } - const Tensor *y() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _x_multiplier = 0; - int32_t _x_shift = 0; - int32_t _y_multiplier = 0; - int32_t _y_shift = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_GREATER_EQUAL_H diff --git a/compiler/luci-interpreter/src/kernels/GreaterEqual.test.cpp b/compiler/luci-interpreter/src/kernels/GreaterEqual.test.cpp deleted file mode 100644 index 11e62644c..000000000 --- a/compiler/luci-interpreter/src/kernels/GreaterEqual.test.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/GreaterEqual.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(GreaterEqualTest, FloatSimple) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - -1, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - false, true, true, // Row 1 - true, true, false, // Row 2 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - GreaterEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 3})); -} - -TEST(GreaterEqualTest, FloatBroardcast) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - -1, 0, 1, // Row 3 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - }; - - std::vector<bool> ref_output_data{ - false, true, true, // Row 1 - true, false, false, // Row 2 - false, false, true, // Row 3 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({3, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - GreaterEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({3, 3})); -} - -// Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. -const float F_MIN = -128.0 / 128.0; -const float F_MAX = 127.0 / 128.0; - -TEST(GreaterEqualTest, Uint8Quantized) -{ - std::vector<float> x_data{ - 0.5, 0.6, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.6, 0.55, 0.5, // Row 1 - -1, 0.05, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - false, true, true, true, // Row 1 - true, false, true, false, // Row 2 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - GreaterEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(GreaterEqualTest, Uint8QuantizedRescale) -{ - std::vector<float> x_data{ - 0.5, 0.5, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.5, 0.6, 0.5, // Row 1 - -1, 0.05, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - false, true, true, true, // Row 1 - true, false, true, false, // Row 2 - }; - - std::pair<float, int32_t> x_quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - std::pair<float, int32_t> y_quant_param = quantizationParams<uint8_t>(F_MIN * 1.2, F_MAX * 1.5); - - Tensor x_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, x_quant_param.first, - x_quant_param.second, x_data); - Tensor y_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, y_quant_param.first, - y_quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - GreaterEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(GreaterEqualTest, Uint8QuantizedBroadcast) -{ - std::vector<float> x_data{ - 0.4, -0.8, 0.7, 0.3, // Row 1 - -0.5, 0.1, 0, 0.5, // Row 2 - 1, 0, 0.05, -1, // Row 3 - }; - - std::vector<float> y_data{ - -1, 0.05, 0, 1, // Row 1 - }; - - std::vector<bool> ref_output_data{ - true, false, true, false, // Row 1 - true, true, true, false, // Row 2 - true, false, true, false, // Row 3 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 3, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 1, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - GreaterEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 3, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(GreaterEqualTest, Input_Type_Mismatch_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::U8>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - GreaterEqual kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(GreaterEqualTest, Input_Output_Type_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - GreaterEqual kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/If.cpp b/compiler/luci-interpreter/src/kernels/If.cpp deleted file mode 100644 index ca982d591..000000000 --- a/compiler/luci-interpreter/src/kernels/If.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/If.h" -#include "kernels/Utils.h" - -#include <cstring> - -namespace luci_interpreter -{ -namespace kernels -{ - -static std::vector<const Tensor *> joinInputs(const Tensor *cond, - const std::vector<const Tensor *> &inputs) -{ - std::vector<const Tensor *> result{cond}; - result.insert(result.cend(), inputs.cbegin(), inputs.cend()); - return result; -} - -If::If(const Tensor *cond, const std::vector<const Tensor *> &inputs, std::vector<Tensor *> outputs, - RuntimeGraph *then_graph, RuntimeGraph *else_graph) - : Kernel(joinInputs(cond, inputs), std::move(outputs)), _then_graph(then_graph), - _else_graph(else_graph) -{ -} - -void If::configure() -{ - LUCI_INTERPRETER_CHECK(cond()->element_type() == DataType::BOOL); - LUCI_INTERPRETER_CHECK(cond()->shape().num_elements() == 1); - - for (RuntimeGraph *graph : {_then_graph, _else_graph}) - { - (void)graph; - LUCI_INTERPRETER_CHECK(graph->getInputTensors().size() == getInputTensors().size() - 1); - LUCI_INTERPRETER_CHECK(graph->getOutputTensors().size() == getOutputTensors().size()); - } -} - -void If::execute() const -{ - const bool cond_value = cond()->data<bool>()[0]; - - RuntimeGraph *active_graph = cond_value ? _then_graph : _else_graph; - const auto &graph_inputs = active_graph->getInputTensors(); - const auto &graph_outputs = active_graph->getOutputTensors(); - - // Copy kernel inputs to active graph inputs. - for (size_t i = 0; i < getInputTensors().size() - 1; ++i) - { - LUCI_INTERPRETER_CHECK(graph_inputs[i]->element_type() == input(i)->element_type()); - graph_inputs[i]->resize(input(i)->shape()); - - const int32_t num_elements = input(i)->shape().num_elements(); - const std::size_t element_size = getDataTypeSize(input(i)->element_type()); - std::memcpy(graph_inputs[i]->data<void>(), input(i)->data<void>(), num_elements * element_size); - } - - active_graph->execute(); - - // Copy graph outputs to kernel outputs. - for (size_t i = 0; i < getOutputTensors().size(); ++i) - { - LUCI_INTERPRETER_CHECK(graph_outputs[i]->element_type() == output(i)->element_type()); - output(i)->resize(graph_outputs[i]->shape()); - - const int32_t num_elements = output(i)->shape().num_elements(); - const std::size_t element_size = getDataTypeSize(output(i)->element_type()); - std::memcpy(output(i)->data<void>(), graph_outputs[i]->data<void>(), - num_elements * element_size); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/If.h b/compiler/luci-interpreter/src/kernels/If.h deleted file mode 100644 index fa6ab371a..000000000 --- a/compiler/luci-interpreter/src/kernels/If.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_IF_H -#define LUCI_INTERPRETER_KERNELS_IF_H - -#include "core/Kernel.h" -#include "core/RuntimeGraph.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class If : public Kernel -{ -public: - If(const Tensor *cond, const std::vector<const Tensor *> &inputs, std::vector<Tensor *> outputs, - RuntimeGraph *then_graph, RuntimeGraph *else_graph); - - const Tensor *cond() const { return _inputs[0]; } - const Tensor *input(int index) const { return _inputs[1 + index]; } - Tensor *output(int index) const { return _outputs[index]; } - - void configure() override; - void execute() const override; - -private: - RuntimeGraph *const _then_graph; - RuntimeGraph *const _else_graph; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_IF_H diff --git a/compiler/luci-interpreter/src/kernels/If.test.cpp b/compiler/luci-interpreter/src/kernels/If.test.cpp deleted file mode 100644 index 6967407fb..000000000 --- a/compiler/luci-interpreter/src/kernels/If.test.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "core/RuntimeModule.h" -#include "kernels/Add.h" -#include "kernels/If.h" -#include "kernels/Mul.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -RuntimeGraph *buildAddSubgraph(RuntimeModule *module) -{ - RuntimeGraph *graph = module->addGraph(); - Tensor *input1 = graph->addTensor( - std::make_unique<Tensor>(DataType::FLOAT32, Shape{}, AffineQuantization{}, "")); - Tensor *input2 = graph->addTensor( - std::make_unique<Tensor>(DataType::FLOAT32, Shape{}, AffineQuantization{}, "")); - Tensor *output = graph->addTensor( - std::make_unique<Tensor>(DataType::FLOAT32, Shape{}, AffineQuantization{}, "")); - - graph->setInputTensors({input1, input2}); - graph->setOutputTensors({output}); - - AddParams params{}; - params.activation = Activation::NONE; - graph->addKernel(std::make_unique<Add>(input1, input2, output, params)); - - return graph; -} - -RuntimeGraph *buildMulSubgraph(RuntimeModule *module) -{ - RuntimeGraph *graph = module->addGraph(); - Tensor *input1 = graph->addTensor( - std::make_unique<Tensor>(DataType::FLOAT32, Shape{}, AffineQuantization{}, "")); - Tensor *input2 = graph->addTensor( - std::make_unique<Tensor>(DataType::FLOAT32, Shape{}, AffineQuantization{}, "")); - Tensor *output = graph->addTensor( - std::make_unique<Tensor>(DataType::FLOAT32, Shape{}, AffineQuantization{}, "")); - - graph->setInputTensors({input1, input2}); - graph->setOutputTensors({output}); - - MulParams params{}; - params.activation = Activation::NONE; - graph->addKernel(std::make_unique<Mul>(input1, input2, output, params)); - - return graph; -} - -TEST(IfTest, CondTrue) -{ - Tensor cond = makeInputTensor<DataType::BOOL>({1}, {true}); - Tensor input1 = makeInputTensor<DataType::FLOAT32>({2}, {5, 7}); - Tensor input2 = makeInputTensor<DataType::FLOAT32>({1, 2}, {1, 2}); - Tensor output = makeOutputTensor(DataType::FLOAT32); - - RuntimeModule module(nullptr); - RuntimeGraph *then_graph = buildAddSubgraph(&module); - RuntimeGraph *else_graph = buildMulSubgraph(&module); - - If kernel(&cond, {&input1, &input2}, {&output}, then_graph, else_graph); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output), FloatArrayNear({6, 9})); -} - -TEST(IfTest, CondFalse) -{ - Tensor cond = makeInputTensor<DataType::BOOL>({1}, {false}); - Tensor input1 = makeInputTensor<DataType::FLOAT32>({2}, {5, 7}); - Tensor input2 = makeInputTensor<DataType::FLOAT32>({1, 2}, {1, 2}); - Tensor output = makeOutputTensor(DataType::FLOAT32); - - RuntimeModule module(nullptr); - RuntimeGraph *then_graph = buildAddSubgraph(&module); - RuntimeGraph *else_graph = buildMulSubgraph(&module); - - If kernel(&cond, {&input1, &input2}, {&output}, then_graph, else_graph); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output), FloatArrayNear({5, 14})); -} - -TEST(IfTest, InvalidCondType_NEG) -{ - Tensor cond = makeInputTensor<DataType::FLOAT32>({1}, {1}); - Tensor input1 = makeInputTensor<DataType::FLOAT32>({2}, {5, 7}); - Tensor input2 = makeInputTensor<DataType::FLOAT32>({1, 2}, {1, 2}); - Tensor output = makeOutputTensor(DataType::FLOAT32); - - RuntimeModule module(nullptr); - RuntimeGraph *then_graph = buildAddSubgraph(&module); - RuntimeGraph *else_graph = buildMulSubgraph(&module); - - If kernel(&cond, {&input1, &input2}, {&output}, then_graph, else_graph); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(IfTest, InvalidCondElementNum_NEG) -{ - Tensor cond = makeInputTensor<DataType::BOOL>({2}, {false, true}); - Tensor input1 = makeInputTensor<DataType::FLOAT32>({2}, {5, 7}); - Tensor input2 = makeInputTensor<DataType::FLOAT32>({1, 2}, {1, 2}); - Tensor output = makeOutputTensor(DataType::FLOAT32); - - RuntimeModule module(nullptr); - RuntimeGraph *then_graph = buildAddSubgraph(&module); - RuntimeGraph *else_graph = buildMulSubgraph(&module); - - If kernel(&cond, {&input1, &input2}, {&output}, then_graph, else_graph); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/L2Normalize.cpp b/compiler/luci-interpreter/src/kernels/L2Normalize.cpp deleted file mode 100644 index 0bf133d9c..000000000 --- a/compiler/luci-interpreter/src/kernels/L2Normalize.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/L2Normalize.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -L2Normalize::L2Normalize(const Tensor *input, Tensor *output, const L2NormParams ¶ms) - : KernelWithParams<L2NormParams>({input}, {output}, params) -{ -} - -void L2Normalize::configure() -{ - LUCI_INTERPRETER_CHECK(input()->shape().num_dims() <= 4); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::FLOAT32 || - output()->element_type() == DataType::U8); - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - if (output()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(output()->scale() == (1. / 128.)); - LUCI_INTERPRETER_CHECK(output()->zero_point() == 128); - } - LUCI_INTERPRETER_CHECK(params().activation == Activation::NONE); - output()->resize(input()->shape()); -} - -void L2Normalize::execute() const -{ - switch (output()->element_type()) - { - case DataType::FLOAT32: - eval<float>(0); - break; - case DataType::U8: - eval<uint8_t>(input()->zero_point()); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -template <typename T> void L2Normalize::eval(int32_t zero_point) const -{ - tflite::L2NormalizationParams op_params{}; - op_params.input_zero_point = zero_point; - tflite::optimized_ops::L2Normalization(op_params, getTensorShape(input()), - getTensorData<T>(input()), getTensorShape(output()), - getTensorData<T>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/L2Normalize.h b/compiler/luci-interpreter/src/kernels/L2Normalize.h deleted file mode 100644 index 6c7dac698..000000000 --- a/compiler/luci-interpreter/src/kernels/L2Normalize.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_L2NORMALIZE_H -#define LUCI_INTERPRETER_KERNELS_L2NORMALIZE_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class L2Normalize : public KernelWithParams<L2NormParams> -{ -public: - L2Normalize(const Tensor *input, Tensor *output, const L2NormParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - template <typename T> void eval(int32_t zero_point) const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_L2NORMALIZE_H diff --git a/compiler/luci-interpreter/src/kernels/L2Normalize.test.cpp b/compiler/luci-interpreter/src/kernels/L2Normalize.test.cpp deleted file mode 100644 index 8f9431182..000000000 --- a/compiler/luci-interpreter/src/kernels/L2Normalize.test.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "kernels/L2Normalize.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> output_data) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - L2NormParams params{}; - params.activation = Activation::NONE; - - L2Normalize kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -template <> -void Check<uint8_t>(std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, - std::initializer_list<float> output_data) -{ - std::pair<float, int32_t> quant_param = - quantizationParams<uint8_t>(std::min(input_data) < 0 ? std::min(input_data) : 0.f, - std::max(input_data) > 0 ? std::max(input_data) : 0.f); - - Tensor input_tensor = - makeInputTensor<DataType::U8>(input_shape, quant_param.first, quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1. / 128., 128); - - L2NormParams params{}; - params.activation = Activation::NONE; - - L2Normalize kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data, output_tensor.scale())); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -template <typename T> class L2NormalizeTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(L2NormalizeTest, DataTypes); - -TYPED_TEST(L2NormalizeTest, Simple) -{ - Check<TypeParam>({1, 1, 1, 6}, {1, 1, 1, 6}, {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}, - {-0.55, 0.3, 0.35, 0.6, -0.35, 0.05}); -} - -TEST(L2NormalizeTest, ActivationType_NEG) -{ - std::vector<float> input_data = {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1, 1, 1, 6}, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - L2NormParams params{}; - params.activation = Activation::RELU6; - - L2Normalize kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(L2NormalizeTest, InvalidOutputQuantParam_NEG) -{ - std::vector<float> input_data = {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}; - - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 1, 1, 6}, 1. / 64., 127, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1. / 64., 127); - - L2NormParams params{}; - params.activation = Activation::NONE; - - L2Normalize kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/L2Pool2D.cpp b/compiler/luci-interpreter/src/kernels/L2Pool2D.cpp deleted file mode 100644 index 979364a7f..000000000 --- a/compiler/luci-interpreter/src/kernels/L2Pool2D.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/L2Pool2D.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -L2Pool2D::L2Pool2D(const Tensor *input, Tensor *output, const Pool2DParams ¶ms) - : KernelWithParams<Pool2DParams>({input}, {output}, params) -{ -} - -void L2Pool2D::configure() -{ - LUCI_INTERPRETER_CHECK(input()->shape().num_dims() == 4); - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - - int batches = input()->shape().dim(0); - int height = input()->shape().dim(1); - int width = input()->shape().dim(2); - int channels_out = input()->shape().dim(3); - - // Matching GetWindowedOutputSize in TensorFlow. - auto padding = params().padding; - int out_width, out_height; - out_width = computeOutputSize(padding, width, params().filter_width, params().stride_width, 1); - out_height = - computeOutputSize(padding, height, params().filter_height, params().stride_height, 1); - _padding_width = - computePadding(params().stride_width, 1, width, params().filter_width, out_width); - _padding_height = - computePadding(params().stride_height, 1, height, params().filter_height, out_height); - - LUCI_INTERPRETER_CHECK(input()->element_type() == DataType::FLOAT32); - output()->resize({batches, out_height, out_width, channels_out}); -} - -void L2Pool2D::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - float activation_min, activation_max; - calculateActivationRange(params().activation, &activation_min, &activation_max); - tflite::PoolParams op_params; - op_params.stride_height = params().stride_height; - op_params.stride_width = params().stride_width; - op_params.filter_height = params().filter_height; - op_params.filter_width = params().filter_width; - op_params.padding_values.height = _padding_height; - op_params.padding_values.width = _padding_width; - op_params.float_activation_min = activation_min; - op_params.float_activation_max = activation_max; - tflite::optimized_ops::L2Pool(op_params, getTensorShape(input()), - getTensorData<float>(input()), getTensorShape(output()), - getTensorData<float>(output())); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/L2Pool2D.h b/compiler/luci-interpreter/src/kernels/L2Pool2D.h deleted file mode 100644 index d40f5f478..000000000 --- a/compiler/luci-interpreter/src/kernels/L2Pool2D.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_L2POOL2D_H -#define LUCI_INTERPRETER_KERNELS_L2POOL2D_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -#include <memory> - -namespace luci_interpreter -{ -namespace kernels -{ - -class L2Pool2D : public KernelWithParams<Pool2DParams> -{ -public: - L2Pool2D(const Tensor *input, Tensor *output, const Pool2DParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - int32_t _padding_height = 0; - int32_t _padding_width = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_L2POOL2D_H diff --git a/compiler/luci-interpreter/src/kernels/L2Pool2D.test.cpp b/compiler/luci-interpreter/src/kernels/L2Pool2D.test.cpp deleted file mode 100644 index 5f834e3c1..000000000 --- a/compiler/luci-interpreter/src/kernels/L2Pool2D.test.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/L2Pool2D.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(L2Pool2DTest, FloatNone) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - 0, 6, 2, 4, // - 3, 2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.activation = Activation::NONE; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{3.5, 6.5}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - // TODO make a Shape checking of output_tensor. -} - -TEST(L2Pool2DTest, FloatRelu) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - -1, -6, 2, 4, // - -3, -2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.activation = Activation::RELU; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{3.53553, 6.5}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - // TODO make a Shape checking of output_tensor. -} - -TEST(L2Pool2DTest, FloatRelu1) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - -0.1, -0.6, 2, 4, // - -0.3, -0.2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.activation = Activation::RELU_N1_TO_1; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{0.353553, 1.0}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - // TODO make a Shape checking of output_tensor. -} - -TEST(L2Pool2DTest, FloatRelu6) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - -0.1, -0.6, 2, 4, // - -0.3, -0.2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.activation = Activation::RELU6; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{0.353553, 6.0}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - // TODO make a Shape checking of output_tensor. -} - -TEST(L2Pool2DTest, FloatPaddingSame) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - 0, 6, 2, 4, // - 3, 2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::SAME; - params.activation = Activation::NONE; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{3.5, 6.5}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - // TODO make a Shape checking of output_tensor. -} - -TEST(L2Pool2DTest, FloatPaddingSameStride) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - 0, 6, 2, 4, // - 3, 2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::SAME; - params.activation = Activation::NONE; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 1; - params.stride_width = 1; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{3.5, 6.0, 6.5, 5.70088, 2.54951, 7.2111, 8.63134, 7.0}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - // TODO make a Shape checking of output_tensor. -} - -TEST(L2Pool2DTest, FloatPaddingValidStride) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - 0, 6, 2, 4, // - 3, 2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.activation = Activation::NONE; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 1; - params.stride_width = 1; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{3.5, 6.0, 6.5}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - // TODO make a Shape checking of output_tensor. -} - -TEST(L2Pool2DTest, InvalidInputShape_NEG) -{ - Shape input_shape{1, 2, 4}; - std::vector<float> input_data{ - 0, 6, 2, 4, // - 3, 2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.activation = Activation::NONE; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 1; - params.stride_width = 1; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(L2Pool2DTest, InvalidInputOutputType_NEG) -{ - Shape input_shape{1, 2, 4}; - std::vector<float> input_data{ - 0, 6, 2, 4, // - 3, 2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.activation = Activation::NONE; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 1; - params.stride_width = 1; - - L2Pool2D kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/LeakyRelu.cpp b/compiler/luci-interpreter/src/kernels/LeakyRelu.cpp deleted file mode 100644 index 919b12792..000000000 --- a/compiler/luci-interpreter/src/kernels/LeakyRelu.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/LeakyRelu.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -LeakyRelu::LeakyRelu(const Tensor *input, Tensor *output, const LeakyReluParams ¶ms) - : KernelWithParams<LeakyReluParams>({input}, {output}, params) -{ -} - -void LeakyRelu::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - if (input()->element_type() == DataType::U8) - { - double alpha_multiplier = input()->scale() * params().alpha / output()->scale(); - quantizeMultiplier(alpha_multiplier, &_output_multiplier_alpha, &_output_shift_alpha); - double identity_multiplier = input()->scale() / output()->scale(); - quantizeMultiplier(identity_multiplier, &_output_multiplier_identity, &_output_shift_identity); - } - output()->resize(input()->shape()); -} - -void LeakyRelu::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void LeakyRelu::evalFloat() const -{ - tflite::LeakyReluParams op_params{}; - op_params.alpha = params().alpha; - tflite::optimized_ops::LeakyRelu(op_params, getTensorShape(input()), - getTensorData<float>(input()), getTensorShape(output()), - getTensorData<float>(output())); -} - -void LeakyRelu::evalQuantized() const -{ - tflite::LeakyReluParams op_params{}; - op_params.input_offset = input()->zero_point(); - op_params.output_offset = output()->zero_point(); - op_params.output_multiplier_alpha = _output_multiplier_alpha; - op_params.output_shift_alpha = _output_shift_alpha; - op_params.output_multiplier_identity = _output_multiplier_identity; - op_params.output_shift_identity = _output_shift_identity; - - tflite::reference_ops::QuantizeLeakyRelu( - op_params, getTensorShape(input()), getTensorData<uint8_t>(input()), getTensorShape(output()), - getTensorData<uint8_t>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/LeakyRelu.h b/compiler/luci-interpreter/src/kernels/LeakyRelu.h deleted file mode 100644 index e66f404df..000000000 --- a/compiler/luci-interpreter/src/kernels/LeakyRelu.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_LEAKYRELU_H -#define LUCI_INTERPRETER_KERNELS_LEAKYRELU_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class LeakyRelu : public KernelWithParams<LeakyReluParams> -{ -public: - LeakyRelu(const Tensor *input, Tensor *output, const LeakyReluParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _output_multiplier_alpha = 0; - int _output_shift_alpha = 0; - int32_t _output_multiplier_identity = 0; - int _output_shift_identity = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_LEAKYRELU_H diff --git a/compiler/luci-interpreter/src/kernels/LeakyRelu.test.cpp b/compiler/luci-interpreter/src/kernels/LeakyRelu.test.cpp deleted file mode 100644 index 2778549ed..000000000 --- a/compiler/luci-interpreter/src/kernels/LeakyRelu.test.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/LeakyRelu.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> output_data, - float alpha) -{ - constexpr DataType element_type = getElementType<T>(); - Tensor input_tensor = makeInputTensor<element_type>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(element_type); - - LeakyReluParams params{}; - params.alpha = alpha; - - LeakyRelu kernel(&input_tensor, &output_tensor, params); - - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(extractTensorData<T>(output_tensor), ::testing::ElementsAreArray(output_data)); -} - -template <> -void Check<uint8_t>(std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, - std::initializer_list<float> output_data, float alpha) -{ - const float quantized_tolerance = getTolerance(-8, 127.f / 16.f, 255); - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-8, 127.f / 16.f); - Tensor input_tensor = - makeInputTensor<DataType::U8>(input_shape, quant_param.first, quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - LeakyReluParams params{}; - params.alpha = alpha; - - LeakyRelu kernel(&input_tensor, &output_tensor, params); - - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data, quantized_tolerance)); -} - -template <typename T> class LeakReluTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(LeakReluTest, DataTypes); - -TYPED_TEST(LeakReluTest, Simple) -{ - Check<TypeParam>(/*input_shape=*/{2, 3}, /*output_shape=*/{2, 3}, - /*input_data=*/ - { - 0.0f, 1.0f, 3.0f, // Row 1 - 1.0f, -1.0f, -2.0f, // Row 2 - }, - /*output_data=*/ - { - 0.0f, 1.0f, 3.0f, // Row 1 - 1.0f, -0.5f, -1.0f, // Row 2 - }, - /*alpha=*/0.5f); - - SUCCEED(); -} - -TEST(LeakReluTest, IvalidInputOutputType_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, { - 0.0f, 1.0f, 3.0f, // Row 1 - 1.0f, -1.0f, -2.0f, // Row 2 - }); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - LeakyReluParams params{}; - params.alpha = 0.5f; - - LeakyRelu kernel(&input_tensor, &output_tensor, params); - - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Less.cpp b/compiler/luci-interpreter/src/kernels/Less.cpp deleted file mode 100644 index 041444926..000000000 --- a/compiler/luci-interpreter/src/kernels/Less.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Less.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/comparisons.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Less::Less(const Tensor *x, const Tensor *y, Tensor *output) : Kernel({x, y}, {output}) {} - -void Less::configure() -{ - LUCI_INTERPRETER_CHECK(x()->element_type() == y()->element_type()); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::BOOL); - - if (x()->element_type() == DataType::U8) - { - quantizeMultiplierSmallerThanOneExp(x()->scale(), &_x_multiplier, &_x_shift); - quantizeMultiplierSmallerThanOneExp(y()->scale(), &_y_multiplier, &_y_shift); - } - output()->resize(calculateShapeForBroadcast(x()->shape(), y()->shape())); -} - -void Less::execute() const -{ - switch (x()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Less::evalFloat() const -{ - const auto x_data = getTensorData<float>(x()); - const auto y_data = getTensorData<float>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowLess(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::Less(op_params, getTensorShape(x()), x_data, getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } -} - -void Less::evalQuantized() const -{ - const auto x_data = getTensorData<uint8_t>(x()); - const auto y_data = getTensorData<uint8_t>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.left_shift = 8; - op_params.input1_offset = -x()->zero_point(); // Note the '-' - op_params.input1_shift = _x_shift; - op_params.input1_multiplier = _x_multiplier; - op_params.input2_offset = -y()->zero_point(); // Note the '-' - op_params.input2_shift = _y_shift; - op_params.input2_multiplier = _y_multiplier; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowLessWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::LessWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, getTensorShape(output()), - output_data); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Less.h b/compiler/luci-interpreter/src/kernels/Less.h deleted file mode 100644 index fe03e10b1..000000000 --- a/compiler/luci-interpreter/src/kernels/Less.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_LESS_H -#define LUCI_INTERPRETER_KERNELS_LESS_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Less : public Kernel -{ -public: - Less(const Tensor *x, const Tensor *y, Tensor *output); - - const Tensor *x() const { return _inputs[0]; } - const Tensor *y() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _x_multiplier = 0; - int32_t _x_shift = 0; - int32_t _y_multiplier = 0; - int32_t _y_shift = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_LESS_H diff --git a/compiler/luci-interpreter/src/kernels/Less.test.cpp b/compiler/luci-interpreter/src/kernels/Less.test.cpp deleted file mode 100644 index 73aa30b36..000000000 --- a/compiler/luci-interpreter/src/kernels/Less.test.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Less.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(LessTest, FloatSimple) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - -1, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - true, false, false, // Row 1 - false, false, true, // Row 2 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Less kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 3})); -} - -TEST(LessTest, FloatBroardcast) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - -1, 0, 1, // Row 3 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - }; - - std::vector<bool> ref_output_data{ - true, false, false, // Row 1 - false, true, true, // Row 2 - true, true, false, // Row 3 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({3, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Less kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({3, 3})); -} - -// Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. -const float F_MIN = -128.0 / 128.0; -const float F_MAX = 127.0 / 128.0; - -TEST(LessTest, Uint8Quantized) -{ - std::vector<float> x_data{ - 0.5, 0.6, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.6, 0.55, 0.5, // Row 1 - -1, 0.05, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - true, false, false, false, // Row 1 - false, true, false, true, // Row 2 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Less kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(LessTest, Uint8QuantizedRescale) -{ - std::vector<float> x_data{ - 0.5, 0.6, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.6, 0.6, 0.5, // Row 1 - -1, 0.05, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - true, false, false, false, // Row 1 - false, true, false, true, // Row 2 - }; - - std::pair<float, int32_t> x_quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - std::pair<float, int32_t> y_quant_param = quantizationParams<uint8_t>(F_MIN * 1.2, F_MAX * 1.5); - - Tensor x_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, x_quant_param.first, - x_quant_param.second, x_data); - Tensor y_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, y_quant_param.first, - y_quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Less kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(LessTest, Uint8QuantizedBroadcast) -{ - std::vector<float> x_data{ - 0.4, -0.8, 0.7, 0.3, // Row 1 - -0.5, 0.1, 0, 0.5, // Row 2 - 1, 0, 0.05, -1, // Row 3 - }; - - std::vector<float> y_data{ - -1, 0.05, 0, 1, // Row 1 - }; - - std::vector<bool> ref_output_data{ - false, true, false, true, // Row 1 - false, false, false, true, // Row 2 - false, true, false, true, // Row 3 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 3, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 1, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Less kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 3, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(LessTest, Input_Type_Mismatch_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::U8>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - Less kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(LessTest, Input_Output_Type_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Less kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/LessEqual.cpp b/compiler/luci-interpreter/src/kernels/LessEqual.cpp deleted file mode 100644 index b8aaba178..000000000 --- a/compiler/luci-interpreter/src/kernels/LessEqual.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/LessEqual.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/comparisons.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -LessEqual::LessEqual(const Tensor *x, const Tensor *y, Tensor *output) : Kernel({x, y}, {output}) {} - -void LessEqual::configure() -{ - LUCI_INTERPRETER_CHECK(x()->element_type() == y()->element_type()); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::BOOL); - - if (x()->element_type() == DataType::U8) - { - quantizeMultiplierSmallerThanOneExp(x()->scale(), &_x_multiplier, &_x_shift); - quantizeMultiplierSmallerThanOneExp(y()->scale(), &_y_multiplier, &_y_shift); - } - output()->resize(calculateShapeForBroadcast(x()->shape(), y()->shape())); -} - -void LessEqual::execute() const -{ - switch (x()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void LessEqual::evalFloat() const -{ - const auto x_data = getTensorData<float>(x()); - const auto y_data = getTensorData<float>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowLessEqual(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::LessEqual(op_params, getTensorShape(x()), x_data, getTensorShape(y()), - y_data, getTensorShape(output()), output_data); - } -} - -void LessEqual::evalQuantized() const -{ - const auto x_data = getTensorData<uint8_t>(x()); - const auto y_data = getTensorData<uint8_t>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.left_shift = 8; - op_params.input1_offset = -x()->zero_point(); // Note the '-' - op_params.input1_shift = _x_shift; - op_params.input1_multiplier = _x_multiplier; - op_params.input2_offset = -y()->zero_point(); // Note the '-' - op_params.input2_shift = _y_shift; - op_params.input2_multiplier = _y_multiplier; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowLessEqualWithScaling( - op_params, getTensorShape(x()), x_data, getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::LessEqualWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/LessEqual.h b/compiler/luci-interpreter/src/kernels/LessEqual.h deleted file mode 100644 index ed4b0f1ea..000000000 --- a/compiler/luci-interpreter/src/kernels/LessEqual.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_LESS_EQUAL_H -#define LUCI_INTERPRETER_KERNELS_LESS_EQUAL_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class LessEqual : public Kernel -{ -public: - LessEqual(const Tensor *x, const Tensor *y, Tensor *output); - - const Tensor *x() const { return _inputs[0]; } - const Tensor *y() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _x_multiplier = 0; - int32_t _x_shift = 0; - int32_t _y_multiplier = 0; - int32_t _y_shift = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_LESS_EQUAL_H diff --git a/compiler/luci-interpreter/src/kernels/LessEqual.test.cpp b/compiler/luci-interpreter/src/kernels/LessEqual.test.cpp deleted file mode 100644 index 9184c061f..000000000 --- a/compiler/luci-interpreter/src/kernels/LessEqual.test.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/LessEqual.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(LessEqualTest, FloatSimple) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - -1, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - true, true, false, // Row 1 - false, true, true, // Row 2 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - LessEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 3})); -} - -TEST(LessEqualTest, FloatBroardcast) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - -1, 0, 1, // Row 3 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - }; - - std::vector<bool> ref_output_data{ - true, true, false, // Row 1 - false, true, true, // Row 2 - true, true, false, // Row 3 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({3, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - LessEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({3, 3})); -} - -// Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. -const float F_MIN = -128.0 / 128.0; -const float F_MAX = 127.0 / 128.0; - -TEST(LessEqualTest, Uint8Quantized) -{ - std::vector<float> x_data{ - 0.5, 0.6, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.6, 0.55, 0.5, // Row 1 - -1, 0.05, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - true, true, false, false, // Row 1 - false, true, false, true, // Row 2 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - LessEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(LessEqualTest, Uint8QuantizedRescale) -{ - std::vector<float> x_data{ - 0.5, 0.6, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.6, 0.6, 0.5, // Row 1 - -1, 0.05, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - true, true, false, false, // Row 1 - false, true, false, true, // Row 2 - }; - - std::pair<float, int32_t> x_quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - std::pair<float, int32_t> y_quant_param = quantizationParams<uint8_t>(F_MIN * 1.2, F_MAX * 1.5); - - Tensor x_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, x_quant_param.first, - x_quant_param.second, x_data); - Tensor y_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, y_quant_param.first, - y_quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - LessEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(LessEqualTest, Uint8QuantizedBroadcast) -{ - std::vector<float> x_data{ - 0.4, -0.8, 0.7, 0.3, // Row 1 - -0.5, 0.1, 0, 0.5, // Row 2 - 1, 0, 0.05, -1, // Row 3 - }; - - std::vector<float> y_data{ - -1, 0.05, 0, 1, // Row 1 - }; - - std::vector<bool> ref_output_data{ - false, true, false, true, // Row 1 - false, false, true, true, // Row 2 - false, true, false, true, // Row 3 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 3, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 1, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - LessEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 3, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(LessEqualTest, Input_Type_Mismatch_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::U8>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - LessEqual kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(LessEqualTest, Input_Output_Type_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - LessEqual kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.cpp b/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.cpp deleted file mode 100644 index b78e27128..000000000 --- a/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/LocalResponseNormalization.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -LocalResponseNormalization::LocalResponseNormalization( - const Tensor *input, Tensor *output, const LocalResponseNormalizationParams ¶ms) - : KernelWithParams<LocalResponseNormalizationParams>({input}, {output}, params) -{ -} - -void LocalResponseNormalization::configure() -{ - LUCI_INTERPRETER_CHECK(input()->shape().num_dims() == 4); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::FLOAT32); - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - output()->resize(input()->shape()); -} - -void LocalResponseNormalization::execute() const -{ - switch (output()->element_type()) - { - case DataType::FLOAT32: - tflite::LocalResponseNormalizationParams op_params; - op_params.range = params().radius; - op_params.bias = params().bias; - op_params.alpha = params().alpha; - op_params.beta = params().beta; - tflite::optimized_ops::LocalResponseNormalization( - op_params, getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.h b/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.h deleted file mode 100644 index 60408a104..000000000 --- a/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_LOCALRESPONSENORMALIZATION_H -#define LUCI_INTERPRETER_KERNELS_LOCALRESPONSENORMALIZATION_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class LocalResponseNormalization : public KernelWithParams<LocalResponseNormalizationParams> -{ -public: - LocalResponseNormalization(const Tensor *input, Tensor *output, - const LocalResponseNormalizationParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_LOCALRESPONSENORMALIZATION_H diff --git a/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.test.cpp b/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.test.cpp deleted file mode 100644 index d98305c1a..000000000 --- a/compiler/luci-interpreter/src/kernels/LocalResponseNormalization.test.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/LocalResponseNormalization.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(LocalResponseNormalizationTest, SameAsL2Norm) -{ - Tensor input_tensor = - makeInputTensor<DataType::FLOAT32>({1, 1, 1, 6}, {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - LocalResponseNormalizationParams params{}; - params.radius = 20; - params.bias = 0.0; - params.alpha = 1.0; - params.beta = 0.5; - - LocalResponseNormalization kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - FloatArrayNear({-0.55, 0.3, 0.35, 0.6, -0.35, 0.05})); -} - -TEST(LocalResponseNormalizationTest, WithAlpha) -{ - Tensor input_tensor = - makeInputTensor<DataType::FLOAT32>({1, 1, 1, 6}, {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - LocalResponseNormalizationParams params{}; - params.radius = 20; - params.bias = 0.0; - params.alpha = 4.0; - params.beta = 0.5; - - LocalResponseNormalization kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - FloatArrayNear({-0.275, 0.15, 0.175, 0.3, -0.175, 0.025})); -} - -TEST(LocalResponseNormalizationTest, WithBias) -{ - Tensor input_tensor = - makeInputTensor<DataType::FLOAT32>({1, 1, 1, 6}, {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - LocalResponseNormalizationParams params{}; - params.radius = 20; - params.bias = 9.0; - params.alpha = 4.0; - params.beta = 0.5; - - LocalResponseNormalization kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - FloatArrayNear({-0.22, 0.12, 0.14, 0.24, -0.14, 0.02})); -} - -TEST(LocalResponseNormalizationTest, SmallRadius) -{ - Tensor input_tensor = - makeInputTensor<DataType::FLOAT32>({1, 1, 1, 6}, {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - LocalResponseNormalizationParams params{}; - params.radius = 2; - params.bias = 9.0; - params.alpha = 4.0; - params.beta = 0.5; - - LocalResponseNormalization kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - FloatArrayNear({-0.264926, 0.125109, 0.140112, 0.267261, -0.161788, 0.0244266})); -} - -TEST(LocalResponseNormalizationTest, InvalidInputDimension_NEG) -{ - Tensor input_tensor = - makeInputTensor<DataType::FLOAT32>({1, 1, 6}, {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - LocalResponseNormalizationParams params{}; - params.radius = 20; - params.bias = 0.0; - params.alpha = 1.0; - params.beta = 0.5; - - LocalResponseNormalization kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(LocalResponseNormalizationTest, InvalidInputOutputType_NEG) -{ - Tensor input_tensor = - makeInputTensor<DataType::FLOAT32>({1, 1, 1, 6}, {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - LocalResponseNormalizationParams params{}; - params.radius = 20; - params.bias = 0.0; - params.alpha = 1.0; - params.beta = 0.5; - - LocalResponseNormalization kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/LogSoftmax.cpp b/compiler/luci-interpreter/src/kernels/LogSoftmax.cpp deleted file mode 100644 index 03d13e4ce..000000000 --- a/compiler/luci-interpreter/src/kernels/LogSoftmax.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/LogSoftmax.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -LogSoftmax::LogSoftmax(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void LogSoftmax::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - if (input()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(output()->scale() == 16. / 256); - LUCI_INTERPRETER_CHECK(output()->zero_point() == 255); - - tflite::SoftmaxParams params{}; - - params.table = _table; - params.beta = 1.0; - - tflite::optimized_ops::PopulateSoftmaxLookupTable(¶ms, input()->scale(), params.beta); - } - output()->resize(input()->shape()); -} - -void LogSoftmax::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void LogSoftmax::evalFloat() const -{ - tflite::SoftmaxParams params{}; - tflite::reference_ops::LogSoftmax(params, getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); -} - -void LogSoftmax::evalQuantized() const -{ - const auto input_shape = getTensorShape(input()); - const auto output_shape = getTensorShape(output()); - const auto input_scale = input()->scale(); - uint8_t *output_data = getTensorData<uint8_t>(output()); - const uint8_t *input_data = getTensorData<uint8_t>(input()); - - tflite::SoftmaxParams params{}; - - params.table = const_cast<float *>(_table); - params.zero_point = output()->zero_point(); - params.scale = output()->scale(); - - tflite::optimized_ops::LogSoftmax(params, input_scale, input_shape, input_data, output_shape, - output_data); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/LogSoftmax.h b/compiler/luci-interpreter/src/kernels/LogSoftmax.h deleted file mode 100644 index 18477fbe3..000000000 --- a/compiler/luci-interpreter/src/kernels/LogSoftmax.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_LOGSOFTMAX_H -#define LUCI_INTERPRETER_KERNELS_LOGSOFTMAX_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class LogSoftmax : public Kernel -{ -public: - LogSoftmax(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - - float _table[256]; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_LOGSOFTMAX_H diff --git a/compiler/luci-interpreter/src/kernels/LogSoftmax.test.cpp b/compiler/luci-interpreter/src/kernels/LogSoftmax.test.cpp deleted file mode 100644 index d3b331dfe..000000000 --- a/compiler/luci-interpreter/src/kernels/LogSoftmax.test.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/LogSoftmax.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(LogSoftmaxTest, Float) -{ - Shape input_shape{2, 4}; - std::vector<float> input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - LogSoftmax kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - -4.14297, -10.14297, -2.14297, -.142971, // - -7.00104, -12.00104, -.00104087, -9.00104, // - }; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(LogSoftmaxTest, Uint8) -{ - float kMin = -10; - float kMax = 10; - float kLogSoftmaxQuantizedTolerance = 16. / 256; - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(kMin, kMax); - std::vector<float> input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = - makeInputTensor<DataType::U8>({2, 4}, quant_param.first, quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 16. / 256, 255); - - LogSoftmax kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - -4.14297, -10.14297, -2.14297, -.142971, // - -7.00104, -12.00104, -.00104087, -9.00104, // - }; - std::vector<int32_t> ref_output_shape{2, 4}; - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, kLogSoftmaxQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); - EXPECT_THAT(extractTensorData<uint8_t>(output_tensor), - ::testing::ElementsAreArray({189, 93, 221, 253, 142, 63, 255, 111})); -} - -TEST(LogSoftmaxTest, InvalidInputOutputType_NEG) -{ - std::vector<float> input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 4}, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 16. / 256, 255); - - LogSoftmax kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(LogSoftmaxTest, InvalidOutputQuantParam_NEG) -{ - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-10, 10); - std::vector<float> input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = - makeInputTensor<DataType::U8>({2, 4}, quant_param.first, quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 20. / 256, 255); - - LogSoftmax kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Logistic.cpp b/compiler/luci-interpreter/src/kernels/Logistic.cpp deleted file mode 100644 index 97d7bf13d..000000000 --- a/compiler/luci-interpreter/src/kernels/Logistic.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Logistic.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -Logistic::Logistic(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Logistic::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - if (input()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(output()->scale() == 1. / 256); - populateLookupTable(); - } - output()->resize(input()->shape()); -} - -void Logistic::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Logistic::evalFloat() const -{ - tflite::reference_ops::Logistic(getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); -} - -void Logistic::evalQuantized() const -{ - const int size = tflite::MatchingFlatSize(getTensorShape(input()), getTensorShape(output())); - uint8_t *output_data = getTensorData<uint8_t>(output()); - const uint8_t *input_data = getTensorData<uint8_t>(input()); - for (int i = 0; i < size; ++i) - { - output_data[i] = getTableValue(input_data[i]); - } -} - -void Logistic::populateLookupTable() -{ - const auto input_scale = static_cast<double>(input()->scale()); - const auto input_zero_point = static_cast<int32_t>(input()->zero_point()); - const auto output_scale = static_cast<double>(output()->scale()); - const auto output_zero_point = static_cast<int32_t>(output()->zero_point()); - const float inverse_scale = 1 / output_scale; - int32_t maxval = std::numeric_limits<uint8_t>::max(); - int32_t minval = std::numeric_limits<uint8_t>::min(); - for (int32_t val = minval; val <= maxval; ++val) - { - const float dequantized = input_scale * (val - input_zero_point); - const float transformed = 1.0f / (1.0f + std::exp(-dequantized)); - const float rescaled = std::round(transformed * inverse_scale); - const int32_t quantized = static_cast<int32_t>(rescaled + output_zero_point); - setTableValue(static_cast<uint8_t>(std::max(std::min(maxval, quantized), minval)), - static_cast<uint8_t>(val)); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Logistic.h b/compiler/luci-interpreter/src/kernels/Logistic.h deleted file mode 100644 index 31de6adf0..000000000 --- a/compiler/luci-interpreter/src/kernels/Logistic.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_LOGISTIC_H -#define LUCI_INTERPRETER_KERNELS_LOGISTIC_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Logistic : public Kernel -{ -public: - Logistic(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void populateLookupTable(); - void setTableValue(uint8_t value, uint8_t idx) { _table[idx] = value; }; - uint8_t getTableValue(uint8_t idx) const { return _table[idx]; }; - -private: - uint8_t _table[256]{}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_LOGISTIC_H diff --git a/compiler/luci-interpreter/src/kernels/Logistic.test.cpp b/compiler/luci-interpreter/src/kernels/Logistic.test.cpp deleted file mode 100644 index d3bbb330d..000000000 --- a/compiler/luci-interpreter/src/kernels/Logistic.test.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Logistic.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> output_data) -{ - Tensor input_tensor = makeInputTensor<getElementType<T>()>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(getElementType<T>()); - - Logistic kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -template <> -void Check<uint8_t>(std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, - std::initializer_list<float> output_data) -{ - std::pair<float, int32_t> input_quant_param = - quantizationParams<uint8_t>(std::min(input_data), std::max(input_data)); - Tensor input_tensor = makeInputTensor<DataType::U8>(input_shape, input_quant_param.first, - input_quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1. / 256, 0); - - Logistic kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data, output_tensor.scale() * 2)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -template <typename T> class LogisticTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(LogisticTest, DataTypes); - -TYPED_TEST(LogisticTest, Simple) -{ - Check<TypeParam>( - {89}, {89}, - {-10.0000000000, -9.7727272727, -9.5454545455, -9.3181818182, -9.0909090909, -8.8636363636, - -8.6363636364, -8.4090909091, -8.1818181818, -7.9545454545, -7.7272727273, -7.5000000000, - -7.2727272727, -7.0454545455, -6.8181818182, -6.5909090909, -6.3636363636, -6.1363636364, - -5.9090909091, -5.6818181818, -5.4545454545, -5.2272727273, -5.0000000000, -4.7727272727, - -4.5454545455, -4.3181818182, -4.0909090909, -3.8636363636, -3.6363636364, -3.4090909091, - -3.1818181818, -2.9545454545, -2.7272727273, -2.5000000000, -2.2727272727, -2.0454545455, - -1.8181818182, -1.5909090909, -1.3636363636, -1.1363636364, -0.9090909091, -0.6818181818, - -0.4545454545, -0.2272727273, 0.0000000000, 0.2272727273, 0.4545454545, 0.6818181818, - 0.9090909091, 1.1363636364, 1.3636363636, 1.5909090909, 1.8181818182, 2.0454545455, - 2.2727272727, 2.5000000000, 2.7272727273, 2.9545454545, 3.1818181818, 3.4090909091, - 3.6363636364, 3.8636363636, 4.0909090909, 4.3181818182, 4.5454545455, 4.7727272727, - 5.0000000000, 5.2272727273, 5.4545454545, 5.6818181818, 5.9090909091, 6.1363636364, - 6.3636363636, 6.5909090909, 6.8181818182, 7.0454545455, 7.2727272727, 7.5000000000, - 7.7272727273, 7.9545454545, 8.1818181818, 8.4090909091, 8.6363636364, 8.8636363636, - 9.0909090909, 9.3181818182, 9.5454545455, 9.7727272727, 10.0000000000}, - {0.0000453979, 0.0000569815, 0.0000715205, 0.0000897689, 0.0001126729, 0.0001414198, - 0.0001774998, 0.0002227827, 0.0002796147, 0.0003509396, 0.0004404502, 0.0005527786, - 0.0006937345, 0.0008706021, 0.0010925128, 0.0013709094, 0.0017201256, 0.0021581065, - 0.0027073042, 0.0033957870, 0.0042586071, 0.0053394826, 0.0066928509, 0.0083863576, - 0.0105038445, 0.0131488902, 0.0164489307, 0.0205599431, 0.0256715863, 0.0320125562, - 0.0398556989, 0.0495221198, 0.0613831074, 0.0758581800, 0.0934070047, 0.1145124805, - 0.1396521834, 0.1692560327, 0.2036499335, 0.2429886272, 0.2871859014, 0.3358556241, - 0.3882805886, 0.4434251301, 0.5000000000, 0.5565748699, 0.6117194114, 0.6641443759, - 0.7128140986, 0.7570113728, 0.7963500665, 0.8307439673, 0.8603478166, 0.8854875195, - 0.9065929953, 0.9241418200, 0.9386168926, 0.9504778802, 0.9601443011, 0.9679874438, - 0.9743284137, 0.9794400569, 0.9835510693, 0.9868511098, 0.9894961555, 0.9916136424, - 0.9933071491, 0.9946605174, 0.9957413929, 0.9966042130, 0.9972926958, 0.9978418935, - 0.9982798744, 0.9986290906, 0.9989074872, 0.9991293979, 0.9993062655, 0.9994472214, - 0.9995595498, 0.9996490604, 0.9997203853, 0.9997772173, 0.9998225002, 0.9998585802, - 0.9998873271, 0.9999102311, 0.9999284795, 0.9999430185, 0.9999546021}); -} - -TEST(LogisticTest, IvalidInputOutputType_NEG) -{ - Shape input_shape = {1}; - std::vector<float> input_data{10}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1. / 256, 0); - - Logistic kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(LogisticTest, IvalidQuantParam_NEG) -{ - Shape input_shape = {2}; - std::vector<float> input_data{-10, 10}; - std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(-10, 10); - Tensor input_tensor = makeInputTensor<DataType::U8>(input_shape, input_quant_param.first, - input_quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1. / 255, 0); - - Logistic kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/MaxPool2D.cpp b/compiler/luci-interpreter/src/kernels/MaxPool2D.cpp deleted file mode 100644 index 123e6e1a2..000000000 --- a/compiler/luci-interpreter/src/kernels/MaxPool2D.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/MaxPool2D.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h> -#include <tensorflow/lite/kernels/internal/reference/pooling.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -MaxPool2D::MaxPool2D(const Tensor *input, Tensor *output, const Pool2DParams ¶ms) - : KernelWithParams<Pool2DParams>({input}, {output}, params) -{ -} - -void MaxPool2D::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - assert(input()->shape().num_dims() == 4); - const Shape &input_shape = input()->shape(); - const int32_t batches = input_shape.dim(0); - const int32_t input_height = input_shape.dim(1); - const int32_t input_width = input_shape.dim(2); - const int32_t depth = input_shape.dim(3); - - const int32_t output_height = computeOutputSize(_params.padding, input_height, - _params.filter_height, _params.stride_height); - const int32_t output_width = - computeOutputSize(_params.padding, input_width, _params.filter_width, _params.stride_width); - - _padding_height = - computePadding(_params.stride_height, 1, input_height, _params.filter_height, output_height); - _padding_width = - computePadding(_params.stride_width, 1, input_width, _params.filter_width, output_width); - - output()->resize({batches, output_height, output_width, depth}); - if (input()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6); - LUCI_INTERPRETER_CHECK(output()->zero_point() == input()->zero_point()); - } - else if (input()->element_type() == DataType::S16) - { - LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6); - LUCI_INTERPRETER_CHECK(input()->zero_point() == 0 && output()->zero_point() == 0); - } -} - -void MaxPool2D::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - case DataType::S16: - evalSInt16(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void MaxPool2D::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - - tflite::reference_ops::MaxPool(params, getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); -} - -void MaxPool2D::evalQuantized() const -{ - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - tflite::reference_ops::MaxPool(params, getTensorShape(input()), getTensorData<uint8_t>(input()), - getTensorShape(output()), getTensorData<uint8_t>(output())); -} - -void MaxPool2D::evalSInt16() const -{ - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - tflite::reference_integer_ops::MaxPool( - params, getTensorShape(input()), getTensorData<int16_t>(input()), // - getTensorShape(output()), getTensorData<int16_t>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/MaxPool2D.h b/compiler/luci-interpreter/src/kernels/MaxPool2D.h deleted file mode 100644 index bb7666305..000000000 --- a/compiler/luci-interpreter/src/kernels/MaxPool2D.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_MAXPOOL2D_H -#define LUCI_INTERPRETER_KERNELS_MAXPOOL2D_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class MaxPool2D : public KernelWithParams<Pool2DParams> -{ -public: - MaxPool2D(const Tensor *input, Tensor *output, const Pool2DParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void evalSInt16() const; - -private: - int32_t _padding_height{}; - int32_t _padding_width{}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_MAXPOOL2D_H diff --git a/compiler/luci-interpreter/src/kernels/MaxPool2D.test.cpp b/compiler/luci-interpreter/src/kernels/MaxPool2D.test.cpp deleted file mode 100644 index 1d7fe06c4..000000000 --- a/compiler/luci-interpreter/src/kernels/MaxPool2D.test.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/MaxPool2D.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(MaxPool2DTest, Float) -{ - Shape input_shape{1, 3, 5, 1}; - std::vector<float> input_data{ - 1, -1, 0, -2, 2, // - -7, -6, -5, -4, -3, // - 5, 4, 3, 6, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - MaxPool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 1, 2, // - 5, 6, // - }; - std::initializer_list<int32_t> ref_output_shape{1, 2, 2, 1}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(MaxPool2DTest, Uint8) -{ - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-15.9375, 15.9375); - std::vector<float> input_data{ - 0, -6, 12, 4, // - -3, -2, 10, 7, // - }; - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, - quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - params.activation = Activation::RELU6; - - MaxPool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{0.0, 6.0}; - std::initializer_list<int32_t> ref_output_shape{1, 1, 2, 1}; - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(MaxPool2DTest, SInt16) -{ - Shape input_shape{1, 3, 5, 1}; - std::vector<int32_t> ref_output_shape{1, 2, 2, 1}; - std::vector<float> input_data{ - 1, -1, 0, -2, 2, // - -7, -6, -5, -4, -3, // - 5, 4, 3, 6, 7, // - }; - std::vector<float> ref_output_data{ - 1, 2, // - 5, 6, // - }; - - Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, 0.2, 0, input_data); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.2, 0); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - MaxPool2D kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Maximum.cpp b/compiler/luci-interpreter/src/kernels/Maximum.cpp deleted file mode 100644 index c522b0706..000000000 --- a/compiler/luci-interpreter/src/kernels/Maximum.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2018 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Maximum.h" - -#include "kernels/Utils.h" - -#include "kernels/BinaryOpCommon.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -Maximum::Maximum(const Tensor *input1, const Tensor *input2, Tensor *output) - : Kernel({input1, input2}, {output}) -{ -} - -void Maximum::configure() -{ - LUCI_INTERPRETER_CHECK(input1()->element_type() == input2()->element_type()) - LUCI_INTERPRETER_CHECK(input1()->element_type() == output()->element_type()) - output()->resize(calculateShapeForBroadcast(input1()->shape(), input2()->shape())); -} - -void Maximum::execute() const -{ - switch (input1()->element_type()) - { - case DataType::FLOAT32: - evalMaximum<float>(); - break; - case DataType::U8: - evalMaximum<uint8_t>(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -template <typename T> inline void Maximum::evalMaximum() const -{ - BinaryOpBroadcastSlow(getTensorShape(input1()), getTensorData<T>(input1()), - getTensorShape(input2()), getTensorData<T>(input2()), - getTensorShape(output()), getTensorData<T>(output()), - [](T x, T y) { return std::max(x, y); }); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Maximum.h b/compiler/luci-interpreter/src/kernels/Maximum.h deleted file mode 100644 index 3c99e69c7..000000000 --- a/compiler/luci-interpreter/src/kernels/Maximum.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_MAXIMUM_H -#define LUCI_INTERPRETER_KERNELS_MAXIMUM_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Maximum : public Kernel -{ -public: - Maximum(const Tensor *input1, const Tensor *input2, Tensor *output); - - const Tensor *input1() const { return _inputs[0]; } - const Tensor *input2() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - template <typename T> inline void evalMaximum() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_MAXIMUM_H diff --git a/compiler/luci-interpreter/src/kernels/Maximum.test.cpp b/compiler/luci-interpreter/src/kernels/Maximum.test.cpp deleted file mode 100644 index 2ddaeaf04..000000000 --- a/compiler/luci-interpreter/src/kernels/Maximum.test.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Maximum.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(MaximumTest, Float) -{ - Shape input_shape{3, 1, 2}; - std::vector<float> input_data1{1.0, 0.0, -1.0, 11.0, -2.0, -1.44}; - std::vector<float> input_data2{-1.0, 0.0, 1.0, 12.0, -3.0, -1.43}; - Tensor input_tensor1 = makeInputTensor<DataType::FLOAT32>(input_shape, input_data1); - Tensor input_tensor2 = makeInputTensor<DataType::FLOAT32>(input_shape, input_data2); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Maximum kernel(&input_tensor1, &input_tensor2, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{1.0, 0.0, 1.0, 12.0, -2.0, -1.43}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(MaximumTest, Uint8) -{ - Shape input_shape{3, 1, 2}; - std::vector<uint8_t> input_data1{1, 0, 2, 11, 2, 23}; - std::vector<uint8_t> input_data2{0, 0, 1, 12, 255, 1}; - Tensor input_tensor1 = makeInputTensor<DataType::U8>(input_shape, input_data1); - Tensor input_tensor2 = makeInputTensor<DataType::U8>(input_shape, input_data2); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - Maximum kernel(&input_tensor1, &input_tensor2, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<int32_t> ref_output_shape{2, 4}; - EXPECT_THAT(extractTensorData<uint8_t>(output_tensor), - ::testing::ElementsAreArray({1, 0, 2, 12, 255, 23})); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Mean.cpp b/compiler/luci-interpreter/src/kernels/Mean.cpp deleted file mode 100644 index 7d022eaf8..000000000 --- a/compiler/luci-interpreter/src/kernels/Mean.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Mean.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -static void resolveAxes(const int *axes_data, int num_axes, tflite::MeanParams *params) -{ - params->axis_count = num_axes; - for (int i = 0; i < num_axes; ++i) - { - params->axis[i] = static_cast<int16>(axes_data[i]); - } - for (int i = num_axes; i < 4; ++i) - { - params->axis[i] = 1; - } -} - -// Returns the number of axes that will be reduced. Removes duplicates. -static int getAxisReductionCount(const int *axes_data, int num_axes, int input_num_dims) -{ - int reduction_count = num_axes; - for (int i = 0; i < num_axes; ++i) - { - int current = axes_data[i] >= 0 ? axes_data[i] : axes_data[i] + input_num_dims; - assert(current >= 0 && current < input_num_dims); - for (int j = 0; j < i; j++) - { - int previous = axes_data[j] >= 0 ? axes_data[j] : axes_data[j] + input_num_dims; - // This checks for duplicate axis - if (current == previous) - { - --reduction_count; - break; - } - } - } - return reduction_count; -} - -static Shape getOutputShape(const Shape &input_shape, const int *axes_data, int num_axes, - bool keep_dims) -{ - int input_num_dims = input_shape.num_dims(); - if (input_num_dims == 0) - { - return Shape(0); - } - - if (keep_dims) - { - Shape output_shape(input_num_dims); - for (int idx = 0; idx < input_num_dims; ++idx) - { - bool is_axis = false; - for (int axis_idx = 0; axis_idx < num_axes; ++axis_idx) - { - if (axes_data[axis_idx] == idx || axes_data[axis_idx] + input_num_dims == idx) - { - is_axis = true; - break; - } - } - if (is_axis) - { - output_shape.dim(idx) = 1; - } - else - { - output_shape.dim(idx) = input_shape.dim(idx); - } - } - return output_shape; - } - else - { - int num_reduce_axes = getAxisReductionCount(axes_data, num_axes, input_num_dims); - Shape output_shape(input_num_dims - num_reduce_axes); - int num_skip_axes = 0; - for (int idx = 0; idx < input_num_dims; ++idx) - { - bool is_axis = false; - for (int axis_idx = 0; axis_idx < num_axes; ++axis_idx) - { - if (axes_data[axis_idx] == idx || axes_data[axis_idx] + input_num_dims == idx) - { - ++num_skip_axes; - is_axis = true; - break; - } - } - if (!is_axis) - { - output_shape.dim(idx - num_skip_axes) = input_shape.dim(idx); - } - } - return output_shape; - } -} - -Mean::Mean(const Tensor *input, const Tensor *axes, Tensor *output, const ReducerParams ¶ms) - : KernelWithParams<ReducerParams>({input, axes}, {output}, params) -{ -} - -void Mean::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - LUCI_INTERPRETER_CHECK(axes()->element_type() == DataType::S32); - if (input()->element_type() == DataType::S16) - { - LUCI_INTERPRETER_CHECK(input()->zero_point() == 0 && output()->zero_point() == 0); - } - - const Shape &input_shape = input()->shape(); - int input_num_dims = input_shape.num_dims(); - - const auto *axes_data = getTensorData<int32_t>(axes()); - int num_axes = axes()->shape().num_elements(); - assert(num_axes <= 4); - - Shape output_shape = getOutputShape(input_shape, axes_data, num_axes, _params.keep_dims); - output()->resize(output_shape); - - tflite::MeanParams params{}; - resolveAxes(axes_data, num_axes, ¶ms); - const bool need_temporaries = - !(_params.keep_dims && input_num_dims == 4 && params.axis_count == 2 && - ((params.axis[0] == 1 && params.axis[1] == 2) || - (params.axis[0] == 2 && params.axis[1] == 1))); - if (need_temporaries) - { - _temp_index = - std::make_unique<Tensor>(DataType::S32, Shape(input_num_dims), AffineQuantization{}, ""); - _resolved_axes = - std::make_unique<Tensor>(DataType::S32, Shape(num_axes), AffineQuantization{}, ""); - _temp_sum = std::make_unique<Tensor>(input()->element_type(), output()->shape(), - AffineQuantization{}, ""); - } -} - -void Mean::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - case DataType::S16: - evalQuantizedS16(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Mean::evalFloat() const -{ - const Shape &input_shape = input()->shape(); - int input_num_dims = input_shape.num_dims(); - const auto *axes_data = getTensorData<int32_t>(axes()); - int num_axes = axes()->shape().num_elements(); - - tflite::MeanParams params{}; - resolveAxes(axes_data, num_axes, ¶ms); - - // Defer to specialized implementation for 4D Mean across axes 1 & 2. - if (_params.keep_dims && input_num_dims == 4 && params.axis_count == 2 && - ((params.axis[0] == 1 && params.axis[1] == 2) || - (params.axis[0] == 2 && params.axis[1] == 1))) - { - tflite::reference_ops::Mean(params, getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); - } - else - { - tflite::reference_ops::Mean( - getTensorData<float>(input()), getTensorShape(input()).DimsData(), - input()->shape().num_dims(), getTensorData<float>(output()), - getTensorShape(output()).DimsData(), output()->shape().num_dims(), axes_data, num_axes, - _params.keep_dims, getTensorData<int>(_temp_index.get()), - getTensorData<int>(_resolved_axes.get()), getTensorData<float>(_temp_sum.get())); - } -} - -void Mean::evalQuantized() const -{ - const Shape &input_shape = input()->shape(); - int input_num_dims = input_shape.num_dims(); - const auto *axes_data = getTensorData<int32_t>(axes()); - int num_axes = axes()->shape().num_elements(); - - tflite::MeanParams params{}; - resolveAxes(axes_data, num_axes, ¶ms); - - // Defer to specialized implementation for 4D Mean across axes 1 & 2. - if (_params.keep_dims && input_num_dims == 4 && params.axis_count == 2 && - ((params.axis[0] == 1 && params.axis[1] == 2) || - (params.axis[0] == 2 && params.axis[1] == 1))) - { - tflite::reference_ops::Mean(params, getTensorShape(input()), getTensorData<uint8_t>(input()), - input()->zero_point(), input()->scale(), getTensorShape(output()), - getTensorData<uint8_t>(output()), output()->zero_point(), - output()->scale()); - } - else if (input()->zero_point() == output()->zero_point() && input()->scale() == output()->scale()) - { - tflite::reference_ops::Mean( - getTensorData<uint8_t>(input()), getTensorShape(input()).DimsData(), - input()->shape().num_dims(), getTensorData<uint8_t>(output()), - getTensorShape(output()).DimsData(), output()->shape().num_dims(), axes_data, num_axes, - _params.keep_dims, getTensorData<int>(_temp_index.get()), - getTensorData<int>(_resolved_axes.get()), getTensorData<int>(_temp_sum.get())); - } - else - { - tflite::reference_ops::QuantizedMeanOrSum<>( - getTensorData<uint8_t>(input()), input()->zero_point(), input()->scale(), - getTensorShape(input()).DimsData(), input()->shape().num_dims(), - getTensorData<uint8_t>(output()), output()->zero_point(), output()->scale(), - getTensorShape(output()).DimsData(), output()->shape().num_dims(), axes_data, num_axes, - _params.keep_dims, getTensorData<int>(_temp_index.get()), - getTensorData<int>(_resolved_axes.get()), getTensorData<int>(_temp_sum.get()), - /*compute_sum=*/false); - } -} - -void Mean::evalQuantizedS16() const -{ - const auto *input_data = getTensorData<int16_t>(input()); - auto *output_data = getTensorData<int16_t>(output()); - - const Shape &input_shape = input()->shape(); - const Shape &output_shape = output()->shape(); - - const auto *axes_data = getTensorData<int32_t>(axes()); - const int num_axes = axes()->shape().num_elements(); - - constexpr int32_t output_min = -std::numeric_limits<int16_t>::max(); - constexpr int32_t output_max = std::numeric_limits<int16_t>::max(); - - // Defer to specialized implementation for 4D Mean across axes 1 & 2. - if (_params.keep_dims && input_shape.num_dims() == 4 && num_axes == 2 && - ((axes_data[0] == 1 && axes_data[1] == 2) || (axes_data[0] == 2 && axes_data[1] == 1))) - { - const int32_t batches = input_shape.dim(0); - const int32_t input_height = input_shape.dim(1); - const int32_t input_width = input_shape.dim(2); - const int32_t depth = input_shape.dim(3); - assert(output_shape.num_dims() == 4); - assert(output_shape.dim(0) == batches); - assert(output_shape.dim(1) == 1); - assert(output_shape.dim(2) == 1); - assert(output_shape.dim(3) == depth); - - const double real_multiplier = - static_cast<double>(input()->scale()) / static_cast<double>(output()->scale()); - - int32_t output_multiplier{}; - int output_shift{}; - quantizeMultiplier(real_multiplier, &output_multiplier, &output_shift); - - const int32_t num_elements_in_axes = input_height * input_width; - - for (int32_t batch = 0; batch < batches; ++batch) - { - for (int32_t c = 0; c < depth; ++c) - { - int32_t acc = 0; - for (int32_t in_y = 0; in_y < input_height; ++in_y) - { - for (int32_t in_x = 0; in_x < input_width; ++in_x) - { - acc += input_data[calcOffset(input_shape, batch, in_y, in_x, c)]; - } - } - int32_t scaled_acc = - tflite::MultiplyByQuantizedMultiplier(acc, output_multiplier, output_shift); - // Divide by the number of elements rounding to the nearest integer. - scaled_acc = scaled_acc > 0 - ? (scaled_acc + num_elements_in_axes / 2) / num_elements_in_axes - : (scaled_acc - num_elements_in_axes / 2) / num_elements_in_axes; - - scaled_acc = std::max(scaled_acc, output_min); - scaled_acc = std::min(scaled_acc, output_max); - - output_data[calcOffset(output_shape, batch, 0, 0, c)] = scaled_acc; - } - } - } - else - { - throw std::runtime_error("Unsupported configuration."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Mean.h b/compiler/luci-interpreter/src/kernels/Mean.h deleted file mode 100644 index 1cc046894..000000000 --- a/compiler/luci-interpreter/src/kernels/Mean.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_MEAN_H -#define LUCI_INTERPRETER_KERNELS_MEAN_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -#include <memory> - -namespace luci_interpreter -{ -namespace kernels -{ - -class Mean : public KernelWithParams<ReducerParams> -{ -public: - Mean(const Tensor *input, const Tensor *axes, Tensor *output, const ReducerParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *axes() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void evalQuantizedS16() const; - -private: - std::unique_ptr<Tensor> _temp_index; - std::unique_ptr<Tensor> _resolved_axes; - std::unique_ptr<Tensor> _temp_sum; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_MEAN_H diff --git a/compiler/luci-interpreter/src/kernels/Mean.test.cpp b/compiler/luci-interpreter/src/kernels/Mean.test.cpp deleted file mode 100644 index e81d2ad5f..000000000 --- a/compiler/luci-interpreter/src/kernels/Mean.test.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Mean.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(MeanTest, FloatKeepDims) -{ - std::vector<float> input_data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, - 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, - 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; - - std::vector<int32_t> axis_data{0, 2}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({4, 3, 2}, input_data); - Tensor axis_tensor = makeInputTensor<DataType::S32>({2}, axis_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ReducerParams params{}; - params.keep_dims = true; - - Mean kernel(&input_tensor, &axis_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{10.5, 12.5, 14.5}; - std::initializer_list<int32_t> ref_output_shape{1, 3, 1}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(MeanTest, FloatKeepDims4DMean) -{ - std::vector<float> input_data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, - 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, - 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; - - std::vector<int32_t> axis_data{1, 2}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 2, 3, 2}, input_data); - Tensor axis_tensor = makeInputTensor<DataType::S32>({2}, axis_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ReducerParams params{}; - params.keep_dims = true; - - Mean kernel(&input_tensor, &axis_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{6, 7, 18, 19}; - std::initializer_list<int32_t> ref_output_shape{2, 1, 1, 2}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(MeanTest, FloatNotKeepDims) -{ - std::vector<float> input_data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, - 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, - 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; - - std::vector<int32_t> axis_data{1, 0, -3, -3}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({4, 3, 2}, input_data); - Tensor axis_tensor = makeInputTensor<DataType::S32>({4}, axis_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ReducerParams params{}; - params.keep_dims = false; - - Mean kernel(&input_tensor, &axis_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{12, 13}; - std::initializer_list<int32_t> ref_output_shape{2}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(MeanTest, Uint8KeepDims) -{ - float kQuantizedTolerance = getTolerance(-1.0, 1.0, 255); - std::vector<float> input_data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-1.0f, 1.0f); - - std::vector<int32_t> axis_data{1}; - Tensor input_tensor = - makeInputTensor<DataType::U8>({3, 2}, quant_param.first, quant_param.second, input_data); - Tensor axis_tensor = makeInputTensor<DataType::S32>({1}, axis_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - ReducerParams params{}; - params.keep_dims = true; - - Mean kernel(&input_tensor, &axis_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{0.3, 0.35, 0.55}; - std::initializer_list<int32_t> ref_output_shape{3, 1}; - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(MeanTest, Uint8NotKeepDims) -{ - float kQuantizedTolerance = getTolerance(-1.0, 1.0, 255); - std::vector<float> input_data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-1.0f, 1.0f); - - std::vector<int32_t> axis_data{1}; - Tensor input_tensor = - makeInputTensor<DataType::U8>({1, 3, 2}, quant_param.first, quant_param.second, input_data); - Tensor axis_tensor = makeInputTensor<DataType::S32>({1}, axis_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - ReducerParams params{}; - params.keep_dims = false; - - Mean kernel(&input_tensor, &axis_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{0.4, 0.4}; - std::initializer_list<int32_t> ref_output_shape{1, 2}; - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST(MeanTest, SInt16KeepDims4D) -{ - std::vector<float> input_data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, - 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, - 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; - std::vector<int32_t> axes_data{1, 2}; - std::vector<float> ref_output_data{6, 7, 18, 19}; - - Tensor input_tensor = makeInputTensor<DataType::S16>({2, 2, 3, 2}, 0.25, 0, input_data); - Tensor axes_tensor = makeInputTensor<DataType::S32>({2}, axes_data); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.2, 0); - - ReducerParams params{}; - params.keep_dims = true; - - Mean kernel(&input_tensor, &axes_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 1, 1, 2})); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Minimum.cpp b/compiler/luci-interpreter/src/kernels/Minimum.cpp deleted file mode 100644 index 5eb13455e..000000000 --- a/compiler/luci-interpreter/src/kernels/Minimum.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2018 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Minimum.h" - -#include "kernels/Utils.h" - -#include "kernels/BinaryOpCommon.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -Minimum::Minimum(const Tensor *input1, const Tensor *input2, Tensor *output) - : Kernel({input1, input2}, {output}) -{ -} - -void Minimum::configure() -{ - LUCI_INTERPRETER_CHECK(input1()->element_type() == input2()->element_type()) - LUCI_INTERPRETER_CHECK(input1()->element_type() == output()->element_type()) - output()->resize(calculateShapeForBroadcast(input1()->shape(), input2()->shape())); -} - -void Minimum::execute() const -{ - switch (input1()->element_type()) - { - case DataType::FLOAT32: - evalMinimum<float>(); - break; - case DataType::U8: - evalMinimum<uint8_t>(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -template <typename T> inline void Minimum::evalMinimum() const -{ - BinaryOpBroadcastSlow(getTensorShape(input1()), getTensorData<T>(input1()), - getTensorShape(input2()), getTensorData<T>(input2()), - getTensorShape(output()), getTensorData<T>(output()), - [](T x, T y) { return std::min(x, y); }); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Minimum.h b/compiler/luci-interpreter/src/kernels/Minimum.h deleted file mode 100644 index 5ff4035b4..000000000 --- a/compiler/luci-interpreter/src/kernels/Minimum.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_MINIMUM_H -#define LUCI_INTERPRETER_KERNELS_MINIMUM_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Minimum : public Kernel -{ -public: - Minimum(const Tensor *input1, const Tensor *input2, Tensor *output); - - const Tensor *input1() const { return _inputs[0]; } - const Tensor *input2() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - template <typename T> inline void evalMinimum() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_MINIMUM_H diff --git a/compiler/luci-interpreter/src/kernels/Minimum.test.cpp b/compiler/luci-interpreter/src/kernels/Minimum.test.cpp deleted file mode 100644 index b6420dd9b..000000000 --- a/compiler/luci-interpreter/src/kernels/Minimum.test.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Minimum.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(MinimumTest, Float) -{ - Shape input_shape{3, 1, 2}; - std::vector<float> input_data1{1.0, 0.0, -1.0, 11.0, -2.0, -1.44}; - std::vector<float> input_data2{-1.0, 0.0, 1.0, 12.0, -3.0, -1.43}; - Tensor input_tensor1 = makeInputTensor<DataType::FLOAT32>(input_shape, input_data1); - Tensor input_tensor2 = makeInputTensor<DataType::FLOAT32>(input_shape, input_data2); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Minimum kernel(&input_tensor1, &input_tensor2, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{-1.0, 0.0, -1.0, 11.0, -3.0, -1.44}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(MinimumTest, Uint8) -{ - Shape input_shape{3, 1, 2}; - std::vector<uint8_t> input_data1{1, 0, 2, 11, 2, 23}; - std::vector<uint8_t> input_data2{0, 0, 1, 12, 255, 1}; - Tensor input_tensor1 = makeInputTensor<DataType::U8>(input_shape, input_data1); - Tensor input_tensor2 = makeInputTensor<DataType::U8>(input_shape, input_data2); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - Minimum kernel(&input_tensor1, &input_tensor2, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<int32_t> ref_output_shape{2, 4}; - EXPECT_THAT(extractTensorData<uint8_t>(output_tensor), - ::testing::ElementsAreArray({0, 0, 1, 11, 2, 1})); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Mul.cpp b/compiler/luci-interpreter/src/kernels/Mul.cpp deleted file mode 100644 index dd31aa099..000000000 --- a/compiler/luci-interpreter/src/kernels/Mul.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Mul.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> -#include <tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h> - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -Mul::Mul(const Tensor *input1, const Tensor *input2, Tensor *output, const MulParams ¶ms) - : KernelWithParams<MulParams>({input1, input2}, {output}, params) -{ -} - -void Mul::configure() -{ - assert(input1()->element_type() == input2()->element_type()); - output()->resize(calculateShapeForBroadcast(input1()->shape(), input2()->shape())); -} - -void Mul::execute() const -{ - switch (input1()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Mul::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::ArithmeticParams params{}; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - - const bool need_broadcast = tflite::reference_ops::ProcessBroadcastShapes( - getTensorShape(input1()), getTensorShape(input2()), ¶ms); - - if (need_broadcast) - { - tflite::optimized_ops::BroadcastMul4DSlow( - params, getTensorShape(input1()), getTensorData<float>(input1()), getTensorShape(input2()), - getTensorData<float>(input2()), getTensorShape(output()), getTensorData<float>(output())); - } - else - { - tflite::optimized_ops::Mul(params, getTensorShape(input1()), getTensorData<float>(input1()), - getTensorShape(input2()), getTensorData<float>(input2()), - getTensorShape(output()), getTensorData<float>(output())); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Mul.h b/compiler/luci-interpreter/src/kernels/Mul.h deleted file mode 100644 index e46160bcb..000000000 --- a/compiler/luci-interpreter/src/kernels/Mul.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_MUL_H -#define LUCI_INTERPRETER_KERNELS_MUL_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -#include <cstdint> -#include <vector> - -namespace luci_interpreter -{ -namespace kernels -{ - -class Mul : public KernelWithParams<MulParams> -{ -public: - Mul(const Tensor *input1, const Tensor *input2, Tensor *output, const MulParams ¶ms); - - const Tensor *input1() const { return _inputs[0]; } - const Tensor *input2() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_MUL_H diff --git a/compiler/luci-interpreter/src/kernels/Mul.test.cpp b/compiler/luci-interpreter/src/kernels/Mul.test.cpp deleted file mode 100644 index fbda3bece..000000000 --- a/compiler/luci-interpreter/src/kernels/Mul.test.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Mul.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(MulTest, Float) -{ - Shape base_shape = {2, 3, 1, 2}; - std::vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}}; - std::vector<std::vector<float>> test_outputs = { - {0.00f, 0.69f, 0.12f, 1.15f, 0.00f, 2.07f, 0.18f, 0.15f, 0.00f, 0.25f, 0.90f, 0.45f, - 0.16f, 0.00f, 0.00f, 0.00f, 0.80f, 0.00f, 0.24f, 0.84f, 0.00f, 1.40f, 1.20f, 2.52f, - 0.00f, 0.00f, 0.64f, 0.00f, 0.00f, 0.00f, 0.14f, 0.00f, 0.00f, 0.00f, 0.70f, 0.00f}, - {0.00f, 0.69f, 0.00f, 0.25f, 0.80f, 0.00f, 0.24f, 0.84f, 0.64f, 0.00f, 0.70f, 0.00f}, - {0.00f, 0.46f, 0.00f, 0.69f, 0.12f, 0.00f, 0.18f, 0.10f, 0.27f, 0.15f, 0.00f, 0.00f, - 0.16f, 0.00f, 0.24f, 0.00f, 0.00f, 0.44f, 0.60f, 1.40f, 1.20f, 2.80f, 1.08f, 2.52f, - 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.35f, 0.00f, 0.70f, 0.00f, 0.63f, 0.00f}, - {0.00f, 0.46f, 0.27f, 0.15f, 0.00f, 0.44f, 0.60f, 1.40f, 0.00f, 0.00f, 0.63f, 0.00f}}; - std::vector<float> input1_data{-0.3f, 2.3f, 0.9f, 0.5f, 0.8f, -1.1f, - 1.2f, 2.8f, -1.6f, 0.0f, 0.7f, -2.2f}; - std::vector<float> input2_data{0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f}; - for (size_t i = 0; i < test_shapes.size(); ++i) - { - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(test_shapes[i], input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - MulParams params{}; - params.activation = Activation::RELU; - - Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs[i], 0.0001f)) - << "With shape number " << i; - } - // Re-run with exchanged inputs. - for (size_t i = 0; i < test_shapes.size(); ++i) - { - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(test_shapes[i], input2_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input1_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - MulParams params{}; - params.activation = Activation::RELU; - - Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs[i], 0.0001f)) - << "With shape number " << i; - } -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/NotEqual.cpp b/compiler/luci-interpreter/src/kernels/NotEqual.cpp deleted file mode 100644 index cd2f6c2c1..000000000 --- a/compiler/luci-interpreter/src/kernels/NotEqual.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/NotEqual.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/comparisons.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -NotEqual::NotEqual(const Tensor *x, const Tensor *y, Tensor *output) : Kernel({x, y}, {output}) {} - -void NotEqual::configure() -{ - LUCI_INTERPRETER_CHECK(x()->element_type() == y()->element_type()); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::BOOL); - - if (x()->element_type() == DataType::U8) - { - quantizeMultiplierSmallerThanOneExp(x()->scale(), &_x_multiplier, &_x_shift); - quantizeMultiplierSmallerThanOneExp(y()->scale(), &_y_multiplier, &_y_shift); - } - output()->resize(calculateShapeForBroadcast(x()->shape(), y()->shape())); -} - -void NotEqual::execute() const -{ - switch (x()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void NotEqual::evalFloat() const -{ - const auto x_data = getTensorData<float>(x()); - const auto y_data = getTensorData<float>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowNotEqual(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::NotEqual(op_params, getTensorShape(x()), x_data, getTensorShape(y()), - y_data, getTensorShape(output()), output_data); - } -} - -void NotEqual::evalQuantized() const -{ - const auto x_data = getTensorData<uint8_t>(x()); - const auto y_data = getTensorData<uint8_t>(y()); - auto output_data = getTensorData<bool>(output()); - - tflite::ComparisonParams op_params; - op_params.left_shift = 8; - op_params.input1_offset = -x()->zero_point(); // Note the '-' - op_params.input1_shift = _x_shift; - op_params.input1_multiplier = _x_multiplier; - op_params.input2_offset = -y()->zero_point(); // Note the '-' - op_params.input2_shift = _y_shift; - op_params.input2_multiplier = _y_multiplier; - op_params.is_broadcast = x()->shape() != y()->shape(); - - if (op_params.is_broadcast) - { - tflite::reference_ops::Broadcast4DSlowNotEqualWithScaling( - op_params, getTensorShape(x()), x_data, getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } - else - { - tflite::reference_ops::NotEqualWithScaling(op_params, getTensorShape(x()), x_data, - getTensorShape(y()), y_data, - getTensorShape(output()), output_data); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/NotEqual.h b/compiler/luci-interpreter/src/kernels/NotEqual.h deleted file mode 100644 index d729c6c14..000000000 --- a/compiler/luci-interpreter/src/kernels/NotEqual.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_NOT_EQUAL_H -#define LUCI_INTERPRETER_KERNELS_NOT_EQUAL_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class NotEqual : public Kernel -{ -public: - NotEqual(const Tensor *x, const Tensor *y, Tensor *output); - - const Tensor *x() const { return _inputs[0]; } - const Tensor *y() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _x_multiplier = 0; - int32_t _x_shift = 0; - int32_t _y_multiplier = 0; - int32_t _y_shift = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_NOT_EQUAL_H diff --git a/compiler/luci-interpreter/src/kernels/NotEqual.test.cpp b/compiler/luci-interpreter/src/kernels/NotEqual.test.cpp deleted file mode 100644 index 8c8712371..000000000 --- a/compiler/luci-interpreter/src/kernels/NotEqual.test.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/NotEqual.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(NotEqualTest, FloatSimple) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - -1, 0, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - true, false, true, // Row 1 - true, false, true, // Row 2 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - NotEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 3})); -} - -TEST(NotEqualTest, FloatBroardcast) -{ - std::vector<float> x_data{ - 0.5, 0.7, 0.9, // Row 1 - 1, 0, -1, // Row 2 - -1, 0, 1, // Row 3 - 0.9, 0.7, 0.5, // Row 4 - }; - - std::vector<float> y_data{ - 0.9, 0.7, 0.5, // Row 1 - }; - - std::vector<bool> ref_output_data{ - true, false, true, // Row 1 - true, true, true, // Row 2 - true, true, true, // Row 3 - false, false, false, // Row 4 - }; - - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({4, 3}, x_data); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1, 3}, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - NotEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({4, 3})); -} - -// Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. -const float F_MIN = -128.0 / 128.0; -const float F_MAX = 127.0 / 128.0; - -TEST(NotEqualTest, Uint8Quantized) -{ - std::vector<float> x_data{ - 0.5, 0.5, 0.7, 0.9, // Row 1 - 1, 0, 0.05, -1, // Row 2 - }; - - std::vector<float> y_data{ - 0.9, 0.5, 0.55, 0.5, // Row 1 - -1, 0, 0.05, 1, // Row 2 - }; - - std::vector<bool> ref_output_data{ - true, false, true, true, // Row 1 - true, false, false, true, // Row 2 - }; - - std::pair<float, int32_t> x_quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, x_quant_param.first, - x_quant_param.second, x_data); - - std::pair<float, int32_t> y_quant_param = quantizationParams<uint8_t>(F_MIN * 2, F_MAX * 2); - Tensor y_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, y_quant_param.first, - y_quant_param.second, y_data); - - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - NotEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(NotEqualTest, Uint8QuantizedBroadcast) -{ - std::vector<float> x_data{ - 0.4, -0.8, 0.7, 0.3, // Row 1 - -0.5, 0.1, 0, 0.5, // Row 2 - 1, 0, 0.05, -1, // Row 3 - -1, 0.05, 0, 1, // Row 4 - }; - - std::vector<float> y_data{ - -1, 0.05, 0, 1, // Row 1 - }; - - std::vector<bool> ref_output_data{ - true, true, true, true, // Row 1 - true, true, false, true, // Row 2 - true, true, true, true, // Row 3 - false, false, false, false, // Row 4 - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(F_MIN, F_MAX); - Tensor x_tensor = - makeInputTensor<DataType::U8>({1, 4, 4, 1}, quant_param.first, quant_param.second, x_data); - Tensor y_tensor = - makeInputTensor<DataType::U8>({1, 1, 4, 1}, quant_param.first, quant_param.second, y_data); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - NotEqual kernel(&x_tensor, &y_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 4, 4, 1})); - EXPECT_THAT(extractTensorData<bool>(output_tensor), ::testing::ElementsAreArray(ref_output_data)); -} - -TEST(NotEqualTest, Input_Type_Mismatch_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::U8>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::BOOL); - - NotEqual kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(NotEqualTest, Input_Output_Type_NEG) -{ - Tensor x_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor y_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - NotEqual kernel(&x_tensor, &y_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Pad.cpp b/compiler/luci-interpreter/src/kernels/Pad.cpp deleted file mode 100644 index bdf3a2a95..000000000 --- a/compiler/luci-interpreter/src/kernels/Pad.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Pad.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -Pad::Pad(const Tensor *input, const Tensor *paddings, Tensor *output) - : Kernel({input, paddings}, {output}) -{ -} - -void Pad::configure() -{ - const Shape &input_shape = input()->shape(); - const int num_dims = input_shape.num_dims(); - - if (num_dims > 4) - throw std::runtime_error("Unsupported number of dimensions."); - - assert(output()->element_type() == input()->element_type()); - assert(paddings()->element_type() == DataType::S32); - // Paddings shape should be [N, 2]. - assert(paddings()->shape().num_dims() == 2); - assert(paddings()->shape().dim(0) == num_dims); - assert(paddings()->shape().dim(1) == 2); - - Shape output_shape(num_dims); - const auto *paddings_data = getTensorData<int32_t>(paddings()); - for (int i = 0; i < num_dims; ++i) - { - const int32_t padding_before = paddings_data[i * 2]; - const int32_t padding_after = paddings_data[i * 2 + 1]; - assert(padding_before >= 0 && padding_after >= 0); - output_shape.dim(i) = input_shape.dim(i) + padding_before + padding_after; - } - - output()->resize(output_shape); -} - -void Pad::execute() const -{ - const int num_dims = input()->shape().num_dims(); - - tflite::PadParams params{}; - params.left_padding_count = num_dims; - params.right_padding_count = num_dims; - - const auto *paddings_data = getTensorData<int32_t>(paddings()); - for (int i = num_dims - 1; i >= 0; --i) - { - params.left_padding[i] = paddings_data[i * 2]; - params.right_padding[i] = paddings_data[i * 2 + 1]; - } - - switch (input()->element_type()) - { - case DataType::FLOAT32: - { - const float pad_value = 0.0f; - tflite::reference_ops::Pad(params, getTensorShape(input()), getTensorData<float>(input()), - &pad_value, getTensorShape(output()), - getTensorData<float>(output())); - break; - } - case DataType::U8: - { - assert(output()->zero_point() >= std::numeric_limits<uint8_t>::min()); - assert(output()->zero_point() <= std::numeric_limits<uint8_t>::max()); - const auto pad_value = static_cast<uint8_t>(output()->zero_point()); - tflite::reference_ops::Pad(params, getTensorShape(input()), getTensorData<uint8_t>(input()), - &pad_value, getTensorShape(output()), - getTensorData<uint8_t>(output())); - break; - } - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Pad.h b/compiler/luci-interpreter/src/kernels/Pad.h deleted file mode 100644 index e05b47f29..000000000 --- a/compiler/luci-interpreter/src/kernels/Pad.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_PAD_H -#define LUCI_INTERPRETER_KERNELS_PAD_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Pad : public Kernel -{ -public: - Pad(const Tensor *input, const Tensor *paddings, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *paddings() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_PAD_H diff --git a/compiler/luci-interpreter/src/kernels/Pad.test.cpp b/compiler/luci-interpreter/src/kernels/Pad.test.cpp deleted file mode 100644 index 4bee07629..000000000 --- a/compiler/luci-interpreter/src/kernels/Pad.test.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Pad.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -float GetTolerance(float min, float max) { return (max - min) / 255.0; } - -TEST(Pad, Uint8) -{ - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-1.0f, 1.0f); - std::vector<float> input_data{-0.8, 0.2, 0.9, 0.7, 0.1, -0.3}; - std::vector<int32_t> paddings_data{0, 0, 0, 2, 1, 3, 0, 0}; - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 3, 1}, quant_param.first, - quant_param.second, input_data); - Tensor paddings_tensor = makeInputTensor<DataType::S32>({4, 2}, paddings_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Pad kernel(&input_tensor, &paddings_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 4, 7, 1})); -} - -TEST(Pad, Float) -{ - std::vector<float> input_data{1, 2, 3, 4, 5, 6}; - std::vector<int32_t> paddings_data{1, 0, 0, 2, 0, 3, 0, 0}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1, 2, 3, 1}, input_data); - Tensor paddings_tensor = makeInputTensor<DataType::S32>({4, 2}, paddings_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pad kernel(&input_tensor, &paddings_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5, - 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - std::initializer_list<int32_t> ref_output_shape{2, 4, 6, 1}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Pow.cpp b/compiler/luci-interpreter/src/kernels/Pow.cpp deleted file mode 100644 index afc10b80e..000000000 --- a/compiler/luci-interpreter/src/kernels/Pow.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Pow.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -Pow::Pow(const Tensor *input1, const Tensor *input2, Tensor *output) - : Kernel({input1, input2}, {output}) -{ -} - -void Pow::configure() -{ - LUCI_INTERPRETER_CHECK(input1()->element_type() == input2()->element_type()); - - output()->resize(calculateShapeForBroadcast(input1()->shape(), input2()->shape())); -} - -void Pow::execute() const -{ - switch (input1()->element_type()) - { - case DataType::FLOAT32: - eval<float>(); - break; - case DataType::S32: - eval<int32_t>(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -template <typename T> void Pow::eval() const -{ - tflite::ArithmeticParams params{}; - - const bool need_broadcast = tflite::reference_ops::ProcessBroadcastShapes( - getTensorShape(input1()), getTensorShape(input2()), ¶ms); - - if (need_broadcast) - { - tflite::reference_ops::BroadcastPow4DSlow(getTensorShape(input1()), getTensorData<T>(input1()), - getTensorShape(input2()), getTensorData<T>(input2()), - getTensorShape(output()), getTensorData<T>(output())); - } - else - { - tflite::reference_ops::Pow(getTensorShape(input1()), getTensorData<T>(input1()), - getTensorShape(input2()), getTensorData<T>(input2()), - getTensorShape(output()), getTensorData<T>(output())); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Pow.h b/compiler/luci-interpreter/src/kernels/Pow.h deleted file mode 100644 index 8ff865e40..000000000 --- a/compiler/luci-interpreter/src/kernels/Pow.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_POW_H -#define LUCI_INTERPRETER_KERNELS_POW_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Pow : public Kernel -{ -public: - Pow(const Tensor *input1, const Tensor *input2, Tensor *output); - - const Tensor *input1() const { return _inputs[0]; } - const Tensor *input2() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - template <typename T> void eval() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_POW_H diff --git a/compiler/luci-interpreter/src/kernels/Pow.test.cpp b/compiler/luci-interpreter/src/kernels/Pow.test.cpp deleted file mode 100644 index 69d8946c8..000000000 --- a/compiler/luci-interpreter/src/kernels/Pow.test.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Pow.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(PowTest, SimplePow) -{ - std::initializer_list<int32_t> base_shape = {1, 1, 3, 2}; - - std::vector<float> input1_data{0.3f, 2.3f, 0.9f, 0.5f, 0.8f, 1.1f}; - std::vector<float> input2_data{0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f}; - std::vector<float> test_outputs{0.786f, 1.2838f, 1.043f, 0.7071f, 0.8f, 1.08956f}; - - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pow kernel(&input1_tensor, &input2_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs, 0.0001f)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(base_shape)); -} - -TEST(PowTest, FloatBroadcastPow) -{ - std::initializer_list<int32_t> input1_shape = {1, 3}; - std::initializer_list<int32_t> input2_shape = {3, 1}; - - std::vector<float> input1_data{0.3f, 2.3f, 0.9f}; - std::vector<float> input2_data{0.2f, 0.3f, 0.4f}; - std::vector<float> test_outputs{0.786f, 1.18126f, 0.9791f, 0.6968f, 1.28386f, - 0.96888f, 0.6178f, 1.3953f, 0.9587f}; - - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(input1_shape, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(input2_shape, input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pow kernel(&input1_tensor, &input2_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs, 0.0001f)); -} - -TEST(PowTest, IntPow) -{ - std::initializer_list<int32_t> base_shape = {1, 3}; - - std::vector<int32_t> input_data{2, 3, 4}; - std::vector<int32_t> test_outputs{4, 27, 256}; - - Tensor input1_tensor = makeInputTensor<DataType::S32>(base_shape, input_data); - Tensor input2_tensor = makeInputTensor<DataType::S32>(base_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::S32); - - Pow kernel(&input1_tensor, &input2_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<int32_t>(output_tensor), ::testing::ElementsAreArray(test_outputs)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(base_shape)); -} - -TEST(PowTest, Input_Output_Type_NEG) -{ - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.0f}); - Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {4}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Pow kernel(&input1_tensor, &input2_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Prelu.cpp b/compiler/luci-interpreter/src/kernels/Prelu.cpp deleted file mode 100644 index e658d87b5..000000000 --- a/compiler/luci-interpreter/src/kernels/Prelu.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Prelu.h" - -#include "kernels/BinaryOpCommon.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Prelu::Prelu(const Tensor *input, const Tensor *alpha, Tensor *output) - : Kernel({input, alpha}, {output}) -{ -} - -void Prelu::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - LUCI_INTERPRETER_CHECK(alpha()->element_type() == output()->element_type()); - - if (input()->element_type() == DataType::U8 || input()->element_type() == DataType::S16) - { - if (input()->element_type() == DataType::S16) - { - LUCI_INTERPRETER_CHECK(input()->zero_point() == 0 && alpha()->zero_point() == 0 && - output()->zero_point() == 0); - } - double alpha_multiplier = input()->scale() * alpha()->scale() / output()->scale(); - quantizeMultiplier(alpha_multiplier, &_output_multiplier_alpha, &_output_shift_alpha); - double identity_multiplier = input()->scale() / output()->scale(); - quantizeMultiplier(identity_multiplier, &_output_multiplier_identity, &_output_shift_identity); - } - output()->resize(calculateShapeForBroadcast(input()->shape(), alpha()->shape())); -} - -void Prelu::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - case DataType::S16: - evalQuantizedS16(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Prelu::evalFloat() const -{ - const auto input_data = getTensorData<float>(input()); - const auto alpha_data = getTensorData<float>(alpha()); - const auto size = getTensorShape(input()).FlatSize(); - auto output_data = getTensorData<float>(output()); - - auto PreluFunc = [](float input, float alpha) { return input >= 0.0 ? input : input * alpha; }; - - if (input()->shape() != alpha()->shape()) - { - tflite::reference_ops::BroadcastBinaryFunction4DSlow<float, float, float>( - getTensorShape(input()), getTensorData<float>(input()), getTensorShape(alpha()), - getTensorData<float>(alpha()), getTensorShape(output()), getTensorData<float>(output()), - PreluFunc); - } - else - { - for (auto i = decltype(size){0}; i < size; ++i) - { - if (input_data[i] >= 0) - output_data[i] = input_data[i]; - else - output_data[i] = input_data[i] * alpha_data[i]; - } - } -} - -void Prelu::evalQuantized() const -{ - tflite::PreluParams op_params{}; - - op_params.input_offset = -input()->zero_point(); // Note the '-'. - op_params.alpha_offset = -alpha()->zero_point(); // Note the '-'. - op_params.output_offset = output()->zero_point(); - op_params.output_shift_1 = _output_shift_identity; - op_params.output_multiplier_1 = _output_multiplier_identity; - op_params.output_shift_2 = _output_shift_alpha; - op_params.output_multiplier_2 = _output_multiplier_alpha; - - if (input()->shape() != alpha()->shape()) - { - tflite::reference_ops::BroadcastPrelu4DSlow( - op_params, getTensorShape(input()), getTensorData<uint8_t>(input()), - getTensorShape(alpha()), getTensorData<uint8_t>(alpha()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - } - else - { - tflite::reference_ops::Prelu<uint8_t>(op_params, getTensorShape(input()), - getTensorData<uint8_t>(input()), getTensorShape(alpha()), - getTensorData<uint8_t>(alpha()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - } -} - -void Prelu::evalQuantizedS16() const -{ - constexpr int32_t quantized_min = std::numeric_limits<int16_t>::min(); - constexpr int32_t quantized_max = std::numeric_limits<int16_t>::max(); - - auto fn = [this, quantized_min, quantized_max](int16_t input_val, int16_t alpha_val) { - const int32_t output_val = - input_val >= 0 - ? tflite::MultiplyByQuantizedMultiplier(input_val, _output_multiplier_identity, - _output_shift_identity) - : tflite::MultiplyByQuantizedMultiplier(input_val * alpha_val, _output_multiplier_alpha, - _output_shift_alpha); - const int32_t clamped_output = std::min(quantized_max, std::max(quantized_min, output_val)); - return static_cast<int16_t>(clamped_output); - }; - - BinaryOpBroadcastSlow(getTensorShape(input()), getTensorData<int16_t>(input()), - getTensorShape(alpha()), getTensorData<int16_t>(alpha()), - getTensorShape(output()), getTensorData<int16_t>(output()), fn); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Prelu.h b/compiler/luci-interpreter/src/kernels/Prelu.h deleted file mode 100644 index c7911a63f..000000000 --- a/compiler/luci-interpreter/src/kernels/Prelu.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_PRELU_H -#define LUCI_INTERPRETER_KERNELS_PRELU_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Prelu : public Kernel -{ -public: - Prelu(const Tensor *input, const Tensor *alpha, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *alpha() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void evalQuantizedS16() const; - -private: - int32_t _output_multiplier_alpha = 0; - int32_t _output_shift_alpha = 0; - int32_t _output_multiplier_identity = 0; - int32_t _output_shift_identity = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_PRELU_H diff --git a/compiler/luci-interpreter/src/kernels/Prelu.test.cpp b/compiler/luci-interpreter/src/kernels/Prelu.test.cpp deleted file mode 100644 index 30702c826..000000000 --- a/compiler/luci-interpreter/src/kernels/Prelu.test.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Prelu.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> alpha_shape, - std::initializer_list<int32_t> output_shape, std::initializer_list<T> input_data, - std::initializer_list<T> alpha_data, std::initializer_list<T> output_data) -{ - constexpr DataType element_type = getElementType<T>(); - Tensor input_tensor = makeInputTensor<element_type>(input_shape, input_data); - Tensor alpha_tensor = makeInputTensor<element_type>(alpha_shape, alpha_data); - Tensor output_tensor = makeOutputTensor(element_type); - - Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); - - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<T>(output_tensor), ::testing::ElementsAreArray(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -TEST(PreluTest, FloatSimple) -{ - Check<float>(/*input_shape=*/{2, 3}, /*alpha_shape=*/{2, 3}, - /*output_shape=*/{2, 3}, - /*input_data=*/ - { - 0.0f, 1.0f, 3.0f, // Row 1 - 1.0f, -1.0f, -2.0f, // Row 2 - }, - /*alpha_data=*/ - { - 0.0f, 0.5f, 0.1f, // Row 1 - 0.0f, 0.5f, 0.1f, // Row 2 - }, - /*output_data=*/ - { - 0.0f, 1.0f, 3.0f, // Row 1 - 1.0f, -0.5f, -0.2f, // Row 2 - }); - - SUCCEED(); -} - -TEST(PreluTest, FloatBroadcast) -{ - Check<float>(/*input_shape=*/{1, 2, 2, 3}, /*alpha_shape=*/{1, 1, 3}, - /*output_shape=*/{1, 2, 2, 3}, - /*input_data=*/ - { - 0.0f, 0.0f, 0.0f, // Row 1, Column 1 - 1.0f, 1.0f, 1.0f, // Row 1, Column 2 - -1.0f, -1.0f, -1.0f, // Row 2, Column 1 - -2.0f, -2.0f, -2.0f, // Row 2, Column 2 - }, - /*alpha_data=*/ - {0.0f, 1.0f, 2.0f}, - /*output_data=*/ - { - 0.0f, 0.0f, 0.0f, // Row 1, Column 1 - 1.0f, 1.0f, 1.0f, // Row 1, Column 2 - 0.0f, -1.0f, -2.0f, // Row 2, Column 1 - 0.0f, -2.0f, -4.0f, // Row 2, Column 2 - }); - - SUCCEED(); -} - -float GetTolerance(float min, float max) { return (max - min) / 255.0; } - -TEST(PreluTest, Uint8Simple) -{ - std::vector<float> input_data{-0.8f, 0.2f, 0.9f, 0.7f, 0.1f, -0.4f}; - std::vector<float> alpha_data{0.5f, 0.5f, 0.5f, 0.25f, 1.0f, 0.25f}; - std::vector<float> ref_output_data{-0.4f, 0.2f, 0.9f, 0.7f, 0.1f, -0.1f}; - - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-1.0f, 1.0f); - - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 3, 1}, quant_param.first, - quant_param.second, input_data); - Tensor alpha_tensor = makeInputTensor<DataType::U8>({1, 2, 3, 1}, quant_param.first, - quant_param.second, alpha_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 3, 1})); - - SUCCEED(); -} - -TEST(PreluTest, Uint8Broadcast) -{ - std::vector<float> input_data{ - 0.0f, 0.0f, 0.0f, // Row 1, Column 1 - 0.5f, 0.5f, 0.5f, // Row 1, Column 2 - -1.0f, -1.0f, -1.0f, // Row 2, Column 1 - -0.25f, -0.25f, -0.25f, // Row 2, Column 2 - }; - std::vector<float> alpha_data{0.0f, 0.5f, -0.5f}; - std::vector<float> ref_output_data{ - 0.0f, 0.0f, 0.0f, // Row 1, Column 1 - 0.5f, 0.5f, 0.5f, // Row 1, Column 2 - 0.0f, -0.5f, 0.5f, // Row 2, Column 1 - 0.0f, -0.125f, 0.125f // Row 2, Column 2 - }; - std::vector<float> ref_quant_output_data{ - 128, 128, 128, // Row 1, Column 1 - 192, 192, 192, // Row 1, Column 2 - 128, 64, 192, // Row 2, Column 1 - 128, 112, 144 // Row 2, Column 2 - }; - float kQuantizedTolerance = 2 * (1. / 256); - const float kMin = -1; - const float kMax = 127.f / 128.f; - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(kMin, kMax); - - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 2, 3}, quant_param.first, - quant_param.second, input_data); - Tensor alpha_tensor = - makeInputTensor<DataType::U8>({1, 1, 3}, quant_param.first, quant_param.second, alpha_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 2, 3})); - EXPECT_THAT(extractTensorData<uint8_t>(output_tensor), - ::testing::ElementsAreArray(ref_quant_output_data)); -} - -TEST(PreluTest, SInt16Simple) -{ - std::vector<float> input_data{-0.8f, 0.2f, 0.9f, 0.7f, 0.1f, -0.4f}; - std::vector<float> alpha_data{0.5f, 0.5f, 0.5f, 0.25f, 1.0f, 0.25f}; - std::vector<float> ref_output_data{-0.4f, 0.2f, 0.9f, 0.7f, 0.1f, -0.1f}; - - Tensor input_tensor = makeInputTensor<DataType::S16>({1, 2, 3, 1}, 0.1, 0, input_data); - Tensor alpha_tensor = makeInputTensor<DataType::S16>({1, 2, 3, 1}, 0.1, 0, alpha_data); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.1, 0); - - Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 3, 1})); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(PreluTest, SInt16Broadcast) -{ - std::vector<float> input_data{ - 0.0f, 0.0f, 0.0f, // Row 1, Column 1 - 0.5f, 0.5f, 0.5f, // Row 1, Column 2 - -1.0f, -1.0f, -1.0f, // Row 2, Column 1 - -0.25f, -0.25f, -0.25f, // Row 2, Column 2 - }; - std::vector<float> alpha_data{0.0f, 0.5f, -0.5f}; - std::vector<float> ref_output_data{ - 0.0f, 0.0f, 0.0f, // Row 1, Column 1 - 0.5f, 0.5f, 0.5f, // Row 1, Column 2 - 0.0f, -0.5f, 0.5f, // Row 2, Column 1 - 0.0f, -0.125f, 0.125f // Row 2, Column 2 - }; - - Tensor input_tensor = makeInputTensor<DataType::S16>({1, 2, 2, 3}, 0.01, 0, input_data); - Tensor alpha_tensor = makeInputTensor<DataType::S16>({1, 1, 3}, 0.1, 0, alpha_data); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.001, 0); - - Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 2, 3})); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(PreluTest, Input_Output_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor alpha_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(PreluTest, Input_Alpha_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor alpha_tensor = makeInputTensor<DataType::U8>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(PreluTest, Invalid_Input_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor alpha_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Relu.cpp b/compiler/luci-interpreter/src/kernels/Relu.cpp deleted file mode 100644 index a2e02d708..000000000 --- a/compiler/luci-interpreter/src/kernels/Relu.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Relu.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Relu::Relu(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Relu::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - if (input()->element_type() == DataType::S16) - { - LUCI_INTERPRETER_CHECK(input()->zero_point() == 0 && output()->zero_point() == 0); - } - - if (input()->element_type() == DataType::U8 || input()->element_type() == DataType::S16) - { - double multiplier = input()->scale() / output()->scale(); - quantizeMultiplier(multiplier, &_output_multiplier, &_output_shift); - } - output()->resize(input()->shape()); -} - -void Relu::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - case DataType::S16: - evalQuantizedS16(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Relu::evalFloat() const -{ - const auto input_data = getTensorData<float>(input()); - const auto input_shape = getTensorShape(input()); - auto output_data = getTensorData<float>(output()); - auto output_shape = getTensorShape(output()); - - tflite::optimized_ops::Relu(input_shape, input_data, output_shape, output_data); -} - -void Relu::evalQuantized() const -{ - tflite::ReluParams params; - params.input_offset = input()->zero_point(); - params.output_offset = output()->zero_point(); - params.output_multiplier = _output_multiplier; - params.output_shift = _output_shift; - - params.quantized_activation_min = - std::max(static_cast<int32_t>(std::numeric_limits<uint8_t>::min()), params.output_offset); - params.quantized_activation_max = static_cast<int32_t>(std::numeric_limits<uint8_t>::max()); - - tflite::optimized_ops::ReluX(params, getTensorShape(input()), getTensorData<uint8_t>(input()), - getTensorShape(output()), getTensorData<uint8_t>(output())); -} - -void Relu::evalQuantizedS16() const -{ - const auto *input_data = getTensorData<int16_t>(input()); - auto *output_data = getTensorData<int16_t>(output()); - - constexpr int32_t output_min = 0; - constexpr int32_t output_max = std::numeric_limits<int16_t>::max(); - - const int32_t num_elements = input()->shape().num_elements(); - - for (int32_t i = 0; i < num_elements; ++i) - { - const int32_t input_val = input_data[i]; - int32_t output_val = - tflite::MultiplyByQuantizedMultiplier(input_val, _output_multiplier, _output_shift); - output_val = std::max(output_val, output_min); - output_val = std::min(output_val, output_max); - output_data[i] = static_cast<int16_t>(output_val); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Relu.h b/compiler/luci-interpreter/src/kernels/Relu.h deleted file mode 100644 index b813f0cdf..000000000 --- a/compiler/luci-interpreter/src/kernels/Relu.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_RELU_H -#define LUCI_INTERPRETER_KERNELS_RELU_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Relu : public Kernel -{ -public: - Relu(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void evalQuantizedS16() const; - -private: - int32_t _output_multiplier{0}; - int32_t _output_shift{0}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_RELU_H diff --git a/compiler/luci-interpreter/src/kernels/Relu.test.cpp b/compiler/luci-interpreter/src/kernels/Relu.test.cpp deleted file mode 100644 index cabefa733..000000000 --- a/compiler/luci-interpreter/src/kernels/Relu.test.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Relu.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(ReluTest, FloatSimple) -{ - std::vector<float> input_data{ - 0.0f, 1.0f, 3.0f, // Row 1 - 1.0f, -1.0f, -2.0f, // Row 2 - }; - - std::vector<float> ref_output_data{ - 0.0f, 1.0f, 3.0f, // Row 1 - 1.0f, 0.0f, 0.0f, // Row 2 - }; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Relu kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 3})); -} - -TEST(ReluTest, Uint8Quantized) -{ - std::vector<float> input_data{ - 0, -6, 2, 4, // - 3, -2, 7, 1, // - }; - // Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. - const float f_min = (-128.0 / 128.0) * 8; - const float f_max = (127.0 / 128.0) * 8; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(f_min, f_max); - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, - quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Relu kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<uint8_t>(output_tensor), - ::testing::ElementsAreArray({128, 128, 160, 192, 176, 128, 240, 144})); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear({0, 0, 2, 4, 3, 0, 7, 1})); -} - -TEST(ReluTest, Uint8Requantized) -{ - std::vector<float> input_data{ - 0, -6, 2, 4, // - 3, -2, 7, 1, // - }; - - // Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. - const float in_min = (-128.0 / 128.0) * 8; - const float in_max = (127.0 / 128.0) * 8; - const float out_min = (0.0 / 256.0) * 8; - const float out_max = (255.0 / 256.0) * 8; - - std::pair<float, int32_t> quant_input = quantizationParams<uint8_t>(in_min, in_max); - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_input.first, - quant_input.second, input_data); - - std::pair<float, int32_t> quant_output = quantizationParams<uint8_t>(out_min, out_max); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_output.first, quant_output.second); - - Relu kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<uint8_t>(output_tensor), - ::testing::ElementsAreArray({0, 0, 64, 128, 96, 0, 224, 32})); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear({0, 0, 2, 4, 3, 0, 7, 1})); -} - -TEST(ReluTest, SInt16) -{ - std::vector<float> input_data{ - 0, -6, 2, 4, // - 3, -2, 7, 1, // - }; - std::vector<float> ref_output_data{ - 0, 0, 2, 4, // - 3, 0, 7, 1, // - }; - - Tensor input_tensor = makeInputTensor<DataType::S16>({1, 2, 4, 1}, 0.5, 0, input_data); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.25, 0); - - Relu kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(ReluTest, Input_Output_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - Relu kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ReluTest, Invalid_Input_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - Relu kernel(&input_tensor, &output_tensor); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Relu6.cpp b/compiler/luci-interpreter/src/kernels/Relu6.cpp deleted file mode 100644 index 1046ef27b..000000000 --- a/compiler/luci-interpreter/src/kernels/Relu6.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Relu6.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Relu6::Relu6(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Relu6::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - - if (input()->element_type() == DataType::U8) - { - double multiplier = input()->scale() / output()->scale(); - quantizeMultiplier(multiplier, &_output_multiplier, &_output_shift); - } - output()->resize(input()->shape()); -} - -void Relu6::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Relu6::evalFloat() const -{ - const auto input_data = getTensorData<float>(input()); - const auto input_shape = getTensorShape(input()); - auto output_data = getTensorData<float>(output()); - auto output_shape = getTensorShape(output()); - - tflite::optimized_ops::Relu6(input_shape, input_data, output_shape, output_data); -} - -void Relu6::evalQuantized() const -{ - tflite::ReluParams params; - params.input_offset = input()->zero_point(); - params.output_offset = output()->zero_point(); - params.output_multiplier = _output_multiplier; - params.output_shift = _output_shift; - - params.quantized_activation_min = - std::max(static_cast<int32_t>(std::numeric_limits<uint8_t>::min()), params.output_offset); - params.quantized_activation_max = - std::min(static_cast<int32_t>(std::numeric_limits<uint8_t>::max()), - params.output_offset + static_cast<int32>(roundf(6.f / output()->scale()))); - - tflite::optimized_ops::ReluX(params, getTensorShape(input()), getTensorData<uint8_t>(input()), - getTensorShape(output()), getTensorData<uint8_t>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Relu6.h b/compiler/luci-interpreter/src/kernels/Relu6.h deleted file mode 100644 index f5030b588..000000000 --- a/compiler/luci-interpreter/src/kernels/Relu6.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_RELU6_H -#define LUCI_INTERPRETER_KERNELS_RELU6_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Relu6 : public Kernel -{ -public: - Relu6(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - int32_t _output_multiplier{0}; - int32_t _output_shift{0}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_RELU6_H diff --git a/compiler/luci-interpreter/src/kernels/Relu6.test.cpp b/compiler/luci-interpreter/src/kernels/Relu6.test.cpp deleted file mode 100644 index a7f104d85..000000000 --- a/compiler/luci-interpreter/src/kernels/Relu6.test.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Relu6.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(Relu6Test, FloatSimple) -{ - std::vector<float> input_data{ - 0.0f, 1.0f, 3.0f, // Row 1 - 7.0f, -1.0f, -2.0f, // Row 2 - }; - - std::vector<float> ref_output_data{ - 0.0f, 1.0f, 3.0f, // Row 1 - 6.0f, 0.0f, 0.0f, // Row 2 - }; - - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 3}, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Relu6 kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 3})); -} - -TEST(Relu6Test, Uint8Quantized) -{ - // Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. - const float f_min = (-128.0 / 128.0) * 10; - const float f_max = (127.0 / 128.0) * 10; - const float tolerance = (f_max - f_min) / 255.0; - - std::vector<float> input_data{ - 0, -6, 2, 8, // - -2, 3, 7, 1, // - }; - - std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(f_min, f_max); - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_param.first, - quant_param.second, input_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Relu6 kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<uint8_t>(output_tensor), - ::testing::ElementsAreArray({128, 128, 154, 205, 128, 166, 205, 141})); - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear({0, 0, 2, 6, 0, 3, 6, 1}, tolerance)); -} - -TEST(Relu6Test, Uint8Requantized) -{ - // Choose min / max in such a way that there are exactly 256 units to avoid rounding errors. - const float in_min = (-128.0 / 128.0) * 10; - const float in_max = (127.0 / 128.0) * 10; - const float out_min = (0.0 / 256.0) * 0; - const float out_max = (255.0 / 256.0) * 6; - const float tolerance = (in_max - in_min) / 255.0; - - std::vector<float> input_data{ - 0, -6, 2, 8, // - -2, 3, 7, 1, // - }; - - std::pair<float, int32_t> quant_input = quantizationParams<uint8_t>(in_min, in_max); - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 4, 1}, quant_input.first, - quant_input.second, input_data); - - std::pair<float, int32_t> quant_output = quantizationParams<uint8_t>(out_min, out_max); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_output.first, quant_output.second); - - Relu6 kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 4, 1})); - EXPECT_THAT(extractTensorData<uint8_t>(output_tensor), - ::testing::ElementsAreArray({0, 0, 87, 255, 0, 127, 255, 43})); - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear({0, 0, 2, 6, 0, 3, 6, 1}, tolerance)); -} - -TEST(Relu6Test, Input_Output_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::U8); - - Relu6 kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(Relu6Test, Invalid_Input_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - Relu6 kernel(&input_tensor, &output_tensor); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Reshape.cpp b/compiler/luci-interpreter/src/kernels/Reshape.cpp deleted file mode 100644 index d88b5392a..000000000 --- a/compiler/luci-interpreter/src/kernels/Reshape.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Reshape.h" - -#include <cassert> -#include <cstring> - -namespace luci_interpreter -{ - -namespace kernels -{ - -static Shape extractShapeFromTensor(const Tensor *tensor) -{ - assert(tensor->element_type() == DataType::S32); - Shape shape(tensor->shape().num_elements()); - const auto *shape_data = tensor->data<int32_t>(); - for (int i = 0; i < tensor->shape().num_elements(); ++i) - { - shape.dim(i) = shape_data[i]; - } - return shape; -} - -static void resolveUnknownDimension(const Shape &input_shape, Shape *output_shape) -{ - const int32_t num_input_elements = input_shape.num_elements(); - int32_t num_output_elements = 1; - int unknown_dim_index = -1; - for (int i = 0; i < output_shape->num_dims(); ++i) - { - const int32_t value = output_shape->dim(i); - if (value == -1) - { - assert(unknown_dim_index == -1); - unknown_dim_index = i; - } - else - { - num_output_elements *= value; - } - } - if (unknown_dim_index != -1) - { - output_shape->dim(unknown_dim_index) = num_input_elements / num_output_elements; - num_output_elements *= output_shape->dim(unknown_dim_index); - } - assert(num_output_elements == num_input_elements); -} - -Reshape::Reshape(const Tensor *input, const Tensor *shape, Tensor *output) - : Kernel({input, shape}, {output}) -{ -} - -void Reshape::configure() -{ - Shape output_shape = extractShapeFromTensor(shape()); - resolveUnknownDimension(input()->shape(), &output_shape); - output()->resize(output_shape); -} - -void Reshape::execute() const -{ - const auto *input_data = input()->data<void>(); - auto *output_data = output()->data<void>(); - - const size_t element_size = getDataTypeSize(input()->element_type()); - const int32_t num_elements = input()->shape().num_elements(); - std::memcpy(output_data, input_data, num_elements * element_size); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Reshape.h b/compiler/luci-interpreter/src/kernels/Reshape.h deleted file mode 100644 index 99b947f77..000000000 --- a/compiler/luci-interpreter/src/kernels/Reshape.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_RESHAPE_H -#define LUCI_INTERPRETER_KERNELS_RESHAPE_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Reshape : public Kernel -{ -public: - Reshape(const Tensor *input, const Tensor *shape, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *shape() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_RESHAPE_H diff --git a/compiler/luci-interpreter/src/kernels/Reshape.test.cpp b/compiler/luci-interpreter/src/kernels/Reshape.test.cpp deleted file mode 100644 index 38159380f..000000000 --- a/compiler/luci-interpreter/src/kernels/Reshape.test.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Reshape.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -// TODO Test types other than FLOAT32. - -TEST(ReshapeTest, Regular) -{ - Shape input_shape{1, 2, 2, 3}; - std::vector<float> input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - Shape shape_shape{2}; - std::vector<int32_t> shape_data{3, 4}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor shape_tensor = makeInputTensor<DataType::S32>(shape_shape, shape_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Reshape kernel(&input_tensor, &shape_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(input_data)); -} - -TEST(ReshapeTest, UnknownDimension) -{ - Shape input_shape{2, 1, 2, 3}; - std::vector<float> input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - Shape shape_shape{3}; - std::vector<int32_t> shape_data{2, -1, 2}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor shape_tensor = makeInputTensor<DataType::S32>(shape_shape, shape_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Reshape kernel(&input_tensor, &shape_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(input_data)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/ResizeBilinear.cpp b/compiler/luci-interpreter/src/kernels/ResizeBilinear.cpp deleted file mode 100644 index 9385855cf..000000000 --- a/compiler/luci-interpreter/src/kernels/ResizeBilinear.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/ResizeBilinear.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -ResizeBilinear::ResizeBilinear(const Tensor *input, const Tensor *size, Tensor *output, - const ResizeBilinearParams ¶ms) - : KernelWithParams<ResizeBilinearParams>({input, size}, {output}, params) -{ -} - -void ResizeBilinear::configure() -{ - LUCI_INTERPRETER_CHECK(input()->shape().num_dims() == 4); - LUCI_INTERPRETER_CHECK(size()->shape().num_dims() == 1); - LUCI_INTERPRETER_CHECK(size()->element_type() == DataType::S32); - if (params().half_pixel_centers && params().align_corners) - throw std::runtime_error("If half_pixel_centers is True, align_corners must be False."); - LUCI_INTERPRETER_CHECK(size()->shape().dim(0) == 2); - Shape output_shape(4); - output_shape.dim(0) = input()->shape().dim(0); - output_shape.dim(1) = getTensorData<int32_t>(size())[0]; - output_shape.dim(2) = getTensorData<int32_t>(size())[1]; - output_shape.dim(3) = input()->shape().dim(3); - output()->resize(output_shape); -} - -void ResizeBilinear::execute() const -{ - tflite::ResizeBilinearParams op_params{}; - op_params.align_corners = params().align_corners; - op_params.half_pixel_centers = params().half_pixel_centers; - switch (output()->element_type()) - { - case DataType::FLOAT32: - tflite::optimized_ops::ResizeBilinear( - op_params, getTensorShape(input()), getTensorData<float>(input()), getTensorShape(size()), - getTensorData<int32_t>(size()), getTensorShape(output()), getTensorData<float>(output())); - break; - case DataType::U8: - tflite::optimized_ops::ResizeBilinear( - op_params, getTensorShape(input()), getTensorData<uint8_t>(input()), - getTensorShape(size()), getTensorData<int32_t>(size()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/ResizeBilinear.h b/compiler/luci-interpreter/src/kernels/ResizeBilinear.h deleted file mode 100644 index b7bdc2ab7..000000000 --- a/compiler/luci-interpreter/src/kernels/ResizeBilinear.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_RESIZEBILINEAR_H -#define LUCI_INTERPRETER_KERNELS_RESIZEBILINEAR_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class ResizeBilinear : public KernelWithParams<ResizeBilinearParams> -{ -public: - ResizeBilinear(const Tensor *input, const Tensor *shape, Tensor *output, - const ResizeBilinearParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *size() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_RESIZEBILINEAR_H diff --git a/compiler/luci-interpreter/src/kernels/ResizeBilinear.test.cpp b/compiler/luci-interpreter/src/kernels/ResizeBilinear.test.cpp deleted file mode 100644 index 51c1359da..000000000 --- a/compiler/luci-interpreter/src/kernels/ResizeBilinear.test.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/ResizeBilinear.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> size_shape, - std::initializer_list<int32_t> output_shape, std::initializer_list<float> input_data, - std::initializer_list<int32_t> size_data, std::initializer_list<float> output_data, - bool align_corners, bool half_pixel_centers) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor size_tensor = makeInputTensor<DataType::S32>(size_shape, size_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeBilinearParams params{}; - params.align_corners = align_corners; - params.half_pixel_centers = half_pixel_centers; - - ResizeBilinear kernel(&input_tensor, &size_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(extractTensorData<T>(output_tensor), FloatArrayNear(output_data)); -} - -template <> -void Check<uint8_t>(std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> size_shape, - std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, - std::initializer_list<int32_t> size_data, - std::initializer_list<float> output_data, bool align_corners, - bool half_pixel_centers) -{ - // On TFlite example use Uint8 value it self, so this means quant param scale 1.0f and zero - // point 0. - Tensor input_tensor = makeInputTensor<DataType::U8>(input_shape, 1.0, 0, input_data); - Tensor size_tensor = makeInputTensor<DataType::S32>(size_shape, size_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1.0, 0); - - ResizeBilinearParams params{}; - params.align_corners = align_corners; - params.half_pixel_centers = half_pixel_centers; - - ResizeBilinear kernel(&input_tensor, &size_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data, output_tensor.scale())); -} - -template <typename T> class ResizeBilinearTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(ResizeBilinearTest, DataTypes); - -TYPED_TEST(ResizeBilinearTest, SimpleTest) -{ - Check<TypeParam>({2, 2, 2, 1}, {2}, {2, 3, 3, 1}, - { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }, - {3, 3}, - { - 3, 5, 6, // - 7, 9, 10, // - 9, 11, 12, // - 4, 8, 10, // - 8, 12, 14, // - 10, 14, 16, // - }, - false, false); - SUCCEED(); -} - -TEST(ResizeBilinearTest, HalfPixelCenterFloatTest) -{ - Check<float>({2, 2, 2, 1}, {2}, {2, 3, 3, 1}, - { - 1, 2, // - 3, 4, // - 1, 2, // - 3, 4 // - }, - {3, 3}, - { - 1, 1.5, 2, // - 2, 2.5, 3, // - 3, 3.5, 4, // - 1, 1.5, 2, // - 2, 2.5, 3, // - 3, 3.5, 4, // - }, - false, true); - SUCCEED(); -} - -TEST(ResizeBilinearTest, HalfPixelCenterUint8Test) -{ - Check<uint8_t>({2, 2, 2, 1}, {2}, {2, 3, 3, 1}, - { - 3, 6, // - 9, 12, // - 4, 10, // - 12, 16 // - }, - {3, 3}, - { - 2, 4, 6, // - 6, 7, 9, // - 9, 10, 12, // - 4, 7, 10, // - 8, 10, 13, // - 12, 14, 16, // - }, - false, true); - SUCCEED(); -} - -TEST(ResizeBilinearTest, InputShapeInvalid_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 2, 2}, { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }); - Tensor size_tensor = makeInputTensor<DataType::S32>({2}, {3, 3}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeBilinearParams params{}; - params.align_corners = false; - params.half_pixel_centers = false; - - ResizeBilinear kernel(&input_tensor, &size_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ResizeBilinearTest, SizeShapeInvalid_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 2, 2, 1}, { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }); - Tensor size_tensor = makeInputTensor<DataType::S32>({2, 1}, {3, 3}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeBilinearParams params{}; - params.align_corners = false; - params.half_pixel_centers = false; - - ResizeBilinear kernel(&input_tensor, &size_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ResizeBilinearTest, SizeDimInvalid_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 2, 2, 1}, { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }); - Tensor size_tensor = makeInputTensor<DataType::S32>({3}, {3, 3, 1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeBilinearParams params{}; - params.align_corners = false; - params.half_pixel_centers = false; - - ResizeBilinear kernel(&input_tensor, &size_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ResizeBilinearTest, InvalidParams_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 2, 2, 1}, { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }); - Tensor size_tensor = makeInputTensor<DataType::S32>({2}, {3, 3}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeBilinearParams params{}; - params.align_corners = true; - params.half_pixel_centers = true; - - ResizeBilinear kernel(&input_tensor, &size_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.cpp b/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.cpp deleted file mode 100644 index e4ad8f742..000000000 --- a/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/ResizeNearestNeighbor.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -ResizeNearestNeighbor::ResizeNearestNeighbor(const Tensor *input, const Tensor *size, - Tensor *output, - const ResizeNearestNeighborParams ¶ms) - : KernelWithParams<ResizeNearestNeighborParams>({input, size}, {output}, params) -{ -} - -void ResizeNearestNeighbor::configure() -{ - LUCI_INTERPRETER_CHECK(input()->shape().num_dims() == 4); - LUCI_INTERPRETER_CHECK(size()->shape().num_dims() == 1); - LUCI_INTERPRETER_CHECK(size()->element_type() == DataType::S32); - LUCI_INTERPRETER_CHECK(size()->shape().dim(0) == 2); - Shape output_shape(4); - output_shape.dim(0) = input()->shape().dim(0); - output_shape.dim(1) = getTensorData<int32_t>(size())[0]; - output_shape.dim(2) = getTensorData<int32_t>(size())[1]; - output_shape.dim(3) = input()->shape().dim(3); - output()->resize(output_shape); -} - -void ResizeNearestNeighbor::execute() const -{ - tflite::ResizeNearestNeighborParams op_params{}; - op_params.align_corners = params().align_corners; - op_params.half_pixel_centers = params().half_pixel_centers; - switch (output()->element_type()) - { - case DataType::FLOAT32: - tflite::reference_ops::ResizeNearestNeighbor( - op_params, getTensorShape(input()), getTensorData<int32_t>(input()), - getTensorShape(size()), getTensorData<int32_t>(size()), getTensorShape(output()), - getTensorData<int32_t>(output())); - break; - case DataType::U8: - tflite::optimized_ops::ResizeNearestNeighbor( - op_params, getTensorShape(input()), getTensorData<uint8_t>(input()), - getTensorShape(size()), getTensorData<int32_t>(size()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.h b/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.h deleted file mode 100644 index 137d031cf..000000000 --- a/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_RESIZENEARESTNEIGHBOR_H -#define LUCI_INTERPRETER_KERNELS_RESIZENEARESTNEIGHBOR_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class ResizeNearestNeighbor : public KernelWithParams<ResizeNearestNeighborParams> -{ -public: - ResizeNearestNeighbor(const Tensor *input, const Tensor *shape, Tensor *output, - const ResizeNearestNeighborParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *size() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_RESIZENEARESTNEIGHBOR_H diff --git a/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.test.cpp b/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.test.cpp deleted file mode 100644 index 9a804cca7..000000000 --- a/compiler/luci-interpreter/src/kernels/ResizeNearestNeighbor.test.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/ResizeNearestNeighbor.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> size_shape, - std::initializer_list<int32_t> output_shape, std::initializer_list<float> input_data, - std::initializer_list<int32_t> size_data, std::initializer_list<float> output_data, - bool align_corners, bool half_pixel_centers) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor size_tensor = makeInputTensor<DataType::S32>(size_shape, size_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeNearestNeighborParams params{}; - params.align_corners = align_corners; - params.half_pixel_centers = half_pixel_centers; - - ResizeNearestNeighbor kernel(&input_tensor, &size_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(extractTensorData<T>(output_tensor), FloatArrayNear(output_data)); -} - -template <> -void Check<uint8_t>(std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> size_shape, - std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, - std::initializer_list<int32_t> size_data, - std::initializer_list<float> output_data, bool align_corners, - bool half_pixel_centers) -{ - std::pair<float, int32_t> quant_param = - quantizationParams<uint8_t>(std::min(input_data) < 0 ? std::min(input_data) : 0.f, - std::max(input_data) > 0 ? std::max(input_data) : 0.f); - Tensor input_tensor = - makeInputTensor<DataType::U8>(input_shape, quant_param.first, quant_param.second, input_data); - Tensor size_tensor = makeInputTensor<DataType::S32>(size_shape, size_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.first); - - ResizeNearestNeighborParams params{}; - params.align_corners = align_corners; - params.half_pixel_centers = half_pixel_centers; - - ResizeNearestNeighbor kernel(&input_tensor, &size_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data, output_tensor.scale())); -} - -template <typename T> class ResizeNearestNeighborTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(ResizeNearestNeighborTest, DataTypes); - -TYPED_TEST(ResizeNearestNeighborTest, SimpleTest) -{ - Check<TypeParam>({2, 2, 2, 1}, {2}, {2, 3, 3, 1}, - { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }, - {3, 3}, - { - 3, 3, 6, // - 3, 3, 6, // - 9, 9, 12, // - 4, 4, 10, // - 4, 4, 10, // - 10, 10, 16, // - }, - false, false); -} - -TYPED_TEST(ResizeNearestNeighborTest, AlignCenterTest) -{ - Check<TypeParam>({2, 2, 2, 1}, {2}, {2, 3, 3, 1}, - { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }, - {3, 3}, - { - 3, 6, 6, // - 9, 12, 12, // - 9, 12, 12, // - 4, 10, 10, // - 10, 16, 16, // - 10, 16, 16, // - }, - true, false); -} - -TYPED_TEST(ResizeNearestNeighborTest, HalfPixelCenterTest) -{ - Check<TypeParam>({2, 2, 2, 1}, {2}, {2, 3, 3, 1}, - { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }, - {3, 3}, - { - 3, 6, 6, // - 9, 12, 12, // - 9, 12, 12, // - 4, 10, 10, // - 10, 16, 16, // - 10, 16, 16, // - }, - false, true); -} - -TEST(ResizeNearestNeighborTest, InputShapeInvalid_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 2, 2}, { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }); - Tensor size_tensor = makeInputTensor<DataType::S32>({2}, {3, 3}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeNearestNeighborParams params{}; - params.align_corners = false; - params.half_pixel_centers = false; - - ResizeNearestNeighbor kernel(&input_tensor, &size_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ResizeNearestNeighborTest, SizeShapeInvalid_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 2, 2, 1}, { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }); - Tensor size_tensor = makeInputTensor<DataType::S32>({2, 1}, {3, 3}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeNearestNeighborParams params{}; - params.align_corners = false; - params.half_pixel_centers = false; - - ResizeNearestNeighbor kernel(&input_tensor, &size_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(ResizeNearestNeighborTest, SizeDimInvalid_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({2, 2, 2, 1}, { - 3, 6, // - 9, 12, // - 4, 10, // - 10, 16 // - }); - Tensor size_tensor = makeInputTensor<DataType::S32>({3}, {3, 3, 1}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - ResizeNearestNeighborParams params{}; - params.align_corners = false; - params.half_pixel_centers = false; - - ResizeNearestNeighbor kernel(&input_tensor, &size_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Reverse.cpp b/compiler/luci-interpreter/src/kernels/Reverse.cpp deleted file mode 100644 index a46308412..000000000 --- a/compiler/luci-interpreter/src/kernels/Reverse.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Reverse.h" -#include "kernels/Utils.h" -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Reverse::Reverse(const Tensor *input, const Tensor *axes, Tensor *output) - : Kernel({input, axes}, {output}) -{ -} - -void Reverse::configure() -{ - assert(axes()->shape().num_dims() == 1); - assert(input()->shape().num_dims() >= axes()->shape().num_elements()); - if (input()->element_type() != DataType::S32 && input()->element_type() != DataType::FLOAT32 && - input()->element_type() != DataType::U8 && input()->element_type() != DataType::S16 && - input()->element_type() != DataType::S64) - { - throw std::runtime_error("Unsupported input type."); - } - if (axes()->element_type() != DataType::S32) - { - throw std::runtime_error("Unsupported axes type."); - } - if (axes()->shape().num_elements() > 1) - { - throw std::runtime_error("Current implementation does not support more than 1 axis."); - } - int axis_value = getTensorData<int32_t>(axes())[0]; - if (axis_value < 0 || axis_value >= input()->shape().num_dims()) - { - throw std::runtime_error("Invalid axes value"); - } - assert(input()->element_type() == output()->element_type()); - - output()->resize(input()->shape()); -} - -void Reverse::execute() const -{ - int axis_value = getTensorData<int32_t>(axes())[0]; - switch (output()->element_type()) - { - case DataType::FLOAT32: - tflite::reference_ops::Reverse<float>(axis_value, getTensorShape(input()), - getTensorData<float>(input()), getTensorShape(output()), - getTensorData<float>(output())); - break; - case DataType::U8: - tflite::reference_ops::Reverse<uint8_t>( - axis_value, getTensorShape(input()), getTensorData<uint8_t>(input()), - getTensorShape(output()), getTensorData<uint8_t>(output())); - break; - default: - throw std::runtime_error("Unsupported output type"); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Reverse.h b/compiler/luci-interpreter/src/kernels/Reverse.h deleted file mode 100644 index 3489dae28..000000000 --- a/compiler/luci-interpreter/src/kernels/Reverse.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_REVERSE_H -#define LUCI_INTERPRETER_KERNELS_REVERSE_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Reverse : public Kernel -{ -public: - Reverse(const Tensor *input, const Tensor *axes, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *axes() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_REVERSE_H diff --git a/compiler/luci-interpreter/src/kernels/Reverse.test.cpp b/compiler/luci-interpreter/src/kernels/Reverse.test.cpp deleted file mode 100644 index 5475a8bd3..000000000 --- a/compiler/luci-interpreter/src/kernels/Reverse.test.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Reverse.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> class ReverseTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(ReverseTest, DataTypes); - -TYPED_TEST(ReverseTest, MultiDimensions) -{ - // TypeParam - std::vector<TypeParam> input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; - Shape input_shape{4, 3, 2}; - std::vector<int32_t> axis_data{1}; - Shape axis_shape{1}; - - std::vector<TypeParam> output_data{5, 6, 3, 4, 1, 2, 11, 12, 9, 10, 7, 8, - 17, 18, 15, 16, 13, 14, 23, 24, 21, 22, 19, 20}; - std::vector<int32_t> output_shape{4, 3, 2}; - - Tensor input_tensor = makeInputTensor<getElementType<TypeParam>()>(input_shape, input_data); - Tensor axis_tensor = makeInputTensor<DataType::S32>(axis_shape, axis_data); - - Tensor output_tensor = makeOutputTensor(getElementType<TypeParam>()); - - Reverse kernel = Reverse(&input_tensor, &axis_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<TypeParam>(output_tensor), - ::testing::ElementsAreArray(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Rsqrt.cpp b/compiler/luci-interpreter/src/kernels/Rsqrt.cpp deleted file mode 100644 index 6dd92dc98..000000000 --- a/compiler/luci-interpreter/src/kernels/Rsqrt.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Rsqrt.h" -#include "kernels/Utils.h" - -#include <stdexcept> -#include <cmath> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Rsqrt::Rsqrt(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Rsqrt::configure() -{ - if (input()->element_type() != output()->element_type()) - { - throw std::runtime_error("Input/output tensor data type mismatch."); - } - output()->resize(input()->shape()); -} - -void Rsqrt::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Rsqrt::evalFloat() const -{ - auto in = getTensorData<float>(input()); - auto out = getTensorData<float>(output()); - auto size = getTensorShape(input()).FlatSize(); - for (auto i = in; i != in + size; ++i) - { - *out = 1.f / std::sqrt(*i); - ++out; - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Rsqrt.h b/compiler/luci-interpreter/src/kernels/Rsqrt.h deleted file mode 100644 index adc5bcfa2..000000000 --- a/compiler/luci-interpreter/src/kernels/Rsqrt.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_RSQRT_H -#define LUCI_INTERPRETER_KERNELS_RSQRT_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Rsqrt : public Kernel -{ -public: - Rsqrt(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_RSQRT_H diff --git a/compiler/luci-interpreter/src/kernels/Rsqrt.test.cpp b/compiler/luci-interpreter/src/kernels/Rsqrt.test.cpp deleted file mode 100644 index d33b800be..000000000 --- a/compiler/luci-interpreter/src/kernels/Rsqrt.test.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Rsqrt.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> output_data) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Rsqrt kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -TEST(RsqrtTest, SimpleRsqrt) -{ - Check( - /*input_shape=*/{1, 2, 4, 1}, /*output_shape=*/{1, 2, 4, 1}, - /*input_data=*/ - { - 5, 4, 8, 2, // - 6, 7.5, 9, 0.3, // - }, - /*output_data=*/ - { - 0.44721360, 0.5, 0.35355339, 0.70710678, // - 0.40824829, 0.36514837, 0.33333333, 1.8257419, // - }); -} - -TEST(RsqrtTest, Input_Output_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::S32); - - Rsqrt kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(RsqrtTest, Invalid_Input_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - Rsqrt kernel(&input_tensor, &output_tensor); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Slice.cpp b/compiler/luci-interpreter/src/kernels/Slice.cpp deleted file mode 100644 index c4bc3c57c..000000000 --- a/compiler/luci-interpreter/src/kernels/Slice.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Slice.h" -#include "Utils.h" -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <cassert> -#include <cstring> - -namespace luci_interpreter -{ - -namespace kernels -{ -const int max_dim = 4; - -Slice::Slice(const Tensor *input, const Tensor *begin, const Tensor *size, Tensor *output) - : Kernel({input, begin, size}, {output}) -{ -} - -template <typename T> -Shape calculateOutputShape(const Tensor *input, const Tensor *begin, const Tensor *size) -{ - Shape output_shape = Shape(input->shape().num_dims()); - for (int idx = 0; idx < input->shape().num_dims(); idx++) - { - T size_value = getTensorData<T>(size)[idx]; - if (size_value < 0) - { - if (size_value != -1) - { - throw std::runtime_error("Invalid size."); - } - size_value = input->shape().dim(idx) - getTensorData<T>(begin)[idx]; - } - else - { - if (input->shape().dim(idx) < getTensorData<T>(begin)[idx] + size_value) - { - throw std::runtime_error("Invalid begin and size."); - } - } - output_shape.dim(idx) = static_cast<int>(size_value); - } - return output_shape; -} - -template <typename T> -void getBeginAndSizeVectors(int dimensions, const Tensor *begin, const Tensor *size, - std::vector<int> *begins, std::vector<int> *sizes) -{ - for (int idx = dimensions - 1; idx >= 0; --idx) - { - begins->push_back(getTensorData<T>(begin)[idx]); - sizes->push_back(getTensorData<T>(size)[idx]); - } -} - -void Slice::configure() -{ - assert(input()->element_type() == output()->element_type()); - assert(begin()->element_type() == DataType::S32 || begin()->element_type() == DataType::S64); - assert(size()->element_type() == DataType::S32 || size()->element_type() == DataType::S64); - assert(begin()->shape().num_dims() == 1); - assert(size()->shape().num_dims() == 1); - assert(input()->shape().num_dims() <= max_dim); - - if (begin()->element_type() == DataType::S32) - { - output()->resize(calculateOutputShape<int32_t>(input(), begin(), size())); - } - else if (begin()->element_type() == DataType::S64) - { - output()->resize(calculateOutputShape<int64_t>(input(), begin(), size())); - } - else - { - throw std::runtime_error("Unsupported type."); - } -} - -void Slice::execute() const -{ - std::vector<int> begins; - begins.reserve(max_dim); - std::vector<int> sizes; - sizes.reserve(max_dim); - if (begin()->element_type() == DataType::S32) - { - getBeginAndSizeVectors<int32_t>(input()->shape().num_dims(), begin(), size(), &begins, &sizes); - } - else if (begin()->element_type() == DataType::S64) - { - getBeginAndSizeVectors<int64_t>(input()->shape().num_dims(), begin(), size(), &begins, &sizes); - } - else - { - throw std::runtime_error("Unsupported begin type."); - } - for (int i = input()->shape().num_dims(); i < max_dim; ++i) - { - begins.push_back(0); - sizes.push_back(1); - } - - assert(begins.size() == 4); - assert(sizes.size() == 4); - tflite::SliceParams op_params{}; - op_params.begin_count = 4; - op_params.size_count = 4; - for (int i = 0; i < 4; i++) - { - op_params.begin[i] = begins[3 - i]; - op_params.size[i] = sizes[3 - i]; - } - switch (input()->element_type()) - { - case DataType::FLOAT32: - tflite::optimized_ops::Slice(op_params, getTensorShape(input()), - getTensorData<float>(input()), getTensorShape(output()), - getTensorData<float>(output())); - break; - case DataType::U8: - tflite::optimized_ops::Slice(op_params, getTensorShape(input()), - getTensorData<uint8_t>(input()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - break; - default: - throw std::runtime_error("Unsupported input type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Slice.h b/compiler/luci-interpreter/src/kernels/Slice.h deleted file mode 100644 index 23c359608..000000000 --- a/compiler/luci-interpreter/src/kernels/Slice.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_SLICE_H -#define LUCI_INTERPRETER_KERNELS_SLICE_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Slice : public Kernel -{ -public: - Slice(const Tensor *input, const Tensor *begin, const Tensor *size, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *begin() const { return _inputs[1]; } - const Tensor *size() const { return _inputs[2]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_SLICE_H diff --git a/compiler/luci-interpreter/src/kernels/Slice.test.cpp b/compiler/luci-interpreter/src/kernels/Slice.test.cpp deleted file mode 100644 index a360a29cc..000000000 --- a/compiler/luci-interpreter/src/kernels/Slice.test.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Slice.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> class SliceTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(SliceTest, DataTypes); - -TYPED_TEST(SliceTest, SimpleTest) -{ - std::vector<TypeParam> input_data{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6}; - Shape input_shape{3, 2, 3, 1}; - std::vector<int32_t> begin_data{1, 0, 0, 0}; - Shape begin_shape{4}; - std::vector<int32_t> size_data{2, 1, -1, 1}; - Shape size_shape{4}; - std::vector<TypeParam> output_data{3, 3, 3, 5, 5, 5}; - std::vector<int32_t> output_shape{2, 1, 3, 1}; - - Tensor input_tensor = makeInputTensor<getElementType<TypeParam>()>(input_shape, input_data); - Tensor begin_tensor = makeInputTensor<DataType::S32>(begin_shape, begin_data); - Tensor size_tensor = makeInputTensor<DataType::S32>(size_shape, size_data); - - Tensor output_tensor = makeOutputTensor(getElementType<TypeParam>()); - - Slice kernel(&input_tensor, &begin_tensor, &size_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<TypeParam>(output_tensor), - ::testing::ElementsAreArray(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Softmax.cpp b/compiler/luci-interpreter/src/kernels/Softmax.cpp deleted file mode 100644 index 642c0ad75..000000000 --- a/compiler/luci-interpreter/src/kernels/Softmax.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Softmax.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/softmax.h> -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Softmax::Softmax(const Tensor *input, Tensor *output, const SoftmaxParams ¶ms) - : KernelWithParams<SoftmaxParams>({input}, {output}, params) -{ -} - -void Softmax::configure() -{ - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - LUCI_INTERPRETER_CHECK(input()->shape().num_dims() >= 1); - if (input()->element_type() == DataType::U8 || input()->element_type() == DataType::S8) - { - LUCI_INTERPRETER_CHECK(output()->zero_point() == 0); - tflite::SoftmaxParams op_params{}; - op_params.table = _table; - tflite::optimized_ops::PopulateSoftmaxLookupTable(&op_params, input()->scale(), params().beta); - } - output()->resize(input()->shape()); -} - -void Softmax::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::S8: - evalQuantized<int8_t>(); - break; - case DataType::U8: - evalQuantized<uint8_t>(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Softmax::evalFloat() const -{ - tflite::SoftmaxParams op_params{}; - op_params.beta = params().beta; - - tflite::reference_ops::Softmax(op_params, getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); -} - -template <typename T> void Softmax::evalQuantized() const -{ - tflite::SoftmaxParams op_params{}; - op_params.table = const_cast<float *>(_table); - op_params.zero_point = output()->zero_point(); - op_params.scale = output()->scale(); - - tflite::optimized_ops::Softmax(op_params, getTensorShape(input()), getTensorData<T>(input()), - getTensorShape(output()), getTensorData<T>(output())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Softmax.h b/compiler/luci-interpreter/src/kernels/Softmax.h deleted file mode 100644 index 1f281df1c..000000000 --- a/compiler/luci-interpreter/src/kernels/Softmax.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_SOFTMAX_H -#define LUCI_INTERPRETER_KERNELS_SOFTMAX_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Softmax : public KernelWithParams<SoftmaxParams> -{ -public: - Softmax(const Tensor *input, Tensor *output, const SoftmaxParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - template <typename T> void evalQuantized() const; - - float _table[256]; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_SOFTMAX_H diff --git a/compiler/luci-interpreter/src/kernels/Softmax.test.cpp b/compiler/luci-interpreter/src/kernels/Softmax.test.cpp deleted file mode 100644 index d3d8209a5..000000000 --- a/compiler/luci-interpreter/src/kernels/Softmax.test.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Softmax.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> output_data) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - SoftmaxParams params{}; - params.beta = 0.1; - - Softmax kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<T>(output_tensor), FloatArrayNear(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), output_shape); -} - -template <> -void Check<uint8_t>(std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, - std::initializer_list<float> output_data) -{ - std::pair<float, int32_t> input_quant_param = - quantizationParams<uint8_t>(std::min<float>(std::min<float>(input_data), 0.f), - std::max<float>(std::max<float>(input_data), 0.f)); - std::pair<float, int32_t> output_quant_param = - quantizationParams<uint8_t>(std::min<float>(std::min<float>(output_data), 0.f), - std::max<float>(std::max<float>(output_data), 0.f)); - Tensor input_tensor = makeInputTensor<DataType::U8>(input_shape, input_quant_param.first, - input_quant_param.second, input_data); - Tensor output_tensor = - makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second); - - SoftmaxParams params{}; - params.beta = 0.1; - - Softmax kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data, output_tensor.scale())); -} - -template <typename T> class SoftmaxTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(SoftmaxTest, DataTypes); - -TYPED_TEST(SoftmaxTest, Simple) -{ - Check<TypeParam>({2, 1, 2, 3}, {2, 1, 2, 3}, - { - 5, -9, 8, // - -7, 2, -4, // - 1, -2, 9, // - 3, -6, -1, // - }, - { - 0.38514, 0.09497, 0.51989, // - 0.20792, 0.51141, 0.28067, // - 0.25212, 0.18678, 0.56110, // - 0.48149, 0.19576, 0.32275, // - }); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/SpaceToDepth.cpp b/compiler/luci-interpreter/src/kernels/SpaceToDepth.cpp deleted file mode 100644 index 6a5bd7cf8..000000000 --- a/compiler/luci-interpreter/src/kernels/SpaceToDepth.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "SpaceToDepth.h" -#include "Utils.h" -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -SpaceToDepth::SpaceToDepth(const Tensor *input, Tensor *output, const SpaceToDepthParams ¶ms) - : KernelWithParams<SpaceToDepthParams>({input}, {output}, params) -{ -} - -void SpaceToDepth::configure() -{ - assert(input()->shape().num_dims() == 4); - assert(output()->element_type() == DataType::FLOAT32 || - output()->element_type() == DataType::U8 || output()->element_type() == DataType::S8 || - output()->element_type() == DataType::S32 || output()->element_type() == DataType::S64); - assert(input()->element_type() == output()->element_type()); - - const int block_size = params().block_size; - const int32_t input_height = input()->shape().dim(1); - const int32_t input_width = input()->shape().dim(2); - int32_t output_height = input_height / block_size; - int32_t output_width = input_width / block_size; - - assert(input_height == output_height * block_size); - assert(input_width == output_width * block_size); - - Shape output_shape(4); - output_shape.dim(0) = input()->shape().dim(0); - output_shape.dim(1) = output_height; - output_shape.dim(2) = output_width; - output_shape.dim(3) = input()->shape().dim(3) * block_size * block_size; - - output()->resize(output_shape); -} - -void SpaceToDepth::execute() const -{ - tflite::SpaceToDepthParams op_params{}; - op_params.block_size = params().block_size; - switch (input()->element_type()) - { - case DataType::FLOAT32: - tflite::optimized_ops::SpaceToDepth(op_params, getTensorShape(input()), - getTensorData<float>(input()), getTensorShape(output()), - getTensorData<float>(output())); - break; - case DataType::U8: - tflite::optimized_ops::SpaceToDepth(op_params, getTensorShape(input()), - getTensorData<uint8_t>(input()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/SpaceToDepth.h b/compiler/luci-interpreter/src/kernels/SpaceToDepth.h deleted file mode 100644 index e66316b11..000000000 --- a/compiler/luci-interpreter/src/kernels/SpaceToDepth.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_SPACETODEPTH_H -#define LUCI_INTERPRETER_KERNELS_SPACETODEPTH_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -#include <vector> - -namespace luci_interpreter -{ -namespace kernels -{ - -class SpaceToDepth : public KernelWithParams<SpaceToDepthParams> -{ -public: - SpaceToDepth(const Tensor *input, Tensor *output, const SpaceToDepthParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_SPACETODEPTH_H diff --git a/compiler/luci-interpreter/src/kernels/SpaceToDepth.test.cpp b/compiler/luci-interpreter/src/kernels/SpaceToDepth.test.cpp deleted file mode 100644 index 77b6655dc..000000000 --- a/compiler/luci-interpreter/src/kernels/SpaceToDepth.test.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/SpaceToDepth.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> class SpaceToDepthTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(SpaceToDepthTest, DataTypes); - -TYPED_TEST(SpaceToDepthTest, SimpleCase) -{ - constexpr DataType element_type = getElementType<TypeParam>(); - std::vector<TypeParam> input_data{1, 5, 6, 7, 2, 3, 4, 8}; - Shape input_shape{1, 2, 2, 2}; - Tensor input_tensor = makeInputTensor<element_type>(input_shape, input_data); - std::vector<TypeParam> output_data{1, 5, 6, 7, 2, 3, 4, 8}; - std::vector<int32_t> output_shape{1, 1, 1, 8}; - Tensor output_tensor = makeOutputTensor(element_type); - - SpaceToDepthParams params{}; - params.block_size = 2; - - SpaceToDepth kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<TypeParam>(output_tensor), - ::testing::ElementsAreArray(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Split.cpp b/compiler/luci-interpreter/src/kernels/Split.cpp deleted file mode 100644 index 325b1c22f..000000000 --- a/compiler/luci-interpreter/src/kernels/Split.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Split.h" - -#include "Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -Split::Split(const Tensor *axis, const Tensor *input, std::vector<Tensor *> outputs) - : Kernel({axis, input}, std::move(outputs)) -{ -} - -void Split::configure() -{ - assert(axis()->shape().num_elements() == 1); - _axis_value = getTensorData<int32_t>(axis())[0]; - if (_axis_value < 0) - _axis_value += input()->shape().num_dims(); - assert(_axis_value >= 0 && _axis_value < input()->shape().num_dims()); - - const int32_t input_size = input()->shape().dim(_axis_value); - assert(input_size % _outputs.size() == 0); - const int32_t slice_size = input_size / _outputs.size(); - - Shape output_shape = input()->shape(); - output_shape.dim(_axis_value) = slice_size; - for (Tensor *output : _outputs) - { - output->resize(output_shape); - } -} - -void Split::execute() const -{ - tflite::SplitParams params{}; - params.num_split = _outputs.size(); - params.axis = _axis_value; - -#define TF_LITE_SPLIT(scalar) \ - { \ - VectorOfTensors<scalar, false> all_outputs(_outputs); \ - tflite::optimized_ops::Split(params, getTensorShape(input()), getTensorData<scalar>(input()), \ - all_outputs.shapes(), all_outputs.data()); \ - } - - switch (input()->element_type()) - { - case DataType::FLOAT32: - TF_LITE_SPLIT(float); - break; - case DataType::U8: - TF_LITE_SPLIT(uint8_t); - break; - default: - throw std::runtime_error("Unsupported type."); - } -#undef TF_LITE_SPLIT -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Split.h b/compiler/luci-interpreter/src/kernels/Split.h deleted file mode 100644 index 9542b1e56..000000000 --- a/compiler/luci-interpreter/src/kernels/Split.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_SPLIT_H -#define LUCI_INTERPRETER_KERNELS_SPLIT_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Split : public Kernel -{ -public: - Split(const Tensor *axis, const Tensor *input, std::vector<Tensor *> outputs); - - const Tensor *axis() const { return _inputs[0]; } - const Tensor *input() const { return _inputs[1]; } - Tensor *output(int index) const { return _outputs[index]; } - - void configure() override; - void execute() const override; - -private: - int32_t _axis_value{}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_SPLIT_H diff --git a/compiler/luci-interpreter/src/kernels/Split.test.cpp b/compiler/luci-interpreter/src/kernels/Split.test.cpp deleted file mode 100644 index 2147d15c1..000000000 --- a/compiler/luci-interpreter/src/kernels/Split.test.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2018 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Split.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(int axis, int num_splits, std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> output_shape, std::initializer_list<T> input_data, - std::vector<std::vector<T>> output_data) -{ - constexpr DataType element_type = getElementType<T>(); - Tensor axis_tensor = makeInputTensor<DataType::S32>({}, {axis}); - Tensor input_tensor = makeInputTensor<element_type>(input_shape, input_data); - - std::vector<Tensor> output_tensors; - output_tensors.reserve(num_splits); - for (int i = 0; i < num_splits; ++i) - { - output_tensors.emplace_back(makeOutputTensor(element_type)); - } - - std::vector<Tensor *> output_tensor_ptrs(num_splits); - for (int i = 0; i < num_splits; ++i) - { - output_tensor_ptrs[i] = &output_tensors[i]; - } - - Split kernel(&axis_tensor, &input_tensor, std::move(output_tensor_ptrs)); - kernel.configure(); - kernel.execute(); - - for (int i = 0; i < num_splits; ++i) - { - EXPECT_THAT(extractTensorData<T>(output_tensors[i]), - ::testing::ElementsAreArray(output_data[i])); - } -} - -template <typename T> class SplitTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(SplitTest, DataTypes); - -TYPED_TEST(SplitTest, FourDimensional) -{ - Check<TypeParam>(/*axis=*/0, /*num_splits=*/2, {2, 2, 2, 2}, {1, 2, 2, 2}, - {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - { - {1, 2, 3, 4, 5, 6, 7, 8}, // - {9, 10, 11, 12, 13, 14, 15, 16}, // - }); - Check<TypeParam>( - /*axis=*/1, /*num_splits=*/2, {2, 2, 2, 2}, {2, 1, 2, 2}, - {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, { - {1, 2, 3, 4, 9, 10, 11, 12}, // - {5, 6, 7, 8, 13, 14, 15, 16}, // - }); - Check<TypeParam>( - /*axis=*/2, /*num_splits=*/2, {2, 2, 2, 2}, {2, 2, 1, 2}, - {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, { - {1, 2, 5, 6, 9, 10, 13, 14}, // - {3, 4, 7, 8, 11, 12, 15, 16}, // - }); - Check<TypeParam>( - /*axis=*/3, /*num_splits=*/2, {2, 2, 2, 2}, {2, 2, 2, 1}, - {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, { - {1, 3, 5, 7, 9, 11, 13, 15}, // - {2, 4, 6, 8, 10, 12, 14, 16}, // - }); -} - -TYPED_TEST(SplitTest, OneDimensional) -{ - Check<TypeParam>( - /*axis=*/0, /*num_splits=*/8, {8}, {1}, {1, 2, 3, 4, 5, 6, 7, 8}, - {{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}}); -} - -TYPED_TEST(SplitTest, NegativeAxis) -{ - Check<TypeParam>( - /*axis=*/-4, /*num_splits=*/2, {2, 2, 2, 2}, {1, 2, 2, 2}, - {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, { - {1, 2, 3, 4, 5, 6, 7, 8}, // - {9, 10, 11, 12, 13, 14, 15, 16}, - }); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Sqrt.cpp b/compiler/luci-interpreter/src/kernels/Sqrt.cpp deleted file mode 100644 index 46e9fc9ad..000000000 --- a/compiler/luci-interpreter/src/kernels/Sqrt.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Sqrt.h" -#include "kernels/Utils.h" - -#include <stdexcept> -#include <cmath> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Sqrt::Sqrt(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Sqrt::configure() -{ - if (input()->element_type() != output()->element_type()) - { - throw std::runtime_error("Input/output tensor data type mismatch."); - } - output()->resize(input()->shape()); -} - -void Sqrt::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Sqrt::evalFloat() const -{ - auto in = getTensorData<float>(input()); - auto out = getTensorData<float>(output()); - auto size = getTensorShape(input()).FlatSize(); - for (auto i = in; i != in + size; ++i) - { - *out = std::sqrt(*i); - ++out; - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Sqrt.h b/compiler/luci-interpreter/src/kernels/Sqrt.h deleted file mode 100644 index 4034655ed..000000000 --- a/compiler/luci-interpreter/src/kernels/Sqrt.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_SQRT_H -#define LUCI_INTERPRETER_KERNELS_SQRT_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Sqrt : public Kernel -{ -public: - Sqrt(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_SQRT_H diff --git a/compiler/luci-interpreter/src/kernels/Sqrt.test.cpp b/compiler/luci-interpreter/src/kernels/Sqrt.test.cpp deleted file mode 100644 index 504db4493..000000000 --- a/compiler/luci-interpreter/src/kernels/Sqrt.test.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Sqrt.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<float> input_data, std::initializer_list<float> output_data) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Sqrt kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -TEST(SqrtTest, SimpleSqrt) -{ - Check( - /*input_shape=*/{1, 2, 4, 1}, /*output_shape=*/{1, 2, 4, 1}, - /*input_data=*/ - { - 0, 8, 2, 4, // - 3, 7, 10, 0.3, // - }, - /*output_data=*/ - { - 0.0, 2.8284271, 1.4142136, 2, // - 1.7320508, 2.6457513, 3.1622777, 0.54772256, // - }); -} - -TEST(SqrtTest, Input_Output_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor output_tensor = makeOutputTensor(DataType::S32); - - Sqrt kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(AddTest, Invalid_Input_Type_NEG) -{ - Tensor input_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - Sqrt kernel(&input_tensor, &output_tensor); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Squeeze.cpp b/compiler/luci-interpreter/src/kernels/Squeeze.cpp deleted file mode 100644 index ce43ef789..000000000 --- a/compiler/luci-interpreter/src/kernels/Squeeze.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2018 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Squeeze.h" - -#include "kernels/Utils.h" - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -Squeeze::Squeeze(const Tensor *input, Tensor *output, const SqueezeParams ¶ms) - : KernelWithParams<SqueezeParams>({input}, {output}, params) -{ -} - -void Squeeze::configure() -{ - int input_num_dims = input()->shape().num_dims(); - int num_squeeze_dims = params().squeeze_dims.size(); - assert(input_num_dims <= 8); - bool should_squeeze[8] = {false}; - int num_squeezed_dims = 0; - if (num_squeeze_dims == 0) - { - for (int idx = 0; idx < input_num_dims; ++idx) - { - if (input()->shape().dim(idx) == 1) - { - should_squeeze[idx] = true; - ++num_squeezed_dims; - } - } - } - else - { - for (int idx = 0; idx < num_squeeze_dims; ++idx) - { - int current = params().squeeze_dims[idx] < 0 ? params().squeeze_dims[idx] + input_num_dims - : params().squeeze_dims[idx]; - assert(current >= 0 && current < input_num_dims && input()->shape().dim(current) == 1); - if (!should_squeeze[current]) - ++num_squeezed_dims; - should_squeeze[current] = true; - } - } - Shape output_shape(input_num_dims - num_squeezed_dims); - for (int in_idx = 0, out_idx = 0; in_idx < input_num_dims; ++in_idx) - { - if (!should_squeeze[in_idx]) - { - output_shape.dim(out_idx++) = input()->shape().dim(in_idx); - } - } - output()->resize(output_shape); -} - -void Squeeze::execute() const -{ - assert(input()->shape().num_elements() == output()->shape().num_elements()); - - const auto *input_data = input()->data<void>(); - auto *output_data = output()->data<void>(); - std::memcpy(output_data, input_data, - getDataTypeSize(input()->element_type()) * input()->shape().num_elements()); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Squeeze.h b/compiler/luci-interpreter/src/kernels/Squeeze.h deleted file mode 100644 index 687af5158..000000000 --- a/compiler/luci-interpreter/src/kernels/Squeeze.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2018 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_SQUEEZE_H -#define LUCI_INTERPRETER_KERNELS_SQUEEZE_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Squeeze : public KernelWithParams<SqueezeParams> -{ -public: - Squeeze(const Tensor *input, Tensor *output, const SqueezeParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_SQUEEZE_H diff --git a/compiler/luci-interpreter/src/kernels/Squeeze.test.cpp b/compiler/luci-interpreter/src/kernels/Squeeze.test.cpp deleted file mode 100644 index ff9fb09d2..000000000 --- a/compiler/luci-interpreter/src/kernels/Squeeze.test.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Squeeze.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<T> input_data, std::initializer_list<T> output_data, - std::initializer_list<int32_t> squeeze_dims) -{ - constexpr DataType element_type = getElementType<T>(); - Tensor input_tensor = makeInputTensor<element_type>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(element_type); - - SqueezeParams params{}; - params.squeeze_dims = squeeze_dims; - - Squeeze kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<T>(output_tensor), ::testing::ElementsAreArray(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -template <typename T> class SqueezeTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(SqueezeTest, DataTypes); - -TYPED_TEST(SqueezeTest, TotalTest) -{ - Check<TypeParam>( - /*input_shape=*/{1, 24, 1}, /*output_shape=*/{24}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}, - /*output_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}, - {-1, 0}); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/StridedSlice.cpp b/compiler/luci-interpreter/src/kernels/StridedSlice.cpp deleted file mode 100644 index 679485439..000000000 --- a/compiler/luci-interpreter/src/kernels/StridedSlice.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/StridedSlice.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -StridedSlice::StridedSlice(const Tensor *input, const Tensor *begin, const Tensor *end, - const Tensor *strides, Tensor *output, const StridedSliceParams ¶ms) - : KernelWithParams<StridedSliceParams>({input, begin, end, strides}, {output}, params) -{ -} - -void StridedSlice::configure() -{ - assert(begin()->shape().num_dims() == 1); - assert(end()->shape().num_dims() == 1); - assert(strides()->shape().num_dims() == 1); - assert(input()->element_type() == output()->element_type()); - assert(begin()->element_type() == DataType::S32); - assert(end()->element_type() == DataType::S32); - assert(strides()->element_type() == DataType::S32); - assert(input()->shape().num_dims() <= 4); - if (params().ellipsis_mask != 0) - { - throw std::runtime_error("ellipsis_mask is not implemented yet."); - } - if (params().new_axis_mask != 0) - { - throw std::runtime_error("new_axis_mask is not implemented yet."); - } - if (input()->element_type() == DataType::U8) - { - assert(input()->scale() == output()->scale()); - assert(input()->zero_point() == output()->zero_point()); - } - tflite::StridedSliceParams op_params{}; - op_params.start_indices_count = input()->shape().num_dims(); - op_params.stop_indices_count = input()->shape().num_dims(); - op_params.strides_count = input()->shape().num_dims(); - - for (int i = 0; i < input()->shape().num_dims(); i++) - { - op_params.start_indices[i] = getTensorData<int32_t>(begin())[i]; - op_params.stop_indices[i] = getTensorData<int32_t>(end())[i]; - op_params.strides[i] = getTensorData<int32_t>(strides())[i]; - } - op_params.begin_mask = params().begin_mask; - op_params.ellipsis_mask = 0; - op_params.end_mask = params().end_mask; - op_params.new_axis_mask = 0; - op_params.shrink_axis_mask = params().shrink_axis_mask; - std::vector<int32_t> output_shape_vector; - for (int i = 0; i < input()->shape().num_dims(); i++) - { - int idx = input()->shape().num_dims() - i - 1; - int32_t stride = getTensorData<int32_t>(strides())[idx]; - assert(stride != 0); - int32_t begin = ::tflite::strided_slice::StartForAxis(op_params, getTensorShape(input()), idx); - int32_t end = - ::tflite::strided_slice::StopForAxis(op_params, getTensorShape(input()), idx, begin); - - const bool shrink_axis = params().shrink_axis_mask & (1 << idx); - if (shrink_axis) - { - end = begin + 1; - } - - int32_t dim_shape = std::ceil((end - begin) / static_cast<float>(stride)); - dim_shape = dim_shape < 0 ? 0 : dim_shape; - if (!shrink_axis) - { - output_shape_vector.push_back(dim_shape); - } - } - Shape output_shape = Shape(output_shape_vector.size()); - for (size_t i = 0; i < output_shape_vector.size(); i++) - { - output_shape.dim(i) = output_shape_vector[output_shape_vector.size() - i - 1]; - } - output()->resize(output_shape); -} - -void StridedSlice::execute() const -{ - tflite::StridedSliceParams op_params{}; - op_params.start_indices_count = input()->shape().num_dims(); - op_params.stop_indices_count = input()->shape().num_dims(); - op_params.strides_count = input()->shape().num_dims(); - - for (int i = 0; i < input()->shape().num_dims(); i++) - { - op_params.start_indices[i] = getTensorData<int32_t>(begin())[i]; - op_params.stop_indices[i] = getTensorData<int32_t>(end())[i]; - op_params.strides[i] = getTensorData<int32_t>(strides())[i]; - } - op_params.begin_mask = params().begin_mask; - op_params.ellipsis_mask = 0; - op_params.end_mask = params().end_mask; - op_params.new_axis_mask = 0; - op_params.shrink_axis_mask = params().shrink_axis_mask; - - switch (input()->element_type()) - { - case DataType::FLOAT32: - tflite::reference_ops::StridedSlice(op_params, getTensorShape(input()), - getTensorData<float>(input()), getTensorShape(output()), - getTensorData<float>(output())); - break; - case DataType::U8: - tflite::reference_ops::StridedSlice(op_params, getTensorShape(input()), - getTensorData<uint8_t>(input()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/StridedSlice.h b/compiler/luci-interpreter/src/kernels/StridedSlice.h deleted file mode 100644 index fc96893a7..000000000 --- a/compiler/luci-interpreter/src/kernels/StridedSlice.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_STRIDEDSLICE_H -#define LUCI_INTERPRETER_KERNELS_STRIDEDSLICE_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class StridedSlice : public KernelWithParams<StridedSliceParams> -{ -public: - StridedSlice(const Tensor *input, const Tensor *begin, const Tensor *end, const Tensor *strides, - Tensor *output, const StridedSliceParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *begin() const { return _inputs[1]; } - const Tensor *end() const { return _inputs[2]; } - const Tensor *strides() const { return _inputs[3]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_STRIDEDSLICE_H diff --git a/compiler/luci-interpreter/src/kernels/StridedSlice.test.cpp b/compiler/luci-interpreter/src/kernels/StridedSlice.test.cpp deleted file mode 100644 index 66dffcaf2..000000000 --- a/compiler/luci-interpreter/src/kernels/StridedSlice.test.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/StridedSlice.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(StridedSliceTest, Float) -{ - Shape input_shape{2, 3, 2}; - std::vector<float> input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - Shape begin_shape{3}; - std::vector<int32_t> begin_data{0, 0, 0}; - Shape end_shape{3}; - std::vector<int32_t> end_data{1, 3, 2}; - Shape strides_shape{3}; - std::vector<int32_t> strides_data{1, 1, 1}; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor begin_tensor = makeInputTensor<DataType::S32>(begin_shape, begin_data); - Tensor end_tensor = makeInputTensor<DataType::S32>(end_shape, end_data); - Tensor strides_tensor = makeInputTensor<DataType::S32>(strides_shape, strides_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - StridedSliceParams params{}; - params.begin_mask = 0; - params.end_mask = 0; - params.ellipsis_mask = 0; - params.new_axis_mask = 0; - params.shrink_axis_mask = 1; - - StridedSlice kernel(&input_tensor, &begin_tensor, &end_tensor, &strides_tensor, &output_tensor, - params); - kernel.configure(); - kernel.execute(); - - std::vector<int32_t> output_shape{3, 2}; - std::vector<float> output_data{1, 2, 3, 4, 5, 6}; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -TEST(StridedSliceTest, Uint8) -{ - Shape input_shape{2, 3, 2}; - std::vector<float> input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - Shape begin_shape{3}; - std::vector<int32_t> begin_data{0, 0, 0}; - Shape end_shape{3}; - std::vector<int32_t> end_data{1, 3, 2}; - Shape strides_shape{3}; - std::vector<int32_t> strides_data{1, 1, 1}; - Tensor input_tensor = makeInputTensor<DataType::U8>(input_shape, 1.0f, 0, input_data); - Tensor begin_tensor = makeInputTensor<DataType::S32>(begin_shape, begin_data); - Tensor end_tensor = makeInputTensor<DataType::S32>(end_shape, end_data); - Tensor strides_tensor = makeInputTensor<DataType::S32>(strides_shape, strides_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1.0f, 0); - - StridedSliceParams params{}; - params.begin_mask = 0; - params.end_mask = 0; - params.ellipsis_mask = 0; - params.new_axis_mask = 0; - params.shrink_axis_mask = 1; - - StridedSlice kernel(&input_tensor, &begin_tensor, &end_tensor, &strides_tensor, &output_tensor, - params); - kernel.configure(); - kernel.execute(); - - std::vector<int32_t> output_shape{3, 2}; - std::vector<float> output_data{1, 2, 3, 4, 5, 6}; - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Sub.cpp b/compiler/luci-interpreter/src/kernels/Sub.cpp deleted file mode 100644 index dd9c1102f..000000000 --- a/compiler/luci-interpreter/src/kernels/Sub.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2019 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Sub.h" -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/optimized/legacy_optimized_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -Sub::Sub(const Tensor *input1, const Tensor *input2, Tensor *output, const SubParams ¶ms) - : KernelWithParams<SubParams>({input1, input2}, {output}, params) -{ -} - -void Sub::configure() -{ - LUCI_INTERPRETER_CHECK(!(input1()->element_type() != input2()->element_type())) - output()->resize(calculateShapeForBroadcast(input1()->shape(), input2()->shape())); -} - -void Sub::execute() const -{ - switch (input1()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Sub::evalFloat() const -{ - float activation_min{}; - float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::ArithmeticParams params{}; - params.float_activation_min = activation_min; - params.float_activation_max = activation_max; - - const bool need_broadcast = tflite::reference_ops::ProcessBroadcastShapes( - getTensorShape(input1()), getTensorShape(input2()), ¶ms); - - if (need_broadcast) - { - tflite::reference_ops::BroadcastSubSlow( - params, getTensorShape(input1()), getTensorData<float>(input1()), getTensorShape(input2()), - getTensorData<float>(input2()), getTensorShape(output()), getTensorData<float>(output())); - } - else - { - tflite::optimized_ops::Sub(params, getTensorShape(input1()), getTensorData<float>(input1()), - getTensorShape(input2()), getTensorData<float>(input2()), - getTensorShape(output()), getTensorData<float>(output())); - } -} - -void Sub::evalQuantized() const -{ - const auto input1_scale = static_cast<double>(input1()->scale()); - const auto input2_scale = static_cast<double>(input2()->scale()); - const auto output_scale = static_cast<double>(output()->scale()); - - const int left_shift = 20; - const double twice_max_input_scale = 2 * std::max(input1_scale, input2_scale); - const double real_input1_multiplier = input1_scale / twice_max_input_scale; - const double real_input2_multiplier = input2_scale / twice_max_input_scale; - const double real_output_multiplier = twice_max_input_scale / ((1 << left_shift) * output_scale); - - int32_t input1_multiplier{}, input2_multiplier{}, output_multiplier{}; - int input1_shift{}, input2_shift{}, output_shift{}; - quantizeMultiplierSmallerThanOneExp(real_input1_multiplier, &input1_multiplier, &input1_shift); - quantizeMultiplierSmallerThanOneExp(real_input2_multiplier, &input2_multiplier, &input2_shift); - quantizeMultiplierSmallerThanOneExp(real_output_multiplier, &output_multiplier, &output_shift); - - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::ArithmeticParams params{}; - params.left_shift = left_shift; - // The kernel expects inputs' zero points to be negated. - params.input1_offset = -input1()->zero_point(); // Note the '-'. - params.input1_multiplier = input1_multiplier; - params.input1_shift = input1_shift; - params.input2_offset = -input2()->zero_point(); // Note the '-'. - params.input2_multiplier = input2_multiplier; - params.input2_shift = input2_shift; - params.output_offset = output()->zero_point(); - params.output_multiplier = output_multiplier; - params.output_shift = output_shift; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - const bool need_broadcast = tflite::reference_ops::ProcessBroadcastShapes( - getTensorShape(input1()), getTensorShape(input2()), ¶ms); - - if (need_broadcast) - { - tflite::reference_ops::BroadcastSubSlow( - params, getTensorShape(input1()), getTensorData<uint8_t>(input1()), - getTensorShape(input2()), getTensorData<uint8_t>(input2()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - } - else - { - tflite::reference_ops::Sub(params, getTensorShape(input1()), getTensorData<uint8_t>(input1()), - getTensorShape(input2()), getTensorData<uint8_t>(input2()), - getTensorShape(output()), getTensorData<uint8_t>(output())); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Sub.h b/compiler/luci-interpreter/src/kernels/Sub.h deleted file mode 100644 index d7940b5c6..000000000 --- a/compiler/luci-interpreter/src/kernels/Sub.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_SUB_H -#define LUCI_INTERPRETER_KERNELS_SUB_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Sub : public KernelWithParams<SubParams> -{ -public: - Sub(const Tensor *input1, const Tensor *input2, Tensor *output, const SubParams ¶ms); - - const Tensor *input1() const { return _inputs[0]; } - const Tensor *input2() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_SUB_H diff --git a/compiler/luci-interpreter/src/kernels/Sub.test.cpp b/compiler/luci-interpreter/src/kernels/Sub.test.cpp deleted file mode 100644 index 9f77fe7e0..000000000 --- a/compiler/luci-interpreter/src/kernels/Sub.test.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Sub.h" -#include "kernels/TestUtils.h" - -#include <algorithm> - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; -using std::pair; -using std::vector; -using std::transform; -using std::initializer_list; - -// for quantized Add, the error shouldn't exceed step -float GetTolerance(float min, float max) -{ - float kQuantizedStep = (max - min) / 255.0; - return kQuantizedStep; -} - -TEST(SubTest, Uint8) -{ - Shape base_shape = {2, 3, 1, 2}; - vector<float> base_data = {-0.3f, 2.3f, 0.9f, 0.5f, 0.8f, -1.1f, - 1.2f, 2.8f, -1.6f, 0.0f, 0.7f, -2.2f}; - vector<Shape> test_shapes = {{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}}; - vector<float> test_data = {0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f}; - vector<vector<int32_t>> output_shapes = {{2, 3, 3, 2}, {2, 3, 1, 2}, {2, 3, 3, 2}, {2, 3, 1, 2}}; - vector<vector<float>> output_data = { - {-0.5f, 2.0f, 0.1f, 1.8f, -1.3f, 1.4f, 0.7f, 0.2f, 1.3f, 0.0f, -0.1f, -0.4f, - 0.6f, -1.4f, 1.2f, -1.6f, -0.2f, -2.0f, 1.0f, 2.5f, 1.6f, 2.3f, 0.2f, 1.9f, - -1.8f, -0.3f, -1.2f, -0.5f, -2.6f, -0.9f, 0.5f, -2.5f, 1.1f, -2.7f, -0.3f, -3.0f}, - {-0.5f, 2.0f, 1.3f, 0.0f, -0.2f, -2.0f, 1.0f, 2.5f, -1.2f, -0.5f, -0.3f, -3.0f}, - {-0.5f, 2.1f, -0.6f, 2.0f, 0.1f, 2.7f, 0.7f, 0.3f, 0.6f, 0.2f, 1.3f, 0.9f, - 0.6f, -1.3f, 0.5f, -1.4f, 1.2f, -0.7f, 0.7f, 2.3f, 0.2f, 1.8f, 0.3f, 1.9f, - -2.1f, -0.5f, -2.6f, -1.0f, -2.5f, -0.9f, 0.2f, -2.7f, -0.3f, -3.0f, -0.2f, -3.0f}, - {-0.5f, 2.1f, 0.6f, 0.2f, 1.2f, -0.7f, 0.7f, 2.3f, -2.6f, -1.0f, -0.2f, -3.0f}}; - - float kQuantizedTolerance = GetTolerance(-3.f, 3.f); - pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-3.f, 3.f); - for (size_t i = 0; i < output_data.size(); ++i) - { - Tensor input1_tensor = - makeInputTensor<DataType::U8>(base_shape, quant_param.first, quant_param.second, base_data); - Tensor input2_tensor = makeInputTensor<DataType::U8>(test_shapes[i], quant_param.first, - quant_param.second, test_data); - Tensor output_tensor = - makeOutputTensor(getElementType<uint8_t>(), quant_param.first, quant_param.second); - - SubParams params{}; - params.activation = Activation::NONE; - - Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data[i], kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shapes[i])); - } - - // Inversion step for output_data, because subtract is not commutative operation - auto multiply = [](auto &i) { - transform(i.begin(), i.end(), i.begin(), [](auto &value) { return value * -1.0f; }); - }; - for_each(output_data.begin(), output_data.end(), multiply); - - // Re-run with exchanged inputs. - for (size_t i = 0; i < output_data.size(); ++i) - { - Tensor input1_tensor = makeInputTensor<DataType::U8>(test_shapes[i], quant_param.first, - quant_param.second, test_data); - Tensor input2_tensor = - makeInputTensor<DataType::U8>(base_shape, quant_param.first, quant_param.second, base_data); - Tensor output_tensor = - makeOutputTensor(getElementType<uint8_t>(), quant_param.first, quant_param.second); - - SubParams params{}; - params.activation = Activation::NONE; - - Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data[i], kQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shapes[i])); - } -} - -TEST(SubTest, Float) -{ - Shape base_shape = {2, 3, 1, 2}; - vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}}; - vector<vector<int32_t>> output_shapes{{2, 3, 3, 2}, {2, 3, 1, 2}, {2, 3, 3, 2}, {2, 3, 1, 2}}; - vector<vector<float>> test_outputs = { - {0.0f, 2.0f, 0.1f, 1.8f, 0.0f, 1.4f, 0.7f, 0.2f, 1.3f, 0.0f, 0.0f, 0.0f, - 0.6f, 0.0f, 1.2f, 0.0f, 0.0f, 0.0f, 1.0f, 2.5f, 1.6f, 2.3f, 0.2f, 1.9f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.1f, 0.0f, 0.0f, 0.0f}, - {0.0f, 2.0f, 1.3f, 0.0f, 0.0f, 0.0f, 1.0f, 2.5f, 0.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 2.1f, 0.0f, 2.0f, 0.1f, 2.7f, 0.7f, 0.3f, 0.6f, 0.2f, 1.3f, 0.9f, - 0.6f, 0.0f, 0.5f, 0.0f, 1.2f, 0.0f, 0.7f, 2.3f, 0.2f, 1.8f, 0.3f, 1.9f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 2.1f, 0.6f, 0.2f, 1.2f, 0.0f, 0.7f, 2.3f, 0.0f, 0.0f, 0.0f, 0.0f}}; - - vector<float> input1_data{-0.3f, 2.3f, 0.9f, 0.5f, 0.8f, -1.1f, - 1.2f, 2.8f, -1.6f, 0.0f, 0.7f, -2.2f}; - vector<float> input2_data{0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f}; - for (size_t i = 0; i < test_shapes.size(); ++i) - { - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>(base_shape, input1_data); - Tensor input2_tensor = makeInputTensor<DataType::FLOAT32>(test_shapes[i], input2_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - SubParams params{}; - params.activation = Activation::RELU; - - Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs[i], 0.0001f)) - << "With shape number " << i; - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shapes[i])); - } -} - -TEST(SubTest, Input_Output_Type_NEG) -{ - Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); - Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {2}); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - SubParams params{}; - params.activation = Activation::RELU; - - Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST(SubTest, Invalid_Input_Type_NEG) -{ - Tensor input1_tensor = makeInputTensor<DataType::S64>({1}, {1}); - Tensor input2_tensor = makeInputTensor<DataType::S64>({1}, {2}); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - SubParams params{}; - params.activation = Activation::RELU; - - Sub kernel(&input1_tensor, &input2_tensor, &output_tensor, params); - kernel.configure(); - EXPECT_ANY_THROW(kernel.execute()); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Tanh.cpp b/compiler/luci-interpreter/src/kernels/Tanh.cpp deleted file mode 100644 index b649d5d2f..000000000 --- a/compiler/luci-interpreter/src/kernels/Tanh.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Tanh.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -namespace luci_interpreter -{ -namespace kernels -{ - -Tanh::Tanh(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Tanh::configure() -{ - assert(input()->element_type() == output()->element_type()); - if (input()->element_type() == DataType::U8) - { - populateLookupTable(); - } - output()->resize(input()->shape()); -} - -void Tanh::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void Tanh::evalFloat() const -{ - tflite::reference_ops::Tanh(getTensorShape(input()), getTensorData<float>(input()), - getTensorShape(output()), getTensorData<float>(output())); -} - -void Tanh::evalQuantized() const -{ - const int size = tflite::MatchingFlatSize(getTensorShape(input()), getTensorShape(output())); - uint8_t *output_data = getTensorData<uint8_t>(output()); - const uint8_t *input_data = getTensorData<uint8_t>(input()); - for (int i = 0; i < size; ++i) - { - output_data[i] = getTableValue(input_data[i]); - } -} - -void Tanh::populateLookupTable() -{ - const auto input_scale = static_cast<double>(input()->scale()); - const auto input_zero_point = static_cast<int32_t>(input()->zero_point()); - const auto output_scale = static_cast<double>(output()->scale()); - const auto output_zero_point = static_cast<int32_t>(output()->zero_point()); - const float inverse_scale = 1 / output_scale; - int32_t maxval = std::numeric_limits<uint8_t>::max(); - int32_t minval = std::numeric_limits<uint8_t>::min(); - for (int32_t val = minval; val <= maxval; ++val) - { - const float dequantized = input_scale * (val - input_zero_point); - const float transformed = std::tanh(dequantized); - const float rescaled = std::round(transformed * inverse_scale); - const int32_t quantized = static_cast<int32_t>(rescaled + output_zero_point); - setTableValue(static_cast<uint8_t>(std::max(std::min(maxval, quantized), minval)), - static_cast<uint8_t>(val)); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Tanh.h b/compiler/luci-interpreter/src/kernels/Tanh.h deleted file mode 100644 index 8017c9638..000000000 --- a/compiler/luci-interpreter/src/kernels/Tanh.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_TANH_H -#define LUCI_INTERPRETER_KERNELS_TANH_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Tanh : public Kernel -{ -public: - Tanh(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void populateLookupTable(); - void setTableValue(uint8_t value, uint8_t idx) { _table[idx] = value; }; - uint8_t getTableValue(uint8_t idx) const { return _table[idx]; }; - -private: - uint8_t _table[256]{}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_TANH_H diff --git a/compiler/luci-interpreter/src/kernels/Tanh.test.cpp b/compiler/luci-interpreter/src/kernels/Tanh.test.cpp deleted file mode 100644 index f91ffa1db..000000000 --- a/compiler/luci-interpreter/src/kernels/Tanh.test.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Tanh.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -TEST(TanhTest, Float) -{ - Shape input_shape{1, 2, 4, 1}; - std::vector<float> input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Tanh kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 0, -0.9999877, 0.9640275, 0.999329, // - 0.99505475, -0.9640275, 1, 0.7615941, // - }; - EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(TanhTest, Uint8) -{ - float kMin = -1; - float kMax = 127.f / 128.f; - float kTanhTolerance = 2 * (1. / 256); - std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(8 * kMin, 8 * kMax); - std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(kMin, kMax); - std::vector<float> input_data{ - 0, -6, 2, 4, // - -4, -2, 8, 1, // - 0, -6, 2, 4, // - -4, -2, 8, 1, // - 0, -6, 2, 4, // - -4, -2, 8, 1, // - 0, -6, 2, 4, // - -4, -2, 8, 1, // - 0, -6, 2, 4, // - -4, -2, 8, 1, // - 0, -6, 2, 4, // - -4, -2, 8, 1, // - }; - Tensor input_tensor = makeInputTensor<DataType::U8>({2, 6, 4, 1}, input_quant_param.first, - input_quant_param.second, input_data); - Tensor output_tensor = - makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second); - - Tanh kernel(&input_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - std::vector<float> ref_output_data{ - 0.0, -0.999987, 0.964027, 0.999329, // - -0.999329, -0.96402, 0.99999, 0.76159, // - 0.0, -0.999987, 0.964027, 0.999329, // - -0.999329, -0.96402, 0.99999, 0.76159, // - 0.0, -0.999987, 0.964027, 0.999329, // - -0.999329, -0.96402, 0.99999, 0.76159, // - 0.0, -0.999987, 0.964027, 0.999329, // - -0.999329, -0.96402, 0.99999, 0.76159, // - 0.0, -0.999987, 0.964027, 0.999329, // - -0.999329, -0.96402, 0.99999, 0.76159, // - 0.0, -0.999987, 0.964027, 0.999329, // - -0.999329, -0.96402, 0.99999, 0.76159, // - }; - std::vector<int32_t> ref_output_shape{2, 6, 4, 1}; - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data, kTanhTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/TestUtils.cpp b/compiler/luci-interpreter/src/kernels/TestUtils.cpp deleted file mode 100644 index 4c19c8810..000000000 --- a/compiler/luci-interpreter/src/kernels/TestUtils.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/TestUtils.h" - -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ -namespace testing -{ - -using ::testing::FloatNear; -using ::testing::Matcher; - -Tensor makeOutputTensor(DataType element_type) { return Tensor(element_type, {}, {}, ""); } - -Tensor makeOutputTensor(DataType element_type, float scale, int32_t zero_point) -{ - return Tensor(element_type, {}, {{scale}, {zero_point}}, ""); -} - -std::vector<float> dequantizeTensorData(const Tensor &tensor) -{ - if (tensor.element_type() == DataType::U8) - { - return dequantize(extractTensorData<uint8_t>(tensor), tensor.scale(), tensor.zero_point()); - } - else if (tensor.element_type() == DataType::S16) - { - // S16 quantization is symmetric, so zero point should be zero. - assert(tensor.zero_point() == 0); - return dequantize(extractTensorData<int16_t>(tensor), tensor.scale(), 0); - } - else - { - throw std::runtime_error("Unsupported type."); - } -} - -Matcher<std::vector<float>> FloatArrayNear(const std::vector<float> &values, float max_abs_error) -{ - std::vector<Matcher<float>> matchers; - matchers.reserve(values.size()); - for (const float v : values) - { - matchers.emplace_back(FloatNear(v, max_abs_error)); - } - return ElementsAreArray(matchers); -} - -std::vector<int32_t> extractTensorShape(const Tensor &tensor) -{ - std::vector<int32_t> result; - int dims = tensor.shape().num_dims(); - for (int i = 0; i < dims; i++) - { - result.push_back(tensor.shape().dim(i)); - } - return result; -} - -} // namespace testing -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/TestUtils.h b/compiler/luci-interpreter/src/kernels/TestUtils.h deleted file mode 100644 index e5bd6a2db..000000000 --- a/compiler/luci-interpreter/src/kernels/TestUtils.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_TESTUTILS_H -#define LUCI_INTERPRETER_KERNELS_TESTUTILS_H - -#include "luci_interpreter/core/Tensor.h" - -#include <type_traits> - -#include <gtest/gtest.h> -#include <gmock/gmock.h> - -namespace luci_interpreter -{ -namespace kernels -{ -namespace testing -{ - -template <typename T> -std::vector<T> quantize(const std::vector<float> &data, float scale, int32_t zero_point); - -template <DataType DT> -Tensor makeInputTensor(const Shape &shape, const std::vector<typename DataTypeImpl<DT>::Type> &data) -{ - Tensor tensor(DT, shape, {}, ""); - tensor.writeData(data.data(), data.size() * sizeof(typename DataTypeImpl<DT>::Type)); - return tensor; -} - -template <DataType DT> -Tensor makeInputTensor(const Shape &shape, float scale, int32_t zero_point, - const std::vector<float> &data) -{ - using NativeT = typename DataTypeImpl<DT>::Type; - Tensor tensor(DT, shape, {{scale}, {zero_point}}, ""); - std::vector<NativeT> quantized_data = quantize<NativeT>(data, scale, zero_point); - tensor.writeData(quantized_data.data(), quantized_data.size() * sizeof(NativeT)); - return tensor; -} - -Tensor makeOutputTensor(DataType element_type); -Tensor makeOutputTensor(DataType element_type, float scale, int32_t zero_point); - -std::vector<int32_t> extractTensorShape(const Tensor &tensor); - -// Returns the corresponding DataType given the type T. -template <typename T> constexpr DataType getElementType() -{ - if (std::is_same<T, float>::value) - return DataType::FLOAT32; - if (std::is_same<T, uint8_t>::value) - return DataType::U8; - if (std::is_same<T, int32_t>::value) - return DataType::S32; - if (std::is_same<T, int64_t>::value) - return DataType::S64; - return DataType::Unknown; -} - -template <typename T> std::vector<T> extractTensorData(const Tensor &tensor) -{ - const auto *data_ptr = tensor.data<T>(); - return std::vector<T>(data_ptr, data_ptr + tensor.shape().num_elements()); -} - -std::vector<float> dequantizeTensorData(const Tensor &tensor); - -// Array version of `::testing::FloatNear` matcher. -::testing::Matcher<std::vector<float>> FloatArrayNear(const std::vector<float> &values, - float max_abs_error = 1.0e-5f); - -template <typename T> -std::vector<T> quantize(const std::vector<float> &data, float scale, int32_t zero_point) -{ - static_assert(std::is_integral<T>::value, "Integral type expected."); - - float q_min{}, q_max{}; - if (std::is_signed<T>::value) - { - // For now, assume that signed type implies signed symmetric quantization. - assert(zero_point == 0); - q_min = -std::numeric_limits<T>::max(); - q_max = std::numeric_limits<T>::max(); - } - else - { - q_min = 0; - q_max = std::numeric_limits<T>::max(); - } - - std::vector<T> q; - for (const auto &f : data) - { - q.push_back(static_cast<T>( - std::max<float>(q_min, std::min<float>(q_max, std::round(zero_point + (f / scale)))))); - } - return q; -} - -template <typename T> -std::vector<float> dequantize(const std::vector<T> &data, float scale, int32_t zero_point) -{ - static_assert(std::is_integral<T>::value, "Integral type expected."); - std::vector<float> f; - for (const T &q : data) - { - f.push_back(scale * (q - zero_point)); - } - return f; -} - -// NOTE Returns scale and zero point for _asymmetric_ range (both signed and unsigned). -template <typename T> std::pair<float, int32_t> quantizationParams(float f_min, float f_max) -{ - static_assert(std::is_integral<T>::value, "Integral type expected."); - int32_t zero_point = 0; - float scale = 0; - const T qmin = std::numeric_limits<T>::lowest(); - const T qmax = std::numeric_limits<T>::max(); - const float qmin_double = qmin; - const float qmax_double = qmax; - // 0 should always be a representable value. Let's assume that the initial - // min,max range contains 0. - assert(f_max >= 0); - assert(f_min <= 0); - if (f_min == f_max) - { - // Special case where the min,max range is a point. Should be {0}. - assert(f_max == 0); - assert(f_min == 0); - return {scale, zero_point}; - } - - // General case. - // - // First determine the scale. - scale = (f_max - f_min) / (qmax_double - qmin_double); - - // Zero-point computation. - // First the initial floating-point computation. The zero-point can be - // determined from solving an affine equation for any known pair - // (real value, corresponding quantized value). - // We know two such pairs: (rmin, qmin) and (rmax, qmax). - // The arithmetic error on the zero point computed from either pair - // will be roughly machine_epsilon * (sum of absolute values of terms) - // so we want to use the variant that adds the smaller terms. - const float zero_point_from_min = qmin_double - f_min / scale; - const float zero_point_from_max = qmax_double - f_max / scale; - - const float zero_point_from_min_error = std::abs(qmin_double) + std::abs(f_min / scale); - - const float zero_point_from_max_error = std::abs(qmax_double) + std::abs(f_max / scale); - - const float zero_point_double = zero_point_from_min_error < zero_point_from_max_error - ? zero_point_from_min - : zero_point_from_max; - - // Now we need to nudge the zero point to be an integer - // (our zero points are integer, and this is motivated by the requirement - // to be able to represent the real value "0" exactly as a quantized value, - // which is required in multiple places, for example in Im2col with SAME - // padding). - - T nudged_zero_point = 0; - if (zero_point_double < qmin_double) - { - nudged_zero_point = qmin; - } - else if (zero_point_double > qmax_double) - { - nudged_zero_point = qmax; - } - else - { - nudged_zero_point = static_cast<T>(std::round(zero_point_double)); - } - - // The zero point should always be in the range of quantized value, - // // [qmin, qmax]. - assert(qmax >= nudged_zero_point); - assert(qmin <= nudged_zero_point); - zero_point = nudged_zero_point; - // finally, return the values - return {scale, zero_point}; -} - -inline float getTolerance(float min, float max, int quantize_steps) -{ - return ((max - min) / quantize_steps); -} - -} // namespace testing -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_TESTUTILS_H diff --git a/compiler/luci-interpreter/src/kernels/Transpose.cpp b/compiler/luci-interpreter/src/kernels/Transpose.cpp deleted file mode 100644 index 8265d9937..000000000 --- a/compiler/luci-interpreter/src/kernels/Transpose.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Transpose.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Transpose::Transpose(const Tensor *input, const Tensor *perm, Tensor *output) - : Kernel({input, perm}, {output}) -{ -} - -void Transpose::configure() -{ - // Transpose op only supports 1D-4D input arrays. - int dims = input()->shape().num_dims(); - const int *perm_data = getTensorData<int32_t>(perm()); - - assert(input()->shape().num_dims() <= 4); - assert(input()->element_type() == output()->element_type()); - - assert(perm()->shape().num_dims() == 1); - assert(perm()->shape().dim(0) == dims); - - Shape output_shape(dims); - for (int i = 0; i < dims; i++) - { - assert(perm_data[i] < dims && perm_data[i] >= 0); - output_shape.dim(i) = input()->shape().dim(perm_data[i]); - } - - output()->resize(output_shape); -} - -void Transpose::execute() const -{ - tflite::TransposeParams params{}; - const int *perm_data = getTensorData<int32_t>(perm()); - const int size = perm()->shape().dim(0); - params.perm_count = size; - for (int i = 0; i < size; i++) - params.perm[i] = perm_data[i]; - switch (input()->element_type()) - { - case DataType::FLOAT32: - tflite::reference_ops::Transpose(params, getTensorShape(input()), - getTensorData<float>(input()), getTensorShape(output()), - getTensorData<float>(output())); - break; - case DataType::U8: - tflite::reference_ops::Transpose(params, getTensorShape(input()), - getTensorData<uint8_t>(input()), getTensorShape(output()), - getTensorData<uint8_t>(output())); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Transpose.h b/compiler/luci-interpreter/src/kernels/Transpose.h deleted file mode 100644 index d6f89c352..000000000 --- a/compiler/luci-interpreter/src/kernels/Transpose.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_TRANSPOSE_H -#define LUCI_INTERPRETER_KERNELS_TRANSPOSE_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Transpose : public Kernel -{ -public: - Transpose(const Tensor *input, const Tensor *perm, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *perm() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_TRANSPOSE_H diff --git a/compiler/luci-interpreter/src/kernels/Transpose.test.cpp b/compiler/luci-interpreter/src/kernels/Transpose.test.cpp deleted file mode 100644 index 1c99223a8..000000000 --- a/compiler/luci-interpreter/src/kernels/Transpose.test.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Transpose.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(std::initializer_list<int32_t> input_shape, std::initializer_list<int32_t> perm_shape, - std::initializer_list<int32_t> output_shape, std::initializer_list<T> input_data, - std::initializer_list<int32_t> perm_data, std::initializer_list<T> output_data) -{ - constexpr DataType element_type = getElementType<T>(); - Tensor input_tensor = makeInputTensor<element_type>(input_shape, input_data); - Tensor perm_tensor = makeInputTensor<DataType::S32>(perm_shape, perm_data); - Tensor output_tensor = makeOutputTensor(element_type); - - Transpose kernel(&input_tensor, &perm_tensor, &output_tensor); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorData<T>(output_tensor), ::testing::ElementsAreArray(output_data)); -} - -template <typename T> class TransposeTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(TransposeTest, DataTypes); - -TYPED_TEST(TransposeTest, Small3D) -{ - Check<TypeParam>(/*input_shape=*/{2, 3, 4}, /*perm_shape=*/{3}, /*output_shape=*/{4, 2, 3}, - /*input_data=*/{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, - /*perm_data=*/{2, 0, 1}, - /*output_data=*/{0, 4, 8, 12, 16, 20, 1, 5, 9, 13, 17, 21, - 2, 6, 10, 14, 18, 22, 3, 7, 11, 15, 19, 23}); -} - -TYPED_TEST(TransposeTest, Large4D) -{ - Check<TypeParam>( - /*input_shape=*/{2, 3, 4, 5}, /*perm_shape=*/{4}, /*output_shape=*/{4, 2, 3, 5}, - /*input_data=*/{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119}, - /*perm_data=*/{2, 0, 1, 3}, - /*output_data=*/{0, 1, 2, 3, 4, 20, 21, 22, 23, 24, 40, 41, 42, 43, 44, - 60, 61, 62, 63, 64, 80, 81, 82, 83, 84, 100, 101, 102, 103, 104, - 5, 6, 7, 8, 9, 25, 26, 27, 28, 29, 45, 46, 47, 48, 49, - 65, 66, 67, 68, 69, 85, 86, 87, 88, 89, 105, 106, 107, 108, 109, - 10, 11, 12, 13, 14, 30, 31, 32, 33, 34, 50, 51, 52, 53, 54, - 70, 71, 72, 73, 74, 90, 91, 92, 93, 94, 110, 111, 112, 113, 114, - 15, 16, 17, 18, 19, 35, 36, 37, 38, 39, 55, 56, 57, 58, 59, - 75, 76, 77, 78, 79, 95, 96, 97, 98, 99, 115, 116, 117, 118, 119}); -} - -TYPED_TEST(TransposeTest, Large2D) -{ - Check<TypeParam>( - /*input_shape=*/{10, 12}, /*perm_shape=*/{2}, /*output_shape=*/{12, 10}, - /*input_data=*/{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119}, - /*perm_data=*/{1, 0}, - /*output_data=*/{ - 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 1, 13, 25, 37, 49, 61, 73, 85, 97, 109, - 2, 14, 26, 38, 50, 62, 74, 86, 98, 110, 3, 15, 27, 39, 51, 63, 75, 87, 99, 111, - 4, 16, 28, 40, 52, 64, 76, 88, 100, 112, 5, 17, 29, 41, 53, 65, 77, 89, 101, 113, - 6, 18, 30, 42, 54, 66, 78, 90, 102, 114, 7, 19, 31, 43, 55, 67, 79, 91, 103, 115, - 8, 20, 32, 44, 56, 68, 80, 92, 104, 116, 9, 21, 33, 45, 57, 69, 81, 93, 105, 117, - 10, 22, 34, 46, 58, 70, 82, 94, 106, 118, 11, 23, 35, 47, 59, 71, 83, 95, 107, 119}); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/TransposeConv.cpp b/compiler/luci-interpreter/src/kernels/TransposeConv.cpp deleted file mode 100644 index 07d92f07f..000000000 --- a/compiler/luci-interpreter/src/kernels/TransposeConv.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/TransposeConv.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -TransposeConv::TransposeConv(const Tensor *output_shape, const Tensor *filter, const Tensor *input, - const Tensor *bias, Tensor *output, const TransposeConvParams ¶ms) - : KernelWithParams<TransposeConvParams>({output_shape, filter, input, bias}, {output}, params) -{ -} - -void TransposeConv::configure() -{ - assert(output_shape()->shape().num_dims() == 1); - assert(input()->shape().num_dims() == 4); - assert(filter()->shape().num_dims() == 4); - assert(input()->element_type() == DataType::FLOAT32 || input()->element_type() == DataType::U8); - assert(input()->element_type() == output()->element_type()); - assert(input()->shape().dim(3) == filter()->shape().dim(3)); - - const int num_dims = output_shape()->shape().dim(0); - Shape out_shape(num_dims); - const auto *shape_data = getTensorData<int32_t>(output_shape()); - for (int i = 0; i < num_dims; i++) - out_shape.dim(i) = shape_data[i]; - output()->resize(out_shape); - - const int32_t filter_height = filter()->shape().dim(1); - const int32_t filter_width = filter()->shape().dim(2); - const int32_t output_height = out_shape.dim(1); - const int32_t output_width = out_shape.dim(2); - - const int32_t unused_output_height = - computeOutputSize(params().padding, output_height, filter_height, params().stride_height, 1); - const int32_t unused_output_width = - computeOutputSize(params().padding, output_width, filter_width, params().stride_width, 1); - - _padding_height = - computePadding(params().stride_height, 1, output_height, filter_height, unused_output_height); - _padding_width = - computePadding(params().stride_width, 1, output_width, filter_width, unused_output_width); - - if (input()->element_type() == DataType::U8) - { - _scratch_tensor = - std::make_unique<Tensor>(DataType::S32, output()->shape(), AffineQuantization{}, ""); - const double input_product_scale = input()->scale() * filter()->scale(); - assert(input_product_scale >= 0); - const double real_multiplier = input_product_scale / output()->scale(); - quantizeMultiplier(real_multiplier, &_output_multiplier, &_output_shift); - } -} - -void TransposeConv::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - default: - throw std::runtime_error("Unsupported type."); - } -} - -void TransposeConv::evalFloat() const -{ - tflite::ConvParams op_params{}; - op_params.padding_type = tflite::PaddingType::kSame; - op_params.padding_values.height = _padding_height; - op_params.padding_values.width = _padding_width; - op_params.stride_height = params().stride_height; - op_params.stride_width = params().stride_width; - op_params.output_multiplier = _output_multiplier; - tflite::reference_ops::TransposeConv(op_params, // - getTensorShape(input()), getTensorData<float>(input()), // - getTensorShape(filter()), getTensorData<float>(filter()), // - getTensorShape(bias()), getTensorData<float>(bias()), // - getTensorShape(output()), getTensorData<float>(output()), // - tflite::RuntimeShape(), nullptr); -} - -void TransposeConv::evalQuantized() const -{ - tflite::ConvParams op_params{}; - op_params.padding_type = tflite::PaddingType::kSame; - op_params.padding_values.height = _padding_height; - op_params.padding_values.width = _padding_width; - op_params.stride_height = params().stride_height; - op_params.stride_width = params().stride_width; - // The kernel expects input and filter zero points to be negated. - op_params.input_offset = -input()->zero_point(); // Note the '-'. - op_params.weights_offset = -filter()->zero_point(); // Note the '-'. - op_params.output_offset = output()->zero_point(); - op_params.output_multiplier = _output_multiplier; - op_params.output_shift = _output_shift; - op_params.quantized_activation_min = std::numeric_limits<uint8_t>::min(); - op_params.quantized_activation_max = std::numeric_limits<uint8_t>::max(); - - tflite::reference_ops::TransposeConv(op_params, // - getTensorShape(input()), getTensorData<uint8>(input()), // - getTensorShape(filter()), getTensorData<uint8>(filter()), // - getTensorShape(bias()), getTensorData<int32_t>(bias()), // - getTensorShape(output()), getTensorData<uint8>(output()), // - tflite::RuntimeShape(), nullptr, // - getTensorData<int32_t>(_scratch_tensor.get())); -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/TransposeConv.h b/compiler/luci-interpreter/src/kernels/TransposeConv.h deleted file mode 100644 index 444439c65..000000000 --- a/compiler/luci-interpreter/src/kernels/TransposeConv.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_TRANSPOSECONV_H -#define LUCI_INTERPRETER_KERNELS_TRANSPOSECONV_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class TransposeConv : public KernelWithParams<TransposeConvParams> -{ -public: - TransposeConv(const Tensor *output_shape, const Tensor *filter, const Tensor *input, - const Tensor *bias, Tensor *output, const TransposeConvParams ¶ms); - - const Tensor *output_shape() const { return _inputs[0]; } - const Tensor *filter() const { return _inputs[1]; } - const Tensor *input() const { return _inputs[2]; } - const Tensor *bias() const { return _inputs[3]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - -private: - std::unique_ptr<Tensor> _scratch_tensor; - - int32_t _padding_height{}; - int32_t _padding_width{}; - // The scaling factor from input to output (aka the 'real multiplier') can - // be represented as a fixed point multiplier plus a left shift. - int32_t _output_multiplier = 0; - int _output_shift = 0; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_TRANSPOSECONV_H diff --git a/compiler/luci-interpreter/src/kernels/TransposeConv.test.cpp b/compiler/luci-interpreter/src/kernels/TransposeConv.test.cpp deleted file mode 100644 index 5a69e7798..000000000 --- a/compiler/luci-interpreter/src/kernels/TransposeConv.test.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/TransposeConv.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T, typename B> -void Check(std::initializer_list<int32_t> output_shape_shape, - std::initializer_list<int32_t> weight_shape, std::initializer_list<int32_t> input_shape, - std::initializer_list<int32_t> bias_shape, std::initializer_list<int32_t> output_shape, - std::initializer_list<int32_t> output_shape_data, std::initializer_list<T> weight_data, - std::initializer_list<T> input_data, std::initializer_list<B> bias_data, - std::initializer_list<T> output_data, luci::Padding padding, int32_t stride_height, - int32_t stride_width) -{ - constexpr DataType element_type = getElementType<T>(); - Tensor output_shape_tensor = - makeInputTensor<DataType::S32>(output_shape_shape, output_shape_data); - Tensor weight_tensor = makeInputTensor<element_type>(weight_shape, weight_data); - Tensor input_data_tensor = makeInputTensor<element_type>(input_shape, input_data); - Tensor output_tensor = makeOutputTensor(element_type); - - TransposeConvParams params{}; - params.padding = padding; - params.stride_height = stride_height; - params.stride_width = stride_width; - - if (bias_data.size() != 0) - { - Tensor bias_tensor = makeInputTensor<getElementType<B>()>(bias_shape, bias_data); - TransposeConv kernel(&output_shape_tensor, &weight_tensor, &input_data_tensor, &bias_tensor, - &output_tensor, params); - kernel.configure(); - kernel.execute(); - } - else - { - TransposeConv kernel(&output_shape_tensor, &weight_tensor, &input_data_tensor, nullptr, - &output_tensor, params); - kernel.configure(); - kernel.execute(); - } - EXPECT_THAT(extractTensorData<T>(output_tensor), ::testing::ElementsAreArray(output_data)); -} - -TEST(TransposeConvTest, FloatSimple) -{ - Check<float, float>( - /*output_shape_shape=*/{4}, /*weight_shape=*/{1, 3, 3, 1}, /*input_shape=*/{1, 4, 4, 1}, - /*bias_shape=*/{}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 4, 4, 1}, - /*weight_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - /*bias_data=*/{}, - /*output_data=*/{29, 62, 83, 75, 99, 192, 237, 198, 207, 372, 417, 330, 263, 446, 485, 365}, - /*params.padding=*/luci::Padding::SAME, /*stride_height=*/1, /*stride_width=*/1); - - SUCCEED(); -} - -TEST(TransposeConvTest, FloatTwoFiltersTest) -{ - Check<float, float>( - /*output_shape_shape=*/{4}, /*weight_shape=*/{1, 3, 3, 2}, /*input_shape=*/{1, 4, 4, 2}, - /*bias_shape=*/{}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 4, 4, 1}, - /*weight_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, - /*bias_data=*/{}, - /*output_data=*/ - {184, 412, 568, 528, 678, 1347, 1689, 1434, 1494, 2715, 3057, 2442, 1968, 3352, 3652, 2760}, - /*params.padding=*/luci::Padding::SAME, /*stride_height=*/1, /*stride_width=*/1); - - SUCCEED(); -} - -TEST(TransposeConvTest, SimpleBiasTest) -{ - Check<float, float>( - /*output_shape_shape=*/{4}, /*weight_shape=*/{2, 3, 3, 1}, - /*input_shape=*/{1, 2, 2, 1}, - /*bias_shape=*/{2}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 5, 5, 2}, - /*weight_data=*/{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18}, - /*input_data=*/{1, 2, 3, 4}, - /*bias_data=*/{3, 4}, - /*output_data=*/{4, 6, 6, 8, 10, 14, 9, 12, 13, 16, 10, 12, 12, 14, 28, 32, 21, - 24, 25, 28, 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, 24, 28, 30, 34, - 64, 72, 39, 44, 47, 52, 42, 46, 48, 52, 106, 114, 63, 68, 71, 76}, - /*params.padding=*/luci::Padding::VALID, /*stride_height=*/2, /*stride_width=*/2); - - SUCCEED(); -} - -TEST(TransposeConvTest, UInt8) -{ - std::vector<float> input_data{1, 2, 3, 4}; - std::vector<float> filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18}; - std::vector<float> bias_data{3, 4}; - std::vector<int32_t> output_shape_data{1, 5, 5, 2}; - std::vector<float> ref_output_data{ - 4, 6, 6, 8, 10, 14, 9, 12, 13, 16, // - 10, 12, 12, 14, 28, 32, 21, 24, 25, 28, // - 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, // - 24, 28, 30, 34, 64, 72, 39, 44, 47, 52, // - 42, 46, 48, 52, 106, 114, 63, 68, 71, 76, // - }; - - // Choose quantization parameters carefully. - auto input_quant = quantizationParams<uint8_t>(-8.0, 7.9375); // s = 1 / 16, zp = 128 - auto filter_quant = quantizationParams<uint8_t>(-24.0, 39.75); // s = 1 / 4, zp = 96 - auto output_quant = quantizationParams<uint8_t>(-64.0, 191.0); // s = 1, zp = 64 - - Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 2, 1}, input_quant.first, - input_quant.second, input_data); - Tensor filter_tensor = makeInputTensor<DataType::U8>({2, 3, 3, 1}, filter_quant.first, - filter_quant.second, filter_data); - Tensor bias_tensor = - makeInputTensor<DataType::S32>({2}, input_quant.first * filter_quant.first, 0, bias_data); - Tensor output_shape_tensor = makeInputTensor<DataType::S32>({4}, output_shape_data); - Tensor output_tensor = makeOutputTensor(DataType::U8, output_quant.first, output_quant.second); - - TransposeConvParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 2; - - TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor, - &output_tensor, params); - kernel.configure(); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Unpack.cpp b/compiler/luci-interpreter/src/kernels/Unpack.cpp deleted file mode 100644 index 834b79926..000000000 --- a/compiler/luci-interpreter/src/kernels/Unpack.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Unpack.h" - -#include "kernels/Utils.h" - -#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> - -#include <stdexcept> - -namespace luci_interpreter -{ - -namespace kernels -{ - -Unpack::Unpack(const Tensor *input, std::vector<Tensor *> outputs, const UnpackParams ¶ms) - : KernelWithParams<UnpackParams>({input}, std::move(outputs), params) -{ -} - -void Unpack::configure() -{ - const Shape &input_shape = input()->shape(); - - int axis = _params.axis; - if (axis < 0) - axis += input()->shape().num_dims(); - assert(axis >= 0 && axis < input_shape.num_dims()); - - Shape output_shape(input_shape.num_dims() - 1); - int out_index = 0; - for (int in_index = 0; in_index < input_shape.num_dims(); ++in_index) - { - if (in_index != axis) - output_shape.dim(out_index++) = input_shape.dim(in_index); - } - - for (Tensor *output : _outputs) - { - assert(output->element_type() == input()->element_type()); - output->resize(output_shape); - } -} - -template <typename T> void Unpack::executeImpl() const -{ - tflite::UnpackParams params{}; - params.axis = _params.axis; - params.num_split = _outputs.size(); - VectorOfTensors<T, false> all_outputs(_outputs); - tflite::reference_ops::Unpack<T>(params, getTensorShape(input()), getTensorData<T>(input()), - **all_outputs.shapes(), all_outputs.data()); -} - -void Unpack::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - return executeImpl<float>(); - case DataType::U8: - return executeImpl<uint8_t>(); - default: - throw std::runtime_error("Unsupported type."); - } -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Unpack.h b/compiler/luci-interpreter/src/kernels/Unpack.h deleted file mode 100644 index f4a44ecad..000000000 --- a/compiler/luci-interpreter/src/kernels/Unpack.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_UNPACK_H -#define LUCI_INTERPRETER_KERNELS_UNPACK_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Unpack : public KernelWithParams<UnpackParams> -{ -public: - Unpack(const Tensor *input, std::vector<Tensor *> outputs, const UnpackParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output(int index) const { return _outputs[index]; } - - void configure() override; - void execute() const override; - -private: - template <typename T> void executeImpl() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_UNPACK_H diff --git a/compiler/luci-interpreter/src/kernels/Unpack.test.cpp b/compiler/luci-interpreter/src/kernels/Unpack.test.cpp deleted file mode 100644 index f70c5847a..000000000 --- a/compiler/luci-interpreter/src/kernels/Unpack.test.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2018 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Unpack.h" -#include "kernels/TestUtils.h" - -namespace luci_interpreter -{ -namespace kernels -{ -namespace -{ - -using namespace testing; - -template <typename T> -void Check(int axis, Shape input_shape, std::initializer_list<T> input_data, - const std::vector<std::initializer_list<int32_t>> &exp_output_shape, - std::vector<std::initializer_list<T>> exp_output_data) -{ - constexpr DataType element_type = getElementType<T>(); - const int num_outputs = input_shape.dim(axis < 0 ? axis + input_shape.num_dims() : axis); - - Tensor input_tensor = makeInputTensor<element_type>(input_shape, input_data); - std::vector<Tensor> output_tensors; - output_tensors.reserve(num_outputs); - for (int i = 0; i < num_outputs; ++i) - { - output_tensors.push_back(makeOutputTensor(element_type)); - } - - std::vector<Tensor *> output_tensor_ptrs(num_outputs); - for (int i = 0; i < num_outputs; ++i) - { - output_tensor_ptrs[i] = &output_tensors[i]; - } - - UnpackParams params{}; - params.axis = axis; - - Unpack kernel(&input_tensor, std::move(output_tensor_ptrs), params); - kernel.configure(); - kernel.execute(); - - for (int i = 0; i < num_outputs; ++i) - { - EXPECT_THAT(extractTensorData<T>(output_tensors[i]), - ::testing::ElementsAreArray(exp_output_data[i])); - } -} - -template <typename T> class UnpackTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types<float, uint8_t>; -TYPED_TEST_CASE(UnpackTest, DataTypes); - -TYPED_TEST(UnpackTest, ThreeOutputs) -{ - Check<TypeParam>(/*axis=*/0, /*input_shape=*/{3, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{2}, {2}, {2}}, - /*exp_output_data=*/{{1, 2}, {3, 4}, {5, 6}}); -} - -TYPED_TEST(UnpackTest, ThreeOutputsAxisOne) -{ - Check<TypeParam>(/*axis=*/1, /*input_shape=*/{3, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{3}, {3}}, - /*exp_output_data=*/{{1, 3, 5}, {2, 4, 6}}); -} - -TYPED_TEST(UnpackTest, ThreeOutputsNegativeAxisOne) -{ - Check<TypeParam>(/*axis=*/-1, /*input_shape=*/{3, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{3}, {3}}, - /*exp_output_data=*/{{1, 3, 5}, {2, 4, 6}}); -} - -TYPED_TEST(UnpackTest, ThreeOutputsNegativeAxisTwo) -{ - Check<TypeParam>(/*axis=*/-2, /*input_shape=*/{3, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{2}, {2}, {2}}, - /*exp_output_data=*/{{1, 2}, {3, 4}, {5, 6}}); -} - -TYPED_TEST(UnpackTest, OneOutput) -{ - Check<TypeParam>(/*axis=*/0, /*input_shape=*/{1, 6}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{6}}, - /*exp_output_data=*/{{1, 2, 3, 4, 5, 6}}); -} - -TYPED_TEST(UnpackTest, ThreeDimensionsTwoOutputs) -{ - Check<TypeParam>(/*axis=*/2, /*input_shape=*/{2, 2, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8}, - /*exp_output_shape=*/{{2, 2}, {2, 2}}, - /*exp_output_data=*/{{1, 3, 5, 7}, {2, 4, 6, 8}}); -} - -TYPED_TEST(UnpackTest, FiveDimensionsTwoOutputs) -{ - Check<TypeParam>( - /*axis=*/2, /*input_shape=*/{2, 2, 2, 2, 1}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - /*exp_output_shape=*/{{2, 2, 2, 1}, {2, 2, 2, 1}}, - /*exp_output_data=*/ - {{1, 2, 5, 6, 9, 10, 13, 14}, {3, 4, 7, 8, 11, 12, 15, 16}}); -} - -TYPED_TEST(UnpackTest, VectorToScalar) -{ - Check<TypeParam>(/*axis=*/0, /*input_shape=*/{5}, - /*input_data=*/{1, 2, 3, 4, 5}, - /*exp_output_shape=*/{{}, {}, {}, {}, {}}, - /*exp_output_data=*/{{1}, {2}, {3}, {4}, {5}}); -} - -} // namespace -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Utils.cpp b/compiler/luci-interpreter/src/kernels/Utils.cpp deleted file mode 100644 index 52e76a81c..000000000 --- a/compiler/luci-interpreter/src/kernels/Utils.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernels/Utils.h" - -#include <cassert> -#include <cmath> -#include <limits> -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -void calculateActivationRange(Activation activation, float *activation_min, float *activation_max) -{ - switch (activation) - { - case Activation::NONE: - *activation_min = std::numeric_limits<float>::lowest(); - *activation_max = std::numeric_limits<float>::max(); - break; - case Activation::RELU: - *activation_min = 0; - *activation_max = std::numeric_limits<float>::max(); - break; - case Activation::RELU_N1_TO_1: - *activation_min = -1; - *activation_max = 1; - break; - case Activation::RELU6: - *activation_min = 0; - *activation_max = 6; - break; - default: - throw std::runtime_error("Unsupported activation."); - } -} - -static void calculateActivationRangeQuantizedImpl(Activation activation, int32_t qmin, int32_t qmax, - const Tensor *output, int32_t *activation_min, - int32_t *activation_max) -{ - const float scale = output->scale(); - const int32_t zero_point = output->zero_point(); - - auto quantize = [scale, zero_point](float x) { - return zero_point + static_cast<int32_t>(std::round(x / scale)); - }; - - switch (activation) - { - case Activation::NONE: - *activation_min = qmin; - *activation_max = qmax; - break; - case Activation::RELU: - *activation_min = std::max(qmin, quantize(0.0f)); - *activation_max = qmax; - break; - case Activation::RELU_N1_TO_1: - *activation_min = std::max(qmin, quantize(-1.0f)); - *activation_max = std::min(qmax, quantize(1.0f)); - break; - case Activation::RELU6: - *activation_min = std::max(qmin, quantize(0.0f)); - *activation_max = std::min(qmax, quantize(6.0f)); - break; - default: - throw std::runtime_error("Unsupported activation."); - } -} - -void calculateActivationRangeQuantized(Activation activation, const Tensor *output, - int32_t *activation_min, int32_t *activation_max) -{ - // For now, assume that signed type implies signed symmetric quantization. - int32_t qmin{}; - int32_t qmax{}; - switch (output->element_type()) - { - case DataType::U8: - qmin = 0; - qmax = std::numeric_limits<uint8_t>::max(); - break; - case DataType::S8: - assert(output->zero_point() == 0); - qmin = -std::numeric_limits<int8_t>::max(); - qmax = std::numeric_limits<int8_t>::max(); - break; - case DataType::S16: - assert(output->zero_point() == 0); - qmin = -std::numeric_limits<int16_t>::max(); - qmax = std::numeric_limits<int16_t>::max(); - break; - default: - throw std::runtime_error("Unsupported type."); - } - - calculateActivationRangeQuantizedImpl(activation, qmin, qmax, output, activation_min, - activation_max); -} - -void quantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift) -{ - if (double_multiplier == 0.0) - { - *quantized_multiplier = 0; - *shift = 0; - return; - } - - const double q = std::frexp(double_multiplier, shift); - auto q_fixed = static_cast<int64_t>(std::round(q * (INT64_C(1) << 31))); - - if (q_fixed == (INT64_C(1) << 31)) - { - q_fixed /= 2; - ++*shift; - } - assert(q_fixed <= std::numeric_limits<int32_t>::max()); - // A shift amount smaller than -31 would cause all bits to be shifted out - // and thus all results would be zero. We implement that instead with - // q_fixed==0, so as to avoid hitting issues with right-shift - // operations with shift amounts greater than 31. Note that this happens - // roughly when abs(double_multiplier) < 2^-31 and the present handling means - // that we're effectively flushing tiny double_multiplier's to zero. - // We could conceivably handle values in the range (roughly) [32, 63] - // as 'denormals' i.e. (shift==0, q_fixed < 2^30). In that point of view - // the present handling is just doing 'flush denormals to zero'. We could - // reconsider and actually generate nonzero denormals if a need arises. - if (*shift < -31) - { - *shift = 0; - q_fixed = 0; - } - *quantized_multiplier = static_cast<int32_t>(q_fixed); -} - -void quantizeMultiplierSmallerThanOneExp(double double_multiplier, int32_t *quantized_multiplier, - int *left_shift) -{ - assert(double_multiplier < 1.0); - assert(double_multiplier > 0.0); - int shift; - quantizeMultiplier(double_multiplier, quantized_multiplier, &shift); - assert(shift <= 0); - *left_shift = shift; -} - -Shape calculateShapeForBroadcast(const Shape &input1_shape, const Shape &input2_shape) -{ - const int num_input1_dims = input1_shape.num_dims(); - const int num_input2_dims = input2_shape.num_dims(); - const int num_out_dims = std::max(num_input1_dims, num_input2_dims); - Shape output_shape(num_out_dims); - - for (int i = 0; i < num_out_dims; ++i) - { - const int32_t input1_dim = i < num_input1_dims ? input1_shape.dim(num_input1_dims - i - 1) : 1; - const int32_t input2_dim = i < num_input2_dims ? input2_shape.dim(num_input2_dims - i - 1) : 1; - assert(input1_dim == input2_dim || input1_dim == 1 || input2_dim == 1); - output_shape.dim(num_out_dims - i - 1) = std::max(input1_dim, input2_dim); - } - - return output_shape; -} - -} // namespace kernels -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Utils.h b/compiler/luci-interpreter/src/kernels/Utils.h deleted file mode 100644 index 67bb7581a..000000000 --- a/compiler/luci-interpreter/src/kernels/Utils.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_UTILS_H -#define LUCI_INTERPRETER_KERNELS_UTILS_H - -#include "core/KernelParams.h" -#include "luci_interpreter/core/Tensor.h" - -#include <tensorflow/lite/kernels/internal/types.h> - -#include <cassert> -#include <cstdint> -#include <stdexcept> - -namespace luci_interpreter -{ -namespace kernels -{ - -#define LUCI_INTERPRETER_CHECK(cond) \ - if (!(cond)) \ - throw std::runtime_error(std::string(__FILE__) + ":" + std::to_string(__LINE__) + +"(" + \ - std::string(#cond) + ") was not true."); - -inline int32_t computePadding(int32_t stride, int32_t dilation_rate, int32_t in_size, - int32_t filter_size, int32_t out_size) -{ - const int32_t effective_filter_size = (filter_size - 1) * dilation_rate + 1; - const int32_t padding = ((out_size - 1) * stride + effective_filter_size - in_size) / 2; - return padding > 0 ? padding : 0; -} - -inline int32_t computePaddingWithOffset(int32_t stride, int32_t dilation_rate, int32_t in_size, - int32_t filter_size, int32_t out_size, int32_t *offset) -{ - int32_t effective_filter_size = (filter_size - 1) * dilation_rate + 1; - int32_t total_padding = ((out_size - 1) * stride + effective_filter_size - in_size); - total_padding = total_padding > 0 ? total_padding : 0; - *offset = total_padding % 2; - return total_padding / 2; -} - -inline int32_t computeOutputSize(Padding padding, int32_t image_size, int32_t filter_size, - int32_t stride, int32_t dilation_rate = 1) -{ - const int32_t effective_filter_size = (filter_size - 1) * dilation_rate + 1; - switch (padding) - { - case Padding::SAME: - return (image_size + stride - 1) / stride; - case Padding::VALID: - return (image_size + stride - effective_filter_size) / stride; - default: - assert(false); - return 0; - } -} - -inline int32_t calcOffset(const Shape &shape, int32_t d0, int32_t d1, int32_t d2, int32_t d3) -{ - return ((d0 * shape.dim(1) + d1) * shape.dim(2) + d2) * shape.dim(3) + d3; -} - -void calculateActivationRange(Activation activation, float *activation_min, float *activation_max); - -void calculateActivationRangeQuantized(Activation activation, const Tensor *output, - int32_t *activation_min, int32_t *activation_max); - -// Decompose a double multiplier into a Q0.31 int32 representation of its -// significand, and shift representation of its exponent. -// -// Handles an arbitrary positive multiplier. The 'shift' output-value is -// basically the 'floating-point exponent' of the multiplier: -// Negative for a right-shift (when the multiplier is <1), positive for a -// left-shift (when the multiplier is >1) -void quantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift); - -// Decompose a double multiplier into a Q0.31 int32 representation of its -// significand, and shift representation of NEGATIVE its exponent --- -// this is intended as a RIGHT-shift. -// -// Restricted to the case where the multiplier < 1 (and non-negative). -void quantizeMultiplierSmallerThanOneExp(double double_multiplier, int32_t *quantized_multiplier, - int *left_shift); - -Shape calculateShapeForBroadcast(const Shape &input1_shape, const Shape &input2_shape); - -inline double getQuantizedConvolutionMultipler(float input_scale, float filter_scale, - float output_scale) -{ - const double input_product_scale = static_cast<double>(input_scale * filter_scale); - LUCI_INTERPRETER_CHECK(input_product_scale >= 0); - return input_product_scale / static_cast<double>(output_scale); -} - -inline tflite::RuntimeShape getTensorShape(const Tensor *tensor) -{ - if (tensor == nullptr) - return tflite::RuntimeShape(); - - const Shape &shape = tensor->shape(); - tflite::RuntimeShape runtime_shape(shape.num_dims()); - for (int i = 0; i < shape.num_dims(); ++i) - { - runtime_shape.SetDim(i, shape.dim(i)); - } - return runtime_shape; -} - -template <typename T> const T *getTensorData(const Tensor *tensor) -{ - return tensor != nullptr ? tensor->data<T>() : nullptr; -} - -template <typename T> T *getTensorData(Tensor *tensor) -{ - return tensor != nullptr ? tensor->data<T>() : nullptr; -} - -// A list of tensors in a format that can be used by kernels like split and -// concatenation. -template <typename T, bool is_const> class VectorOfTensors -{ -public: - using ElementT = typename std::conditional<is_const, const T, T>::type; - using TensorT = typename std::conditional<is_const, const Tensor, Tensor>::type; - - // Build with the tensors in 'tensor_list'. - explicit VectorOfTensors(const std::vector<TensorT *> &tensor_list) - { - const int num_tensors = tensor_list.size(); - - all_data_.reserve(num_tensors); - all_shape_.reserve(num_tensors); - all_shape_ptr_.reserve(num_tensors); - - for (TensorT *tensor : tensor_list) - { - all_data_.push_back(getTensorData<T>(tensor)); - all_shape_.push_back(getTensorShape(tensor)); - } - - // Taking the pointer from inside a std::vector is only OK if the vector is - // never modified, so we populate all_shape in the previous loop and then we - // are free to grab iterators here. - for (tflite::RuntimeShape &shape : all_shape_) - { - all_shape_ptr_.push_back(&shape); - } - } - // Return a pointer to the data pointers of all tensors in the list. For - // example: - // float* const* f = v.data(); - // f[0][1] is the second element of the first tensor. - ElementT *const *data() const { return all_data_.data(); } - - // Return a pointer the shape pointers of all tensors in the list. For - // example: - // const RuntimeShape* const* d = v.dims(); - // dims[1] are the dimensions of the second tensor in the list. - const tflite::RuntimeShape *const *shapes() const { return all_shape_ptr_.data(); } - -private: - std::vector<ElementT *> all_data_; - std::vector<tflite::RuntimeShape> all_shape_; - std::vector<tflite::RuntimeShape *> all_shape_ptr_; -}; - -// A list of quantized tensors in a format that can be used by kernels like -// split and concatenation. -template <bool is_const> class VectorOfQuantizedTensors : public VectorOfTensors<uint8_t, is_const> -{ -public: - using typename VectorOfTensors<uint8_t, is_const>::TensorT; - - // Build with the tensors in 'tensor_list'. - explicit VectorOfQuantizedTensors(const std::vector<TensorT *> &tensor_list) - : VectorOfTensors<uint8_t, is_const>(tensor_list) - { - for (TensorT *tensor : tensor_list) - { - zero_point_.push_back(tensor->zero_point()); - scale_.push_back(tensor->scale()); - } - } - - const float *scale() const { return scale_.data(); } - const int32_t *zero_point() const { return zero_point_.data(); } - -private: - std::vector<int32_t> zero_point_; - std::vector<float> scale_; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_UTILS_H diff --git a/compiler/luci-interpreter/src/loader/CMakeLists.txt b/compiler/luci-interpreter/src/loader/CMakeLists.txt deleted file mode 100644 index d99485d06..000000000 --- a/compiler/luci-interpreter/src/loader/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -nnas_find_package(GTest REQUIRED) - -set(SOURCES - GraphLoader.h - GraphLoader.cpp - KernelBuilder.h - KernelBuilder.cpp - ModuleLoader.h - ModuleLoader.cpp - RuntimeToIR.h) - -add_library(luci_interpreter_loader STATIC ${SOURCES}) -set_target_properties(luci_interpreter_loader PROPERTIES POSITION_INDEPENDENT_CODE ON) -target_include_directories(luci_interpreter_loader PUBLIC "${LUCI_INTERPRETER_SOURCE_DIR}") -target_link_libraries(luci_interpreter_loader - PUBLIC luci_lang luci_interpreter_core - PRIVATE luci_interpreter_kernels nncc_common) - -set(TEST_SOURCES KernelBuilder.test.cpp) - -GTest_AddTest(luci_interpreter_loader_test ${TEST_SOURCES}) -target_link_libraries(luci_interpreter_loader_test luci_interpreter_loader) diff --git a/compiler/luci-interpreter/src/loader/GraphLoader.cpp b/compiler/luci-interpreter/src/loader/GraphLoader.cpp deleted file mode 100644 index 95c654769..000000000 --- a/compiler/luci-interpreter/src/loader/GraphLoader.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "loader/GraphLoader.h" - -#include "loader/KernelBuilder.h" - -#include <loco/IR/Algorithm.h> - -namespace luci_interpreter -{ -namespace -{ - -template <typename NodeT> Shape getNodeShape(const NodeT *node) -{ - Shape shape(node->rank()); - for (uint32_t i = 0; i < node->rank(); ++i) - { - shape.dim(i) = node->dim(i).value(); - } - return shape; -} - -template <DataType DT> const void *getNodeDataImpl(const luci::CircleConst *node, size_t *data_size) -{ - const size_t element_size = getDataTypeSize(DT); - const int32_t num_elements = node->size<DT>(); - - *data_size = num_elements * element_size; - if (*data_size > 0) - { - // FIXME There is no good way to get the pointer to the data currently. - return &node->at<DT>(0); - } - return nullptr; -} - -const void *getNodeData(const luci::CircleConst *node, size_t *data_size) -{ - switch (node->dtype()) - { - case DataType::U8: - return getNodeDataImpl<DataType::U8>(node, data_size); - case DataType::FLOAT32: - return getNodeDataImpl<DataType::FLOAT32>(node, data_size); - case DataType::S32: - return getNodeDataImpl<DataType::S32>(node, data_size); - default: - throw std::runtime_error("Unsupported type."); - } -} - -bool isExecutableNode(const luci::CircleNode *node) -{ - switch (node->opcode()) - { - // These nodes denote inputs / outputs of a graph. - case luci::CircleOpcode::CIRCLECONST: - case luci::CircleOpcode::CIRCLEINPUT: - case luci::CircleOpcode::CIRCLEOUTPUT: - case luci::CircleOpcode::CIRCLEOUTPUTEXCLUDE: - // The following nodes denote outputs of multiple-output nodes. - case luci::CircleOpcode::CIRCLEIFOUT: - case luci::CircleOpcode::CIRCLESPLITOUT: - case luci::CircleOpcode::CIRCLEUNPACKOUT: - return false; - default: - return true; - } -} - -bool isTensorProducingNode(const luci::CircleNode *node) -{ - switch (node->opcode()) - { - // Output nodes do not produce tensors. - case luci::CircleOpcode::CIRCLEOUTPUT: - // The following nodes are multiple-output nodes. They do not produce tensors, the tensors - // are produced by the corresponding *Out nodes instead. - case luci::CircleOpcode::IF: - case luci::CircleOpcode::SPLIT: - case luci::CircleOpcode::UNPACK: - return false; - default: - return true; - } -} - -} // namespace - -GraphLoader::GraphLoader( - const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, - const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) - : _graph(graph), _runtime_graph(runtime_graph), _runtime_to_ir(runtime_to_ir), - _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor) -{ -} - -void GraphLoader::loadTensors() -{ - for (uint32_t i = 0; i < _graph->nodes()->size(); ++i) - { - const auto *node = loco::must_cast<const luci::CircleNode *>(_graph->nodes()->at(i)); - - if (!isTensorProducingNode(node)) - continue; - - // Only Input and Const nodes have shapes. Shapes of intermediate tensors will be inferred. - Shape shape{}; - if (const auto *input_node = dynamic_cast<const luci::CircleInput *>(node)) - { - shape = getNodeShape(input_node); - } - else if (const auto *const_node = dynamic_cast<const luci::CircleConst *>(node)) - { - shape = getNodeShape(const_node); - } - - AffineQuantization quantization; - if (node->quantparam() != nullptr) - { - const luci::CircleQuantParam *params = node->quantparam(); - quantization.scale.assign(params->scale.cbegin(), params->scale.cend()); - quantization.zero_point.assign(params->zerop.cbegin(), params->zerop.cend()); - quantization.quantized_dimension = params->quantized_dimension; - } - - auto tensor = std::make_unique<Tensor>(node->dtype(), std::move(shape), std::move(quantization), - node->name()); - - if (const auto *const_node = dynamic_cast<const luci::CircleConst *>(node)) - { - size_t data_size{}; - const void *const_data = getNodeData(const_node, &data_size); - if (const_data != nullptr) - tensor->writeData(const_data, data_size); - } - - _node_to_tensor.emplace(node, tensor.get()); - _runtime_to_ir.tensor_to_node.emplace(tensor.get(), node); - - _runtime_graph->addTensor(std::move(tensor)); - } -} - -void GraphLoader::initInputOutputTensors() const -{ - auto input_nodes = loco::input_nodes(_graph); - std::vector<Tensor *> input_tensors(input_nodes.size()); - for (size_t i = 0; i < input_nodes.size(); ++i) - { - input_tensors[i] = _node_to_tensor.at(input_nodes[i]); - } - _runtime_graph->setInputTensors(input_tensors); - - auto output_nodes = loco::output_nodes(const_cast<loco::Graph *>(_graph)); - std::vector<Tensor *> output_tensors(output_nodes.size()); - for (size_t i = 0; i < output_nodes.size(); ++i) - { - const auto *node = loco::must_cast<const luci::CircleOutput *>(output_nodes[i]); - output_tensors[i] = _node_to_tensor.at(node->from()); - } - _runtime_graph->setOutputTensors(output_tensors); -} - -void GraphLoader::loadOperators() -{ - KernelBuilder kernel_builder(_graph_to_runtime_graph, _node_to_tensor); - - // Create kernels for executable nodes. This has to be done in execution order. - for (const loco::Node *loco_node : - loco::postorder_traversal(loco::output_nodes(const_cast<loco::Graph *>(_graph)))) - { - const auto *node = loco::must_cast<const luci::CircleNode *>(loco_node); - - if (isExecutableNode(node)) - { - std::unique_ptr<Kernel> kernel = node->accept(&kernel_builder); - _runtime_to_ir.kernel_to_node.emplace(kernel.get(), node); - _runtime_graph->addKernel(std::move(kernel)); - } - } -} - -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/GraphLoader.h b/compiler/luci-interpreter/src/loader/GraphLoader.h deleted file mode 100644 index 89c5bcad7..000000000 --- a/compiler/luci-interpreter/src/loader/GraphLoader.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_LOADER_GRAPHLOADER_H -#define LUCI_INTERPRETER_LOADER_GRAPHLOADER_H - -#include "core/RuntimeGraph.h" -#include "loader/RuntimeToIR.h" - -#include <loco/IR/Graph.h> - -#include <unordered_map> - -namespace luci_interpreter -{ - -class GraphLoader -{ -public: - GraphLoader(const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, - const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor); - - void loadTensors(); - void initInputOutputTensors() const; - void loadOperators(); - -private: - const loco::Graph *_graph; - RuntimeGraph *_runtime_graph; - RuntimeToIR &_runtime_to_ir; - - const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph; - std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_LOADER_GRAPHLOADER_H diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.cpp b/compiler/luci-interpreter/src/loader/KernelBuilder.cpp deleted file mode 100644 index 66aa38ff0..000000000 --- a/compiler/luci-interpreter/src/loader/KernelBuilder.cpp +++ /dev/null @@ -1,842 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "loader/KernelBuilder.h" - -#include "kernels/Add.h" -#include "kernels/ArgMax.h" -#include "kernels/AveragePool2D.h" -#include "kernels/Concatenation.h" -#include "kernels/Conv2D.h" -#include "kernels/DepthToSpace.h" -#include "kernels/DepthwiseConv2D.h" -#include "kernels/Div.h" -#include "kernels/Elu.h" -#include "kernels/Floor.h" -#include "kernels/FloorDiv.h" -#include "kernels/Equal.h" -#include "kernels/FullyConnected.h" -#include "kernels/Greater.h" -#include "kernels/GreaterEqual.h" -#include "kernels/If.h" -#include "kernels/L2Normalize.h" -#include "kernels/L2Pool2D.h" -#include "kernels/LeakyRelu.h" -#include "kernels/Less.h" -#include "kernels/LessEqual.h" -#include "kernels/LocalResponseNormalization.h" -#include "kernels/Logistic.h" -#include "kernels/LogSoftmax.h" -#include "kernels/Maximum.h" -#include "kernels/MaxPool2D.h" -#include "kernels/Mean.h" -#include "kernels/Minimum.h" -#include "kernels/Mul.h" -#include "kernels/NotEqual.h" -#include "kernels/Pad.h" -#include "kernels/Pow.h" -#include "kernels/Prelu.h" -#include "kernels/Relu.h" -#include "kernels/Relu6.h" -#include "kernels/Reshape.h" -#include "kernels/ResizeBilinear.h" -#include "kernels/ResizeNearestNeighbor.h" -#include "kernels/Reverse.h" -#include "kernels/Rsqrt.h" -#include "kernels/Slice.h" -#include "kernels/Softmax.h" -#include "kernels/SpaceToDepth.h" -#include "kernels/Split.h" -#include "kernels/StridedSlice.h" -#include "kernels/Sqrt.h" -#include "kernels/Sub.h" -#include "kernels/Squeeze.h" -#include "kernels/Tanh.h" -#include "kernels/Unpack.h" -#include "kernels/Transpose.h" -#include "kernels/TransposeConv.h" - -#include <stdexcept> - -namespace luci_interpreter -{ - -template <typename CircleNodeOut> -static std::vector<const loco::Node *> collectOutputNodes(const luci::CircleNode *node) -{ - std::vector<const CircleNodeOut *> output_nodes; - for (const loco::Node *loco_node : loco::succs(node)) - { - output_nodes.push_back(loco::must_cast<const CircleNodeOut *>(loco_node)); - } - std::sort(output_nodes.begin(), output_nodes.end(), - [](const CircleNodeOut *node1, const CircleNodeOut *node2) { - return node1->index() < node2->index(); - }); - return {output_nodes.cbegin(), output_nodes.cend()}; -} - -const Tensor *KernelBuilder::getInputTensor(const loco::Node *node) const -{ - const Tensor *tensor = _node_to_tensor.at(node); - assert(tensor != nullptr); - return tensor; -} - -const Tensor *KernelBuilder::getOptionalInputTensor(const loco::Node *node) const -{ - if (dynamic_cast<const luci::CircleOutputExclude *>(node)) - { - return nullptr; - } - return getInputTensor(node); -} - -Tensor *KernelBuilder::getOutputTensor(const loco::Node *node) const -{ - Tensor *tensor = _node_to_tensor.at(node); - assert(tensor != nullptr); - return tensor; -} - -std::vector<Tensor *> -KernelBuilder::getOutputTensors(const std::vector<const loco::Node *> &nodes) const -{ - std::vector<Tensor *> tensors; - tensors.reserve(nodes.size()); - for (const loco::Node *node : nodes) - tensors.push_back(getOutputTensor(node)); - return tensors; -} - -RuntimeGraph *KernelBuilder::getRuntimeGraph(const loco::Graph *graph) const -{ - RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph); - assert(runtime_graph != nullptr); - return runtime_graph; -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAdd *node) -{ - assert(node->arity() == 2); - - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - AddParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::Add>(input1, input2, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleArgMax *node) -{ - assert(node->arity() == 2); - const Tensor *input = getInputTensor(node->input()); - const Tensor *axis = getInputTensor(node->dimension()); - Tensor *output = getOutputTensor(node); - - ArgMaxParams params{}; - params.output_type = node->output_type(); - - return std::make_unique<kernels::ArgMax>(input, axis, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAveragePool2D *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->value()); - Tensor *output = getOutputTensor(node); - - Pool2DParams params{}; - params.padding = node->padding(); - params.filter_height = node->filter()->h(); - params.filter_width = node->filter()->w(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::AveragePool2D>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConcatenation *node) -{ - std::vector<const Tensor *> inputs(node->numValues()); - for (uint32_t i = 0; i < node->numValues(); ++i) - { - inputs[i] = getInputTensor(node->values(i)); - } - Tensor *output = getOutputTensor(node); - - ConcatenationParams params{}; - params.axis = node->axis(); - - return std::make_unique<kernels::Concatenation>(std::move(inputs), output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConst *) -{ - throw std::runtime_error("Const node cannot be executed."); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConv2D *node) -{ - assert(node->arity() == 3); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *filter = getInputTensor(node->filter()); - const Tensor *bias = getInputTensor(node->bias()); - Tensor *output = getOutputTensor(node); - - Conv2DParams params{}; - params.padding = node->padding(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.dilation_height_factor = node->dilation()->h(); - params.dilation_width_factor = node->dilation()->w(); - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::Conv2D>(input, filter, bias, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthToSpace *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->input()); - Tensor *output = getOutputTensor(node); - - DepthToSpaceParams params{}; - params.block_size = node->block_size(); - - return std::make_unique<kernels::DepthToSpace>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthwiseConv2D *node) -{ - assert(node->arity() == 3); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *filter = getInputTensor(node->filter()); - const Tensor *bias = getInputTensor(node->bias()); - Tensor *output = getOutputTensor(node); - - DepthwiseConv2DParams params{}; - params.padding = node->padding(); - params.depth_multiplier = node->depthMultiplier(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.dilation_height_factor = node->dilation()->h(); - params.dilation_width_factor = node->dilation()->w(); - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::DepthwiseConv2D>(input, filter, bias, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDiv *node) -{ - assert(node->arity() == 2); - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - DivParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::Div>(input1, input2, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleElu *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->features()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Elu>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleFloor *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Floor>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleFloorDiv *node) -{ - assert(node->arity() == 2); - - const Tensor *x = getInputTensor(node->x()); - const Tensor *y = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::FloorDiv>(x, y, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleEqual *node) -{ - assert(node->arity() == 2); - - const Tensor *x = getInputTensor(node->x()); - const Tensor *y = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Equal>(x, y, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleFullyConnected *node) -{ - assert(node->arity() == 3); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *weights = getInputTensor(node->weights()); - const Tensor *bias = getOptionalInputTensor(node->bias()); - Tensor *output = getOutputTensor(node); - - FullyConnectedParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::FullyConnected>(input, weights, bias, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleGreater *node) -{ - assert(node->arity() == 2); - - const Tensor *x = getInputTensor(node->x()); - const Tensor *y = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Greater>(x, y, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleGreaterEqual *node) -{ - assert(node->arity() == 2); - - const Tensor *x = getInputTensor(node->x()); - const Tensor *y = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::GreaterEqual>(x, y, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleIf *node) -{ - auto output_nodes = collectOutputNodes<luci::CircleIfOut>(node); - assert(node->arity() == 1 + node->input_count()); - assert(output_nodes.size() == static_cast<size_t>(node->output_count())); - - const Tensor *cond = getInputTensor(node->cond()); - std::vector<const Tensor *> inputs(node->input_count()); - for (uint32_t i = 0; i < node->input_count(); ++i) - { - inputs[i] = getInputTensor(node->input(i)); - } - std::vector<Tensor *> outputs = getOutputTensors(output_nodes); - - RuntimeGraph *then_graph = getRuntimeGraph(node->then_graph()); - RuntimeGraph *else_graph = getRuntimeGraph(node->else_graph()); - - return std::make_unique<kernels::If>(cond, std::move(inputs), std::move(outputs), then_graph, - else_graph); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleInput *) -{ - throw std::runtime_error("Input node cannot be executed."); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Normalize *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - L2NormParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::L2Normalize>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Pool2D *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->value()); - Tensor *output = getOutputTensor(node); - - Pool2DParams params{}; - params.padding = node->padding(); - params.filter_height = node->filter()->h(); - params.filter_width = node->filter()->w(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::L2Pool2D>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLeakyRelu *node) -{ - assert(node->arity() == 1); - const Tensor *input = getInputTensor(node->features()); - Tensor *output = getOutputTensor(node); - - LeakyReluParams params{}; - params.alpha = node->alpha(); - - return std::make_unique<kernels::LeakyRelu>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLess *node) -{ - assert(node->arity() == 2); - - const Tensor *x = getInputTensor(node->x()); - const Tensor *y = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Less>(x, y, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLessEqual *node) -{ - assert(node->arity() == 2); - - const Tensor *x = getInputTensor(node->x()); - const Tensor *y = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::LessEqual>(x, y, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLocalResponseNormalization *node) -{ - assert(node->arity() == 1); - const Tensor *input = getInputTensor(node->input()); - Tensor *output = getOutputTensor(node); - - LocalResponseNormalizationParams params{}; - params.radius = node->radius(); - params.bias = node->bias(); - params.alpha = node->alpha(); - params.beta = node->beta(); - - return std::make_unique<kernels::LocalResponseNormalization>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLogistic *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Logistic>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLogSoftmax *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->logits()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::LogSoftmax>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMaximum *node) -{ - assert(node->arity() == 2); - - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Maximum>(input1, input2, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMaxPool2D *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->value()); - Tensor *output = getOutputTensor(node); - - Pool2DParams params{}; - params.padding = node->padding(); - params.filter_height = node->filter()->h(); - params.filter_width = node->filter()->w(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::MaxPool2D>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMean *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *axes = getInputTensor(node->reduction_indices()); - Tensor *output = getOutputTensor(node); - - ReducerParams params{}; - params.keep_dims = node->keep_dims(); - - return std::make_unique<kernels::Mean>(input, axes, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMinimum *node) -{ - assert(node->arity() == 2); - - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Minimum>(input1, input2, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMul *node) -{ - assert(node->arity() == 2); - - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - MulParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::Mul>(input1, input2, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleNotEqual *node) -{ - assert(node->arity() == 2); - - const Tensor *x = getInputTensor(node->x()); - const Tensor *y = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::NotEqual>(x, y, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleOutput *) -{ - throw std::runtime_error("Output node cannot be executed."); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CirclePad *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *paddings = getInputTensor(node->paddings()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Pad>(input, paddings, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CirclePow *node) -{ - assert(node->arity() == 2); - - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Pow>(input1, input2, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CirclePRelu *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *alpha = getInputTensor(node->alpha()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Prelu>(input, alpha, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleRelu *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->features()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Relu>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleRelu6 *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->features()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Relu6>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReshape *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->tensor()); - const Tensor *shape = getInputTensor(node->shape()); - Tensor *output = getOutputTensor(node); - - // NOTE 'newShape' attribute is ignored. - return std::make_unique<kernels::Reshape>(input, shape, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleResizeBilinear *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *size = getInputTensor(node->size()); - Tensor *output = getOutputTensor(node); - - ResizeBilinearParams params{}; - params.align_corners = node->align_corners(); - params.half_pixel_centers = node->half_pixel_centers(); - - return std::make_unique<kernels::ResizeBilinear>(input, size, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleResizeNearestNeighbor *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *size = getInputTensor(node->size()); - Tensor *output = getOutputTensor(node); - - ResizeNearestNeighborParams params{}; - params.align_corners = node->align_corners(); - // TODO update half_pixel_centers after CircleResizeNearestNeighbor updated - // Current CircleResizeNearestNeighbor don't have half_pixel_centers. - // default value on current is false. - // it need to be updated when CircleResizeNearestNeighbor updated. - params.half_pixel_centers = false; - - return std::make_unique<kernels::ResizeNearestNeighbor>(input, size, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReverseV2 *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->tensor()); - const Tensor *axes = getInputTensor(node->axis()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Reverse>(input, axes, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleRsqrt *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Rsqrt>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSub *node) -{ - assert(node->arity() == 2); - - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - SubParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::Sub>(input1, input2, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSlice *node) -{ - assert(node->arity() == 3); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *begin = getInputTensor(node->begin()); - const Tensor *size = getInputTensor(node->size()); - - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Slice>(input, begin, size, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSoftmax *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->logits()); - Tensor *output = getOutputTensor(node); - - SoftmaxParams params{}; - params.beta = node->beta(); - - return std::make_unique<kernels::Softmax>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSpaceToDepth *node) -{ - assert(node->arity() == 1); - const Tensor *input = getInputTensor(node->input()); - - Tensor *output = getOutputTensor(node); - - SpaceToDepthParams params{}; - params.block_size = node->block_size(); - - return std::make_unique<kernels::SpaceToDepth>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSplit *node) -{ - auto output_nodes = collectOutputNodes<luci::CircleSplitOut>(node); - assert(node->arity() == 2); - assert(output_nodes.size() == static_cast<size_t>(node->num_split())); - - const Tensor *axis = getInputTensor(node->split_dim()); - const Tensor *input = getInputTensor(node->input()); - std::vector<Tensor *> outputs = getOutputTensors(output_nodes); - - // NOTE 'num_splits' attribute is ignored. - return std::make_unique<kernels::Split>(axis, input, std::move(outputs)); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqrt *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Sqrt>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqueeze *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->input()); - Tensor *output = getOutputTensor(node); - - SqueezeParams params{}; - params.squeeze_dims = node->squeeze_dims(); - - return std::make_unique<kernels::Squeeze>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleStridedSlice *node) -{ - assert(node->arity() == 4); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *begin = getInputTensor(node->begin()); - const Tensor *end = getInputTensor(node->end()); - const Tensor *strides = getInputTensor(node->strides()); - - Tensor *output = getOutputTensor(node); - - StridedSliceParams params{}; - params.begin_mask = node->begin_mask(); - params.ellipsis_mask = node->ellipsis_mask(); - params.end_mask = node->end_mask(); - params.new_axis_mask = node->new_axis_mask(); - params.shrink_axis_mask = node->shrink_axis_mask(); - - return std::make_unique<kernels::StridedSlice>(input, begin, end, strides, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTanh *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Tanh>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTranspose *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->a()); - const Tensor *perm = getInputTensor(node->perm()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Transpose>(input, perm, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTransposeConv *node) -{ - assert(node->arity() == 4); - - const Tensor *input_sizes = getInputTensor(node->inputSizes()); - const Tensor *filter = getInputTensor(node->filter()); - const Tensor *out_backprop = getInputTensor(node->outBackprop()); - const Tensor *bias = getOptionalInputTensor(node->bias()); - - Tensor *output = getOutputTensor(node); - - TransposeConvParams params{}; - params.padding = node->padding(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - - return std::make_unique<kernels::TransposeConv>(input_sizes, filter, out_backprop, bias, output, - params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleUnpack *node) -{ - auto output_nodes = collectOutputNodes<luci::CircleUnpackOut>(node); - assert(node->arity() == 1); - assert(output_nodes.size() == static_cast<size_t>(node->num())); - - const Tensor *input = getInputTensor(node->value()); - std::vector<Tensor *> outputs = getOutputTensors(output_nodes); - - UnpackParams params{}; - params.axis = node->axis(); - - // NOTE 'num' attribute is ignored. - return std::make_unique<kernels::Unpack>(input, std::move(outputs), params); -} - -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.h b/compiler/luci-interpreter/src/loader/KernelBuilder.h deleted file mode 100644 index 663104700..000000000 --- a/compiler/luci-interpreter/src/loader/KernelBuilder.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_LOADER_KERNELBUILDER_H -#define LUCI_INTERPRETER_LOADER_KERNELBUILDER_H - -#include "core/Kernel.h" -#include "core/RuntimeGraph.h" - -#include <luci/IR/CircleNodeVisitor.h> - -#include <memory> -#include <vector> -#include <unordered_map> - -namespace luci_interpreter -{ - -class KernelBuilder : public luci::CircleNodeVisitor<std::unique_ptr<Kernel>> -{ -public: - KernelBuilder( - const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, - const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) - : _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor) - { - } - - std::unique_ptr<Kernel> visit(const luci::CircleAdd *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleArgMax *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleAveragePool2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleConcatenation *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleConv2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleConst *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleDepthToSpace *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleDepthwiseConv2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleDiv *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleElu *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleFloor *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleFloorDiv *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleEqual *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleFullyConnected *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleGreater *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleGreaterEqual *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleIf *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleL2Normalize *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleL2Pool2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLeakyRelu *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLess *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLessEqual *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLocalResponseNormalization *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLogistic *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLogSoftmax *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleInput *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleMaximum *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleMaxPool2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleMean *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleMinimum *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleMul *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleNotEqual *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleOutput *node) override; - std::unique_ptr<Kernel> visit(const luci::CirclePad *node) override; - std::unique_ptr<Kernel> visit(const luci::CirclePow *node) override; - std::unique_ptr<Kernel> visit(const luci::CirclePRelu *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleRelu *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleRelu6 *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleReshape *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleResizeBilinear *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleResizeNearestNeighbor *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleReverseV2 *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleRsqrt *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSub *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSlice *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSoftmax *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSpaceToDepth *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSplit *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleStridedSlice *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSqrt *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSqueeze *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleTanh *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleTranspose *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleTransposeConv *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleUnpack *node) override; - -private: - const Tensor *getInputTensor(const loco::Node *node) const; - - const Tensor *getOptionalInputTensor(const loco::Node *node) const; - - Tensor *getOutputTensor(const loco::Node *node) const; - - std::vector<Tensor *> getOutputTensors(const std::vector<const loco::Node *> &nodes) const; - - RuntimeGraph *getRuntimeGraph(const loco::Graph *graph) const; - -private: - const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph; - const std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_LOADER_KERNELBUILDER_H diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp b/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp deleted file mode 100644 index ea055542d..000000000 --- a/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp +++ /dev/null @@ -1,1135 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "loader/GraphLoader.h" -#include "loader/KernelBuilder.h" - -#include <kernels/Add.h> -#include <kernels/ArgMax.h> -#include <kernels/AveragePool2D.h> -#include <kernels/Concatenation.h> -#include <kernels/Conv2D.h> -#include <kernels/DepthToSpace.h> -#include <kernels/DepthwiseConv2D.h> -#include <kernels/Div.h> -#include <kernels/Elu.h> -#include <kernels/Floor.h> -#include <kernels/FloorDiv.h> -#include <kernels/Equal.h> -#include <kernels/FullyConnected.h> -#include <kernels/Greater.h> -#include <kernels/GreaterEqual.h> -#include <kernels/L2Normalize.h> -#include <kernels/L2Pool2D.h> -#include <kernels/LeakyRelu.h> -#include <kernels/Less.h> -#include <kernels/LessEqual.h> -#include <kernels/LocalResponseNormalization.h> -#include <kernels/Logistic.h> -#include <kernels/LogSoftmax.h> -#include <kernels/Maximum.h> -#include <kernels/MaxPool2D.h> -#include <kernels/Mean.h> -#include <kernels/Minimum.h> -#include <kernels/Mul.h> -#include <kernels/NotEqual.h> -#include <kernels/Pad.h> -#include <kernels/Pow.h> -#include <kernels/Prelu.h> -#include <kernels/Relu.h> -#include <kernels/Relu6.h> -#include <kernels/Reshape.h> -#include <kernels/ResizeBilinear.h> -#include <kernels/ResizeNearestNeighbor.h> -#include <kernels/Reverse.h> -#include <kernels/Rsqrt.h> -#include <kernels/Slice.h> -#include <kernels/Softmax.h> -#include <kernels/SpaceToDepth.h> -#include <kernels/Split.h> -#include <kernels/Sqrt.h> -#include <kernels/Sub.h> -#include <kernels/Squeeze.h> -#include <kernels/StridedSlice.h> -#include <kernels/Tanh.h> -#include <kernels/Transpose.h> -#include <kernels/TransposeConv.h> -#include <kernels/Unpack.h> - -#include <gmock/gmock.h> - -namespace luci_interpreter -{ -namespace -{ - -using namespace testing; - -class KernelBuilderTest : public Test -{ -protected: - luci::CircleInput *createInputNode() { return createNode<luci::CircleInput>(); } - - template <typename NodeT, typename... Args> NodeT *createNode(Args &&... args) - { - auto *node = _graph.nodes()->create<NodeT>(std::forward<Args>(args)...); - // The actual type does not matter for the purpose of the tests. - // NOTE The type is meaningless for nodes with multiple outputs (corresponding *Out nodes carry - // actual output types). - node->dtype(loco::DataType::FLOAT32); - return node; - } - - template <typename NodeOutT> NodeOutT *createNodeOut(loco::Node *node, int index) - { - auto *node_out = createNode<NodeOutT>(); - node_out->input(node); - node_out->index(index); - return node_out; - } - - template <typename KernelT> std::unique_ptr<KernelT> buildKernel(const luci::CircleNode *op) - { - std::unordered_map<const loco::Graph *, RuntimeGraph *> graph_to_runtime_graph; - - RuntimeGraph runtime_graph(nullptr); - RuntimeToIR runtime_to_ir; - GraphLoader graph_loader(&_graph, &runtime_graph, runtime_to_ir, graph_to_runtime_graph, - _node_to_tensor); - graph_loader.loadTensors(); - - KernelBuilder kernel_builder(graph_to_runtime_graph, _node_to_tensor); - - auto kernel = op->accept(&kernel_builder); - return std::unique_ptr<KernelT>(dynamic_cast<KernelT *>(kernel.release())); - } - - void checkTensor(const Tensor *tensor, const loco::Node *node) - { - EXPECT_THAT(tensor, Eq(_node_to_tensor.at(node))); - } - -private: - loco::Graph _graph; - std::unordered_map<const loco::Node *, Tensor *> _node_to_tensor; -}; - -TEST_F(KernelBuilderTest, Add) -{ - auto *input1 = createInputNode(); - auto *input2 = createInputNode(); - - auto *op = createNode<luci::CircleAdd>(); - op->x(input1); - op->y(input2); - - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::Add>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input1(), input1); - checkTensor(kernel->input2(), input2); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, ArgMax) -{ - auto *input = createInputNode(); - auto *axis = createInputNode(); - - auto *op = createNode<luci::CircleArgMax>(); - op->input(input); - op->dimension(axis); - - op->output_type(loco::DataType::FLOAT32); - - auto kernel = buildKernel<kernels::ArgMax>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->axis(), axis); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().output_type, Eq(op->output_type())); -} - -TEST_F(KernelBuilderTest, AveragePool2D) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleAveragePool2D>(); - op->value(input); - - op->padding(luci::Padding::SAME); - op->filter()->h(11); - op->filter()->w(13); - op->stride()->h(17); - op->stride()->w(19); - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::AveragePool2D>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().padding, Eq(op->padding())); - EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h())); - EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w())); - EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); - EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, Concatenation) -{ - auto *input1 = createInputNode(); - auto *input2 = createInputNode(); - - auto *op = createNode<luci::CircleConcatenation>(2); - op->values(0, input1); - op->values(1, input2); - op->axis(11); - - auto kernel = buildKernel<kernels::Concatenation>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(0), input1); - checkTensor(kernel->input(1), input2); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().axis, Eq(op->axis())); -} - -TEST_F(KernelBuilderTest, Conv2D) -{ - auto *input = createInputNode(); - auto *filter = createInputNode(); - auto *bias = createInputNode(); - - auto *op = createNode<luci::CircleConv2D>(); - op->input(input); - op->filter(filter); - op->bias(bias); - - op->padding(luci::Padding::SAME); - op->stride()->h(11); - op->stride()->w(13); - op->dilation()->h(17); - op->dilation()->w(19); - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::Conv2D>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->filter(), filter); - checkTensor(kernel->bias(), bias); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().padding, Eq(op->padding())); - EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); - EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); - EXPECT_THAT(kernel->params().dilation_height_factor, Eq(op->dilation()->h())); - EXPECT_THAT(kernel->params().dilation_width_factor, Eq(op->dilation()->w())); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, DepthToSpace) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleDepthToSpace>(); - op->input(input); - - op->block_size(11); - - auto kernel = buildKernel<kernels::DepthToSpace>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().block_size, Eq(op->block_size())); -} - -TEST_F(KernelBuilderTest, DepthwiseConv2D) -{ - auto *input = createInputNode(); - auto *filter = createInputNode(); - auto *bias = createInputNode(); - - auto *op = createNode<luci::CircleDepthwiseConv2D>(); - op->input(input); - op->filter(filter); - op->bias(bias); - - op->padding(luci::Padding::SAME); - op->depthMultiplier(11); - op->stride()->h(13); - op->stride()->w(17); - op->dilation()->h(19); - op->dilation()->w(23); - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::DepthwiseConv2D>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->filter(), filter); - checkTensor(kernel->bias(), bias); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().padding, Eq(op->padding())); - EXPECT_THAT(kernel->params().depth_multiplier, Eq(op->depthMultiplier())); - EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); - EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); - EXPECT_THAT(kernel->params().dilation_height_factor, Eq(op->dilation()->h())); - EXPECT_THAT(kernel->params().dilation_width_factor, Eq(op->dilation()->w())); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, Div) -{ - auto *input1 = createInputNode(); - auto *input2 = createInputNode(); - - auto *op = createNode<luci::CircleDiv>(); - op->x(input1); - op->y(input2); - - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::Div>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input1(), input1); - checkTensor(kernel->input2(), input2); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, Elu) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleElu>(); - op->features(input); - - auto kernel = buildKernel<kernels::Elu>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Floor) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleFloor>(); - op->x(input); - - auto kernel = buildKernel<kernels::Floor>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, FloorDiv) -{ - auto *x = createInputNode(); - auto *y = createInputNode(); - - auto *op = createNode<luci::CircleFloorDiv>(); - op->x(x); - op->y(y); - - auto kernel = buildKernel<kernels::FloorDiv>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->x(), x); - checkTensor(kernel->y(), y); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Equal) -{ - auto *x_input = createInputNode(); - auto *y_input = createInputNode(); - - auto *op = createNode<luci::CircleEqual>(); - op->x(x_input); - op->y(y_input); - - auto kernel = buildKernel<kernels::Equal>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->x(), x_input); - checkTensor(kernel->y(), y_input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, FullyConnected) -{ - auto *input = createInputNode(); - auto *weights = createInputNode(); - auto *bias = createInputNode(); - - auto *op = createNode<luci::CircleFullyConnected>(); - op->input(input); - op->weights(weights); - op->bias(bias); - - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::FullyConnected>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->weights(), weights); - checkTensor(kernel->bias(), bias); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, Greater) -{ - auto *x_input = createInputNode(); - auto *y_input = createInputNode(); - - auto *op = createNode<luci::CircleGreater>(); - op->x(x_input); - op->y(y_input); - - auto kernel = buildKernel<kernels::Greater>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->x(), x_input); - checkTensor(kernel->y(), y_input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, GreaterEqual) -{ - auto *x_input = createInputNode(); - auto *y_input = createInputNode(); - - auto *op = createNode<luci::CircleGreaterEqual>(); - op->x(x_input); - op->y(y_input); - - auto kernel = buildKernel<kernels::GreaterEqual>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->x(), x_input); - checkTensor(kernel->y(), y_input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, L2Normalize) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleL2Normalize>(); - op->x(input); - - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::L2Normalize>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, L2Pool2D) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleL2Pool2D>(); - op->value(input); - - op->padding(luci::Padding::SAME); - op->filter()->h(11); - op->filter()->w(13); - op->stride()->h(17); - op->stride()->w(19); - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::L2Pool2D>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().padding, Eq(op->padding())); - EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h())); - EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w())); - EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); - EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, LeakyRelu) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleLeakyRelu>(); - op->features(input); - - op->alpha(11.0f); - - auto kernel = buildKernel<kernels::LeakyRelu>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().alpha, Eq(op->alpha())); -} - -TEST_F(KernelBuilderTest, Less) -{ - auto *x_input = createInputNode(); - auto *y_input = createInputNode(); - - auto *op = createNode<luci::CircleLess>(); - op->x(x_input); - op->y(y_input); - - auto kernel = buildKernel<kernels::Less>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->x(), x_input); - checkTensor(kernel->y(), y_input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, LessEqual) -{ - auto *x_input = createInputNode(); - auto *y_input = createInputNode(); - - auto *op = createNode<luci::CircleLessEqual>(); - op->x(x_input); - op->y(y_input); - - auto kernel = buildKernel<kernels::LessEqual>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->x(), x_input); - checkTensor(kernel->y(), y_input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, LocalResponseNormalization) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleLocalResponseNormalization>(); - op->input(input); - - op->radius(11); - op->bias(13.0f); - op->alpha(15.0f); - op->beta(17.0f); - - auto kernel = buildKernel<kernels::LocalResponseNormalization>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().radius, Eq(op->radius())); - EXPECT_THAT(kernel->params().bias, Eq(op->bias())); - EXPECT_THAT(kernel->params().alpha, Eq(op->alpha())); - EXPECT_THAT(kernel->params().beta, Eq(op->beta())); -} - -TEST_F(KernelBuilderTest, Logistic) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleLogistic>(); - op->x(input); - - auto kernel = buildKernel<kernels::Logistic>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, LogSoftmax) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleLogSoftmax>(); - op->logits(input); - - auto kernel = buildKernel<kernels::LogSoftmax>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Maximum) -{ - auto *input1 = createInputNode(); - auto *input2 = createInputNode(); - - auto *op = createNode<luci::CircleMaximum>(); - op->x(input1); - op->y(input2); - - auto kernel = buildKernel<kernels::Maximum>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input1(), input1); - checkTensor(kernel->input2(), input2); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, MaxPool2D) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleMaxPool2D>(); - op->value(input); - - op->padding(luci::Padding::SAME); - op->filter()->h(11); - op->filter()->w(13); - op->stride()->h(17); - op->stride()->w(19); - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::MaxPool2D>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().padding, Eq(op->padding())); - EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h())); - EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w())); - EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); - EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, Mean) -{ - auto *input = createInputNode(); - auto *axes = createInputNode(); - - auto *op = createNode<luci::CircleMean>(); - op->input(input); - op->reduction_indices(axes); - - op->keep_dims(true); - - auto kernel = buildKernel<kernels::Mean>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->axes(), axes); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().keep_dims, Eq(op->keep_dims())); -} - -TEST_F(KernelBuilderTest, Minimum) -{ - auto *input1 = createInputNode(); - auto *input2 = createInputNode(); - - auto *op = createNode<luci::CircleMinimum>(); - op->x(input1); - op->y(input2); - - auto kernel = buildKernel<kernels::Minimum>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input1(), input1); - checkTensor(kernel->input2(), input2); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Mul) -{ - auto *input1 = createInputNode(); - auto *input2 = createInputNode(); - - auto *op = createNode<luci::CircleMul>(); - op->x(input1); - op->y(input2); - - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::Mul>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input1(), input1); - checkTensor(kernel->input2(), input2); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, NotEqual) -{ - auto *x_input = createInputNode(); - auto *y_input = createInputNode(); - - auto *op = createNode<luci::CircleNotEqual>(); - op->x(x_input); - op->y(y_input); - - auto kernel = buildKernel<kernels::NotEqual>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->x(), x_input); - checkTensor(kernel->y(), y_input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Pad) -{ - auto *input = createInputNode(); - auto *paddings = createInputNode(); - - auto *op = createNode<luci::CirclePad>(); - op->input(input); - op->paddings(paddings); - - auto kernel = buildKernel<kernels::Pad>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->paddings(), paddings); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Pow) -{ - auto *input1 = createInputNode(); - auto *input2 = createInputNode(); - - auto *op = createNode<luci::CirclePow>(); - op->x(input1); - op->y(input2); - - auto kernel = buildKernel<kernels::Pow>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input1(), input1); - checkTensor(kernel->input2(), input2); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Prelu) -{ - auto *input = createInputNode(); - auto *alpha = createInputNode(); - - auto *op = createNode<luci::CirclePRelu>(); - op->input(input); - op->alpha(alpha); - - auto kernel = buildKernel<kernels::Prelu>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->alpha(), alpha); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Relu) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleRelu>(); - op->features(input); - - auto kernel = buildKernel<kernels::Relu>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Relu6) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleRelu6>(); - op->features(input); - - auto kernel = buildKernel<kernels::Relu6>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Reshape) -{ - auto *input = createInputNode(); - auto *shape = createInputNode(); - - auto *op = createNode<luci::CircleReshape>(); - op->tensor(input); - op->shape(shape); - - auto kernel = buildKernel<kernels::Reshape>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->shape(), shape); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, ResizeBilinear) -{ - auto *input = createInputNode(); - auto *size = createInputNode(); - - auto *op = createNode<luci::CircleResizeBilinear>(); - op->input(input); - op->size(size); - op->align_corners(true); - op->half_pixel_centers(true); - - auto kernel = buildKernel<kernels::ResizeBilinear>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->size(), size); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().align_corners, Eq(op->align_corners())); - EXPECT_THAT(kernel->params().half_pixel_centers, Eq(op->half_pixel_centers())); -} - -TEST_F(KernelBuilderTest, ResizeNearestNeighbor) -{ - auto *input = createInputNode(); - auto *size = createInputNode(); - - auto *op = createNode<luci::CircleResizeNearestNeighbor>(); - op->input(input); - op->size(size); - op->align_corners(true); - - auto kernel = buildKernel<kernels::ResizeNearestNeighbor>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->size(), size); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().align_corners, Eq(op->align_corners())); - // TODO currently half_pixel_centers are not implemented on CircleResizeNearestNeighbor - // after adding, need to be updated. -} - -TEST_F(KernelBuilderTest, ReverseV2) -{ - auto *input = createInputNode(); - auto *axes = createInputNode(); - - auto *op = createNode<luci::CircleReverseV2>(); - op->tensor(input); - op->axis(axes); - - auto kernel = buildKernel<kernels::Reverse>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->axes(), axes); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Rsqrt) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleRsqrt>(); - op->x(input); - - auto kernel = buildKernel<kernels::Rsqrt>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Slice) -{ - auto *input = createInputNode(); - auto *begin = createInputNode(); - auto *size = createInputNode(); - - auto *op = createNode<luci::CircleSlice>(); - op->input(input); - op->begin(begin); - op->size(size); - - auto kernel = buildKernel<kernels::Slice>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->begin(), begin); - checkTensor(kernel->size(), size); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Softmax) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleSoftmax>(); - op->logits(input); - - op->beta(11.0f); - - auto kernel = buildKernel<kernels::Softmax>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().beta, Eq(op->beta())); -} - -TEST_F(KernelBuilderTest, SpaceToDepth) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleSpaceToDepth>(); - op->input(input); - - op->block_size(11); - - auto kernel = buildKernel<kernels::SpaceToDepth>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().block_size, op->block_size()); -} - -TEST_F(KernelBuilderTest, Split) -{ - auto *axis = createInputNode(); - auto *input = createInputNode(); - auto *op = createNode<luci::CircleSplit>(); - auto *output1 = createNodeOut<luci::CircleSplitOut>(op, 0); - auto *output2 = createNodeOut<luci::CircleSplitOut>(op, 1); - - op->split_dim(axis); - op->input(input); - - op->num_split(2); - - auto kernel = buildKernel<kernels::Split>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->axis(), axis); - checkTensor(kernel->input(), input); - checkTensor(kernel->output(0), output1); - checkTensor(kernel->output(1), output2); -} - -TEST_F(KernelBuilderTest, Sqrt) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleSqrt>(); - op->x(input); - - auto kernel = buildKernel<kernels::Sqrt>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Sub) -{ - auto *input1 = createInputNode(); - auto *input2 = createInputNode(); - - auto *op = createNode<luci::CircleSub>(); - op->x(input1); - op->y(input2); - - op->fusedActivationFunction(luci::FusedActFunc::RELU); - - auto kernel = buildKernel<kernels::Sub>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input1(), input1); - checkTensor(kernel->input2(), input2); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); -} - -TEST_F(KernelBuilderTest, Squeeze) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleSqueeze>(); - op->input(input); - - op->squeeze_dims({11, 13}); - - auto kernel = buildKernel<kernels::Squeeze>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().squeeze_dims, ElementsAreArray(op->squeeze_dims())); -} - -TEST_F(KernelBuilderTest, StridedSlice) -{ - auto *input = createInputNode(); - auto *begin = createInputNode(); - auto *end = createInputNode(); - auto *strides = createInputNode(); - - auto *op = createNode<luci::CircleStridedSlice>(); - op->input(input); - op->begin(begin); - op->end(end); - op->strides(strides); - - op->begin_mask(11); - op->ellipsis_mask(13); - op->end_mask(17); - op->new_axis_mask(19); - op->shrink_axis_mask(23); - - auto kernel = buildKernel<kernels::StridedSlice>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->begin(), begin); - checkTensor(kernel->end(), end); - checkTensor(kernel->strides(), strides); - checkTensor(kernel->output(), op); - EXPECT_THAT(kernel->params().begin_mask, Eq(op->begin_mask())); - EXPECT_THAT(kernel->params().ellipsis_mask, Eq(op->ellipsis_mask())); - EXPECT_THAT(kernel->params().end_mask, Eq(op->end_mask())); - EXPECT_THAT(kernel->params().new_axis_mask, Eq(op->new_axis_mask())); - EXPECT_THAT(kernel->params().shrink_axis_mask, Eq(op->shrink_axis_mask())); -} - -TEST_F(KernelBuilderTest, Tanh) -{ - auto *input = createInputNode(); - - auto *op = createNode<luci::CircleTanh>(); - op->x(input); - - auto kernel = buildKernel<kernels::Tanh>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, Transpose) -{ - auto *input = createInputNode(); - auto *perm = createInputNode(); - - auto *op = createNode<luci::CircleTranspose>(); - op->a(input); - op->perm(perm); - - auto kernel = buildKernel<kernels::Transpose>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->perm(), perm); - checkTensor(kernel->output(), op); -} - -TEST_F(KernelBuilderTest, TransposeConv) -{ - auto *output_shape = createInputNode(); - auto *filter = createInputNode(); - auto *input = createInputNode(); - auto *bias = createInputNode(); - - auto *op = createNode<luci::CircleTransposeConv>(); - op->inputSizes(output_shape); - op->filter(filter); - op->outBackprop(input); - op->bias(bias); - - op->padding(luci::Padding::SAME); - op->stride()->h(11); - op->stride()->w(13); - - auto kernel = buildKernel<kernels::TransposeConv>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->output_shape(), output_shape); - checkTensor(kernel->filter(), filter); - checkTensor(kernel->input(), input); - checkTensor(kernel->output(), op); - checkTensor(kernel->bias(), bias); - EXPECT_THAT(kernel->params().padding, Eq(op->padding())); - EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); - EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); -} - -TEST_F(KernelBuilderTest, Unpack) -{ - auto *input = createInputNode(); - auto *op = createNode<luci::CircleUnpack>(); - auto *output1 = createNodeOut<luci::CircleUnpackOut>(op, 0); - auto *output2 = createNodeOut<luci::CircleUnpackOut>(op, 1); - - op->value(input); - - op->num(2); - op->axis(11); - - auto kernel = buildKernel<kernels::Unpack>(op); - ASSERT_THAT(kernel, NotNull()); - - checkTensor(kernel->input(), input); - checkTensor(kernel->output(0), output1); - checkTensor(kernel->output(1), output2); - EXPECT_THAT(kernel->params().axis, Eq(op->axis())); -} - -TEST_F(KernelBuilderTest, NonExisting1_NEG) -{ - auto *op = createNode<luci::CircleConst>(); - ASSERT_ANY_THROW(buildKernel<Kernel>(op)); -} - -TEST_F(KernelBuilderTest, NonExisting2_NEG) -{ - auto *op = createNode<luci::CircleInput>(); - ASSERT_ANY_THROW(buildKernel<Kernel>(op)); -} - -TEST_F(KernelBuilderTest, NonExisting3_NEG) -{ - auto *op = createNode<luci::CircleOutput>(); - ASSERT_ANY_THROW(buildKernel<Kernel>(op)); -} - -} // namespace -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/ModuleLoader.cpp b/compiler/luci-interpreter/src/loader/ModuleLoader.cpp deleted file mode 100644 index b9a2ae0a9..000000000 --- a/compiler/luci-interpreter/src/loader/ModuleLoader.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ModuleLoader.h" - -#include "GraphLoader.h" - -namespace luci_interpreter -{ - -ModuleLoader::ModuleLoader(const luci::Module *module, RuntimeModule *runtime_module, - RuntimeToIR &runtime_to_ir, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) - : _module(module), _runtime_module(runtime_module), _runtime_to_ir(runtime_to_ir), - _node_to_tensor(node_to_tensor) -{ -} - -void ModuleLoader::load() -{ - // Runtime graphs have to be created in advance, because they will be needed during the loading - // process for control flow nodes. - for (size_t i = 0; i < _module->size(); ++i) - { - _graph_to_runtime_graph.emplace(_module->graph(i), _runtime_module->addGraph()); - } - for (size_t i = 0; i < _module->size(); ++i) - { - const loco::Graph *graph = _module->graph(i); - RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph); - GraphLoader loader(graph, runtime_graph, _runtime_to_ir, _graph_to_runtime_graph, - _node_to_tensor); - loader.loadTensors(); - loader.initInputOutputTensors(); - loader.loadOperators(); - } -} - -} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/ModuleLoader.h b/compiler/luci-interpreter/src/loader/ModuleLoader.h deleted file mode 100644 index 1af0ed747..000000000 --- a/compiler/luci-interpreter/src/loader/ModuleLoader.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_LOADER_MODULELOADER_H -#define LUCI_INTERPRETER_LOADER_MODULELOADER_H - -#include "core/RuntimeModule.h" -#include "loader/RuntimeToIR.h" - -#include <luci/IR/Module.h> - -#include <unordered_map> - -namespace luci_interpreter -{ - -class ModuleLoader -{ -public: - ModuleLoader(const luci::Module *module, RuntimeModule *runtime_module, - RuntimeToIR &runtime_to_ir, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor); - - void load(); - -private: - const luci::Module *_module; - RuntimeModule *_runtime_module; - RuntimeToIR &_runtime_to_ir; - std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor; - std::unordered_map<const loco::Graph *, RuntimeGraph *> _graph_to_runtime_graph; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_LOADER_MODULELOADER_H diff --git a/compiler/luci-interpreter/src/loader/RuntimeToIR.h b/compiler/luci-interpreter/src/loader/RuntimeToIR.h deleted file mode 100644 index 9ea8b1fa2..000000000 --- a/compiler/luci-interpreter/src/loader/RuntimeToIR.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_LOADER_RUNTIMETOIR_H -#define LUCI_INTERPRETER_LOADER_RUNTIMETOIR_H - -#include "luci_interpreter/core/Tensor.h" - -#include <luci/IR/CircleNode.h> - -#include <unordered_map> - -namespace luci_interpreter -{ - -// Maps runtime entities back to IR entities. It is used to implement observing functionality. -struct RuntimeToIR -{ - std::unordered_map<const Tensor *, const luci::CircleNode *> tensor_to_node; - std::unordered_map<const Kernel *, const luci::CircleNode *> kernel_to_node; -}; - -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_LOADER_RUNTIMETOIR_H |