
Hoy en día, cuando las redes neuronales aran las extensiones de Big Data, y la inteligencia artificial está considerando si es rentable para él obtener un salario por su trabajo en Bitcoin, la tarea que tuve fue encontrar la biblioteca multiplataforma abierta más rápida para cargar, guardar y transcodificar archivos gráficos parecía un anacronismo real . Pero, de hecho, esta tarea es más relevante que nunca: para todas las tecnologías de visión artificial y aprendizaje automático, se deben descargar gigabytes de imágenes y, a veces, los datos intermedios se deben guardar como imágenes. Entonces, hacer esto de la manera más rápida es muy deseable. En este artículo encontraremos la biblioteca que estamos buscando y, lo más importante, trataremos con un producto muy útil que simplifica enormemente tareas similares y muchas otras: Google Benchmark.
Entonces, la declaración exacta del problema dice: en la aplicación, los archivos jpeg y tiff con profundidad de color de 24 y 8 bits, así como bmp de 32 bits, se cargan en la memoria. Los tamaños de imagen varían de pequeños (32x32 píxeles) a grandes, con una resolución de 15K. En el proceso, los archivos se modifican, después de lo cual deben guardarse en el disco en los formatos especificados. Y esto debe hacerse mediante una biblioteca de código abierto multiplataforma que tenga el máximo rendimiento en los procesadores Intel modernos con soporte para instrucciones vectoriales AVX2. La biblioteca también es compatible con la biblioteca de formatos de textura comprimida DirectX DXT1. El
componente de imágenes de Windows se toma como punto de referencia para el rendimiento: el marco estándar para trabajar con imágenes en Windows, es decir, necesita encontrar una biblioteca que funcione en pie de igualdad o más rápido que WIC.
Pero el requisito más importante es que se necesita una solución en este momento, pero mejor ayer.
Conozca las bibliotecas para trabajar con bmp, tiff, jpeg
La solución comienza con un paso obvio y sin complicaciones, aunque no muy rápido: un estudio exhaustivo de
Wikileaks github ,
stackoverflow y otros google en busca de candidatos adecuados para el papel de la biblioteca deseada. Había pocos de esos:
- FreeImage . Un shell sobre las famosas bibliotecas LibJPEG, LibPNG, LibTIFF. El soporte DXT1 está presente a través del complemento. La desventaja es que la calidad del ahorro de JPEG en la API se establece de manera demasiado discreta: 100, 75.50 y 25%. Para cambiar este parámetro, deberá comprender y editar el código. El proyecto está activo y en desarrollo: la última versión 3.18.0 se lanzó el 31 de julio de 2018. El ensamblaje en Windows es trivial, todos los componentes se crean automáticamente.
- Cimg Este es un contenedor de archivos de encabezado C ++ sobre un antiguo paquete de
artefactos ImageMagick . El paquete requiere una instalación de compilación separada, también es posible usarlo directamente, sin pasar por Cimg. Tiene muchas posibilidades para trabajar con imágenes: filtros, transformaciones, definición de morfología, etc. Admite HDR, no admite DXT1. - DevIL ( Biblioteca de imágenes del desarrollador ). Una biblioteca C muy sencilla de estilo OpenGL. Contiene un shell sobre LibJPEG, LibPNG, LibTIFF, pero también tiene una amplia funcionalidad incorporada, además admite muchos formatos de imagen, incluido DXT1. Para el montaje utiliza CMake. La mayoría de las dependencias, incluidas LibJPEG, LibPNG, LibTIFF, no están incluidas en DevIL y deben descargarse y compilarse por separado. La última actualización de DevIL con respecto al sistema de compilación tiene fecha 01/01/2017, y la anterior generalmente ocurrió en 2014, por lo que si hay posibles problemas con la biblioteca, puede haber problemas con su solución.
- OpenImageIO . Se posiciona como una herramienta de desarrollo de software profesional para trabajar con imágenes. Es compatible en forma de complementos que funcionan con muchos formatos de fotos exóticas e incluso video. Build for Windows requiere Boost y Qt 4. precompilados. No hay una versión ensamblada ya preparada para las pruebas.
- Boost GIL (Biblioteca de imágenes genéricas) Boost y eso es todo. Aunque no todos. Esta biblioteca también contiene un contenedor sobre LibJPEG, LibPNG y LibTIFF.
- SDL_image 2.0 Se utiliza con la biblioteca SDL y, se reirá, pero también contiene un shell sobre LibJPEG, LibPNG y LibTIFF.
Todas las bibliotecas encontradas se compilaron en Windows utilizando el nivel máximo de optimización del compilador de Visual Studio y el modificador / arch: AVX2.
Lo mismo se aplica a las bibliotecas LibJPEG, LibPNG y LibTIFF, para acelerar el trabajo tomado del nuevo paquete de la
biblioteca OpenCV .
Conoce el punto de referencia de Google
El siguiente paso de la solución también es obvio: crear un punto de referencia para comparar el rendimiento de las bibliotecas encontradas, y el uso de la biblioteca de microbenchmarking de Google Benchmark, ampliamente conocida en círculos estrechos, lo hace simple y rápido.
Google Benchmark puede medir con precisión el rendimiento de los fragmentos de código que insertó en el cuerpo del ciclo C ++ 11.
static void BM_foo1(benchmark::State& state) {
en funciones registradas como referencia
Y ejecutarlos:
BENCHMARK_MAIN();
Luego emita un informe en el formato especificado: salida de la consola, json, csv.
El informe contendrá datos sobre el sistema de ejecución (procesador, configuración de caché), el tiempo operativo global total de cada una de las funciones medidas, así como el tiempo que le toma al procesador. Estos tiempos generalmente difieren: el primero, por ejemplo, incluye un retraso de lectura / escritura, y el segundo para puntos de referencia de subprocesos múltiples es la suma del tiempo de funcionamiento de todos los núcleos.
El último parámetro que muestra el punto de referencia de Google es el número de iteraciones realizadas para la función, que es necesaria para una medición precisa estadísticamente correcta de su tiempo de operación. El sistema lo selecciona usted mismo, automáticamente, haciendo mediciones preliminares.
¿Qué es una "medición precisa" del tiempo de ejecución? Puede escribir disertaciones sobre este tema, pero en este caso es suficiente decir que:
- Por defecto, la medición está en grupos de procesadores, es decir, el orden teórico de precisión es exactamente esto. La salida predeterminada es en nanosegundos;
- los resultados en todas las pruebas que he visto son muy estables de lanzamiento a lanzamiento;
- Según mis datos de inteligencia, los desarrolladores de software de computadora de a bordo de una de las empresas automovilísticas más grandes del mundo utilizan y confían plenamente en sus resultados. Entonces lo creeremos.
Lo único a lo que vale la pena prestarle atención: el punto de referencia de Google no proporciona "limpieza" de la memoria caché entre los inicios de las iteraciones de referencia. Si es necesario, debe ocuparse de esto usted mismo.
Pero el punto de referencia de Google puede hacer muchas otras cosas:
- calcular la complejidad asintótica del algoritmo (O);
- funcionan correctamente con puntos de referencia de subprocesos múltiples, midiendo su duración no en tics de procesador, sino en el modo "en tiempo real" (reloj de pared);
- use su propia función de medición de tiempo "manual", que puede ser útil, por ejemplo, al medir el trabajo en la GPU;
- establecer automáticamente puntos de referencia con diferentes conjuntos de argumentos para un cuerpo dado de la función medida;
- muestra el valor promedio, la mediana y la desviación estándar para múltiples inicios del punto de referencia;
- Establezca sus propios contadores y etiquetas que se reflejarán en el informe de referencia de Google.
El benchmark de Google se descarga desde
el repositorio de github , ensamblado para la plataforma apropiada usando Cmake (el ensamblaje de Visual Studio está disponible para Windows), la biblioteca resultante se vinculará a su proyecto (en el caso de Windows, también se requiere un enlace con la biblioteca shlwapi), el archivo de encabezado de benchmark se agrega a su código .h, después de lo cual todo funciona como se describe anteriormente.
Si no funciona, el único lugar, además del
sitio ya indicado , donde puede obtener al menos algo de información y ayuda sobre el punto de referencia de Google es un
foro de productos especializado .
En nuestro caso, todo funcionó sin problemas. Después de comunicarse con los clientes, se definieron 4 puntos de referencia, que se cargan y guardan con un nombre diferente:
- Archivo jpeg de 8 bits con una resolución de 15k
- Archivo jpeg de 24 bits con una resolución de 15k
- Archivo tiff de 24 bits con una resolución de 15k
- Archivo bmp de 32 bits con una resolución de 32x32
Conoce los resultados
Originalmente se planeó que todas las bibliotecas encontradas, es decir, FreeImage, Cimg, DevIL, OpenImageIO, Boost GIL y SDL_image 2.0, participen en la prueba de comparación con Windows Imaging Component (WIC). Pero los últimos tres bibliotecas, dependiendo de "monstruos" como Boost y SDL, les pidieron a los clientes que se fueran en reserva en caso de emergencia, si la biblioteca deseada no se encuentra entre las tres primeras. Y, afortunadamente, fue encontrada. Aunque no de inmediato.
El siguiente es un informe generado por el punto de referencia de Google, que muestra que:
- FreeImage completamente con una puntuación aplastante pierde WIC en todas las pruebas, por lo que ya no se puede considerar.
- Cimg pierde WIC limpiamente en todas partes, excepto para cargar tiff, donde es ligeramente (menos del 5%) más rápido. Por desgracia, también tendrá que ser eliminado. Además, esto se aplica al uso directo del paquete ImageMagick.
Sigue siendo la biblioteca DevIL. Muestra excelentes resultados en casos de carga de bmp y tiff (3 y 2.8 veces más altos que WIC!), JPEG en blanco y negro (1.75 veces mejor que WIC), pero se ralentiza un poco al cargar un JPEG normal de 24 bits: lo hace en 3 % más lento que WIC.
08/15/18 11:15:44 Running c:\WIC\WIC_test\Release\WIC_test.exe Run on (8 X 4008 MHz CPU s) CPU Caches: L1 Data 32K (x4) L1 Instruction 32K (x4) L2 Unified 262K (x4) L3 Unified 8388K (x1) |
Benchmark | Time | CPU | Iterations |
BM_WIC8jpeg | 72 ms | 70 ms | 11 |
BM_cimg8jpeg | 562 ms | 52 ms | 10 |
BM_FreeImage8jpeg | 147 ms | 144 ms | 5 |
BM_devIL8jpeg | 41 ms | 41 ms | 17 |
|
BM_WIC24jpeg | 266 ms | 260 ms | 3 |
BM_cimg24jpeg | 656 ms | 128 ms | 6 |
BM_FreeImage24jpeg | 594 ms | 594 ms | 1 |
BM_devIL24jpeg | 276 ms | 276 ms | 3 |
|
BM_WIC24tiff | 844 ms | 844 ms | 1 |
BM_cimg24tiff | 808 ms | 131 ms | 5 |
BM_FreeImage24tiff | 953 ms | 938 ms | 1 |
BM_devIL24tiff | 305 ms | 305 ms | 2 |
|
BM_WIC32 | 3 ms | 3 ms | 236 |
BM_cimg32 | 71 ms | 7 ms | 90 |
BM_FreeImage32 | 6 ms | 5 ms | 112 |
BM_devIL32 | 1 ms | 1 ms | 747 |
Por supuesto, DevIL también podría ser rechazado en esta etapa, pero aquí aparece otra biblioteca en el marco:
Libjpeg-turbo .
Su salida se puede cumplir fácilmente con aplausos:
Libjpeg-turbo es una biblioteca multiplataforma que implementa completamente la funcionalidad libjpeg (API) y agrega su propia funcionalidad (por ejemplo, trabajando con buffers de 32 bits). Al mismo tiempo, para la arquitectura x86, Libjpeg-turbo utiliza activamente instrucciones de vectores (SSE2, AVX2) y, según sus creadores, es 2-6 veces más rápido que libjpeg (!)
Por lo tanto, el siguiente paso es construir DevIL con Libjpeg-turbo en lugar de libjpeg. Libjpeg-turbo con la ayuda de CMake construye Visual Studio sin problemas, y luego casi de inmediato (con el reemplazo del único #define, que determina la versión de libjpeg en el archivo de encabezado DevIL), comienza a funcionar como parte de DevIL.
Como resultado, el informe de referencia de Google se ve así:
Benchmark | Time | CPU | Iterations |
BM_WIC8jpeg | 72 ms | 68 ms | 9 |
BM_cimg8jpeg | 565 ms | 39 ms | 10 |
BM_FreeImage8jpeg | 148 ms | 141 ms | 5 |
BM_devIL8jpeg | 31 ms | 31 ms | 24 |
|
BM_WIC24jpeg | 269 ms | 266 ms | 2 |
BM_cimg24jpeg | 675 ms | 131 ms | 5 |
BM_FreeImage24jpeg | 604 ms | 594 ms | 1 |
BM_devIL24jpeg | 149 ms | 150 ms | 5 |
|
BM_WIC24tiff | 833 ms | 828 ms | 1 |
BM_cimg24tiff | 785 ms | 138 ms | 5 |
BM_FreeImage24tiff | 943 ms | 938 ms | 1 |
BM_devIL24tiff | 318 ms | 320 ms | 2 |
|
BM_WIC32 | 4 ms | 3 ms | 236 |
BM_cimg32 | 74 ms | 8 ms | 56 |
BM_FreeImage32 | 6 ms | 5 ms | 100 |
BM_devIL32 | 1 ms | 1 ms | 747 |
Por supuesto, las mejoras de rendimiento con jpeg ni siquiera son el doble en comparación con libjpeg, pero debería serlo, porque la superioridad de la velocidad solo se aplica a la codificación / decodificación jpeg, y la prueba incluye la sobrecarga de leer / escribir un archivo.
Pero se puede ver que, en promedio, DevIL es más rápido que WIC en el caso de jpeg de 8 bits
2.3 veces, jpeg de 24 bits
1.8 veces, tiff de 24 bits -
2.7 veces, bmp de 32 bits -
3.5 veces.
El problema está resuelto. Tres días laborables previos a las vacaciones de verano se gastaron completamente en la decisión. Por supuesto, si hubiera un poco más, sería posible que hubiera una biblioteca con resultados aún más impresionantes, y si fuera mucho más, entonces quizás escribiría la biblioteca que estaba buscando.
Pero incluso lo que es impresionante. Por lo tanto, si está buscando una biblioteca multiplataforma para trabajar con archivos gráficos que sea rápida y fácil en todos los sentidos, preste atención a
DevIL , y si necesita realizar mediciones comparativas del código de manera rápida y precisa, entonces
el punto de referencia de Google está a su servicio.