Daré una versión corta y luego la ampliaré con una respuesta más larga y completa en la sección debajo de la versión corta.
Version corta:
- Teniendo antecedentes eléctricos, ¿dónde empiezo el aprendizaje automático?
- ¿Qué significa ser 'inteligente' después de que la IA se haya integrado en el cerebro humano?
- ¿Es un gran problema que AI haya escrito un guión de película?
- ¿Qué pasaría si un robot autoconsciente cometiera un asesinato o cualquier otro delito? ¿Se les aplican las leyes actuales?
- ¿Hemos entrado oficialmente en la era de los robots y la inteligencia artificial?
En un nivel alto, una red neuronal toma algunos puntos de datos, cada uno de los cuales tiene algún tipo de clasificación. Los puntos de datos pueden ser imágenes u oraciones, por ejemplo. Las clasificaciones pueden ser qué tipo de objeto muestra la imagen o el sentimiento de una oración.
Cada punto de datos tiene un conjunto de características (piense en el valor de píxeles en un punto o si existe una palabra en una oración) y lo que la red neuronal intenta hacer es encontrar un mapeo entre estas características a la clasificación adecuada.
Cómo aprende a hacer esto con precisión es a través de ver muchos ejemplos. A través de una gran cantidad de datos, prueba y error, la red neuronal está esencialmente calculando cuánto ponderar cada característica en su decisión final.
Por ejemplo, si estaba tratando de clasificar un sistema de reconocimiento de dígitos simple que solo toma imágenes de 0 y 1, la red neuronal aprenderá con el tiempo que la presencia de píxeles fuertes en la imagen central es una característica que probablemente sea más probable que se asigne a una clasificación de 1.
Una vez que ha visto muchos datos, puede usar los pesos que aprendió para hacer predicciones sobre datos que nunca antes había visto. En pocas palabras, cómo funcionan las arquitecturas de redes neuronales más simples.
Versión más larga (con las matemáticas):
Creo que la mejor manera de explicar los detalles de cómo se entrena una red neuronal es con un pequeño ejemplo.
Vayamos con el ejemplo mencionado anteriormente de clasificar 1’s y 0’s de las imágenes de escritura a mano. Ahora, en este ejemplo, nuestros “datos” son cada imagen, etiquetada como 1 o 0. Y recuerde que cada imagen tiene un conjunto de características, y en este ejemplo usaremos sus valores de píxeles como características. Es importante recordar que podemos elegir nuestras funciones para que sean lo que queramos y, en el mundo real, podríamos incluso querer “diseñar” nuevas funciones a partir de los datos que tenemos. Pero para este ejemplo, mantengamos las cosas simples.
Asumamos por simplicidad que las imágenes son 3 x 3 y los valores de píxeles son discretos, con un valor de 1 para blanco y 0 para negro. Una representación intuitiva del conjunto de características para una imagen es una matriz. Aquí hay un ejemplo de cómo podría verse una transformación de una imagen a un conjunto de características (tenga en cuenta que esto podría ser diferente para otra imagen dependiendo de cómo se coloque el 1 o el 0).
[matemática] A = \ begin {bmatrix} 0 & 1 & 0 \\ 0 & 1 & 0 \\ 0 & 1 & 0 \ end {bmatrix} [/ math]
[matemática] B = \ begin {bmatrix} 0 & 1 & 0 \\ 1 & 0 & 1 \\ 0 & 1 & 0 \ end {bmatrix} [/ math]
Entonces, en este ejemplo, tenemos 9 características que representan cada punto de datos. Ahora, en el mundo del aprendizaje automático, nos gusta que cada punto de datos se represente como un vector de características en lugar de una matriz de características (podríamos pasar nuestros datos como una matriz, pero luego entraríamos en el mundo de los tensores – vamos a Mantén las cosas simples). Entonces, un truco simple que se usa todo el tiempo es aplanar (formalmente conocido como vectorización) la matriz.
Así es como se ven nuestras matrices aplanadas:
[math] \ operatorname {vec} (A) = \ begin {bmatrix} 0 & 1 & 0 & 0 & 1 & 0 & 0 & 1 & 0 \ end {bmatrix} ^ \ top [/ math]
[math] \ operatorname {vec} (B) = \ begin {bmatrix} 0 & 1 & 0 & 1 & 0 & 1 & 0 & 1 & 0 \ end {bmatrix} ^ \ top [/ math]
Hacemos esta operación para cada imagen y al final apilamos nuestros vectores de fila en una matriz de datos de entrenamiento (llamemos a esta matriz [matemáticas] X [/ matemáticas]). Cada fila corresponde a una clasificación (0 o 1) y estas clasificaciones se pueden consolidar en un vector de columna que se pasa junto con los datos de entrenamiento (llamemos a este vector de columna de verdad fundamental [math] y [/ math]). Es por eso que este método de clasificación se llama aprendizaje supervisado: estamos pasando datos junto con etiquetas.
Ahora etiquetemos cada vector de fila de [math] X [/ math] como [math] x_i [/ math], que consiste en las características de cada imagen. Cada elemento de [math] x_i [/ math] corresponde a una neurona en la capa de entrada. Cada una de estas neuronas de la capa de entrada [matemáticas] i [/ matemáticas] está conectada a una neurona oculta [matemáticas] j [/ matemáticas] a través de algo llamado sinapsis, que simplemente tiene un peso [matemáticas] w_ {ij} [/ matemáticas] . Cada neurona en la capa oculta recibe una versión ponderada de cada neurona de la capa de entrada. La capa oculta suma cada una de las entradas ponderadas, esencialmente realizando la operación de un producto de puntos. Formalmente, después de la sumatoria, el resultado es un escalar en la neurona [matemática] j [/ matemática] es [matemática] u_j = \ [/ matemática] [matemática] x_i \ cdot w_j [/ matemática] donde [matemática] w_j [/ matemática ] es el vector de peso de todos los pesos entrantes a la neurona [math] j [/ math]. Podemos generalizar esta operación para todas las neuronas como una simple multiplicación de matriz [matemática] u = Wx_i [/ matemática] con [matemática] W [/ matemática] representando la matriz con todas [matemática] w_ {ij} [/ matemática] como entradas (en otras explicaciones también verá [math] u = Wx_i + b [/ math] donde [math] b [/ math] representa un vector de sesgo que simplemente permite un mejor entrenamiento de las redes en la práctica).
Ahora, después de haber obtenido las sumas ponderadas de las neuronas de entrada, hay un último paso que debemos realizar antes de pasar este vector a la siguiente capa oculta. Esto implica aplicar una función de activación a todos los elementos en el vector [math] u [/ math] que obtuvimos en la sección anterior. Una función de activación común que se usa es la función sigmoidea (también hay otras opciones):
[matemáticas] g (x) = \ frac {1} {1 + e ^ {- x}} [/ matemáticas]
El uso principal de las funciones de activación es que permiten que las redes neuronales modelen relaciones más complejas y no lineales a través de composiciones de tales funciones. En otras palabras, si las funciones de activación no estuvieran presentes, nuestra red neuronal consistiría simplemente en muchas operaciones lineales, que de hecho solo podrían modelar con precisión las relaciones lineales.
Pero una vez que tenemos nuestras funciones de activación para una capa oculta, simplemente aplicamos este elemento de función al vector [math] u [/ math] para obtener la salida de la primera capa oculta [math] h_1 = g (u) [/ matemáticas]. Luego pasamos esta salida a las capas ocultas posteriores y repetimos el mismo proceso.
Cuando finalmente llegamos a la capa de salida, aplicamos la activación una vez más para obtener una salida [matemática] a [/ matemática], que representa la estimación de las redes neuronales de la salida para cada muestra de entrenamiento.
Ahora, aquí es donde entra en juego la optimización. Ya sabemos cuál debería ser el resultado de nuestras muestras de entrenamiento: tenemos en el vector [math] y [/ math] que representa la verdad fundamental. Y en las iteraciones iniciales de entrenamiento de la red neuronal, los pesos se inicializan aleatoriamente y es muy poco probable que obtengamos la salida correcta en el primer intento a través de nuestro conjunto de entrenamiento. Existe alguna noción de error o pérdida y a lo largo del entrenamiento queremos minimizar ese error.
Esta noción de error se representa en las redes neuronales como una función de pérdida y una de las funciones de pérdida más intuitivas es la función de error cuadrático medio:
[matemáticas] MSE \ = \ frac {1} {N} \ sum_ {i = 1} ^ {N} (y_i – a_i) ^ 2 [/ matemáticas]
Esta función literalmente toma el promedio del error al cuadrado entre la estimación de la salida de la red neuronal y la salida correcta. También hay otras funciones de pérdida más sofisticadas, como la función de pérdida de entropía cruzada y la función de pérdida de divergencia KL que se inspiran en las ideas de la teoría de la información.
Ahora, como se mencionó anteriormente, nuestro objetivo aquí es pasar por la fase de entrenamiento y minimizar esta función de pérdida. Idealmente, nos gustaría “ajustar” nuestros pesos para que podamos minimizar esta función de pérdida. ¿Cómo hacemos para hacer eso?
Probablemente recuerde de su curso de cálculo cómo encontrar mínimos locales de una función arbitraria. En dimensiones superiores, esto se expande para encontrar derivadas parciales y específicamente gradientes. En los casos en que nuestras funciones pueden ser increíblemente complejas y no lineales, utilizamos un método fundamental llamado descenso de gradiente. Este método esencialmente encuentra el gradiente en puntos de datos particulares y ajusta los pesos para que la función se mueva en la dirección del descenso más pronunciado, minimizando así la pérdida. Hay una gran cantidad de teoría detrás de esto que te animo a que estudies al leer sobre el algoritmo.
Ahora, una última pieza del rompecabezas es cómo calcular gradientes en redes neuronales. Aquí es donde entra en juego el famoso algoritmo de retropropagación y, al final del día, se reduce a aplicar la regla de la cadena a derivadas parciales. Otras respuestas han hecho un buen trabajo al explicar esta idea, y si quieres ver mi explicación, mira mi respuesta a ¿Cómo entiendo la belleza del algoritmo de retropropagación?