Cómo un Tensorflow mal configurado en Docker puede ser 10 veces más lento de lo esperado
por Pierre Paci
TL:DR: TensorFlow lee la cantidad de núcleos de CPU lógicos para configurarse, lo cual puede ser incorrecto cuando tiene un contenedor con restricción de CPU.
Hagamos un punto de referencia simple comparando una inferencia en GPU, CPU en el host, CPU en la ventana acoplable y CPU en la ventana acoplable con restricción.
Keras/Tensorflow parece realizar alguna operación en la GPU en la primera llamada a .predict(), por lo que no cronometrará la primera llamada, sino la segunda.
Ejecutarlo en mi Nvidia 1080 dará como resultado un tiempo de inferencia de ~0,01 s por imagen.
Esta vez, en mi CPU, sin un contenedor, se necesitan ~0,12 s. 12 veces más lento está en el orden de magnitud de lo que se puede esperar entre CPU y GPU. Tenga en cuenta que mi TensorFlow no está compilado correctamente con soporte AVX o MKL. La GPU se hizo no visible mediante el uso de la variable de entorno CUDA_VISIBLE_DEVICES.
Agreguemos un contenedor.
Nota: Pillow es una biblioteca de manejo de imágenes requerida por Keras para cargar una imagen.
La ejecución de este contenedor dará como resultado un tiempo de inferencia de ~0,15 s. Tal vez algunos gastos generales de Docker o algunas versiones de TF sean diferentes a los de mi host, pero ese no es el objetivo de este artículo. El verdadero punto llegará ahora.
La solución
Estoy usando un i7 7700k con 8 núcleos lógicos, 4 físicos. Entonces, si configuramos el contenedor para que use solo 2 núcleos lógicos (1 físico), debería ser aproximadamente 4 veces más lento, es decir, aproximadamente 0,6 s. Las restricciones las impondrá la API de Docker. En realidad, da como resultado una inferencia de 2,5 s: ¡cuatro veces más lenta de lo esperado!
De hecho, TensorFlow utiliza la cantidad de núcleos lógicos para calcular algunas cifras de rendimiento interno. Aquí se producirá una sobrecarga ya que la cantidad de núcleos informados difiere de lo que está disponible. En su servidor de producción, podría ser incluso mayor. En nuestros servidores, era 10 veces más lento ya que Xeon tiene más núcleos.
Entonces, qué podemos hacer ?
¡La guía de rendimiento de TensorFlow tiene la respuesta!
Usando estos nuevos parámetros, obtenemos el siguiente código:
Y ahora, solo se necesitan ~0,6 s. ¡Y eso es exactamente lo que se esperaba!
En conclusión, incluso si Docker parece simplificar el entorno de producción, ¡tenga siempre cuidado! Y no olvide utilizar la guía de rendimiento en la documentación.