* @bug No known bugs except for NYI items
*/
+#include <layer_internal.h>
#include <nntrainer_error.h>
#include <nntrainer_log.h>
#include <tflite_layer.h>
}
}
-int TfLiteLayer::initialize(Manager &manager) {
+void TfLiteLayer::finalize(InitLayerContext &context) {
tflite::ops::builtin::BuiltinOpResolver resolver;
model = tflite::FlatBufferModel::BuildFromFile(modelfile.c_str());
if (!model)
- return ML_ERROR_INVALID_PARAMETER;
+ throw std::invalid_argument("Failed to build tflite model");
tflite::InterpreterBuilder(*model.get(), resolver)(&interpreter);
if (!interpreter)
- return ML_ERROR_INVALID_PARAMETER;
+ throw std::invalid_argument("Failed to build tflite interpreter");
if (interpreter->AllocateTensors() != kTfLiteOk)
throw std::runtime_error("Failed to allocate tensors!");
std::vector<TensorDim> dims;
setDimensions(interpreter->inputs(), dims, false);
- setDimensions(interpreter->outputs(), output_dim, true);
+ const std::vector<TensorDim> &input_dims = context.getInputDimensions();
- if (input_dim.size() && input_dim[0].getTensorDim(0) != 0) {
- if (dims.size() != input_dim.size())
- throw std::invalid_argument(
- "Provided number of input dimensions mismatch");
+ if (dims.size() != input_dims.size())
+ throw std::invalid_argument("Provided number of input dimensions mismatch");
- for (size_t idx = 0; idx < dims.size(); idx++) {
- if (dims[idx] != input_dim[idx])
- throw std::invalid_argument("Input dimensions mismatch");
- }
- } else {
- input_dim.resize(dims.size());
- std::copy(dims.begin(), dims.end(), input_dim.begin());
+ for (size_t idx = 0; idx < dims.size(); idx++) {
+ if (dims[idx] != input_dims[idx])
+ throw std::invalid_argument("Input dimensions mismatch");
}
- return ML_ERROR_NONE;
+ std::vector<TensorDim> output_dims;
+ setDimensions(interpreter->outputs(), output_dims, true);
+ context.setOutputDimensions(output_dims);
+}
+
+void TfLiteLayer::setProperty(const std::vector<std::string> &values) {
+ /// @todo: deprecate this in favor of loadProperties
+ for (unsigned int i = 0; i < values.size(); ++i) {
+ std::string key;
+ std::string value;
+ std::stringstream ss;
+
+ if (getKeyValue(values[i], key, value) != ML_ERROR_NONE) {
+ throw std::invalid_argument("Error parsing the property: " + values[i]);
+ }
+
+ if (value.empty()) {
+ ss << "value is empty: key: " << key << ", value: " << value;
+ throw std::invalid_argument(ss.str());
+ }
+
+ /// @note this calls derived setProperty if available
+ setProperty(key, value);
+ }
}
-void TfLiteLayer::setProperty(const PropertyType type,
+void TfLiteLayer::setProperty(const std::string &type_str,
const std::string &value) {
+ using PropertyType = LayerV1::PropertyType;
+ LayerV1::PropertyType type =
+ static_cast<LayerV1::PropertyType>(parseLayerProperty(type_str));
+
switch (type) {
case PropertyType::modelfile: {
- if (!value.empty())
- modelfile = value;
+ modelfile = value;
} break;
default:
- LayerV1::setProperty(type, value);
- break;
+ std::string msg = "[TfLiteLayer] Unknown Layer Property Key for value " +
+ std::string(value);
+ throw exception::not_supported(msg);
}
}
-void TfLiteLayer::forwarding(bool training) {
-#ifdef DEBUG
- if (net_input.size() != input_dim.size())
- throw std::invalid_argument("Provided number of input dimensions mismatch");
-
- for (unsigned int idx = 0; idx < input_dim.size(); idx++) {
- if (net_input[idx]->getDim() != input_dim[idx])
- throw std::invalid_argument("Input dimensions mismatch");
- }
-#endif
+void TfLiteLayer::forwarding(RunLayerContext &context, bool training) {
auto in_indices = interpreter->inputs();
- for (size_t idx = 0; idx < net_input.size(); idx++)
+ for (size_t idx = 0; idx < in_indices.size(); idx++)
interpreter->tensor(in_indices[idx])->data.raw =
- (char *)net_input[idx]->getVariableRef().getData();
+ reinterpret_cast<char *>(context.getInput(idx).getData());
auto out_indices = interpreter->outputs();
for (size_t idx = 0; idx < out_indices.size(); idx++) {
interpreter->tensor(out_indices[idx])->data.raw =
- reinterpret_cast<char *>(net_hidden[idx]->getVariableRef().getData());
+ reinterpret_cast<char *>(context.getOutput(idx).getData());
}
int status = interpreter->Invoke();
#endif
}
-void TfLiteLayer::copy(std::shared_ptr<LayerV1> l) {
- LayerV1::copy(l);
-
- std::shared_ptr<TfLiteLayer> from = std::static_pointer_cast<TfLiteLayer>(l);
- this->modelfile = from->modelfile;
-}
-
-void TfLiteLayer::calcDerivative() {
+void TfLiteLayer::calcDerivative(RunLayerContext &context) {
throw exception::not_supported(
"calcDerivative is not supported for tflite layer");
}
#define __TENSORFLOW_LITE_H__
#ifdef __cplusplus
-#include <layer_internal.h>
-#include <tensor.h>
+#include <layer_devel.h>
#include <tensorflow/contrib/lite/interpreter.h>
#include <tensorflow/contrib/lite/kernels/register.h>
* @class TfLiteLayer
* @brief Tensorflow Lite layer
*/
-class TfLiteLayer : public LayerV1 {
+class TfLiteLayer : public Layer {
public:
/**
* @brief Constructor of NNStreamer Layer
*/
TfLiteLayer(std::string model = "") :
- LayerV1(),
+ Layer(),
modelfile(model),
interpreter(nullptr),
model(nullptr) {}
~TfLiteLayer() = default;
/**
- * @copydoc Layer::forwarding(bool training)
+ * @copydoc Layer::finalize(InitLayerContext &context)
*/
- void forwarding(bool training = true) override;
+ void finalize(InitLayerContext &context) override;
/**
- * @copydoc Layer::calcDerivative()
+ * @copydoc Layer::forwarding(RunLayerContext &context, bool training)
*/
- void calcDerivative() override;
+ void forwarding(RunLayerContext &context, bool training) override;
/**
- * @copydoc Layer::copy(std::shared_ptr<layer> l)
+ * @copydoc Layer::calcDerivative(RunLayerContext &context)
*/
- void copy(std::shared_ptr<LayerV1> l) override;
-
- /**
- * @copydoc Layer::initialize()
- */
- int initialize(Manager &manager) override;
-
- /**
- * @copydoc bool supportBackwarding() const
- */
- bool supportBackwarding() const override { return false; };
+ void calcDerivative(RunLayerContext &context) override;
/**
* @copydoc Layer::getType()
*/
const std::string getType() const override { return TfLiteLayer::type; };
- using LayerV1::setProperty;
+ /**
+ * @copydoc Layer::supportBackwarding()
+ */
+ bool supportBackwarding() const { return false; }
/**
* @copydoc Layer::setProperty(const PropertyType type, const std::string
* &value)
*/
- void setProperty(const PropertyType type,
- const std::string &value = "") override;
+ void setProperty(const std::vector<std::string> &values) override;
inline static const std::string type = "backbone_tflite";
*/
void setDimensions(const std::vector<int> &tensor_idx_list,
std::vector<TensorDim> &dim, bool is_output);
+
+ /**
+ * @brief setProperty by type and value separated
+ * @param[in] type property type to be passed
+ * @param[in] value value to be passed
+ * @exception exception::not_supported when property type is not valid for
+ * the particular layer
+ * @exception std::invalid_argument invalid argument
+ */
+ void setProperty(const std::string &type_str, const std::string &value);
};
} // namespace nntrainer
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Parichay Kapoor <pk.kapoor@samsung.com>
+ *
+ * @file unittest_layers_tflite.cpp
+ * @date 12 June 2021
+ * @brief TfLite Layer Test
+ * @see https://github.com/nnstreamer/nntrainer
+ * @author Parichay Kapoor <pk.kapoor@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+#include <tuple>
+
+#include <gtest/gtest.h>
+
+#include <layers_common_tests.h>
+#include <tflite_layer.h>
+
+auto semantic_tflite = LayerSemanticsParamType(
+ nntrainer::createLayer<nntrainer::TfLiteLayer>, nntrainer::TfLiteLayer::type,
+ {"modelfile=../test/test_models/models/add.tflite"}, {}, 0, false);
+
+INSTANTIATE_TEST_CASE_P(TfLite, LayerSemantics,
+ ::testing::Values(semantic_tflite));