El rendimiento de TensorFlow Serving depende en gran medida de la aplicación que ejecuta, el entorno en el que se implementa y otro software con el que comparte el acceso a los recursos de hardware subyacentes. Como tal, ajustar su rendimiento depende en cierta medida de cada caso y existen muy pocas reglas universales que garanticen un rendimiento óptimo en todos los entornos. Dicho esto, este documento tiene como objetivo capturar algunos principios generales y mejores prácticas para ejecutar TensorFlow Serving.
Utilice la guía Solicitudes de inferencia de perfiles con TensorBoard para comprender el comportamiento subyacente del cálculo de su modelo en las solicitudes de inferencia y utilice esta guía para mejorar iterativamente su rendimiento.
Consejos rápidos
- ¿La latencia de la primera solicitud es demasiado alta? Habilitar el calentamiento del modelo .
- ¿Está interesado en una mayor utilización o rendimiento de los recursos? Configurar procesamiento por lotes
Ajuste del rendimiento: objetivos y parámetros
Al ajustar el rendimiento de TensorFlow Serving, generalmente hay 2 tipos de objetivos que puede tener y 3 grupos de parámetros para modificar para mejorar esos objetivos.
Objetivos
TensorFlow Serving es un sistema de publicación en línea para modelos de aprendizaje automático. Como ocurre con muchos otros sistemas de servicio en línea, su principal objetivo de rendimiento es maximizar el rendimiento manteniendo la latencia de cola por debajo de ciertos límites . Dependiendo de los detalles y la madurez de su aplicación, es posible que le importe más la latencia promedio que la latencia de cola , pero alguna noción de latencia y rendimiento suelen ser las métricas con las que establece los objetivos de rendimiento. Tenga en cuenta que no analizamos la disponibilidad en esta guía, ya que es más una función del entorno de implementación.
Parámetros
Podemos pensar aproximadamente en 3 grupos de parámetros cuya configuración determina el rendimiento observado: 1) el modelo TensorFlow 2) las solicitudes de inferencia y 3) el servidor (hardware y binario).
1) El modelo TensorFlow
El modelo define el cálculo que realizará TensorFlow Serving al recibir cada solicitud entrante.
Debajo del capó, TensorFlow Serving utiliza el tiempo de ejecución de TensorFlow para realizar la inferencia real de sus solicitudes. Esto significa que la latencia promedio de atender una solicitud con TensorFlow Serving suele ser al menos la de hacer inferencia directamente con TensorFlow. Esto significa que si en una máquina determinada, la inferencia en un solo ejemplo toma 2 segundos y tiene un objetivo de latencia inferior a un segundo, necesita perfilar las solicitudes de inferencia, comprender qué operaciones de TensorFlow y subgráficos de su modelo contribuyen más a esa latencia. y rediseñe su modelo teniendo en cuenta la latencia de inferencia como restricción de diseño.
Tenga en cuenta que, si bien la latencia promedio de realizar inferencias con TensorFlow Serving generalmente no es menor que usar TensorFlow directamente, donde TensorFlow Serving brilla es en mantener la latencia de cola baja para muchos clientes que consultan muchos modelos diferentes, todo mientras se utiliza eficientemente el hardware subyacente para maximizar el rendimiento. .
2) Las solicitudes de inferencia
Superficies API
TensorFlow Serving tiene dos superficies API (HTTP y gRPC), las cuales implementan la API PredictionService (con la excepción del servidor HTTP que no expone un punto final MultiInference
). Ambas superficies API están altamente ajustadas y agregan una latencia mínima, pero en la práctica, se observa que la superficie gRPC tiene un rendimiento ligeramente mayor.
Métodos API
En general, se recomienda utilizar los puntos finales Classify y Regress, ya que aceptan tf.Example , que es una abstracción de nivel superior; sin embargo, en casos raros de solicitudes estructuradas grandes (O(Mb)), los usuarios expertos pueden usar PredictRequest y codificar directamente sus mensajes Protobuf en un TensorProto, y omitir la serialización y deserialización desde tf. Ejemplo de una fuente de ligera ganancia de rendimiento.
Tamaño del lote
Hay dos formas principales en que el procesamiento por lotes puede mejorar su rendimiento. Puede configurar sus clientes para que envíen solicitudes por lotes a TensorFlow Serving, o puede enviar solicitudes individuales y configurar TensorFlow Serving para esperar hasta un período de tiempo predeterminado y realizar inferencias en todas las solicitudes que lleguen en ese período en un lote. La configuración de este último tipo de procesamiento por lotes le permite alcanzar TensorFlow Serving con un QPS extremadamente alto, al tiempo que le permite escalar de forma sublineal los recursos informáticos necesarios para mantenerse al día. Esto se analiza con más detalle en la guía de configuración y en el archivo README de procesamiento por lotes .
3) El servidor (hardware y binario)
El binario TensorFlow Serving realiza una contabilidad bastante precisa del hardware en el que se ejecuta. Como tal, debe evitar ejecutar otras aplicaciones que consuman mucha memoria o computación en la misma máquina, especialmente aquellas con uso dinámico de recursos.
Al igual que con muchos otros tipos de cargas de trabajo, TensorFlow Serving es más eficiente cuando se implementa en menos máquinas y más grandes (más CPU y RAM) (es decir, una Deployment
con replicas
más bajas en términos de Kubernetes). Esto se debe a un mejor potencial para la implementación multiinquilino para utilizar el hardware y menores costos fijos (servidor RPC, tiempo de ejecución de TensorFlow, etc.).
Aceleradores
Si su host tiene acceso a un acelerador, asegúrese de haber implementado su modelo para colocar cálculos densos en el acelerador; esto debe hacerse automáticamente si ha utilizado API de TensorFlow de alto nivel, pero si ha creado gráficos personalizados o desea fijar partes específicas de gráficos en aceleradores específicos, es posible que deba colocar manualmente ciertos subgráficos en los aceleradores (es decir, usarlos with tf.device('/device:GPU:0'): ...
).
CPU modernas
Las CPU modernas han ampliado continuamente la arquitectura del conjunto de instrucciones x86 para mejorar la compatibilidad con SIMD (datos múltiples de instrucción única) y otras características críticas para cálculos densos (por ejemplo, una multiplicación y suma en un ciclo de reloj). Sin embargo, para poder ejecutarse en máquinas un poco más antiguas, TensorFlow y TensorFlow Serving se crean con la modesta suposición de que la CPU host no admite las funciones más nuevas.
Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
Si ve esta entrada de registro (posiblemente extensiones diferentes a las 2 enumeradas) al iniciar TensorFlow Serving, significa que puede reconstruir TensorFlow Serving y apuntar a la plataforma de su host en particular y disfrutar de un mejor rendimiento. Construir TensorFlow Serving desde el código fuente es relativamente fácil usando Docker y está documentado aquí .
Configuración binaria
TensorFlow Serving ofrece una serie de controles de configuración que gobiernan su comportamiento en tiempo de ejecución, en su mayoría configurados a través de indicadores de línea de comandos . Algunos de estos (en particular tensorflow_intra_op_parallelism
y tensorflow_inter_op_parallelism
) se transmiten para configurar el tiempo de ejecución de TensorFlow y se configuran automáticamente, lo que los usuarios expertos pueden anular haciendo muchos experimentos y encontrando la configuración adecuada para su carga de trabajo y entorno específicos.
Vida de una solicitud de inferencia de servicio de TensorFlow
Repasemos brevemente la vida de un ejemplo prototípico de una solicitud de inferencia de TensorFlow Serving para ver el recorrido que recorre una solicitud típica. Para nuestro ejemplo, profundizaremos en una solicitud de predicción que recibe la superficie API gRPC de TensorFlow Serving 2.0.0.
Primero veamos un diagrama de secuencia a nivel de componente y luego saltemos al código que implementa esta serie de interacciones.
Diagrama de secuencia
Tenga en cuenta que el Cliente es un componente propiedad del usuario, Prediction Service, Servables y Server Core son propiedad de TensorFlow Serving y TensorFlow Runtime es propiedad de Core TensorFlow .
Detalles de la secuencia
-
PredictionServiceImpl::Predict
recibePredictRequest
- Invocamos
TensorflowPredictor::Predict
, propagando la fecha límite de la solicitud desde la solicitud gRPC (si se configuró una). - Dentro de
TensorflowPredictor::Predict
, buscamos el Servable (modelo) sobre el que la solicitud busca realizar la inferencia, del cual recuperamos información sobre el SavedModel y, lo que es más importante, un identificador del objetoSession
en el que se encuentra (posiblemente parcialmente) el gráfico del modelo. cargado. Este objeto Servable se creó y se confirmó en la memoria cuando TensorFlow Serving cargó el modelo. Luego invocamos internal::RunPredict para realizar la predicción. - En
internal::RunPredict
, después de validar y preprocesar la solicitud, usamos el objetoSession
para realizar la inferencia usando una llamada de bloqueo a Session::Run , momento en el cual ingresamos al código base central de TensorFlow. Después de queSession::Run
regrese y nuestros tensoresoutputs
se hayan completado, convertimos las salidas en unaPredictionResponse
y devolvemos el resultado a la pila de llamadas.