Redes Neuronales y Aprendizaje Profundo

¿Qué harás?

En esta curso se verá más que una introducción a las redes neuronales, un repaso de ellas y algunos algoritmos muy importantes. Además, verás cómo optimizar ciertos algoritmos y la intuición de estos.

Tendrás que implementar regresión logística tanto vectorizada como no vectorizada. Además, tendrás que implementar una red neuronal con una capa oculta desde cero usando todo lo que se vió anteriormente. Posteriormente, tendrás que generalizar lo anterior para cualquier número de capas ocultas (igual todo desde cero). Finalmente, usarás la red que hiciste para identificar imagenes y decidir si hay un gato o no.

Implementarás y ganarás intuición de los algoritmos de optimización, propagación hacia adelante y hacia atrás, entre otros. Si deseas optimizar tu red verás algo sobre parámetros e hiperparámetros, pero eso ya lo verás a mayor profundidad en el siguiente curso.

Regresión logística

Este es un algoritmo para clasificación binaria, así que primero verás qué es la clasificación binaria.

Clasificación Binaria

La meta de este modelo es clasificar los elementos de un conjunto dado en dos grupos bajo una regla de clasificación que se va entrenando. Los ejemplos más típicos son, por ejemplo, determinar si un paciente tiene una enfermedad o no; saber si en la imagen hay un gato o no; detectar si un email es spam o no; entre otros. Como el nombre lo indica, nuestro output será un número binario: $0$ o $1$.

Notación

Las siguientes notaciones son las que estarás usando a lo largo del curso.

  • $n_x$ será el tamaño de nuestro input. Por ejemplo, si usamos imágenes de $64x64$ pixeles como input, $n_x=64\cdot64$.
  • $n_y$ será el tamaño de nuestro output.
  • Un ejemplo de entrenamiento está representado por la pareja ordenada $(x,y)$, donde $x\in\Bbb R^{n_x}$ y $y\in{0,1}$.
  • Si queremos saber el $i-$ ésimo elemento, lo denotaremos por $$(x^{(i)}, y^{(i)}).$$
  • Representamos al conjunto de $m$ entrenamientos como $$\left{(x^{(1)}, y^{(1)}),\ldots, (x^{(m)}, y^{(m)})\right},$$ donde $x\in\Bbb R^n$ y $y\in{0,1}$.
  • Por temas de eficiencia computacional (NumPy es muy eficiente trabajando con matrices), definiremos las siguientes matrices: $$X=\begin{pmatrix}\vdots& \vdots& & \vdots\ x^{(1)} & x^{(2)}&\ldots& x^{(m)}\\vdots& \vdots& & \vdots \end{pmatrix},\ \ \ \ Y=\begin{pmatrix}y^{(1)} & y^{(2)}&\ldots& y^{(m)}\\end{pmatrix},$$ de donde $X\in\Bbb R^{{n_x}\times m}, Y\in \Bbb R^{1\times m}$.

Regresión Logística

Este algoritmo es usado para predecir variables categóricas. Así, dado $x$, queremos saber la probalidad de que $y$ sea 1, es decir,$$\hat{y}=P(y=1\mid x).$$ En el otuput se usa la función $sigmoid:$ $$\sigma(z)=\frac{1}{1+e^{-z}},$$ por ende, $$\hat{y}=\sigma(w^Tx+b),$$ donde $w\in\Bbb R^{n_x},b\in\Bbb R$ son los pesos en la red y los sesgos respectivamente.

Función de coste

Vimos que nuestro output es $$\hat{y}=\sigma(w^Tx+b),$$ donde $\sigma(z^{(i)})=\frac{1}{1+e^{-z^{(i)}}}$. Así, dado un conjunto de $m$ entrenamientos, $${(x^{(1)}, y^{(1)}),\ldots, (x^{(m)}, y^{(m)})},$$ queremos aproximar lo más posible $\hat{y}^{(i)}$ con $y^{(i)}$ para toda $i\in{1,\ldots,m}$.

Ahora, en el curso verás que la función de error es $$\mathcal{L}(\hat{y},y) = - (y\log(\hat{y}) + (1-y)\log(1-\hat{y})).$$ y verás por qué estamos usando esta función y no otra, como por ejemplo MSE; spoiler: no es convexa. Por tanto, la función de costo es $$J(w,b)=\frac{1}{m}\sum_{i=1}^m \mathcal{L}(\hat{y}^{(i)},y^{(i)}),$$ que es, la función de entropía cruzada binaria (en inglés, binary cross-entropy loss function). Para optimizarla podemos usar, por ejemplo, descenso de gradiente. Más adelante en la especialiación se verán otros métodos que nos pueden ayudar con la eficiencia.

Vectorización

Sabemos que, para implementar los algoritmos anteriormente vistos, si no consideramos que son vectores, estaremos usando demasiados ciclos (lo que implica un gran coste computacional). Lo bueno es que se puede usar conceptos sencillos de Álgebra Lineal para mejorar esto. Además, en python tenemos una gran ayuda de numpy.

En efecto, para obtener $z=w^Tx+b$ de manera sencilla, hay que usar el hecho de que $x$, $w$ y $b$ son vectores para poder hacer uso las operaciones con matrices. Esto es, en código de python,

z=np.dot(w,x)+b

Y es muy eficiente y además minimizamos los errores que podemos hacer en código. Ahora, habrá que ver cómo usar esto para usarlo para todo el conjunto de entrenamiento. La respuesta vuelve a ser la misma: matrices.

Recordemos que $$z^{(1)}=w^Tx^{(1)}+b,\ z^{(2)}=w^Tx^{(2)}+b,\ \ldots,\ z^{(m)}=w^Tx^{(m)}+b,$$ de donde $$a^{(1)}=\sigma(z^{(1)}),\ a^{(2)}=\sigma(z^{(2)}),\ldots,\ a^{(m)}=\sigma(z^{(m)})$$ y $$X=\begin{pmatrix}\vdots& \vdots& & \vdots\ x^{(1)} & x^{(2)}&\ldots& x^{(m)}\\vdots& \vdots& & \vdots \end{pmatrix},$$ por tanto, podemos hacer $$Z = \begin{pmatrix}z^{(1)} & z^{(2)}&\ldots& z^{(m)} \end{pmatrix}\text{ y } B=\begin{pmatrix}b &b&\ldots& b\end{pmatrix},$$ con $B$ una matriz de $1\times m$. Por tanto, hacemos, en python,

 z = np.dot(w,x)+b

y hemos obtenido $\sigma(z)!$

Redes Neuronales Profundas

Definimos a una red neuronal profunda cuando es una red neuronal con 3 o más capas.

Nos interesa usar esta arquitectura para hacer relaciones con los datos desde lo más sencillo hasta lo más complejo. Por ejemplo, en una aplicación para reconocer rostros podemos pensar que las capas hacen lo siguiente: Input del audio -> Reconocimiento de bajos o altos -> Reconocimiento de fonemas -> Reconocimiento de palabras -> Reconocimiento de oraciones, etc.

Además, hay ciertas funciones que se pueden hacer usando un bajo número de capas de neuronas, pero el costo es grande: requerimos una cantidad exponencial de neuronas para esto. Un ejemplo que se verá de esto es si queremos obtener $$y=x_1\ XOR\ x_2\ XOR\ldots XOR\ x_n$$

Propagación hacia atrás

Conocido como backpropagation. Este algoritmo sirve para entrenar redes neuronales. De hecho, este algoritmo es lo que hace que la red aprenda. El corazón de este algoritmo radica en la regla de la cadena. No te preocupes, se te presentará primero la idea de cómo hacer derivadas en una gráfica y de ahí lo extrapolarás hacía una red. Si tienes un buen fundamento del Cálculo, este algoritmo te resultará sencillo.

Propagación hacia adelante

En esta parte verás cómo cada capa procesa su información y la pasa a la siguiente capa. Nada nuevo si ya alguna vez implementaste una red neuronal. ![](https://miro.medium.com/max/828/1*nX6L9rclTnx0Hph5i01wzg.jpeg =400x200)

Funciones de activación

Este es un hiperparámetro que se tiene que decidir. Verás las siguientes 4 junto con algunas de sus ventajas y desventajas: $sigmoid,\tanh, ReLU, Leaky,ReLU$.

Sirve para clasificación binaria. Solo sirve para la capa de salida. La desventaja es que tiene un gradiente de descenso lento cuando estamos lejos tanto por la derecha o por la izquierda; por ende, debemos de hacer que nuestro gradiente de descenso empiece por valores cerca del intervalo $(-4,4)$. Esta función está dada por $$\sigma(z)=\frac{1}{1+e^{-z}},$$ de donde $\sigma(z)\approx 1$ si $z$ es muy grande y $\sigma(z)\approx 0$ si $z$ es muy pequeña.

  • $\tanh:$

![Función sigmoide](https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Hyperbolic_Tangent.svg/1200px-Hyperbolic_Tangent.svg.png =500x300)

El descenso del gradiente es mucho más rápido.

  • $ReLU:$

![Función sigmoide](https://media.springernature.com/lw685/springer-static/image/chp%3A10.1007%2F978-981-16-2248-9_5/MediaObjects/505610_1_En_5_Fig2_HTML.png =400x300)

Esta es la función por defecto para la activación de neuronas. Notemos que su pendiente es 0 o 1. La ventaja es que es muy fácil de implementar: basta con usar la función max(), como se puede observar. Además, una red neuronal es mucho más fácil de optimizar cuando tenemos funciones lineales; esta función se comporta como una función lineal.

Uno de los problemas es que no no existe su derivada en el punto 0. Para solucionar esto, se introdujo $Leaky,ReLU$.

  • $Leaky,ReLU$

![Función sigmoide](https://www.i2tutorials.com/wp-content/media/2019/09/Deep-learning-25-i2tutorials.png =400x300)

Como bien se dijo anteriormente, esto nos ayudará para tener una derivada en el 0. Claramente la desventaja radica en que es mucho más sencillo de usar $ReLU$, pues no se necesita de estar modificando un hiperparámetro (en caso de la imágen, el hiperparámetro es 0.1). Por lo mismo y por otras razones, esta función casi no es usada.

Parámetros e hiperparámetros

En esta parte verás lo que tendrás que ir modificando en tu red neuronal dependiendo del tipo de problema a atacar.

  • Los principales parámetros de una red neuronal son sus pesos y sesgos: $W$ y $b$.
  • Los hiperparámetros, que son parámetros para controlar los algoritmos, son, por decir algunos, - Taza de aprendizaje. - Número de iteraciones. - Número de capas ocultas. - Número de neuronas. - La decisión de funciones de activación.

Al finalizar este curso te darás cuenta lo importante que es encontrar valores para cada uno de estos parámetros e hiperparámetros. Si sigues con la especialización, esto lo verás en el siguiente curso.