diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp
index 66a943fc66..dd4fb0fe89 100644
--- a/modules/dnn/include/opencv2/dnn/dnn.hpp
+++ b/modules/dnn/include/opencv2/dnn/dnn.hpp
@@ -1105,23 +1105,29 @@ CV__DNN_INLINE_NS_BEGIN
/** @brief Reads a network model stored in TFLite framework's format.
* @param model path to the .tflite file with binary flatbuffers description of the network architecture
+ * @param engine select DNN engine to be used. With auto selection the new engine is used first and falls back to classic.
+ * Please pay attention that the new DNN does not support non-CPU back-ends for now.
* @returns Net object.
*/
- CV_EXPORTS_W Net readNetFromTFLite(CV_WRAP_FILE_PATH const String &model);
+ CV_EXPORTS_W Net readNetFromTFLite(CV_WRAP_FILE_PATH const String &model, int engine=ENGINE_AUTO);
/** @brief Reads a network model stored in TFLite framework's format.
* @param bufferModel buffer containing the content of the tflite file
+ * @param engine select DNN engine to be used. With auto selection the new engine is used first and falls back to classic.
+ * Please pay attention that the new DNN does not support non-CPU back-ends for now.
* @returns Net object.
*/
- CV_EXPORTS_W Net readNetFromTFLite(const std::vector& bufferModel);
+ CV_EXPORTS_W Net readNetFromTFLite(const std::vector& bufferModel, int engine=ENGINE_AUTO);
/** @brief Reads a network model stored in TFLite framework's format.
* @details This is an overloaded member function, provided for convenience.
* It differs from the above function only in what argument(s) it accepts.
* @param bufferModel buffer containing the content of the tflite file
* @param lenModel length of bufferModel
+ * @param engine select DNN engine to be used. With auto selection the new engine is used first and falls back to classic.
+ * Please pay attention that the new DNN does not support non-CPU back-ends for now.
*/
- CV_EXPORTS Net readNetFromTFLite(const char *bufferModel, size_t lenModel);
+ CV_EXPORTS Net readNetFromTFLite(const char *bufferModel, size_t lenModel, int engine=ENGINE_AUTO);
/**
* @brief Read deep learning network represented in one of the supported formats.
diff --git a/modules/dnn/misc/objc/gen_dict.json b/modules/dnn/misc/objc/gen_dict.json
index e45023e9d8..166a544735 100644
--- a/modules/dnn/misc/objc/gen_dict.json
+++ b/modules/dnn/misc/objc/gen_dict.json
@@ -9,8 +9,8 @@
"(Net*)readNetFromONNX:(ByteVector*)buffer engine:(int)engine" : { "readNetFromONNX" : {"name" : "readNetFromONNXBuffer"} },
"(Net*)readNetFromTensorflow:(NSString*)model config:(NSString*)config" : { "readNetFromTensorflow" : {"name" : "readNetFromTensorflowFile"} },
"(Net*)readNetFromTensorflow:(ByteVector*)bufferModel bufferConfig:(ByteVector*)bufferConfig" : { "readNetFromTensorflow" : {"name" : "readNetFromTensorflowBuffer"} },
- "(Net*)readNetFromTFLite:(NSString*)model" : { "readNetFromTFLite" : {"name" : "readNetFromTFLiteFile"} },
- "(Net*)readNetFromTFLite:(ByteVector*)buffer" : { "readNetFromTFLite" : {"name" : "readNetFromTFLiteBuffer"} }
+ "(Net*)readNetFromTFLite:(NSString*)model engine:(int)engine" : { "readNetFromTFLite" : {"name" : "readNetFromTFLiteFile"} },
+ "(Net*)readNetFromTFLite:(ByteVector*)buffer engine:(int)engine" : { "readNetFromTFLite" : {"name" : "readNetFromTFLiteBuffer"} }
},
"Net": {
"(void)forward:(NSMutableArray*)outputBlobs outputName:(NSString*)outputName" : { "forward" : {"name" : "forwardOutputBlobs"} },
diff --git a/modules/dnn/src/tflite/tflite_importer.cpp b/modules/dnn/src/tflite/tflite_importer.cpp
index 8b9a824fbf..6e5a90b795 100644
--- a/modules/dnn/src/tflite/tflite_importer.cpp
+++ b/modules/dnn/src/tflite/tflite_importer.cpp
@@ -3,12 +3,14 @@
// of this distribution and at http://opencv.org/license.html.
#include "../precomp.hpp"
+#include "../net_impl.hpp"
#ifdef HAVE_FLATBUFFERS
#include "schema_generated.h"
#include "builtin_op_data.h"
#endif
+#include
#include
#undef CV_LOG_STRIP_LEVEL
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
@@ -24,13 +26,15 @@ using namespace opencv_tflite;
class TFLiteImporter {
public:
- TFLiteImporter(Net& net, const char* modelBuffer, size_t bufSize);
+ TFLiteImporter(Net& net, const char* modelBuffer, size_t bufSize, bool newEngine);
private:
+ bool newEngine;
const opencv_tflite::Model* model;
const flatbuffers::Vector >* modelTensors;
std::map allTensors;
Net& dstNet;
+ std::vector> curProg;
// This is a vector of pairs (layerId, outputId) where we iterate over
// indices from TFLite notation and get created OpenCV layers.
@@ -75,11 +79,12 @@ private:
void parseFusedActivation(const Operator& op, ActivationFunctionType activ);
void parseActivation(const Operator& op, const std::string& opcode, LayerParams& layerParams, bool isFused);
- void addLayer(LayerParams& layerParams, const Operator& op);
- int addPermuteLayer(const std::vector& order, const std::string& permName, const std::pair& inpId, int dtype);
+ void addLayer(LayerParams& layerParams, const Operator& op, bool additionalPreLayer = false, bool additionalPostLayer = false);
+ void addLayer(LayerParams& layerParams, const std::vector& inputTensors, const std::vector& outputTensors);
+ int addPermuteLayer(const std::vector& order, const std::string& permName, const std::pair& inpId, int dtype, int inpTensorId);
int addReshapeLayer(const std::vector& shape, int axis, int num_axes,
- const std::string& name, const std::pair& inpId, int dtype);
- int addFlattenLayer(int axis, int end_axis, const std::string& name, const std::pair& inpId, int dtype);
+ const std::string& name, const std::pair& inpId, int dtype, int inpTensorId);
+ int addFlattenLayer(int axis, int end_axis, const std::string& name, const std::pair& inpId, int dtype, int outTensorId);
inline bool isInt8(const Operator& op);
inline void getQuantParams(const Operator& op, float& inpScale, int& inpZero, float& outScale, int& outZero);
@@ -120,8 +125,8 @@ Mat TFLiteImporter::parseTensor(const Tensor& tensor)
return shape.empty() ? Mat() : Mat(shape, dtype, const_cast(data));
}
-TFLiteImporter::TFLiteImporter(Net& dstNet, const char* modelBuffer, size_t bufSize)
- : dstNet(dstNet), dispatch(buildDispatchMap())
+TFLiteImporter::TFLiteImporter(Net& dstNet, const char* modelBuffer, size_t bufSize, bool newEngine)
+ : newEngine(newEngine), dstNet(dstNet), dispatch(buildDispatchMap())
{
flatbuffers::Verifier verifier((const uint8_t*)modelBuffer, bufSize);
if (!VerifyModelBuffer(verifier)) {
@@ -178,6 +183,12 @@ void TFLiteImporter::populateNet()
size_t subgraph_inputs_size = subgraph_inputs->size();
std::vector inputsNames(subgraph_inputs_size);
std::vector inputsShapes(subgraph_inputs_size);
+
+ // NEW ENGINE
+ Net::Impl* netImpl = dstNet.getImpl();
+ std::vector modelInputs, modelOutputs;
+ Ptr curr_graph;
+
for (size_t i = 0; i < subgraph_inputs_size; ++i)
{
size_t idx = subgraph_inputs->Get(i);
@@ -196,16 +207,46 @@ void TFLiteImporter::populateNet()
std::swap(shape[1], shape[2]);
}
inputsShapes[i] = shape;
+
+ if (newEngine)
+ {
+ modelInputs.push_back(netImpl->newArg(tensor->name()->str(), DNN_ARG_INPUT));
+ netImpl->args.at(modelInputs.back().idx).type = CV_32F;
+ netImpl->args.at(modelInputs.back().idx).shape = shape;
+ }
}
- dstNet.setInputsNames(inputsNames);
- for (size_t i = 0; i < subgraph_inputs_size; ++i)
+ if (!newEngine)
{
- dstNet.setInputShape(inputsNames[i], inputsShapes[i]);
+ dstNet.setInputsNames(inputsNames);
+ for (size_t i = 0; i < subgraph_inputs_size; ++i)
+ {
+ dstNet.setInputShape(inputsNames[i], inputsShapes[i]);
+ }
}
const auto& all_operators = *subgraph_operators;
const size_t all_operators_size = all_operators.size();
+
+ if (newEngine)
+ {
+ const auto last_op = all_operators[all_operators_size - 1];
+ const auto op_outputs = last_op->outputs();
+ std::string type = EnumNameBuiltinOperator(
+ BuiltinOperator(opCodes->Get(last_op->opcode_index())->deprecated_builtin_code()));
+ for (int idx : *op_outputs)
+ {
+ std::string tensorName = modelTensors->Get(idx)->name()->str();
+ modelOutputs.push_back(netImpl->newArg(tensorName, DNN_ARG_OUTPUT));
+
+ // TFLite_Detection_PostProcess layer returns 4 outputs
+ // (num_bboxes, bboxes, classes, conf)
+ // but our detection_output layer returns one output with all the data
+ if (type == "TFLite_Detection_PostProcess")
+ break;
+ }
+ }
+
for (size_t op_idx = 0; op_idx < all_operators_size; ++op_idx)
{
const auto op = all_operators[op_idx];
@@ -259,6 +300,17 @@ void TFLiteImporter::populateNet()
throw;
}
}
+ if (newEngine)
+ {
+ Ptr curr_graph = netImpl->newGraph(subgraph->name()->str(), modelInputs, true);
+ curr_graph->setOutputs(modelOutputs);
+ curr_graph->setProg(curProg);
+
+ netImpl->mainGraph = curr_graph;
+ netImpl->modelFormat = DNN_MODEL_TFLITE;
+ netImpl->originalLayout = DATA_LAYOUT_NCHW; // TODO Should we set NHWC?
+ netImpl->prepareForInference();
+ }
}
TFLiteImporter::DispatchMap TFLiteImporter::buildDispatchMap()
@@ -293,7 +345,7 @@ TFLiteImporter::DispatchMap TFLiteImporter::buildDispatchMap()
return dispatch;
}
-void TFLiteImporter::addLayer(LayerParams& layerParams, const Operator& op) {
+void TFLiteImporter::addLayer(LayerParams& layerParams, const Operator& op, bool additionalPreLayer, bool additionalPostLayer) {
const auto op_inputs = op.inputs();
const auto op_outputs = op.outputs();
@@ -329,10 +381,14 @@ void TFLiteImporter::addLayer(LayerParams& layerParams, const Operator& op) {
layerParams.set("zeropoints", outZero);
}
}
- int layerId = dstNet.addLayer(layerParams.name, layerParams.type, dtype, layerParams);
+
+ int layerId = -1;
+ if (!newEngine)
+ layerId = dstNet.addLayer(layerParams.name, layerParams.type, dtype, layerParams);
// Connect layer to inputs
int i = 0;
+ std::vector inputTensors;
std::vector inpLayouts;
for (int idx : *op_inputs) {
if (layerIds.find(idx) == layerIds.end()) {
@@ -340,9 +396,19 @@ void TFLiteImporter::addLayer(LayerParams& layerParams, const Operator& op) {
}
inpLayouts.push_back(layouts[idx]);
- auto it = layerIds.find(idx);
- CV_Assert(it != layerIds.end());
- dstNet.connect(it->second.first, it->second.second, layerId, i++);
+ if (newEngine)
+ {
+ std::string tensorName = modelTensors->Get(idx)->name()->str();
+ if (additionalPreLayer)
+ tensorName += "_additional_pre_layer";
+ inputTensors.push_back(tensorName);
+ }
+ else
+ {
+ auto it = layerIds.find(idx);
+ CV_Assert(it != layerIds.end());
+ dstNet.connect(it->second.first, it->second.second, layerId, i++);
+ }
}
// Predict output layout. Some layer-specific parsers may set them explicitly.
@@ -364,9 +430,44 @@ void TFLiteImporter::addLayer(LayerParams& layerParams, const Operator& op) {
// Register outputs
i = 0;
+ std::vector outputTensors;
for (int idx : *op_outputs) {
- layerIds[idx] = std::make_pair(layerId, i++);
+ if (newEngine)
+ {
+ std::string tensorName = modelTensors->Get(idx)->name()->str();
+ if (additionalPostLayer)
+ tensorName = tensorName + "_additional_post_layer";
+ outputTensors.push_back(tensorName);
+ layerIds[idx] = std::make_pair(-1, -1);
+ }
+ else
+ layerIds[idx] = std::make_pair(layerId, i++);
+
+ // TFLite_Detection_PostProcess layer returns 4 outputs
+ // (num_bboxes, bboxes, classes, conf)
+ // but our detection_output layer returns one output with all the data
+ if (layerParams.type == "DetectionOutput")
+ break;
}
+
+ if (newEngine)
+ {
+ if (additionalPostLayer)
+ layerParams.name += "_pre";
+ addLayer(layerParams, inputTensors, outputTensors);
+ }
+}
+
+void TFLiteImporter::addLayer(LayerParams& layerParams, const std::vector& inputTensors, const std::vector& outputTensors) {
+ Ptr layer = LayerFactory::createLayerInstance(layerParams.type, layerParams);
+ if (!layer)
+ CV_Error(Error::StsError, "Can't create layer " + layerParams.name + " with type " + layerParams.type);
+ layer->netimpl = dstNet.getImpl();
+ for (const std::string& inputName : inputTensors)
+ layer->inputs.push_back(dstNet.getArg(inputName));
+ for (const std::string& outputName : outputTensors)
+ layer->outputs.push_back(dstNet.getArg(outputName));
+ curProg.push_back(layer);
}
void TFLiteImporter::parseConvolution(const Operator& op, const std::string& opcode, LayerParams& layerParams) {
@@ -428,7 +529,10 @@ void TFLiteImporter::parseConvolution(const Operator& op, const std::string& opc
}
}
}
- addLayer(layerParams, op);
+
+ std::string fusedActivationType = EnumNameActivationFunctionType(options->fused_activation_function());
+ bool haveFusedActivation = fusedActivationType != "NONE";
+ addLayer(layerParams, op, false, haveFusedActivation);
parseFusedActivation(op, options->fused_activation_function());
}
@@ -490,7 +594,10 @@ void TFLiteImporter::parseDWConvolution(const Operator& op, const std::string& o
}
}
}
- addLayer(layerParams, op);
+
+ std::string fusedActivationType = EnumNameActivationFunctionType(options->fused_activation_function());
+ bool haveFusedActivation = fusedActivationType != "NONE";
+ addLayer(layerParams, op, false, haveFusedActivation);
parseFusedActivation(op, options->fused_activation_function());
}
@@ -557,7 +664,10 @@ void TFLiteImporter::parseEltwise(const Operator& op, const std::string& opcode,
layerParams.set("scales", outScale);
layerParams.set("zeropoints", outZero);
}
- addLayer(layerParams, op);
+
+ std::string fusedActivationType = EnumNameActivationFunctionType(activ);
+ bool haveFusedActivation = fusedActivationType != "NONE";
+ addLayer(layerParams, op, false, haveFusedActivation);
parseFusedActivation(op, activ);
}
@@ -576,7 +686,10 @@ void TFLiteImporter::parsePooling(const Operator& op, const std::string& opcode,
layerParams.set("pool", "ave");
else
CV_Error(Error::StsNotImplemented, "Pool type selection for " + opcode);
- addLayer(layerParams, op);
+
+ std::string fusedActivationType = EnumNameActivationFunctionType(options->fused_activation_function());
+ bool haveFusedActivation = fusedActivationType != "NONE";
+ addLayer(layerParams, op, false, haveFusedActivation);
parseFusedActivation(op, options->fused_activation_function());
}
@@ -628,6 +741,7 @@ void TFLiteImporter::parseReshape(const Operator& op, const std::string& opcode,
shape.assign(options->new_shape()->begin(), options->new_shape()->end());
}
+ bool additionalPreLayer = false;
if (inpLayout == DNN_LAYOUT_NHWC) {
if (shape.size() == 4) {
// Keep data but change a shape to OpenCV's NCHW order
@@ -638,13 +752,14 @@ void TFLiteImporter::parseReshape(const Operator& op, const std::string& opcode,
std::vector order = {0, 2, 3, 1};
const std::string name = layerParams.name + "/permute";
auto inpId = layerIds[op.inputs()->Get(0)];
- int permId = addPermuteLayer(order, name, inpId, isInt8(op) ? CV_8S : CV_32F); // NCHW -> NHWC
+ int permId = addPermuteLayer(order, name, inpId, isInt8(op) ? CV_8S : CV_32F, op.inputs()->Get(0)); // NCHW -> NHWC
layerIds[op.inputs()->Get(0)] = std::make_pair(permId, 0);
layouts[op.outputs()->Get(0)] = DNN_LAYOUT_NCHW;
+ additionalPreLayer = true;
}
}
layerParams.set("dim", DictValue::arrayInt(shape.data(), shape.size()));
- addLayer(layerParams, op);
+ addLayer(layerParams, op, additionalPreLayer);
}
void TFLiteImporter::parseConcat(const Operator& op, const std::string& opcode, LayerParams& layerParams) {
@@ -660,7 +775,10 @@ void TFLiteImporter::parseConcat(const Operator& op, const std::string& opcode,
axis = remap[axis];
}
layerParams.set("axis", axis);
- addLayer(layerParams, op);
+
+ std::string fusedActivationType = EnumNameActivationFunctionType(options->fused_activation_function());
+ bool haveFusedActivation = fusedActivationType != "NONE";
+ addLayer(layerParams, op, false, haveFusedActivation);
parseFusedActivation(op, options->fused_activation_function());
}
@@ -690,14 +808,14 @@ void TFLiteImporter::parsePack(const Operator& op, const std::string& opcode, La
}
const auto name = modelTensors->Get(inp)->name()->str() + "/reshape";
int reshapeId = addReshapeLayer(shape, axis == dims ? dims - 1 : axis, 1,
- name, inpId, isInt8(op) ? CV_8S : CV_32F);
+ name, inpId, isInt8(op) ? CV_8S : CV_32F, inp);
originLayerIds[inp] = layerIds[inp];
layerIds[inp] = std::make_pair(reshapeId, 0);
}
layerParams.type = "Concat";
layerParams.set("axis", axis);
- addLayer(layerParams, op);
+ addLayer(layerParams, op, true, false);
// Restore origin layer inputs
for (const auto& ids : originLayerIds) {
@@ -787,11 +905,11 @@ void TFLiteImporter::parseGlobalPooling(const Operator& op, const std::string& o
if (!keep_dims) {
const auto name = layerParams.name;
layerParams.name += "/global_pooling";
- addLayer(layerParams, op);
+ addLayer(layerParams, op, false, true);
int out = op.outputs()->Get(0);
auto outId = layerIds[out];
- int flattenId = addFlattenLayer(1, -1, name, outId, isInt8(op) ? CV_8S : CV_32F);
+ int flattenId = addFlattenLayer(1, -1, name, outId, isInt8(op) ? CV_8S : CV_32F, out);
layerIds[out] = std::make_pair(flattenId, 0);
}
else {
@@ -800,35 +918,68 @@ void TFLiteImporter::parseGlobalPooling(const Operator& op, const std::string& o
}
int TFLiteImporter::addPermuteLayer(const std::vector& order, const std::string& permName,
- const std::pair& inpId, int dtype)
+ const std::pair& inpId, int dtype, int inpTensorId)
{
LayerParams permLP;
permLP.set("order", DictValue::arrayInt(order.data(), order.size()));
- int permId = dstNet.addLayer(permName, "Permute", dtype, permLP);
- dstNet.connect(inpId.first, inpId.second, permId, 0);
- return permId;
+ if (newEngine)
+ {
+ permLP.type = "Permute";
+ permLP.name = permName;
+ std::string tensorName = modelTensors->Get(inpTensorId)->name()->str();
+ addLayer(permLP, {tensorName}, {tensorName + "_additional_pre_layer"});
+ return -1;
+ }
+ else
+ {
+ int permId = dstNet.addLayer(permName, "Permute", dtype, permLP);
+ dstNet.connect(inpId.first, inpId.second, permId, 0);
+ return permId;
+ }
}
int TFLiteImporter::addReshapeLayer(const std::vector& shape, int axis, int num_axes,
- const std::string& name, const std::pair& inpId, int dtype)
+ const std::string& name, const std::pair& inpId, int dtype, int inpTensorId)
{
LayerParams lp;
lp.set("axis", axis);
lp.set("dim", DictValue::arrayInt(shape.data(), shape.size()));
lp.set("num_axes", num_axes);
- int id = dstNet.addLayer(name, "Reshape", dtype, lp);
- dstNet.connect(inpId.first, inpId.second, id, 0);
- return id;
+ if (newEngine)
+ {
+ lp.type = "Reshape";
+ lp.name = name;
+ std::string tensorName = modelTensors->Get(inpTensorId)->name()->str();
+ addLayer(lp, {tensorName}, {tensorName + "_additional_pre_layer"});
+ return -1;
+ }
+ else
+ {
+ int id = dstNet.addLayer(name, "Reshape", dtype, lp);
+ dstNet.connect(inpId.first, inpId.second, id, 0);
+ return id;
+ }
}
-int TFLiteImporter::addFlattenLayer(int axis, int end_axis, const std::string& name, const std::pair& inpId, int dtype)
+int TFLiteImporter::addFlattenLayer(int axis, int end_axis, const std::string& name, const std::pair& inpId, int dtype, int outTensorId)
{
LayerParams lp;
lp.set("axis", axis);
lp.set("end_axis", end_axis);
- int id = dstNet.addLayer(name, "Flatten", dtype, lp);
- dstNet.connect(inpId.first, inpId.second, id, 0);
- return id;
+ if (newEngine)
+ {
+ lp.type = "Flatten";
+ lp.name = name;
+ std::string tensorName = modelTensors->Get(outTensorId)->name()->str();
+ addLayer(lp, {tensorName + "_additional_post_layer"}, {tensorName});
+ return -1;
+ }
+ else
+ {
+ int id = dstNet.addLayer(name, "Flatten", dtype, lp);
+ dstNet.connect(inpId.first, inpId.second, id, 0);
+ return id;
+ }
}
void TFLiteImporter::parseDeconvolution(const Operator& op, const std::string& opcode, LayerParams& layerParams) {
@@ -926,7 +1077,10 @@ void TFLiteImporter::parseFullyConnected(const Operator& op, const std::string&
layerParams.set("transB", true);
layerParams.set("constB", true);
- addLayer(layerParams, op);
+
+ std::string fusedActivationType = EnumNameActivationFunctionType(options->fused_activation_function());
+ bool haveFusedActivation = fusedActivationType != "NONE";
+ addLayer(layerParams, op, false, haveFusedActivation);
parseFusedActivation(op, options->fused_activation_function());
}
@@ -1013,14 +1167,25 @@ void TFLiteImporter::parseDetectionPostProcess(const Operator& op, const std::st
priorsLP.type = "Const";
priorsLP.blobs.resize(1, priors);
- int priorsId = dstNet.addLayer(priorsLP.name, priorsLP.type, priorsLP);
- layerIds[op.inputs()->Get(2)] = std::make_pair(priorsId, 0);
+ if (newEngine)
+ {
+ std::string outTensorName = modelTensors->Get(op.inputs()->Get(2))->name()->str();
+ addLayer(priorsLP, {}, {outTensorName});
+ layerIds[op.inputs()->Get(2)] = std::make_pair(-1, -1);
+ }
+ else
+ {
+ int priorsId = dstNet.addLayer(priorsLP.name, priorsLP.type, priorsLP);
+ layerIds[op.inputs()->Get(2)] = std::make_pair(priorsId, 0);
+ }
addLayer(layerParams, op);
}
void TFLiteImporter::parseFusedActivation(const Operator& op, ActivationFunctionType activ) {
LayerParams activParams;
- activParams.name = modelTensors->Get(op.outputs()->Get(0))->name()->str() + "/activ";
+ activParams.name = modelTensors->Get(op.outputs()->Get(0))->name()->str();
+ if (!newEngine)
+ activParams.name += "/activ";
parseActivation(op, EnumNameActivationFunctionType(activ), activParams, true);
}
@@ -1092,13 +1257,22 @@ void TFLiteImporter::parseActivation(const Operator& op, const std::string& opco
}
if (isFused) {
- int dtype = isInt8(op) ? CV_8S : CV_32F;
- int layerId = dstNet.addLayerToPrev(activParams.name, activParams.type, dtype, activParams);
+ if (newEngine)
+ {
+ std::string tensorName = modelTensors->Get(op.outputs()->Get(0))->name()->str();
+ addLayer(activParams, {tensorName + "_additional_post_layer"}, {tensorName});
+ layerIds[op.outputs()->Get(0)] = std::make_pair(-1, -1);
+ }
+ else
+ {
+ int dtype = isInt8(op) ? CV_8S : CV_32F;
+ int layerId = dstNet.addLayerToPrev(activParams.name, activParams.type, dtype, activParams);
- // Override layer ids mapping
- int i = 0;
- for (int idx : *op.outputs()) {
- layerIds[idx] = std::make_pair(layerId, i++);
+ // Override layer ids mapping
+ int i = 0;
+ for (int idx : *op.outputs()) {
+ layerIds[idx] = std::make_pair(layerId, i++);
+ }
}
} else {
addLayer(activParams, op);
@@ -1136,7 +1310,11 @@ void TFLiteImporter::getQuantParams(const Operator& op, float& inpScale, int& in
}
}
-Net readNetFromTFLite(const String &modelPath) {
+Net readNetFromTFLite(const String &modelPath, int engine) {
+ static const int engine_forced = utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", ENGINE_AUTO);
+ if(engine_forced != ENGINE_AUTO)
+ engine = engine_forced;
+
Net net;
std::vector content;
@@ -1155,17 +1333,21 @@ Net readNetFromTFLite(const String &modelPath) {
ifs.read(content.data(), sz);
CV_Assert(!ifs.bad());
- TFLiteImporter(net, content.data(), content.size());
+ TFLiteImporter(net, content.data(), content.size(), engine == ENGINE_NEW || engine == ENGINE_AUTO);
return net;
}
-Net readNetFromTFLite(const std::vector& bufferModel) {
+Net readNetFromTFLite(const std::vector& bufferModel, int engine) {
return readNetFromTFLite((const char*)bufferModel.data(), bufferModel.size());
}
-Net readNetFromTFLite(const char *bufferModel, size_t bufSize) {
+Net readNetFromTFLite(const char *bufferModel, size_t bufSize, int engine) {
+ static const int engine_forced = utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", ENGINE_AUTO);
+ if(engine_forced != ENGINE_AUTO)
+ engine = engine_forced;
+
Net net;
- TFLiteImporter(net, bufferModel, bufSize);
+ TFLiteImporter(net, bufferModel, bufSize, engine == ENGINE_NEW || engine == ENGINE_AUTO);
return net;
}
@@ -1173,15 +1355,15 @@ Net readNetFromTFLite(const char *bufferModel, size_t bufSize) {
#define DNN_TFLITE_UNSUPPORTED() CV_Error(Error::StsError, "DNN/TFLite: Build OpenCV with FlatBuffers to import TFLite models: https://github.com/opencv/opencv/pull/23161")
-Net readNetFromTFLite(const String &) {
+Net readNetFromTFLite(const String &, int) {
DNN_TFLITE_UNSUPPORTED();
}
-Net readNetFromTFLite(const std::vector&) {
+Net readNetFromTFLite(const std::vector&, int) {
DNN_TFLITE_UNSUPPORTED();
}
-Net readNetFromTFLite(const char *, size_t) {
+Net readNetFromTFLite(const char *, size_t, int) {
DNN_TFLITE_UNSUPPORTED();
}
diff --git a/modules/dnn/test/test_tflite_importer.cpp b/modules/dnn/test/test_tflite_importer.cpp
index 6f21fe34ef..bc01ee2ee1 100644
--- a/modules/dnn/test/test_tflite_importer.cpp
+++ b/modules/dnn/test/test_tflite_importer.cpp
@@ -155,6 +155,9 @@ TEST_P(Test_TFLite, max_unpooling)
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
+ if (net.getMainGraph())
+ throw SkipTestException("The new dnn engine doesn't support forward to specified layers"); // https://github.com/opencv/opencv/issues/26349
+
Mat input = imread(findDataFile("cv/shared/lena.png"));
cvtColor(input, input, COLOR_BGR2RGBA);
input = input.mul(Scalar(1, 1, 1, 0));