Sunteți pe pagina 1din 35

Tecnológico de Monterey Campus Guadalajara

Maestría en Ciencias de la Computación

Programación​ ​Paralela
Localización​ ​y​ ​detección​ ​de​ ​objetos​ ​en​ ​tiempo​ ​real

Alejandra Rodríguez García


Efrain​ ​Martinez

Jueves​ ​16​ ​de​ ​noviembre​ ​del​ ​2017


Martínez,​ ​Rodríguez​ ​ ​1

Índice

Índice 1

Abstract 3

Introducción 4

Motivación 4

Objetivo 7

Alcances 7

Hipotesis 7

Estudio​ ​del​ ​arte 7

Patentes 7

Investigación 9

Productos​ ​en​ ​el​ ​mercado 11

Algoritmo​ ​elegido 12

Metodología​ ​implementada 12

GPU 12

Cámara​ ​web 13

Código​ ​fuente 13

Cambios​ ​en​ ​el​ ​código 16

Resultados​ ​obtenidos 17

Resultado​ ​de​ ​hipótesis 18

Conclusiones 19

Fortalezas 19

Debilidades 19

Trabajo​ ​a​ ​futuro 19


Martínez,​ ​Rodríguez​ ​ ​2

Diccionario 20

Adas 20

Cadena​ ​de​ ​efectos​ ​en​ ​los​ ​vehículos​ ​autónomos. 20

Cuda 21

GPU 21

Nvidia 21

OpcnCV 21

Bibliografía 22

Anexo​ ​1.​ ​Código​ ​de​ ​operaciones​ ​ejecutadas​ ​en​ ​la​ ​GPU 24

im2col_kernels.cu 24

activation_kernels.cu 25

convolutional_kernels.cu 27
Martínez,​ ​Rodríguez​ ​ ​3

Abstract
Las tecnologías de asistencia en la conducción permiten reducir el margen de error en la toma de
decisiones ante una situación de emergencia que ponga en riesgo la seguridad de una o más
personas dentro o fuera de un vehículo. Es por eso que se están haciendo grandes esfuerzos en
mejorar dichas tecnologías o agregar nuevas funcionalidades en las existentes que ayuden a reducir
las tasas de accidentes de tránsito en el mundo. Pero para lograr este objetivo de manera eficiente y
en tiempo real, se requiere una gran capacidad de cómputo debido a la gran cantidad de información
que tienen que analizar estos sistemas para decidir ejecutar alguna acción o no. Una alternativa para
ello es la programación paralela, la cual se basa en el uso de GPUs. Nvidia, es una compañía que
desarrolla el ecosistema tecnológico que se puede utilizar para este fin. El resultado deseado de esta
combinación​ ​de​ ​tecnologías​ ​es​ ​la​ ​seguridad​ ​a​ ​la​ ​hora​ ​de​ ​conducir​ ​eliminando​ ​el​ ​error​ ​humano.
Martínez,​ ​Rodríguez​ ​ ​4

Localización​ ​y​ ​detección​ ​de​ ​objetos​ ​en​ ​tiempo​ ​real

Introducción

Actualmente, los sistemas de asistencia de conducción avanzados (ADAS por sus siglas en inglés)
están adquiriendo cada vez más relevancia en la fabricación de vehículos, especialmente en áreas
donde la seguridad es crítica. Ha habido mejoras significativas en el desarrollo de sensores, radares y
sistemas de visión por computadora para determinar la distancia a otros vehículos u objetos así como
mejorar el campo de visión para alertar a los conductores sobre riesgos potenciales que pueden
poner en peligro la vida o integridad física de las personas dentro o fuera del vehículo. Sin embargo,
estos sistemas, en especial los sistemas de visión por computadora, requieren de un procesamiento
de​ ​cómputo​ ​elevado​ ​para​ ​poder​ ​manejar​ ​imágenes​ ​en​ ​tiempo​ ​real.
La computación en paralelo (GPUs) sirve para realizar tareas que necesitan velocidad y uno de
los requisitos es procesar varios cálculos al mismo tiempo. La diferencia de entre esta tecnología y
una CPU es que una GPU es capaz de procesar muchas tareas al mismo tiempo, mientras que la
CPU la forma en que lo realiza es sequencial. ¿Como? La GPU está compuesta por cientos de
procesadores​ ​que​ ​lo​ ​permiten​ ​ ​de​ ​manera​ ​eficiente.

Vehículo​ ​autónomo
Para reducir el error humano a la hora de conducir, se ha desarrollado el concepto de vehículo
autónomo (Salaman, 2017). Existen dos tipos de carros autónomos: los semi-autonomos y los
autónomos. Los carros autónomos son completamente manejados a través de sistemas, sensores y
algoritmos mientras que los semi, son los que incluyen sistemas de apoyo al conductor. (Business
insider, 2017). Se utiliza el machine learning para las aplicaciones de manejo autónomo, aprenden a
través de la información que entra por sensores y cámaras, es decir aprendizaje por imitación.
(Innocenti,​ ​Linden,​ ​Panahandeh,​ ​Sevensson,​ ​Mohammadiha,​ ​2017)

Motivación

Recientes avances en tecnología han permitido que emerjan soluciones disruptivas en una gran
cantidad de áreas donde había habido un crecimiento lento en décadas anteriores. Este es el caso de
la movilidad urbana, donde algunos de los objetivos incluyen mejorar los servicios de transporte
público y reducir el uso del carro para bajar las emisiones de CO2, reducir los embotellamientos y
minimizar los accidentes de tránsito. Sin embargo, los beneficios de estas tecnologías están lejos de
ser una realidad, especialmente en países de desarrollo donde la flota vehicular continúa en
crecimiento, al igual que los accidentes de tránsito. De acuerdo a la Organización Mundial de la Salud
(OMS), cerca de 1.25 millones de personas mueren cada año como resultado de un choques en la
Martínez,​ ​Rodríguez​ ​ ​5

carretera y entre 20 y 50 millones de gente sufre de lesiones no fatales, muchos de ellos incurriendo
en una discapacidad como resultado de dicha lesión. Por esta razón, los accidentes de tráfico
representan la novena causa de muerte en el mundo y la primera causa entre gente entre 15-29 años
de​ ​edad​ ​(ver​ ​figura​ ​1).

Figura​ ​1
Figura 1. Estadísticas globales de muertes relacionadas con accidentes de tráfico. A la izquierda, el número de muertes en el
mundo por accidentes en carreteras, 2013. A la izquierda, el top ten de las causas de muertes en gente entre 15-29 años de
edad,​ ​información​ ​de​ ​2012.​ ​Recuperado​ ​el​ ​10​ ​de​ ​octubre​ ​de​ ​2017​ ​del​ ​reporte​ ​WHO​ ​Global​ ​Status​ ​Report​ ​on​ ​Road​ ​Safety​ ​2015.

En​ ​México,​ ​la​ ​situación​ ​no​ ​es​ ​muy​ ​distinta,​ ​44%​ ​de​ ​los​ ​accidentes​ ​son​ ​accidentes​ ​de​ ​tráfico​ ​y
alrededor​ ​de​ ​15,000​ ​personas​ ​mueren​ ​cada​ ​año​ ​como​ ​consecuencia​ ​de​ ​ello.​ ​Además,​ ​es​ ​importante
mencionar​ ​que​ ​más​ ​del​ ​80%​ ​de​ ​estos​ ​accidentes​ ​fueron​ ​generados​ ​en​ ​colisiones​ ​vehículo​ ​a​ ​vehículo
donde​ ​9​ ​de​ ​10​ ​fueron​ ​responsabilidad​ ​del​ ​conductor.

En México, la situación no es muy distinta, 44% de los accidentes son accidentes de tráfico y
alrededor de 15,000 personas mueren cada año como consecuencia de ello. Además, es importante
mencionar que más del 80% de estos accidentes fueron generados en colisiones vehículo a vehículo
donde​ ​9​ ​de​ ​10​ ​fueron​ ​responsabilidad​ ​del​ ​conductor​ ​(ver​ ​figura​ ​2).
Martínez,​ ​Rodríguez​ ​ ​6

Figura​ ​2.​ ​Reporte​ ​de​ ​accidentes​ ​de​ ​tránsito​ ​en​ ​México​ ​para​ ​el​ ​periodo​ ​de​ ​2010-2015.​ ​La​ ​mayoría​ ​(69%)​ ​de​ ​los​ ​accidentes​ ​se
generan​ ​por​ ​colisiones​ ​vehículo​ ​a​ ​vehículo.​ ​ ​Recuperado​ ​el​ ​11​ ​de​ ​octubre​ ​de​ ​2017​ ​del​ ​portal​ ​del​ ​INEGI.

Mientras que el uso de ADAS se espera pueda asistir a los conductores en más y más sofisticadas
formas al proveer información acerca de las condiciones o el ambiente de conducción para tratar de
minimizar los accidentes de tránsito, aún se requiere enfocar esfuerzos en el desarrollo de algoritmos
más​ ​rápidos​ ​y​ ​eficientes​ ​para​ ​dicho​ ​propósito.
Martínez,​ ​Rodríguez​ ​ ​7

Objetivo

El objetivo de este proyecto es implementar un sistema ADAS por medio de un algoritmo “state of
the art” para reconocimiento y ubicación de objetos utilizando una GPU y una cámara de uso
comercial.

Alcances

Para esta investigación se tiene como propósito encontrar un algoritmo ya existente que más se
acerque a resolver el problema que nos estamos planteando que fuera como nuestra base, de ahí
modificar lo que fuera necesario. En este caso se encontró un algoritmo muy utilizado en las
aplicaciones​ ​de​ ​detección​ ​de​ ​objetos​ ​en​ ​tiempo​ ​real.

Hipotesis

1. Lograr detectar los objetos en la imagen capturada de la cámara, y lograr imprimir la


localización​ ​de​ ​estos.
2. Lograr​ ​que​ ​el​ ​algoritmo​ ​trabaje​ ​en​ ​tiempo​ ​real

Estudio​ ​del​ ​arte

Patentes
El 13 de julio del 2011, google ingresa la solicitud de patente con número US 8,195,394B1 de
nombre “​OBJECT DETECTION AND CLASSIFICATION FOR AUTONOMOUS VEHICLES”, misma
que fue aprobada el 5 de junio del 2012, con el objetivo de generar un sistema ADAS para que un
vehículo autónomo sea capaz de detectar los objetos dentro de su área de visión. De esta manera, se
podrían tomar decisiones de acuerdo al objeto en cuestión, ya sea esquivarlo, disminuir la velocidad o
detener​ ​el​ ​automóvil​ ​por​ ​completo.
Martínez,​ ​Rodríguez​ ​ ​8

Figura​ ​3.1

La figura 3.1, ilustra el flujo de decisión con el que se construiría el algoritmo para el vehículo
autónomo de google. Desde que ingresa la información del objeto a través de los sensores, se
identifica qué es en caso de estar a una distancia lo suficientemente cercana, de lo contrario solo
identifica el lugar en el que está. El alcance de esta patente no llega a que el algoritmo tome una
decisión​ ​de​ ​acuerdo​ ​al​ ​objeto​ ​identificado.

Figura​ ​3​.2
Martínez,​ ​Rodríguez​ ​ ​9

La figura 3.2 demuestra algunos de los objetos que podría detectar el vehículo. Los
señalamientos, las características de la calle, los peatones y cualquier objeto que pudiera
interponerse​ ​en​ ​el​ ​camino​ ​del​ ​mismo.
La invención que aclama google acerca de la patente es que se se identificará el objeto y todos
sus detalles como su posición en cuanto al campo de visión, así como el área geográfica que lo
rodea. Esta información la podrá comunicar el vehículo con los demás sensores y equipo de cómputo
del vehículo podrá tomar una decisión en cuanto a la dirección y velocidad. Será también capaz de
detallarla​ ​en​ ​diferentes​ ​pantallas​ ​de​ ​manera​ ​más​ ​visual.
Investigación
Como aplicaciones, también existen en el mercado diferentes algoritmos que funcionan como
ADAS que al igual que la detección de objetos utiliza la visión computacional. De parte de la
tecnología de NVIDIA, existe un hardware hecho para la detección de los carriles para los coches
autónomos. En la figura 3, se puede observar que información necesita recolectar para funcionar. Las
tres cámaras detectan todo el campo de visión del conductor, evitando cualquier punto ciego, toma en
cuenta cuál es pa posición del volante para predecir cualquier cambio de dirección y finalmente un
disco duro de estado sólido para guardar todos los datos generados y comparar en la información
obtenida en tiempo-real y poder compararla con el histórico. El resultado de este sistema, es un
control​ ​total​ ​del​ ​manejo​ ​del​ ​vehículo.

Figura​ ​3

Para llegar al punto de saber si el coche se encuentra en el carril correcto y antes de que se
empiece realmente a manejar el cómputo en paralelo, este sistema se necesita entrenar. En la figura
4 se muestra en el diagrama como entro la información, y qué comandos se utilizaron en el volante
para​ ​generar​ ​datos​ ​de​ ​comportamiento.
Martínez,​ ​Rodríguez​ ​ ​10

Figura​ ​4

El​ ​algoritmo​ ​que​ ​se​ ​eligió​ ​para​ ​la​ ​detección​ ​de​ ​objetos​ ​tendría​ ​un​ ​diagrama​ ​similar,​ ​con​ ​la
diferencia​ ​que​ ​se​ ​utilizó​ ​solamente​ ​una​ ​cámara​ ​y​ ​no​ ​tres​ ​para​ ​cuestiones​ ​de​ ​prueba.​ ​En​ ​cuanto​ ​a
sensores​ ​externos,​ ​no​ ​se​ ​utilizó​ ​ninguno.​ ​La​ ​figura​ ​5​ ​representa​ ​un​ ​diagrama​ ​más​ ​acercado​ ​a​ ​la​ ​forma
en​ ​el​ ​que​ ​se​ ​entrenó​ ​nuestro​ ​sistema,​ ​a​ ​pesar​ ​de​ ​que​ ​no​ ​era​ ​el​ ​mismo​ ​objetivo.

Figura​ ​5

La figura 5 describe cómo hicieron para entrenar la generación de comandos de dirección para
que el vehículo viaje de manera autónoma. La información entra por la cámara central para ser
evaluada por la red neuronal y genere un comando de conducción. Como conclusión a esta
investigación, se demostró que este sistema ADAS, es capaz de aprender a seguir dentro del mismo
carril teniendo total control sobre las decisiones de cambio de ruta y dirección. Para que sea un
algoritmo​ ​mucho​ ​más​ ​robusto​ ​necesita​ ​de​ ​más​ ​sesiones​ ​de​ ​entrenamiento.
Se encontró otro paper similar, ​“Imitation Learning for Vision-based Lane Keeping Assistance”​, en
el que se utiliza tecnología de NVIDIA igualmente para un algoritmo ADAS para que el vehículo
reconozca el carril en el que se encuentra y el evitar los cambios bruscos de dirección. Este como el
anterior, utiliza redes neuronales tanto como para aprender como para hacerlo de manera autónoma.
Pero a diferencia del paper anterior, en este se basó más en modelos matemáticos para calcular los
ángulos en los que se mueve la dirección del carro. Es capaz de aprender y clonar el comportamiento
del​ ​vehículo​ ​y​ ​el​ ​modo​ ​en​ ​el​ ​que​ ​hace​ ​el​ ​trayecto.
Martínez,​ ​Rodríguez​ ​ ​11

Figura​ ​6

La figura 6 es la representación gráfica de los cambios de dirección que aprende el modelo


matemático. En cuanto a dificultad, el segundo algoritmo es más complicado en cuanto al modelo
pero a diferencia del primero que tiene como objetivo la conducción autónoma, el segundo solamente
se enfoca a la dirección del vehículo para que se mantenga en su mismo carril. El objetivo de este
proyecto es similar en cuanto a cómo hace el primero pero no el alcance y similar al segundo en
cuanto​ ​al​ ​alcance,​ ​pero​ ​no​ ​el​ ​objetivo.
Productos​ ​en​ ​el​ ​mercado
En el mercado existen ya productos que sirven para la implementación de ADAS, para brindar
automatización a ciertas funcionalidades del vehículo. En la figura 7, se muestra el diagrama de
procesamiento de datos de una computadora de la compañía AUTOSAR. Este hardware se diseñó
para​ ​prototipar​ ​estos​ ​algoritmos​ ​en​ ​vehículos​ ​que​ ​no​ ​lo​ ​contengan​ ​ya​ ​implementado​ ​de​ ​fabrica.

Figura​ ​7
Martínez,​ ​Rodríguez​ ​ ​12

Para funcionar, se le conectan sensores de entrada (Cámaras, radar GPS, sensores de


movimiento, sensores de distancia, red inalámbrica de internet). La información se procesa en el
hardware, las conclusiones generadas crearán a su vez indicaciones (cambios en la velocidad y en la
dirección) según sea necesario. El algoritmo de está tecnología está desarrollado en C, OpenCV,
CUDA​ ​de​ ​NVIDIA​ ​y​ ​puede​ ​correr​ ​en​ ​sistemas​ ​operativos​ ​Linux​ ​y​ ​Windows.

Algoritmo​ ​elegido

Se eligió un algoritmo basado en Redes Neuronales Convolucionales llamado YOLO que aplica
una sola red neuronal a la imagen completa. Esta red divide la imagen en regiones y predice cuadros
delimitadores del objeto basándose en las probabilidades calculadas para cada región. La red corre a
45 fps (frames por segundo) sin procesamiento de batch en una GPU Titan X y puede correr hasta
150 fps en una versión más rápida. Esto significa que puede procesar video en tiempo real con
menos de 25ms de latencia. Además, alcanza más del doble de la precisión promedio de otros
sistemas​ ​en​ ​tiempo​ ​real.

Metodología​ ​implementada

GPU

Para la implementación del algoritmo seleccionado se utilizó una GPU Geforce 820m de NVidia
montada​ ​sobre​ ​una​ ​Laptop​ ​Asus​ ​X455L,​ ​la​ ​cual​ ​cuenta​ ​con​ ​las​ ​siguientes​ ​características:

​ ​ ​Total​​ ​amount​ ​of​ ​global​​ ​memory​: 1985​​ ​MBytes​​ ​(​2081685504​​ ​bytes)


​ ​ ​(​ ​2​)​ ​Multiprocessors​,​ ​(​ ​48​)​ ​CUDA​ ​Cores​/​MP​: 96​​ ​CUDA​ ​Cores
​ ​ ​GPU​ ​Max​​ ​Clock​​ ​rate​: 1250​​ ​MHz​​ ​(​1.25​​ ​GHz)
​ ​ ​Memory​​ ​Clock​​ ​rate​: 900​​ ​Mhz
​ ​ ​Memory​​ ​Bus​​ ​Width​: 64​-​bit
​ ​ ​L2​ ​Cache​​ ​Size​: 131072​​ ​bytes
​ ​ ​Maximum​​ ​Texture​​ ​Dimension​​ ​Size​​ ​(​x​,​y​,​z​) 1D​=(​65536​),​​ ​2D​=(​65536​,​ ​65535​),
3D​=(​2048​,​ ​2048​,​ ​2048)
​ ​ ​Maximum​​ ​Layered​​ ​1D​​ ​Texture​​ ​Size​,​ ​(​num​)​ ​layers​ ​ ​1D​=(​16384​),​​ ​2048​​ ​layers
​ ​ ​Maximum​​ ​Layered​​ ​2D​​ ​Texture​​ ​Size​,​ ​(​num​)​ ​layers​ ​ ​2D​=(​16384​,​ ​16384​),​​ ​2048​​ ​layers
​ ​ ​Total​​ ​amount​ ​of​ ​constant​ ​memory​: 65536​​ ​bytes
​ ​ ​Total​​ ​amount​ ​of​ ​shared​ ​memory​ ​per​ ​block​: 49152​​ ​bytes
​ ​ ​Total​​ ​number​ ​of​ ​registers​ ​available​ ​per​ ​block​:​ ​32768
​ ​ ​Warp​​ ​size​: 32
​ ​ ​Maximum​​ ​number​ ​of​ ​threads​ ​per​ ​multiprocessor​:​ ​ ​1536
​ ​ ​Maximum​​ ​number​ ​of​ ​threads​ ​per​ ​block​: 1024
​ ​ ​Max​​ ​dimension​ ​size​ ​of​ ​a​ ​thread​ ​block​ ​(​x​,​y​,​z​):​​ ​(​1024​,​ ​1024​,​ ​64)
​ ​ ​Max​​ ​dimension​ ​size​ ​of​ ​a​ ​grid​ ​size (​x​,​y​,​z​):​​ ​(​65535​,​ ​65535​,​ ​65535)
​ ​ ​Maximum​​ ​memory​ ​pitch​: 2147483647​​ ​bytes
​ ​ ​Texture​​ ​alignment​: 512​​ ​bytes
​ ​ ​Concurrent​​ ​copy​ ​and​​ ​kernel​ ​execution​: Yes​​ ​with​​ ​1​ ​copy​ ​engine​(​s)
​ ​ ​Run​​ ​time​ ​limit​ ​on​ ​kernels​: Yes
​ ​ ​Integrated​​ ​GPU​ ​sharing​ ​Host​​ ​Memory​: No
​ ​ ​Support​​ ​host​ ​page​-​locked​ ​memory​ ​mapping​: Yes
​ ​ ​Alignment​​ ​requirement​ ​for​​ ​Surfaces​: Yes
Martínez,​ ​Rodríguez​ ​ ​13

​ ​ ​Device​​ h ​ as​ ​ECC​ ​support​: Disabled


​ ​ ​Device​​ s ​ upports​ ​Unified​​ ​Addressing​​ ​(​UVA​): Yes
​ ​ ​Device​​ P ​ CI​ ​Domain​​ ​ID​ ​/​ ​Bus​​ ​ID​ ​/​ ​location​ ​ID​:​ ​ ​ ​0​ ​/​ ​4​ ​/​ ​0

Cámara​ ​web

Para transmitir video en tiempo real, se utilizó una cámara web QuickCam Orbit AF de la marca
Logithech​ ​(ver​ ​figura​ ​X).

Figura​ ​X.​ ​Cámara​ ​web​ ​utilizada​ ​para​ ​la​ ​obtención​ ​de​ ​video​ ​en​ ​tiempo​ ​real​ ​para​ ​la​ ​aplicación​ ​de​ ​detección​ ​de​ ​objetos.
Martínez,​ ​Rodríguez​ ​ ​14

Código​ ​fuente

El código utilizado fue YOLO (Revisar anexo 1), un algoritmo de detección de objetos que puede
ser implementado en cualquier lenguaje. En este caso se implementó en C, para realizarlo en
paralelo. Utiliza una red neuronal que analiza la imagen completa para dividirla en regiones las cuales
de​ ​vuelven​ ​los​ ​cuadros​ ​de​ ​predicción​ ​a​ ​las​ ​que​ ​al​ ​final​ ​se​ ​les​ ​agrega​ ​un​ ​porcentaje​ ​de​ ​acierto.
Antes de realizar cualquier modificación se corrió el programa en dos versiones: la primera fue
utilizando​ ​el​ ​CPU,​ ​la​ ​segunda​ ​con​ ​los​ ​GPUS

Figura​ ​8.1

Figura​ ​8.2

En la figura 8.1 se puede observar que detectar una imagen estática sencilla se tarda 13.69
segundos, mientras que la figura 8.2 demuestra que esa misma tarea la realiza en menos de un
segundo.​ ​Es​ ​decir,​ ​es​ ​16​ ​veces​ ​más​ ​rápido.

Figura​ ​8.3
Martínez,​ ​Rodríguez​ ​ ​15

En la figura 8.3 se puede observar el resultado que da, el algoritmo de detección de objetos que
se​ ​encontró.

Figura​ ​8.4

En la figura 8.3 se puede observar de manera gráfica, cómo funciona el algoritmo y cómo detecta
el objeto en la imagen. Se utiliza una red neuronal que analiza toda la imagen generando áreas de
detección. En la figura 8.4 se muestra como se ve todo el programa original al correrse utilizando los
GPUS.

Figura​ ​8.4
Martínez,​ ​Rodríguez​ ​ ​16

Este modelo, a diferencia de los papers encontrados, no se entrenó de manera personal, es decir,
estaba ya previamente entrenado. Se utilizó el modelo Darknet entrenado a partir del algoritmo
YOLO.

Cambios​ ​en​ ​el​ ​código

Para agregar al resultado del algoritmo, la ubicación de los objetos, se necesitaron realizar ciertos
cambios​ ​en​ ​el​ ​código.

​ ​ r ​ gb​[​0​]​ ​=​ ​red;


​ ​ ​rgb​[​1​]​ ​=​ ​green;
​ ​ ​rgb​[​2​]​ ​=​ ​blue;
​ ​ ​box​ ​b​ ​=​ ​boxes​[​i​];

​ ​ ​/*​ ​=========​ ​added​ ​on​ ​3-nov-17​ ​by​ ​ARG​ ​&​ ​EMM​ =


​ ============​ ​*/
​ ​ ​/*​ ​Aquí​ ​se​ ​imprimirá​ ​la​ ​posición​ ​del​ ​objeto​ r ​ especto​ ​al​ ​eje​ ​X​ ​y​ ​Y​ ​*/
​ ​ ​printf​(​"Object​ ​position​ ​(center)​ ​->​ ​X:​ ​%.2f​ Y ​ :​ ​%.2f\n"​,​ ​b​.​w​,​ ​b​.​h​);

​ ​ ​/*​ ​variable​ ​temporal​ ​*/


​ ​ ​char​​ ​tmpBuffx​[​4​],​​ ​tmpBuffy​[​4​];

​ ​ ​/*​ ​Se​ ​genera​ ​una​ ​variable​ ​en​ ​la​ ​que​ ​se​ ​agregaran​ ​las​ ​coordenadas​ ​del​ ​objeto​ ​*/
​ ​ ​char​​ ​*​imLabel​ ​=​ ​malloc​(​strlen​(​names​[​class​])​​ ​+​ ​strlen​(​"​ ​x:"​)​ ​+​ ​strlen​(​tmpBuffx​)​ ​+
​ ​ ​strlen​(​"​ ​y:"​)​ ​+​ ​strlen​(​tmpBuffy​)​ ​+​ ​1​);
​ ​ ​sprintf​(​tmpBuffx​,​ ​"%.1f"​,​ ​b​.​x​);
​ ​ ​sprintf​(​tmpBuffy​,​ ​"%.1f"​,​ ​b​.​y​);

​ ​ ​ ​/*​ ​El​ ​nombre​ ​de​ ​la​ ​clase​ ​y​ ​las​ ​coordenadas​ ​del​ ​objeto​ ​se​ ​almacenan​ ​en​ ​imLabel​ ​*/
​ ​ ​ ​strcpy​(​imLabel​,​ ​names​[​class​]);
​ ​ ​ ​/*​ ​Coordenada​ ​x​ ​*/
​ ​ ​ ​strcat​(​imLabel​,​ ​"​ ​x:"​);
​ ​ ​ ​strcat​(​imLabel​,​ ​tmpBuffx​);
​ ​ ​ ​/*​ ​Coordenada​ ​y​ ​*/
​ ​ ​ ​strcat​(​imLabel​,​ ​"​ ​y:"​);
​ ​ ​ ​strcat​(​imLabel​,​ ​tmpBuffy​);

​ ​ ​ ​/*​ ​=========​ ​added​ ​on​ ​3-nov-17​ ​by​ ​ARG​ ​&​ ​EMM​ ​=============​ ​*/

​ ​ ​ ​int​​ ​left​ ​ ​=​ ​(​b​.​x​-​b​.​w​/​2.​)*​im​.​w;


​ ​ ​ ​int​​ ​right​ ​=​ ​(​b​.​x​+​b​.​w​/​2.​)*​im​.​w;
​ ​ ​ ​int​​ ​top​ ​ ​ ​=​ ​(​b​.​y​-​b​.​h​/​2.​)*​im​.​h;
​ ​ ​ ​int​​ ​bot​ ​ ​ ​=​ ​(​b​.​y​+​b​.​h​/​2.​)*​im​.​h;

​ ​ ​ ​if​(​left​ ​<​ ​0​)​ ​left​ ​=​ ​0;


​ ​ ​ ​if​(​right​ ​>​ ​im​.​w​-​1​)​ ​right​ ​=​ ​im​.​w​-​1;
​ ​ ​ ​if​(​top​ ​<​ ​0​)​ ​top​ ​=​ ​0;
​ ​ ​ ​if​(​bot​ ​>​ ​im​.​h​-​1​)​ ​bot​ ​=​ ​im​.​h​-​1;

​ ​ ​ d ​ raw_box_width​(​im​,​ ​left​,​ ​top​,​ ​right​,​ ​bot​,​ ​width​,​ ​red​,​ ​green​,​ ​blue​);


​ ​ ​ ​if​​ ​(​alphabet​)​ ​{

​ ​ ​ ​/*​ ​Se​ ​manda​ ​a​ ​imprimir​ ​la​ ​etiqueta​ ​imLabel​ ​en​ ​el​ ​cuadro​ ​del​ ​objeto​ ​detectado​ ​*/
​ ​ ​ ​image​ ​label​ ​=​ ​get_label​(​alphabet​,​ ​imLabel​,​ ​(​im​.​h​*.​03​)/​10​);
​ ​ ​ ​draw_label​(​im​,​ ​top​ ​+​ ​width​,​ ​left​,​ ​label​,​ ​rgb​);
​ ​ ​ ​free_image​(​label​);
​ ​ ​ ​free​(​imLabel​);
​ ​ ​ ​}
Martínez,​ ​Rodríguez​ ​ ​17

​ ​ ​ ​if​​ ​(​masks​){
​ ​ ​ ​image​ ​mask​ ​=​ ​float_to_image​(​14​,​ ​14​,​ ​1​,​ ​masks​[​i​]);
​ ​ ​ ​image​ ​resized_mask​ ​=​ ​resize_image​(​mask​,​ ​b​.​w​*​im​.​w​,​ ​b​.​h​*​im​.​h​);
​ ​ ​ ​image​ ​tmask​ ​=​ ​threshold_image​(​resized_mask​,​ ​.​5​);
​ ​ ​ ​embed_image​(​tmask​,​ ​im​,​ ​left​,​ ​top​);
​ ​ ​ ​free_image​(​mask​);
​ ​ ​ ​free_image​(​resized_mask​);
​ ​ ​ ​free_image​(​tmask​);
​ ​ ​ ​ }

Resultados​ ​obtenidos

Haciendo las modificaciones mencionadas anteriormente, se logró agregar en el código la


localización​ ​del​ ​objeto,​ ​en​ ​cuanto​ ​a​ ​la​ ​posición​ ​x​ ​e​ ​y​ ​dentro​ ​de​ ​la​ ​imagen​ ​que​ ​captura​ ​la​ ​videocámara.

Figura​ ​9

En la figura 9 se demuestra el resultado de los cambios realizados. Al cuadro que detecta el objeto
se imprime la etiqueta de la posición de acuerdo al campo de visión, en este caso la cámara web de
la laptop. Las coordenadas por lo tanto, las toma en dos dimensiones siendo el punto de partida u
origen, el lado superior izquierdo de la pantalla en donde se muestre la imagen. El video obtenido de
la cámara web se mostró a una velocidad de 1.4 fps, la cuál era la capacidad máxima permitida por la
GPU.
Martínez,​ ​Rodríguez​ ​ ​18

Figura​ ​9.2

En la figura 9.2 se muestra el resultado del profiler generado durante 10 segundos de operación
del programa. En éste se muestran las operaciones ejecutadas por la GPU y el tiempo de cada una
de ellas. Por ejemplo, las operaciones de memcpy se ejecutaron en un total de 813 ms con un total
de 511 invocaciones. El total de bytes utilizados fueron 1.257 GB de memoria a una tasa de
transferencia​ ​de​ ​1,544​ ​GB​ ​por​ ​segundo.

Resultado​ ​de​ ​hipótesis


1. Se logra predecir el objeto ya en qué posición se encuentra dentro del campo de visión, más
no​ ​se​ ​ha​ ​logrado​ ​aún​ ​determinar​ ​la​ ​distancia​ ​a​ ​la​ ​que​ ​se​ ​encuentra​ ​comparado​ ​a​ ​cámara.
2. El algoritmo corre efectivamente en tiempo real. Como se menciona anteriormente en la
figura 9, se compara correctamente qué objeto está viendo y en qué posición está utilizando
una​ ​cámara​ ​en​ ​tiempo​ ​real.
Martínez,​ ​Rodríguez​ ​ ​19

Conclusiones

Durante el desarrollo de este trabajo se aplicaron los conocimientos aprendidos durante la materia
de Computo Paralelo para entender el código del proyecto de detección de objetos elegido y poder
realizar su implementación en la tarjeta GPU que teníamos disponible. Para ello se realizó la
instalación de los drivers Cuda en su versión 8.0 y también las librerías de OpenGL que utiliza la
aplicación​ ​para​ ​poder​ ​mostrar​ ​los​ ​resultados​ ​en​ ​el​ ​video​ ​en​ ​tiempo​ ​real.
Si bien los resultados mostrados se corrieron a una velocidad de 1.4 fps, esto se debió a que la
capacidad de la GPU elegida no era la óptima para este algoritmo y por lo tanto no significa que éste
no posea el performance esperado, el cual fue probado en una GPU de mayores prestaciones (Titan
X).
Nuestra aportación para este proyecto fue agregarle la localización del objeto en la imagen de
acuerdo a su posición en el eje X y Y respecto a un punto origen (0,0) sobre la esquina superior
izquierda del área de visión de la cámara. Si bien faltaría información de profundidad para detectar
profundidad,​ ​esto​ ​puede​ ​agregarse​ ​fácilmente​ ​por​ ​medio​ ​de​ ​sensores.

Fortalezas

Este es un código que es ya implementado en varias versiones y la librería con la que cuenta es
tan robusta que puede detectar cualquier objeto. Una de las fortalezas de este algoritmo es que se
puede implementar en varios lenguajes, y la librería tiene distintas versiones de modo que se puede
implementar​ ​según​ ​la​ ​capacidad​ ​que​ ​se​ ​tenga​ ​en​ ​el​ ​Hardware.

Debilidades

Se necesita un equipo igual de robusto que la base de datos, de lo contrario la librería saturaría la
memoria​ ​y​ ​no​ ​podrá​ ​correr​ ​el​ ​programa.

Trabajo​ ​a​ ​futuro

Si bien el algoritmo utilizado permite detectar objetos en tiempo real y conocer su ubicación en el
campo de visión de la cámara, puede agregarse información acerca de la profundidad para
determinar la distancia al objeto y mejorar con ello la información para el sistema ADAS. También
sería importante utilizar una GPU con mayores prestaciones para poder correr el algoritmo a una
velocidad​ ​mayor​ ​a​ ​la​ ​alcanzada​ ​por​ ​nuestra​ ​GPU​ ​(1.4​ ​fps)
Martínez,​ ​Rodríguez​ ​ ​20

Diccionario

Adas

Advanced Driver Assistance Systems, son los algoritmos que ayudan al conductor a manejar un
carro de manera más segura al detectar peligros en el camino, reducir la velocidad en caso de una
posible​ ​colisión​ ​y​ ​apoyo​ ​en​ ​los​ ​puntos​ ​ciegos,​ ​entre​ ​otras​ ​cosas.
Los algoritmos están diseñados para entender y aprender del entorno en el que el carro está
rodeado, para de esta manera poder predecir futuras ocurrencias durante el trayecto. Es necesario
que​ ​estos​ ​se​ ​corran​ ​en​ ​tiempo​ ​real,​ ​por​ ​tal​ ​motivo​ ​se​ ​utiliza​ ​el​ ​computo​ ​paralelo.
Direct​ ​Imitation​ ​Learning
El buen manejo que se aprenderá se basa en el cumplimiento de dos cosas: mantener el carro en
el carril y manejar sin cambios bruscos. Estos se pueden medir dependiendo del cambio de
aceleración o número de cambios de direcciones. (Innocenti, Linden, Panahandeh, Sevensson,
Mohammadiha,​ ​2017)​ ​(2).
Sistema​ ​de​ ​prevención​ ​de​ ​colisiones
Este algoritmo entra en el frenado y disminución de la velocidad del carro cuando detecta algún
objeto adelante, el cambio repentino de velocidad de otros conductores, detectar objetos más allá de
la visión en climas difíciles (Kristen Hopper, 2016) Con este algoritmo se detectan tanto la velocidad
de​ ​los​ ​objetos​ ​como​ ​la​ ​dirección​ ​hacía​ ​la​ ​que​ ​van.
Detector​ ​de​ ​carril
Algoritmo utilizado para detectar que el automóvil este en el carril adecuado y cuando este
comienza a desviarse del mismo. Utiliza una cámara para detectar la anchura del carril, el ancho del
carro,​ ​las​ ​medidas​ ​de​ ​las​ ​curvas,​ ​la​ ​orientación​ ​del​ ​carro,​ ​y​ ​los​ ​caminos​ ​laterales.​ ​Lussereau,2015)
En este algoritmo, se le da una anchura al carril y al vehiculo de manera que este último tenga que
estar a la mitad de la medida del primero. (Innocenti, Linden, Panahandeh, Sevensson,
Mohammadiha,​ ​2017)​ ​(2).

Cadena​ ​de​ ​efectos​ ​en​ ​los​ ​vehículos​ ​autónomos.

Herramientas​ ​de​ ​entrada​ ​de​ ​información:​ ​cámara,​ ​sensores,​ ​radar,​ ​mapa​ ​GPS
Percepción: Generación de datos a través de la entrada de información acerca de la localización,
el​ ​ambiente,​ ​el​ ​procesamiento​ ​de​ ​datos​ ​y​ ​el​ ​aprendizaje​ ​de​ ​datos.
Aplicación:​ ​Se​ ​planea​ ​la​ ​trayectoria.​ ​Apoyo​ ​en​ ​la​ ​toma​ ​de​ ​decisiones.​ ​Control​ ​de​ ​funciones.
Acciones realizadas: El cambio de velocidad, la maquina de transmisión, los frenos, cambios de
dirección.
Martínez,​ ​Rodríguez​ ​ ​21

Cuda

Es una arquitectura desarrollada por NVIDIA para el procesamiento en paralelo, de esta manera
aumentar el rendimiento de los cálculos realizados. Esta plataforma cuenta con extensiones en
C/C++​ ​para​ ​su​ ​implementación.

GPU

Es la unidad de procesamiento gráfico compuesta de muchos cores que aumenta la capacidad del
procesamiento​ ​en​ ​paralelo.

Nvidia

DAVE​ ​–​ ​DAVE​ ​2


Nvidia para construir un sistema de manejo autónomo en vías públicas. Se necesitaba una
manera de codificarlo sin que fuera secuencial y sin la necesidad de tener un número infiinito de
condicionales​ ​pues​ ​es​ ​un​ ​ambiente​ ​en​ ​el​ ​que​ ​la​ ​aleatoriedad​ ​predomina.
Se desarrolló la plataforma DRIVE, en la que el desarrollo como la implementación de un carro
autónomo pueden acelerarse. Esta también permite que el procesamiento de datos e información que
recibe la plataforma sea en tiempo real, que a su vez da oportunidad de que la maquina aprenda del
conductor y su entorno para predecir comportamientos. Este comportamiento es posible gracias a
que se combina tecnología de aprendizaje profundo y procesamiento paralelo. Además de Nvidia
DIVE PX se utilizó reconociento de patrones y deep learning ediante la entrada información en
formato de video. Estos programas sirvieron a su vez para desarrollara programas más potentes
como​ ​el​ ​DARPA​ ​Learning​ ​Applied​ ​to​ ​Ground​ ​Robotics”.
Se​ ​utilizan​ ​tres​ ​cámaras​ ​para​ ​aprender​ ​del​ ​conductor​ ​y​ ​de​ ​los​ ​errores.

OpcnCV

Es una librería de código abierto desarrollada originalmente por Intel para aplicaciones que
requieren​ ​visión​ ​computacional​ ​en​ ​tiempo-real.
Martínez,​ ​Rodríguez​ ​ ​22

Bibliografía

Christopher Innocenti∗, Henrik Linde ́n∗, Ghazaleh Panahandeh, Lennart Svensson, Nasser
Mohammadiha. (2017). Imitation Learning for Vision-based Lane Keeping Assistance. 15 de
septiembre​ ​del​ ​2017,​ ​de​ ​arXiv.org​ ​Sitio​ ​web:​ ​https://arxiv.org/pdf/1709.03853.pdf
dSpace. (2017). Typical Setup for Prototyping ADAS and Automated Driving Functions. Octubre del
2017, de dSpace Sitio web:
https://www.dspace.com/en/inc/home/applicationfields/our_solutions_for/driver_assistance_system
s/rapid_prototyping/typical_set-up_for_prototyping.cfm
Jerome Lussereau, Proc ́opio Stein, Jean-Alix David, Lukas Rummelhard, Amaury Ne- gre, et al..
Integration of ADAS algorithm in a Vehicle Prototype. IEEE International Workshop on Advanced
Robotics and its Social Impacts ARSO 2015, Jul 2015, LYON, France. IEEE International
Workshop on Advanced Robotics and its Social Impacts, 2015, <http://arso2015.inria.fr/>.
<hal-01212431>
Joseph Redmon, Ali Farhadi. (2016). YOLO: Real-Time Object Detection. Septiembre del 2017, de
Darknet​ ​Sitio​ ​web:​ ​https://pjreddie.com/darknet/yolo/
Kristen Hopper. (2016). Collision Avoidance Systems. 31 de agosto del 2016, de Micron Sitio web:
https://www.micron.com/about/blogs/2016/september/collision-avoidance-systems
Mariusz Bojarski, Davide Del Testa, Daniel Dworakowski, Bernhard Firner, Beat Flepp, Prasoon
Goyal, Lawrence D. Jackel, Mathew Monfort, Urs Muller, Jiakai Zhang, Xin Zhang, Jake Zhao.
(2016). End to End Learning for Self-Driving Cars. Octubre del 2016, de NVIDIA Sitio web:
http://images.nvidia.com/content/tegra/automotive/images/2016/solutions/pdf/end-to-end-dl-using-p
x.pdf
Nvidia. (2017). Asistencia al conductor conduce de forma más inteligente. conduce de forma más
segura. 29 de agosto del 2017, de Nvidia Sitio web:
http://la.nvidia.com/object/advanced-driver-assistance-systems-la.html
Nvidia. (2017). The AI Car Computer for Autonomous Driving. 20 de agosto del 2017, de Nvidia Sitio
web:​​ ​http://www.nvidia.com/object/drive-px.html 
Nvidia. (2017). ¿QUÉ ES LA COMPUTACIÓN ACELERADA POR GPU?. Septiembre del 2017, de
Nvidia​ ​Sitio​ ​web:​ ​http://la.nvidia.com/object/what-is-gpu-computing-la.html
OBJECT DETECTION AND CLASSIFICATION FOR AUTONOMOUS VEHICLES. (2012). US
8,195,394B1. ​ ​Patente.
Organización Mundial de la Salud, Global status report on road safety 2015, 2015. Recuperado el
10/10/2017​ ​de:​ ​http://www.who.int/mediacentre/factsheets/fs358/en/
Salman, Yasir Dawood. (2017). Distance measurement for self-driving cars using stereo camera. UNIV
UTARI MALAYSIA-UUM, COLL ARTS & SCI, INFOR TECHNOL BLDG, SINTOK, KEDAH 06010,
MALAYSIA,​ ​1,​ ​3.​ ​31​ ​de​ ​agosto​ ​del​ ​2017,​ ​De​ ​Web​ ​of​ ​science​ ​Base​ ​de​ ​datos.
Martínez,​ ​Rodríguez​ ​ ​23

Sistema Estatal y Municipal de Bases de Datos. INEGI. Recuperado el 11/10/2017 de :


http://sc.inegi.org.mx/cobdem/index.jsp
Tech Insider. (15 de junio 2016). 10 million self-driving cars will be on the road by 2020. 29 de agosto
del 2017, de Business Insider Sitio web:
http://www.businessinsider.com/report-10-million-self-driving-cars-will-be-on-the-road-by-2020-201
5-5-6
Martínez,​ ​Rodríguez​ ​ ​24

Anexo​ ​1.​ ​Código​ ​de​ ​operaciones​ ​ejecutadas​ ​en​ ​la​ ​GPU

im2col_kernels.cu

#include​​ ​"cuda_runtime.h"
#include​​ ​"curand.h"
#include​​ ​"cublas_v2.h"

extern​​ ​"C"​​ ​{
#include​​ ​"im2col.h"
#include​​ ​"cuda.h"
}

​ rc:​ ​https://github.com/BVLC/caffe/blob/master/src/caffe/util/im2col.cu
//​ s
//​ Y​ ou​ ​may​ ​also​ ​want​ ​to​ ​read:​ ​https://github.com/BVLC/caffe/blob/master/LICENSE

__global__​ ​void​​ ​im2col_gpu_kernel​(​const​​ ​int​​ ​n​,​ ​const​​ ​float​*​ ​data_im,


const​​ ​int​​ ​height​,​ ​const​​ ​int​​ ​width​,​ ​const​​ ​int​​ ​ksize,
const​​ ​int​​ ​pad,
const​​ ​int​​ ​stride,
const​​ ​int​​ ​height_col​,​ ​const​​ ​int​​ ​width_col,
float​​ ​*​data_col​)​ ​{
int​​ ​index​ ​=​ ​blockIdx​.​x​*​blockDim​.​x​+​threadIdx​.​x;
for​(;​​ ​index​ ​<​ ​n​;​ ​index​ ​+=​​ ​blockDim​.​x​*​gridDim​.​x​){
int​​ ​w_out​ ​=​ ​index​ ​%​ ​width_col;
int​​ ​h_index​ ​=​ ​index​ ​/​ ​width_col;
int​​ ​h_out​ ​=​ ​h_index​ ​%​ ​height_col;
int​​ ​channel_in​ ​=​ ​h_index​ ​/​ ​height_col;
int​​ ​channel_out​ ​=​ ​channel_in​ ​*​ ​ksize​ ​*​ ​ksize;
int​​ ​h_in​ ​=​ ​h_out​ ​*​ ​stride​ ​-​ ​pad;
int​​ ​w_in​ ​=​ ​w_out​ ​*​ ​stride​ ​-​ ​pad;
float​*​ ​data_col_ptr​ ​=​ ​data_col;
data_col_ptr​ ​+=​​ ​(​channel_out​ ​*​ ​height_col​ ​+​ ​h_out​)​ ​*​ ​width_col​ ​+​ ​w_out;
const​​ ​float​*​ ​data_im_ptr​ ​=​ ​data_im;
data_im_ptr​ ​+=​​ ​(​channel_in​ ​*​ ​height​ ​+​ ​h_in​)​ ​*​ ​width​ ​+​ ​w_in;
for​​ ​(​int​​ ​i​ ​=​ ​0​;​ ​i​ ​<​ ​ksize​;​ ​++​i​)​ ​{
for​​ ​(​int​​ ​j​ ​=​ ​0​;​ ​j​ ​<​ ​ksize​;​ ​++​j​)​ ​{
int​​ ​h​ ​=​ ​h_in​ ​+​ ​i;
int​​ ​w​ ​=​ ​w_in​ ​+​ ​j;

*​data_col_ptr​ ​=​ ​(​h​ ​>=​​ ​0​ ​&&​​ ​w​ ​>=​​ ​0​ ​&&​​ ​h​ ​<​ ​height​ ​&&​​ ​w​ ​<​ ​width​)​ ​?
data_im_ptr​[​i​ ​*​ ​width​ ​+​ ​j​]​ ​:​ ​0;

//*data_col_ptr​ ​=​ ​data_im_ptr[ii​ ​*​ ​width​ ​+​ ​jj];

data_col_ptr​ ​+=​​ ​height_col​ ​*​ ​width_col;


}
}
}
}

void​​ ​im2col_gpu​(​float​​ ​*​im,


int​​ ​channels​,​ ​int​​ ​height​,​ ​int​​ ​width,
Martínez,​ ​Rodríguez​ ​ ​25

int​​ ​ksize​,​ ​int​​ ​stride​,​ ​int​​ ​pad​,​ ​float​​ ​*​data_col​){


//​ ​We​ ​are​ ​going​ ​to​ ​launch​ ​channels​ ​*​ ​height_col​ ​*​ ​width_col​ ​kernels,​ ​each
//​ ​kernel​ ​responsible​ ​for​ ​copying​ ​a​ ​single-channel​ ​grid.
int​​ ​height_col​ ​=​ ​(​height​ ​+​ ​2​ ​*​ ​pad​ ​-​ ​ksize​)​ ​/​ ​stride​ ​+​ ​1;
int​​ ​width_col​ ​=​ ​(​width​ ​+​ ​2​ ​*​ ​pad​ ​-​ ​ksize​)​ ​/​ ​stride​ ​+​ ​1;
int​​ ​num_kernels​ ​=​ ​channels​ ​*​ ​height_col​ ​*​ ​width_col;
im2col_gpu_kernel​<<<(​num_kernels​+​BLOCK​-​1​)/​BLOCK,
BLOCK​>>>(
num_kernels​,​ ​im​,​ ​height​,​ ​width​,​ ​ksize​,​ ​pad,
stride​,​ ​height_col,
width_col​,​ ​data_col​);
}

activation_kernels.cu

#include​​ ​"cuda_runtime.h"
#include​​ ​"curand.h"
#include​​ ​"cublas_v2.h"

extern​​ ​"C"​​ ​{
#include​​ ​"activations.h"
#include​​ ​"cuda.h"
}

__device__​ ​float​​ ​lhtan_activate_kernel​(​float​​ x ​ )


{
if​(​x​ ​<​ ​0​)​ ​return​​ ​.​001f​*​x;
if​(​x​ ​>​ ​1​)​ ​return​​ ​.​001f​*(​x​-​1.f​)​ ​+​ ​1.f;
return​​ ​x;
}
__device__​ ​float​​ ​lhtan_gradient_kernel​(​float​​ x ​ )
{
if​(​x​ ​>​ ​0​ ​&&​​ ​x​ ​<​ ​1​)​ ​return​​ ​1;
return​​ ​.​001;
}

__device__​ ​float​​ ​hardtan_activate_kernel​(​float​​ ​x)


{
if​​ ​(​x​ ​<​ ​-​1​)​ ​return​​ ​-​1;
if​​ ​(​x​ ​>​ ​1​)​ ​return​​ ​1;
return​​ ​x;
}
__device__​ ​float​​ ​linear_activate_kernel​(​float​​ ​x​){​return​​ ​x​;}
__device__​ ​float​​ ​logistic_activate_kernel​(​float​​ ​x​){​return​​ ​1.f​/(​1.f​​ ​+​ ​expf​(-​x​));}
__device__​ ​float​​ ​loggy_activate_kernel​(​float​​ ​x​){​return​​ ​2.f​/(​1.f​​ ​+​ ​expf​(-​x​))​​ ​-​ ​1​;}
__device__​ ​float​​ ​relu_activate_kernel​(​float​​ ​x​){​return​​ ​x​*(​x​>​0​);}
__device__​ ​float​​ ​elu_activate_kernel​(​float​​ ​x​){​return​​ ​(​x​ ​>=​​ ​0​)*​x​ ​+​ ​(​x​ ​<​ ​0​)*(​expf​(​x​)-​1​);}
__device__​ ​float​​ ​relie_activate_kernel​(​float​​ ​x​){​return​​ ​(​x​>​0​)​ ​?​ ​x​ ​:​ ​.​01f​*​x​;}
__device__​ ​float​​ ​ramp_activate_kernel​(​float​​ ​x​){​return​​ ​x​*(​x​>​0​)+.​1f​*​x​;}
__device__​ ​float​​ ​leaky_activate_kernel​(​float​​ ​x​){​return​​ ​(​x​>​0​)​ ​?​ ​x​ ​:​ ​.​1f​*​x​;}
Martínez,​ ​Rodríguez​ ​ ​26

__device__​ ​float​​ ​tanh_activate_kernel​(​float​​ ​x​){​return​​ ​(​2.f​/(​1​ ​+​ ​expf​(-​2​*​x​))​​ ​-​ ​1​);}


__device__​ ​float​​ ​plse_activate_kernel​(​float​​ ​x)
{
if​(​x​ ​<​ ​-​4​)​ ​return​​ ​.​01f​​ ​*​ ​(​x​ ​+​ ​4​);
if​(​x​ ​>​ ​4​)​ ​ ​return​​ ​.​01f​​ ​*​ ​(​x​ ​-​ ​4​)​ ​+​ ​1;
return​​ ​.​125f​*​x​ ​+​ ​.​5f;
}
__device__​ ​float​​ ​stair_activate_kernel​(​float​​ ​x)
{
int​​ ​n​ ​=​ ​floorf​(​x​);
if​​ ​(​n​%​2​ ​==​​ ​0​)​ ​return​​ ​floorf​(​x​/​2​);
else​​ ​return​​ ​(​x​ ​-​ ​n​)​ ​+​ ​floorf​(​x​/​2​);
}

__device__​ ​float​​ ​hardtan_gradient_kernel​(​float​​ ​x)


{
if​​ ​(​x​ ​>​ ​-​1​ ​&&​​ ​x​ ​<​ ​1​)​ ​return​​ ​1;
return​​ ​0;
}
__device__​ ​float​​ ​linear_gradient_kernel​(​float​​ ​x​){​return​​ ​1​;}
__device__​ ​float​​ ​logistic_gradient_kernel​(​float​​ ​x​){​return​​ ​(​1​-​x​)*​x​;}
__device__​ ​float​​ ​loggy_gradient_kernel​(​float​​ ​x)
{
float​​ ​y​ ​=​ ​(​x​+​1​)/​2;
return​​ ​2​*(​1​-​y​)*​y;
}
__device__​ ​float​​ ​relu_gradient_kernel​(​float​​ ​x​){​return​​ ​(​x​>​0​);}
__device__​ ​float​​ ​elu_gradient_kernel​(​float​​ ​x​){​return​​ ​(​x​ ​>=​​ ​0​)​ ​+​ ​(​x​ ​<​ ​0​)*(​x​ ​+​ ​1​);}
__device__​ ​float​​ ​relie_gradient_kernel​(​float​​ ​x​){​return​​ ​(​x​>​0​)​ ​?​ ​1​ ​:​ ​.​01f​;}
__device__​ ​float​​ ​ramp_gradient_kernel​(​float​​ ​x​){​return​​ ​(​x​>​0​)+.​1f​;}
__device__​ ​float​​ ​leaky_gradient_kernel​(​float​​ ​x​){​return​​ ​(​x​>​0​)​ ​?​ ​1​ ​:​ ​.​1f​;}
__device__​ ​float​​ ​tanh_gradient_kernel​(​float​​ ​x​){​return​​ ​1​-​x​*​x​;}
__device__​ ​float​​ ​plse_gradient_kernel​(​float​​ ​x​){​return​​ ​(​x​ ​<​ ​0​ ​||​​ ​x​ ​>​ ​1​)​ ​?​ ​.​01f​​ ​:​ ​.​125f​;}
__device__​ ​float​​ ​stair_gradient_kernel​(​float​​ ​x)
{
if​​ ​(​floorf​(​x​)​ ​==​​ ​x​)​ ​return​​ ​0;
return​​ ​1;
}

__device__​ ​float​​ ​activate_kernel​(​float​​ ​x​,​ ​ACTIVATION​ ​a)


{
switch​(​a​){
case​​ ​LINEAR:
return​​ ​linear_activate_kernel​(​x​);
case​​ ​LOGISTIC:
return​​ ​logistic_activate_kernel​(​x​);
case​​ ​LOGGY:
return​​ ​loggy_activate_kernel​(​x​);
case​​ ​RELU:
return​​ ​relu_activate_kernel​(​x​);
case​​ ​ELU:
return​​ ​elu_activate_kernel​(​x​);
Martínez,​ ​Rodríguez​ ​ ​27

case​​ ​RELIE:
return​​ ​relie_activate_kernel​(​x​);
case​​ ​RAMP:
return​​ ​ramp_activate_kernel​(​x​);
case​​ ​LEAKY:
return​​ ​leaky_activate_kernel​(​x​);
case​​ ​TANH:
return​​ ​tanh_activate_kernel​(​x​);
case​​ ​PLSE:
return​​ ​plse_activate_kernel​(​x​);
case​​ ​STAIR:
return​​ ​stair_activate_kernel​(​x​);
case​​ ​HARDTAN:
return​​ ​hardtan_activate_kernel​(​x​);
case​​ ​LHTAN:
return​​ ​lhtan_activate_kernel​(​x​);
}
return​​ ​0;
}

__device__​ ​float​​ ​gradient_kernel​(​float​​ ​x​,​ ​ACTIVATION​ ​a)


{
switch​(​a​){
case​​ ​LINEAR:
return​​ ​linear_gradient_kernel​(​x​);
case​​ ​LOGISTIC:
return​​ ​logistic_gradient_kernel​(​x​);
case​​ ​LOGGY:
return​​ ​loggy_gradient_kernel​(​x​);
case​​ ​RELU:
return​​ ​relu_gradient_kernel​(​x​);
case​​ ​ELU:
return​​ ​elu_gradient_kernel​(​x​);
case​​ ​RELIE:
return​​ ​relie_gradient_kernel​(​x​);
case​​ ​RAMP:
return​​ ​ramp_gradient_kernel​(​x​);
case​​ ​LEAKY:
return​​ ​leaky_gradient_kernel​(​x​);
case​​ ​TANH:
return​​ ​tanh_gradient_kernel​(​x​);
case​​ ​PLSE:
return​​ ​plse_gradient_kernel​(​x​);
case​​ ​STAIR:
return​​ ​stair_gradient_kernel​(​x​);
case​​ ​HARDTAN:
return​​ ​hardtan_gradient_kernel​(​x​);
case​​ ​LHTAN:
return​​ ​lhtan_gradient_kernel​(​x​);
}
return​​ ​0;
}
Martínez,​ ​Rodríguez​ ​ ​28

__global__​ ​void​​ ​activate_array_kernel​(​float​​ ​*​x​,​ ​int​​ ​n​,​ ​ACTIVATION​ a ​ )


{
int​​ ​i​ ​=​ ​(​blockIdx​.​x​ ​+​ ​blockIdx​.​y​*​gridDim​.​x​)​ ​*​ ​blockDim​.​x​ ​+​ t​ hreadIdx​.​x;
if​(​i​ ​<​ ​n​)​ ​x​[​i​]​ ​=​ ​activate_kernel​(​x​[​i​],​​ ​a​);
}

__global__​ ​void​​ ​gradient_array_kernel​(​float​​ ​*​x​,​ ​int​​ ​n​,​ ​ACTIVATION​ a ​ ​,​ ​float​​ ​*​delta)
{
int​​ ​i​ ​=​ ​(​blockIdx​.​x​ ​+​ ​blockIdx​.​y​*​gridDim​.​x​)​ ​*​ ​blockDim​.​x​ ​+​ t​ hreadIdx​.​x;
if​(​i​ ​<​ ​n​)​ ​delta​[​i​]​ ​*=​​ ​gradient_kernel​(​x​[​i​],​​ ​a​);
}

extern​​ ​"C"​​ ​void​​ ​activate_array_gpu​(​float​​ ​*​x​,​ ​int​​ n


​ ​,​ ​ACTIVATION​ ​a)
{
activate_array_kernel​<<<​cuda_gridsize​(​n​),​​ B ​ LOCK​>>>(​x​,​ ​n​,​ ​a​);
check_error​(​cudaPeekAtLastError​());
}

extern​​ ​"C"​​ ​void​​ ​gradient_array_gpu​(​float​​ ​*​x​,​ ​int​​ n


​ ​,​ ​ACTIVATION​ ​a​,​ ​float​​ ​*​delta)
{
gradient_array_kernel​<<<​cuda_gridsize​(​n​),​​ B ​ LOCK​>>>(​x​,​ ​n​,​ ​a​,​ ​delta​);
check_error​(​cudaPeekAtLastError​());
}

convolutional_kernels.cu
#include​​ ​"cuda_runtime.h"
#include​​ ​"curand.h"
#include​​ ​"cublas_v2.h"

extern​​ ​"C"​​ ​{
#include​​ ​"convolutional_layer.h"
#include​​ ​"batchnorm_layer.h"
#include​​ ​"gemm.h"
#include​​ ​"blas.h"
#include​​ ​"im2col.h"
#include​​ ​"col2im.h"
#include​​ ​"utils.h"
#include​​ ​"cuda.h"
}

__global__​ ​void​​ ​binarize_kernel​(​float​​ ​*​x​,​ ​int​​ ​n​,​ ​float​​ ​*​binary)


{
int​​ ​i​ ​=​ ​(​blockIdx​.​x​ ​+​ ​blockIdx​.​y​*​gridDim​.​x​)​ ​*​ ​blockDim​.​x​ ​+​ ​threadIdx​.​x;
if​​ ​(​i​ ​>=​​ ​n​)​ ​return;
binary​[​i​]​ ​=​ ​(​x​[​i​]​ ​>=​​ ​0​)​ ​?​ ​1​ ​:​ ​-​1;
}

void​​ ​binarize_gpu​(​float​​ ​*​x​,​ ​int​​ ​n​,​ ​float​​ ​*​binary)


{
binarize_kernel​<<<​cuda_gridsize​(​n​),​​ ​BLOCK​>>>(​x​,​ ​n​,​ ​binary​);
Martínez,​ ​Rodríguez​ ​ ​29

check_error​(​cudaPeekAtLastError​());
}

__global__​ ​void​​ ​binarize_input_kernel​(​float​​ ​*​input​,​ ​int​​ ​n​,​ ​int​​ ​size​,​ ​float​​ ​*​binary)
{
int​​ ​s​ ​=​ ​(​blockIdx​.​x​ ​+​ ​blockIdx​.​y​*​gridDim​.​x​)​ ​*​ ​blockDim​.​x​ ​+​ ​threadIdx​.​x;
if​​ ​(​s​ ​>=​​ ​size​)​ ​return;
int​​ ​i​ ​=​ ​0;
float​​ ​mean​ ​=​ ​0;
for​(​i​ ​=​ ​0​;​ ​i​ ​<​ ​n​;​ ​++​i​){
mean​ ​+=​​ ​fabsf​(​input​[​i​*​size​ ​+​ ​s​]);
}
mean​ ​=​ ​mean​ ​/​ ​n;
for​(​i​ ​=​ ​0​;​ ​i​ ​<​ ​n​;​ ​++​i​){
binary​[​i​*​size​ ​+​ ​s​]​ ​=​ ​(​input​[​i​*​size​ ​+​ ​s​]​ ​>​ ​0​)​ ​?​ ​mean​ ​:​ ​-​mean;
}
}

void​​ ​binarize_input_gpu​(​float​​ ​*​input​,​ ​int​​ ​n​,​ ​int​​ ​size​,​ ​float​​ ​*​binary)


{
binarize_input_kernel​<<<​cuda_gridsize​(​size​),​​ ​BLOCK​>>>(​input​,​ ​n​,​ ​size​,​ ​binary​);
check_error​(​cudaPeekAtLastError​());
}

__global__​ ​void​​ ​binarize_weights_kernel​(​float​​ ​*​weights​,​ ​int​​ ​n​,​ ​int​​ ​size​,​ ​float​​ ​*​binary)
{
int​​ ​f​ ​=​ ​(​blockIdx​.​x​ ​+​ ​blockIdx​.​y​*​gridDim​.​x​)​ ​*​ ​blockDim​.​x​ ​+​ ​threadIdx​.​x;
if​​ ​(​f​ ​>=​​ ​n​)​ ​return;
int​​ ​i​ ​=​ ​0;
float​​ ​mean​ ​=​ ​0;
for​(​i​ ​=​ ​0​;​ ​i​ ​<​ ​size​;​ ​++​i​){
mean​ ​+=​​ ​fabsf​(​weights​[​f​*​size​ ​+​ ​i​]);
}
mean​ ​=​ ​mean​ ​/​ ​size;
for​(​i​ ​=​ ​0​;​ ​i​ ​<​ ​size​;​ ​++​i​){
binary​[​f​*​size​ ​+​ ​i​]​ ​=​ ​(​weights​[​f​*​size​ ​+​ ​i​]​ ​>​ ​0​)​ ​?​ ​mean​ ​:​ ​-​mean;
//binary[f*size​ ​+​ ​i]​ ​=​ ​weights[f*size​ ​+​ ​i];
}
}

void​​ ​binarize_weights_gpu​(​float​​ ​*​weights​,​ ​int​​ ​n​,​ ​int​​ ​size​,​ ​float​​ ​*​binary)


{
binarize_weights_kernel​<<<​cuda_gridsize​(​n​),​​ ​BLOCK​>>>(​weights​,​ ​n​,​ ​size​,​ ​binary​);
check_error​(​cudaPeekAtLastError​());
}

void​​ ​forward_convolutional_layer_gpu​(​convolutional_layer​ ​l​,​ ​network​ ​net)


{
fill_gpu​(​l​.​outputs​*​l​.​batch​,​ ​0​,​ ​l​.​output_gpu​,​ ​1​);
if​(​l​.​binary​){
binarize_weights_gpu​(​l​.​weights_gpu​,​ ​l​.​n​,​ ​l​.​c​/​l​.​groups​*​l​.​size​*​l​.​size​,
l​.​binary_weights_gpu​);
Martínez,​ ​Rodríguez​ ​ ​30

swap_binary​(&​l​);
}

if​(​l​.​xnor​){
binarize_weights_gpu​(​l​.​weights_gpu​,​ ​l​.​n​,​ ​l​.​c​/​l​.​groups​*​l​.​size​*​l​.​size​,
l​.​binary_weights_gpu​);
swap_binary​(&​l​);
binarize_gpu​(​net​.​input_gpu​,​ ​l​.​c​*​l​.​h​*​l​.​w​*​l​.​batch​,​ ​l​.​binary_input_gpu​);
net​.​input_gpu​ ​=​ ​l​.​binary_input_gpu;
}

#ifdef​​ ​CUDNN
float​​ ​one​ ​=​ ​1;
cudnnConvolutionForward​(​cudnn_handle​(),
&​one,
l​.​srcTensorDesc,
net​.​input_gpu,
l​.​weightDesc,
l​.​weights_gpu,
l​.​convDesc,
l​.​fw_algo,
net​.​workspace,
l​.​workspace_size,
&​one,
l​.​dstTensorDesc,
l​.​output_gpu​);

#else
int​​ ​i​,​ ​j;
int​​ ​m​ ​=​ ​l​.​n​/​l​.​groups;
int​​ ​k​ ​=​ ​l​.​size​*​l​.​size​*​l​.​c​/​l​.​groups;
int​​ ​n​ ​=​ ​l​.​out_w​*​l​.​out_h;
for​(​i​ ​=​ ​0​;​ ​i​ ​<​ ​l​.​batch​;​ ​++​i​){
for​(​j​ ​=​ ​0​;​ ​j​ ​<​ ​l​.​groups​;​ ​++​j​){
float​​ ​*​a​ ​=​ ​l​.​weights_gpu​ ​+​ ​j​*​l​.​nweights​/​l​.​groups;
float​​ ​*​b​ ​=​ ​net​.​workspace;
float​​ ​*​c​ ​=​ ​l​.​output_gpu​ ​+​ ​(​i​*​l​.​groups​ ​+​ ​j​)*​n​*​m;

im2col_gpu​(​net​.​input_gpu​ ​+​ ​(​i​*​l​.​groups​ ​+​ ​j​)*​l​.​c​/​l​.​groups​*​l​.​h​*​l​.​w,


l​.​c​/​l​.​groups​,​ ​l​.​h​,​ ​l​.​w​,​ ​l​.​size​,​ ​l​.​stride​,​ ​l​.​pad​,​ ​b​);
gemm_gpu​(​0​,​0​,​m​,​n​,​k​,​1​,​a​,​k​,​b​,​n​,​1​,​c​,​n​);
}
}
#endif

if​​ ​(​l​.​batch_normalize​)​ ​{
forward_batchnorm_layer_gpu​(​l​,​ ​net​);
}​​ ​else​​ ​{
add_bias_gpu​(​l​.​output_gpu​,​ ​l​.​biases_gpu​,​ ​l​.​batch​,​ ​l​.​n​,​ ​l​.​out_w​*​l​.​out_h​);
}

activate_array_gpu​(​l​.​output_gpu​,​ ​l​.​outputs​*​l​.​batch​,​ ​l​.​activation​);


//if(l.dot​ ​>​ ​0)​ ​dot_error_gpu(l);
Martínez,​ ​Rodríguez​ ​ ​31

if​(​l​.​binary​ ​||​​ ​l​.​xnor​)​ ​swap_binary​(&​l​);


}

__global__​ ​void​​ s ​ mooth_kernel​(​float​​ ​*​x​,​ ​int​​ ​n​,​ ​int​​ ​w​,​ ​int​​ ​h​,​ ​int​​ c
​ ​,​ ​int​​ ​size​,​ ​float​​ ​rate​,
float​​ ​*​delta)
{
int​​ ​id​ ​=​ ​(​blockIdx​.​x​ ​+​ ​blockIdx​.​y​*​gridDim​.​x​)​ ​*​ b ​ lockDim​.​x​ ​+​ ​threadIdx​.​x;
if​(​id​ ​>=​​ n​ ​)​ ​return;

int​​ ​j​ ​=​ ​id​ ​%​ w ​ ;


id​ ​/=​​ ​w;
int​​ ​i​ ​=​ ​id​ ​%​ h ​ ;
id​ ​/=​​ ​h;
int​​ ​k​ ​=​ ​id​ ​%​ c ​ ;
id​ ​/=​​ ​c;
int​​ ​b​ ​=​ ​id;

int​​ w
​ _offset​ ​=​ ​-(​size​/​2.f​);
int​​ h​ _offset​ ​=​ ​-(​size​/​2.f​);

int​​ ​out_index​ ​=​ ​j​ ​+​ ​w​*(​i​ ​+​ ​h​*(​k​ ​+​ ​c​*​b​));
int​​ ​l​,​ ​m;
for​(​l​ ​=​ ​0​;​ ​l​ ​<​ ​size​;​ ​++​l​){
for​(​m​ ​=​ ​0​;​ ​m​ ​<​ ​size​;​ ​++​m​){
int​​ ​cur_h​ ​=​ ​h_offset​ ​+​ ​i​ ​+​ ​l;
int​​ ​cur_w​ ​=​ ​w_offset​ ​+​ ​j​ ​+​ ​m;
int​​ ​index​ ​=​ ​cur_w​ ​+​ ​w​*(​cur_h​ ​+​ ​h​*(​k​ ​+​ ​b​*​c​));
int​​ ​valid​ ​=​ ​(​cur_h​ ​>=​​ ​0​ ​&&​​ ​cur_h​ ​<​ ​h​ ​&&
cur_w​ ​>=​​ ​0​ ​&&​​ ​cur_w​ ​<​ ​w​);
delta​[​out_index​]​ ​+=​​ ​valid​ ​?​ ​rate​*(​x​[​index​]​ ​-​ ​x​[​out_index​])​​ ​:​ ​0;
}
}
}

extern​​ ​"C"​​ ​void​​ ​smooth_layer​(​layer​ ​l​,​ ​int​​ ​size​,​ ​float​​ ​rate)


{
int​​ ​h​ ​=​ l ​ ​.​out_h;
int​​ ​w​ ​=​ l ​ ​.​out_w;
int​​ ​c​ ​=​ l ​ ​.​out_c;

size_t​​ ​n​ ​=​ ​h​*​w​*​c​*​l​.​batch;

smooth_kernel​<<<​cuda_gridsize​(​n​),​​ ​BLOCK​>>>(​l​.​output_gpu​,​ ​n​,​ ​l​.​w​,​ ​l​.​h​,​ ​l​.​c​,​ ​size​,


rate​,​ ​l​.​delta_gpu​);
check_error​(​cudaPeekAtLastError​());
}

void​​ ​backward_convolutional_layer_gpu​(​convolutional_layer​ ​l​,​ ​network​ ​net)


{
if​(​l​.​smooth​){
smooth_layer​(​l​,​ ​5​,​ ​l​.​smooth​);
}
constrain_gpu​(​l​.​outputs​*​l​.​batch​,​ ​1​,​ ​l​.​delta_gpu​,​ ​1​);
Martínez,​ ​Rodríguez​ ​ ​32

gradient_array_gpu​(​l​.​output_gpu​,​ ​l​.​outputs​*​l​.​batch​,​ ​l​.​activation​,​ ​l​.​delta_gpu​);

if​(​l​.​batch_normalize​){
backward_batchnorm_layer_gpu​(​l​,​ ​net​);
}​​ ​else​​ ​{
backward_bias_gpu​(​l​.​bias_updates_gpu​,​ ​l​.​delta_gpu​,​ ​l​.​batch​,​ ​l​.​n​,​ ​l​.​out_w​*​l​.​out_h​);
}
float​​ ​*​original_input​ ​=​ ​net​.​input_gpu;

if​(​l​.​xnor​)​ ​net​.​input_gpu​ ​=​ ​l​.​binary_input_gpu;


#ifdef​​ ​CUDNN
float​​ ​one​ ​=​ ​1;
cudnnConvolutionBackwardFilter​(​cudnn_handle​(),
&​one,
l​.​srcTensorDesc,
net​.​input_gpu,
l​.​ddstTensorDesc,
l​.​delta_gpu,
l​.​convDesc,
l​.​bf_algo,
net​.​workspace,
l​.​workspace_size,
&​one,
l​.​dweightDesc,
l​.​weight_updates_gpu​);

if​(​net​.​delta_gpu​){
if​(​l​.​binary​ ​||​​ ​l​.​xnor​)​ ​swap_binary​(&​l​);
cudnnConvolutionBackwardData​(​cudnn_handle​(),
&​one,
l​.​weightDesc,
l​.​weights_gpu,
l​.​ddstTensorDesc,
l​.​delta_gpu,
l​.​convDesc,
l​.​bd_algo,
net​.​workspace,
l​.​workspace_size,
&​one,
l​.​dsrcTensorDesc,
net​.​delta_gpu​);
if​(​l​.​binary​ ​||​​ ​l​.​xnor​)​ ​swap_binary​(&​l​);
if​(​l​.​xnor​)​ ​gradient_array_gpu​(​original_input​,​ ​l​.​batch​*​l​.​c​*​l​.​h​*​l​.​w​,​ ​HARDTAN​,
net​.​delta_gpu​);
}

#else
int​​ m
​ ​ ​=​ l ​ ​.​n​/​l​.​groups;
int​​ n​ ​ ​=​ l ​ ​.​size​*​l​.​size​*​l​.​c​/​l​.​groups;
int​​ k ​ ​ ​=​ l ​ ​.​out_w​*​l​.​out_h;

int​​ ​i​,​ ​j;


Martínez,​ ​Rodríguez​ ​ ​33

for​(​i​ ​=​ ​0​;​ ​i​ ​<​ ​l​.​batch​;​ ​++​i​){


for​(​j​ ​=​ ​0​;​ ​j​ ​<​ ​l​.​groups​;​ ​++​j​){
float​​ ​*​a​ ​=​ ​l​.​delta_gpu​ ​+​ ​(​i​*​l​.​groups​ ​+​ ​j​)*​m​*​k;
float​​ ​*​b​ ​=​ ​net​.​workspace;
float​​ ​*​c​ ​=​ ​l​.​weight_updates_gpu​ ​+​ ​j​*​l​.​nweights​/​l​.​groups;

float​​ ​*​im​ ​=​ ​net​.​input​+(​i​*​l​.​groups​ ​+​ ​j​)*​l​.​c​/​l​.​groups​*​l​.​h​*​l​.​w;

im2col_gpu​(​im​,​ ​l​.​c​/​l​.​groups​,​ ​l​.​h​,​ ​l​.​w,


l​.​size​,​ ​l​.​stride​,​ ​l​.​pad​,​ ​b​);
gemm_gpu​(​0​,​1​,​m​,​n​,​k​,​1​,​a​,​k​,​b​,​k​,​1​,​c​,​n​);

if​(​net​.​delta_gpu​){
if​(​l​.​binary​ ​||​​ ​l​.​xnor​)​ ​swap_binary​(&​l​);
a​ ​=​ ​l​.​weights_gpu​ ​+​ ​j​*​l​.​nweights​/​l​.​groups;
b​ ​=​ ​l​.​delta_gpu​ ​+​ ​(​i​*​l​.​groups​ ​+​ ​j​)*​m​*​k;
c​ ​=​ ​net​.​workspace;

gemm_gpu​(​1​,​0​,​n​,​k​,​m​,​1​,​a​,​n​,​b​,​k​,​0​,​c​,​k​);

col2im_gpu​(​net​.​workspace​,​ ​l​.​c​/​l​.​groups​,​ ​l​.​h​,​ ​l​.​w​,​ ​l​.​size​,​ ​l​.​stride,


l​.​pad​,​ ​net​.​delta_gpu​ ​+​ ​(​i​*​l​.​groups​ ​+​ ​j​)*​l​.​c​/​l​.​groups​*​l​.​h​*​l​.​w​);
if​(​l​.​binary​ ​||​​ ​l​.​xnor​)​ ​{
swap_binary​(&​l​);
}
}
if​(​l​.​xnor​)​ ​gradient_array_gpu​(​original_input​ ​+​ ​i​*​l​.​c​*​l​.​h​*​l​.​w​,​ ​l​.​c​*​l​.​h​*​l​.​w​,
HARDTAN​,​ n
​ et​.​delta_gpu​ ​+​ ​i​*​l​.​c​*​l​.​h​*​l​.​w​);
}
}
#endif
}

void​​ ​pull_convolutional_layer​(​layer​ ​l)


{
cuda_pull_array​(​l​.​weights_gpu​,​ ​l​.​weights​,​ ​l​.​nweights​);
cuda_pull_array​(​l​.​biases_gpu​,​ ​l​.​biases​,​ ​l​.​n​);
cuda_pull_array​(​l​.​weight_updates_gpu​,​ ​l​.​weight_updates​,​ ​l​.​nweights​);
cuda_pull_array​(​l​.​bias_updates_gpu​,​ ​l​.​bias_updates​,​ ​l​.​n​);
if​​ ​(​l​.​batch_normalize​){
cuda_pull_array​(​l​.​scales_gpu​,​ ​l​.​scales​,​ ​l​.​n​);
cuda_pull_array​(​l​.​rolling_mean_gpu​,​ ​l​.​rolling_mean​,​ ​l​.​n​);
cuda_pull_array​(​l​.​rolling_variance_gpu​,​ ​l​.​rolling_variance​,​ ​l​.​n​);
}
}

void​​ ​push_convolutional_layer​(​layer​ ​l)


{
cuda_push_array​(​l​.​weights_gpu​,​ ​l​.​weights​,​ ​l​.​nweights​);
cuda_push_array​(​l​.​biases_gpu​,​ ​l​.​biases​,​ ​l​.​n​);
cuda_push_array​(​l​.​weight_updates_gpu​,​ ​l​.​weight_updates​,​ ​l​.​nweights​);
cuda_push_array​(​l​.​bias_updates_gpu​,​ ​l​.​bias_updates​,​ ​l​.​n​);
if​​ ​(​l​.​batch_normalize​){
Martínez,​ ​Rodríguez​ ​ ​34

cuda_push_array​(​l​.​scales_gpu​,​ ​l​.​scales​,​ ​l​.​n​);


cuda_push_array​(​l​.​rolling_mean_gpu​,​ ​l​.​rolling_mean​,​ ​l​.​n​);
cuda_push_array​(​l​.​rolling_variance_gpu​,​ ​l​.​rolling_variance​,​ ​l​.​n​);
}
}

void​​ ​update_convolutional_layer_gpu​(​layer​ ​l​,​ ​update_args​ ​a)


{
float​​ ​learning_rate​ ​=​ ​a​.​learning_rate​*​l​.​learning_rate_scale;
float​​ ​momentum​ ​=​ ​a​.​momentum;
float​​ ​decay​ ​=​ ​a​.​decay;
int​​ ​batch​ ​=​ ​a​.​batch;

if​(​a​.​adam​){
adam_update_gpu​(​l​.​weights_gpu​,​ ​l​.​weight_updates_gpu​,​ ​l​.​m_gpu​,​ ​l​.​v_gpu​,​ ​a​.​B1​,​ ​a​.​B2​,
a​.​eps​,​ ​decay​,​ ​learning_rate​,​ ​l​.​nweights​,​ ​batch​,​ ​a​.​t​);
adam_update_gpu​(​l​.​biases_gpu​,​ ​l​.​bias_updates_gpu​,​ ​l​.​bias_m_gpu​,​ ​l​.​bias_v_gpu​,
a​.​B1​,​ ​a​.​B2​,​ ​a​.​eps​,​ ​decay​,​ ​learning_rate​,​ ​l​.​n​,​ ​batch​,​ ​a​.​t​);
if​(​l​.​scales_gpu​){
adam_update_gpu​(​l​.​scales_gpu​,​ ​l​.​scale_updates_gpu​,​ ​l​.​scale_m_gpu​,
l​.​scale_v_gpu​,​ ​a​.​B1​,​ ​a​.​B2​,​ ​a​.​eps​,​ ​decay​,​ ​learning_rate​,​ ​l​.​n​,​ ​batch​,​ ​a​.​t​);
}
}​else{
axpy_gpu​(​l​.​nweights​,​ ​-​decay​*​batch​,​ ​l​.​weights_gpu​,​ ​1​,​ ​l​.​weight_updates_gpu​,​ ​1​);
axpy_gpu​(​l​.​nweights​,​ ​learning_rate​/​batch​,​ ​l​.​weight_updates_gpu​,​ ​1​,​ ​l​.​weights_gpu​,
1​);
scal_gpu​(​l​.​nweights​,​ ​momentum​,​ ​l​.​weight_updates_gpu​,​ ​1​);

axpy_gpu​(​l​.​n​,​ l
​ earning_rate​/​batch​,​ ​l​.​bias_updates_gpu​,​ ​1​,​ ​l​.​biases_gpu​,​ ​1​);
scal_gpu​(​l​.​n​,​ m​ omentum​,​ ​l​.​bias_updates_gpu​,​ ​1​);

if​(​l​.​scales_gpu​){
axpy_gpu​(​l​.​n​,​ ​learning_rate​/​batch​,​ ​l​.​scale_updates_gpu​,​ ​1​,​ ​l​.​scales_gpu​,
1​);
scal_gpu​(​l​.​n​,​ ​momentum​,​ ​l​.​scale_updates_gpu​,​ ​1​);
}
}
}

S-ar putea să vă placă și