Este tutorial mostra como usar os componentes do TensorFlow Serving para criar o TensorFlow ModelServer padrão que descobre e fornece dinamicamente novas versões de um modelo treinado do TensorFlow. Se você só quer usar o servidor padrão para servir os seus modelos, consulte TensorFlow Servindo tutorial básico .
Este tutorial usa o modelo simples de regressão do Softmax apresentado no tutorial do TensorFlow para classificação de imagens manuscritas (dados MNIST). Se você não sabe o que TensorFlow ou MNIST é, ver a MNIST Para ML Beginners tutorial.
O código para este tutorial consiste em duas partes:
A Python arquivo mnist_saved_model.py que os trens e exportações múltiplas versões do modelo.
A C ++ arquivo main.cc que é o padrão TensorFlow ModelServer que descobre nova exportados modelos e executa um gRPC serviço para servi-los.
Este tutorial percorre as seguintes tarefas:
- Treine e exporte um modelo TensorFlow.
- Gerenciar modelo de versionamento com TensorFlow Servindo
ServerCore
. - Configurar lotes usando
SavedModelBundleSourceAdapterConfig
. - Sirva pedido com TensorFlow Servindo
ServerCore
. - Execute e teste o serviço.
Antes de começar, primeiro instalar Docker
Treine e exporte o modelo TensorFlow
Primeiro, se você ainda não fez isso, clone este repositório em sua máquina local:
git clone https://github.com/tensorflow/serving.git
cd serving
Limpe o diretório de exportação se ele já existir:
rm -rf /tmp/models
Treine (com 100 iterações) e exporte a primeira versão do modelo:
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=100 --model_version=1 /tmp/mnist
Treine (com 2.000 iterações) e exporte a segunda versão do modelo:
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=2000 --model_version=2 /tmp/mnist
Como você pode ver na mnist_saved_model.py
, o treinamento e exportação é feito da mesma maneira que é na TensorFlow Servindo tutorial básico . Para fins de demonstração, você está intencionalmente diminuindo as iterações de treinamento para a primeira execução e exportando-as como v1, enquanto o treina normalmente para a segunda execução e exporta-as como v2 para o mesmo diretório pai - como esperamos que o último alcance melhor precisão de classificação devido ao treinamento mais intensivo. Você deverá ver a formação de dados para cada corrida de treinamento em sua /tmp/mnist
diretório:
$ ls /tmp/mnist
1 2
ServerCore
Agora imagine que v1 e v2 do modelo são gerados dinamicamente no tempo de execução, conforme novos algoritmos estão sendo experimentados ou quando o modelo é treinado com um novo conjunto de dados. Em um ambiente de produção, você pode querer construir um servidor que possa suportar distribuição gradual, em que a v2 pode ser descoberta, carregada, experimentada, monitorada ou revertida enquanto atende a v1. Como alternativa, você pode desativar a v1 antes de ativar a v2. O TensorFlow Serving é compatível com as duas opções - enquanto uma é boa para manter a disponibilidade durante a transição, a outra é boa para minimizar o uso de recursos (por exemplo, RAM).
TensorFlow Servindo Manager
faz exatamente isso. Ele lida com todo o ciclo de vida dos modelos do TensorFlow, incluindo carregamento, disponibilização e descarga, bem como transições de versão. Neste tutorial, você vai construir seu servidor no topo de uma TensorFlow Servindo ServerCore
, que envolve internamente um 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()
leva um ServerCore :: parâmetro Opções. Aqui estão algumas opções comumente usadas:
-
ModelServerConfig
que especifica modelos para ser carregado. Modelos são declarados, quer atravésmodel_config_list
, que declara uma lista estática de modelos, ou atravéscustom_model_config
, que define uma forma personalizada para declarar uma lista de modelos que podem ficar atualizados em tempo de execução. -
PlatformConfigMap
que mapeia a partir do nome da plataforma (tal comotensorflow
) para oPlatformConfig
, que é usada para criar oSourceAdapter
.SourceAdapter
adaptaStoragePath
(o caminho no qual uma versão do modelo é descoberto) para modelarLoader
(cargas a versão do modelo de caminho de armazenamento e fornece interfaces de transição de estado para oManager
). SePlatformConfig
contémSavedModelBundleSourceAdapterConfig
, umSavedModelBundleSourceAdapter
será criado, que vamos explicar mais tarde.
SavedModelBundle
é um componente chave da TensorFlow Serviço. Ela representa um modelo TensorFlow carregado a partir de um determinado caminho e fornece o mesmo Session::Run
interface como TensorFlow à inferência prazo. SavedModelBundleSourceAdapter
adapta caminho de armazenamento para Loader<SavedModelBundle>
modo que o modelo de vida pode ser gerido pelo Manager
. Por favor note que SavedModelBundle
é o sucessor do obsoleto SessionBundle
. Os usuários são encorajados a usar SavedModelBundle
como suporte para SessionBundle
em breve será removido.
Com todos estes, ServerCore
faz internamente o seguinte:
- Instancia um
FileSystemStoragePathSource
que os caminhos de exportação monitores modelo declarou emmodel_config_list
. - Instancia um
SourceAdapter
usando oPlatformConfigMap
com a plataforma modelo declarou emmodel_config_list
e liga oFileSystemStoragePathSource
a ele. Desta forma, sempre que uma nova versão do modelo é descoberto sob o caminho de exportação, oSavedModelBundleSourceAdapter
adapta-lo a umLoader<SavedModelBundle>
. - Instancia uma implementação específica de
Manager
chamadoAspiredVersionsManager
que gerencia todas essasLoader
instâncias criadas pelaSavedModelBundleSourceAdapter
.ServerCore
exporta oManager
de interface, delegando as chamadas paraAspiredVersionsManager
.
Sempre que uma nova versão está disponível, este AspiredVersionsManager
carrega a nova versão, e sob seu comportamento descarrega padrão do antigo. Se você deseja começar a personalizar, é recomendável entender os componentes que ele cria internamente e como configurá-los.
É importante mencionar que o TensorFlow Serving foi projetado do zero para ser muito flexível e extensível. Você pode construir vários plugins para o comportamento do sistema personalização, enquanto aproveitando componentes principais genéricos como ServerCore
e AspiredVersionsManager
. Por exemplo, você pode construir um plug-in de fonte de dados que monitora o armazenamento em nuvem em vez de armazenamento local, ou pode construir um plug-in de política de versão que faz a transição de versão de uma maneira diferente - na verdade, você pode até construir um plug-in de modelo personalizado que serve modelos não TensorFlow. Esses tópicos estão fora do escopo deste tutorial. No entanto, você pode consultar a fonte personalizada e personalizado veiculáveis tutoriais para mais informações.
Lote
Outro recurso típico de servidor que desejamos em um ambiente de produção é o envio em lote. Aceleradores de hardware modernos (GPUs, etc.) usados para fazer inferência de aprendizado de máquina geralmente alcançam a melhor eficiência de computação quando as solicitações de inferência são executadas em grandes lotes.
De dosagem pode ser ligado através do fornecimento adequado SessionBundleConfig
ao criar o SavedModelBundleSourceAdapter
. Neste caso, definir as BatchingParameters
com valores padrão muito bonito. O batching pode ser ajustado definindo valores de tempo limite personalizado, batch_size, etc. Para mais detalhes, consulte a 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;
Ao chegar lote completo, pedidos de inferência são mescladas internamente em uma única solicitação grande (tensor) e tensorflow::Session::Run()
é invocado (que é onde o ganho de eficiência real em GPUs vem).
Servir com o gerente
Como mencionado acima, TensorFlow Servindo Manager
é concebida para ser um componente genérico que pode lidar com a carga, que serve, de descarga e versão de transição de modelos gerados por sistemas de aprendizagem de máquina arbitrária. Suas APIs são construídas em torno dos seguintes conceitos-chave:
Veiculável: veiculável é qualquer objeto opaco que pode ser usado para servir as solicitações do cliente. O tamanho e a granularidade de um serviço são flexíveis, de modo que um único serviço pode incluir qualquer coisa, desde um único fragmento de uma tabela de consulta a um único modelo aprendido por máquina a uma tupla de modelos. Um serviço pode ser de qualquer tipo e interface.
Veiculáveis Versão: Servables são versionadas e TensorFlow Servindo
Manager
podem gerenciar uma ou mais versões de um que possa ser veiculado. O controle de versão permite que mais de uma versão de um serviço seja carregada simultaneamente, suportando implementação gradual e experimentação.Veiculável Fluxo: Um fluxo que podem ser veiculados é a sequência de versões de um que possa ser veiculado, com o aumento do números de versão.
Modelo: Um modelo aprendeu-máquina é representado por um ou mais servables. Exemplos de servables são:
- Sessão TensorFlow ou invólucros em torno deles, como
SavedModelBundle
. - Outros tipos de modelos aprendidos com a máquina.
- Tabelas de consulta de vocabulário.
- Incorporação de tabelas de pesquisa.
Um modelo composto pode ser representado como vários serviços independentes ou como um único serviço composto. Um que possa ser veiculado pode também corresponder a uma fracção de um modelo, por exemplo, com uma tabela de pesquisa de grande Sharded em muitos
Manager
casos.- Sessão TensorFlow ou invólucros em torno deles, como
Para colocar tudo isso no contexto deste tutorial:
Modelos TensorFlow são representados por um tipo de que possa ser veiculado -
SavedModelBundle
.SavedModelBundle
internamente consiste em umtensorflow:Session
emparelhado com alguns metadados sobre o gráfico é carregado para a sessão e como executá-lo por inferência.Há um diretório do sistema de arquivos contendo um fluxo de exportações do TensorFlow, cada uma em seu próprio subdiretório, cujo nome é um número de versão. O diretório externo pode ser considerado a representação serializada do stream de serviço para o modelo TensorFlow que está sendo servido. Cada exportação corresponde a um serviço que pode ser carregado.
AspiredVersionsManager
monitora o fluxo de exportação, e gerencia o ciclo de vida de todos osSavedModelBundle
servables dinamicamente.
TensorflowPredictImpl::Predict
, em seguida, apenas:
- Solicita
SavedModelBundle
do gerente (através ServerCore). - Usa as
generic signatures
para mapear nomes tensor lógicos emPredictRequest
a nomes tensor reais e os valores se ligam a tensores. - Executa inferência.
Teste e execute o servidor
Copie a primeira versão da exportação para a pasta monitorada:
mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored
Em seguida, inicie o servidor:
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 &
O servidor emitirá mensagens de log a cada segundo que dizem "Aspiring version for servable ...", o que significa que ele encontrou a exportação e está rastreando sua existência contínua.
Vamos executar o cliente com --concurrency=10
. Isso enviará solicitações simultâneas ao servidor e, assim, acionará sua lógica de envio em lote.
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
O que resulta em uma saída semelhante a:
...
Inference error rate: 13.1%
Em seguida, copiamos a segunda versão da exportação para a pasta monitorada e executamos novamente o teste:
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
O que resulta em uma saída semelhante a:
...
Inference error rate: 9.5%
Isso confirma que seu servidor descobre automaticamente a nova versão e a usa para servir!