Skip to content

Commit 4844bdc

Browse files
Merge pull request #699 from khanhlvg:c-task-error-reporting
PiperOrigin-RevId: 399081136
2 parents cf2bec4 + e6ec31f commit 4844bdc

File tree

5 files changed

+399
-0
lines changed

5 files changed

+399
-0
lines changed

tensorflow_lite_support/c/BUILD

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package(
2+
default_visibility = ["//tensorflow_lite_support:__subpackages__"],
3+
licenses = ["notice"], # Apache 2.0
4+
)
5+
6+
cc_library(
7+
name = "common",
8+
srcs = ["common.cc"],
9+
hdrs = ["common.h"],
10+
)
11+
12+
cc_library(
13+
name = "common_utils",
14+
srcs = ["common_utils.cc"],
15+
hdrs = ["common_utils.h"],
16+
deps = [
17+
":common",
18+
"//tensorflow_lite_support/cc:common",
19+
"@com_google_absl//absl/status",
20+
"@com_google_absl//absl/strings",
21+
"@com_google_absl//absl/strings:cord",
22+
],
23+
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================*/
15+
16+
#include "tensorflow_lite_support/c/common.h"
17+
18+
void TfLiteSupportErrorDelete(TfLiteSupportError *error) {
19+
delete error->message;
20+
delete error;
21+
}

tensorflow_lite_support/c/common.h

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================*/
15+
#ifndef TENSORFLOW_LITE_SUPPORT_C_COMMON_H_
16+
#define TENSORFLOW_LITE_SUPPORT_C_COMMON_H_
17+
18+
// Defines C struct and error codes for describing any error returned from the C
19+
// Task Library.
20+
21+
#ifdef __cplusplus
22+
extern "C" {
23+
#endif // __cplusplus
24+
25+
// Error codes for TensorFlow Lite Task Library C APIs.
26+
//
27+
// Holds one to one mapping with `TfLiteSupportStatus` code starting from kError
28+
// = 1. Omits `kOk` since `TfLiteErrorCode` is only to be used in the event of
29+
// an error and does not account for success unlike `TfLiteSupportStatus`. In
30+
// case of success, TensorFlow Lite Task Library C APIs return the appropriate
31+
// return value and a null error. One to one mapping makes it easier to convert
32+
// between `TfLiteSupportStatus` and `TfLiteSupportErrorCode` without long
33+
// switch statements.
34+
//
35+
// Also holds error codes mapping to absl::Status::code() starting from
36+
// kNotFound = 900 in cases where the absl::Status payload can't
37+
// be mapped to a `TfLiteSupportStatus` code. kErrorCodeFirst and kErrorCodeLast
38+
// are also provided for safety checks during conversion between
39+
// `TfLiteSupportStatus` and `TfLiteSupportErrorCode`. In case of modifications
40+
// in error codes, ensure that kErrorCodeFirst and kErrorCodeLast is
41+
// respectively, set to the least and greatest enum value amongst the error
42+
// codes mapping to TfLiteSupportStatus.
43+
enum TfLiteSupportErrorCode {
44+
// Unspecified error.
45+
kError = 1,
46+
// Invalid argument specified.
47+
kInvalidArgumentError = 2,
48+
// Invalid FlatBuffer file or buffer specified.
49+
kInvalidFlatBufferError = 3,
50+
// Model contains a builtin op that isn't supported by the OpResolver or
51+
// delegates.
52+
kUnsupportedBuiltinOpError = 4,
53+
// Model contains a custom op that isn't supported by the OpResolver or
54+
// delegates.
55+
kUnsupportedCustomOpError = 5,
56+
57+
// File I/O error codes.
58+
59+
// No such file.
60+
kFileNotFoundError = 100,
61+
// Permission issue.
62+
kFilePermissionDeniedError,
63+
// I/O error when reading file.
64+
kFileReadError,
65+
// I/O error when mmap-ing file.
66+
kFileMmapError,
67+
68+
// TensorFlow Lite metadata error codes.
69+
70+
// Unexpected schema version (aka file_identifier) in the Metadata FlatBuffer.
71+
kMetadataInvalidSchemaVersionError = 200,
72+
// No such associated file within metadata, or file has not been packed.
73+
kMetadataAssociatedFileNotFoundError,
74+
// ZIP I/O error when unpacking an associated file.
75+
kMetadataAssociatedFileZipError,
76+
// Inconsistency error between the metadata and actual TF Lite model.
77+
// E.g.: number of labels and output tensor values differ.
78+
kMetadataInconsistencyError,
79+
// Invalid process units specified.
80+
// E.g.: multiple ProcessUnits with the same type for a given tensor.
81+
kMetadataInvalidProcessUnitsError,
82+
// Inconsistency error with the number of labels.
83+
// E.g.: label files for different locales have a different number of labels.
84+
kMetadataNumLabelsMismatchError,
85+
// Score calibration parameters parsing error.
86+
// E.g.: too many parameters provided in the corresponding associated file.
87+
kMetadataMalformedScoreCalibrationError,
88+
// Unexpected number of subgraphs for the current task.
89+
// E.g.: image classification expects a single subgraph.
90+
kMetadataInvalidNumSubgraphsError,
91+
// A given tensor requires NormalizationOptions but none were found.
92+
// E.g.: float input tensor requires normalization to preprocess input images.
93+
kMetadataMissingNormalizationOptionsError,
94+
// Invalid ContentProperties specified.
95+
// E.g. expected ImageProperties, got BoundingBoxProperties.
96+
kMetadataInvalidContentPropertiesError,
97+
// Metadata is mandatory but was not found.
98+
// E.g. current task requires TFLite Model Metadata but none was found.
99+
kMetadataNotFoundError,
100+
// Associated TENSOR_AXIS_LABELS or TENSOR_VALUE_LABELS file is mandatory but
101+
// none was found or it was empty.
102+
// E.g. current task requires labels but none were found.
103+
kMetadataMissingLabelsError,
104+
// The ProcessingUnit for tokenizer is not correctly configured.
105+
// E.g BertTokenizer doesn't have a valid vocab file associated.
106+
kMetadataInvalidTokenizerError,
107+
108+
// Input tensor(s) error codes.
109+
110+
// Unexpected number of input tensors for the current task.
111+
// E.g. current task expects a single input tensor.
112+
kInvalidNumInputTensorsError = 300,
113+
// Unexpected input tensor dimensions for the current task.
114+
// E.g.: only 4D input tensors supported.
115+
kInvalidInputTensorDimensionsError,
116+
// Unexpected input tensor type for the current task.
117+
// E.g.: current task expects a uint8 pixel image as input.
118+
kInvalidInputTensorTypeError,
119+
// Unexpected input tensor bytes size.
120+
// E.g.: size in bytes does not correspond to the expected number of pixels.
121+
kInvalidInputTensorSizeError,
122+
// No correct input tensor found for the model.
123+
// E.g.: input tensor name is not part of the text model's input tensors.
124+
kInputTensorNotFoundError,
125+
126+
// Output tensor(s) error codes.
127+
128+
// Unexpected output tensor dimensions for the current task.
129+
// E.g.: only a batch size of 1 is supported.
130+
kInvalidOutputTensorDimensionsError = 400,
131+
// Unexpected input tensor type for the current task.
132+
// E.g.: multi-head model with different output tensor types.
133+
kInvalidOutputTensorTypeError,
134+
// No correct output tensor found for the model.
135+
// E.g.: output tensor name is not part of the text model's output tensors.
136+
kOutputTensorNotFoundError,
137+
// Unexpected number of output tensors for the current task.
138+
// E.g.: current task expects a single output tensor.
139+
kInvalidNumOutputTensorsError,
140+
141+
// Image processing error codes.
142+
143+
// Unspecified image processing failures.
144+
kImageProcessingError = 500,
145+
// Unexpected input or output buffer metadata.
146+
// E.g.: rotate RGBA buffer to Grayscale buffer by 90 degrees.
147+
kImageProcessingInvalidArgumentError,
148+
// Image processing operation failures.
149+
// E.g. libyuv rotation failed for an unknown reason.
150+
kImageProcessingBackendError,
151+
152+
// Convenience error codes for condition checks during type casting.
153+
//
154+
// Codes mapping to absl status codes should not be considered for these
155+
// ranges.
156+
// They must be used exclsively for checking if error codes fall in valid
157+
// ranges when converting between TfLiteSupportStatus and
158+
// TfLiteSupportErrorCodee.
159+
160+
// Ensure it holds the least enum value amongst error codes mapping to
161+
// TfLiteSupportStatus.
162+
kErrorCodeFirst = kError,
163+
// Ensure it holds the greatest enum value amongst error codes mapping to
164+
// TfLiteSupportStatus.
165+
kErrorCodeLast = kImageProcessingBackendError,
166+
167+
// Absl Status Codes Mapping
168+
//
169+
// Codes starting from 900 will be used to map absl::Status created by TfLite
170+
// and are used as is by TfLite Support C++ layer. Such absl status objects
171+
// don't have a TfLiteSupportStatus in the payload that can be mapped to other
172+
// error codes in this struct. You must use the absl::Status::code() and map
173+
// them to the following error codes in such cases.
174+
// For more info on respective absl status codes, please see:
175+
// https://github.com/abseil/abseil-cpp/blob/master/absl/status/status.h#L91
176+
177+
// kNotFound indicates some requested entity (such as a file or directory)
178+
// was not found.
179+
kNotFoundError = 900,
180+
// kInternal indicates an internal error has occurred
181+
// and some invariants expected by the underlying system have not been
182+
// satisfied. This error code is reserved for serious errors.
183+
kInternalError,
184+
185+
};
186+
187+
// A `TfLiteSupportError` encapsulates an error code and a descriptive message
188+
// to return in the event of an error being encountered in any TensorFlow Lite
189+
// Task Library C API.
190+
typedef struct TfLiteSupportError {
191+
// Holds the error code.
192+
enum TfLiteSupportErrorCode code;
193+
// Detailed description of the error.
194+
char *message;
195+
} TfLiteSupportError;
196+
197+
void TfLiteSupportErrorDelete(TfLiteSupportError *error);
198+
199+
#ifdef __cplusplus
200+
} // extern "C"
201+
#endif // __cplusplus
202+
203+
#endif // TENSORFLOW_LITE_SUPPORT_C_COMMON_H_
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================*/
15+
16+
#include "tensorflow_lite_support/c/common_utils.h"
17+
18+
#include <string>
19+
20+
#include "external/com_google_absl/absl/status/status.h"
21+
#include "external/com_google_absl/absl/strings/cord.h"
22+
#include "tensorflow_lite_support/cc/common.h"
23+
24+
namespace tflite {
25+
namespace support {
26+
27+
void CreateTfLiteSupportErrorWithStatus(const absl::Status& status,
28+
TfLiteSupportError** error) {
29+
if (status.ok() or error == nullptr) return;
30+
31+
// Payload of absl::Status created by the tflite task library stores an
32+
// appropriate value of the enum TfLiteSupportStatus. The integer value
33+
// corresponding to the TfLiteSupportStatus enum stored in the payload is
34+
// extracted here to later map to the appropriate error code to be returned.
35+
// In cases where the enum is not stored in (payload is NULL or the payload
36+
// string cannot be converted to an integer), we set the error code value to
37+
// be 1 (kError of TfLiteErrorCode used in the C library to signify any errors
38+
// not falling into other categories.) Since payload is of type absl::Cord
39+
// that can be type cast into an absl::optional<std::string>, we use the
40+
// std::stoi function to convert it into an integer code if possible.
41+
int generic_error_code = static_cast<int>(kError);
42+
int error_code;
43+
try {
44+
// Try converting payload to integer if payload is not empty. Otherwise
45+
// convert a string signifying generic error code kError to integer.
46+
error_code = std::stoi(static_cast<absl::optional<std::string>>(
47+
status.GetPayload(kTfLiteSupportPayload))
48+
.value_or(std::to_string(generic_error_code)));
49+
} catch (std::invalid_argument& e) {
50+
// If non empty payload string cannot be converted to an integer. Set error
51+
// code to 1(kError).
52+
error_code = generic_error_code;
53+
}
54+
55+
// If error_code is outside the range of enum values possible or is kError, we
56+
// try to map the absl::Status::code() to assign appropriate
57+
// TfLiteSupportErrorCode or kError in default cases. Note: The mapping to
58+
// absl::Status::code() is done to generate a more specific error code than
59+
// kError in cases when the payload can't be mapped to TfLiteSupportStatus.
60+
// This can happen when absl::Status returned by TfLite are in turn returned
61+
// without moodification by TfLite Support Methods.
62+
if (error_code > static_cast<int>(kErrorCodeLast) ||
63+
error_code <= static_cast<int>(kErrorCodeFirst)) {
64+
switch (status.code()) {
65+
case absl::StatusCode::kInternal:
66+
error_code = kInternalError;
67+
break;
68+
case absl::StatusCode::kInvalidArgument:
69+
error_code = kInvalidArgumentError;
70+
break;
71+
case absl::StatusCode::kNotFound:
72+
error_code = kNotFoundError;
73+
break;
74+
default:
75+
error_code = kError;
76+
break;
77+
}
78+
}
79+
80+
*error = new TfLiteSupportError;
81+
// TfLiteErrorCode has a one to one mapping with TfLiteSupportStatus starting
82+
// from the value 1(kError) and hence will be correctly initialized if
83+
// directly cast from the integer code derived from TfLiteSupportStatus stored
84+
// in payload. TfLiteErrorCode omits kOk = 0 of TfLiteSupportStatus.
85+
//
86+
// TODO(prianka): Investigate if switching between error code cast to
87+
// TfLiteSupportStatus and assigning appropriate value to TfLiteErrorCode is
88+
// necessary (If 'TfLiteSupportStatus' or other edge cases).
89+
(*error)->code = static_cast<TfLiteSupportErrorCode>(error_code);
90+
// Stores a string including absl status code and message(if non empty) as the
91+
// error message See
92+
// https://github.com/abseil/abseil-cpp/blob/master/absl/status/status.h#L514
93+
// for explanation. absl::Status::message() can also be used but not always
94+
// guaranteed to be non empty.
95+
(*error)->message = strdup(
96+
status.ToString(absl::StatusToStringMode::kWithNoExtraData).c_str());
97+
}
98+
99+
} // namespace support
100+
} // namespace tflite

0 commit comments

Comments
 (0)