Este tutorial le muestra cómo utilizar los componentes de TensorFlow Serving para crear el TensorFlow ModelServer estándar que descubre y ofrece dinámicamente nuevas versiones de un modelo de TensorFlow entrenado. Si solo desea utilizar el servidor estándar para servir sus modelos, consulte el tutorial básico de TensorFlow Serving .
Este tutorial utiliza el modelo de regresión Softmax simple introducido en el tutorial de TensorFlow para la clasificación de imágenes escritas a mano (datos MNIST). Si no sabe qué es TensorFlow o MNIST, consulte el tutorial MNIST para principiantes de ML .
El código de este tutorial consta de dos partes:
Un archivo Python mnist_saved_model.py que entrena y exporta múltiples versiones del modelo.
Un archivo C++ main.cc , que es el TensorFlow ModelServer estándar que descubre nuevos modelos exportados y ejecuta un servicio gRPC para brindarlos.
Este tutorial recorre las siguientes tareas:
- Entrene y exporte un modelo de TensorFlow.
- Administre el control de versiones del modelo con TensorFlow Serving
ServerCore
. - Configure el procesamiento por lotes mediante
SavedModelBundleSourceAdapterConfig
. - Servir solicitud con TensorFlow Serving
ServerCore
. - Ejecute y pruebe el servicio.
Antes de comenzar, primero instale Docker
Entrenar y exportar el modelo TensorFlow
Primero, si aún no lo has hecho, clona este repositorio en tu máquina local:
git clone https://github.com/tensorflow/serving.git
cd serving
Borre el directorio de exportación si ya existe:
rm -rf /tmp/models
Entrene (con 100 iteraciones) y exporte la primera versión del modelo:
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=100 --model_version=1 /tmp/mnist
Entrene (con 2000 iteraciones) y exporte la segunda versión del modelo:
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=2000 --model_version=2 /tmp/mnist
Como puede ver en mnist_saved_model.py
, el entrenamiento y la exportación se realizan de la misma manera que en el tutorial básico de TensorFlow Serving . Para fines de demostración, está reduciendo intencionalmente las iteraciones de entrenamiento para la primera ejecución y exportándolas como v1, mientras las entrena normalmente para la segunda ejecución y las exporta como v2 al mismo directorio principal, como esperamos que logre este último. mejor precisión de clasificación debido a un entrenamiento más intensivo. Deberías ver los datos de entrenamiento para cada ejecución de entrenamiento en tu directorio /tmp/mnist
:
$ ls /tmp/mnist
1 2
Núcleo del servidor
Ahora imagine que v1 y v2 del modelo se generan dinámicamente en tiempo de ejecución, a medida que se experimentan con nuevos algoritmos o cuando el modelo se entrena con un nuevo conjunto de datos. En un entorno de producción, es posible que desee crear un servidor que admita una implementación gradual, en el que se pueda descubrir, cargar, experimentar, monitorear o revertir la versión 2 mientras se sirve la versión 1. Alternativamente, es posible que desees derribar la v1 antes de abrir la v2. TensorFlow Serving admite ambas opciones: mientras que una es buena para mantener la disponibilidad durante la transición, la otra es buena para minimizar el uso de recursos (por ejemplo, RAM).
TensorFlow Serving Manager
hace exactamente eso. Maneja el ciclo de vida completo de los modelos de TensorFlow, incluida su carga, entrega y descarga, así como las transiciones de versiones. En este tutorial, construirá su servidor sobre TensorFlow Serving ServerCore
, que encapsula internamente un 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()
toma un parámetro ServerCore::Options. A continuación se muestran algunas opciones de uso común:
-
ModelServerConfig
que especifica los modelos que se cargarán. Los modelos se declaran mediantemodel_config_list
, que declara una lista estática de modelos, o mediantecustom_model_config
, que define una forma personalizada de declarar una lista de modelos que pueden actualizarse en tiempo de ejecución. -
PlatformConfigMap
que se asigna desde el nombre de la plataforma (comotensorflow
) aPlatformConfig
, que se utiliza para crearSourceAdapter
.SourceAdapter
adaptaStoragePath
(la ruta donde se descubre una versión del modelo) al ModelLoader
(carga la versión del modelo desde la ruta de almacenamiento y proporciona interfaces de transición de estado alManager
). SiPlatformConfig
contieneSavedModelBundleSourceAdapterConfig
, se creará unSavedModelBundleSourceAdapter
, que explicaremos más adelante.
SavedModelBundle
es un componente clave de TensorFlow Serving. Representa un modelo de TensorFlow cargado desde una ruta determinada y proporciona la misma interfaz Session::Run
que TensorFlow para ejecutar la inferencia. SavedModelBundleSourceAdapter
adapta la ruta de almacenamiento a Loader<SavedModelBundle>
para que Manager
pueda administrar la vida útil del modelo. Tenga en cuenta que SavedModelBundle
es el sucesor del obsoleto SessionBundle
. Se anima a los usuarios a utilizar SavedModelBundle
ya que pronto se eliminará la compatibilidad con SessionBundle
.
Con todo esto, ServerCore
internamente hace lo siguiente:
- Crea una instancia de
FileSystemStoragePathSource
que monitorea las rutas de exportación del modelo declaradas enmodel_config_list
. - Crea una instancia de
SourceAdapter
utilizandoPlatformConfigMap
con la plataforma modelo declarada enmodel_config_list
y le conectaFileSystemStoragePathSource
. De esta manera, cada vez que se descubre una nueva versión del modelo en la ruta de exportación,SavedModelBundleSourceAdapter
la adapta aLoader<SavedModelBundle>
. - Crea una instancia de una implementación específica de
Manager
llamadaAspiredVersionsManager
que administra todas las instanciasLoader
creadas porSavedModelBundleSourceAdapter
.ServerCore
exporta la interfazManager
delegando las llamadas aAspiredVersionsManager
.
Siempre que hay una nueva versión disponible, este AspiredVersionsManager
carga la nueva versión y, según su comportamiento predeterminado, descarga la anterior. Si desea comenzar a personalizar, le recomendamos que comprenda los componentes que crea internamente y cómo configurarlos.
Cabe mencionar que TensorFlow Serving está diseñado desde cero para ser muy flexible y extensible. Puede crear varios complementos para personalizar el comportamiento del sistema y, al mismo tiempo, aprovechar los componentes centrales genéricos como ServerCore
y AspiredVersionsManager
. Por ejemplo, podría crear un complemento de fuente de datos que supervise el almacenamiento en la nube en lugar del almacenamiento local, o podría crear un complemento de política de versiones que realice la transición de versión de una manera diferente; de hecho, incluso podría crear un complemento de modelo personalizado que sirva Modelos que no son TensorFlow. Estos temas están fuera del alcance de este tutorial. Sin embargo, puede consultar la fuente personalizada y los tutoriales de servicio personalizados para obtener más información.
procesamiento por lotes
Otra característica típica del servidor que queremos en un entorno de producción es el procesamiento por lotes. Los aceleradores de hardware modernos (GPU, etc.) utilizados para realizar inferencias de aprendizaje automático generalmente logran la mejor eficiencia de cálculo cuando las solicitudes de inferencia se ejecutan en lotes grandes.
El procesamiento por lotes se puede activar proporcionando SessionBundleConfig
adecuado al crear SavedModelBundleSourceAdapter
. En este caso configuramos BatchingParameters
con valores prácticamente predeterminados. El procesamiento por lotes se puede ajustar estableciendo valores personalizados de tiempo de espera, tamaño de lote, etc. Para obtener más información, consulte 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;
Al alcanzar el lote completo, las solicitudes de inferencia se fusionan internamente en una única solicitud grande (tensor) y se invoca tensorflow::Session::Run()
(que es de donde proviene la ganancia de eficiencia real en las GPU).
Servir con el gerente
Como se mencionó anteriormente, TensorFlow Serving Manager
está diseñado para ser un componente genérico que puede manejar la carga, entrega, descarga y transición de versiones de modelos generados por sistemas arbitrarios de aprendizaje automático. Sus API se basan en los siguientes conceptos clave:
Servable : Servable es cualquier objeto opaco que se puede utilizar para atender solicitudes de clientes. El tamaño y la granularidad de un servable es flexible, de modo que un único servable puede incluir cualquier cosa, desde un único fragmento de una tabla de búsqueda hasta un único modelo aprendido por máquina o una tupla de modelos. Un servable puede ser de cualquier tipo e interfaz.
Versión servible : los servables tienen versiones y TensorFlow Serving
Manager
puede administrar una o más versiones de un servable. El control de versiones permite cargar más de una versión de un servable simultáneamente, lo que permite una implementación y experimentación graduales.Flujo servible : un flujo servible es la secuencia de versiones de un servible, con números de versión crecientes.
Modelo : un modelo aprendido por máquina está representado por uno o más servables. Ejemplos de servicios son:
- Sesión de TensorFlow o envoltorios que las rodean, como
SavedModelBundle
. - Otros tipos de modelos de aprendizaje automático.
- Tablas de consulta de vocabulario.
- Incrustar tablas de búsqueda.
Un modelo compuesto podría representarse como múltiples servables independientes o como un único servible compuesto. Un servable también puede corresponder a una fracción de un modelo, por ejemplo, con una tabla de búsqueda grande dividida en muchas instancias
Manager
.- Sesión de TensorFlow o envoltorios que las rodean, como
Para poner todo esto en el contexto de este tutorial:
Los modelos de TensorFlow están representados por un tipo de servable:
SavedModelBundle
.SavedModelBundle
consta internamente de untensorflow:Session
emparejado con algunos metadatos sobre qué gráfico se carga en la sesión y cómo ejecutarlo para inferencia.Hay un directorio del sistema de archivos que contiene un flujo de exportaciones de TensorFlow, cada una en su propio subdirectorio cuyo nombre es un número de versión. Se puede considerar el directorio externo como la representación serializada de la secuencia que se puede servir para el modelo de TensorFlow que se sirve. Cada exportación corresponde a un servable que se puede cargar.
AspiredVersionsManager
monitorea el flujo de exportación y administra dinámicamente el ciclo de vida de todos los serviciosSavedModelBundle
.
TensorflowPredictImpl::Predict
y luego simplemente:
- Solicita
SavedModelBundle
del administrador (a través de ServerCore). - Utiliza
generic signatures
para asignar nombres de tensores lógicos enPredictRequest
a nombres de tensores reales y vincular valores a tensores. - Ejecuta inferencia.
Probar y ejecutar el servidor
Copie la primera versión de la exportación a la carpeta monitoreada:
mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored
Luego inicie el 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 &
El servidor emitirá mensajes de registro cada segundo que dicen "Versión aspirante a servable ...", lo que significa que ha encontrado la exportación y está rastreando su existencia continua.
Ejecutemos el cliente con --concurrency=10
. Esto enviará solicitudes simultáneas al servidor y, por lo tanto, activará su lógica de procesamiento por lotes.
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
Lo que da como resultado un resultado similar a:
...
Inference error rate: 13.1%
Luego copiamos la segunda versión de la exportación a la carpeta monitoreada y volvemos a ejecutar la prueba:
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
Lo que da como resultado un resultado similar a:
...
Inference error rate: 9.5%
¡Esto confirma que su servidor descubre automáticamente la nueva versión y la utiliza para servir!