Darknet: Red neuronal Open Source escrita en C.

Darknet es una red neuronal escrita en C y CUDA. Es rápida, fácil de instalar, y soporta tanto computación por CPU como por GPU.

Así comienza la introducción que nos hace Joseph Redmon en su web respecto a éste maravilloso repositorio que ha creado en Github.

Allí podemos encontrar toda la información relativa a la librería, así como al Paper sobre la visión por computación que ha desarrollado.

Sin embargo, en éste artículo quiero centrarme en dos de las funciones que se pueden realizar con ésta librería: la creación de pesadillas (así es cómo las denominan) y la clasificación de imágenes.

Pesadillas

Darknet Nightmares

Joseph, relata en uno de los apartados de su web cómo se les ocurrió a los creadores del paper ejecutar las redes neuronales profundas que utilizaban, también en el sentido contrario, para así, poder visualizar qué era lo que la máquina estaba pensando durante dicho proceso.

Como resultado obtuvieron una serie de imágenes que denominaron: Nightmares. Relata también cómo otros investigadores han continuado este trabajo, incluyendo una publicación que Google mas tarde publicitaría mucho.

Pues bien, en éste artículo pretendo traducir las instrucciones que Pjreddie explica en su web (en inglés) para que todo el mundo pueda generar con éste maravilloso software sus propias “pesadillas” y clasificaciones.

Instalación

try harder!

Lo primero que nos indica el autor es que debemos instalar la librería en nuestro sistema, esta parte la obviaré, ya que para instalarla basta con seguir las instrucciones que se detallan aquí ,de todas formas, mas adelante recordaremos cómo hacerlo.

A continuación el autor nos explica que generaremos nuestras pesadillas con un modelo de red neuronal pre-entrenado llamado VGG-16. Sin embargo, sólo utilizaremos las capas convolucionales de dicho modelo, con lo que utilizaremos el archivo vgg-conf.cfg que ya figura en la ruta /cfg/ de la librería.

Para que funcione correctamente, se deben descargar los pesos previamente entrenados de aquí (57 MB).

Al lío

Utilizaremos la siguiente imagen incluida en el directorio /data/ del repositorio para emular el ejemplo que nos enseña Joseph en su web:

El grito de Munch

Una vez instala y configurada ya podremos generar nuestra propia pesadilla con el siguiente comando:

./darknet nightmare cfg/vgg-conv.cfg vgg-conv.weights data/scream.jpg 10 

El comando se estructura de la siguiente forma: en primer lugar tenemos el ejecutable darknet que se ejecuta con la función nightmare como argumento, y a continuación la ruta con el fichero de configuración y el de los pesos de la red neuronal respectivamente: cfg/vgg-conf.cfg vgg-conv.weights. A continuación la ruta donde se encuentra la imagen a la que vamos a realizar dicho proceso, y por último el número de capas que deseamos utilizar data/scream.jpg 10

El autor nos indica también, que éste proceso puede llevarnos un tiempo, dependiendo de si estamos utilizando solo la CPU o hemos habitado también la GPU (esto debemos hacerlo editando el fichero cfg/vgg-conf.cfg). Nos recomienda habilitar CUDA para acelerar el proceso de generación de éstas imágenes, y nos explica cómo hacerlo en el apartado de instalación antes mencionado.

Sin embargo, para habilitar CUDA hay que disponer de una tarjeta gráfica compatible e instalar los drivers correspondientes antes de compilar darknet con esta opción.

Si todo ha salido correctamente en la carpeta raíz de la librería aparecerá una imagen similar a ésta:

El grito de munch (procesado por Nightmare)

Opciones especiales

rizar el rizo

Darknet genera éstas imágenes en rondas sucesivas, es decir la imagen de salida de la primera ronda será el input de la siguiente y así sucesivamente. La imagen de cada una de las rondas también queda almacenada en el disco duro. Asimismo cada ronda se compone de varias iteraciones y en cada iteración darknet modifica la imagen para mejorar la capa correspondiente en alguna escala. La escala es escogida al azar de un conjunto de octavas. La capa también se elige al azar entre una variedad de capas posibles. A continuación explicaremos qué parámetros pueden añadirse a la función para modificar éste procedimiento a nuestro gusto:

  • -rounds n: cambia el número de rondas (1 por defecto). A mayor número de rondas mas imágenes generará, y por lo general significará mayor cambio en la imagen original.
  • -iters n: cambia el número de iteraciones por ronda (10 por defecto). Cuantas mas iteraciones hagamos mas cambios se producirán por cada ronda en la imagen.
  • -range n: cambia el rango de capas posibles (1 por defecto). Si se deja por defecto (1) solo se elige la capa dada en cada iteración. De lo contrario, se elige una capa aleatoriamente dentro del rango de capas. (Por ejemplo: para 10 capas con rango 3, elegiría una aleatoriamente entre las capas 9-11).
  • octaves -n: cambia el número de escalas posibles (4 por defecto). En una octava solo se examina la imagen a tamaño completo. Cada octava adicional agrega una versión más pequeña de la imagen (concretamente 3/4 del tamaño de la octava anterior).
  • rate x: cambia la tasa de aprendizaje de la imagen (0.05 por defecto). A mayor rate mas cambios se producirán en la imagen por iteración, pero también produce mas inestabilidad e imprecisión en la imagen.
  • thresh x: cambia el umbral para ampliar las features (1.0 por defecto). Solo las entidades que superen el umbral x respecto de las desviaciones estándar de la media se ampliarán en la capa destino. Cuanto mayor sea el umbral menos features se ampliarán en la siguiente capa.
  • zoom x: cambia el zoom aplicado a cada imagen después de cada ronda (1.0 por defecto). Adicionalmente se puede agregar un zoom in (x <1) o zoom out (x > 1) para que se aplique a la imagen después de cada ronda.
  • rotate x: cambia la rotación aplicada a la imagen después de cada ronda (0.0 por defecto).

Con estas opciones ya puedes personalizar las pesadillas como desees.

Aquí pongo otra imagen creada con nightmare a modo de ejemplo con el modelo vgg-conv :

imagen creada con nightmare


Clasificación de imágenes

otras funciones de Darknet.

Respecto a la clasificación de imágenes Joseph explica que han desarrollado un sistema que han decidido bautizar como YOLO: You Only Look Once, cuyo sistema de detección es capaz de procesar imágenes (hasta 30 frames por segundo), con una precision del 57.9% en los test COCO.

COCO es un dataset de detección de objetos a gran escala, con segmentación y subtítulos que tiene varias características:

  • Segmentación de objetos
  • Reconocimiento en contexto
  • 80 categorías de objetos
  • 1.5 millones de instancias de objetos
  • 91 categorias de “cosas”
  • 5 subtitulos por imagen
  • 250000 personas con keypoints

Los sistemas de detección previos revierten a los clasificadores o localizadores para realizar la detección. Aplican un modelo a una imagen en múltiples ubicaciones y escalas. Las regiones de alta puntuación en la imagen se consideran detecciones.

Hacen incapié en que utilizan un enfoque diferente. Aplican una sola red neuronal a la imagen completa. Esta red divide la imagen en regiones y predice los cuadros y probabilidades del límite de cada región. Estos cuadros delimitados luego son ponderados por las probabilidades predichas.

Este modelo tiene, por tanto, varias ventajas respecto a los sistemas basados en clasificacion. La red observa toda la imagen en el tiempo de prueba, por lo que sus predicciones estan formadas por el contexto global de la imagen. También realiza prediciones con una sola evaluación de la red, a diferencia de sistemas de Redes basadas en Regiones R-CNN, que requieren miles de evaluaciones para una sola imagen. Esto lo hace extremadamente rápido, mas de 1000 veces que una R-CNN y unas 100 veces mas rápido que una Fast R-CNN.

Detección: utilizando un modelo pre-entrenado.

Veamos a continuación un ejemplo práctico de detección en imágenes con el modelo pre-entrenado. Recordad que para ello tendremos que haber instalado la librería de darknet como hemos mencionado antes.

Para ello ejecutaremos en un terminal:

git clone https://github.com/pjreddie/darknet
cd daknet 
make

Fácil!

Ya debería figurar el archivo de configuración en el subdirectorio cfg/ . Tendrás que descargar el archivo de pesos pre-entrenados aquí , o ejecutar:

wget https://pjreddie.com/media/files/yolov3.weights

Una vez preparado esto, ya podemos ejecutar el detector.

Utilizaremos una de las imágenes que vienen de ejemplo con la librería dento del directorio data/ en éste ejemplo usaremos ésta:

imagen de ejemplo.

y a continuación lanzamos el comando para realizar la detección:

./darknet detect cfg/yolov3.cfg yolov3.weights data/horses.jpg

debería generar una salida mas o menos así:

layer     filters    size              input                output
    0 conv     32  3 x 3 / 1   608 x 608 x   3   ->   608 x 608 x  32  0.639 BFLOPs
    1 conv     64  3 x 3 / 2   608 x 608 x  32   ->   304 x 304 x  64  3.407 BFLOPs
    2 conv     32  1 x 1 / 1   304 x 304 x  64   ->   304 x 304 x  32  0.379 BFLOPs
    3 conv     64  3 x 3 / 1   304 x 304 x  32   ->   304 x 304 x  64  3.407 BFLOPs
    4 res    1                 304 x 304 x  64   ->   304 x 304 x  64
    5 conv    128  3 x 3 / 2   304 x 304 x  64   ->   152 x 152 x 128  3.407 BFLOPs
    6 conv     64  1 x 1 / 1   152 x 152 x 128   ->   152 x 152 x  64  0.379 BFLOPs
    7 conv    128  3 x 3 / 1   152 x 152 x  64   ->   152 x 152 x 128  3.407 BFLOPs
    8 res    5                 152 x 152 x 128   ->   152 x 152 x 128
    9 conv     64  1 x 1 / 1   152 x 152 x 128   ->   152 x 152 x  64  0.379 BFLOPs
   10 conv    128  3 x 3 / 1   152 x 152 x  64   ->   152 x 152 x 128  3.407 BFLOPs
   11 res    8                 152 x 152 x 128   ->   152 x 152 x 128
   12 conv    256  3 x 3 / 2   152 x 152 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   13 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
   14 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   15 res   12                  76 x  76 x 256   ->    76 x  76 x 256
   16 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
   17 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   18 res   15                  76 x  76 x 256   ->    76 x  76 x 256
   19 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
   20 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   21 res   18                  76 x  76 x 256   ->    76 x  76 x 256
   22 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
   23 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   24 res   21                  76 x  76 x 256   ->    76 x  76 x 256
   25 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
   26 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   27 res   24                  76 x  76 x 256   ->    76 x  76 x 256
   28 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
   29 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   30 res   27                  76 x  76 x 256   ->    76 x  76 x 256
   31 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
   32 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   33 res   30                  76 x  76 x 256   ->    76 x  76 x 256
   34 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
   35 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
   36 res   33                  76 x  76 x 256   ->    76 x  76 x 256
   37 conv    512  3 x 3 / 2    76 x  76 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   38 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   39 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   40 res   37                  38 x  38 x 512   ->    38 x  38 x 512
   41 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   42 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   43 res   40                  38 x  38 x 512   ->    38 x  38 x 512
   44 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   45 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   46 res   43                  38 x  38 x 512   ->    38 x  38 x 512
   47 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   48 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   49 res   46                  38 x  38 x 512   ->    38 x  38 x 512
   50 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   51 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   52 res   49                  38 x  38 x 512   ->    38 x  38 x 512
   53 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   54 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   55 res   52                  38 x  38 x 512   ->    38 x  38 x 512
   56 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   57 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   58 res   55                  38 x  38 x 512   ->    38 x  38 x 512
   59 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   60 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   61 res   58                  38 x  38 x 512   ->    38 x  38 x 512
   62 conv   1024  3 x 3 / 2    38 x  38 x 512   ->    19 x  19 x1024  3.407 BFLOPs
   63 conv    512  1 x 1 / 1    19 x  19 x1024   ->    19 x  19 x 512  0.379 BFLOPs
   64 conv   1024  3 x 3 / 1    19 x  19 x 512   ->    19 x  19 x1024  3.407 BFLOPs
   65 res   62                  19 x  19 x1024   ->    19 x  19 x1024
   66 conv    512  1 x 1 / 1    19 x  19 x1024   ->    19 x  19 x 512  0.379 BFLOPs
   67 conv   1024  3 x 3 / 1    19 x  19 x 512   ->    19 x  19 x1024  3.407 BFLOPs
   68 res   65                  19 x  19 x1024   ->    19 x  19 x1024
   69 conv    512  1 x 1 / 1    19 x  19 x1024   ->    19 x  19 x 512  0.379 BFLOPs
   70 conv   1024  3 x 3 / 1    19 x  19 x 512   ->    19 x  19 x1024  3.407 BFLOPs
   71 res   68                  19 x  19 x1024   ->    19 x  19 x1024
   72 conv    512  1 x 1 / 1    19 x  19 x1024   ->    19 x  19 x 512  0.379 BFLOPs
   73 conv   1024  3 x 3 / 1    19 x  19 x 512   ->    19 x  19 x1024  3.407 BFLOPs
   74 res   71                  19 x  19 x1024   ->    19 x  19 x1024
   75 conv    512  1 x 1 / 1    19 x  19 x1024   ->    19 x  19 x 512  0.379 BFLOPs
   76 conv   1024  3 x 3 / 1    19 x  19 x 512   ->    19 x  19 x1024  3.407 BFLOPs
   77 conv    512  1 x 1 / 1    19 x  19 x1024   ->    19 x  19 x 512  0.379 BFLOPs
   78 conv   1024  3 x 3 / 1    19 x  19 x 512   ->    19 x  19 x1024  3.407 BFLOPs
   79 conv    512  1 x 1 / 1    19 x  19 x1024   ->    19 x  19 x 512  0.379 BFLOPs
   80 conv   1024  3 x 3 / 1    19 x  19 x 512   ->    19 x  19 x1024  3.407 BFLOPs
   81 conv    255  1 x 1 / 1    19 x  19 x1024   ->    19 x  19 x 255  0.189 BFLOPs
   82 yolo
   83 route  79
   84 conv    256  1 x 1 / 1    19 x  19 x 512   ->    19 x  19 x 256  0.095 BFLOPs
   85 upsample            2x    19 x  19 x 256   ->    38 x  38 x 256
   86 route  85 61
   87 conv    256  1 x 1 / 1    38 x  38 x 768   ->    38 x  38 x 256  0.568 BFLOPs
   88 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   89 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   90 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   91 conv    256  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 256  0.379 BFLOPs
   92 conv    512  3 x 3 / 1    38 x  38 x 256   ->    38 x  38 x 512  3.407 BFLOPs
   93 conv    255  1 x 1 / 1    38 x  38 x 512   ->    38 x  38 x 255  0.377 BFLOPs
   94 yolo
   95 route  91
   96 conv    128  1 x 1 / 1    38 x  38 x 256   ->    38 x  38 x 128  0.095 BFLOPs
   97 upsample            2x    38 x  38 x 128   ->    76 x  76 x 128
   98 route  97 36
   99 conv    128  1 x 1 / 1    76 x  76 x 384   ->    76 x  76 x 128  0.568 BFLOPs
  100 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
  101 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
  102 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
  103 conv    128  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 128  0.379 BFLOPs
  104 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
  105 conv    255  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x 255  0.754 BFLOPs
  106 yolo
Loading weights from yolov3.weights...Done!
data/horses.jpg: Predicted in 20.274472 seconds.
horse: 100%
horse: 100%
horse: 96%
horse: 95%

y si nos fijamos en la carpeta raiz de darknet veremos una imagen que se llama predictions.jpg (o algo parecido) en la que la red neuronal ha clasificado los objetos que ha detectado:

Detección realizada por darknet

Como podemos ver darknet identifica (y acota) los objetos mediante recuadros con etiquetas en la imagen. En la salida de la consola especifica la confianza que tiene de cada una de las predicciones y el tiempo estimado que le llevó encontrarla. En el ejemplo descrito vemos velocidades relativas a la computación por CPU (20, 27 segundos) ya que no hemos compilado la librería para utilizar OPENCV y CUDA, en cuyo caso la velocidad de detección se reduciría drásticamente.

Conclusión

No me gustaria finalizar sin recordar que todo esto es fruto del trabajo de Joseph Redmon y Ali Farhadi a los que quiero también agradecer su trabajo, así como haber liberado esta red neuronal bajo licencia de dominio público a través de internet.

@article{yolov3,
  title={YOLOv3: An Incremental Improvement},
  author={Redmon, Joseph and Farhadi, Ali},
  journal = {arXiv},
  year={2018}
}

Deja una respuesta