Budowanie standardowego serwera TensorFlow ModelServer

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Ten samouczek pokazuje, jak używać komponentów TensorFlow Serving do budowania standardowego serwera TensorFlow ModelServer, który dynamicznie wykrywa i obsługuje nowe wersje wytrenowanego modelu TensorFlow. Jeśli chcesz po prostu użyć standardowego serwera służyć modeli, patrz TensorFlow Serving podstawowy samouczek .

W tym samouczku zastosowano prosty model regresji Softmax wprowadzony w samouczku TensorFlow do klasyfikacji obrazów odręcznych (dane MNIST). Jeśli nie wiesz, co TensorFlow lub MNIST jest zobaczyć MNIST ML początkujących tutoriala.

Kod tego samouczka składa się z dwóch części:

  • Pythona plik mnist_saved_model.py że pociągi i eksportu różne wersje tego modelu.

  • C ++ plik main.cc który jest standardem TensorFlow ModelServer który odkrywa nowe modele eksportowane i prowadzi gRPC usługi dla służenia im.

W tym samouczku opisano następujące zadania:

  1. Trenuj i eksportuj model TensorFlow.
  2. Zarządzanie modelu o wersjach z TensorFlow Serving ServerCore .
  3. Konfiguracja za pomocą dozownika SavedModelBundleSourceAdapterConfig .
  4. Podawać prośbę wraz TensorFlow Serving ServerCore .
  5. Uruchom i przetestuj usługę.

Przed rozpoczęciem pracy najpierw zainstalować Döcker

Trenuj i eksportuj model TensorFlow

Po pierwsze, jeśli jeszcze tego nie zrobiłeś, sklonuj to repozytorium na swoją maszynę lokalną:

git clone https://github.com/tensorflow/serving.git
cd serving

Wyczyść katalog eksportu, jeśli już istnieje:

rm -rf /tmp/models

Trenuj (ze 100 iteracjami) i eksportuj pierwszą wersję modelu:

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  --training_iteration=100 --model_version=1 /tmp/mnist

Trenuj (z 2000 iteracjami) i eksportuj drugą wersję modelu:

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  --training_iteration=2000 --model_version=2 /tmp/mnist

Jak widać w mnist_saved_model.py , szkolenie i eksportowanie odbywa się w ten sam sposób, że jest w TensorFlow Serving podstawowy samouczek . W celach demonstracyjnych celowo zmniejszasz iteracje uczące dla pierwszego przebiegu i eksportujesz go jako v1, podczas gdy trenujesz go normalnie dla drugiego przebiegu i eksportujesz jako v2 do tego samego katalogu nadrzędnego – jak oczekujemy, że osiągnie ten drugi lepsza dokładność klasyfikacji dzięki intensywniejszym treningom. Powinieneś zobaczyć trening danych dla każdego cyklu szkoleniowym w swojej /tmp/mnist katalogu:

$ ls /tmp/mnist
1  2

Rdzeń serwera

Teraz wyobraź sobie, że v1 i v2 modelu są generowane dynamicznie w czasie wykonywania, gdy eksperymentuje się z nowymi algorytmami lub gdy model jest szkolony przy użyciu nowego zestawu danych. W środowisku produkcyjnym możesz chcieć zbudować serwer, który będzie obsługiwał stopniowe wdrażanie, w którym v2 będzie można wykrywać, ładować, eksperymentować, monitorować lub cofać podczas obsługi v1. Alternatywnie możesz chcieć zburzyć v1 przed uruchomieniem v2. TensorFlow Serving obsługuje obie opcje — podczas gdy jedna jest dobra do utrzymania dostępności podczas przejścia, druga jest dobra do minimalizowania zużycia zasobów (np. pamięci RAM).

TensorFlow Serving Manager robi dokładnie to. Obsługuje pełny cykl życia modeli TensorFlow, w tym ładowanie, udostępnianie i rozładowywanie ich, a także przejścia wersji. W tym samouczku będzie budować swój serwer na szczycie TensorFlow Serving ServerCore , która wewnętrznie owija się AspiredVersionsManager .

int main(int argc, char** argv) {
  ...

  ServerCore::Options options;
  options.model_server_config = model_server_config;
  options.servable_state_monitor_creator = &CreateServableStateMonitor;
  options.custom_model_config_loader = &LoadCustomModelConfig;

  ::google::protobuf::Any source_adapter_config;
  SavedModelBundleSourceAdapterConfig
      saved_model_bundle_source_adapter_config;
  source_adapter_config.PackFrom(saved_model_bundle_source_adapter_config);
  (*(*options.platform_config_map.mutable_platform_configs())
      [kTensorFlowModelPlatform].mutable_source_adapter_config()) =
      source_adapter_config;

  std::unique_ptr<ServerCore> core;
  TF_CHECK_OK(ServerCore::Create(options, &core));
  RunServer(port, std::move(core));

  return 0;
}

ServerCore::Create() zajmuje ServerCore :: parametru opcje. Oto kilka często używanych opcji:

  • ModelServerConfig że modele Określa być załadowany. Modele są zgłaszane zarówno przez model_config_list , który deklaruje statyczną listę modeli, lub poprzez custom_model_config , która definiuje niestandardowy sposób deklarowania listę modeli, które mogą uzyskać zaktualizowane przy starcie.
  • PlatformConfigMap który mapuje z nazwy platformy (takie jak tensorflow ) do PlatformConfig , który jest używany do tworzenia SourceAdapter . SourceAdapter dostosowuje StoragePath (ścieżka gdzie wersja modelu zostanie wykryty) do modelowania Loader (ładunki wersję modelu z ścieżki przechowywania i zapewnia interfejsy zmiana stanu do Manager ). Jeśli PlatformConfig zawiera SavedModelBundleSourceAdapterConfig , A SavedModelBundleSourceAdapter zostanie utworzony, które omówimy później.

SavedModelBundle jest kluczowym składnikiem TensorFlow podaniem. Reprezentuje model TensorFlow załadowany z danej ścieżki i zapewnia ten sam Session::Run interfejs jako TensorFlow Aby uruchomić wnioskowania. SavedModelBundleSourceAdapter dostosowuje ścieżkę do przechowywania Loader<SavedModelBundle> więc ten model życia może być zarządzany przez Manager . Należy pamiętać, że SavedModelBundle jest następcą nieaktualnych SessionBundle . Użytkownicy są zachęcani do korzystania SavedModelBundle jako wsparcie dla SessionBundle zostaną wkrótce usunięte.

Z tych wszystkich, ServerCore wewnętrznie wykonuje następujące czynności:

  • Instancję FileSystemStoragePathSource że ścieżki eksport monitory modelu zadeklarowane w model_config_list .
  • Instancję SourceAdapter pomocą PlatformConfigMap z platformą modelu zadeklarowane w model_config_list i łączy FileSystemStoragePathSource do niego. W ten sposób, gdy nowa wersja modelu jest odkryta w ścieżce eksportowej, SavedModelBundleSourceAdapter dostosowuje go do Loader<SavedModelBundle> .
  • Instancję realizacji określonego w Manager nazywa AspiredVersionsManager który zarządza wszystkich takich Loader instancje stworzone przez SavedModelBundleSourceAdapter . ServerCore eksportuje Manager interfejsu poprzez przekazanie połączenia do AspiredVersionsManager .

Ilekroć nowa wersja jest dostępna, to AspiredVersionsManager ładuje nową wersję, a pod jego domyślne zachowanie rozładowuje starego. Jeśli chcesz rozpocząć dostosowywanie, zachęcamy do zrozumienia komponentów, które tworzy wewnętrznie i jak je konfigurować.

Warto wspomnieć, że TensorFlow Serving został zaprojektowany od podstaw tak, aby był bardzo elastyczny i rozszerzalny. Można budować różne wtyczki do zachowania systemu Dostosuj, a jednocześnie skorzystać z ogólnych kluczowych komponentów takich jak ServerCore i AspiredVersionsManager . Na przykład możesz zbudować wtyczkę źródła danych, która monitoruje przechowywanie w chmurze zamiast pamięci lokalnej, lub możesz zbudować wtyczkę polityki wersji, która dokonuje zmiany wersji w inny sposób – w rzeczywistości możesz nawet zbudować niestandardowy model wtyczki, który obsługuje modele inne niż TensorFlow. Te tematy są poza zakresem tego samouczka. Można jednak odnieść się do źródła niestandardowych i niestandardowych servable tutoriali aby uzyskać więcej informacji.

Dozowanie

Inną typową funkcją serwera, której chcemy w środowisku produkcyjnym, jest przetwarzanie wsadowe. Nowoczesne akceleratory sprzętowe (GPU itp.) używane do wnioskowania uczenia maszynowego zwykle osiągają najlepszą wydajność obliczeń, gdy żądania wnioskowania są uruchamiane w dużych partiach.

Dozownika można włączyć poprzez zapewnienie właściwego SessionBundleConfig podczas tworzenia SavedModelBundleSourceAdapter . W tym przypadku możemy ustawić BatchingParameters z prawie wartości domyślnych. Grupowanie można dostroić, ustawiając niestandardowe wartości limitu czasu, rozmiaru partii itp. Aby uzyskać szczegółowe informacje, zapoznaj się z BatchingParameters .

SessionBundleConfig session_bundle_config;
// Batching config
if (enable_batching) {
  BatchingParameters* batching_parameters =
      session_bundle_config.mutable_batching_parameters();
  batching_parameters->mutable_thread_pool_name()->set_value(
      "model_server_batch_threads");
}
*saved_model_bundle_source_adapter_config.mutable_legacy_config() =
    session_bundle_config;

Po osiągnięciu pełnego wsadu wnioski wnioskowania są połączone wewnętrznie w jednym dużym życzenie (tensor) oraz tensorflow::Session::Run() jest wywoływana (czyli tam, gdzie rzeczywisty przyrost wydajności na GPU pochodzi).

Służ z menedżerem

Jak wspomniano powyżej, TensorFlow Serving Manager ma być rodzajowy składnik, który może obsłużyć załadunek, służąc, rozładunku i wersji przejście modeli wygenerowanych przez dowolnych systemów uczenia maszynowego. Jego interfejsy API są zbudowane wokół następujących kluczowych pojęć:

  • Servable: Servable jakakolwiek nieprzezroczysty obiekt, który może być używany do obsługi żądań klientów. Rozmiar i ziarnistość serwowalnego jest elastyczne, tak że pojedynczy serwowalny może zawierać wszystko, od pojedynczego fragmentu tabeli przeglądowej, przez pojedynczy model uczony maszynowo, po krotkę modeli. Serwer może mieć dowolny typ i interfejs.

  • Servable wersja: Servables są wersjami i TensorFlow Serving Manager może zarządzać jeden lub więcej wersje servable. Wersjonowanie pozwala na jednoczesne ładowanie więcej niż jednej wersji serwera, obsługując stopniowe wdrażanie i eksperymentowanie.

  • Servable Stream: a servable strumień jest sekwencją wersjami servable, wraz ze wzrostem liczby wersji.

  • Model: Model maszynowego dowiedział reprezentowany jest przez jeden lub więcej servables. Przykładami obiektów serwowalnych są:

    • TensorFlow sesja lub obwolut wokół nich, takie jak SavedModelBundle .
    • Inne rodzaje modeli uczących się maszynowo.
    • Tabele wyszukiwania słownictwa.
    • Osadzanie tabel przeglądowych.

    Model złożony może być reprezentowany jako wiele niezależnych serwowalnych lub jako jeden złożony serwowalny. Servable może również odpowiadać ułamek modelu, na przykład o dużej tablicy przeglądowej sharded w wielu Manager przypadkach.

Aby umieścić to wszystko w kontekście tego samouczka:

  • Modele TensorFlow są reprezentowane przez jednego rodzaju servable - SavedModelBundle . SavedModelBundle składa się wewnętrznie z tensorflow:Session w połączeniu z pewnym metadanych o co wykres jest załadowany do sesji i jak go uruchomić dla wnioskowania.

  • Istnieje katalog systemu plików zawierający strumień eksportów TensorFlow, każdy w swoim własnym podkatalogu, którego nazwa jest numerem wersji. Katalog zewnętrzny można traktować jako serializowaną reprezentację serwowalnego strumienia dla obsługiwanego modelu TensorFlow. Każdy eksport odpowiada serwisowi, który można załadować.

  • AspiredVersionsManager monitoruje strumień eksportowej oraz zarządza cyklem życia wszystkich SavedModelBundle servables dynamicznie.

TensorflowPredictImpl::Predict potem po prostu:

  • Żąda SavedModelBundle od kierownika (poprzez ServerCore).
  • Korzysta z generic signatures do mapowania nazw logicznych tensora w PredictRequest do prawdziwych nazwisk tensorowych i wartości powiązań do tensorów.
  • Uruchamia wnioskowanie.

Przetestuj i uruchom serwer

Skopiuj pierwszą wersję eksportu do monitorowanego folderu:

mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored

Następnie uruchom serwer:

docker run -p 8500:8500 \
  --mount type=bind,source=/tmp/monitored,target=/models/mnist \
  -t --entrypoint=tensorflow_model_server tensorflow/serving --enable_batching \
  --port=8500 --model_name=mnist --model_base_path=/models/mnist &

Serwer będzie co sekundę wysyłał komunikaty dziennika z informacją „Aspiring version for servable…”, co oznacza, że ​​znalazł eksport i śledzi jego dalsze istnienie.

Uciekajmy klientowi --concurrency=10 . Spowoduje to wysłanie równoczesnych żądań do serwera, a tym samym wyzwoli logikę przetwarzania wsadowego.

tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500 --concurrency=10

Co daje wynik, który wygląda następująco:

...
Inference error rate: 13.1%

Następnie kopiujemy drugą wersję eksportu do monitorowanego folderu i ponownie uruchamiamy test:

cp -r /tmp/mnist/2 /tmp/monitored
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500 --concurrency=10

Co daje wynik, który wygląda następująco:

...
Inference error rate: 9.5%

Potwierdza to, że Twój serwer automatycznie wykrywa nową wersję i używa jej do obsługi!