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:

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:

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 :

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:

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:

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}
}