1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker *
4*993b0882SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker *
8*993b0882SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker *
10*993b0882SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker */
16*993b0882SAndroid Build Coastguard Worker
17*993b0882SAndroid Build Coastguard Worker #include "utils/tflite/text_encoder.h"
18*993b0882SAndroid Build Coastguard Worker
19*993b0882SAndroid Build Coastguard Worker #include <memory>
20*993b0882SAndroid Build Coastguard Worker #include <vector>
21*993b0882SAndroid Build Coastguard Worker
22*993b0882SAndroid Build Coastguard Worker #include "utils/base/logging.h"
23*993b0882SAndroid Build Coastguard Worker #include "utils/container/double-array-trie.h"
24*993b0882SAndroid Build Coastguard Worker #include "utils/container/sorted-strings-table.h"
25*993b0882SAndroid Build Coastguard Worker #include "utils/sentencepiece/encoder.h"
26*993b0882SAndroid Build Coastguard Worker #include "utils/sentencepiece/normalizer.h"
27*993b0882SAndroid Build Coastguard Worker #include "utils/strings/stringpiece.h"
28*993b0882SAndroid Build Coastguard Worker #include "utils/tflite/encoder_common.h"
29*993b0882SAndroid Build Coastguard Worker #include "utils/tflite/text_encoder_config_generated.h"
30*993b0882SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
31*993b0882SAndroid Build Coastguard Worker #include "flatbuffers/flexbuffers.h"
32*993b0882SAndroid Build Coastguard Worker #include "tensorflow/lite/kernels/kernel_util.h"
33*993b0882SAndroid Build Coastguard Worker #include "tensorflow/lite/model.h"
34*993b0882SAndroid Build Coastguard Worker #include "tensorflow/lite/string_util.h"
35*993b0882SAndroid Build Coastguard Worker
36*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
37*993b0882SAndroid Build Coastguard Worker namespace {
38*993b0882SAndroid Build Coastguard Worker
39*993b0882SAndroid Build Coastguard Worker struct TextEncoderOp {
40*993b0882SAndroid Build Coastguard Worker std::unique_ptr<SentencePieceNormalizer> normalizer;
41*993b0882SAndroid Build Coastguard Worker std::unique_ptr<Encoder> encoder;
42*993b0882SAndroid Build Coastguard Worker std::unique_ptr<StringSet> matcher;
43*993b0882SAndroid Build Coastguard Worker };
44*993b0882SAndroid Build Coastguard Worker
45*993b0882SAndroid Build Coastguard Worker // Input parameters for the op.
46*993b0882SAndroid Build Coastguard Worker // The conversation message as a (1, conversation length) string tensor.
47*993b0882SAndroid Build Coastguard Worker constexpr const int kInputTexts = 0;
48*993b0882SAndroid Build Coastguard Worker
49*993b0882SAndroid Build Coastguard Worker // The number of messages, the conversation length, int scalar.
50*993b0882SAndroid Build Coastguard Worker constexpr const int kInputNumInputs = 1;
51*993b0882SAndroid Build Coastguard Worker
52*993b0882SAndroid Build Coastguard Worker // Maximum output length of the encoding, int scalar.
53*993b0882SAndroid Build Coastguard Worker constexpr const int kInputMaxLength = 2;
54*993b0882SAndroid Build Coastguard Worker
55*993b0882SAndroid Build Coastguard Worker // Additional attributes to align to the sentence pieces, e.g. user ids per
56*993b0882SAndroid Build Coastguard Worker // message.
57*993b0882SAndroid Build Coastguard Worker constexpr const int kInputAttr = 3;
58*993b0882SAndroid Build Coastguard Worker
59*993b0882SAndroid Build Coastguard Worker // Output parameters for the op.
60*993b0882SAndroid Build Coastguard Worker // The text sentence piece encodings as ids, (1, max output length) int tensor.
61*993b0882SAndroid Build Coastguard Worker constexpr const int kOutputEncoded = 0;
62*993b0882SAndroid Build Coastguard Worker
63*993b0882SAndroid Build Coastguard Worker // Relative position of each sentence piece in the input text,
64*993b0882SAndroid Build Coastguard Worker // (1, max output length) int tensor.
65*993b0882SAndroid Build Coastguard Worker constexpr const int kOutputPosition = 1;
66*993b0882SAndroid Build Coastguard Worker
67*993b0882SAndroid Build Coastguard Worker // Output length after trimming to the maximum output length specified.
68*993b0882SAndroid Build Coastguard Worker // int scalar.
69*993b0882SAndroid Build Coastguard Worker constexpr const int kOutputLengths = 2;
70*993b0882SAndroid Build Coastguard Worker
71*993b0882SAndroid Build Coastguard Worker // Padded and sentence piece aligned provided attributes, e.g. user id per
72*993b0882SAndroid Build Coastguard Worker // sentence piece.
73*993b0882SAndroid Build Coastguard Worker constexpr const int kOutputAttr = 3;
74*993b0882SAndroid Build Coastguard Worker
75*993b0882SAndroid Build Coastguard Worker const char kTextEncoderConfigAttr[] = "text_encoder_config";
76*993b0882SAndroid Build Coastguard Worker
77*993b0882SAndroid Build Coastguard Worker // Initializes text encoder object from serialized options:
78*993b0882SAndroid Build Coastguard Worker // The options are a flexbuffers attribute map that contain the op config
79*993b0882SAndroid Build Coastguard Worker // with the key `text_encoder_config` as `TextEncoderConfig`.
Initialize(TfLiteContext * context,const char * buffer,size_t length)80*993b0882SAndroid Build Coastguard Worker void* Initialize(TfLiteContext* context, const char* buffer, size_t length) {
81*993b0882SAndroid Build Coastguard Worker const flexbuffers::Map& attr_map =
82*993b0882SAndroid Build Coastguard Worker flexbuffers::GetRoot(reinterpret_cast<const uint8_t*>(buffer), length)
83*993b0882SAndroid Build Coastguard Worker .AsMap();
84*993b0882SAndroid Build Coastguard Worker const flexbuffers::Blob serialized_config =
85*993b0882SAndroid Build Coastguard Worker attr_map[kTextEncoderConfigAttr].AsBlob();
86*993b0882SAndroid Build Coastguard Worker const TextEncoderConfig* config =
87*993b0882SAndroid Build Coastguard Worker flatbuffers::GetRoot<TextEncoderConfig>(serialized_config.data());
88*993b0882SAndroid Build Coastguard Worker
89*993b0882SAndroid Build Coastguard Worker std::unique_ptr<TextEncoderOp> encoder_op(new TextEncoderOp());
90*993b0882SAndroid Build Coastguard Worker
91*993b0882SAndroid Build Coastguard Worker // Create normalizer from options.
92*993b0882SAndroid Build Coastguard Worker const TrieNode* charsmap_trie_nodes = reinterpret_cast<const TrieNode*>(
93*993b0882SAndroid Build Coastguard Worker config->normalization_charsmap()->Data());
94*993b0882SAndroid Build Coastguard Worker const int charsmap_trie_nodes_length =
95*993b0882SAndroid Build Coastguard Worker config->normalization_charsmap()->size() / sizeof(TrieNode);
96*993b0882SAndroid Build Coastguard Worker encoder_op->normalizer.reset(new SentencePieceNormalizer(
97*993b0882SAndroid Build Coastguard Worker DoubleArrayTrie(charsmap_trie_nodes, charsmap_trie_nodes_length),
98*993b0882SAndroid Build Coastguard Worker StringPiece(config->normalization_charsmap_values()->data(),
99*993b0882SAndroid Build Coastguard Worker config->normalization_charsmap_values()->size()),
100*993b0882SAndroid Build Coastguard Worker config->add_dummy_prefix(), config->remove_extra_whitespaces(),
101*993b0882SAndroid Build Coastguard Worker config->escape_whitespaces()));
102*993b0882SAndroid Build Coastguard Worker
103*993b0882SAndroid Build Coastguard Worker const int num_pieces = config->pieces_scores()->size();
104*993b0882SAndroid Build Coastguard Worker
105*993b0882SAndroid Build Coastguard Worker switch (config->matcher_type()) {
106*993b0882SAndroid Build Coastguard Worker case SentencePieceMatcherType_MAPPED_TRIE: {
107*993b0882SAndroid Build Coastguard Worker const TrieNode* pieces_trie_nodes =
108*993b0882SAndroid Build Coastguard Worker reinterpret_cast<const TrieNode*>(config->pieces()->Data());
109*993b0882SAndroid Build Coastguard Worker const int pieces_trie_nodes_length =
110*993b0882SAndroid Build Coastguard Worker config->pieces()->size() / sizeof(TrieNode);
111*993b0882SAndroid Build Coastguard Worker encoder_op->matcher.reset(
112*993b0882SAndroid Build Coastguard Worker new DoubleArrayTrie(pieces_trie_nodes, pieces_trie_nodes_length));
113*993b0882SAndroid Build Coastguard Worker break;
114*993b0882SAndroid Build Coastguard Worker }
115*993b0882SAndroid Build Coastguard Worker case SentencePieceMatcherType_SORTED_STRING_TABLE: {
116*993b0882SAndroid Build Coastguard Worker encoder_op->matcher.reset(new SortedStringsTable(
117*993b0882SAndroid Build Coastguard Worker num_pieces, config->pieces_offsets()->data(),
118*993b0882SAndroid Build Coastguard Worker StringPiece(config->pieces()->data(), config->pieces()->size())));
119*993b0882SAndroid Build Coastguard Worker break;
120*993b0882SAndroid Build Coastguard Worker }
121*993b0882SAndroid Build Coastguard Worker default: {
122*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Unknown sentence piece matcher type.";
123*993b0882SAndroid Build Coastguard Worker return nullptr;
124*993b0882SAndroid Build Coastguard Worker }
125*993b0882SAndroid Build Coastguard Worker }
126*993b0882SAndroid Build Coastguard Worker encoder_op->encoder.reset(new Encoder(
127*993b0882SAndroid Build Coastguard Worker encoder_op->matcher.get(), num_pieces, config->pieces_scores()->data(),
128*993b0882SAndroid Build Coastguard Worker config->start_code(), config->end_code(), config->encoding_offset(),
129*993b0882SAndroid Build Coastguard Worker config->unknown_code(), config->unknown_score()));
130*993b0882SAndroid Build Coastguard Worker return encoder_op.release();
131*993b0882SAndroid Build Coastguard Worker }
132*993b0882SAndroid Build Coastguard Worker
Free(TfLiteContext * context,void * buffer)133*993b0882SAndroid Build Coastguard Worker void Free(TfLiteContext* context, void* buffer) {
134*993b0882SAndroid Build Coastguard Worker delete reinterpret_cast<TextEncoderOp*>(buffer);
135*993b0882SAndroid Build Coastguard Worker }
136*993b0882SAndroid Build Coastguard Worker
ResizeOutputTensors(TfLiteContext * context,TfLiteNode * node,int max_output_length)137*993b0882SAndroid Build Coastguard Worker TfLiteStatus ResizeOutputTensors(TfLiteContext* context, TfLiteNode* node,
138*993b0882SAndroid Build Coastguard Worker int max_output_length) {
139*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_OK(
140*993b0882SAndroid Build Coastguard Worker context,
141*993b0882SAndroid Build Coastguard Worker ResizeOutputTensor(max_output_length,
142*993b0882SAndroid Build Coastguard Worker &context->tensors[node->outputs->data[kOutputEncoded]],
143*993b0882SAndroid Build Coastguard Worker context));
144*993b0882SAndroid Build Coastguard Worker
145*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_OK(
146*993b0882SAndroid Build Coastguard Worker context,
147*993b0882SAndroid Build Coastguard Worker ResizeOutputTensor(
148*993b0882SAndroid Build Coastguard Worker max_output_length,
149*993b0882SAndroid Build Coastguard Worker &context->tensors[node->outputs->data[kOutputPosition]], context));
150*993b0882SAndroid Build Coastguard Worker
151*993b0882SAndroid Build Coastguard Worker const int num_output_attrs = node->outputs->size - kOutputAttr;
152*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < num_output_attrs; ++i) {
153*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_OK(
154*993b0882SAndroid Build Coastguard Worker context,
155*993b0882SAndroid Build Coastguard Worker ResizeOutputTensor(
156*993b0882SAndroid Build Coastguard Worker max_output_length,
157*993b0882SAndroid Build Coastguard Worker &context->tensors[node->outputs->data[kOutputAttr + i]], context));
158*993b0882SAndroid Build Coastguard Worker }
159*993b0882SAndroid Build Coastguard Worker return kTfLiteOk;
160*993b0882SAndroid Build Coastguard Worker }
161*993b0882SAndroid Build Coastguard Worker
Prepare(TfLiteContext * context,TfLiteNode * node)162*993b0882SAndroid Build Coastguard Worker TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
163*993b0882SAndroid Build Coastguard Worker // Check that the batch dimension is kBatchSize.
164*993b0882SAndroid Build Coastguard Worker const TfLiteTensor& input_text =
165*993b0882SAndroid Build Coastguard Worker context->tensors[node->inputs->data[kInputTexts]];
166*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_EQ(context, input_text.dims->size, kEncoderInputRank);
167*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_EQ(context, input_text.dims->data[0], kEncoderBatchSize);
168*993b0882SAndroid Build Coastguard Worker
169*993b0882SAndroid Build Coastguard Worker TfLiteTensor& output_lengths =
170*993b0882SAndroid Build Coastguard Worker context->tensors[node->outputs->data[kOutputLengths]];
171*993b0882SAndroid Build Coastguard Worker TfLiteTensor& output_encoded =
172*993b0882SAndroid Build Coastguard Worker context->tensors[node->outputs->data[kOutputEncoded]];
173*993b0882SAndroid Build Coastguard Worker TfLiteTensor& output_positions =
174*993b0882SAndroid Build Coastguard Worker context->tensors[node->outputs->data[kOutputPosition]];
175*993b0882SAndroid Build Coastguard Worker
176*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_OK(context,
177*993b0882SAndroid Build Coastguard Worker context->ResizeTensor(context, &output_lengths,
178*993b0882SAndroid Build Coastguard Worker CreateIntArray({kEncoderBatchSize})));
179*993b0882SAndroid Build Coastguard Worker
180*993b0882SAndroid Build Coastguard Worker // Check that there are enough outputs for attributes.
181*993b0882SAndroid Build Coastguard Worker const int num_output_attrs = node->outputs->size - kOutputAttr;
182*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_EQ(context, node->inputs->size - kInputAttr, num_output_attrs);
183*993b0882SAndroid Build Coastguard Worker
184*993b0882SAndroid Build Coastguard Worker // Copy attribute types from input to output tensors.
185*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < num_output_attrs; ++i) {
186*993b0882SAndroid Build Coastguard Worker TfLiteTensor& input = context->tensors[node->inputs->data[kInputAttr + i]];
187*993b0882SAndroid Build Coastguard Worker TfLiteTensor& output =
188*993b0882SAndroid Build Coastguard Worker context->tensors[node->outputs->data[kOutputAttr + i]];
189*993b0882SAndroid Build Coastguard Worker output.type = input.type;
190*993b0882SAndroid Build Coastguard Worker }
191*993b0882SAndroid Build Coastguard Worker
192*993b0882SAndroid Build Coastguard Worker const TfLiteTensor& output_length =
193*993b0882SAndroid Build Coastguard Worker context->tensors[node->inputs->data[kInputMaxLength]];
194*993b0882SAndroid Build Coastguard Worker
195*993b0882SAndroid Build Coastguard Worker if (tflite::IsConstantTensor(&output_length)) {
196*993b0882SAndroid Build Coastguard Worker return ResizeOutputTensors(context, node, output_length.data.i64[0]);
197*993b0882SAndroid Build Coastguard Worker } else {
198*993b0882SAndroid Build Coastguard Worker tflite::SetTensorToDynamic(&output_encoded);
199*993b0882SAndroid Build Coastguard Worker tflite::SetTensorToDynamic(&output_positions);
200*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < num_output_attrs; ++i) {
201*993b0882SAndroid Build Coastguard Worker TfLiteTensor& output_attr =
202*993b0882SAndroid Build Coastguard Worker context->tensors[node->outputs->data[kOutputAttr + i]];
203*993b0882SAndroid Build Coastguard Worker tflite::SetTensorToDynamic(&output_attr);
204*993b0882SAndroid Build Coastguard Worker }
205*993b0882SAndroid Build Coastguard Worker }
206*993b0882SAndroid Build Coastguard Worker
207*993b0882SAndroid Build Coastguard Worker return kTfLiteOk;
208*993b0882SAndroid Build Coastguard Worker }
209*993b0882SAndroid Build Coastguard Worker
Eval(TfLiteContext * context,TfLiteNode * node)210*993b0882SAndroid Build Coastguard Worker TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
211*993b0882SAndroid Build Coastguard Worker if (node->user_data == nullptr) {
212*993b0882SAndroid Build Coastguard Worker return kTfLiteError;
213*993b0882SAndroid Build Coastguard Worker }
214*993b0882SAndroid Build Coastguard Worker const TextEncoderOp* encoder_op =
215*993b0882SAndroid Build Coastguard Worker reinterpret_cast<TextEncoderOp*>(node->user_data);
216*993b0882SAndroid Build Coastguard Worker const TfLiteTensor& input_text =
217*993b0882SAndroid Build Coastguard Worker context->tensors[node->inputs->data[kInputTexts]];
218*993b0882SAndroid Build Coastguard Worker const int num_strings = tflite::GetStringCount(&input_text);
219*993b0882SAndroid Build Coastguard Worker // Check that the number of strings matches the length parameter.
220*993b0882SAndroid Build Coastguard Worker const int num_strings_param =
221*993b0882SAndroid Build Coastguard Worker context->tensors[node->inputs->data[kInputNumInputs]].data.i32[0];
222*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_EQ(context, num_strings, num_strings_param);
223*993b0882SAndroid Build Coastguard Worker
224*993b0882SAndroid Build Coastguard Worker TfLiteTensor& output_encoded =
225*993b0882SAndroid Build Coastguard Worker context->tensors[node->outputs->data[kOutputEncoded]];
226*993b0882SAndroid Build Coastguard Worker if (tflite::IsDynamicTensor(&output_encoded)) {
227*993b0882SAndroid Build Coastguard Worker const TfLiteTensor& output_length =
228*993b0882SAndroid Build Coastguard Worker context->tensors[node->inputs->data[kInputMaxLength]];
229*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_OK(
230*993b0882SAndroid Build Coastguard Worker context, ResizeOutputTensors(context, node, output_length.data.i64[0]));
231*993b0882SAndroid Build Coastguard Worker }
232*993b0882SAndroid Build Coastguard Worker TfLiteTensor& output_positions =
233*993b0882SAndroid Build Coastguard Worker context->tensors[node->outputs->data[kOutputPosition]];
234*993b0882SAndroid Build Coastguard Worker
235*993b0882SAndroid Build Coastguard Worker std::vector<int> encoded_total;
236*993b0882SAndroid Build Coastguard Worker std::vector<int> encoded_offsets;
237*993b0882SAndroid Build Coastguard Worker std::vector<int> encoded_positions;
238*993b0882SAndroid Build Coastguard Worker encoded_offsets.reserve(num_strings);
239*993b0882SAndroid Build Coastguard Worker const int max_output_length = output_encoded.dims->data[1];
240*993b0882SAndroid Build Coastguard Worker const int max_encoded_position = max_output_length;
241*993b0882SAndroid Build Coastguard Worker
242*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < num_strings; ++i) {
243*993b0882SAndroid Build Coastguard Worker const auto& strref = tflite::GetString(&input_text, i);
244*993b0882SAndroid Build Coastguard Worker std::string normalized;
245*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE(context,
246*993b0882SAndroid Build Coastguard Worker encoder_op->normalizer->Normalize(
247*993b0882SAndroid Build Coastguard Worker StringPiece(strref.str, strref.len), &normalized));
248*993b0882SAndroid Build Coastguard Worker std::vector<int> encoded;
249*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE(context, encoder_op->encoder->Encode(normalized, &encoded));
250*993b0882SAndroid Build Coastguard Worker encoded_total.insert(encoded_total.end(), encoded.begin(), encoded.end());
251*993b0882SAndroid Build Coastguard Worker encoded_offsets.push_back(encoded_total.size());
252*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < encoded.size(); i++) {
253*993b0882SAndroid Build Coastguard Worker encoded_positions.push_back(std::min(i, max_encoded_position - 1));
254*993b0882SAndroid Build Coastguard Worker }
255*993b0882SAndroid Build Coastguard Worker }
256*993b0882SAndroid Build Coastguard Worker
257*993b0882SAndroid Build Coastguard Worker const int num_skip = CopyDataToTensorAndPadOrTruncate(
258*993b0882SAndroid Build Coastguard Worker max_output_length, encoded_total,
259*993b0882SAndroid Build Coastguard Worker /*padding_value=*/encoded_total.back(), &output_encoded);
260*993b0882SAndroid Build Coastguard Worker TfLiteTensor& output_lengths =
261*993b0882SAndroid Build Coastguard Worker context->tensors[node->outputs->data[kOutputLengths]];
262*993b0882SAndroid Build Coastguard Worker output_lengths.data.i32[0] = encoded_total.size() - num_skip;
263*993b0882SAndroid Build Coastguard Worker CopyDataToTensorAndPadOrTruncate(max_output_length, encoded_positions,
264*993b0882SAndroid Build Coastguard Worker /*padding_value=*/max_encoded_position,
265*993b0882SAndroid Build Coastguard Worker &output_positions);
266*993b0882SAndroid Build Coastguard Worker
267*993b0882SAndroid Build Coastguard Worker // Process attributes, all checks of sizes and types are done in Prepare.
268*993b0882SAndroid Build Coastguard Worker const int num_output_attrs = node->outputs->size - kOutputAttr;
269*993b0882SAndroid Build Coastguard Worker TF_LITE_ENSURE_EQ(context, node->inputs->size - kInputAttr, num_output_attrs);
270*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < num_output_attrs; ++i) {
271*993b0882SAndroid Build Coastguard Worker TfLiteStatus attr_status = CopyValuesToTensorAndPadOrTruncate(
272*993b0882SAndroid Build Coastguard Worker context->tensors[node->inputs->data[kInputAttr + i]], encoded_offsets,
273*993b0882SAndroid Build Coastguard Worker num_skip, context,
274*993b0882SAndroid Build Coastguard Worker &context->tensors[node->outputs->data[kOutputAttr + i]]);
275*993b0882SAndroid Build Coastguard Worker if (attr_status != kTfLiteOk) {
276*993b0882SAndroid Build Coastguard Worker return attr_status;
277*993b0882SAndroid Build Coastguard Worker }
278*993b0882SAndroid Build Coastguard Worker }
279*993b0882SAndroid Build Coastguard Worker
280*993b0882SAndroid Build Coastguard Worker return kTfLiteOk;
281*993b0882SAndroid Build Coastguard Worker }
282*993b0882SAndroid Build Coastguard Worker
283*993b0882SAndroid Build Coastguard Worker } // namespace
284*993b0882SAndroid Build Coastguard Worker } // namespace libtextclassifier3
285*993b0882SAndroid Build Coastguard Worker
286*993b0882SAndroid Build Coastguard Worker namespace tflite {
287*993b0882SAndroid Build Coastguard Worker namespace ops {
288*993b0882SAndroid Build Coastguard Worker namespace custom {
289*993b0882SAndroid Build Coastguard Worker
Register_TEXT_ENCODER()290*993b0882SAndroid Build Coastguard Worker TfLiteRegistration* Register_TEXT_ENCODER() {
291*993b0882SAndroid Build Coastguard Worker static TfLiteRegistration registration = {
292*993b0882SAndroid Build Coastguard Worker libtextclassifier3::Initialize, libtextclassifier3::Free,
293*993b0882SAndroid Build Coastguard Worker libtextclassifier3::Prepare, libtextclassifier3::Eval};
294*993b0882SAndroid Build Coastguard Worker return ®istration;
295*993b0882SAndroid Build Coastguard Worker }
296*993b0882SAndroid Build Coastguard Worker
297*993b0882SAndroid Build Coastguard Worker } // namespace custom
298*993b0882SAndroid Build Coastguard Worker } // namespace ops
299*993b0882SAndroid Build Coastguard Worker } // namespace tflite
300