Una red neuronal es un composición inteligente de módulos lineales y no lineales. Cuando los escogemos sabiamente, tenemos una herramienta muy poderosa para optimizar cualquier función matemática. Por ejemplo una que separe clases con un limite de decisión no lineal.

Un tópico que no es siempre explicado en detalle, a pesar de su naturaleza intuitiva y modular, es el algoritmo de retro-alimentación (backpropagation algorithm), responsable de actualizar parámetros "entrenables" en la red. Construyamos una red neuronal desde cero para ver el funcionamiento interno de una red neuronal usando piezas de LEGO como una analogía, un bloque a la vez.

Puedes ver el código implementando estos conceptos en el siguiente repositorio: https://github.com/omar-florez/scratch_mlp

Las Redes Neuronales como una Composición de Piezas

La figura de arriba muestra algo de la matemática usada para entrenar una red neuronal. Haremos sentido de esto durante el artículo. Una red neuronal es una pila de módulos con diferentes propósitos:

  • Entrada X alimenta la red neuronal con datos sin procesar, la cual se almacena en una matriz en la cual las observaciones con filas y las dimensiones son columnas.
  • Pesos W1 proyectan entrada X a la primera capa escondida h1. Pesos W1 trabajan entonces como un kernel lineal.
  • Una función Sigmoid que previene los números de la capa escondida de salir del rango 0-1. El resultado es un array activaciones neuronales h1 = Sigmoid(WX).

Hasta este punto estas operaciones solo calculan un sistema general lineal, el cual no tiene la capacidad de modelar interacciones no lineales. Esto cambia cuando ponemos otro elemento en el pila, añadiendo profundidad a la estructura modular. Mientras más profunda sea la red, más interacciones no-lineales podremos aprender y problemas mas complejos podremos resolver, lo cual puede explicar en parte la popularidad de redes neuronales.

¿Por qué debería leer esto?

Si uno entiende las partes internas de una red neuronal, es mas fácil saber qué cambiar primero cuando el algoritmo no funcione como es esperado, y permite definir una estrategia para probar invariantes y comportamientos esperados que uno saben son parte del algoritmo. Esto también es útil cuando quieres crear nuevos algoritmos que actualmente no están implementados en la librería de Machine Learning de preferencia.

¿Por qué hacer debugging de modelos de aprendizaje de máquina es una tarea compleja?

Por experiencia, los modelos matemáticos no funcionan como es esperado al primer intento. A veces estos pueden darte una exactitud baja para datos nuevos, tomar mucho tiempo de entrenamiento o mucha memoria RAM, devolver una gran cantidad de falsos negativos o valores NaN (Not a Number), etc. Déjame mostrarte algunos casos donde saber cómo funciona el algoritmo puede ser útil:

  • Si toma mucho tiempo para entrenar, es quizás una buena idea incrementar el tamaño del mini-batch o array de observaciones que alimentan a la red neuronal, para reducir la varianza en las observaciones y así ayudar al algoritmo a converger.

  • Si se observa valores NaN, el algoritmo ha recibido gradientes con valores muy altos produciendo desborde de memoria RAM. Piensa esto como una secuencia de multiplicaciones de matrices que explotan después de varias iteraciones. Reducir la velocidad de aprendizaje tendrá el efecto de escalar estos valores. Reduciendo el número de capas reducirá el número de multiplicaciones. Y poniendo una cota superior a los gradientes (clipping gradients) controlará este problema explícitamente.