TICS-579-Deep Learning

Clase 1: Preliminares

Alfonso Tobar-Arancibia

Introducción al Curso

¿Por qué estudiar Deep Learning?

Principalmente porque es el Estado del Arte en las aplicaciones más Impresionantes en la Inteligencia Artificial.

Alexnet (2012)

AlphaGo (2016)

Transformers (2017)

GPT (2019)

¿Por qué estudiar Deep Learning?

Principalmente porque es el Estado del Arte en las aplicaciones más Impresionantes en la Inteligencia Artificial.

GPT-3 (2021)

AlphaFold (2021)

Stable Diffussion/Dalle (2022)

LLMs (2023) (ChatGPT/Llama)

¿Por qué estudiar Deep Learning?

Imágen tomada de la Clase de Zico Colter

Imágen tomada de la Clase de Zico Colter

¿Por qué estudiar Deep Learning?

Facilidad y Autograd

  • Frameworks como Tensorflow, Pytorch o Jax permiten realizar esto de manera mucho más sencilla.
    • Frameworks permiten calcular gradientes de manera automática.
    • Antigua mente trabajar en Torch, Caffe o Theano podía tomar cerca de 50K líneas de código.

Cómputo

Estado del Arte

  • Modelos de Deep Learning pueden generar sistemas que entiendan imágenes, textos, audios, videos, grafos, etc.

El nacimiento de las Redes Neuronales

Las redes neuronales artificiales (ANN), son modelos inspirados en el mecanismo cerebral de sinapsis. Su unidad más básica es una Neurona.

El nacimiento de las Redes Neuronales

Las redes neuronales artificiales (ANN), son modelos inspirados en el mecanismo cerebral de sinapsis. Su unidad más básica es una Neurona.

Este tipo de nomenclatura está sumamente pasada de moda.

  • Este cálculo se puede representar como:

\[ y = \phi(w_1 \cdot x_1 + w_2 \cdot x_2 + ... + w_5 \cdot x_5)\] \[ y = \phi(w^T \cdot x)\]

donde \(w = [w_1, w_2, w_3, w_4, w_5]\) y \(x = [x_1, x_2, x_3, x_4, x_5]\).

  • ¿Qué pasa si \(\phi(.)\) vale la función identidad?
  • Tenemos una Regresión Lineal.
  • ¿Qué pasa si \(\phi(.)\) vale la función sigmoide?
  • Tenemos una Regresión Logística.

Arquitectura de una Red

Estructura más común

(Probablemente tampoco seguiremos esta nomenclatura)
  • Nodos o Neuronas
  • Edges o Conexiones
  • Capas

¿Cuántas capas tiene esta red?

Depende

  • Normalmente todas las neuronas de una capa anterior se conectan con las de una capa posterior (Hay excepciones).
  • Dependiendo de la forma en la que se conecten, cada Arquitectura recibe un nombre.

Intuición y conceptos iniciales

Los Ingredientes de un Algoritmo de Aprendizaje

Hipótesis

Una función que describe como mapear inputs (features) con outputs (labels) por medio de parámetros.

Loss Function

Una función que especifica cuanta información se pierde. Mayor pérdida implica más error de estimación.

Método de Optimización

Es el responsable de combinar la hipótesis y la loss function. Corresponde a un procedimiento para determinar los parámetros de la hipótesis, minimizando la suma de las pérdidas en un set de entrenamiento.

Ejemplo: Softmax Regression

Softmax Regression

Corresponde la versión multiclase de una Regresión Logística. También se le llama una Shallow Network.

Consideremos un problema de clasificación multiclase de \(k\) clases tal que:

  • Datos de Entrenamiento: \(x^{(i)}, y^{(i)} \in {1,...,k}\) para \(i=1,...,m\).
    • \(n\): Es el número de Features.
    • \(m\): Es el número de puntos en el training set.
    • \(k\): Es el número de clases del problema.

Vamos a tener en total \(n \times k\) parámetros o pesos que actualizar.

Softmax Regression: Hipótesis

Vamos a definir una función que mapea valores de \(x \in \mathbb{R}\) a vectores de \(k\) dimensiones.

\[ h: \mathbb{R}^n \rightarrow \mathbb{R}^k\] \[ x \rightarrow h_\theta(x) = \theta^T x\]

donde \(\theta \in \mathbb{R}^{n \times k}\) y \(x \in \mathbb{R}^{n\times 1}\)

En este caso usamos una hipótesis lineal, ya que se usa una multiplicación matricial (o producto punto) para relacionar \(\theta\) y \(x\).

En este caso el output de \(h_i(x)\) devolverá la probabilidad de pertenecer a una cierta clase \(i\).

¿Cuál es el tamaño/dimensión de \(h_\theta(x)\)?

Notación Matricial

Una manera más conveniente de escribir estas operaciones es utilizar (Matrix Batch Form).

Design Matrix

\[X \in \mathbb{R}^{m \times n} = \begin{bmatrix} &-x^{(1)T}-\\ & \vdots & \\ &-x^{(m)T}- &\\ \end{bmatrix}\]

Labels Vector

\[y \in {1,...,k} = \begin{bmatrix} &-y^{(1)}-\\ & \vdots & \\ &-y^{(m)}- &\\ \end{bmatrix}\]

La hipótesis también se puede reescribir de manera matricial como:

\[h_\theta(X) = \begin{bmatrix} &-h_\theta(x^{(1)})^T-\\ & \vdots & \\ &-h_\theta(x^{(m)})^T-\\ \end{bmatrix}\]

\[h_\theta(X)= \begin{bmatrix} &-x^{(1)T} \theta-\\ & \vdots & \\ &-x^{(m)T} \theta-\\ \end{bmatrix} = X \theta\]

Normalmente este tipo de operaciones son las que utilizaremos para hacer nuestro código.

Loss Function: Softmax/Cross-Entropy Loss

La salida de nuestra Shallow Network retornará valores reales.

Para poder tener una mejor interpretación del significado de cada una aplicaremos la función Softmax lo cual permitirá normalizar los resultados y llevará los resultados a una “distribución de probabilidad” (valores positivos que sumen 1).

Formalmente definiremos la función Softmax como:

\[s_i = p(label = i) = \frac{exp(h_i(x))}{\sum_{j=1}^k exp(h_j(x))}\]

\[s = \begin{bmatrix} &s_1&\\ & \vdots & \\ &s_k&\\ \end{bmatrix}\]

Loss Function: Softmax/Cross-Entropy Loss

Para medir el error/pérdida de información utilizaremos el Negative Log Loss o Cross Entropy Loss.

\[l_{ce}(h(x), y) = -log\left(p(label = y)\right)\]

Para garantizar el éxito de nuestro modelo, básicamente queremos maximizar la probabilidad de encontrar la etiqueta correcta, es decir, que \(p(label = y)\) sea lo más alto posible.

Normalmente en los problemas de optimización no se suele maximizar sino minimizar. Minimizar el valor negativo es equivalente a maximizar. Esto sería equivalente a minimizar el error del modelo.

Finalmente por razones de estabilidad numérica, minimizamos el logaritmo de la probabilidad que es una técnica bien conocida en Estadística.

\[\begin{align} l_{ce}(h(x), y) = -log\left(p(label = y)\right) &= -log \left(\frac{exp(h_{(i = y)}(x))}{\sum_{j=1}^k exp(h_j(x))}\right) \\ &= - h_{(i=y)}(x) + log\left(\sum_{j = 1}^k exp(h_j(x))\right)\end{align}\]

Método de Optimización

El último ingrediente de un algoritmo de aprendizaje es el método de optimización. Es necesario minimizar la pérdida promedio asociada a todos los puntos de un cierto set de entrenamiento. Para ello definimos esto formalmente como:

\[\underset{\theta}{minimize} = \frac{1}{m} \sum_{i=1}^m l_{ce}(h_\theta(x^{(i)}), y^{(i)})\]

¿Cómo encontramos los parámetros \(\theta\) que minimizan la pérdida de información/error de estimación?

Gradient Descent

Es un método numérico que permite minimizar funciones moviéndose en dirección contraria al Gradiente. Es computacionalmente muy eficiente y fácil de implementar en código.

Gradient Descent

Se define el gradiente como la matriz que contiene las derivadas parciales de una función \(f\). Se denota como:

\[\nabla_\theta f(\theta) \in \mathbb{R}^{n \times k} = \begin{bmatrix} \frac{\partial f(\theta)}{\partial \theta_{11}} & \cdots & \frac{\partial f(\theta)}{\partial \theta_{1k}} \\ \cdots & \ddots & \cdots \\ \frac{\partial f(\theta)}{\partial \theta_{n1}} & \cdots & \frac{\partial f(\theta)}{\partial \theta_{nk}} \end{bmatrix}\]

\(\theta_{ij}\) corresponde al parámetro que une el nodo/feature \(i\) con el nodo/predicción \(j\).

El gradiente apunta a la dirección de máximo crecimiento de la función \(f\).

Gradient Descent: Regla de Actualización

Para minimizar la función, la idea es descender iterativamente por el trayecto en contra del gradiente. La regla de actualización se define como:

\[\theta := \theta - \alpha \nabla_\theta f(\theta) = \theta - \frac{\alpha}{m}\nabla_\theta l_{ce}(X\theta,y)\]

con \(\theta \in \mathbb{R}^{n \times k}\) y \(\alpha > 0\) corresponde al step size o learning rate.

En nuestro caso \(f\) corresponderá a nuestro \(l_{ce}\) calculado anteriormente. El problema es, ¿cuánto vale el gradiente del Cross Entropy Loss?

Calculando el Gradiente a mano

Simplifiquemos el problema a calcular para un sólo vector \(x\).

\[\theta := \theta - \alpha \nabla_\theta l_{ce}(\theta^Tx,y) \]

¿Cuánto vale el Gradiente?

  • No es tan sencillo, ya que derivamos respecto a \(\theta\) que es una matriz.
  • Pero derivamos a \(\theta^T x\) que es un vector.
  • Para ello, lo correcto es utilizar Calculo Diferencial Matricial, Jacobianos y Productos de Kroenecker (que probablemente no han visto en ningún curso).
    • SPOILER: Yo tampoco lo he visto en ningún curso.
  • Usaremos un truco (sumamente hacky 😱) que jamás deben revelar y que avergonzaría a cualquier profesor de Cálculo.
    • Pretenderemos que todos los valores son escalares y corregiremos las dimensiones al final.

Calculando el Gradiente a mano

Simplifiquemos el problema pensando que calcularemos el Gradiente para un sólo vector \(x\).

Es decir, \(x \in \mathbb{R}^{n\times1}\).

Además sabemos que \(\nabla_\theta l_{ce}(\theta^Tx, y)\) debe tener dimensiones \(n \times k\).

¿Por qué?

\[\nabla_\theta l_{ce}(\theta^T x,y) = \frac{\partial l_{ce}(\theta^T x,y)}{\partial \theta^T x} \cdot \frac{\partial \theta^Tx}{\partial \theta}\]

\[\frac{\partial l_{ce}(\theta^T x,y)}{\partial \theta^T x} = \frac{\partial l_{ce}(h_\theta(x), y)}{\partial h_\theta(x)} = \begin{bmatrix} \frac{\partial l_{ce}(h,y)}{\partial h_1} \\ \vdots\\ \frac{\partial l_{ce}(h,y)}{\partial h_k} \\ \end{bmatrix}\]

Luego el gradiente de \(l_{ce}\) respecto a \(h\) tiene dimensiones \(k \times 1\).

Calculando el Gradiente a mano

\[\begin{align} \frac{\partial l_{ce}(h,y)}{\partial h_i} &= \frac{\partial }{\partial h_i}\left(-h_{(i = y)} + log \sum_{j = 1}^k exp(h_j)\right) \\ &= -\frac{\partial h_{(i = y)}}{\partial h_i}+ \frac{1}{\sum_{j = 1}^k exp(h_j)} \cdot \frac{\partial}{\partial h_i}\left(\sum_{j=1}^k exp(h_j)\right) \\ &= -\frac{\partial h_{(i = y)}}{\partial h_i}+ \frac{exp(h_i)}{\sum_{j = 1}^k exp(h_j)} \\ &= - 1\{i=y\} + s_i = s_i - 1\{i=y\} \end{align} \]

\[1\{i = y\} = \begin{cases} 1, & \text{i = y} \\ 0, & \text{otherwise} \end{cases} \]

Finalmente en forma vectorial quedaría como:

\[\frac{\partial l_{ce}(\theta^T x,y)}{\partial \theta^T x} = s - e_y\]

Donde \(z\), es el vector de Softmax y \(e_y\) es un vector con un 1 en la posición \(y\) y 0 en el resto.

Calculando el Gradiente a mano

\[\nabla_\theta l_{ce}(\theta^T x,y) = \frac{\partial l_{ce}(\theta^T x,y)}{\partial \theta^T x} \cdot \frac{\partial \theta^Tx}{\partial \theta}\] \[\nabla_\theta l_{ce}(\theta^T x,y) = (s-e_y)\cdot x \]

Ojo con las dimensiones

  • \(s-e_y \in \mathbb{R}^{k \times 1}\)
  • \(x \in \mathbb{R}^{n \times 1}\)

Luego:

\[\nabla_\theta l_{ce}(\theta^T x,y) = x (s-e_y)^T\]

¿Cuál es el tamaño de \(\nabla_\theta l_{ce}(\theta^T x,y)\)?

\(n \times k\)

¿Por qué?

Calculando el Gradiente Matrix Batch Form

Esto sería equivalente a tomar en consideración todos los puntos del Training Set

\[\begin{align}\nabla_\theta l_{ce}(X\theta,y) &= \frac{\partial l_{ce}(X\theta,y)}{\partial X\theta} \cdot \frac{\partial X\theta}{\partial \theta}\\ &= (S - I_y) \cdot X \\ &= X^T \cdot (S - I_y) \end{align}\]

  • \(S\) corresponde al Softmax de \(X\theta\) aplicado por filas.
  • \(I_y\) corresponde al One Hot Encoder de las etiquetas. Filas con 1 en la etiqueta correcta y 0 en el resto.

Ojo con las dimensiones

  • \(S - I_y \in \mathbb{R}^{m \times k}\)
  • \(X \in \mathbb{R}^{m \times n}\)

¿Cuál es el tamaño de \(\nabla_\theta l_{ce}(X\theta,y)\)?

Finalmente la Regla de Actualización de parámetros usando Gradient Descent queda como:

\[\theta := \theta - \frac{\alpha}{m} X^T (S - I_y)\]

Conclusiones

  • Acabamos de entrenar una Shallow Network, sin definir ningún concepto Fancy que es propio del área.
  • No hemos hablado ni de:
    • Forward Pass
    • Epochs
    • Backpropagation
    • Adam
    • Activation Functions
    • etc.
  • Aplicando esta simple regla se puede obtener cerca de un 8% de error clasificando dígitos en MNIST.
  • Se puede programar en pocas líneas en Python.

Pero, ¿qué pasa con arquitecturas más complejas?

¡¡Eso es todo!!

Anexos

Multiplicación Matricial

  • Donde \(B_{*,i}\) corresponde a la columna \(i\) de B.
  • Donde \(A_{i,*}\) corresponde a la fila \(i\) de A.