1. Zanim zaczniesz
Z tego ćwiczenia dowiesz się, jak przeprowadzać klasyfikowanie tekstu za pomocą aplikacji Flutter za pomocą TensorFlow Serve poprzez REST i gRPC.
Wymagania wstępne
- Podstawowe informacje o rozwoju Fluttera w Dart
- Podstawowe informacje o systemach uczących się z TensorFlow, np. szkolenia czy wdrażanie
- Podstawowe informacje o terminalach i Dockerze
- Wytrenuj model wykrywania spamu w komentarzach dzięki ćwiczeniom z programowania TensorFlow Lite Kreator modeli
Czego się nauczysz
- Jak utworzyć prostą aplikację Flutter i sklasyfikować tekst za pomocą TensorFlow Serving (REST i gRPC).
- Jak wyświetlać wyniki w interfejsie.
Czego potrzebujesz
- Pakiet SDK Flutter
- Konfiguracja Flutter na Androida lub iOS
- Konfigurowanie kodu Visual Studio (VS Code) Flutter i Dart
- Docker
- Bash
- Kompilator bufora protokołu i wtyczka gRPC dla kompilatora protokołów (wymagane tylko w przypadku, gdy chcesz samodzielnie wygenerować kod wewnętrzny gRPC)
2. Skonfiguruj środowisko programistyczne Flutter
Do ukończenia tego modułu potrzebujesz oprogramowania Flutter, czyli pakietu Flutter SDK i edytora.
Ćwiczenia z programowania możesz uruchomić na dowolnym z tych urządzeń:
- Symulator iOS (wymaga zainstalowania narzędzi Xcode).
- Emulator Androida (wymaga konfiguracji w Android Studio).
- Przeglądarka (do przeprowadzenia debugowania wymagany jest Chrome).
- Jako aplikacja komputerowa Windows, Linux lub macOS. Programuj na platformie, na której zamierzasz wdrożyć aplikację. Jeśli więc chcesz utworzyć aplikację komputerową na Windows, musisz ją utworzyć, by mieć dostęp do odpowiedniej łańcucha kompilacji. Istnieją szczegółowe wymagania systemowe, które szczegółowo opisujemy na stronie docs.flutter.dev/desktop.
3. Konfiguracja
Aby pobrać kod tych ćwiczeń z programowania:
- Przejdź do repozytorium GitHub dla tych ćwiczeń z programowania.
- Kliknij Kod > Pobierz plik ZIP, aby pobrać cały kod do tych ćwiczeń z programowania.
- Rozpakuj pobrany plik ZIP, aby rozpakować folder główny aplikacji
codelabs-main
ze wszystkimi potrzebnymi zasobami.
Na potrzeby tego ćwiczenia z programu potrzebujesz tylko plików z podkatalogu tfserving-flutter/codelab2
repozytorium, które zawiera 2 foldery:
- Folder
starter
zawiera kod początkowy, który wykorzystasz w tym ćwiczeniu z programowania. - Folder
finished
zawiera pełny kod gotowej aplikacji.
4. Pobierz zależności dla projektu
- W pliku VS Code kliknij File > Open folder, a następnie wybierz folder
starter
z pobranego wcześniej kodu źródłowego. - Jeśli pojawi się okno z prośbą o pobranie pakietów wymaganych przez aplikację startową, kliknij Pobierz pakiety.
- Jeśli nie widzisz tego okna, otwórz terminal i uruchom polecenie
flutter pub get
w folderzestarter
.
5. Uruchom aplikację startową
- W VS Code sprawdź, czy emulator Androida lub Symulator iOS jest prawidłowo skonfigurowany i pojawia się na pasku stanu.
Oto przykład tego, co widzisz, gdy używasz Pixela 5 z Emulatorem Androida:
Oto, co możesz zobaczyć, gdy używasz iPhone'a z 13 z Symulatorem iOS:
- Kliknij Rozpocznij debugowanie.
Uruchamianie i poznawanie aplikacji
Aplikacja powinna pojawić się w emulatorze Androida lub symulatorze iOS. Interfejs jest bardzo prosty. Istnieje pole tekstowe, w którym użytkownik może wpisać tekst. Użytkownik może wybrać, czy dane mają być przesyłane do backendu z użyciem REST lub gRPC. Backend używa modelu TensorFlow, który wykonuje klasyfikację tekstu na wstępnie przetwarzanych danych wejściowych i zwraca wynik klasyfikacji do aplikacji klienckiej, co z kolei aktualizuje interfejs użytkownika.
Jeśli klikniesz Klasyfikuj, nic się nie stanie, ponieważ nie można jeszcze nawiązać komunikacji z backendem.
6. Wdrażanie modelu klasyfikacji tekstu za pomocą serwera w TensorFlow
Klasyfikacja tekstu to bardzo częste zadanie systemów uczących się, które klasyfikuje teksty do wstępnie zdefiniowanych kategorii. W tym ćwiczeniu z programowania wdrożysz model wytrenowany z poziomu Wytrenuj model wykrywania spamu w komentarzach za pomocą narzędzia TensorFlow Lite Kreator modeli z TensorFlow Serve i wywołaj backend z frontendu Flutter, aby sklasyfikować tekst wejściowy jako spam lub nie spam.
Rozpocznij udostępnianie TensorFlow
- W terminalu uruchom udostępnianie TensorFlow z Dockerem, zastępując zmienną
PATH/TO/SAVEDMODEL
ścieżką bezwzględną folderumm_spam_savedmodel
na komputerze.
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 automatycznie pobiera najpierw obraz związany z wyświetlaniem TensorFlow, co zajmuje minutę. Po tym czasie powinno rozpocząć się udostępnianie TensorFlow. Dziennik powinien wyglądać jak ten fragment kodu:
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. Tokenowe wprowadzanie zdań
Backend jest już gotowy, więc możesz już wysyłać żądania klientów do serwera TensorFlow, ale najpierw musisz tokenizować dane wejściowe. Sprawdzając tensor wejściowy modelu, widać, że oczekuje on listy 20 liczb całkowitych, a nie nieprzetworzonych ciągów znaków. Tokenizacja polega na przypisaniu pojedynczych słów w aplikacji do listy liczb całkowitych opartych na słowniku słownikowym przed ich wysłaniem do backendu do klasyfikacji. Jeśli na przykład wpiszesz buy book online to learn more
, tokenizacja zostanie zmapowana na [32, 79, 183, 10, 224, 631, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
. Konkretne liczby mogą się różnić w zależności od słownika.
- W pliku
lib/main.dart
dodaj ten kod do metodypredict()
, by utworzyć słownik słownikowy_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]);
}
}
}
- Od razu za poprzednim fragmentem kodu dodaj ten kod, aby zaimplementować tokenizację:
// 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;
}
}
Kod ten tworzy małym spadkiem ciąg znaków zdania, usuwa znaki inne niż alfanumeryczne i mapuje słowa na 20 indeksów liczb całkowitych na podstawie tabeli słownictwa.
8. Łączenie aplikacji Flutter z TensorFlow Serving przez REST
Istnieją dwa sposoby wysyłania żądań do obsługi TensorFlow:
- REST
- gRPC
Wysyłanie żądań i odbieranie odpowiedzi przez REST
Aby wysyłać żądania i otrzymywać odpowiedzi za pomocą REST, wykonaj 3 proste kroki:
- Utwórz żądanie REST.
- Wyślij żądanie REST do serwera TensorFlow Serving.
- Wyodrębnij przewidywany wynik z odpowiedzi REST i wyrenderuj interfejs użytkownika.
Wykonaj te czynności w pliku main.dart
.
Tworzenie i wysyłanie żądania REST do udostępniania w TensorFlow
- Obecnie funkcja
predict()
nie wysyła żądania REST do serwera TensorFlow. Aby utworzyć żądanie REST, musisz wdrożyć gałąź REST:
if (_connectionMode == ConnectionModeType.rest) {
// TODO: Create and send the REST request.
}
- Dodaj ten kod do gałęzi 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],
}),
);
Przetwórz odpowiedź REST z wyświetlania w TensorFlow
- Aby przetworzyć odpowiedź REST, dodaj ten kod tuż za poprzednim fragmentem kodu:
// 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');
}
Kod przetwarzający wyodrębnia prawdopodobieństwo, że zdanie wejściowe jest wiadomością ze spamem, i wyświetla wynik klasyfikacji w interfejsie użytkownika.
Uruchom
- Kliknij Rozpocznij debugowanie, a następnie zaczekaj na załadowanie aplikacji.
- Wpisz tekst i wybierz REST > Classify.
9. Połącz aplikację Flutter z TensorFlow Serving przez gRPC
Oprócz REST, TensorFlow Serving obsługuje też gRPC.
gRPC to nowoczesna platforma RPC o wysokiej wydajności, która może działać w dowolnym środowisku. Może skutecznie łączyć usługi w centrach danych i z innych, a także korzystać z wtyczek z obsługą równoważenia obciążenia, śledzenia, kontroli stanu i uwierzytelniania. Zaobserwowano, że gRPC jest w praktyce bardziej wydajny niż REST.
Wysyłanie żądań i odbieranie odpowiedzi za pomocą gRPC
Dostępne są 4 proste czynności do wysyłania żądań i odbierania odpowiedzi przy użyciu gRPC:
- Opcjonalnie: wygeneruj kod śledzenia klienta gRPC.
- Utwórz żądanie gRPC.
- Wyślij żądanie gRPC do wyświetlania przez TensorFlow.
- Wyodrębnij przewidywany wynik z odpowiedzi gRPC i wyrenderuj interfejs użytkownika.
Wykonaj te czynności w pliku main.dart
.
Opcjonalnie: wygeneruj kod wewnętrzny klienta gRPC
Aby używać gRPC z udostępnianiem za pomocą TensorFlow, musisz wykonać przepływ pracy gRPC. Więcej informacji znajdziesz w dokumentacji gRPC.
Pliki TensorFlow i TensorFlow definiują pliki .proto
. Od TensorFlow 2.8 i TensorFlow 2.8 potrzebne są te pliki .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
- W terminalu przejdź do folderu
starter/lib/proto/
i wygeneruj atrapę:
bash generate_grpc_stub_dart.sh
Utwórz żądanie gRPC
Podobnie jak w przypadku żądania REST, żądanie gRPC tworzy się w gałęzi gRPC.
if (_connectionMode == ConnectionModeType.rest) {
} else {
// TODO: Create and send the gRPC request.
}
- Dodaj ten kod, aby utworzyć żądanie 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});
Uwaga: nazwy tensorów wejściowych i wyjściowych mogą się różnić w zależności od modelu, nawet jeśli architektura modelu jest taka sama. Pamiętaj o aktualizowaniu ich, jeśli trenujesz własny model.
Wyślij żądanie gRPC do udostępniania w TensorFlow
- Dodaj ten kod po poprzednim fragmencie kodu, aby wysłać żądanie gRPC do wyświetlania w TensorFlow:
// Send the gRPC request.
PredictResponse response = await _stub.predict(request);
Przetwórz odpowiedź gRPC z udostępniania w TensorFlow
- Dodaj ten kod po poprzednim fragmencie kodu, aby zaimplementować funkcje wywołania zwrotnego w celu obsługi odpowiedzi:
// 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');
}
Teraz kod postprocessing wyodrębnia wynik klasyfikacji z odpowiedzi i wyświetla go w interfejsie użytkownika.
Uruchom
- Kliknij Rozpocznij debugowanie, a następnie zaczekaj na załadowanie aplikacji.
- Wpisz tekst i wybierz gRPC > Classify.
10. Gratulacje
Dzięki wykorzystaniu TensorFlow dodano klasyfikację tekstu do aplikacji.
W ramach kolejnego ćwiczenia z programowania ulepszysz model, by móc wykrywać określone wiadomości ze spamem, których nie może wykryć bieżąca aplikacja.