1. Hinweis
In diesem Codelab lernen Sie, wie Sie eine Inferenz aus Textklassifizierung aus einer Flutter-Anwendung mit TensorFlow Serving über REST und gRPC ausführen.
Vorbereitung
- Grundkenntnisse der Flutterentwicklung mit Dart
- Grundlegendes Wissen über maschinelles Lernen mit TensorFlow, z. B. für Training und Bereitstellung
- Grundkenntnisse zu Terminals und Docker
- Trainieren Sie ein Kommentar-Spamerkennungsmodell mit dem Codelab für TensorFlow Lite-Modellersteller
Lerninhalte
- Einfache Flutter-Anwendung erstellen und Texte über TensorFlow Serving (REST und gRPC) klassifizieren.
- So zeigen Sie die Ergebnisse in der Benutzeroberfläche an.
Voraussetzungen
- Flutter-SDK
- Einrichtung von Android oder iOS für Flutter
- Visual Studio Code (VS Code) einrichten für Flutter und Dart
- Docker
- Bash
- Protokollzwischenspeicher und gRPC Dart-Plug-in für den Protokollkompilierer (nur erforderlich, wenn Sie den gRPC-Stub selbst noch einmal generieren möchten)
2. Flutter-Entwicklungsumgebung einrichten
Für die Entwicklung von Flutter benötigen Sie für dieses Lab zwei Softwareprodukte: das Flutter SDK und einen Bearbeiter.
Sie können das Codelab auf folgenden Geräten ausführen:
- Der iOS-Simulator (Installation von Xcode-Tools erforderlich).
- Der Android-Emulator (Einrichtung in Android Studio erforderlich).
- Ein Browser (für die Fehlerbehebung ist Chrome erforderlich).
- Als Desktop-App für Windows, Linux oder macOS Sie müssen auf der Plattform entwickeln, auf der Sie die Bereitstellung planen möchten. Wenn Sie also eine Windows-Desktop-App entwickeln möchten, müssen Sie unter Windows auf die entsprechende Build-Kette zugreifen. Betriebssystemspezifische Anforderungen finden Sie unter docs.flutter.dev/desktop.
3. Einrichten
So laden Sie den Code für dieses Codelab herunter:
- Rufen Sie das GitHub-Repository für dieses Codelab auf.
- Klicken Sie auf Code gt; ZIP herunterladen, um den gesamten Code für dieses Codelab herunterzuladen.
- Entpacken Sie die heruntergeladene ZIP-Datei, um den Stammordner
codelabs-main
mit allen benötigten Ressourcen zu entpacken.
Für dieses Codelab benötigen Sie nur die Dateien im Unterverzeichnis tfserving-flutter/codelab2
des Repositorys mit zwei Ordnern:
- Der Ordner
starter
enthält den Startcode, den Sie für dieses Codelab erstellen. - Der Ordner
finished
enthält den abgeschlossenen Code für die fertige Beispiel-App.
4. Abhängigkeiten für das Projekt herunterladen
- Klicken Sie im VS Code auf File > Ordner öffnen und wählen Sie dann den Ordner
starter
aus dem Quellcode, den Sie zuvor heruntergeladen haben. - Wenn Sie ein Dialogfeld sehen, in dem Sie aufgefordert werden, die erforderlichen Pakete für die Starter-App herunterzuladen, klicken Sie auf Pakete abrufen.
- Wenn Sie dieses Dialogfeld nicht sehen, öffnen Sie das Terminal und führen Sie dann den Befehl
flutter pub get
im Ordnerstarter
aus.
5. Start-App ausführen
- Vergewissern Sie sich in VS Code, dass der Android-Emulator bzw. iOS-Simulator richtig eingerichtet ist und in der Statusleiste angezeigt wird.
Sie sehen zum Beispiel, was Sie sehen, wenn Sie Pixel 5 mit dem Android-Emulator verwenden:
Das siehst du auf einem iPhone 13 mit dem iOS-Simulator:
- Klicken Sie auf
Debugging starten.
App ausführen und entdecken
Die App sollte auf Ihrem Android-Emulator oder iOS-Simulator gestartet werden. Die Benutzeroberfläche ist ziemlich einfach. Es gibt ein Textfeld, in dem der Nutzer Text eingeben kann. Der Nutzer kann auswählen, ob er die Daten mit REST oder gRPC an das Back-End senden soll. Das Back-End verwendet ein TensorFlow-Modell, um Text in der vorverarbeiteten Eingabe zu klassifizieren. Anschließend wird das Klassifizierungsergebnis an die Client-App zurückgegeben, die wiederum die UI aktualisiert.
Wenn Sie auf Klassifizieren klicken, passiert nichts, da die Kommunikation mit dem Back-End noch nicht möglich ist.
6. Textklassifizierungsmodell mit TensorFlow Serving bereitstellen
Die Klassifizierung von Texten ist eine sehr häufige Aufgabe für maschinelles Lernen. Dabei werden Texte in vordefinierte Kategorien unterteilt. In diesem Codelab stellen Sie das vortrainierte Modell aus dem Train-Kommentarerkennungsmodell mit TensorFlow Lite Model Maker mit TensorFlow Serving bereit und rufen das Back-End von Ihrem Flutter-Front-End auf, um den Eingabetext als Spam oder Kein Spam zu klassifizieren.
TensorFlow-Bereitstellung starten
- Starten Sie in Ihrem Terminal TensorFlow Serving mit Docker, aber ersetzen Sie den Platzhalter
PATH/TO/SAVEDMODEL
durch den absoluten Pfad des Ordnersmm_spam_savedmodel
auf Ihrem Computer.
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 lädt automatisch das TensorFlow Serving-Image herunter. Das dauert eine Minute. Danach sollte die TensorFlow-Bereitstellung beginnen. Das Protokoll sollte so aussehen:
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. Eingabesatz in Tokens umwandeln
Das Back-End ist jetzt einsatzbereit, sodass Sie Clientanfragen fast an TensorFlow Serving senden können. Zuerst müssen Sie jedoch den Eingabesatz in Tokens umwandeln. Wenn Sie den Eingabetensor des Modells prüfen, sehen Sie, dass eine Liste von 20 Ganzzahlzahlen anstelle von Rohstrings erwartet wird. Bei der Tokenisierung werden die einzelnen Wörter, die Sie in der App eingeben, einer Liste von Ganzzahlen basierend auf einem Wörterbuch zugeordnet, bevor Sie sie zur Klassifizierung an das Back-End senden. Wenn Sie beispielsweise buy book online to learn more
eingeben, wird dieser über den Tokenisierungsprozess [32, 79, 183, 10, 224, 631, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
zugeordnet. Die genauen Zahlen können je nach Wörterbuch variieren.
- Fügen Sie in der Datei
lib/main.dart
diesen Code in diepredict()
-Methode ein, um das Vokabularwörterbuch_vocabMap
zu erstellen.
// 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]);
}
}
}
- Fügen Sie unmittelbar nach dem vorherigen Code-Snippet den folgenden Code hinzu, um die Tokenisierung zu implementieren:
// 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;
}
}
Dieser Code in Kleinbuchstaben enthält den Satzstring, entfernt Zeichen, die nicht das Alphabet sind, und ordnet die Wörter basierend auf der Vokabulartabelle 20 Ganzzahlindexen zu.
8. Flutter-App mit TensorFlow über REST verbinden
Es gibt zwei Möglichkeiten, Anfragen an die TensorFlow-Bereitstellung zu senden:
- REST
- gRPC
Anfragen senden und Antworten über REST erhalten
Drei einfache Schritte zum Senden von Anfragen und zum Empfangen von Antworten über REST:
- Erstellen Sie die REST-Anfrage.
- Senden Sie die REST-Anfrage an TensorFlow Serving.
- Extrahieren Sie das vorhergesagte Ergebnis aus der REST-Antwort und rendern Sie die UI.
Sie führen die Schritte in der Datei main.dart
aus.
REST-Anfrage erstellen und an TensorFlow Serving senden
- Aktuell sendet die Funktion
predict()
die REST-Anfrage nicht an TensorFlow Serving. Sie müssen den REST-Branch implementieren, um eine REST-Anfrage zu erstellen:
if (_connectionMode == ConnectionModeType.rest) {
// TODO: Create and send the REST request.
}
- Fügen Sie diesen Code dem REST-Branch hinzu:
//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-Antwort von TensorFlow Serving verarbeiten
- Fügen Sie diesen Code direkt nach dem vorherigen Code-Snippet ein, um die REST-Antwort zu verarbeiten:
// 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');
}
Der Nachbearbeitungscode extrahiert die Wahrscheinlichkeit, dass der eingegebene Satz eine Spamnachricht aus der Antwort ist, und zeigt das Klassifizierungsergebnis in der Benutzeroberfläche an.
Ausführen
- Klicken Sie auf
Debugging starten und warten Sie, bis die App geladen wurde.
- Geben Sie Text ein und wählen Sie REST > Classify aus.
9. Flutter-Anwendung mit TensorFlow über gRPC verbinden
Zusätzlich zur REST-Unterstützung unterstützt TensorFlow Serving auch BeyondCorp.
gRPC ist ein modernes, leistungsstarkes Open-Source-RPC-Framework (Remote Procedure Call), das in jeder Umgebung ausgeführt werden kann. Dank der flexiblen Unterstützung für Load-Balancing, Tracing, Systemdiagnose und Authentifizierung lassen sich Dienste effizient in und zwischen Rechenzentren verbinden. Es wurde festgestellt, dass gRPC in der Praxis leistungsstärker ist als REST.
Anfragen mit gRPC senden und Antworten erhalten
Das Senden von Anfragen und das Empfangen von Antworten mit gRPC erfolgt in vier einfachen Schritten:
- Optional: Erstellen Sie den gRPC-Client-Stub-Code.
- Erstellen Sie die gRPC-Anfrage.
- Senden Sie die gRPC-Anfrage an TensorFlow Serving.
- Extrahieren Sie das vorhergesagte Ergebnis aus der gRPC-Antwort und rendern Sie die UI.
Sie führen die Schritte in der Datei main.dart
aus.
Optional: gRPC-Client-Stub-Code generieren
Wenn Sie gRPC mit TensorFlow Serving verwenden möchten, müssen Sie dem gRPC-Workflow folgen. Weitere Informationen finden Sie in der BeyondCorp-Dokumentation.
Die Bereitstellung von .proto
-Dateien wird durch TensorFlow Serving und TensorFlow definiert. Ab TensorFlow und TensorFlow Serving 2.8 sind diese .proto
-Dateien erforderlich:
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
- Gehen Sie in Ihrem Terminal zum Ordner
starter/lib/proto/
und generieren Sie die Stubs:
bash generate_grpc_stub_dart.sh
gRPC-Anfrage erstellen
Ähnlich wie bei der REST-Anfrage erstellen Sie die gRPC-Anfrage im gRPC-Branch.
if (_connectionMode == ConnectionModeType.rest) {
} else {
// TODO: Create and send the gRPC request.
}
- Fügen Sie diesen Code hinzu, um die gRPC-Anfrage zu erstellen:
//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});
Hinweis: Die Namen von Eingabe- und Ausgabetensoren können sich von Modell zu Modell unterscheiden, auch wenn die Modellarchitekturen identisch sind. Aktualisieren Sie sie, wenn Sie Ihr eigenes Modell trainieren.
gRPC-Anfrage an TensorFlow Serving senden
- Fügen Sie diesen Code nach dem vorherigen Code-Snippet ein, um die gRPC-Anfrage an die TensorFlow-Bereitstellung zu senden:
// Send the gRPC request.
PredictResponse response = await _stub.predict(request);
gRPC-Antwort von TensorFlow Serving verarbeiten
- Füge diesen Code nach dem vorherigen Code-Snippet ein, um die Callback-Funktionen zur Verarbeitung der Antwort zu implementieren:
// 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');
}
Der Nachbearbeitungscode extrahiert jetzt das Klassifizierungsergebnis aus der Antwort und zeigt sie in der Benutzeroberfläche an.
Ausführen
- Klicken Sie auf
Debugging starten und warten Sie, bis die App geladen wurde.
- Geben Sie Text ein und wählen Sie GRP > Classify aus.
10. Glückwunsch
Sie haben mit TensorFlow Serving Ihrer App Textklassifizierungsfunktionen hinzugefügt.
Im nächsten Codelab werden Sie das Modell so optimieren, dass Sie bestimmte Spamnachrichten erkennen können, die von der aktuellen App nicht erkannt werden.