1. Прежде чем начать
В этой лабораторной работе вы узнаете, как выполнить вывод классификации текста из приложения Flutter с помощью TensorFlow Serving через REST и gRPC.
Предпосылки
- Базовые знания по разработке Flutter с использованием Dart
- Базовые знания машинного обучения с TensorFlow, например, обучение и развертывание
- Базовые знания терминалов и Docker
- Обучение модели обнаружения спама в комментариях с помощью практической работы TensorFlow Lite Model Maker
Чему вы научитесь
- Как создать простое приложение Flutter и классифицировать тексты с помощью TensorFlow Serving (REST и gRPC).
- Как отобразить результаты в пользовательском интерфейсе.
Что вам понадобится
- Flutter SDK
- Настройка Flutter для Android или iOS
- Настройка Visual Studio Code (VS Code) для Flutter и Dart
- Докер
- Баш
- Компилятор буфера протокола и плагин gRPC Dart для компилятора протокола (необходим только в том случае, если вы хотите самостоятельно повторно сгенерировать заглушку gRPC)
2. Настройте среду разработки Flutter
Для разработки на Flutter вам понадобятся два программных обеспечения для выполнения этой лабораторной работы: Flutter SDK и редактор .
Вы можете запустить практическую работу, используя любое из этих устройств:
- Симулятор iOS (требуется установка инструментов Xcode).
- Эмулятор Android (требуется настройка в Android Studio).
- Браузер (для отладки требуется Chrome).
- В качестве настольного приложения для Windows , Linux или macOS . Разработка должна осуществляться на той платформе, на которой планируется её развертывание. Таким образом, если вы хотите разработать настольное приложение для Windows, вам необходимо разрабатывать его в Windows, чтобы получить доступ к соответствующей цепочке сборки. Существуют специфические требования к операционной системе, которые подробно описаны на сайте docs.flutter.dev/desktop .
3. Приступайте к настройке
Чтобы загрузить код для этой лабораторной работы:
- Перейдите в репозиторий GitHub для этой лабораторной работы.
- Нажмите Код > Загрузить zip , чтобы загрузить весь код для этой лабораторной работы.
- Распакуйте загруженный zip-файл, чтобы распаковать корневую папку
codelabs-main
со всеми необходимыми вам ресурсами.
Для этой лабораторной работы вам понадобятся только файлы в подкаталоге tfserving-flutter/codelab2
в репозитории, который содержит две папки:
- В
starter
папке содержится стартовый код, на основе которого вы будете строить эту лабораторную работу. -
finished
папка содержит готовый код для готового примера приложения.
4. Загрузите зависимости для проекта.
- В VS Code нажмите Файл > Открыть папку , а затем выберите
starter
папку из исходного кода, который вы скачали ранее. - Если появится диалоговое окно с предложением загрузить необходимые пакеты для стартового приложения, нажмите кнопку Получить пакеты .
- Если вы не видите это диалоговое окно, откройте терминал и выполните команду
flutter pub get
вstarter
папке.
5. Запустите стартовое приложение.
- В VS Code убедитесь, что Android Emulator или iOS Simulator правильно настроен и отображается в строке состояния.
Например, вот что вы видите при использовании Pixel 5 с эмулятором Android:
Вот что вы видите при использовании iPhone 13 с iOS Simulator:
- Щелкните
Начать отладку .
Запустите и изучите приложение
Приложение должно запускаться на вашем эмуляторе Android или симуляторе iOS. Пользовательский интерфейс довольно прост. Есть текстовое поле, в которое пользователь может ввести текст. Пользователь может выбрать, отправлять ли данные на бэкенд с помощью REST или gRPC. Бэкенд использует модель TensorFlow для классификации текста на основе предварительно обработанных входных данных и возвращает результат классификации клиентскому приложению, которое, в свою очередь, обновляет пользовательский интерфейс.
Если нажать кнопку «Классифицировать» , ничего не произойдет, поскольку система пока не может связаться с бэкэндом.
6. Разверните модель классификации текста с помощью TensorFlow Serving
Классификация текста — очень распространённая задача машинного обучения, которая классифицирует тексты по предопределённым категориям. В этой лабораторной работе вы развернёте предварительно обученную модель из лабораторной работы «Обучение модели обнаружения спама в комментариях с помощью TensorFlow Lite Model Maker» с TensorFlow Serving и вызовете бэкенд из фронтенда Flutter, чтобы классифицировать входящий текст как спам или нет .
Запустить TensorFlow Serving
- В терминале запустите TensorFlow Serving с Docker, но замените заполнитель
PATH/TO/SAVEDMODEL
на абсолютный путь к папкеmm_spam_savedmodel
на вашем компьютере.
docker pull tensorflow/serving docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/spam-detection" -e MODEL_NAME=spam-detection tensorflow/serving
Сначала Docker автоматически загрузит образ TensorFlow Serving, что займёт около минуты. После этого TensorFlow Serving должен запуститься. Журнал должен выглядеть следующим образом:
2022-02-25 06:01:12.513231: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle. 2022-02-25 06:01:12.585012: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 3000000000 Hz 2022-02-25 06:01:13.395083: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ssd_mobilenet_v2_2/123 2022-02-25 06:01:13.837562: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 1928700 microseconds. 2022-02-25 06:01:13.877848: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ssd_mobilenet_v2_2/123/assets.extra/tf_serving_warmup_requests 2022-02-25 06:01:13.929844: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: spam-detection version: 123} 2022-02-25 06:01:13.985848: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models 2022-02-25 06:01:13.985987: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled 2022-02-25 06:01:13.988994: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ... [warn] getaddrinfo: address family for nodename not supported 2022-02-25 06:01:14.033872: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ... [evhttp_server.cc : 245] NET_LOG: Entering the event loop ...
7. Токенизировать входящее предложение
Бэкэнд готов, поэтому вы почти готовы отправлять клиентские запросы в TensorFlow Serving, но сначала вам нужно токенизировать входное предложение. Если вы проверите входной тензор модели, вы увидите, что он ожидает список из 20 целых чисел вместо необработанных строк. Токенизация — это когда вы сопоставляете отдельные слова, которые вы вводите в приложении, со списком целых чисел на основе словарного словаря, прежде чем отправить их на бэкэнд для классификации. Например, если вы вводите buy book online to learn more
, процесс токенизации сопоставляет его с [32, 79, 183, 10, 224, 631, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
. Конкретные числа могут различаться в зависимости от словарного словаря.
- В файле
lib/main.dart
добавьте этот код в методpredict()
для создания словаря слов_vocabMap
.
// Build _vocabMap if empty.
if (_vocabMap.isEmpty) {
final vocabFileString = await rootBundle.loadString(vocabFile);
final lines = vocabFileString.split('\n');
for (final l in lines) {
if (l != "") {
var wordAndIndex = l.split(' ');
(_vocabMap)[wordAndIndex[0]] = int.parse(wordAndIndex[1]);
}
}
}
- Сразу после предыдущего фрагмента кода добавьте этот код для реализации токенизации:
// Tokenize the input sentence.
final inputWords = _inputSentenceController.text
.toLowerCase()
.replaceAll(RegExp('[^a-z ]'), '')
.split(' ');
// Initialize with padding token.
_tokenIndices = List.filled(maxSentenceLength, 0);
var i = 0;
for (final w in inputWords) {
if ((_vocabMap).containsKey(w)) {
_tokenIndices[i] = (_vocabMap)[w]!;
i++;
}
// Truncate the string if longer than maxSentenceLength.
if (i >= maxSentenceLength - 1) {
break;
}
}
Этот код переводит строку предложения в нижний регистр, удаляет символы, не входящие в алфавитный список, и сопоставляет слова с 20 целочисленными индексами на основе таблицы словаря.
8. Подключите приложение Flutter к TensorFlow Serving через REST.
Существует два способа отправки запросов в TensorFlow Serving:
- ОТДЫХ
- gRPC
Отправка запросов и получение ответов через REST
Для отправки запросов и получения ответов через REST необходимо выполнить три простых шага:
- Создайте REST-запрос.
- Отправьте REST-запрос в TensorFlow Serving.
- Извлеките прогнозируемый результат из ответа REST и отобразите пользовательский интерфейс.
Эти шаги выполняются в файле main.dart
.
Создайте и отправьте REST-запрос в TensorFlow Serving
- В настоящее время функция
predict()
не отправляет REST-запрос в TensorFlow Serving. Для создания REST-запроса необходимо реализовать ветку REST:
if (_connectionMode == ConnectionModeType.rest) {
// TODO: Create and send the REST request.
}
- Добавьте этот код в ветку REST:
//Create the REST request.
final response = await http.post(
Uri.parse('http://' +
_server +
':' +
restPort.toString() +
'/v1/models/' +
modelName +
':predict'),
body: jsonEncode(<String, List<List<int>>>{
'instances': [_tokenIndices],
}),
);
Обработать ответ REST от TensorFlow Serving
- Добавьте этот код сразу после предыдущего фрагмента кода для обработки ответа REST:
// Process the REST response.
if (response.statusCode == 200) {
Map<String, dynamic> result = jsonDecode(response.body);
if (result['predictions']![0][1] >= classificationThreshold) {
return 'This sentence is spam. Spam score is ' +
result['predictions']![0][1].toString();
}
return 'This sentence is not spam. Spam score is ' +
result['predictions']![0][1].toString();
} else {
throw Exception('Error response');
}
Код постобработки извлекает из ответа вероятность того, что входящее предложение является спам-сообщением, и отображает результат классификации в пользовательском интерфейсе.
Запусти это
- Щелкните
Начните отладку и дождитесь загрузки приложения.
- Введите текст и выберите REST > Классифицировать .
9. Подключите приложение Flutter к TensorFlow Serving через gRPC.
Помимо REST, TensorFlow Serving также поддерживает gRPC .
gRPC — это современная высокопроизводительная платформа удалённого вызова процедур (RPC) с открытым исходным кодом, которая может работать в любой среде. Она обеспечивает эффективное подключение сервисов внутри и между центрами обработки данных благодаря подключаемым модулям для балансировки нагрузки, трассировки, проверки работоспособности и аутентификации. На практике gRPC демонстрирует более высокую производительность, чем REST.
Отправка запросов и получение ответов с помощью gRPC
Для отправки запросов и получения ответов с помощью gRPC необходимо выполнить четыре простых шага:
- Необязательно: сгенерируйте заглушку кода клиента gRPC.
- Создайте запрос gRPC.
- Отправьте запрос gRPC в TensorFlow Serving.
- Извлеките прогнозируемый результат из ответа gRPC и отобразите пользовательский интерфейс.
Эти шаги выполняются в файле main.dart
.
Необязательно: сгенерируйте заглушку кода клиента gRPC.
Чтобы использовать gRPC с TensorFlow Serving, необходимо следовать рабочему процессу gRPC. Подробнее см. в документации gRPC .
TensorFlow Serving и TensorFlow определяют файлы .proto
автоматически. Начиная с TensorFlow и TensorFlow Serving версии 2.8, необходимы следующие файлы .proto
:
tensorflow/core/example/example.proto
tensorflow/core/example/feature.proto
tensorflow/core/protobuf/struct.proto
tensorflow/core/protobuf/saved_object_graph.proto
tensorflow/core/protobuf/saver.proto
tensorflow/core/protobuf/trackable_object_graph.proto
tensorflow/core/protobuf/meta_graph.proto
tensorflow/core/framework/node_def.proto
tensorflow/core/framework/attr_value.proto
tensorflow/core/framework/function.proto
tensorflow/core/framework/types.proto
tensorflow/core/framework/tensor_shape.proto
tensorflow/core/framework/full_type.proto
tensorflow/core/framework/versions.proto
tensorflow/core/framework/op_def.proto
tensorflow/core/framework/graph.proto
tensorflow/core/framework/tensor.proto
tensorflow/core/framework/resource_handle.proto
tensorflow/core/framework/variable.proto
tensorflow_serving/apis/inference.proto
tensorflow_serving/apis/classification.proto
tensorflow_serving/apis/predict.proto
tensorflow_serving/apis/regression.proto
tensorflow_serving/apis/get_model_metadata.proto
tensorflow_serving/apis/input.proto
tensorflow_serving/apis/prediction_service.proto
tensorflow_serving/apis/model.proto
google/protobuf/any.proto
google/protobuf/wrappers.proto
- В терминале перейдите в папку
starter/lib/proto/
и сгенерируйте заглушку:
bash generate_grpc_stub_dart.sh
Создайте запрос gRPC
Подобно запросу REST, запрос gRPC создается в ветке gRPC.
if (_connectionMode == ConnectionModeType.rest) {
} else {
// TODO: Create and send the gRPC request.
}
- Добавьте этот код для создания запроса gRPC:
//Create the gRPC request.
final channel = ClientChannel(_server,
port: grpcPort,
options:
const ChannelOptions(credentials: ChannelCredentials.insecure()));
_stub = PredictionServiceClient(channel,
options: CallOptions(timeout: const Duration(seconds: 10)));
ModelSpec modelSpec = ModelSpec(
name: 'spam-detection',
signatureName: 'serving_default',
);
TensorShapeProto_Dim batchDim = TensorShapeProto_Dim(size: Int64(1));
TensorShapeProto_Dim inputDim =
TensorShapeProto_Dim(size: Int64(maxSentenceLength));
TensorShapeProto inputTensorShape =
TensorShapeProto(dim: [batchDim, inputDim]);
TensorProto inputTensor = TensorProto(
dtype: DataType.DT_INT32,
tensorShape: inputTensorShape,
intVal: _tokenIndices);
// If you train your own model, update the input and output tensor names.
const inputTensorName = 'input_3';
const outputTensorName = 'dense_5';
PredictRequest request = PredictRequest(
modelSpec: modelSpec, inputs: {inputTensorName: inputTensor});
Примечание: Имена входных и выходных тензоров могут различаться в разных моделях, даже если их архитектура одинакова. Обязательно обновите их, если вы обучаете собственную модель.
Отправьте запрос gRPC в TensorFlow Serving
- Добавьте этот код после предыдущего фрагмента кода для отправки запроса gRPC в TensorFlow Serving:
// Send the gRPC request.
PredictResponse response = await _stub.predict(request);
Обработать ответ gRPC от TensorFlow Serving
- Добавьте этот код после предыдущего фрагмента кода, чтобы реализовать функции обратного вызова для обработки ответа:
// Process the response.
if (response.outputs.containsKey(outputTensorName)) {
if (response.outputs[outputTensorName]!.floatVal[1] >
classificationThreshold) {
return 'This sentence is spam. Spam score is ' +
response.outputs[outputTensorName]!.floatVal[1].toString();
} else {
return 'This sentence is not spam. Spam score is ' +
response.outputs[outputTensorName]!.floatVal[1].toString();
}
} else {
throw Exception('Error response');
}
Теперь код постобработки извлекает результат классификации из ответа и отображает его в пользовательском интерфейсе.
Запусти это
- Щелкните
Начните отладку и дождитесь загрузки приложения.
- Введите текст, а затем выберите gRPC > Классифицировать .
10. Поздравления
Вы использовали TensorFlow Serving для добавления возможностей классификации текста в свое приложение!
В следующей лабораторной работе вы улучшите модель, чтобы иметь возможность обнаруживать определенные спам-сообщения, которые не могут быть обнаружены текущим приложением.