blob: 52e74e2cc3ab370bcb920ce6779bcab18d6d9bb3 [file] [edit]
/*
* Copyright (C) 2024 Intel Corporation
* SPDX-License-Identifier: Apache-2.0
*/
#include "delegate/intel_openvino/openvino_delegate.h"
#include <memory>
#include <vector>
#include "delegate/intel_openvino/openvino_delegate_kernel.h"
#include "tensorflow/lite/builtin_ops.h"
#include "tensorflow/lite/c/c_api_opaque.h"
#include "tensorflow/lite/c/c_api_types.h"
#include "tensorflow/lite/delegates/utils/simple_opaque_delegate.h"
namespace tflite {
namespace openvinodelegate {
bool OpenVINODelegate::CheckInputType(TfLiteType tensor_type,
TfLiteType expected_type) const {
return expected_type == tensor_type;
}
bool OpenVINODelegate::CheckDataTypeSupported(
const TfLiteOpaqueContext *context, const TfLiteOpaqueNode *node,
const std::vector<std::vector<TfLiteType>> supported_types) const {
const int *inputs;
int num_inputs;
if (TfLiteOpaqueNodeInputs(node, &inputs, &num_inputs) != kTfLiteOk)
return false;
if (num_inputs < supported_types.size()) return false;
for (int i = 0; i < supported_types.size(); i++) {
int tensor_id = inputs[i];
bool supported = false;
const TfLiteOpaqueTensor *opaque_tensor =
TfLiteOpaqueContextGetOpaqueTensor(context, tensor_id);
TfLiteType type = TfLiteOpaqueTensorType(opaque_tensor);
for (TfLiteType supported_type : supported_types[i])
supported |= CheckInputType(type, supported_type);
if (!supported) return false;
}
return true;
}
bool OpenVINODelegate::CheckDims(
const TfLiteOpaqueContext *context, const TfLiteOpaqueNode *node,
const std::vector<std::vector<int>> &dims_size) const {
const int *inputs;
int num_inputs;
if (TfLiteOpaqueNodeInputs(node, &inputs, &num_inputs) != kTfLiteOk)
return false;
if (num_inputs < dims_size.size()) return false;
for (int i = 0; i < dims_size.size(); i++) {
bool supported = false;
const TfLiteOpaqueTensor *opaque_tensor =
TfLiteOpaqueContextGetOpaqueTensor(context, inputs[i]);
for (int j = 0; j < dims_size[i].size(); j++) {
if (TfLiteOpaqueTensorNumDims(opaque_tensor) == dims_size[i][j]) {
supported |= true;
for (int k = 0; k < dims_size[i][j]; k++)
if (TfLiteOpaqueTensorDim(opaque_tensor, k) == 0) return false;
}
}
if (!supported) return false;
}
return true;
}
bool OpenVINODelegate::CheckNodeSupportByOpenVINO(
const TfLiteRegistrationExternal *registration,
const TfLiteOpaqueNode *node, const TfLiteOpaqueContext *context) const {
const int *inputs;
int num_inputs;
if (TfLiteOpaqueNodeInputs(node, &inputs, &num_inputs) != kTfLiteOk)
return false;
switch (TfLiteOperatorGetBuiltInCode(registration)) {
case kTfLiteBuiltinAdd: {
return CheckDataTypeSupported(context, node,
{{kTfLiteFloat32}, {kTfLiteFloat32}}) &&
CheckDims(context, node, {{1, 2, 3, 4}, {1, 2, 3, 4}});
}
case kTfLiteBuiltinAveragePool2d: {
return CheckDataTypeSupported(context, node, {{kTfLiteFloat32}}) &&
CheckDims(context, node, {{4}});
}
case kTfLiteBuiltinConv2d: {
if (num_inputs == 2) {
return CheckDataTypeSupported(context, node,
{{kTfLiteFloat32}, {kTfLiteFloat32}}) &&
CheckDims(context, node, {{4}, {4}});
} else if (num_inputs == 3) {
return CheckDataTypeSupported(
context, node,
{{kTfLiteFloat32}, {kTfLiteFloat32}, {kTfLiteFloat32}}) &&
CheckDims(context, node, {{4}, {4}, {1}});
} else {
return false;
}
}
case kTfLiteBuiltinConcatenation: {
// NOTE: Concatenation is allowed to have variadic input tensors , but we
// check type for 2 input tensors. Rest are assumed to have same type if
// present
return CheckDataTypeSupported(context, node,
{{kTfLiteFloat32}, {kTfLiteFloat32}});
}
case kTfLiteBuiltinDepthwiseConv2d: {
if (num_inputs == 2) {
return CheckDataTypeSupported(context, node,
{{kTfLiteFloat32}, {kTfLiteFloat32}}) &&
CheckDims(context, node, {{4}, {4}});
} else if (num_inputs == 3) {
return CheckDataTypeSupported(
context, node,
{{kTfLiteFloat32}, {kTfLiteFloat32}, {kTfLiteFloat32}}) &&
CheckDims(context, node, {{4}, {4}, {1}});
} else {
return false;
}
}
case kTfLiteBuiltinDequantize: {
return CheckDataTypeSupported(context, node, {{kTfLiteFloat16}});
}
case kTfLiteBuiltinResizeBilinear: {
return CheckDataTypeSupported(context, node,
{{kTfLiteFloat32}, {kTfLiteInt32}});
}
case kTfLiteBuiltinRelu: {
return CheckDataTypeSupported(context, node, {{kTfLiteFloat32}});
}
case kTfLiteBuiltinRelu6: {
return CheckDataTypeSupported(context, node, {{kTfLiteFloat32}});
}
case kTfLiteBuiltinLogistic: {
return CheckDataTypeSupported(context, node, {{kTfLiteFloat32}});
}
case kTfLiteBuiltinHardSwish: {
return CheckDataTypeSupported(context, node, {{kTfLiteFloat32}});
}
case kTfLiteBuiltinMul: {
return CheckDataTypeSupported(context, node,
{{kTfLiteFloat32}, {kTfLiteFloat32}}) &&
CheckDims(context, node, {{1, 2, 3, 4}, {1, 2, 3, 4}});
}
case kTfLiteBuiltinSoftmax: {
auto *softmax_params = reinterpret_cast<TfLiteSoftmaxParams *>(
TfLiteOpaqueNodeGetBuiltinData(node));
if (softmax_params->beta != 1.0f) {
TFLITE_LOG(INFO) << "Unsupported Softmax op, beta value is not 1.0";
return false;
}
return CheckDataTypeSupported(context, node, {{kTfLiteFloat32}});
}
case kTfLiteBuiltinTanh: {
return CheckDataTypeSupported(context, node, {{kTfLiteFloat32}});
}
case kTfLiteBuiltinReshape: {
return CheckDataTypeSupported(context, node,
{{kTfLiteFloat32}, {kTfLiteInt32}}) &&
CheckDims(context, node, {{1, 2, 3, 4}, {1}});
}
case kTfLiteBuiltinMaxPool2d: {
return CheckDataTypeSupported(context, node, {{kTfLiteFloat32}}) &&
CheckDims(context, node, {{4}});
}
case kTfLiteBuiltinMean: {
return CheckDataTypeSupported(context, node,
{{kTfLiteFloat32}, {kTfLiteInt32}}) &&
CheckDims(context, node, {{4}, {1}});
}
case kTfLiteBuiltinTransposeConv: {
if (num_inputs == 3) {
return CheckDataTypeSupported(
context, node,
{{kTfLiteInt32}, {kTfLiteFloat32}, {kTfLiteFloat32}}) &&
CheckDims(context, node, {{1}, {4}, {4}});
} else if (num_inputs == 4) {
return CheckDataTypeSupported(context, node,
{{kTfLiteInt32},
{kTfLiteFloat32},
{kTfLiteFloat32},
{kTfLiteFloat32}}) &&
CheckDims(context, node, {{1}, {4}, {4}, {1}});
} else {
return false;
}
}
case kTfLiteBuiltinPad: {
return CheckDataTypeSupported(
context, node,
{{kTfLiteFloat32}, {kTfLiteInt32, kTfLiteInt64}}) &&
CheckDims(context, node, {{1, 2, 3, 4}, {2}});
}
default:
return false;
}
}
bool OpenVINODelegate::IsNodeSupportedByDelegate(
const TfLiteRegistrationExternal *registration,
const TfLiteOpaqueNode *node, TfLiteOpaqueContext *context) const {
if (registration == nullptr || node == nullptr || context == nullptr)
return false;
return CheckNodeSupportByOpenVINO(registration, node, context);
}
TfLiteStatus OpenVINODelegate::Initialize(TfLiteOpaqueContext *context) {
return kTfLiteOk;
}
const char *OpenVINODelegate::Name() const {
return "OpenVINO SimpleOpaqueDelegate";
}
std::unique_ptr<tflite::SimpleOpaqueDelegateKernelInterface>
OpenVINODelegate::CreateDelegateKernelInterface() {
return std::unique_ptr<tflite::openvinodelegate::OpenVINODelegateKernel>(
new tflite::openvinodelegate::OpenVINODelegateKernel(options_));
}
} // namespace openvinodelegate
} // namespace tflite