Red neuronal de aprendizaje profundo Los modelos se ajustan a los datos de entrenamiento utilizando el algoritmo de optimización de descenso de gradiente estocástico.
Las actualizaciones de los pesos del modelo se hacen, usando la retropropagación del algoritmo de error. La combinación del algoritmo de optimización y actualización de pesos fue cuidadosamente elegida y es el enfoque más eficiente conocido para ajustar las redes neuronales.
No obstante, es posible utilizar algoritmos de optimización alternativos para ajustar un modelo de red neuronal a un conjunto de datos de entrenamiento. Este puede ser un ejercicio útil para aprender más sobre el funcionamiento de las redes neuronales y la naturaleza central de la optimización en el aprendizaje aplicado de las máquinas. También puede ser necesario para las redes neuronales con arquitecturas de modelos no convencionales y funciones de transferencia no diferenciables.
En este tutorial, descubrirá cómo optimizar manualmente los pesos de los modelos de redes neuronales.
Después de completar este tutorial, lo sabrás:
- Cómo desarrollar el pase de inferencia hacia adelante para modelos de redes neuronales desde cero.
- Cómo optimizar los pesos de un modelo de Perceptrón para la clasificación binaria.
- Cómo optimizar los pesos de un modelo de Perceptrón Multicapa usando escalada estocástica de colinas.
Empecemos.
Resumen del Tutorial
Este tutorial está dividido en tres partes; son:
- Optimizar las redes neuronales
- Optimizar un modelo de Perceptrón
- Optimizar un perceptor multicapa
Optimizar las redes neuronales
El aprendizaje profundo o las redes neuronales son un tipo flexible de aprendizaje por máquina.
Son modelos compuestos de nodos y capas inspirados en la estructura y función del cerebro. Un modelo de red neuronal funciona propagando un vector de entrada determinado a través de una o más capas para producir una salida numérica que puede ser interpretada para la clasificación o el modelado predictivo de regresión.
Los modelos se entrenan exponiendo repetidamente el modelo a ejemplos de entrada y salida y ajustando los pesos para minimizar el error de la salida del modelo en comparación con la salida esperada. Esto se llama el algoritmo de optimización de descenso de gradiente estocástico. Los pesos del modelo se ajustan usando una regla específica del cálculo que asigna el error proporcionalmente a cada peso de la red. Esto se llama el algoritmo de retropropagación.
El algoritmo de optimización de descenso de gradiente estocástico con actualizaciones de peso realizadas mediante retropropagación es la mejor manera de entrenar modelos de redes neuronales. Sin embargo, no es la única forma de entrenar una red neuronal.
Es posible utilizar cualquier algoritmo de optimización arbitrario para entrenar un modelo de red neuronal.
Es decir, podemos definir una arquitectura de modelo de red neuronal y utilizar un determinado algoritmo de optimización para encontrar un conjunto de pesos para el modelo que resulte en un mínimo de error de predicción o un máximo de precisión de clasificación.
Se espera que el uso de algoritmos de optimización alternativos sea menos eficiente en promedio que el uso de descenso de gradiente estocástico con retropropagación. No obstante, puede ser más eficiente en algunos casos concretos, como las arquitecturas de red no estándar o las funciones de transferencia no diferencial.
También puede ser un ejercicio interesante para demostrar la naturaleza central de la optimización en el entrenamiento de los algoritmos de aprendizaje de la máquina, y específicamente de las redes neuronales.
A continuación, exploremos cómo entrenar una simple red neural de un solo nodo llamada modelo Perceptrón usando escalada estocástica de colinas.
Optimizar un modelo de Perceptrón
El algoritmo de Perceptrón es el tipo más simple de red neural artificial.
Se trata de un modelo de una sola neurona que puede ser utilizado para problemas de clasificación de dos clases y proporciona la base para el desarrollo posterior de redes mucho más grandes.
En esta sección, optimizaremos los pesos de un modelo de red neural de Perceptrón.
Primero, definamos un problema de clasificación binaria sintética que podamos usar como el foco de la optimización del modelo.
Podemos usar la función make_classification() para definir un problema de clasificación binaria con 1.000 filas y cinco variables de entrada.
En el ejemplo que figura a continuación se crea el conjunto de datos y se resume la forma de los mismos.
# Definir un conjunto de datos de clasificación binaria de sklearn.conjuntos de datos importación hacer_clasificación # Definir el conjunto de datos X, y = make_classification(n_muestras=1000, n_funciones=5, n_informativo=2, n_redundante=1, estado_aleatorio=1) # resumir la forma del conjunto de datos imprimir(X.forma, y.forma) |
Ejecutando el ejemplo se imprime la forma del conjunto de datos creados, confirmando nuestras expectativas.
A continuación, necesitamos definir un modelo de Perceptrón.
El modelo de Perceptrón tiene un solo nodo que tiene un peso de entrada para cada columna del conjunto de datos.
Cada entrada se multiplica por su correspondiente peso para obtener una suma ponderada y luego se añade un peso de sesgo, como un coeficiente de intercepción en un modelo de regresión. Esta suma ponderada se llama activación. Finalmente, la activación se interpreta y se utiliza para predecir la etiqueta de clase, 1 para una activación positiva y 0 para una activación negativa.
Antes de optimizar los pesos del modelo, debemos desarrollar el modelo y nuestra confianza en cómo funciona.
Comencemos por definir una función para interpretar la activación del modelo.
Esto se llama la función de activación, o la función de transferencia; este último nombre es más tradicional y es mi preferencia.
El transferencia() La función de abajo toma la activación del modelo y devuelve una etiqueta de clase, clase=1 para una activación positiva o cero y clase=0 para una activación negativa. Esto se llama una función de transferencia de pasos.
# Función de transferencia def transferencia(activación): si activación >= 0.0: volver 1 volver 0 |
A continuación, podemos desarrollar una función que calcula la activación del modelo para una determinada fila de datos de entrada del conjunto de datos.
Esta función tomará la fila de datos y los pesos del modelo y calculará la suma ponderada de la entrada con la adición del peso del sesgo. El activar() La función de abajo implementa esto.
Nota: Estamos usando listas Python simples y un estilo de programación imperativo en lugar de arreglos NumPy o compresiones de listas intencionalmente para hacer el código más legible para los principiantes de Python. Siéntanse libres de optimizarlo y publicar su código en los comentarios de abajo.
# Función de activación def activar(fila, pesos): # Agrega el sesgo, el último peso activación = pesos[[–1] # Agregar la entrada ponderada para i en rango(len(fila)): activación += pesos[[i] * fila[[i] volver activación |
A continuación, podemos usar el activar() y transferencia() funciona conjuntamente para generar una predicción para una fila de datos dada. El predict_row() La función de abajo implementa esto.
# Usar pesos de modelo para predecir 0 o 1 para una fila de datos dada def predict_row(fila, pesos): # Activar para la entrada activación = activar(fila, pesos) # Transferencia para la activación volver transferencia(activación) |
A continuación, podemos llamar al predict_row() para cada fila en un conjunto de datos dado. El predict_dataset() La función de abajo implementa esto.
De nuevo, estamos usando intencionadamente un estilo de codificación simple e imperativo para la legibilidad en lugar de las compresiones de la lista.
# Usar pesos de modelo para generar predicciones para un conjunto de datos de filas def predict_dataset(X, pesos): yhats = lista() para fila en X: yhat = predict_row(fila, pesos) yhats.anexar(yhat) volver yhats |
Finalmente, podemos usar el modelo para hacer predicciones sobre nuestro conjunto de datos sintéticos para confirmar que todo funciona correctamente.
Podemos generar un conjunto aleatorio de pesos modelo usando la función rand().
Recordemos que necesitamos un peso para cada entrada (cinco entradas en este conjunto de datos) más un peso extra para el peso del sesgo.
... # Definir el conjunto de datos X, y = make_classification(n_muestras=1000, n_funciones=5, n_informativo=2, n_redundante=1, estado_aleatorio=1) # determinar el número de pesos n_peso = X.forma[[1] + 1 # Generar pesos aleatorios pesos = rand(n_peso) |
Podemos usar estos pesos con el conjunto de datos para hacer predicciones.
... # Generar predicciones para el conjunto de datos yhat = predict_dataset(X, pesos) |
Podemos evaluar la exactitud de la clasificación de estas predicciones.
... # calcular la precisión puntuación = accuracy_score(y, yhat) imprimir(puntuación) |
Eso es todo.
Podemos unir todo esto y demostrar nuestro sencillo modelo de Perceptrón para la clasificación. El ejemplo completo se enumera a continuación.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# Modelo simple de perceptrón para la clasificación binaria de numpy.al azar importación rand de sklearn.conjuntos de datos importación make_classification de sklearn.métrica importación exactitud_puntuación # Función de transferencia def transferencia(activación): si activación >= 0.0: volver 1 volver 0 # Función de activación def activar(fila, pesos): # Agrega el sesgo, el último peso activación = pesos[[–1] # Agregar la entrada ponderada para i en rango(len(fila)): activación += pesos[[i] * fila[[i] volver activación # Usar pesos de modelo para predecir 0 o 1 para una fila de datos dada def predict_row(fila, pesos): # Activar para la entrada activación = activar(fila, pesos) # Transferencia para la activación volver transferencia(activación) # Usar pesos de modelo para generar predicciones para un conjunto de datos de filas def predict_dataset(X, pesos): yhats = lista() para fila en X: yhat = predict_row(fila, pesos) yhats.anexar(yhat) volver yhats # Definir el conjunto de datos X, y = make_classification(n_muestras=1000, n_funciones=5, n_informativo=2, n_redundante=1, estado_aleatorio=1) # determinar el número de pesos n_peso = X.forma[[1] + 1 # Generar pesos aleatorios pesos = rand(n_peso) # Generar predicciones para el conjunto de datos yhat = predict_dataset(X, pesos) # calcular la precisión puntuación = accuracy_score(y, yhat) imprimir(puntuación) |
La ejecución del ejemplo genera una predicción para cada ejemplo en el conjunto de datos de entrenamiento y luego imprime la precisión de la clasificación para las predicciones.
Nota: Sus resultados pueden variar dada la naturaleza estocástica del algoritmo o el procedimiento de evaluación, o las diferencias en la precisión numérica. Considere ejecutar el ejemplo unas cuantas veces y compare el resultado promedio.
Se esperaría una precisión de alrededor del 50 por ciento dado un conjunto de pesos aleatorios y un conjunto de datos con un número igual de ejemplos en cada clase, y eso es aproximadamente lo que vemos en este caso.
Ahora podemos optimizar los pesos del conjunto de datos para lograr una buena precisión en este conjunto de datos.
Primero, tenemos que dividir el conjunto de datos en trenes y conjuntos de pruebas. Es importante retener algunos datos no utilizados en la optimización del modelo para que podamos preparar una estimación razonable del rendimiento del modelo cuando se utilice para hacer predicciones sobre nuevos datos.
Utilizaremos el 67 por ciento de los datos para el entrenamiento y el 33 por ciento restante como un conjunto de pruebas para evaluar el rendimiento del modelo.
... # Dividido en conjuntos de prueba de trenes X_tren, X_test, y_tren, y_test = prueba_de_trenes_split(X, y, tamaño_de_prueba=0.33) |
A continuación, podemos desarrollar un algoritmo de escalada de colinas estocástico.
El algoritmo de optimización requiere una función objetiva para optimizar. Debe tomar un conjunto de pesos y devolver una puntuación que debe ser minimizada o maximizada correspondiente a un modelo mejor.
En este caso, evaluaremos la exactitud del modelo con un conjunto determinado de pesos y devolveremos la exactitud de la clasificación, que debe ser maximizada.
El objetivo() La siguiente función implementa esto, dado el conjunto de datos y un conjunto de pesos, y devuelve la precisión del modelo
# Función objetiva def objetivo(X, y, pesos): # Generar predicciones para el conjunto de datos yhat = predict_dataset(X, pesos) # calcular la precisión puntuación = accuracy_score(y, yhat) volver puntuación |
A continuación, podemos definir el algoritmo de escalada de colinas estocástico.
El algoritmo requerirá una solución inicial (por ejemplo, pesos aleatorios) e irá haciendo iterativamente pequeños cambios en la solución y comprobando si da lugar a un modelo de mejor rendimiento. La cantidad de cambios realizados en la solución actual se controla mediante un tamaño_paso hiperparámetro. Este proceso continuará durante un número fijo de iteraciones, también proporcionadas como hiperparámetro.
El escalada de colinas() La función que figura a continuación implementa esto, tomando como argumentos el conjunto de datos, la función objetiva, la solución inicial y los hiperparámetros y devuelve el mejor conjunto de pesos encontrados y el rendimiento estimado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Algoritmo de búsqueda local de escalada de colinas def escalada(X, y, objetivo, solución, n_iter, tamaño_paso): # Evaluar el punto inicial solution_eval = objetivo(X, y, solución) # Corre la subida de la colina para i en rango(n_iter): # dar un paso candidato = solución + randn(len(solución)) * paso_tamaño # Evaluar el punto de candidato candidata_eval = objetivo(X, y, candidato) # comprobar si debemos mantener el nuevo punto si candidata_eval >= solution_eval: # Almacena el nuevo punto solución, solution_eval = candidato, candidato_eval # Reportar el progreso… imprimir(‘>%d %.5f’ % (i, solution_eval)) volver [[solución, solution_eval] |
Podemos entonces llamar a esta función, pasando un conjunto de pesos como solución inicial y el conjunto de datos de entrenamiento como el conjunto de datos para optimizar el modelo contra.
... # Definir las iteraciones totales n_iter = 1000 # Definir el tamaño máximo del paso tamaño_paso = 0.05 # determinar el número de pesos n_peso = X.forma[[1] + 1 # definir la solución inicial solución = rand(n_peso) # realizar la búsqueda de la escalada de la colina pesos, puntuación = escalada(X_tren, y_tren, objetivo, solución, n_iter, tamaño_paso) imprimir(«¡Hecho!) imprimir(«f(%s) = %f % (pesos, puntuación)) |
Finalmente, podemos evaluar el mejor modelo en el conjunto de datos de la prueba y reportar el rendimiento.
... # Generar predicciones para el conjunto de datos de la prueba yhat = predict_dataset(X_test, pesos) # calcular la precisión puntuación = accuracy_score(y_test, yhat) imprimir(«Precisión de la prueba: %.5f % (puntuación * 100)) |
Enlazando todo esto, el ejemplo completo de optimización de los pesos de un modelo de Perceptrón en el conjunto de datos de optimización binaria sintética se enumera a continuación.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# Subir una colina para optimizar los pesos de un modelo de perceptrón para la clasificación de numpy importación asarray de numpy.al azar importación randn de numpy.al azar importación rand de sklearn.conjuntos de datos importación make_classification de sklearn.model_selection importación prueba_de_trenes_split de sklearn.métrica importación exactitud_puntuación # Función de transferencia def transferencia(activación): si activación >= 0.0: volver 1 volver 0 # Función de activación def activar(fila, pesos): # Agrega el sesgo, el último peso activación = pesos[[–1] # Agregar la entrada ponderada para i en rango(len(fila)): activación += pesos[[i] * fila[[i] volver activación # Usar pesos de modelo para predecir 0 o 1 para una fila de datos dada def predict_row(fila, pesos): # Activar para la entrada activación = activar(fila, pesos) # Transferencia para la activación volver transferencia(activación) # Usar pesos de modelo para generar predicciones para un conjunto de datos de filas def predict_dataset(X, pesos): yhats = lista() para fila en X: yhat = predict_row(fila, pesos) yhats.anexar(yhat) volver yhats # Función objetiva def objetivo(X, y, pesos): # Generar predicciones para el conjunto de datos yhat = predict_dataset(X, pesos) # calcular la precisión puntuación = accuracy_score(y, yhat) volver puntuación # Algoritmo de búsqueda local de escalada de colinas def escalada(X, y, objetivo, solución, n_iter, tamaño_paso): # Evaluar el punto inicial solution_eval = objetivo(X, y, solución) # Corre la subida de la colina para i en rango(n_iter): # dar un paso candidato = solución + randn(len(solución)) * paso_tamaño # Evaluar el punto de candidato candidata_eval = objetivo(X, y, candidato) # comprobar si debemos mantener el nuevo punto si candidata_eval >= solution_eval: # Almacena el nuevo punto solución, solution_eval = candidato, candidato_eval # Reportar el progreso… imprimir(‘>%d %.5f’ % (i, solution_eval)) volver [[solución, solution_eval] # Definir el conjunto de datos X, y = make_classification(n_muestras=1000, n_funciones=5, n_informativo=2, n_redundante=1, estado_aleatorio=1) # Dividido en conjuntos de prueba de trenes X_tren, X_test, y_tren, y_test = prueba_de_trenes_split(X, y, tamaño_de_prueba=0.33) # Definir las iteraciones totales n_iter = 1000 # Definir el tamaño máximo del paso tamaño_paso = 0.05 # determinar el número de pesos n_peso = X.forma[[1] + 1 # definir la solución inicial solución = rand(n_peso) # realizar la búsqueda de la escalada de la colina pesos, puntuación = escalada(X_tren, y_tren, objetivo, solución, n_iter, tamaño_paso) imprimir(«¡Hecho!) imprimir(«f(%s) = %f % (pesos, puntuación)) # Generar predicciones para el conjunto de datos de la prueba yhat = predict_dataset(X_test, pesos) # calcular la precisión puntuación = accuracy_score(y_test, yhat) imprimir(«Precisión de la prueba: %.5f % (puntuación * 100)) |
Al ejecutar el ejemplo se informará del número de iteración y la precisión de la clasificación cada vez que se produzca una mejora en el modelo.
Al final de la búsqueda, se informa del rendimiento del mejor conjunto de pesos en el conjunto de datos de entrenamiento y se calcula e informa del rendimiento del mismo modelo en el conjunto de datos de prueba.
Nota: Sus resultados pueden variar dada la naturaleza estocástica del algoritmo o el procedimiento de evaluación, o las diferencias en la precisión numérica. Considere ejecutar el ejemplo unas cuantas veces y compare el resultado promedio.
En este caso, podemos ver que el algoritmo de optimización encontró un conjunto de pesos que alcanzaba una precisión de alrededor del 88,5 por ciento en el conjunto de datos de entrenamiento y de alrededor del 81,8 por ciento en el conjunto de datos de prueba.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
… >111 0.88060 >119 0.88060 >126 0.88209 >134 0.88209 >205 0.88209 >262 0.88209 >280 0.88209 >293 0.88209 >297 0.88209 >336 0.88209 >373 0.88209 >437 0.88358 >463 0.88507 >630 0.88507 >701 0.88507 ¡Hecho! f([ 0.0097317 0.13818088 1.17634326 -0.04296336 0.00485813 -0.14767616]) = 0.885075 Precisión de la prueba: 81.81818 |
Ahora que estamos familiarizados con la forma de optimizar manualmente los pesos de un modelo de Perceptrón, veamos cómo podemos ampliar el ejemplo para optimizar los pesos de un modelo de Perceptrón Multicapa (MLP).
Optimizar un perceptor multicapa
Un modelo de Perceptrón Multicapa (MLP) es una red neuronal con una o más capas, donde cada capa tiene uno o más nodos.
Es una extensión de un modelo de Perceptrón y es quizás el modelo de red neural (aprendizaje profundo) más utilizado.
En esta sección, nos basaremos en lo que aprendimos en la sección anterior para optimizar los pesos de los modelos MLP con un número arbitrario de capas y nodos por capa.
Primero, desarrollaremos el modelo y lo probaremos con pesos aleatorios, luego usaremos la escalada estocástica para optimizar los pesos del modelo.
Cuando se utilizan los MLP para la clasificación binaria, es común utilizar una función de transferencia sigmoidea (también llamada función logística) en lugar de la función de transferencia escalonada utilizada en el Perceptrón.
Esta función produce un valor real entre 0-1 que representa una distribución de probabilidad binomial, por ejemplo, la probabilidad de que un ejemplo pertenezca a la clase=1. El transferencia() La función de abajo implementa esto.
# Función de transferencia def transferencia(activación): # Función de transferencia del sigmoide volver 1.0 / (1.0 + exp(–activación)) |
Podemos usar el mismo activar() de la sección anterior. Aquí, la usaremos para calcular la activación de cada nodo en una capa dada.
El predict_row() debe ser reemplazada por una versión más elaborada.
La función toma una fila de datos y la red y devuelve la salida de la red.
Definiremos nuestra red como una lista de listas. Cada capa será una lista de nodos y cada nodo será una lista o matriz de pesos.
Para calcular la predicción de la red, simplemente enumeramos las capas, luego enumeramos los nodos, y luego calculamos la salida de activación y transferencia para cada nodo. En este caso, utilizaremos la misma función de transferencia para todos los nodos de la red, aunque no tiene por qué ser así.
En las redes con más de una capa, la salida de la capa anterior se utiliza como entrada a cada nodo de la capa siguiente. La salida de la última capa de la red es entonces devuelta.
El predict_row() La función de abajo implementa esto.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Función de activación de una red def predict_row(fila, red): aportaciones = fila # enumerar las capas de la red desde la entrada a la salida para capa en red: new_inputs = lista() # enumerar los nodos en la capa para nodo en capa: # Activar el nodo activación = activar(aportaciones, nodo) # Activación de la transferencia salida = transferencia(activación) # Salida de la tienda new_inputs.anexar(salida) # La salida de esta capa es la entrada a la siguiente capa aportaciones = new_inputs volver aportaciones[[0] |
Eso es todo.
Finalmente, necesitamos definir una red para usar.
Por ejemplo, podemos definir un MLP con una sola capa oculta con un solo nodo de la siguiente manera:
... # Crear una red de un solo nodo nodo = rand(n_inputs + 1) capa = [[nodo] red = [[capa] |
Esto es prácticamente un Perceptrón, aunque con una función de transferencia de sigmoides. Bastante aburrido.
Definamos un MLP con una capa oculta y una capa de salida. La primera capa oculta tendrá 10 nodos, y cada nodo tomará el patrón de entrada del conjunto de datos (por ejemplo, cinco entradas). La capa de salida tendrá un solo nodo que toma las entradas de las salidas de la primera capa oculta y luego da salida a una predicción.
... # una capa oculta y una capa de salida n_escondido = 10 escondido1 = [[rand(n_inputs + 1) para _ en rango(n_escondido)] salida1 = [[rand(n_escondido + 1)] red = [[escondido1, salida1] |
Podemos usar el modelo para hacer predicciones sobre el conjunto de datos.
... # Generar predicciones para el conjunto de datos yhat = predict_dataset(X, red) |
Antes de calcular la precisión de la clasificación, debemos redondear las predicciones a las etiquetas de clase 0 y 1.
... # alrededor de las predicciones yhat = [[ronda(y) para y en yhat] # calcular la precisión puntuación = accuracy_score(y, yhat) imprimir(puntuación) |
Enlazando todo esto, el ejemplo completo de evaluación de un MLP con pesos iniciales aleatorios en nuestro conjunto de datos de clasificación binaria sintética se enumera a continuación.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# desarrollar un modelo de clasificación mlp de matemáticas importación exp de numpy.al azar importación rand de sklearn.conjuntos de datos importación make_classification de sklearn.métrica importación exactitud_puntuación # Función de transferencia def transferencia(activación): # Función de transferencia del sigmoide volver 1.0 / (1.0 + exp(–activación)) # Función de activación def activar(fila, pesos): # Agrega el sesgo, el último peso activación = pesos[[–1] # Agregar la entrada ponderada para i en rango(len(fila)): activación += pesos[[i] * fila[[i] volver activación # Función de activación de una red def predict_row(fila, red): aportaciones = fila # enumerar las capas de la red desde la entrada a la salida para capa en red: new_inputs = lista() # enumerar los nodos en la capa para nodo en capa: # Activar el nodo activación = activar(aportaciones, nodo) # Activación de la transferencia salida = transferencia(activación) # Salida de la tienda new_inputs.anexar(salida) # La salida de esta capa es la entrada a la siguiente capa aportaciones = new_inputs volver aportaciones[[0] # Usar pesos de modelo para generar predicciones para un conjunto de datos de filas def predict_dataset(X, red): yhats = lista() para fila en X: yhat = predict_row(fila, red) yhats.anexar(yhat) volver yhats # Definir el conjunto de datos X, y = make_classification(n_muestras=1000, n_funciones=5, n_informativo=2, n_redundante=1, estado_aleatorio=1) # Determinar el número de entradas n_inputs = X.forma[[1] # una capa oculta y una capa de salida n_escondido = 10 escondido1 = [[rand(n_inputs + 1) para _ en rango(n_escondido)] salida1 = [[rand(n_escondido + 1)] red = [[escondido1, salida1] # Generar predicciones para el conjunto de datos yhat = predict_dataset(X, red) # alrededor de las predicciones yhat = [[ronda(y) para y en yhat] # calcular la precisión puntuación = accuracy_score(y, yhat) imprimir(puntuación) |
La ejecución del ejemplo genera una predicción para cada ejemplo en el conjunto de datos de entrenamiento, y luego imprime la precisión de la clasificación para las predicciones.
Nota: Sus resultados pueden variar dada la naturaleza estocástica del algoritmo o el procedimiento de evaluación, o las diferencias en la precisión numérica. Considere ejecutar el ejemplo unas cuantas veces y compare el resultado promedio.
Una vez más, esperaríamos una precisión de alrededor del 50 por ciento dado un conjunto de pesos aleatorios y un conjunto de datos con un número igual de ejemplos en cada clase, y eso es aproximadamente lo que vemos en este caso.
A continuación, podemos aplicar el algoritmo de escalada de colinas estocástica al conjunto de datos.
Es muy parecido a aplicar la escalada al modelo Perceptrón, excepto que en este caso, un escalón requiere una modificación de todos los pesos de la red.
Para ello, desarrollaremos una nueva función que crea una copia de la red y muta cada peso en la red mientras hace la copia.
El paso() La función de abajo implementa esto.
# dar un paso en el espacio de búsqueda def paso(red, tamaño_paso): new_net = lista() # enumerar las capas en la red para capa en red: new_layer = lista() # enumerar los nodos en esta capa para nodo en capa: # muta el nodo nuevo_nodo = nodo.copia() + randn(len(nodo)) * paso_tamaño # Almacenar el nodo en la capa new_layer.anexar(nuevo_nodo) # almacenar la capa en la red new_net.anexar(new_layer) volver new_net |
Modificar todo el peso de la red es agresivo.
Un paso menos agresivo en el espacio de búsqueda podría ser hacer un pequeño cambio en un subconjunto de los pesos del modelo, quizás controlado por un hiperparámetro. Esto se deja como una extensión.
Podemos entonces llamar a esto nuevo paso() de la función de escalada().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Algoritmo de búsqueda local de escalada de colinas def escalada(X, y, objetivo, solución, n_iter, tamaño_paso): # Evaluar el punto inicial solution_eval = objetivo(X, y, solución) # Corre la subida de la colina para i en rango(n_iter): # dar un paso candidato = paso(solución, tamaño_paso) # Evaluar el punto de candidato candidata_eval = objetivo(X, y, candidato) # comprobar si debemos mantener el nuevo punto si candidata_eval >= solution_eval: # Almacena el nuevo punto solución, solution_eval = candidato, candidato_eval # Reportar el progreso… imprimir(‘>%d %f’ % (i, solution_eval)) volver [[solución, solution_eval] |
A continuación se presenta el ejemplo completo de aplicación de la escalada estocástica de colinas para optimizar los pesos de un modelo MLP para la clasificación binaria.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# escalada estocástica de colinas para optimizar un perceptrón multicapa para la clasificación de matemáticas importación exp de numpy.al azar importación randn de numpy.al azar importación rand de sklearn.conjuntos de datos importación make_classification de sklearn.model_selection importación prueba_de_trenes_split de sklearn.métrica importación exactitud_puntuación # Función de transferencia def transferencia(activación): # Función de transferencia del sigmoide volver 1.0 / (1.0 + exp(–activación)) # Función de activación def activar(fila, pesos): # Agrega el sesgo, el último peso activación = pesos[[–1] # Agregar la entrada ponderada para i en rango(len(fila)): activación += pesos[[i] * fila[[i] volver activación # Función de activación de una red def predict_row(fila, red): aportaciones = fila # enumerar las capas de la red desde la entrada a la salida para capa en red: new_inputs = lista() # enumerar los nodos en la capa para nodo en capa: # Activar el nodo activación = activar(aportaciones, nodo) # Activación de la transferencia salida = transferencia(activación) # Salida de la tienda new_inputs.anexar(salida) # La salida de esta capa es la entrada a la siguiente capa aportaciones = new_inputs volver aportaciones[[0] # Usar pesos de modelo para generar predicciones para un conjunto de datos de filas def predict_dataset(X, red): yhats = lista() para fila en X: yhat = predict_row(fila, red) yhats.anexar(yhat) volver yhats # Función objetiva def objetivo(X, y, red): # Generar predicciones para el conjunto de datos yhat = predict_dataset(X, red) # alrededor de las predicciones yhat = [[ronda(y) para y en yhat] # calcular la precisión puntuación = accuracy_score(y, yhat) volver puntuación # dar un paso en el espacio de búsqueda def paso(red, tamaño_paso): new_net = lista() # enumerar las capas en la red para capa en red: new_layer = lista() # enumerar los nodos en esta capa para nodo en capa: # muta el nodo nuevo_nodo = nodo.copia() + randn(len(nodo)) * paso_tamaño # Almacenar el nodo en la capa new_layer.anexar(nuevo_nodo) # almacenar la capa en la red new_net.anexar(new_layer) volver nuevo_net # Algoritmo de búsqueda local de escalada de colinas def escalada(X, y, objetivo, solución, n_iter, tamaño_paso): # Evaluar el punto inicial solution_eval = objetivo(X, y, solución) # Corre la subida de la colina para i en rango(n_iter): # dar un paso candidato = paso(solución, tamaño_paso) # Evaluar el punto de candidato candidata_eval = objetivo(X, y, candidato) # comprobar si debemos mantener el nuevo punto si candidata_eval >= solution_eval: # Almacena el nuevo punto solución, solution_eval = candidato, candidato_eval # Reportar el progreso… imprimir(‘>%d %f’ % (i, solution_eval)) volver [[solución, solution_eval] # Definir el conjunto de datos X, y = make_classification(n_muestras=1000, n_funciones=5, n_informativo=2, n_redundante=1, estado_aleatorio=1) # Dividido en conjuntos de prueba de trenes X_tren, X_test, y_tren, y_test = prueba_de_trenes_split(X, y, tamaño_de_prueba=0.33) # Definir las iteraciones totales n_iter = 1000 # Definir el tamaño máximo del paso tamaño_paso = 0.1 # Determinar el número de entradas n_inputs = X.forma[[1] # una capa oculta y una capa de salida n_escondido = 10 escondido1 = [[rand(n_inputs + 1) para _ en rango(n_escondido)] salida1 = [[rand(n_escondido + 1)] red = [[escondido1, salida1] # realizar la búsqueda de la escalada de la colina red, puntuación = escalada(X_tren, y_tren, objetivo, red, n_iter, tamaño_paso) imprimir(«¡Hecho!) imprimir(«Mejor: %f % (puntuación)) # Generar predicciones para el conjunto de datos de la prueba yhat = predict_dataset(X_test, red) # alrededor de las predicciones yhat = [[ronda(y) para y en yhat] # calcular la precisión puntuación = accuracy_score(y_test, yhat) imprimir(«Precisión de la prueba: %.5f % (puntuación * 100)) |
Al ejecutar el ejemplo se informará del número de iteración y la precisión de la clasificación cada vez que se produzca una mejora en el modelo.
Al final de la búsqueda, se informa del rendimiento del mejor conjunto de pesos en el conjunto de datos de entrenamiento y se calcula e informa del rendimiento del mismo modelo en el conjunto de datos de prueba.
Nota: Sus resultados pueden variar dada la naturaleza estocástica del algoritmo o el procedimiento de evaluación, o las diferencias en la precisión numérica. Considere ejecutar el ejemplo unas cuantas veces y compare el resultado promedio.
En este caso, podemos ver que el algoritmo de optimización encontró un conjunto de pesos que alcanzaba una precisión de alrededor del 87,3 por ciento en el conjunto de datos de entrenamiento y de alrededor del 85,1 por ciento en el conjunto de datos de prueba.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
… >55 0.755224 >56 0.765672 >59 0.794030 >66 0.805970 >77 0.835821 >120 0.838806 >165 0.840299 >188 0.841791 >218 0.846269 >232 0.852239 >237 0.852239 >239 0.855224 >292 0.867164 >368 0.868657 >823 0.868657 >852 0.871642 >889 0.871642 >892 0.871642 >992 0.873134 ¡Hecho! Mejor: 0.873134 Precisión de la prueba: 85.15152 |
Más lecturas
Esta sección proporciona más recursos sobre el tema si desea profundizar en él.
Tutoriales
APIs
Resumen
En este tutorial, descubriste cómo optimizar manualmente los pesos de los modelos de redes neuronales.
Específicamente, aprendiste:
- Cómo desarrollar el pase de inferencia hacia adelante para modelos de redes neuronales desde cero.
- Cómo optimizar los pesos de un modelo de Perceptrón para la clasificación binaria.
- Cómo optimizar los pesos de un modelo de Perceptrón Multicapa usando escalada estocástica de colinas.
¿Tiene alguna pregunta?
Haga sus preguntas en los comentarios de abajo y haré lo posible por responder.