Improve error logs when converting model with control flow. Also update the g3doc to clearly convey that 'control flow' is not currently supported.

PiperOrigin-RevId: 248773536
This commit is contained in:
Haoliang Zhang 2019-05-17 13:05:36 -07:00 committed by TensorFlower Gardener
parent 39e91628f5
commit 5260e5f979
3 changed files with 202 additions and 56 deletions

View File

@ -30,8 +30,16 @@ Since the number of TensorFlow Lite operations is smaller than TensorFlow's,
some inference models may not be able to convert. For unimplemented operations, some inference models may not be able to convert. For unimplemented operations,
take a look at the question on take a look at the question on
[missing operators](faq.md#why-are-some-operations-not-implemented-in-tensorflow-lite). [missing operators](faq.md#why-are-some-operations-not-implemented-in-tensorflow-lite).
Unsupported operators include embeddings and LSTM/RNNs. For conversion issues Unsupported operators include embeddings and LSTM/RNNs. For models with
not related to missing operations, search our LSTM/RNNs, you can also try the experimental API
[OpHint](https://www.tensorflow.org/api_docs/python/tf/lite/OpHint) to convert.
Models with control flow ops (Switch, Merge, etc) are not convertible at the
moment, but we are working on adding support for control flow in Tensorflow
Lite, please see
[GitHub issues](https://github.com/tensorflow/tensorflow/issues/28485).
For conversion issues not related to missing operations or control flow ops,
search our
[GitHub issues](https://github.com/tensorflow/tensorflow/issues?q=label%3Acomp%3Alite+) [GitHub issues](https://github.com/tensorflow/tensorflow/issues?q=label%3Acomp%3Alite+)
or file a [new one](https://github.com/tensorflow/tensorflow/issues). or file a [new one](https://github.com/tensorflow/tensorflow/issues).

View File

@ -16,6 +16,7 @@ limitations under the License.
#include "flatbuffers/flexbuffers.h" #include "flatbuffers/flexbuffers.h"
#include "absl/strings/str_join.h" #include "absl/strings/str_join.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/lite/context.h" #include "tensorflow/lite/context.h"
#include "tensorflow/lite/schema/schema_generated.h" #include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/toco/tflite/operator.h" #include "tensorflow/lite/toco/tflite/operator.h"
@ -431,6 +432,31 @@ tensorflow::Status Export(const Model& model, string* output_file_contents,
return Export(model, output_file_contents, params, ops_by_type); return Export(model, output_file_contents, params, ops_by_type);
} }
void ParseControlFlowErrors(std::set<string>* custom_ops,
std::vector<string>* error_msgs) {
std::set<string> unsupported_control_flow_ops;
// Check if unsupported ops contains control flow ops. It's impossible
// to implement these ops as custom ops at the moment.
for (const auto& op : *custom_ops) {
if (IsControlFlowOp(op)) {
unsupported_control_flow_ops.insert(op);
}
}
if (!unsupported_control_flow_ops.empty()) {
error_msgs->push_back(absl::StrCat(
"TensorFlow Lite currently doesn't support control flow ops: ",
absl::StrJoin(unsupported_control_flow_ops, ", "), ".",
" We are working on supporting control flow ops, please see github "
"issue at "
"https://github.com/tensorflow/tensorflow/issues/28485."));
}
// Remove control flow ops from `custom_ops` set so that they won't be
// reported again in later messages.
for (const auto& op : unsupported_control_flow_ops) {
custom_ops->erase(op);
}
}
tensorflow::Status Export( tensorflow::Status Export(
const Model& model, string* output_file_contents, const Model& model, string* output_file_contents,
const ExportParams& params, const ExportParams& params,
@ -483,6 +509,18 @@ tensorflow::Status Export(
if (!custom_ops.empty()) { if (!custom_ops.empty()) {
if (!params.allow_custom_ops) { if (!params.allow_custom_ops) {
auto please_report_bug_message = []() {
return "We are continually in the process of adding support to "
"TensorFlow Lite for more ops. It would be helpful if you could "
"inform us of how this conversion went by opening a github "
"issue at "
"https://github.com/tensorflow/tensorflow/issues/new?template="
"40-tflite-op-request.md\n and pasting the following:\n\n";
};
std::vector<string> error_msgs;
ParseControlFlowErrors(&custom_ops, &error_msgs);
// Remove ExpandDims and ReorderAxes from unimplemented list unless they // Remove ExpandDims and ReorderAxes from unimplemented list unless they
// compose the list. Both ops are removed during graph transformations. // compose the list. Both ops are removed during graph transformations.
// However, if an op is unimplemented earlier in the model, the graph // However, if an op is unimplemented earlier in the model, the graph
@ -499,20 +537,12 @@ tensorflow::Status Export(
custom_ops_final = custom_ops; custom_ops_final = custom_ops;
} }
auto please_report_bug_message = []() { if (!custom_ops_final.empty()) {
return "We are continually in the process of adding support to "
"TensorFlow Lite for more ops. It would be helpful if you could "
"inform us of how this conversion went by opening a github "
"issue at "
"https://github.com/tensorflow/tensorflow/issues/new?template="
"40-tflite-op-request.md\n and pasting the following:\n\n";
};
if (params.enable_select_tf_ops) { if (params.enable_select_tf_ops) {
return tensorflow::errors::InvalidArgument(absl::StrCat( error_msgs.push_back(absl::StrCat(
please_report_bug_message(),
"Some of the operators in the model are not supported by " "Some of the operators in the model are not supported by "
"the standard TensorFlow Lite runtime and are not recognized by " "the standard TensorFlow Lite runtime and are not recognized "
"by "
"TensorFlow. If you have a custom " "TensorFlow. If you have a custom "
"implementation for them you can disable this error with " "implementation for them you can disable this error with "
"--allow_custom_ops, or by setting allow_custom_ops=True " "--allow_custom_ops, or by setting allow_custom_ops=True "
@ -523,15 +553,15 @@ tensorflow::Status Export(
"of operators for which you will need custom implementations: ", "of operators for which you will need custom implementations: ",
absl::StrJoin(custom_ops_final, ", "), ".")); absl::StrJoin(custom_ops_final, ", "), "."));
} else { } else {
return tensorflow::errors::InvalidArgument(absl::StrCat( error_msgs.push_back(absl::StrCat(
please_report_bug_message(),
"Some of the operators in the model are not supported by " "Some of the operators in the model are not supported by "
"the standard TensorFlow Lite runtime. If those are native " "the standard TensorFlow Lite runtime. If those are native "
"TensorFlow operators, you might be able to use the extended " "TensorFlow operators, you might be able to use the extended "
"runtime by passing --enable_select_tf_ops, or by setting " "runtime by passing --enable_select_tf_ops, or by setting "
"target_ops=TFLITE_BUILTINS,SELECT_TF_OPS when calling " "target_ops=TFLITE_BUILTINS,SELECT_TF_OPS when calling "
"tf.lite.TFLiteConverter(). Otherwise, if you have a " "tf.lite.TFLiteConverter(). Otherwise, if you have a "
"custom implementation for them you can disable this error with " "custom implementation for them you can disable this error "
"with "
"--allow_custom_ops, or by setting allow_custom_ops=True " "--allow_custom_ops, or by setting allow_custom_ops=True "
"when calling tf.lite.TFLiteConverter(). Here is a list " "when calling tf.lite.TFLiteConverter(). Here is a list "
"of builtin operators you are using: ", "of builtin operators you are using: ",
@ -541,19 +571,10 @@ tensorflow::Status Export(
absl::StrJoin(custom_ops_final, ", "), ".")); absl::StrJoin(custom_ops_final, ", "), "."));
} }
} }
if (!error_msgs.empty()) {
std::set<string> unsupported_control_flow_ops;
// Check if unsupported ops contains control flow ops. It's impossible
// to implement these ops as custom ops at the moment.
for (const auto& op : custom_ops) {
if (IsControlFlowOp(op)) {
unsupported_control_flow_ops.insert(op);
}
}
if (!unsupported_control_flow_ops.empty()) {
return tensorflow::errors::InvalidArgument(absl::StrCat( return tensorflow::errors::InvalidArgument(absl::StrCat(
"TensorFlow Lite currently doesn't support control flow ops: ", please_report_bug_message(), absl::StrJoin(error_msgs, " ")));
absl::StrJoin(unsupported_control_flow_ops, ", "), ".")); }
} }
} }

View File

@ -227,6 +227,123 @@ TEST_F(ExportTest, Export) {
EXPECT_THAT(ExportAndGetOperatorIndices(params), ElementsAre(1, 0, 2, 3)); EXPECT_THAT(ExportAndGetOperatorIndices(params), ElementsAre(1, 0, 2, 3));
} }
TEST_F(ExportTest, UnsupportedControlFlowErrors) {
AddOperatorsByName({"Conv", "Add", "Switch", "Merge"});
ExportParams params;
params.allow_custom_ops = false;
// The model contains control flow ops which are not convertible, so we should
// check the returned error message.
string output;
const auto ops_by_type = BuildOperatorByTypeMap();
auto status = Export(input_model_, &output, params, ops_by_type);
EXPECT_EQ(status.error_message(),
"We are continually in the process of adding support to TensorFlow "
"Lite for more ops. It would be helpful if you could inform us of "
"how this conversion went by opening a github issue at "
"https://github.com/tensorflow/tensorflow/issues/"
"new?template=40-tflite-op-request.md\n and pasting the "
"following:\n\nTensorFlow Lite currently doesn't support control "
"flow ops: Merge, Switch. We are working on supporting control "
"flow ops, please see github issue at "
"https://github.com/tensorflow/tensorflow/issues/28485.");
}
TEST_F(ExportTest, UnsupportedOpsAndNeedEnableFlex) {
AddOperatorsByName({"Conv", "Add", "BatchNormWithGlobalNormalization"});
ExportParams params;
params.allow_custom_ops = false;
params.enable_select_tf_ops = false;
string output;
const auto ops_by_type = BuildOperatorByTypeMap();
auto status = Export(input_model_, &output, params, ops_by_type);
EXPECT_EQ(
status.error_message(),
"We are continually in the process of adding support to TensorFlow Lite "
"for more ops. It would be helpful if you could inform us of how this "
"conversion went by opening a github issue at "
"https://github.com/tensorflow/tensorflow/issues/"
"new?template=40-tflite-op-request.md\n and pasting the "
"following:\n\nSome of the operators in the model are not supported by "
"the standard TensorFlow Lite runtime. If those are native TensorFlow "
"operators, you might be able to use the extended runtime by passing "
"--enable_select_tf_ops, or by setting "
"target_ops=TFLITE_BUILTINS,SELECT_TF_OPS when calling "
"tf.lite.TFLiteConverter(). Otherwise, if you have a custom "
"implementation for them you can disable this error with "
"--allow_custom_ops, or by setting allow_custom_ops=True when calling "
"tf.lite.TFLiteConverter(). Here is a list of builtin operators you are "
"using: ADD, CONV_2D. Here is a list of operators for which you will "
"need custom implementations: BatchNormWithGlobalNormalization.");
}
TEST_F(ExportTest, UnsupportedOpsNeedCustomImplementation) {
AddOperatorsByName({"Conv", "Add", "MyCustomOp1", "MyCustomOp2"});
ExportParams params;
params.allow_custom_ops = false;
params.enable_select_tf_ops = true;
string output;
const auto ops_by_type = BuildOperatorByTypeMap();
auto status = Export(input_model_, &output, params, ops_by_type);
EXPECT_EQ(
status.error_message(),
"We are continually in the process of adding support to TensorFlow Lite "
"for more ops. It would be helpful if you could inform us of how this "
"conversion went by opening a github issue at "
"https://github.com/tensorflow/tensorflow/issues/"
"new?template=40-tflite-op-request.md\n and pasting the "
"following:\n\nSome of the operators in the model are not supported by "
"the standard TensorFlow Lite runtime and are not recognized by "
"TensorFlow. If you have a custom implementation for them you can "
"disable this error with --allow_custom_ops, or by setting "
"allow_custom_ops=True when calling tf.lite.TFLiteConverter(). Here is a "
"list of builtin operators you are using: ADD, CONV_2D. Here is a list "
"of operators for which you will need custom implementations: "
"MyCustomOp1, MyCustomOp2.");
}
TEST_F(ExportTest, UnsupportedControlFlowAndCustomOpsErrors) {
AddOperatorsByName(
{"Conv", "Add", "Switch", "Merge", "MyCustomOp1", "MyCustomOp2"});
ExportParams params;
params.allow_custom_ops = false;
// The model contains control flow ops which are not convertible, so we should
// check the returned error message.
string output;
const auto ops_by_type = BuildOperatorByTypeMap();
auto status = Export(input_model_, &output, params, ops_by_type);
EXPECT_EQ(
status.error_message(),
"We are continually in the process of adding support to TensorFlow Lite "
"for more ops. It would be helpful if you could inform us of how this "
"conversion went by opening a github issue at "
"https://github.com/tensorflow/tensorflow/issues/"
"new?template=40-tflite-op-request.md\n and pasting the "
"following:\n\nTensorFlow Lite currently doesn't support control flow "
"ops: Merge, Switch. We are working on supporting control flow ops, "
"please see github issue at "
"https://github.com/tensorflow/tensorflow/issues/28485. Some of the "
"operators in the model are not supported by the standard TensorFlow "
"Lite runtime. If those are native TensorFlow operators, you might be "
"able to use the extended runtime by passing --enable_select_tf_ops, or "
"by setting target_ops=TFLITE_BUILTINS,SELECT_TF_OPS when calling "
"tf.lite.TFLiteConverter(). Otherwise, if you have a custom "
"implementation for them you can disable this error with "
"--allow_custom_ops, or by setting allow_custom_ops=True when calling "
"tf.lite.TFLiteConverter(). Here is a list of builtin operators you are "
"using: ADD, CONV_2D. Here is a list of operators for which you will "
"need custom implementations: MyCustomOp1, MyCustomOp2.");
}
TEST_F(ExportTest, QuantizeWeights) { TEST_F(ExportTest, QuantizeWeights) {
// Sanity check for quantize_weights parameter. // Sanity check for quantize_weights parameter.
BuildQuantizableTestModel(); BuildQuantizableTestModel();
@ -335,7 +452,7 @@ TEST_F(OpSetsTest, BuiltinsAndTfSelect) {
// This test is based on a hypothetical scenario that dilation is supported // This test is based on a hypothetical scenario that dilation is supported
// only in Conv version 2. So Toco populates version=1 when dialation // only in Conv version 2. So Toco populates version=1 when dialation
// parameters are all 1, and version=2 otehrwise. // parameters are all 1, and version=2 otherwise.
class FakeConvolutionOperator class FakeConvolutionOperator
: public BuiltinOperator<ConvOperator, ::tflite::Conv2DOptions, : public BuiltinOperator<ConvOperator, ::tflite::Conv2DOptions,
::tflite::BuiltinOptions_Conv2DOptions> { ::tflite::BuiltinOptions_Conv2DOptions> {