Tworzenie aplikacji na iOS do prognozowania wartości

1. Zanim zaczniesz

Z tego ćwiczenia dowiesz się, jak uruchomić wnioskowanie regresji w aplikacji na iOS przy użyciu TensorFlow Serving with REST i gRPC.

Wymagania wstępne

  • Podstawowe informacje o programowaniu iOS w Swift
  • Podstawowa wiedza dotycząca systemów uczących się z TensorFlow, np. szkolenia i wdrażanie
  • Podstawowe informacje o Colaboratory
  • Podstawowa znajomość terminali, Pythona i Dockera

Czego się nauczysz

  • Jak wytrenować model regresji za pomocą TensorFlow.
  • Jak utworzyć prostą aplikację na iOS i tworzyć prognozy na podstawie wytrenowanego modelu przy użyciu TensorFlow Serving (REST i gRPC).
  • Sposób wyświetlania wyniku w interfejsie.

Czego potrzebujesz

2. Konfiguracja

Aby pobrać kod tych ćwiczeń z programowania:

  1. Przejdź do repozytorium GitHub dla tych ćwiczeń z programowania.
  2. Kliknij Kod > Pobierz plik ZIP, aby pobrać cały kod do tych ćwiczeń z programowania.

a72f2bb4caa9a96.png

  1. Rozpakuj pobrany plik ZIP, aby rozpakować folder główny aplikacji codelabs ze wszystkimi potrzebnymi zasobami.

Na potrzeby tego ćwiczenia z programu potrzebujesz tylko plików z podkatalogu TFServing/RegressioniOS 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.

3. Pobierz zależności dla projektu

Pobierz wymagane bloki reklamowe

  • W folderze starter/iOS uruchom polecenie:
pod install

Cocoapods zainstaluje wszystkie niezbędne biblioteki i wygeneruje nowy plik regression.xcworkspace.

4. Uruchom aplikację startową

  • Kliknij dwukrotnie plik regression.xcworkspace, aby otworzyć Xcode.

Uruchamianie i poznawanie aplikacji

  1. Zmień urządzenie docelowe na dowolnego iPhone'a, na przykład iPhone'a 13.

A57198a4f21f970.png

  1. Kliknij cacc15c5638260ed.png „Uruchom'”, a następnie zaczekaj na skompilowanie projektu przez Xcode i uruchomienie aplikacji startowej w symulatorze.

Interfejs jest bardzo prosty. Jest pole tekstowe, w którym możesz wpisać liczbę, która jest wysyłana do backendu TensorFlow Udostępniającego REST lub gRPC. Backend wykonuje regresję wartości wejściowej i zwraca przewidywaną wartość do aplikacji klienckiej, która ponownie wyświetla wynik w interfejsie.

d2976072474ce0b1.png

Jeśli wpiszesz liczbę i klikniesz Wnioskuj, nic się nie stanie, ponieważ aplikacja nie może jeszcze nawiązać komunikacji z backendem.

5. Wytrenuj prosty model regresji za pomocą TensorFlow

Regresja jest jednym z najczęstszych zadań ML. Jego celem jest przewidywanie pojedynczej ciągłej ilości na podstawie danych wejściowych. Na przykład na podstawie dzisiejszej pogody prognozowana jest najwyższa temperatura jutro.

Wytrenuj model regresji

  1. Otwórz ten link w przeglądarce.

Colab wczytuje notatki w języku Python.

  1. W notatniku Python zaimportuj biblioteki TensorFlow i NumPy, a następnie utwórz 6 par danych treningowych z danymi xs i ys jako etykietami.

Jeśli nanosisz te punkty na wykres, występują one w linii prostej, ponieważ są generowane na podstawie równania y = 2x –1.

56d05252cfc9df9d.png

  1. Użyj interfejsu API Keras, aby utworzyć prostą dwuwarstwową sieć neuronową, aby przewidzieć wartość y na podstawie danych wejściowych x. Następnie skompiluj i dopasuj model.
xs = np.array([-1.0,  0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
ys = np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)

model = tf.keras.Sequential([
   tf.keras.layers.Dense(units=10, input_shape=[1]),
   tf.keras.layers.Dense(units=1),
   ])

model.compile(optimizer='sgd',
             loss='mean_squared_error')

history = model.fit(xs, ys, epochs=500, verbose=0)

print("Finished training the model")

print(model.predict([10.0]))

Model trenuje się w ciągu kilku sekund. Widać, że przewidywana wartość danych wejściowych 10 to 18.999996, co jest całkiem niezłym wynikiem, ponieważ rzeczywistość jest: 2 * 10 -1 = 19.

  1. Wyeksportuj model:
model_dir = './regression/'
version = 123
export_path = os.path.join(model_dir, str(version))
model.save(export_path, save_format="tf")
print('\nexport_path = {}'.format(export_path))
!ls -l {export_path}
  1. Spakuj wyeksportowany plik SavedModel do jednego pliku regression.zip:
!zip -r regression.zip ./regression
  1. Kliknij Runtime > Run all (Uruchom wszystko) w menu nawigacyjnym, by uruchomić notatki, a następnie poczekaj na zakończenie uruchomienia.
  2. Kliknij C55600d42359f901.png Pliki, a następnie pobierz plik regression.zip.

bceda15d86571583.png

6. Wdróż model regresji za pomocą udostępniania TensorFlow

  • Aby wdrożyć model za pomocą Narzędzia TensorFlow, zdekompresuj pobrany plik regression.zip za pomocą narzędzia do dekompresji, takiego jak 7-Zip.

Struktura folderów powinna wyglądać tak:

7faeb4f03af39646.png

Folder regression można nazywać folderem SavedModel. 123 to przykładowy numer wersji. Jeśli chcesz, możesz wybrać inny numer.

Rozpocznij udostępnianie TensorFlow

  • W terminalu uruchom udostępnianie TensorFlow z Dockerem, zastępując zmienną PATH/TO/SAVEDMODEL ścieżką bezwzględną folderu regression na komputerze.
docker pull tensorflow/serving

docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/regression" -e MODEL_NAME=regression 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: regression 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. Łączenie aplikacji na iOS z TensorFlow Serving przez REST

Backend jest już gotowy, więc możesz wysyłać żądania klienta do usługi TensorFlow, aby tworzyć prognozy. Istnieją dwa sposoby wysyłania żądań do obsługi TensorFlow:

  • REST
  • gRPC

Wysyłaj żądania i odbieraj odpowiedzi za pomocą REST

Aby to zrobić:

  1. Utwórz żądanie REST.
  2. Wyślij żądanie REST do serwera TensorFlow Serving.
  3. Wyodrębnij przewidywany wynik z odpowiedzi REST i wyrenderuj interfejs użytkownika.

Te kroki możesz wykonać w pliku iOS/regression/ViewController.swift.

Utwórz żądanie REST

  1. Obecnie funkcja doInference() nie wysyła żądania REST do serwera TensorFlow. Aby utworzyć żądanie REST, musisz wdrożyć tę gałąź REST:
if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
    print("Using REST")
    // TODO: Add code to send a REST request to TensorFlow Serving.
    
}

Udostępnianie w TensorFlow oczekuje na żądanie POST zawierające jedną wartość, dlatego musisz umieścić wartość wejściową w formacie JSON, który jest ładunkiem żądania.

  1. Dodaj ten kod do gałęzi REST:
//Create the REST request.
let json: [String: Any] = ["signature_name" : "serving_default", "instances" : [[value]]]

let jsonData = try? JSONSerialization.data(withJSONObject: json)

let url = URL(string: "http://localhost:8501/v1/models/regression:predict")!
var request = URLRequest(url: url)
request.httpMethod = "POST"

// Insert JSON data into the request.
request.httpBody = jsonData

Wyślij żądanie REST do serwera TensorFlow

  • Dodaj ten kod bezpośrednio po kodzie w gałęzi REST:
// Send the REST request.
let task = URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data = data, error == nil else {
        print(error?.localizedDescription ?? "No data")
        return
    }
    
    // TODO: Add code to process the response.
}

task.resume()

Przetwórz odpowiedź REST z wyświetlania w TensorFlow

  • Dodaj ten kod do poprzedniego fragmentu kodu zaraz po komentarzu: TODO: Add code to process the response.:
// Process the REST response.
let results: RESTResults = try! JSONDecoder().decode(RESTResults.self, from: data)
DispatchQueue.main.async{
    self.txtOutput.text = String(results.predictions[0][0])
}

Teraz funkcja przetwarzania końcowego wyodrębnia przewidywane wartości z odpowiedzi i wyświetla wynik w interfejsie użytkownika.

Uruchom

  1. Kliknij cacc15c5638260ed.png Uruchom&#39, a następnie poczekaj, aż Xcode uruchomi aplikację w Symulatorze.
  2. Wpisz liczbę w polu tekstowym, a następnie kliknij Wnioskuj.

Teraz zobaczysz w interfejsie przewidywaną wartość.

df9bcb9aa21bb30e.png

8. Łączenie aplikacji na iOS z TensorFlow Serving przez gRPC

Oprócz REST, TensorFlow Serving obsługuje też gRPC.

B6F4449C2C850b0e.png

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

Wystarczą 4 proste kroki:

  1. Opcjonalnie: wygeneruj kod śledzenia klienta gRPC.
  2. Utwórz żądanie gRPC.
  3. Wyślij żądanie gRPC do wyświetlania przez TensorFlow.
  4. Wyodrębnij przewidywany wynik z odpowiedzi gRPC i wyrenderuj interfejs użytkownika.

Te kroki możesz wykonać w pliku iOS/regression/ViewController.swift.

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.

a9d0e5cb543467b4.png

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

Aby wygenerować kod wewnętrzny klienta gRPC:

  1. W terminalu przejdź do folderu starter/src/proto/ i wygeneruj fragment:
bash generate_grpc_stub_swift.sh

W folderze starter/src/proto/generated/import zostanie wygenerowanych kilka plików .swift.

  1. Jeśli nie zostały one jeszcze skopiowane do projektu, przeciągnij wszystkie wygenerowane pliki .swift do projektu w Xcode.

9e65705cf6be7aac.png

Utwórz żądanie gRPC

Podobnie jak w przypadku żądania REST, żądanie gRPC tworzy się w gałęzi gRPC.

if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
    
}
else {
    print("Using gRPC")
    // TODO: add code to send a gRPC request to TF Serving
    
}
  • Aby utworzyć żądanie gRPC, dodaj ten kod do gałęzi gRPC:
//Create the gRPC request.
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let channel = ClientConnection.insecure(group: group).connect(host: "localhost", port: 8500)
let stub = Tensorflow_Serving_PredictionServiceClient(channel: channel)

var modelSpec = Tensorflow_Serving_ModelSpec()
modelSpec.name = "regression"
modelSpec.signatureName = "serving_default"

// Prepare the input tensor.
var batchDim = Tensorflow_TensorShapeProto.Dim()
batchDim.size = 1
var inputDim = Tensorflow_TensorShapeProto.Dim()
inputDim.size = 1
var inputTensorShape = Tensorflow_TensorShapeProto()
inputTensorShape.dim = [batchDim, inputDim]
var inputTensor = Tensorflow_TensorProto()
inputTensor.dtype = Tensorflow_DataType.dtFloat
inputTensor.tensorShape = inputTensorShape
inputTensor.floatVal = [Float(value)]

var request = Tensorflow_Serving_PredictRequest()
request.modelSpec = modelSpec
request.inputs = ["dense_input" : inputTensor]

let callOptions = CallOptions(timeLimit: .timeout(.seconds(15)))

Wyślij żądanie gRPC do udostępniania w TensorFlow

  • Dodaj ten kod do gałęzi gRPC tuż za kodem w poprzednim fragmencie kodu:
// Send the gRPC request.
let call = stub.predict(request, callOptions: callOptions)

Przetwórz odpowiedź gRPC z udostępniania w TensorFlow

  • Dodaj ten kod bezpośrednio po kodzie w poprzednim fragmencie kodu:
// Process the response.
call.response.whenSuccess { response in
    let result = response.outputs["dense_1"]?.floatVal[0]
    DispatchQueue.main.async{
        self.txtOutput.text = String(describing: result!)
    }
}
call.response.whenFailure { error in
    print("Call failed with error\n\(error)")
}

Teraz funkcja przetwarzania końcowego wyodrębnia przewidywane wartości z odpowiedzi i wyświetla wynik w interfejsie użytkownika.

Uruchom

  1. Kliknij cacc15c5638260ed.png Uruchom&#39 w menu nawigacyjnym, a następnie poczekaj, aż Xcode uruchomi aplikację w Symulatorze.
  2. Wpisz liczbę w polu tekstowym, a następnie kliknij Wnioskuj.

Teraz zobaczysz w interfejsie przewidywaną wartość.

9. Gratulacje

Dzięki udostępnianiu danych TensorFlow dodano funkcje regresji do aplikacji.

Więcej informacji