| diff --git a/tensorflow/lite/delegates/nnapi/nnapi_delegate.cc b/tensorflow/lite/delegates/nnapi/nnapi_delegate.cc |
| index 5c31a27a..f49fc1fa 100644 |
| --- a/tensorflow/lite/delegates/nnapi/nnapi_delegate.cc |
| +++ b/tensorflow/lite/delegates/nnapi/nnapi_delegate.cc |
| @@ -3423,6 +3423,8 @@ bool NNAPIDelegateKernel::Validate( |
| NNAPIValidationFailureType::kUnsupportedOperatorVariant, |
| "Expecting 2 inputs", &val_ctx); |
| } break; |
| + case kTfLiteBuiltinCustom: { |
| + } break; |
| default: |
| // All other operators are not mapped. |
| AddValidationFailure(NNAPIValidationFailureType::kUnsupportedOperator, |
| @@ -4308,6 +4310,49 @@ TfLiteStatus NNAPIDelegateKernel::Map( |
| case kTfLiteBuiltinReverseV2: { |
| *nn_op_type = ANEURALNETWORKS_REVERSE; |
| } break; |
| + case kTfLiteBuiltinCustom: { |
| + TfLiteNode* node; |
| + TfLiteRegistration* reg; |
| + context->GetNodeAndRegistration(context, mapping_args.node_index, &node, ®); |
| + if (strcmp(reg->custom_name, "Convolution2DTransposeBias") == 0) { |
| + // Convolution2DTransposeBias can be processed as TRANSPOSE_CONV_2D |
| + int input_tensor_flags = 0; |
| + const int input_tensor_id = |
| + mapping_args.node->inputs->data[0]; |
| + const int weight_tensor_id = |
| + mapping_args.node->inputs->data[1]; |
| + const int bias_tensor_id = |
| + mapping_args.node->inputs->data[2]; |
| + |
| + // Transpose convolution doesn't have hybrid variation. |
| + const bool hybrid_op = false; |
| + |
| + mapping_args.builder->AddTensorInput(input_tensor_id, hybrid_op, input_tensor_flags); // 1 |
| + mapping_args.builder->AddTensorInput(weight_tensor_id, hybrid_op, input_tensor_flags); // 2 |
| + |
| + // Get params from custom_initial_data |
| + TfLiteTransposeConvParams deconv_params = {kTfLitePaddingUnknown}; |
| + std::memcpy(&deconv_params, mapping_args.node->custom_initial_data, |
| + mapping_args.node->custom_initial_data_size); |
| + |
| + mapping_args.builder->AddTensorInput(bias_tensor_id, hybrid_op, input_tensor_flags); // 3 |
| + mapping_args.builder->AddScalarInt32Operand(0); // 4 |
| + mapping_args.builder->AddScalarInt32Operand(0); // 5 |
| + mapping_args.builder->AddScalarInt32Operand(0); // 6 |
| + mapping_args.builder->AddScalarInt32Operand(0); // 7 |
| + mapping_args.builder->AddScalarInt32Operand(deconv_params.stride_width); // 8 |
| + mapping_args.builder->AddScalarInt32Operand(deconv_params.stride_height); // 9 |
| + |
| + // ANEURALNETWORKS_FUSED_NONE |
| + mapping_args.builder->AddScalarInt32Operand(0); |
| + // Use NHWC layout for input and output. |
| + mapping_args.builder->AddScalarBoolOperand(false); |
| + |
| + *nn_op_type = ANEURALNETWORKS_TRANSPOSE_CONV; |
| + } else { |
| + return kTfLiteError; |
| + } |
| + } break; |
| default: |
| // All other operators are not mapped. |
| return kTfLiteError; |
| @@ -5801,6 +5846,8 @@ TfLiteStatus NNAPIDelegateKernel::AddOpsAndTensors( |
| return kTfLiteError; |
| } |
| } |
| + } else if (reg->builtin_code == kTfLiteBuiltinCustom) { |
| + continue; |
| } else { |
| TF_LITE_ENSURE_STATUS( |
| builder.AddTensorInput(input_index, hybrid_op, input_tensor_flags)); |