Eine Flutter-App zum Klassifizieren von Text erstellen

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

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

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:

  1. Rufen Sie das GitHub-Repository für dieses Codelab auf.
  2. Klicken Sie auf Code gt; ZIP herunterladen, um den gesamten Code für dieses Codelab herunterzuladen.

2cd45599f51fb8a2.png

  1. 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

  1. 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.
  2. Wenn Sie ein Dialogfeld sehen, in dem Sie aufgefordert werden, die erforderlichen Pakete für die Starter-App herunterzuladen, klicken Sie auf Pakete abrufen.
  3. Wenn Sie dieses Dialogfeld nicht sehen, öffnen Sie das Terminal und führen Sie dann den Befehl flutter pub get im Ordner starter aus.

7ada07c300f166a6

5. Start-App ausführen

  1. 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:

9767649231898791

Das siehst du auf einem iPhone 13 mit dem iOS-Simulator:

95529e3a682268b2

  1. Klicken Sie auf a19a0c68bc4046e6 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.

b298f605d64dc132.png d3ef3ccd3c338108.png

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 Ordners mm_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.

  1. Fügen Sie in der Datei lib/main.dart diesen Code in die predict()-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]);
    }
  }
} 
  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:

  1. Erstellen Sie die REST-Anfrage.
  2. Senden Sie die REST-Anfrage an TensorFlow Serving.
  3. 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

  1. 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.

}
  1. 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

  1. Klicken Sie auf a19a0c68bc4046e6 Debugging starten und warten Sie, bis die App geladen wurde.
  2. Geben Sie Text ein und wählen Sie REST > Classify aus.

8e21d795af36d07a.png e79a0367a03c2169

9. Flutter-Anwendung mit TensorFlow über gRPC verbinden

Zusätzlich zur REST-Unterstützung unterstützt TensorFlow Serving auch BeyondCorp.

b6f4449c2c850b0e.png

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:

  1. Optional: Erstellen Sie den gRPC-Client-Stub-Code.
  2. Erstellen Sie die gRPC-Anfrage.
  3. Senden Sie die gRPC-Anfrage an TensorFlow Serving.
  4. 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.

a9d0e5cb543467b4.png

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

  1. Klicken Sie auf a19a0c68bc4046e6 Debugging starten und warten Sie, bis die App geladen wurde.
  2. Geben Sie Text ein und wählen Sie GRP > Classify aus.

e44e6e9a5bde2188 92644d723f61968c.png

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.

Weitere Informationen