Compilación de TensorFlow ModelServer estándar

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

En este instructivo, se muestra cómo usar los componentes de TensorFlow Serving para compilar el TensorFlow ModelServer estándar que descubre y entrega dinámicamente nuevas versiones de un modelo TensorFlow entrenado. Si lo que desea es utilizar el servidor estándar para servir a sus modelos, véase TensorFlow Sirviendo tutorial básico .

Este instructivo usa el modelo simple de regresión de Softmax presentado en el instructivo de TensorFlow para la clasificación de imágenes manuscritas (datos MNIST). Si usted no sabe lo que es TensorFlow o MNIST, ver el MNIST Por ML principiantes tutorial.

El código de este tutorial consta de dos partes:

  • Un archivo de Python mnist_saved_model.py que los trenes y las exportaciones de varias versiones del modelo.

  • Un archivo de C ++ main.cc que es el estándar TensorFlow ModelServer que descubre nuevos modelos exportados y dirige una GRPC servicio para servirlos.

Este tutorial recorre las siguientes tareas:

  1. Entrene y exporte un modelo de TensorFlow.
  2. Manejo de modelo de versiones con TensorFlow Sirviendo ServerCore .
  3. Configurar procesamiento por lotes utilizando SavedModelBundleSourceAdapterConfig .
  4. Servir pedido Servir con TensorFlow ServerCore .
  5. Ejecute y pruebe el servicio.

Antes de comenzar, primero instalar acoplable

Entrenar y exportar el modelo de TensorFlow

Primero, si aún no lo ha hecho, clone este repositorio en su 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 se puede ver en mnist_saved_model.py , la formación y la exportación se realiza de la misma manera que se encuentra en la TensorFlow Sirviendo tutorial básico . Para fines de demostración, está marcando intencionalmente las iteraciones de entrenamiento para la primera ejecución y exportándolo como v1, mientras lo entrena normalmente para la segunda ejecución y lo 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ía ver la formación de datos para cada recorrido de entrenamiento en su /tmp/mnist directorio:

$ ls /tmp/mnist
1  2

ServerCore

Ahora imagine que la v1 y la v2 del modelo se generan dinámicamente en tiempo de ejecución, mientras se experimentan 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 la implementación gradual, en el que v2 se puede descubrir, cargar, experimentar, monitorear o revertir mientras se entrega v1. Alternativamente, es posible que desee eliminar v1 antes de abrir 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).

Sirviendo TensorFlow Manager hace exactamente eso. Maneja el ciclo de vida completo de los modelos de TensorFlow, incluida la carga, el servicio y la descarga, así como las transiciones de versión. En este tutorial, se va a construir su servidor en la parte superior de un TensorFlow Sirviendo ServerCore , que se envuelve en su interior 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 :: Opciones. A continuación, se muestran algunas opciones de uso común:

  • ModelServerConfig que los modelos especifica para ser cargados. Los modelos se declaran ya sea a través model_config_list , que declara una lista estática de los modelos, o por medio de custom_model_config , que define una forma personalizada para declarar una lista de modelos que pueden recibir información actualizada en tiempo de ejecución.
  • PlatformConfigMap que se asigna a partir del nombre de la plataforma (como tensorflow ) a la PlatformConfig , que se utiliza para crear la SourceAdapter . SourceAdapter adapta StoragePath (la ruta donde se descubrió una versión del modelo) para modelar Loader (cargas la versión del modelo de ruta de almacenamiento y proporciona interfaces de transición de estado para el Manager ). Si PlatformConfig contiene SavedModelBundleSourceAdapterConfig , un SavedModelBundleSourceAdapter se creará, que explicaremos más adelante.

SavedModelBundle es un componente clave de TensorFlow porción. Representa un modelo TensorFlow cargado desde una trayectoria dada y proporciona la misma Session::Run interfaz como TensorFlow a plazo inferencia. SavedModelBundleSourceAdapter se adapta a la ruta de almacenamiento Loader<SavedModelBundle> por lo que el modelo de vida puede ser gestionado por Manager . Tenga en cuenta que SavedModelBundle es el sucesor del obsoleto SessionBundle . Se anima a los usuarios a utilizar SavedModelBundle como el apoyo a SessionBundle pronto será eliminado.

Con todo esto, ServerCore hace internamente la siguiente:

  • Instancia un FileSystemStoragePathSource que las rutas de exportación monitores modelo declaran en model_config_list .
  • Instancia un SourceAdapter utilizando el PlatformConfigMap con la plataforma modelo declaró en model_config_list y conecta la FileSystemStoragePathSource a ella. De esta manera, cada vez que una nueva versión del modelo se descubre bajo la ruta de exportación, la SavedModelBundleSourceAdapter se adapta a un Loader<SavedModelBundle> .
  • Crea la instancia de una implementación específica del Manager llamada AspiredVersionsManager que gestiona todos estos Loader instancias creadas por el SavedModelBundleSourceAdapter . ServerCore exporta el Manager la interfaz mediante la delegación de las llamadas a AspiredVersionsManager .

Cada vez que una nueva versión está disponible, este AspiredVersionsManager carga la nueva versión, y bajo su comportamiento predeterminado de descarga el uno viejo. Si desea comenzar a personalizar, le recomendamos que comprenda los componentes que crea internamente y cómo configurarlos.

Vale la pena mencionar que TensorFlow Serving está diseñado desde cero para ser muy flexible y extensible. Usted puede construir varios plugins para el comportamiento del sistema para requisitos particulares, aprovechando al mismo tiempo los componentes básicos genéricos como ServerCore y AspiredVersionsManager . Por ejem modelos que no son de TensorFlow. Estos temas están fuera del alcance de este tutorial. Sin embargo, se puede hacer referencia a la fuente de la costumbre y la costumbre se pueden publicar y tutoriales para más información.

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.) que se utilizan 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.

Preparación de lotes se puede activar proporcionando adecuada SessionBundleConfig al crear el SavedModelBundleSourceAdapter . En este caso, establecemos los BatchingParameters con valores por defecto más o menos. El procesamiento por lotes se puede ajustar estableciendo valores personalizados de tiempo de espera, tamaño de lote, etc. Para más detalles, 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 llegar lote completo, solicitudes de inferencia se fusionan internamente en una sola petición grande (tensor), y tensorflow::Session::Run() se invoca (que es donde el aumento de la eficiencia real de las GPU viene).

Sirva con el gerente

Como se mencionó anteriormente, TensorFlow Sirviendo Manager está diseñado para ser un componente genérico que puede manejar la carga, que sirve, descarga y transición versión de modelos generados por los sistemas de aprendizaje de máquina arbitrarias. Sus API se basan en los siguientes conceptos clave:

  • Servable: servable es cualquier objeto opaco que puede ser utilizado para servir las peticiones de cliente. El tamaño y la granularidad de un servidor es flexible, de modo que un único servidor puede incluir cualquier cosa, desde un solo fragmento de una tabla de búsqueda hasta un solo modelo de aprendizaje automático y una tupla de modelos. Un servidor puede ser de cualquier tipo e interfaz.

  • Servable Versión: Servables están versionados y TensorFlow Sirviendo Manager puede administrar una o más versiones de un servable. El control de versiones permite que se cargue más de una versión de un servidor al mismo tiempo, lo que permite la implementación y la experimentación graduales.

  • Servable Stream: Una corriente servable es la secuencia de versiones de un servable, con el aumento de números de versión.

  • Modelo: Un modelo de máquina-aprendido está representado por uno o más servables. Ejemplos de servibles son:

    • TensorFlow sesión o envolturas alrededor de ellos, como SavedModelBundle .
    • Otros tipos de modelos de aprendizaje automático.
    • Tablas de búsqueda de vocabulario.
    • Incorporación de tablas de búsqueda.

    Un modelo compuesto podría representarse como varios servidores independientes o como un solo servidor compuesto. A servable también puede corresponder a una fracción de un modelo, por ejemplo con una gran tabla de búsqueda fragmentados a través de muchos Manager instancias.

Para poner todo esto en el contexto de este tutorial:

  • TensorFlow modelos están representados por un tipo de servable - SavedModelBundle . SavedModelBundle interna consiste en una tensorflow:Session emparejado con algunos metadatos acerca de lo que el gráfico se carga en la sesión y la forma de ejecutarlo para la 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. El directorio externo se puede considerar como la representación serializada de la transmisión servible para el modelo de TensorFlow que se entrega. Cada exportación corresponde a un servicio que se puede cargar.

  • AspiredVersionsManager monitorea la corriente de exportación, y gestiona el ciclo de vida de todos los SavedModelBundle servables dinámicamente.

TensorflowPredictImpl::Predict entonces simplemente:

  • Pide SavedModelBundle desde el gestor (a través de ServerCore).
  • Utiliza las generic signatures para asignar nombres lógicos tensor en PredictRequest a los nombres reales de tensor y valores vinculados a los tensores.
  • Ejecuta inferencia.

Pruebe y ejecute 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 para servable ...", lo que significa que ha encontrado la exportación y está rastreando su existencia continua.

Vamos a ejecutar 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 una salida que se ve así:

...
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 una salida que se ve así:

...
Inference error rate: 9.5%

¡Esto confirma que su servidor descubre automáticamente la nueva versión y la usa para servir!