Red Neuronal en FPGAs: Proyecto Fin de Grado
Red Neuronal en FPGAs: Proyecto Fin de Grado
de Ingeniería de Computadores
Julio de 2019
Índice
Índice ..................................................................................................................................... I
Objetivo ................................................................................................................................ V
Abstract................................................................................................................................ IX
2.2 FPGAs................................................................................................................................. 16
Capítulo 5: Planificación........................................................................................................ 87
6.3 Análisis............................................................................................................................... 89
Conclusiones........................................................................................................................ 93
II
Implementación del algoritmo “Backpropagation” ................................................................ 95
Glosario de Acrónimos.......................................................................................................... 97
Bibliografía ......................................................................................................................... 99
III
IV
Objetivo
El objetivo de este proyecto es la implementación de una red neuronal artificial ya entrenada
en cualquier FPGA. Para la realización de este proyecto, se tendrán en cuenta varios hitos:
V
VI
Resumen
Este proyecto consiste en la realización de una red neuronal artificial con una FPGA (Field
Programming Gate Array, del español, matriz de puertas programables). Para ello, en la primera
iteración del proyecto se realizarán los componentes básicos necesarios para el correcto
funcionamiento de la red neuronal artificial. Para poder desarrollar este proyecto han sido
necesarios unos conocimientos previos en una materia específica como es la inteligencia
artificial y el lenguaje de descripción hardware VHDL, los cuales, se han reflejado en el apartado
de conocimientos previos del proyecto.
Por otro lado, en la parte de desarrollo, se ha realizado una arquitectura modular bottom-to-
top (del español, de más bajo a más alto) que consiste en el desarrollo de componentes más
pequeños y básicos, a más grandes y complejos. Cada módulo es independiente del resto y su
función está totalmente acotada a un objetivo, como por ejemplo, controlar otro módulo,
realización de un algoritmo, etc. De esta manera se consigue un sistema escalable, fácil de
comprobar, con posibilidades de mejoras y de conexión con otros proyectos. Entre todos los
módulos cabe destacar varios de ellos, como pueden ser, la realización de la función sigmoid
(del español, función sigmoide) y los módulos encargados de controlar las distintas neuronas,
capas y la totalidad de la red neuronal.
Para finalizar, se definen unas líneas futuras en las que se añaden nuevas características con
mejoras a nivel de rendimiento, escalabilidad y funcionalidades para alargar la vida útil del
proyecto.
VII
VIII
Abstract
This project consists in the realization of an artificial neural network with a FPGA (Field
Programming Gate Array). At the first iteration of the project it will be done the basic
components in order to the properly functioning of the artificial neural network. To be able to
do this project, it has been necessary a previous knowledge in a specific ambit such as the
artificial intelligence and the hardware description language VHDL, which has been reflected at
the background knowledge chapter.
On the other hand, at the development part it has been accomplished a modular architecture
bottom-to-top which consist in the develop of basic and smaller components to more complex
and bigger. Each module is independent of others and its task is limited to a specific target, such
as control another module, doing an algorithm and so on. Then, in this way, a scalable system
is achieved, easy to check, better possibilities for improvement and it is easier to connect with
other projects. Among all the modules it is worth mentioning several of them, like the develop
of the sigmoid function and the entities in charge of controlling the distinct neurons, layers and
the whole neural network.
As a check of everything done, at the results chapter, the structure of a neural network which
implement the XNOR logic gate is shown through the structure generate in this project.
Finally, future lines are defined in which new characteristics with performance improvement,
scalability and functionalities are added in order to lengthen the useful life of the project.
IX
X
Capítulo 1: Introducción
Este proyecto se ha realizado para estudiar la viabilidad del uso de otros tipos de hardware para
el tratamiento de enormes cantidades de datos de una empresa grande como el BBVA (Banco
Bilbao Vizcaya Argentaria) (BBVA, 2019), mediante el uso de la IA (Inteligencia Artificial)
(Adarraga & Zaccagnini, 1994), más en concreto, Redes Neuronales Artificiales (Ng, 2018).
El BBVA es una entidad bancaria española, la cual, consta de un activo de 676.689 millones de
euros de euros a 31 de diciembre de 2018, siendo la segunda entidad financiera española por
volumen de activos. A su vez, cuenta con 7.963 oficinas, 125.627 empleados y 74,5 millones de
clientes, estando presente en más de 30 países.
Debido a lo dicho anteriormente, el BBVA quiere encontrar un modo de dar servicio a todos sus
clientes de manera específica ofreciendo un trato particular a cada uno.
Para poder realizar este servicio, lo ideal sería aplicar lo que haría un empleado del BBVA a un
cliente, pero en vez de mediante un recurso humano, empleado, este, sería una máquina. Esta
sustitución se basa en el proceso que se denomina Aprendizaje de Máquinas (del inglés,
machine learning) (Ng, 2018).
Para ello, se han realizado varias líneas de investigación, búsqueda de conocimiento sobre redes
neuronales, varios cursos y proyectos de machine learning y la búsqueda de algoritmos
implementados para operaciones básicas en dichos aspectos.
Otra de las finalidades de este proyecto es el uso de hardware específico para el desarrollo de
redes neuronales, ya que todas las implementaciones extendidas son mediante el uso de CPUs
(del inglés, Central Processing Unit) y GPUs (del inglés, Graphics Processing Unit).
1
2
Capítulo 2: Conocimientos Previos
Las principales tecnologías aplicadas en este proyecto son el uso de Redes Neuronales
Artificiales, FPGAs (Xilinx, 2019) como medio procesamiento y controlador, por último, el
lenguaje de descripción Hardware VHDL (VHSIC (Very High Speed Integrated Circuit, del
español, Circuito integrado de muy alta velocidad ) Hardware Description Language, del
español, Lenguaje de descripción hardware). Por tanto, se va a proceder a revisar someramente
las mismas.
3
Históricamente, el uso de redes de neuronas fue utilizado con frecuencia a partir de los años
80s y hasta 90s, periodo en el cual, hubo un decrecimiento en la investigación y uso de las
mismas.
Su abandono fue debido a que el hardware y el entendimiento de las redes de neuronas no era
suficiente, por lo cual, se quedaron en el olvido hasta hoy en día que, con la era del Big Data
(macro datos, datos masivos, inteligencia de datos o datos a gran escala) (Marr, 2014) se han
vuelto a usar asiduamente ya que es una de las mejores formas de tratar tanta cantidad de
datos de manera correcta para dar un resultado adecuado. En la siguiente figura se puede
observar el proceso genérico que se realiza cuando tienes una cantidad masiva de datos o Big
Data.
A continuación, se procede a desarrollar los pasos que hace una neurona en función de lo dicho
anteriormente.
4
En primer lugar, uno de los elementos principales son las dendritas (Lexikon, 2003), que son
prolongaciones protoplásmicas ramificadas bastante cortas de la neurona, dedicadas
principalmente a la recepción de estímulos y, secundariamente, a la alimentación celular. Son
terminales de las neuronas; y sirven como receptores de impulsos nerviosos provenientes
desde un axón perteneciente a otra neurona. Su principal función es recibir los impulsos de
otras neuronas y enviarlas hasta el soma de la neurona.
Lo más importante de esta definición es la recepción de estímulos. En el caso de las ANN las
neuronas serían las que reciben los estímulos que serían los valores generados en las anteriores
neuronas o lo que es igual a nivel técnico valores de entrada o del inglés “Input”.
La principal función del núcleo de la neurona sería el procesamiento, que en una ANN la
principal función equivaldría a realizar las operaciones, por ejemplo, la multiplicación de una
neurona por su peso asociado (lo cual se expondrá más adelante).
Por último, estaría el axón este daría salida a otra neurona o si es la última neurona daría paso,
por ejemplo, al movimiento de un músculo. En el caso de una ANN serían las flechas que asocian
cada neurona con otra. En lenguaje técnico valores de salida o del inglés “Output”.
5
Cabe destacar que las redes neuronales artificiales están inspiradas en las biológicas, pero al
ser un modelo formal se obvian muchos procesos biológicos (algunas de las características del
sistema biológico no están reflejados en el modelo computacional y viceversa).
• El mecanismo de aprendizaje para que por cada iteración de la red está actualice los
pesos.
La función de una red neuronal artificial 𝑓(𝑥) es una composición de funciones 𝑔𝑖 (𝑥), la cual
𝑓 (𝑥 ) = 𝐾(∑𝑖 𝑤𝑖 𝑔𝑖 (𝑥 )) donde 𝐾 es la función de activación de la neurona, 𝑔𝑖 (𝑥 ) la neurona 𝑖 y
𝑤𝑖 el peso de la neurona 𝑖. En la siguiente figura se muestra la representación de una neurona
artificial indicando su similitud con el modelo biológico.
Figura. 2.1.4. Símil Red neuronal artificial vs Biológica. (Martínez, Rico, Romero, & Castro, 2018)
• ReLU (Google, 2019) (del inglés, Rectified Linear Unit): Función de activación
de unidad lineal rectificada, que a menudo funciona mejor que una función suave,
como la sigmoide, y es mucho más fácil de calcular.
• TanH (Wolfram, 2019) (del inglés, Hyperbolic Tangent): Se define como el cociente
entre el seno hiperbólico y el coseno hiperbólico del número real “x”.
Estas funciones se activan en función de los valores de entradas provocando así un cambio leve
en la producción debido a que estas funciones siempre transitan de forma suave.
Por último, el aprendizaje, que es la característica más importante en una ANN. Este es la mejor
optimización para resolver el problema se está tratando. Durante este proceso las neuronas
actualizan su peso 𝑤𝑖 dando lugar a una salida deseada o al menos una consistente, de esta
manera la red podrá en un futuro responder a situaciones aún no procesadas.
7
ajustar bien será capaz de predecir información que viene incompleta dando una salida
coherente.
1. Aprendizaje Supervisado (Hubel & Wiesel, 2005): En este tipo de aprendizaje, se sabe
cuál es la salida “output” y el mismo consiste en la comparación del resultado que se
obtiene de la red con el teórico esperado. Por consiguiente, se usa una función que
minimiza el error cometido al comparar el valor teórico y el obtenido, y con este error
minimizado, se recalculan los pesos asociadas a cada neurona. Se repite este proceso
hasta que la salida de la red y la esperada son prácticamente iguales. A este tipo de
parejas se le suele denominar conjunto de aprendizaje.
donde i = 1,2, … , n; j = 1,2, … , p; wij es el peso de la conexión entre los dos PEs
(Procesadores Elementales, más comúnmente llamado neuronas).
8
• Aprendizaje Competitivo: Es un tipo de aprendizaje que usa inhibición lateral o lo
que es lo mismo el ganador se lo lleva todo “all-in”. Este tipo de aprendizaje lo usan
redes neuronales como los Mapas Auto-Organizativos (Kohonen, 1984) el cual se
puede observar un ejemplo en la siguiente figura, la cual representa los patrones de
votación de la organización European University Association (del inglés, Asociación
de universidades europeas).
Figura 2.1.6. Mapa auto organizado de los patrones de votación del Congreso de EUA.
(Wikipedia, 2019)
9
𝑊𝑖𝑗𝑛𝑢𝑒𝑣𝑜 = max(𝑊𝑖𝑗𝑣𝑖𝑒𝑗𝑜 , 𝑎𝑘𝑖 )
a) Red de dos capas: Puede capturar mapeos lineales entre las entradas y las
salidas. Dos redes neuronales que utilizan este aprendizaje son el Perceptrón
(Rosenblatt, 1962) y ADALINE (Widrow & Hoff, 1960).
b) Red multicapa: Puede capturar mapeos no lineales entre las entradas y las
salidas. Este algoritmo es uno de los más usados y comúnmente se le
denomina Backpropagation (Retro propagación). Utilizando una regla
encadenada se pueden recalcular los pesos para un número arbitrario de
capas. Sin embargo, el aprendizaje es lento ya que el número de iteraciones
que se tiene que realizar por cada patrón del conjunto de datos es grande.
Este algoritmo fue introducido por (Rumerlhart, Hinton & Williams, 1986).
• Aprendizaje por Reforzamiento: Ideado por (Widrow, Grupta & Maitra 1973) y
desarrollado por (Willians, 1983). Este tipo de aprendizaje es similar al anterior ya
que es un aprendizaje supervisado y recalcula los pesos por error cometido. Sin
embargo, en este caso el error se calcula por cada neurona de manera individual en
vez de colectivamente como en el caso de las redes multicapa. Este aprendizaje es
bueno en el caso de que se tenga mucha información específica del error. Un
ejemplo del aprendizaje por refuerzo es el de la IA AlphaZero (Deepmind, 2019) de
la empresa DeepMind, la cual, mediante el uso de este aprendizaje ha sido capaz de
derrotar a la mejor IA de Ajedrez hasta el momento (StockFish) (stockfishchess,
2008), a su vez también domina el Go (usgo, 1997) y el Shogi (Sobre Japón), ambos
juegos de estrategias similares al ajedrez. La siguiente figura representa la curva de
aprendizaje del algoritmo AlphaGo zero durante 40 días aprendiendo por sí mismo.
10
Figura 2.1.7. Curva de aprendizaje por refuerzo de AlphaGo. (Deepmind, 2019)
En la siguiente tabla se puede observar un pequeño resumen de los distintos aprendizajes vistos
anteriormente. Esta tabla consta de 4 columnas:
1. Algoritmo de entrenamiento.
4. Capacidad de almacenamiento.
11
Algoritmo de Tiempo de Categoría de Capacidad de
Entrenamiento Entrenamiento Aprendizaje Almacenamiento
Aprendizaje Hebbiano Rápido No supervisado Escaso
2.1.3 Aplicaciones.
Debido a que las redes neuronales tienen características similares a las del cerebro humano,
son capaces de aprender de la experiencia, de abstraer características esenciales a partir de
entradas que presentan información irrelevante, de generalizar de casos anteriores a nuevos
casos…etc. Todo esto permite su aplicación en un gran número de áreas muy diferenciadas.
En el amplio abanico de aplicaciones que hoy en día pueden tener las redes neuronales cabe
destacar algunas en las que se están usando de manera práctica (Matich, 2001):
o Pronunciación fonética.
12
➢ Reconocimiento de caracteres y palabras (Lenguaje Natural)
o Resumir texto.
o Crear chat-bots.
o Reconocer entidades.
o Análisis de sentimiento.
➢ Visión
o Reconocimiento Facial.
o Imagen a texto.
➢ Reconocimiento de Patrones
➢ Robótica
➢ Finanzas
o Identificación de falsificaciones.
o Interpretación de firmas.
➢ Medio ambiente
➢ Medicina
13
2.1.3 Software y librerías.
Actualmente, debido al resurgimiento de la IA, muchas de las grandes empresas IT (del inglés,
Information Technology, Tecnologías de la información) han proporcionado gran cantidad de
software, librerías con código abierto (free source) y herramientas para que este ímpetu por
facilitar la vida humana usando IAs para muchísimas cosas no se pierda, y que todo el mundo
pueda aportar su granito de arena. Empresas como el gigante Google (Google, 2019) con
TensorFlow (Tensorflow, 2019) es una biblioteca de código abierto para aprendizaje
automático a través de un rango de tareas. Desarrollado por Google para satisfacer sus
necesidades de sistemas capaces de construir, entrenar redes neuronales , detectar y descifrar
patrones, correlaciones, análogos al aprendizaje y razonamiento usados por los humanos.
TensorFlow fue originalmente desarrollado por el equipo de Google Brain para uso interno en
Google, antes de ser publicado bajo la licencia de código abierto Apache 2.0 el 9 de noviembre
de 2015. TensorFlow, está hecho en C++ (Stroustrup, 1985), aunque, su uso habitual, para que
sea más rápido, cómodo y sencillo de usar es mediante el uso de la API (del inglés, application
programming interface, Interfaz de programación de aplicaciones) en Python (Python, 2019). El
Playground (Tensorflow, 2019) de TensorFlow es una herramienta destinada a que se conozca
cómo funciona por dentro una red neuronal de manera gráfica e interactiva. En la siguiente
figura se aprecian las distintas compañías que usan TensorFlow.
Figura 2.1.8. Principales empresas que utilizan TensorFlow para machine learning. (Tensorflow, 2019)
14
Facebook (Facebook, 2019), desarrolló Torch (Torch, 2019) una biblioteca de código
abierto para aprendizaje automático, un marco de computación científica, y un lenguaje
de script basado en el lenguaje de programación Lua (Lua, 2019). Proporciona un amplio rango
de algoritmos de aprendizaje profundo, y usa el lenguaje de script LuaJIT (Lua, 2019),
existiendo, también, una implementación inferior en C (Brian & Dennis, 1978).
No podía faltar la compañía, Microsoft (Microsoft, 2019), con su The Microsoft Cognitive Toolkit
una de las primeras en proporcionar acceso al deep learning (vertiente del machine learning
que usa técnicas de aprendizaje más detalladas) en Open Source. Esta, combina los principales
modelos de aprendizaje profundo y machine learning, optimizadores del error mediante el uso
del Gradient Descent (del español, descenso por gradiente), el cual, es un método matemático
Theano (Theano, 2019), fue un proyecto open source de la Universidad de Montreal (Université
de Montréal, 2019), en el cual usando una de las librerías más famosa de Python (Numpy
(Numpy, 2019)) consiguieron desarrollar una librería en Python ultra escalable, tanto en GPUs
como en CPUs.
Por último, Keras (Keras, 2019), es un framework de código abierto para redes neuronales
escrito en Python y es capaz de usar varios de los frameworks anteriormente vistos como
TensorFlow, CNTK, Theano, y, además, MXNet (Mxnet, 2019). Añade un nivel, más de
abstracción permitiendo así un uso particularmente fácil para alguien que no sepa programar
15
prácticamente. Fue desarrollado en un proyecto llamado ONEIROS (Open-ended Neuro-
Electronic Intelligent Robot Operating System) y su principal autor es François Cholle (Keras,
2019) un ingeniero de Google. En la siguiente imagen se puede observar el uso para deep
learning de las distintas librerías y cuáles son las preferidas a nivel de puntuación en estrellas
de Github (un sistema de control de versiones bastante popular) (GitHub, 2019).
Figura 2.1.9. Deep learning frameworks con más popularidad en GitHub (GitHub, 2019).
2.2 FPGAs.
Una FPGA (Field Programming Gate Array, matriz de puertas programables) (University of
Toronto, 2019) es un dispositivo lógico programable que contiene un conjunto de CPLDs (del
inglés, Complex Programmable Logic Device, dispositivo lógico programable) para los cuales su
funcionalidad e interconexión se realiza mediante el uso de un lenguaje de descripción
hardware como puede ser VHDL (IEEE, 1988) el cual se detallará más adelante. A continuación,
se muestra un ejemplo de FPGA de la gama virtex UltraScale de xilinx.
16
Figura 2.2.1. FPGA de la empresa XILINX, gama Virtex Ultra Scale. (Xilinx, 2019)
Las FPGAs nacen debido a que su principal diferencia frente a los ASICs (del inglés, Application-
Specific Integrated Circuit, circuito integrado de aplicación específica), en que son
reprogramables, por lo tanto, añaden reducciones de coste y diseño. Sin embargo, es verdad
que todo tiene sus inconvenientes cuando se comparan cosas, y en el caso de la FPGA se ve
afectado en que el rendimiento y consumo energético son mayores con respecto a los ASICs.
Las FPGAs fueron desarrolladas en el año 1984 por Ross Freeman y Bernard Vonderschmitt
(Funding Universe, 2019), cofundadores de Xilinx (Xilinx, 2019), y surgen como, ya se ha
explicado anteriormente, una evolución de los CPLDs.
17
realizan los bloques lógicos van a parar a unos escasos biestables síncronos, mientras que, en
una FPGA cada bloque lógico contiene dichos biestables, por lo que, da mayor libertad.
Por otro lado, dentro de la matriz de conexionado, en una FPGA se le pueden añadir puertas
lógicas que facilitan el cálculo de operaciones matriciales, como puede ser sumadores o
multiplicadores.
Una vez explicado un poco de historia y comparado con sus dispositivos similares más próximos,
se pueden preguntar ¿para qué se va a usar un elemento hardware tan desconocido si existen
hardware genérico como las CPUs y GPUs? Pues, bien, precisamente se quiere abordar este
tema ya que es una de las preguntas que más se hacen los desarrolladores cuando se enfrentan
a una decisión de elección de tecnologías a usar para realizar las implementaciones hardware
de sus sistemas.
18
constan de operaciones matriciales) el procesamiento por vatio de una FGPA es unas 3-4 veces
mejor que el de una GPU (GFLOPs por vatio).
• Cloud Computing
• Procesamiento de Imagen
• Big Data
• Ancho de banda
• Robótica
• HD-Video
• machine learning
• deep learning
Por otro lado, se tendrá que tener en cuenta otros requisitos existentes tales como,
presupuesto, compatibilidades, es un sistema de tiempo real, espacio, desarrollo, flexibilidad,
tipos de interfaces, cálculo y latencia. Para ello, a continuación, se describirá una tabla
comparativa en donde se muestra a modo resumen en cuales de los aspectos descritos
anteriormente es mejor una FPGA o una GPU.
Latencia FPGA
19
Características Análisis Ganador
Una FPGA gana en GFLOPs por vatio en ratio de 2-3 a
una GPU.
Procesamiento por FPGA
vatio
Las GPUs solo pueden estar conectadas vía PCIe
mientras que las FPGAS pueden estar por PCIe, fibra
óptica, en sistemas empotrados, como
coprocesadores, puertos serie, etc.
Interfaces FPGA
Como se puede ver, hay bastantes aspectos a tener en cuenta a la hora de elegir entre uno u
otro. En la siguiente figura se puede ver la tabla en un gráfico cualitativo.
20
Figura 2.2.3. Gráfico Cualitativo de la tabla 2.2.1. (Berten, 2019)
Los bloques lógicos o CLB constan de tres elementos principales (como se puede observar en la
figura 2.2.5), las LUTs (Look Up Table), un full-adder (del inglés, sumador total) y un flip-flop (del
21
inglés, biestable) tipo D. Con este conjunto mediante, LUTs, las cuales, usan multiplexores
dentro para generar cualquier circuito combinacional, como se ejemplifica en la figura 2.2.6,
además de otro (multiplexor) para seleccionar si el modo es asíncrono o síncrono. A
continuación, pasa por el full-adder, este se usa para interconectar varias LUTs con el propósito
de poder realizar circuitos combinacionales más complejos y el resultado generado se guarda
en el biestable D para así guardar la configuración del bloque lógico (esto da la opción de que
sea reprogramable).
Figura 2.2.6.
Como se genera un circuito combinacional a través de una LUT. (Blanco Pinto, 2019)
22
En esta figura, se describe como hacer un circuito combinacional en una LUT, para ello se
dispone de una memoria SRAM, y, de un multiplexor n-1. El número de entradas definirá el
tamaño del multiplexor, en este caso son tres entradas 23 = 8, por lo que, el multiplexor será
de ocho a uno. Una vez visto los componentes, se procede a realizar la tabla de verdad del
circuito a implementar. Por consiguiente, las distintas combinaciones de la salida “y” se
introducen en los distintos bloques de la SRAM de manera ordenada, haciendo coincidir las
entradas del multiplexor con el bloque de memoria correspondiente a la combinación para
activar la entrada del multiplexor.
Por otro lado, la matriz de Inter-conexionado es la que genera la conexión entre los distintos
bloques lógicos. Está matriz, aunque pase por todos los bloques no tiene por qué estar activada
ya que el enrutamiento de una FPGA no está segmentado, o sea, cada segmento de cableado
abarca solo un bloque lógico y está termina en un switch (como se observa en la siguiente
figura), el cual, se pueden hacer caminos más largos activando los switch y haciendo así la
conexión entre estos CLB.
Figura 2.2.7. Switch de unión entre los distintos CLB de la matriz de conexionado. (Wikipedia, 2019)
Los bloques de E/S (I/O) son básicamente por donde se hará la interacción con la FPGA tanto
en entrada de datos como de salida de los mismos. En la figura 2.2.8 se puede apreciar el
circuito I/O, que someramente se puede indicar que es un circuito estándar de entrada y salida
de datos.
Por último, a parte de estos tres principales bloques las FPGAs, por lo general llevan integrados,
bloques de RAM y DSPs (del inglés, Digital Signal Processor, Procesadores Digitales de Señales),
23
los cuales tienen muchas funcionalidades, pero la principal o por lo menos una de las cuales
afectará mucho a este PFG es el uso de los DSPs para hacer multiplicadores-acumuladores,
matrices y operaciones en coma flotante.
24
En este proyecto se usará y se comparan las distintas gamas de FPGAs de la empresa Xilinx
(Figura 2.2.9). La elección fue debido a que en el BBVA usaban la gama alta de FPGAs de Xilinx
e, incluso, tienen un programa de ayuda a la educación, donde, proporcionan FPGAs de prueba
para educación. También, ofrecen la licencia para que se use un software, el cual, proporciona
herramientas y útiles para poder modelar la FPGA de manera más simple. En la siguiente figura
se muestra el logotipo de uno de los principales fabricantes de FPGAs actualmente, Xilinx.
Dentro de Xilinx existen varias gamas de FPGAs, como se puede ver en la tabla 2.2.2,
mostrándose, de izquierda a derecha según desciende el tamaño de fabricación de los
transitores la gama a la que pertenecen las mismas, empezando por la gama con mayor tamaño
de transistores, a la izquierda. Dentro de la misma tecnología, se mejoran las prestaciones de
más abajo (la que menos prestaciones tienes) a más arriba (la que más), por ejemplo, se pueden
usar con fibra óptica, tienen más bloques de RAM, DSP, LUTs, I/O, etc. Lo que provoca, que se
puedan hacer proyectos más grandes o que requieran de mayor complejidad, flexibilidad,
capacidad de memoria principal o I/O.
Tabla 2.2.3. Comparativa entre gama Kintex-7 y Kintex Ultra Scale. (Xilinx, 2019)
Para este tipo de aplicación, Big Data, se podría usar una de las gamas más altas y
probablemente usar varías si se quiere para uso empresarial, ya que, se precisa de memoria y
mucha E/S debido a la cantidad de datos que las redes neuronales tratan. Para que se entienda
esto último, si en la primera capa de la red neuronal se tienen 3 neuronas y números de entrada
en coma flotante (264 ) como estos buses de datos serían en paralelo, se usarían 64 x 3 = 192
bloques de E/S, teniendo en cuenta que el ejemplo es muy básico para una red neuronal, y, que
una gama alta dispone de unos 500 bloques de E/S se usarían el 40% de los bloques de E/S. Sin
embargo, para hacerlo con pocos datos y a pequeña escala como es el objetivo de este
proyecto, vale con la simulación que genera Vivado (Xilinx, 2019), software de Xilinx para
modelar FPGAs, y una FPGA de gama baja o media.
26
Para hacerse una idea, en la tabla 2.2.4, la cual esta sacada de las especificaciones de Xilinx de
la gama Virtex UltraScale+, se puede observar la cantidad de principales prestaciones que tiene
esta gama (LUTs, RAM, DSP, I/O, CLK). En los resultados del proyecto se adjuntará una tabla
similar indicando la cantidad de LUTs, RAM, DSPs, E/S y CLKs usados, y, que recursos se
necesitarían para un proyecto más grande.
Tabla 2.2.4. Resumen de características de la FPGA Virtex ultrascale+ de Xilinx. (Xilinx, 2019)
1. Defensa y Aeroespacial
• Avionics/DO-254
• Comunicaciones
• Misiles y municiones
• Soluciones de seguridad
27
• Espacio
2. Audio
• Conectividad
• DSP
3. Industria Automotriz
• Procesamiento de imagen
4. Bioinformática
5. Broadcast
• Codificadores
• Switches y Routers
• Monitores
6. Electrónica de consumo
• Monitores digitales
• Cámaras digitales
• Impresoras Multifunción
• Dispositivos portables
• Decodificadores
28
7. Centro de Datos
• Servers (servidores)
• Seguridad
• Routers
• Switches
• Gateways
• Balanceadores de carga
8. Super computación
• Servers
• Super Computadores
• SIGINT sistemas
• Radares
9. Industrial
• Redes industriales
• Control de Motores
• ASICs
• Emulación hardware
11. Medicina
• Ultrasonidos
• Resonancias magnéticas
29
• Rayos-X
• Tomografías
• Sistemas quirúrgicos
12. Seguridad
• Soluciones de seguridad
• Procesamiento de Imagen
• Monitores digitales
• Visión artificial
• Procesamiento de red
• Interfaces de conexión
• Backhaul
• Radio
• Banda base
Como se puede observar las FPGAs son aplicables a una gran parte de los proyectos que
necesita la sociedad, desde aplicaciones para economía hasta medicina. Esto es debido a que al
ser un dispositivo hardware “genérico” se pueden usar para muchísimas aplicaciones y es
reprogramable a su vez, modelándolo de una cierta manera con un lenguaje de modelación
30
hardware como puede ser VHDL, esta se convierte en un dispositivo hardware especifico.
Debido a este motivo, las FPGAs proporcionan otros casos de uso, en el cual, sus “hermanos”
genéricos (CPU, GPU) tienen más dificultades para hacer frente a este tipo de situaciones.
2.3 VHDL.
VHDL (Wikipedia, 2019) es un lenguaje de especificación definido por el IEEE (IEEE,
2019) (Institute of Electrical and Electronics Engineers, Instituto de ingeniería eléctrica y
electrónica) (ANSI/IEEE 1076-1993) (IEEE, 1988) utilizado para describir circuitos digitales y para
la automatización de diseño electrónico. VHDL es acrónimo proveniente de la combinación de
dos acrónimos: VHSIC (Very High Speed Integrated Circuit, circuito integrado de muy alta
velocidad) y HDL (Hardware Description Language, lenguaje de descripción hardware). Aunque
puede ser usado de forma general para describir cualquier circuito digital, se usa principalmente
Una vez vista la definición del lenguaje VHDL, se revisará, someramente, su historia. VHDL se
creó a la vez que ADA por el Departamento de Defensa (DOD, Department of Defense) (DOD,
2019) de los Estados Unidos con la idea de documentar todos los ASICs que sus sistemas de
defensa llevaban y los entendiese todo el mundo o, lo que es lo mismo, un estándar. Como se
ha expuesto anteriormente, VHDL es coetáneo de ADA, aunque, por motivos lógicos es
diferente a ADA, si bien, este tiene gran influencia en la sintaxis de VHDL.
Al principio de su creación, en la fase inicial de VHDL (1987), el IEEE incluyó algunos tipos de
datos como pueden ser, numéricos (enteros y reales), lógicos como el bit y el boolean,
caracteres, tiempo, y un vector de bits (bit_vector), para, posteriormente, comprobar que les
faltaba un tipo de datos para hacer una lógica plurivalente, por lo que posteriormente
programaron el tipo de dato std_logic_vector en el cual se podían ya definir un bus de datos.
Ya hasta 2002 no hubo cambios significativos, solamente opciones de seguridad como los tipos
de datos protegidos y añadieron complejidad a los tipos de datos reales con los “unsigned” (sin
signo) y “signed” (con signo).
31
2.3.1 Diseño y Estructura.
En VHDL hay varias formas de diseñar un mismo circuito, de un nivel de abstracción mayor a
uno menor, todas ellas son igualmente válidas, siendo elección de cual usar de las mismas del
desarrollador, teniendo cada una sus procedimientos de diseño específicos:
• Flujo de Datos: En este diseño, se describe la forma en la que los datos se trasfieren
entre los distintos módulos de la entidad mediante la estructura when-else.
1. entity Sumador2bits is
2. Port ( c_in:in STD_LOGIC; --Carry de entrada
3. sum_0 : in STD_LOGIC; --Bit a
4. sum_1 : in STD_LOGIC; --Bit b
5. total : out STD_LOGIC; --Resultado a+b
6. c_out:out STD_LOGIC ); -- Carry de salida
7. end Sumador2bits;
8.
9. architecture flujo of Sumador2bits is
10. begin
11. total<= (sum_0 xor sum_1 xor c_in); --a+b+carry in
12. c_out<= (sum_0 and sum_1) or((sum_0 xor sum_1)and c_in);
--Carry out
13. end flujo;
• Diseño Estructural: En este caso se modela el circuito con modelos lógicos hechos
por el fabricante o por el usuario, como pueden ser puertas lógicas, sumadores,
contadores, etc.
1. library IEEE;
2. use IEEE.STD_LOGIC_1164.ALL;
3.
4. entity medio_sumador is
5. port(
6. A : in STD_LOGIC;
7. B : in STD_LOGIC;
8. C : out STD_LOGIC;
9. S : out STD_LOGIC
10. );
11. end medio_sumador;
12.
13. architecture estructural of medio_sumador is
33
14. component compuerta_and is
15. port(
16. a : in std_logic;
17. b : in std_logic;
18. s : out std_logic
19. );
20. end component;
21.
22. component compuerta_xor is
23. port(
24. a : in std_logic;
25. b : in std_logic;
26. s : out std_logic
27. );
28. end component;
29.
30. begin
31.
32. ACARREO: compuerta_and port map( A, B, C );
33. SUMA: compuerta_xor port map( A, B, S );
34.
35. end estructural;
• Por último, el diseño mixto el cual consiste en una combinación de los anteriores de
cualquier manera.
1. División del diseño en módulos separados, como se observa en la figura 2.3.1. Debido a
esta modularidad se obtiene que en un futuro se pueda usar este módulo para otros
proyectos o ampliar el mismo sin necesidad de cambiar prácticamente nada.
34
Figura 2.3.1. Ejemplo de división por módulos.
4. Síntesis. Una vez que se verifica la simulación funcional se procederá a hacer la síntesis
en la cual, se asigna un hardware en concreto (FPGA, ASIC) y se comprueban si se ha
incumplido alguna operación que no es sintetizable, como puede ser la división o
exponenciación de números no constantes.
6. Ubicación y enrutamiento (Place and Route, P&R), no siendo necesario, aunque es muy
útil ya que en este procedimiento es donde se enrutan los bloques y pueden provocar
retardos de propagación si un bloque que está muy conectado con otro bloque y, este,
está muy lejos del mismo (pudiendo ser recolocado).
7. Una vez hecho el enrutamiento, se asignan las latencias a cada bloque SDF (del inglés,
Standard Delay Format, Formato estándar de retardos) dando paso a la siguiente etapa
que será la simulación temporal.
35
8. Simulación temporal. En este apartado, se comprobará lo mismo que en la simulación
funcional, pero con los correspondientes retardos lo que puede provocar incoherencias
en el resultado teniendo que volver a una de las etapas anteriores ya que se tendrá que
optimizar el enrutamiento o solventar una condición de carrera, etc.
9. Por último, una vez que se valida la simulación temporal se volcará el código en el
dispositivo en cuestión, y se comprobará que todo funciona correctamente.
2.3.2 Sintaxis.
Para empezar en la figura 2.3.2 se observa una lista de todas las palabras reservadas en VHDL.
Ahora, teniendo una referencia de las palabras reservadas, en VHDL existen dos divisiones muy
claras con respecto a la estructura. Una es la parte declarativa donde se define simplemente la
entidad con sus respectivas, entradas, salidas y el tipo de estas, y, otra totalmente aparte donde
se define su arquitectura detalladamente y el comportamiento de la entidad.
Por lo tanto, se tiene la entidad que se define mediante la palabra reservada “entity” y la
arquitectura mediante “architecture”.
36
Ejemplo declarativo de entidad:
1. ENTITY Nombre_entidad IS
2. PORT ( Nombre de señal: modo tipo de señal;
3. . . .
4. Nombre de señal: modo tipo de señal );
5. END nombre_entidad;
• Operadores Lógicos: AND, XOR, OR, NOT, NOR, NAND, XNOR, para BIT y BOOLEAN.
• De relación: = (igual), /= (distinto), < (menor que), > (mayor que), >= (mayor igual),
<= (menor igual) para enteros.
Otras dos de las palabras reservadas muy importantes son “component” y “package” cuando
se define un componente se crea una instanciación concurrente de una entidad previamente
diseñada la cual se suele usar en una instancia de nivel superior, por ejemplo, si quieres hacer
un acumulador se necesita un registro tipo D y un sumador de n bits, la instancia superior sería
el acumulador y esta tendría dos componentes el registro tipo D y el sumador de n bits. La
declaración de los componentes tiene que ser en la parte declarativa de una arquitectura.
Pero claro, como bien se ha dicho otra de las palabras reservadas asociada a esta es “package”
donde, por ejemplo, se definirá los componentes, funciones, procedimientos, señales y
constantes que irán en ese paquete. El “paquete” se podrá usar en cualquier proyecto
37
importando dicho “paquete”, sin embargo, los componentes solo se pueden usar en la misma
raíz del proyecto.
1. PACKAGE nombre_paquete IS
2. Declaración de tipos
3. Declaración de señales.
4. Declaración de constantes
5. Declaración de componentes
6. Definición de funciones
7. Definición de procedimientos
8. END nombre_paquete
9.
10. PACKAGE BODY nombre_paquete IS
11. Declaración de tipos
12. Declaración de constantes
13. Definición de funciones
14. Definición de procedimientos
15. END nombre_paquete
38
2.3.3 Vivado Xilinx.
Vivado Design Suite (cuyo logo se muestra en la Figura 2.3.3) es un software de Xilinx escrito en
C++ para la síntesis y el análisis de proyectos HDL o de modelación hardware siendo,
básicamente, lo mismo que el ISE de Xilinx pero con alguna característica más y una mejor
experiencia de usuario en cuanto a usabilidad. Es el entorno de desarrollo que se usará en este
proyecto ya que proporcionará herramientas de diseño, un editor para VHDL, simulaciones
funcionales, temporales, librerías con componentes hechos por Xilinx (algunas son de pago
otras no). Por último, también permite la realización de la síntesis del HDL a parte de otras
utilidades, como importación de módulos ya hechas.
2. VHDL es muy determinista, en cambio, Verilog solo lo es cuando se sigue ciertas reglas.
3. VHDL, en lo que a sintaxis se refiere, es parecido a ADA. Sin embargo, Verilog, es más
parecido a C.
39
40
Capítulo 3: Desarrollo
En este capítulo se expondrá como se ha realizado el proyecto, las distintas tomas de decisiones,
razones por las que se han tomado esas decisiones y por último su implementación en VHDL
con su respectiva arquitectura, diseño, etc.
3.1 Arquitectura
En primer lugar, a lo largo de este apartado se irá describiendo la arquitectura a través de una
figura de una red neuronal (como se observa en la figura 3.1.1), se irá focalizando por partes
realizando así una arquitectura estructural por bloques de menor a mayor (arquitectura
comúnmente llamada bottom-to-top). Antes de nada, aclarar que en este apartado no se verá
la implementación a fondo ya que esto se hará en el apartado de implementación en VHDL.
1. La entidad más pequeña de una red neuronal, quitando las entradas y las salidas que no
dejan de ser a nivel hardware señales, es la neurona, como se expuso anteriormente,
siendo la unidad básica de computo de una red neuronal, por lo tanto, la que se va a
encargar de hacer con unos datos que le lleguen una serie de operaciones.
41
Para ello, se realizará una entidad que se denominará “neuron” y será la unidad de
procesamiento que constará simplemente de un acumulador y un multiplicador con una
serie de “flags” para saber cuándo acumular, resetear, multiplicar, etc. Por consiguiente,
habrá otros dos módulos, uno encargado de controlar todo este componente y el otro
será el proceso de acceder a la función sigmoid que se tratará más adelante. Con
controlar, se refiere al hecho de activar o desactivar las señales de control que harán
que esta neurona, acumule o multiplique en función de lo que se requiera en ese
momento y el resultado pasarlo por el proceso de lectura de la función sigmoid. Por lo
tanto, se deberá tener una entidad top que será la que contenga estas tres entidades
como se puede apreciar en la figura 3.1.2 con sus respectivas entradas y salidas.
Una vez visto la neurona se podría decir que la entidad Neuron_top es igual a una
neurona de la figura 3.1.1 que se veían representadas como a1, a2, a3 … an.
2. La siguiente entidad es el Layer (figura 3.1.3) o capa, la cual crea y controla neuronas,
esta contiene a Neuron_top y simplemente constará de una unidad de control (no hará
ningún cálculo), generará las neuronas necesarias para esa capa y tendrá asociada una
matriz con los pesos de cada neurona. Esta matriz será de NxM donde N será el número
de neuronas de la capa anterior y M el número de neuronas de la capa actual. Recordar
42
que los pesos estarán en memoria fijos (no se recalcularán) ya que el objetivo de este
proyecto es la viabilidad de una red neuronal en una FPGA, por lo tanto, no es necesario
añadirle más complejidad de algoritmia (Backpropagation para recalcular los pesos
asociados). La parte de control de la capa es muy básica y simplemente se irá
comunicando con las neuronas proporcionándoles los pesos asociados a cada una y una
serie de activadores de señal. En la siguiente figura se muestra a nivel arquitectural la
entidad descrita previamente, con sus componentes, entradas y salidas.
44
Figura 3.1.4. Entidad Sigmoid.
45
4. Por último, se diseña y se implementa la entidad final, la cual consiste en un cómputo
de todas las anteriores o lo que es igual la entidad ANN (figura 3.1.6). Esta entidad se
encargará de crear el número de capas a través de un parámetro genérico y, a su vez,
se encargará de conectar las respectivas salidas de las capas ocultas con las entradas de
las siguientes capas. Cada resultado generado en la salida de una capa se asignará a un
bus de datos que básicamente tendrá un tamaño: 𝐵𝑢𝑠 𝑑𝑒 𝑑𝑎𝑡𝑜𝑠 = (𝑁 𝑑𝑒 𝑛𝑒𝑢𝑟𝑜𝑛𝑎𝑠 ∗
𝑁 𝑏𝑖𝑡𝑠 𝑑𝑒 𝑠𝑎𝑙𝑖𝑑𝑎) − 1 ℎ𝑎𝑠𝑡𝑎 0.
Por ejemplo, si dentro de la capa hay 3 neuronas y las salidas son de 8 bits sería (3*8) -
1 = 23 hasta 0, el dato de la neurona 1 sería desde el bit 0 hasta 7, la neurona 2 desde el
bit 8 hasta el 15, por último, la neurona 3 sería desde el bit 16 hasta el 23.
La estructura a nivel gráfico se puede observar en la figura 3.1.6, la cual muestra sus
entradas, salidas y la conexión entre las distintas capas.
46
3.2 Implementación en VHDL
Una vez vista la arquitectura se pasará a la implementación de la misma en VHDL, por lo tanto,
en este apartado se empleará un punto de vista más algorítmico dando así, fuerza a la
arquitectura previamente definida y con ejemplos de código para que sea más sencillo su
análisis.
3.2.1 Neuron
La entidad neuron a nivel de Input/Output (del inglés, entrada y salida) consta de ocho señales
de entrada, una de salida, dos señales internas y por último tres parámetros genéricos los cuales
son configurables. Las señales de entrada son:
1. CLK, esta señal de entrada es el reloj y es de tipo std_logic (‘0’ o ‘1’), con ella se
mantendrá un proceso síncrono que se activará a nivel alto o lo que es igual cuando la
señal sea = ‘1’.
2. RST, la señal encargada de resetear, al igual que el CLK es de tipo std_logic y su cometido
será una vez que se active a nivel alto se vaciará el contenido de las dos señales internas
de la entidad.
3. A, la señal que contiene un dato de entrada que puede ser el dato de salida de una de
las capas anteriores o el dato de entrada inicial, en cuyo caso, se trataría de la primera
capa de la red neuronal. Esta señal es de tipo std_logic_vector simplemente es un vector
de tipo lógico, por ejemplo, si el vector es de 3 downto 0 sería un vector de bits (‘0000’,
“0001”, …,”1111”) en el cual se podrán hacer 24 = 16 𝑐𝑜𝑚𝑏𝑖𝑛𝑎𝑐𝑖𝑜𝑛𝑒𝑠. En este caso, la
señal de entrada será un vector que irá desde el parámetro genérico nbits-1 downto 0,
lo cual se hace para que el bus de entrada del dato sea configurable y pueda usarse en
distintos proyectos. Como se describió anteriormente la entidad neuron es un
acumulador y una multiplicación, debido a esto la señal será uno de los datos de entrada
que se usarán para multiplicarlo frente al otro vector de entrada el cual será el peso de
esa neurona.
47
4. La señal B será el otro vector de entrada de tipo std_logic_vector y en ella estarán los
pesos de la neurona.
5. BIAS, señal de entrada tiene como finalidad conocer cuál es el valor constante o “bias”
de la neurona. Esta señal de entrada consta con su propio valor genérico, el cual define
la amplitud de su bus de datos.
6. CE1, es una señal de tipo lógica (comúnmente llamada de ‘flag’, del inglés, bandera)
std_logic que se usará para controlar la activación del multiplicador a nivel alto, por lo
tanto, si es ‘0’ no se producirá la multiplicación en ese ciclo de reloj y al contrario si es
‘1’.
7. CE2, otra señal de tipo lógica o flag que se usará para activar el acumulador a nivel alto.
8. Por último, la señal Load es un flag que se emplea para diferenciar entre acumular solo
el peso de la neurona ya que es el peso inicial o acumular el dato anterior más el
resultado de la multiplicación entre el dato de entrada A y B. A nivel alto ‘1’ significará
que se ha de acumular el peso inicial exclusivamente y a nivel bajo se acumulará lo
acumulado anteriormente más el resultado de la multiplicación.
La señal de salida es una exclusivamente y será la señal result. Esta señal es un vector lógico,
pero a diferencia de los vectores lógicos de entrada vistos anteriormente, al tratarse de la salida
en la cual se pueden producir una multiplicación y una acumulación se la han añadido un
numero de bits extra para evitar lo comúnmente conocido como overflow (del inglés,
desbordamiento). También, se añadirán unos bits extras debido a que el bus de datos de “BIAS”
no tiene que ser igual que el de los datos de entrada. Por lo tanto, será un vector que irá desde
(nbits*nFlow*BiasBits) – 1 downto 0, como por ejemplo, si el valor de nbits es 1, nFlow es 2 y
BiasBits es 2, este vector sería (1*2*2 = 4) -1 downto 0, o lo que es igual, 3 downto 0 (‘0000’,
“0001”, …,”1111”). Lo más importante de esta señal de salida es que será asíncrona, ya que,
esta se produce fuera del proceso ‘CLK’.
Por otra parte, las señales internas son todas de tipo In/Out ya que estas son internas del
componente y no son visibles para el resto de los componentes. Estas señales serán de tipo
std_logic y al igual que la variable de salida “result” irá desde (nbits*nFlow*BiasBits) – 1 downto
48
0. Una será la señal Mreg, donde se guardará el resultado de la multiplicación entre “A” y “B” y
la otra será la señal accum, donde se almacenará el resultado de la suma entre el valor de la
iteración anterior y la multiplicación de la iteración actual.
Por último, los parámetros genéricos. Estos parámetros genéricos, son parámetros de tipo
natural configurables para distintos usos del proyecto. “nbits” el cual marca el tamaño del bus
de datos de los valores de entrada y salida. Un ejemplo sería, si deseas tener como entrada un
tipo entero que se representa con 32 bits, este parámetro se configurará con nbits = 32. El
parámetro genérico, que tratará el overflow, “nflow”, y, por último, “BiasBits”, el cual tendrá la
misma utilidad que “nbits” pero para el bus del peso inicial.
Una vez visto las distintas conexiones (puertos, señales y genéricos), se procederá a describir el
proceso funcional.
1. process (CLK)
2. begin
3. if CLK'event and CLK = '1' then
4. if RST = '1' then
5. acc <= (others => '0');
6. Mreg <= (others => '0');
7. else
8. if CE1 = '1' then
9. Mreg <= resize(unsigned(A)*unsigned(B),nbits*nflow*Bias
Bits);
10. end if;
11. if CE2 = '1' then
12. if LOAD = '1' then
13. acc <= resize(unsigned(BIAS),nbits*nflow); --
(bias)
14. else
15. acc <= acc + Mreg;
16. end if;
17. end if;
18. end if;
19. end if;
20. end process;
21. Result <= std_logic_vector(acc);
Como se puede apreciar es un proceso síncrono, cuyo principal evento es el reloj a nivel alto,
por lo tanto, si el reloj está a nivel alto se pasará al siguiente control lógico, que es el reset, si
este está activo se procederá a poner a ‘0’ las señales internas del correspondiente. Sin
embargo, si no está activo las siguientes unidades de control al mismo nivel por lo que se
realizarán en el mismo ciclo, serán los clock enable, tanto como el del multiplicador como el del
49
acumulador. Si el clock enable del multiplicador está a nivel alto se multiplicarán ‘A’ y ‘B’ y el
resultado se asignará a la señal Mreg. Por otro lado, cuando el clock enable del acumulador este
activo si la señal ‘LOAD’ está a su vez activa se acumulará ‘BIAS’ sino se acumulará el resultado
de la iteración anterior con el registro de la multiplicación ‘Mreg’.
Por último, como se ha dicho anteriormente el resultado del acumulador se asignará a la salida
‘result’ de manera asíncrona, esto se hace así ya que como se ha visto en la arquitectura el
control de las iteraciones que realizará este proceso se hará en la entidad que está por encima
del componente neuron. Para que sea más sencillo de entender en el siguiente diagrama de
flujo figura 3.2.1 se mostrará los estados por los que pasará este componente en un ciclo de
reloj a nivel alto de manera gráfica (aunque luego cada instrucción conlleve más ciclos de reloj).
50
3.2.2 Sigmoid
Como se expuso en la parte arquitectural de la función de activación de las neuronas, esta
función será la función sigmoid y esta entidad se encargará de realizar dos procesos uno de
escritura en una LUT y otra de controlar el proceso de acceso a la misma.
1. entity Activation_Sigmoid is
2. generic
3. (
4. nbits : natural;
5. nflow : natural;
6. BiasBits: natural;
7. Prange: real;
8. Pinicial: real;
9. step: real
10. );
11. port
12. (
13. reset : in std_logic;
14. clk : in std_logic;
15. run_in : in std_logic; -- Start and input data
validation
16. inputs : in std_logic_vector((nbits*nflow*BiasBits)-
1 downto 0); -- Input data
17. run_out : out std_logic; -- Output data validation, run_in
for the next layer
18. outputs : out std_logic_vector(nbits-1 downto 0) -- Output
data
19. );
20. end Activation_Sigmoid;
Esta tiene seis genéricos los cuales son muy importantes ya que son los datos iniciales de los
que partirá la discretización de la función:
1. nbits: Como en todas las entidades este parámetro es el número de bits del bus de
datos.
2. nflow: Número de bits para evitar el overflow que se trasmite debido al posible
desbordamiento que puede provocar la salida del componente neuron.
3. BiasBits: Número de bits del bus de datos para el puerto de entrada “BIAS” o peso inicial.
51
6. Step: Debido a que se está haciendo una discretización se necesita dar un valor escalón
ya que dependiendo del valor de X se tratará de un escalón u otro.
3. Run_in: Puerto de entrada para saber si hay que hacer el proceso de lectura en la LUT.
4. Inputs: Datos de entrada producidos por una neurona, por lo tanto, este puerto irá
desde longitud (nbits*nflow*BiasBits – 1) downto 0 ya que, en las salidas de las
neuronas, y, el valor de “BIAS” se puede producir un desbordamiento.
5. Run_out: Puerto de salida para dar paso a la siguiente iteración ya que se ha acabado el
proceso de lectura en la LUT.
Una vez vistas las señales tanto genéricas como los puertos de entrada/salida en esta
arquitectura hay dos fases muy importantes ya que una será donde se hará el desarrollo de la
función sigmoid y otro el proceso de lectura y su debido control.
52
14. for idx in -(2**((nbits*nflow*BiasBits)-
1)) to (2**((nbits*nflow*BiasBits) -1))-1 loop
15. result := Prange/(1.0+exp(((-
step*Pinicial)/Prange)*x)) - (Prange/2.0); --density function from
sigmoid
16. real_result := result*(2.0**((nbits*nflow*BiasBits)-
1)); -- without signed
17. real_result := round(real_result); -- rounded the
number for discretation
18. F_result := integer(real_result); -- change to
integer
19. fbits := std_logic_vector(to_signed(F_result,nbits))
; -- convert to vector for saving in the LUT
20. table(to_integer(to_unsigned(idx+(2**(nbits*nflow*Bi
asBits)),(nbits*nflow*BiasBits)))):= fbits; -- save in the LUT
21. x := x+scale; --swap range.
22. end loop;
23. return table;
24. end Sigmoidal;
25.
26. signal Table: table_sigmoid := Sigmoidal(1.0,nbits, BiasBits,
nflow); -- Generation of the LUT (at synthesis time)
La table_sigmoid será un tipo especial (type table_sigmoid) que consistirá en un vector, pero
limitado en función de nbits, nflow y BiasBits, más específicamente será de longitud
2𝑛𝑏𝑖𝑡𝑠 × 𝑛𝑓𝑙𝑜𝑤 × 𝐵𝑖𝑎𝑠𝐵𝑖𝑡𝑠 ya que sé tendrá que tener el mismo número de entradas en la LUT que
posibilidades de datos de entrada. Por otra parte, una vez que se acceda a este vector, el valor
dentro del mismo (este es el valor con el que se activa la neurona) tendrá una longitud igual al
número de bits del parámetro genérico nbits - 1 downto 0.
Para poner un ejemplo más sencillo de entender, si nbits es 2, nflow es 2 y BiasBits es 2 esta
tabla irá desde 0 𝑡𝑜 2(2∗2∗2) − 1 o lo que es igual desde 0 hasta 255 y por lo tanto se tendrá
este número de entradas en la LUT.
Además, estará la función que rellena este tipo “table_sigmoid”. A esta función se le pasará el
margen que se quiere, el número de bits de entrada y el número de bits de overflow. En primer
lugar, se creará una constante que generará los escalones en función de la dimensión de los
datos de entrada y el margen que se asigne, esta constante será en función de la fórmula:
2∗𝑚𝑎𝑟𝑔𝑖𝑛
𝑠𝑐𝑎𝑙𝑒 = . Por ejemplo, el escalón para 4 bits de entrada, 2 de
2𝑛𝑏𝑖𝑡𝑠 ×𝑛𝑓𝑙𝑜𝑤 × 𝐵𝑖𝑎𝑠𝐵𝑖𝑡𝑠
2 ×1
desbordamiento, 1 de bias y un margen de 1 será = 0.0078 lo que significa es que cada
28
escalón de la función será de 0.0078 más que el valor anterior, iniciándose, el primer escalón,
en 0.
53
En segundo lugar, se iniciará la variable X de la función al parámetro de entrada del margen y
se realizará un bucle que recorrerá básicamente lo mismo que el tipo sigmoid solo que este
tratará también los números negativos y por lo tanto el recorrido será:
−(2((𝑛𝑏𝑖𝑡𝑠∗𝑛𝑓𝑙𝑜𝑤∗𝐵𝑖𝑎𝑠𝐵𝑖𝑡𝑠)−1) ) 𝑡𝑜 (2((𝑛𝑏𝑖𝑡𝑠∗𝑛𝑓𝑙𝑜𝑤∗𝐵𝑖𝑎𝑠𝐵𝑖𝑡𝑠) −1) ) − 1. Nótese la resta del 1 para
quitar un bit al vector y así poder tener el mismo número de negativos que de positivos.
Una vez dentro del bucle se define la función de densidad (discretizándola) que será:
𝑃𝑟𝑎𝑛𝑔𝑒
𝑓 (𝑥 ) =
−𝑠𝑡𝑒𝑝∗𝑃𝑖𝑛𝑖𝑐𝑖𝑎𝑙
(( )∗𝑥) 𝑃𝑟𝑎𝑛𝑔𝑒
𝑃𝑟𝑎𝑛𝑔𝑒
(1 + 𝑒 )−(
2 )
Para finalizar, se cambiará de rango en la escala, por lo tanto, a X (el valor inicial era el margen)
se le sumará el valor scale, anteriormente descrito.
Por otro lado, se definirá el proceso de acceso y control (como se observa en la figura 3.2.2) a
esta LUT la cual se generará en síntesis ya que después de terminar la función se añadirá una
señal:
Esta llamará a la función descrita anteriormente y al ser una instanciación de una señal se
asegura que se creará en síntesis y no dará problemas de compatibilidad.
Por lo tanto, se tiene la LUT en la señal Table, ahora bien, el proceso funcional será:
1. begin
2.
3. -- Description of the activation function
4. dataIn <= to_integer(unsigned(inputs));
5. Activation: process(clk,reset)
6. begin
7. if clk'event and clk = '1' then
8. if reset = '1' then
9. run_out <= '0';
10. outputs <= (others => '0');
54
11. else
12. if run_in = '1' then
13. run_out <='1';
14. outputs <=Table(dataIn); -- Assigns output
value from the LUT
15. else
16. run_out <='0';
17. end if;
18. end if;
19. end if;
20. end process;
En primer lugar, se transforma el vector de entrada a entero para poder acceder a su correcta
posición en la LUT, luego sigue el proceso que, al ser síncrono, se activa cuando la entrada de
reloj esté a nivel alto. Si el puerto de entrada reset está activo se reinician las salidas, si no se
continua con el proceso de acceso a la LUT en la que se encuentran los resultados de la función
sigmoid. Por consiguiente, lo primero y único que se comprobará será si el puerto de entrada
run_in está activa ya que significará que el resultado en la neurona asociada estará listo, se
activará la señal que da paso a la siguiente parte del proceso de la entidad neuron_top y se
asigna valor al dato de salida “outputs” según el valor de la LUT en función del valor “dataIn”.
Todo este proceso se puede observar en la siguiente figura 3.2.2, la cual, es un diagrama de
flujo que describe el proceso anterior.
1. entity neuron_top is
2. Generic(
3. NnAnt: natural;
4. BiasBits: natural;
5. nbits: natural --- Bit width of the input data
6. );
7. Port (
8. DATAIN: in STD_LOGIC_VECTOR((nbits*NnAnt)-1 downto 0);
9. CLOCK: in STD_LOGIC;
10. Wdata: in STD_LOGIC_VECTOR((nbits*NnAnt)-1 downto 0); -
- Data weight port
11. Start_neuron: in STD_LOGIC;
12. Init_neuron: in STD_LOGIC_VECTOR((nbits*BiasBits)-
1 downto 0); -- bias neurons
13. RESET: in STD_LOGIC; -- reset
14. Fneuron: out std_logic; -- finish that iteration
15. Odata: out STD_LOGIC_VECTOR(nbits-1 downto 0)
16. );
17. end neuron_top;
Los puertos de entrada/salida y los parámetros genéricos de este componente son los
siguientes:
2. BiasBits número de bits del bus de datos del peso de la neurona inicial o “bias”.
1. DATAIN o lo que es igual datos de entrada, lo más importante de este puerto es que
como se puede apreciar en el trozo de código anterior va desde longitud (nbits*Nnant)
– 1 downto 0, esto significa que será un puerto de entrada que depende de la cantidad
de neuronas que había en la capa anterior donde, por ejemplo, si se tienen 3 neuronas
en la capa anterior y el bus de datos son de dos bits este vector tendrá como límite de
su índice desde 5 hasta 0.
2. CLOCK, el reloj.
3. Wdata, este es el vector de los pesos al igual que los datos de entrada este depende de
las neuronas de la capa anterior.
56
4. Start_neuron, es el puerto de entrada que da lugar al inicio del controlador.
Los de salida son dos, uno para indicar que se ha finalizado la iteración y se tiene el resultado
disponible (Fneuron) y 0data que es el vector de salida o el resultado que estará listo cuando la
otra señal se active.
Todas ellas son por lo general señales auxiliares para facilitar el proceso que va a controlar los
componentes “neuron” y “sigmoid”. Por otro lado, la señal de estado, que se usará para realizar
un diagrama de flujo que constará de cinco estados.
En primer lugar, en esta arquitectura existen tres partes diferenciales, las cuales se tratarán de
manera independiente, aunque sean totalmente complementarias, incluso, dependientes para
que sea más sencillo de explicar. La primera parte de un proceso con lista de sensibilidad los
57
puertos CLOCK, Init_neuron, Wdata, DATAIN, y RESET. Dentro de este proceso se distinguen
dos apartados un bucle for y un evento síncrono o lo que es igual un evento de reloj:
• En el bucle for lo que se hará es rellenar los distintos datos alojados en los puertos
de entrada Wdata y DATAIN a las señales auxiliares “Weight” y DataInVector,
ambas vectores enteros, con el fin de que sea más fácil acceder a ella según el
estado en el que se esté del flujo.
• Por otro lado, como se ha dicho, dentro del proceso se realizará un flujo de datos
que irá desde el estado “e0” al “e4” o lo que es igual cinco estados donde se
controlarán cuantas iteraciones se tienen que hacer, si la neurona tiene que
multiplicar, acumular o si se tiene el resultado para pasarlo al componente sigmoid,
etc. Como se puede ver en el siguiente diagrama de flujo figura 3.2.3 según en el
estado en el que se encuentre el proceso se harán unas determinadas acciones.
1. El estado cero es el estado inicial en el cual se comprobarán si la señal reset está activa,
el puerto “Start_neuron” está desactivado o se ha finalizado la iteración (NeuronFinish)
como consecuencia se reiniciarán todas las salidas y señales, además, se entrará en el
bucle sobre el estado inicial. Sin embargo, si ocurre lo contrario se comprobará si es la
primera iteración, si es, se acumula el peso inicial, “BIAS”, ya que no hace falta
multiplicar y se procederá a ir al estado “e2”. Por otro lado, si no es la primera iteración
se multiplicará el dato de entrada por el peso correspondiente a esa neurona asociado
a ese dato de entrada y se irá al estado “e1”.
58
3. En el estado dos solo se llegará si es la primera iteración de todas ya que consiste en
acumular el peso inicial o “bias”, por lo que solo se dejará un ciclo de reloj para que
acumule y en este estado se aumentará el contador “Aweights” (contador que se usa
para delimitar el número de iteraciones en función de las neuronas de la capa anterior)
y se vuelve al estado inicial 0 o “e0”.
Todo lo anterior, con las diferentes transiciones entre los distintos estados, en forma de
diagrama de flujo, se muestra en la siguiente figura.
59
Figura 3.2.3. Diagrama de flujo proceso Neuron top.
1. entity Layer_Generation is
2. Generic(
3. nbits: natural;
4. NN: natural;
5. NnAnt: natural;
6. id: natural:=0
7. );
8. Port (
60
9. DATAIN: in STD_LOGIC_VECTOR((nbits*NnAnt)-1 downto 0);
10. CLOCK: in STD_LOGIC;
11. Start_layer: in STD_LOGIC;
12. RST: in STD_LOGIC;
13. Fneurons: out STD_LOGIC;
14. Odata: out STD_LOGIC_VECTOR((nbits*NN)-1 downto 0) --DATAOUT
is a vector to group all Outs of de neurons
15. );
16. end Layer_Generation;
Este componente consta de cuatro puertos de entrada, dos de salida, cuatro variables
genéricas y el componente neuron_top.
Señales Genéricas:
3. NnAnt: Número de neuronas del layer anterior o del número de entradas si es la capa
inicial.
4. Id: Este elemento es un id asociado a cada layer para distinguir entre capas iniciales,
ocultos y finales.
4. Start_layer: Puerto de entrada que da el paso inicial para iniciar las operaciones del layer
en cuestión.
6. Odata: Puerto de salida por donde irán los datos de salida de este componente
61
componente genérico. En este proceso se dividirán en dos vectores, uno para el peso inicial de
las neuronas (bias) y otro con el resto de los pesos de la matriz. Como puede observarse en el
código mostrado a continuación:
En este código se puede observar la manera en la que se crean los dos vectores descritos
anteriormente, para más tarde pasar a cada neurona sus pesos frente al layer anterior
correctamente. Como no se pueden pasar vectores multidimensionales como si fueran señales
del siguiente componente (en este caso componente neuron) el modo de desarrollo que ha
sido tratado es el siguiente:
1. Se tiene una matriz W con los pesos en memoria, por lo que se recorrerá con un doble
for el primero para iterar sobre filas y el siguiente sobre columnas.
2. También, en otro vector, se tienen los valores asociados al peso inicial o bias.
62
En segundo lugar, se hará una comprobación dentro del proceso para determinar si han
finalizado todas las neuronas de hacer sus operaciones. Esto se hace simplemente para que
el componente superior a este sepa que ya están terminadas todas las operaciones del
layer. También tiene un propósito adicional, que no haya condiciones de carrera como se
puede observar en el siguiente código:
1. entity top_layers is
2. Generic(
3. nbits: natural;
4. NIn: natural;
5. NtotalLayers: natural;
6. NLayerInit: natural;
7. NLayerOthers: natural;
8. NLayerFinish: natural
9. );
10. Port (
11. DATAIN: in STD_LOGIC_VECTOR((nbits*NIn)-1 downto 0);
12. CLK: in STD_LOGIC;
13. RESET: in STD_LOGIC;
14. start_ANN: in STD_LOGIC;
63
15. OdataANN: out STD_LOGIC_VECTOR(nbits-1 downto 0);
16. FinishANN: out STD_LOGIC
17. );
18. end top_layers;
Esta entidad cuenta con 4 puertos de entrada, 2 de salida, 6 genéricos y como en todas las
entidades el componente anterior layer generation.
Señales Genéricas:
4. NLayerInit: Número de neuronas de la capa inicial ya que se necesita distinguir entre los
iniciales, los ocultos y el de salida.
5. NLayerOthers: Número de neuronas de las capas ocultas, todas ellas tendrán el mismo
número de neuronas.
6. NLayerFinish: Número de neuronas del layer final, si son varias se estaría realizando una
regresión y si es una neurona sería una clasificación.
7. RESET: Puerto de entrada para reiniciar los valores de todos los componentes.
8. CLOCK: Puerto de entrada para controlar (la sincronización) los ciclos de reloj de todos
los componentes.
9. DATAIN: Puerto de entrada de datos, el tamaño variará dependiendo del tamaño del
bus de datos y del número de datos de entrada.
10. Start_ANN: Puerto de entrada que da el paso inicial para iniciar la red neuronal.
11. FinishANN: Puerto de salida que dará por finalizada una iteración completa de la red
neuronal.
64
Una vez visto, los puertos de la entidad lo único que se hará en este componente es
parametrizar todos los componentes según los datos genéricos que se han definido.
Para ello se han realizado cinco tipos distintos de generaciones del componente
layer_generation, ya que, las señales y los puertos tienen que ir conectados de manera distinta.
En primer lugar, se declara un for que generará el número de capas que se hayan definido en
el puerto genérico NtotalLayers. La primera instanciación es el layer inicial porque en este
caso a los valores genéricos del componente layer_generation se le asignará el número de
neuronas iniciales que se elijan para esta capa, luego el número de neuronas anterior sería el
mismo número de entradas y por último el id el 0.
1. port map (DATAIN => DATAIN, CLOCK => CLK, Start_layer => start_ANN, RST
=> reset_all, Fneurons => Flayer(r), Odata => OlayerInit);
Los datos de entrada en este caso son los que vengan del mismo puerto, luego el inicio del layer
será el inicio de la red neuronal y el puerto de salida será una señal para pasar como puerto de
entrada DATAIN del siguiente.
En la segunda instanciación se trata el caso en el que solo existan dos layer en la red neuronal
ya que podría no haber capas ocultas y existir, solamente, un layer inicial y otro final. Para ello
se comprueba primero que haya como máximo dos capas y además se esté en el layer final.
65
1. port map (DATAIN => OlayerInit, CLOCK => CLK, Start_layer => Flayer(r-1),
RST => reset_all, Fneurons => Flayer(r), Odata => OdataANN);
Los datos de entrada son los datos de salida del layer inicial, el inicio de esta capa será el final
de la capa inicial, el final del layer será el final de la iteración de la red neuronal y, por último,
los datos de salida serán los datos de salida de la red neuronal.
A continuación, hay dos instanciaciones que son parecidas y son las de las capas ocultas. Hay
una diferencia entre una y otra y es simplemente que la que es posterior al layer inicial hay que
instanciarla de manera distinta por lo que a esta se nombrará “LX1” y a la genérica “LX”. Primero
se desarrollará la genérica ya que “LX1” es un cambio simple. Como se muestra en el siguiente
código:
Si se está en el caso de que no sea el layer inicial ni el final, es un layer oculto por lo que tanto
el número de neuronas del layer como las del layer anterior serán iguales.
Los puertos asignados de los layers ocultos “LX” serán, como se muestran a continuación:
1. port map (DATAIN => OlayerOthers(r-1), CLOCK => CLK, Start_layer =>
Flayer(r-1), RST => reset_all, Fneurons => Flayer(r), Odata =>
OlayerOthers(r));
Los datos de entrada serán los datos de salida del layer oculto anterior y los datos de salida
serán asignados a una señal, la cual es un vector con los datos de salida de cada capa oculta
para poder asignarle a los datos de entrada de la siguiente capa oculta.
La diferencia entre “LX1” y “LX” está en que el número de neuronas de la capa anterior es el
número de neuronas del layer inicial y que la entrada de datos es la salida del layer inicial.
Por último, sería la instanciación de la capa final genérica (en el cual existen capas ocultas). Lo
anterior, codificado, se muestra a continuación:
66
Si se está en el caso final, el número de neuronas dependerá si será una regresión o una
clasificación, luego el número de neuronas del layer anterior será el que tengan las capas
ocultas.
Para dar por concluido este capítulo, la asignación de puertos, en este caso, será como se
muestra en el siguiente código:
1. port map (DATAIN => OlayerOthers(r-1), CLOCK => CLK, Start_layer =>
Flayer(r-1), RST => reset_all, Fneurons => Flayer(r), Odata => OdataANN);
Los datos de entrada DATAIN serán el último valor del vector asociado a los layers ocultos, el
final de este layer corresponderá con el final de una iteración de la red neuronal y los datos de
salida serán los datos de salida de la red neuronal.
67
68
Capítulo 4: Resultados
En este capítulo se abordará todo lo que respecta a resultados de simulación de las distintas
entidades y un ejemplo funcional del proyecto en conjunto. Para ello, como se ha explicado
anteriormente, se trata de una arquitectura bottom-to-top, por lo que, del mismo modo, se
definirán las distintas simulaciones funcionales. En estas simulaciones o pruebas se
comprobarán que todas entidades cumplen los requisitos definidos en el desarrollo,
asegurando así, ningún comportamiento erróneo.
69
lo que es igual, Mreg = “4”. A su vez, se puede comprobar que el resultado P y el acumulador
están con valor a “0”, lo cual, es correcto.
La siguiente comprobación, será desactivar CE1, activar el CE2, dando como resultado que
el acumulador tendrá el valor multiplicado anteriormente o lo que es igual acc = “4” y la
salida P igual que el acumulador. En la figura 4.1.2 se comprueba este caso.
A continuación, se comprobará que si el CE2 = ‘1’ y a su vez el LOAD = ‘1’ el acumulador será
igual al valor de entrada de BIAS, que, en este caso será 1. Como se muestra en la figura 4.1.3
Por lo tanto, si se tiene un bus de datos de 2 bits, 2 bits para evitar posibles desbordamientos y
1 bit en el bus de datos de “BIAS”, la LUT tendrá una capacidad de almacenamiento de
2(2∗2∗1) = 16 posibles combinaciones. Para poder facilitar el entendimiento de los ejemplos,
según los estímulos de entrada, se definirá una tabla de verdad que simula el resultado de la
función sigmoid con valores genéricos: BiasBits igual a 1 y nbits, nflow, Prange, Pinicial, step
igual a 2.
71
a b c d out
0 0 0 0 0
0 0 0 1 1
0 0 1 0 2
0 0 1 1 3
0 1 0 0 0
0 1 0 1 0
0 1 1 0 1
0 1 1 1 2
1 0 0 0 2
1 0 0 1 2
1 0 1 0 3
1 0 1 1 0
1 1 0 0 0
1 1 0 1 1
1 1 1 0 2
1 1 1 1 3
En la siguiente figura, se puede observar como con la señal de entrada, run_in, activa (indicando
que se puede acceder a la tabla que guarda los resultados de la función sigmoid) y un valor de
entrada de “1000” se obtiene en la salida un “2”, ya que, si se observa en la tabla 4.2.1 el valor
asociado a el “1000” es “2”. En este apartado se puede observar que cuando se produce una
salida, también, se genera una señal de salida “run_out”, encargada de avisar a la entidad
superior.
72
Figura 4.2.1. Simulación entidad sigmoid, primera comprobación.
El siguiente y último requerimiento en este módulo, es que, si el valor de reset se activa, tanto
el valor de “outputs” y “run_out” deberán volver a su estado original, como se puede apreciar
en la figura 4.2.2 mostrada a continuación.
A continuación, se procederá a multiplicar el valor de entrada “DATAIN” con valor “10”, por
el peso de la neurona que se ha establecido en “11”, por lo que el resultado será “0110”, o,
en decimal, 3 x 2 = 6. Como el acumulador de la entidad neuron, tenía un 3 procedente del
paso anterior, el resultado final, será la suma de ambos, 6 + 3 = 9, en binario, “1001”.
Simulación mostrada en la siguiente figura:
74
Figura 4.3.2. Simulación entidad neuron_top, segunda comprobación.
También, hay que recalcar, que, en esta simulación al tener la variable genérica “Nant”, con
solo una neurona anterior, solo existirá una iteración del proceso. Pero este proceso se repetiría
tantas veces como neuronas anteriores se tengan.
75
4.4 Simulación de la entidad Layer generation
Para la simulación de esta entidad algunos parámetros genéricos cambiaran, ya que, se vuelve
más tedioso el seguimiento del proceso.
2. Número de neuronas anteriores, “Nant” igual a 2 (en este caso las neuronas anteriores
serán los valores de entrada).
3. Número de neuronas del layer, “NN” igual a 2, por lo que, se tendrá 2 entidades
“neuron_top”.
1 1 1
Con los valores genéricos anteriores, y, la matriz de pesos , se genera una estructura
0 1 1
como la que se puede observar en la siguiente figura 4.4.1.
Además, se genera una LUT con los valores generados por la función sigmoid tal que:
X1 X2 Out
0 0 0
0 1 1
1 0 0
1 1 1
Tabla 4.4.1. Tabla de verdad función sigmoid, bus de datos de 1 bit.
76
Figura 4.4.1. Estructura generada para la simulación de la entidad layer generation.
Neurona “N1”: En primer lugar, se le sumaría el peso de la neurona “Bias” por lo que, en
“N1” se tendría un resultado de “1”. En la segunda iteración, se multiplicaría el valor de
entrada “X1” por el peso de “X1-N1”, o lo que es igual, 1*1 = 1 y se le sumaría el resultado
anterior, dando lugar, “N1” = 2. En la última iteración, se multiplicaría, el valor de entrada
“X2” por el peso de “X2-N1”, 0*1 = 0, obteniendo un resultado final en “N1” de 2. Para
finalizar, el resultado de “N1” (en este caso en binario sería “10”) se accedería a la LUT
donde están guardados los resultados de la función sigmoid, y, se obtiene que para el valor
“10” el resultado es un “0” (como se aprecia en la tabla 4.4.1).
Neurona “N2”: El mismo proceso que la neurona anterior, primero se le sumaría el peso de
la neurona “Bias” por lo que, en “N2” se tendría un resultado de “0”. En la segunda iteración,
se multiplicaría el valor de entrada “X1” por el peso de “X1-N2”, o lo que es igual, 1*1 = 1 y
se le sumaría el resultado anterior, dando lugar, “N2” = 1. En la última iteración, se
77
multiplicaría, el valor de entrada “X2” por el peso de “X2-N2”, 0*1 = 0, obteniendo un
resultado final en “N2” de 1. Para finalizar, el resultado de “N2” (en este caso en binario
sería “01”) se accedería a la LUT donde están guardados los resultados de la función sigmoid,
y, se obtiene que para el valor “01” el resultado es un “1” (como se aprecia en la tabla 4.4.1).
Este mismo proceso, pero con la simulación funcional producida por la entidad, se puede
apreciar en la siguiente figura:
El proceso es el mismo descrito anteriormente, pero hay que clarificar dos circunstancias que
pueden llevar a error.
El primer factor a tener en cuenta, son los vectores de entrada y de salida. Aunque, en el
apartado de desarrollo ya se ha explicado, debido a que en las entidades no se pueden definir
puertos de tipo matricial lo que se hace es dividir un vector de entrada lógico en n partes
dependiendo del número de neuronas anteriores. Por lo tanto, en este ejemplo el vector de
entrada tiene que ser de tamaño 2 bits, uno para la entrada “X1” y el otro para la entrada “X2”,
más específicamente, si el vector de entrada es 01, la entrada “X1” tendrá un valor de “1” y la
entrada “X2” un valor de “0”. Lo mismo con el valor de salida, “Odata” es igual a “10” por lo
que, la neurona “N1” tiene un valor de “0” y la neurona “N2” de “1”.
El segundo factor a tener en cuenta es que el resultado no está disponible hasta que todas las
neuronas han terminado su proceso. Esta casuística se puede apreciar cuando la señal
“Fneurons“se activa a nivel alto. La señal también produce que se reinicien los valores de salida
78
de las neuronas, por lo tanto, para observar los resultados de las neuronas se tienen que
observar un ciclo de reloj antes.
Para ello, es importante saber cómo se forma una XNOR y su tabla de verdad. La puerta lógica
XNOR, con representación lógica, 𝐴 . 𝐵 + 𝐴̅ . 𝐵̅ , se puede realizar con otras puertas lógicas, para
ser exactos, una de las posibilidades es mediante el uso de una puerta AND, una NOR y una OR.
A continuación, en la tabla 4.5.1 se observa su tabla de verdad.
Por consiguiente, para realizar esta misma expresión lógica usando una red neuronal que
clasifique si el valor de entrada produzca las mismas salidas que se generarían en una puerta
lógica XNOR, se hará uso de varias figuras.
En la primera figura 4.5.1 mostrada a continuación, se muestra el valor de los pesos que
deben tener las neuronas y bias, para la obtención de la puerta lógica x1 AND x2, teniendo en
cuenta varios factores:
79
Figura 4.5.1. Red neuronal que clasifica una puerta lógica AND.
Por otro lado, la puerta lógica NOR, teniendo en cuenta los puntos anteriores sería como en
la figura 4.5.2.
Figura 4.5.2. Red neuronal que clasifica una puerta lógica NAND.
A continuación, la puerta lógica OR, figura 4.5.3, misma situación que en las anteriores.
80
Figura 4.5.3. Red neuronal que clasifica una puerta lógica OR.
Estas son las puertas lógicas que se necesitan para forma la XNOR. Ahora si se agrupan todas
quedaría una red neuronal con 2 entradas y dos capas. En la capa 2, se tendrían dos
neuronas y en la capa 3 o capa de salida se tendría una neurona. El resultado se puede
observar en la siguiente figura. Una vez vista la estructura generada, la tabla con los
resultados de la función sigmoid asociada a este ejemplo, consta de 16 entradas, debido a
que el valor BiasBits es igual a 2 y nflow igual a 2 se genera una tabla de 24 = 16.
81
a b c d out
0 0 0 0 0
0 0 0 1 0
0 0 1 0 1
0 0 1 1 1
0 1 0 0 0
0 1 0 1 0
0 1 1 0 1
0 1 1 1 1
1 0 0 0 1
1 0 0 1 1
1 0 1 0 1
1 0 1 1 0
1 1 0 0 0
1 1 0 1 1
1 1 1 0 1
1 1 1 1 0
82
Figura 4.5.4. Red neuronal que clasifica una puerta lógica XNOR.
Por consiguiente, realizando el proceso paso a paso, por ejemplo, para unos valores de entrada
X1 igual a 0 y X2 igual a 0:
1. En la primera iteración se tendría que N1(operación AND) con valores de entrada 00,
cuando se acumula la neurona inicial un 0, ya que, el peso asociado es 00. Sin embargo,
en N2(operación NOR), se acumularía el peso asociado 11, por lo que se obtiene un
resultado de 3.
2. Para la segunda iteración, se tendría que X1, siendo igual a 0 multiplicado por el peso 1,
daría un 0 como resultado. Por otro lado, para la neurona N2, con peso igual a 1, se
obtendría un resultado de 0, si se suma con el resultado anterior seguiría como estaba,
o lo que es igual 3.
3. En la tercera iteración, con X2 igual 0, sería el mismo resultado que la segunda iteración,
produciendo un valor de salida de N1 = 0 y N2 = 3.
4. Para finalizar con las iteraciones del primer layer, los valores obtenido se pasarían por
la tabla de la función sigmoid, produciendo un valor de resultado para N1 = 0 y N2 = 1
(como se puede observar en la tabla 4.5.2, para valores N1= “0000” y N2=”0011”) y un
83
estímulo de salida que comunica a la entidad que puede pasar a la siguiente capa con
valores de entrada previamente dichos.
Para la verificación completa, de forma análoga, se hace con las otras tres parejas de entrada,
obteniéndose el resultado esperado. En las siguientes figuras, se puede observar los distintos
resultados para todas las combinaciones de una puerta lógica XNOR de dos bits de entrada. El
valor de salida de la ANN es “OdataANN”, el flag de final del proceso de scoring es “FinishANN”,
el valor de entrada es “DATAIN y el resto son señales que contiene los pesos de cada neurona
y las salidas producidas en las distintas capas.
Figura 4.5.5. Resultado ANN (clasificando XNOR), para un valor de entrada “00”.
84
Figura 4.5.6. Resultado ANN (clasificando XNOR), para un valor de entrada “01”.
Figura 4.5.7. Resultado ANN (clasificando XNOR), para un valor de entrada “10”.
85
Figura 4.5.8. Resultado ANN (clasificando XNOR), para un valor de entrada “11”.
86
Capítulo 5: Planificación
En este apartado se expondrá la planificación del proyecto mediante el siguiente diagrama de
Gantt.
Los tiempos son a nivel semanal, suponiendo que hubiese un analista-programador el cual se
encarga de los dos primeros hitos y un programador que se encarga de los otros dos, daría lugar
a unos presupuestos como los que se aprecian en la siguiente tabla (teniendo en cuenta que
los salarios son acordes al boletín oficial de la comunidad de Madrid (BOCM) de 2019):
Mensual
Tabla 5.1. Tabla de costes humanos y materiales del proyecto en base al tiempo.
87
Teniendo en cuenta que los costes materiales son solo un ordenador para poder realizar todo,
y que, las licencias del software usado para la simulación funcional son gratuitas. El proyecto
tendría un coste total de 11.634,16 €.
88
Capítulo 6: Aspectos éticos, sociales y
ambientales
En este capítulo se identificarán, describirán y analizarán los distintos aspectos sociales, éticos
y ambientales más relevantes tanto positivos como negativos.
6.1 Identificación
En primer lugar, para poder identificar estos aspectos de manera sencilla, hay que sesgar el
ámbito del proyecto. Este proyecto pertenece al ámbito de las tecnologías de la información y
comunicación, más específicamente, al diseño y modelado hardware.
Por otra parte, este proyecto tiene como finalidad investigación y análisis de viabilidad.
6.2 Descripción
Los principales problemas éticos/legales que se van a abordar son los siguientes:
1. Propiedad intelectual.
2. Privacidad.
2. Seguridad y mantenimiento.
1. Agentes contaminantes.
2. Consumo eléctrico.
3. Reutilización o reciclaje.
6.3 Análisis
El análisis se realizará acorde al orden definido anteriormente.
89
Con lo que a propiedad intelectual se refiere, cabe destacar varios aspectos. La figura del tutor
de proyecto, las de las entidades involucradas en el desarrollo, y, la normativa UPM
(Universidad Politécnica de Madrid) como entidad para prevenir y detectar posibles plagios.
Conviene recalcar, que, cualquier información, documentación, idea, etcétera no realizado por
el autor y/o tutor del proyecto ha sido correspondientemente referenciada siguiendo la
normativa APA.
Por lo que a privacidad respecta, este proyecto tiene un fin de investigación y académico,
teniendo como consecuencia que, cualquier uso de datos, serán de carácter aleatorio o
totalmente anonimizados. Si bien es cierto que el alcance de este proyecto es, para ser usado
en un contexto de big data, en el caso de uso comercial se deberá seguir la normativa de la
LOPD.
La ley orgánica de protección de datos se define como “Ley Orgánica que tiene por objeto garantizar
y proteger, en lo que concierne al tratamiento de los datos personales, las libertades públicas y los
derechos fundamentales de las personas físicas, y especialmente de su honor e intimidad personal y
familiar” (BOE, 2000). Como se ha mencionado anteriormente, en lo que al tratamiento de
datos respecta, en este proyecto no se usarán ningún tipo de dato de carácter personal. Sin
embargo, si su uso fuese necesario, a los propietarios de dichos datos se les proporcionaría un
documento de consentimiento de cesión de datos, en el cual, constaría la concesión, uso y la
posibilidad de la eliminación total de los mismos.
Siguiendo con los aspectos sociales, con respecto a la seguridad y mantenimiento del sistema,
por un lado, la seguridad estará basada en el bit de anticopia que una FPGA nos proporciona
provocando que sea muy difícil el acceso al código embebido y los datos que circulan por el
mismo. También, destacar que el flujo de datos previo al acceso del sistema tendrá que cuidar
de la seguridad y protección de los datos, pero, el sistema no se responsabilizará de la seguridad
y protección en ese contexto.
Por otra parte, para el mantenimiento se han definido una seria de líneas futuras, en las cuales
se mejoraría el rendimiento y la usabilidad del sistema.
90
Para finalizar, en lo que al medioambiente se refiere, en este proyecto uno de los principales
puntos en los que se ha hecho hincapié, es en el consumo energético con respecto a las mimas
soluciones usando un hardware distinto. Por lo tanto, aunque, el sistema se nutre de energía
eléctrica (no autogenerada), el ahorro energético es importante. Por último, los agentes
contaminantes, al estar usando chips, PLCs, etc, son, por lo general, materiales como, plásticos,
el caso de desecho se tendrá que reciclar de manera coherente, ya que, muchos de los
91
92
Conclusiones
En primer lugar, todos los hitos han sido alcanzados satisfactoriamente de tal manera que
siguiendo el orden de hitos propuestos en el apartado de objetivo se concluye que:
1. Se han adquirido los conocimientos necesarios sobre redes neuronales artificiales, para
poder realizar dicho proyecto, mediante uso de documentación y cursos certificados, las
cuales se pueden encontrar en la bibliografía de este proyecto. También se han usado
conocimientos previos impartidos en el Grado de Ingeniería de Computadores de la
Universidad Politécnica de Madrid en asignaturas como Integración de Sistemas,
Sistemas Digitales, Mecatrónica, Sistemas con Microcontroladores y Microprocesadores
para dar una solución a nivel hardware y estructural apropiada al proyecto.
4. Por último, se ha conseguido realizar un ejemplo de red neuronal artificial que realiza
lógica XNOR.
93
94
Líneas Futuras
Este capítulo abordará las diferentes continuaciones del proyecto logrando cumplir el objetivo
del mantenimiento del sistema y ofreciendo la posibilidad de alargar la vida útil del mismo.
Cada línea futura distinta se tratará en apartados distintos, aunque, no todas serán dependiente
unas de otras, y, se podrán realizar en paralelo o en proyectos distintos. También, destacar, que
el orden de los sub-capítulos marca la prioridad que se ha elegido para continuar el proyecto.
96
Glosario de Acrónimos
FPGA Field Programming Gate Array
IA Inteligencia Artificial
Big Data macrodatos, datos masivos, inteligencia de datos o datos a gran escala
97
IEEE Institute of Electrical and Electronic Engineers
98
Bibliografía
Adarraga, P., & Zaccagnini, J. L. (1994). PSICOLOGÍA E INTELIGENCIA ARTIFICIAL. Madrid:
TROTTA.
Aguilera López, R. (2002). Tratado elemental de ajedrez. Madrid: Aguilera (Centro de Ajedrez
Internacional).
Brian, W. K., & Dennis, N. R. (1978). The C programming language. Englewood Cliffs, New
Jersey: Prentice-Hall software series.
99
Deepmind. (13 de Marzo de 2019). [Link]/. Obtenido de [Link]/:
[Link]
and-go/
Funding Universe. (Marzo de 2019). Funding Universe Xilinx. Obtenido de Funding Universe
Xilinx: [Link]
Hubel, D. H., & Wiesel, T. (2005). Brain and visual perception: the story of a 25-year
collaboration. Oxford: Oxford University Press US.
100
IEEE. (1988). IEEE Digital Libary. Obtenido de IEEE Digital Libary:
[Link]
Jonathan, B., & Jonathan, M. B. (1 de Enero de 1988). Oxford Academic. Obtenido de Oxford
Academic: [Link]
Lise, G., & Ben, T. (2007). Introduction to Statistical Relational Learning. Maryland: MIT Press.
Martínez, E. F., Rico, A. F., Romero, G. R., & Castro, D. L. (Junio de 2018).
[Link] Obtenido de [Link]
[Link]
f?sequence=1&isAllowed=y
101
Microsoft. (Marzo de 2019). Microsoft, cognitive-toolkit. Obtenido de Microsoft, cognitive-
toolkit: [Link]
Skiena, S. S. (1998). The Algorithm Design Manual. New York: Springer Science & Business
Media.
Stroustrup, B. (1985).
102
Université de Montréal. (Marzo de 2019). Université de Montréal. Obtenido de Université de
Montréal: [Link]
Wikipedia. (Marzo de 2019). Wikipedia Logic Cell. Obtenido de Wikipedia Logic Cell:
[Link]
Wikipedia. (Abril de 2019). Wikipedia Switch Box. Obtenido de Wikipedia Switch Box:
[Link]
104
FPGAs impact the adaptability of neural networks positively as they allow for reprogramming to accommodate changes in design. However, they may compromise performance compared to dedicated hardware due to additional logic used for reconfigurability, thus influencing energy efficiency and speed .
BBVA's use of machine learning to personalize customer interactions and enhance efficiency could substantially improve customer satisfaction and operational cost-effectiveness, potentially leading to stronger competitiveness and market presence across the more than 30 countries in which it operates .
BBVA may encounter several challenges such as ensuring data quality and privacy across diverse regulatory environments, integrating machine learning models with existing systems, and aligning machine learning strategies with varied market needs and customer expectations in different countries .
Open-source frameworks like Theano and Torch offer significant benefits for deep learning model development by providing extensive collections of machine learning algorithms, supporting multiple languages, and enabling scalability across different hardware configurations, which fosters collaborative improvements and adaptation in the community .
BBVA aims to enhance customer service by using machine learning to simulate the actions an employee would take with a client, thereby providing tailored services efficiently through machines instead of human resources .
TensorFlow allows users, especially those new to programming, to easily implement neural networks by providing a high-level Python API that abstracts complex implementations, making the process simpler and more intuitive .
The 'Neuron Top' entity accumulates input values, applies biases, and computes outputs by integrating inputs with weights, completing the propagation of signals as part of the neural network's forward propagation. It ensures precise data handling and processing at each node level in the network .
FPGAs are advantageous over ASICs in that they are reprogrammable, allowing cost and design flexibility. However, FPGAs have higher energy consumption and lower performance compared to ASICs, due to the overhead of reconfigurability .
Languages like VHDL are crucial for designing hardware-specific models because they allow for precise control over the architecture and functioning of digital circuits, facilitating the implementation of neural networks on programmable logic devices like FPGAs, where detailed customization of hardware function and connectivity is required .
The 'Layer Generation' entity is responsible for creating layers in a neural network by initializing the weights and controlling the flow of data across neurons. It defines the number of bits for data buses and provides input and output ports to manage data flow, thereby supporting the propagation and processing of inputs through the network .