W tym samouczku pokazano, jak używać składników TensorFlow Serving do kompilowania standardowego TensorFlow ModelServer, który dynamicznie odnajduje i udostępnia nowe wersje przeszkolonego modelu TensorFlow. Jeśli chcesz używać standardowego serwera do obsługi swoich modeli, zobacz podstawowy samouczek dotyczący obsługi TensorFlow .
W tym samouczku zastosowano prosty model regresji Softmax wprowadzony w samouczku TensorFlow do klasyfikacji obrazów pisanych odręcznie (dane MNIST). Jeśli nie wiesz, czym jest TensorFlow lub MNIST, zapoznaj się z samouczkiem MNIST dla początkujących ML .
Kod tego samouczka składa się z dwóch części:
Plik Pythona mnist_saved_model.py , który szkoli i eksportuje wiele wersji modelu.
Plik C++ main.cc będący standardowym serwerem TensorFlow ModelServer, który wykrywa nowe wyeksportowane modele i uruchamia usługę gRPC w celu ich obsługi.
W tym samouczku opisano następujące zadania:
- Trenuj i eksportuj model TensorFlow.
- Zarządzaj wersjonowaniem modelu za pomocą TensorFlow Serving
ServerCore
. - Skonfiguruj przetwarzanie wsadowe przy użyciu
SavedModelBundleSourceAdapterConfig
. - Obsługuj żądanie za pomocą TensorFlow obsługującego
ServerCore
. - Uruchom i przetestuj usługę.
Zanim zaczniesz, najpierw zainstaluj Docker
Trenuj i eksportuj model TensorFlow
Po pierwsze, jeśli jeszcze tego nie zrobiłeś, sklonuj to repozytorium na swój komputer lokalny:
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
, trenowanie i eksportowanie odbywa się w taki sam sposób, jak w podstawowym samouczku dotyczącym obsługi TensorFlow . W celach demonstracyjnych celowo wybierasz iteracje szkoleniowe dla pierwszego uruchomienia i eksportujesz je jako v1, podczas gdy trenujesz normalnie w drugim uruchomieniu i eksportujesz je jako v2 do tego samego katalogu nadrzędnego - tak jak oczekujemy, że ten ostatni osiągnie lepsza dokładność klasyfikacji dzięki intensywniejszemu szkoleniu. Powinieneś zobaczyć dane treningowe dla każdego przebiegu treningowego w katalogu /tmp/mnist
:
$ ls /tmp/mnist
1 2
Rdzeń Serwera
Teraz wyobraź sobie, że wersje 1 i 2 modelu są generowane dynamicznie w czasie wykonywania, gdy eksperymentowane są nowe algorytmy lub gdy model jest szkolony przy użyciu nowego zestawu danych. W środowisku produkcyjnym możesz chcieć zbudować serwer obsługujący stopniowe wdrażanie, w którym można wykrywać, ładować, eksperymentować, monitorować lub przywracać wersję 2 podczas udostępniania wersji 1. Alternatywnie możesz chcieć usunąć wersję 1 przed przywołaniem wersji 2. TensorFlow Serving obsługuje obie opcje — jedna jest dobra do utrzymywania dostępności podczas przejścia, druga jest dobra do minimalizowania zużycia zasobów (np. pamięci RAM).
Dokładnie to robi TensorFlow Serving Manager
. Obsługuje pełny cykl życia modeli TensorFlow, w tym ich ładowanie, udostępnianie i rozładowywanie, a także przejścia wersji. W tym samouczku zbudujesz swój serwer na bazie TensorFlow Serving ServerCore
, który wewnętrznie otacza 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()
przyjmuje parametr ServerCore::Options. Oto kilka często używanych opcji:
-
ModelServerConfig
, który określa modele do załadowania. Modele są deklarowane albo poprzezmodel_config_list
, który deklaruje statyczną listę modeli, albo poprzezcustom_model_config
, który definiuje niestandardowy sposób deklarowania listy modeli, które mogą zostać zaktualizowane w czasie wykonywania. -
PlatformConfigMap
, która odwzorowuje nazwę platformy (taką jaktensorflow
) naPlatformConfig
, która służy do tworzeniaSourceAdapter
.SourceAdapter
dostosowujeStoragePath
(ścieżkę, w której wykryta jest wersja modelu) doLoader
model (ładowuje wersję modelu ze ścieżki magazynu i udostępnia interfejsy przejścia stanu doManager
). JeśliPlatformConfig
zawieraSavedModelBundleSourceAdapterConfig
, zostanie utworzonySavedModelBundleSourceAdapter
, co wyjaśnimy później.
SavedModelBundle
to kluczowy element udostępniania TensorFlow. Reprezentuje model TensorFlow załadowany z danej ścieżki i zapewnia ten sam interfejs Session::Run
co TensorFlow do uruchamiania wnioskowania. SavedModelBundleSourceAdapter
dostosowuje ścieżkę przechowywania do Loader<SavedModelBundle>
dzięki czemu okres życia modelu może być zarządzany przez Manager
. Należy pamiętać, że SavedModelBundle
jest następcą przestarzałego SessionBundle
. Zachęcamy użytkowników do korzystania z SavedModelBundle
, ponieważ obsługa SessionBundle
zostanie wkrótce usunięta.
Mając to wszystko na uwadze, ServerCore
wewnętrznie wykonuje następujące czynności:
- Tworzy instancję
FileSystemStoragePathSource
, która monitoruje ścieżki eksportu modelu zadeklarowane wmodel_config_list
. - Tworzy instancję
SourceAdapter
przy użyciuPlatformConfigMap
z platformą modelową zadeklarowaną wmodel_config_list
i łączy z niąFileSystemStoragePathSource
. W ten sposób za każdym razem, gdy w ścieżce eksportu zostanie wykryta nowa wersja modelu,SavedModelBundleSourceAdapter
dostosowuje ją doLoader<SavedModelBundle>
. - Tworzy instancję określonej implementacji
Manager
o nazwieAspiredVersionsManager
, która zarządza wszystkimi takimi instancjamiLoader
utworzonymi przezSavedModelBundleSourceAdapter
.ServerCore
eksportuje interfejsManager
, delegując wywołania doAspiredVersionsManager
.
Ilekroć dostępna jest nowa wersja, ten AspiredVersionsManager
ładuje nową wersję i zgodnie z domyślnym zachowaniem usuwa starą. Jeśli chcesz rozpocząć dostosowywanie, zachęcamy do zrozumienia komponentów tworzonych wewnętrznie i sposobu ich konfiguracji.
Warto wspomnieć, że TensorFlow Serving został zaprojektowany od podstaw tak, aby był bardzo elastyczny i rozszerzalny. Możesz tworzyć różne wtyczki, aby dostosować zachowanie systemu, korzystając jednocześnie z ogólnych podstawowych komponentów, takich jak ServerCore
i AspiredVersionsManager
. Można na przykład zbudować wtyczkę źródła danych, która monitoruje pamięć w chmurze zamiast pamięci lokalnej, lub można zbudować wtyczkę zasad wersji, która przeprowadza zmianę wersji w inny sposób — można nawet zbudować niestandardową wtyczkę modelu, która obsługuje modele inne niż TensorFlow. Te tematy wykraczają poza zakres tego samouczka. Więcej informacji można jednak znaleźć w niestandardowych źródłach i niestandardowych samouczkach, które można udostępnić.
Dozowanie
Inną typową funkcją serwera, której potrzebujemy w środowisku produkcyjnym, jest przetwarzanie wsadowe. Nowoczesne akceleratory sprzętowe (procesory graficzne itp.) używane do wnioskowania w ramach uczenia maszynowego zwykle osiągają najlepszą wydajność obliczeniową, gdy żądania wnioskowania są uruchamiane w dużych partiach.
Przetwarzanie wsadowe można włączyć, podając odpowiednią SessionBundleConfig
podczas tworzenia SavedModelBundleSourceAdapter
. W tym przypadku ustawiliśmy BatchingParameters
na prawie wartości domyślne. Dzielenie wsadowe można dostosować, ustawiając niestandardowe wartości limitu czasu, rozmiaru_wsadu itp. Aby uzyskać szczegółowe informacje, zobacz 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łnej partii żądania wnioskowania są wewnętrznie łączone w jedno duże żądanie (tensor) i wywoływany jest tensorflow::Session::Run()
(stąd pochodzi rzeczywisty wzrost wydajności procesorów graficznych).
Podawaj z menadżerem
Jak wspomniano powyżej, TensorFlow Serving Manager
został zaprojektowany jako ogólny komponent, który może obsługiwać ładowanie, udostępnianie, rozładowywanie i przenoszenie wersji modeli generowanych przez dowolne systemy uczenia maszynowego. Jego interfejsy API są zbudowane wokół następujących kluczowych koncepcji:
Servable : Servable to dowolny nieprzezroczysty obiekt, którego można użyć do obsługi żądań klientów. Rozmiar i szczegółowość serwowalnego obiektu jest elastyczny, tak że pojedynczy serwable może zawierać wszystko, od pojedynczego fragmentu tabeli przeglądowej, przez pojedynczy model uczony maszynowo, aż po krotkę modeli. Obiekt serwowalny może być dowolnego typu i interfejsu.
Wersja obsługiwana : Elementy serwowalne są wersjonowane, a
Manager
obsługi TensorFlow może zarządzać jedną lub większą liczbą wersji serwowalnych. Wersjonowanie umożliwia jednoczesne ładowanie więcej niż jednej wersji obiektu serwowalnego, co ułatwia stopniowe wdrażanie i eksperymentowanie.Strumień możliwy do serwowania : Strumień możliwy do serwowania to sekwencja wersji strumienia udostępnianego, z rosnącymi numerami wersji.
Model : model uczony maszynowo jest reprezentowany przez jeden lub więcej obiektów serwable. Przykładowe serwable to:
- Sesja TensorFlow lub opakowania 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 obiektów serwable lub jako pojedynczy obiekt złożony. Element serwowalny może również odpowiadać części Modelu, na przykład z dużą tabelą przeglądową podzieloną na wiele instancji
Manager
.- Sesja TensorFlow lub opakowania wokół nich, takie jak
Aby umieścić to wszystko w kontekście tego samouczka:
Modele TensorFlow są reprezentowane przez jeden rodzaj obsługiwanego elementu —
SavedModelBundle
.SavedModelBundle
wewnętrznie składa się ztensorflow:Session
w połączeniu z pewnymi metadanymi dotyczącymi tego, jaki wykres jest ładowany do sesji i jak go uruchomić w celu wyciągnięcia wniosków.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ę obsługiwanego strumienia dla obsługiwanego modelu TensorFlow. Każdy eksport odpowiada elementom serwowalnym, które można załadować.
AspiredVersionsManager
monitoruje strumień eksportu i dynamicznie zarządza cyklem życia wszystkich obiektówSavedModelBundle
.
TensorflowPredictImpl::Predict
a następnie po prostu:
- Żąda
SavedModelBundle
od menedżera (poprzez ServerCore). - Używa
generic signatures
do mapowania logicznych nazw tensorów wPredictRequest
na rzeczywiste nazwy tensorów i wiązania wartości z tensorami. - 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ę emitował komunikaty dziennika o treści „Wersja aspirująca do obsłużenia…”, co oznacza, że znalazł eksport i śledzi jego dalsze istnienie.
Uruchommy klienta za pomocą --concurrency=10
. Spowoduje to wysłanie równoczesnych żądań do serwera i w ten sposób uruchomi 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%
To potwierdza, że Twój serwer automatycznie wykryje nową wersję i użyje jej do serwowania!