Algoritmo de optimización de búsqueda de cuadrícula en Python

El artículo explica cómo usar el algoritmo de optimización de búsqueda de cuadrícula en Python para ajustar hiperparámetros para algoritmos de aprendizaje profundo.

Introducción

En este tutorial, vamos a hablar sobre un algoritmo de optimización (o automatización) muy poderoso, es decir, el algoritmo de búsqueda de cuadrícula. Se usa más comúnmente para el ajuste de hiperparámetros en modelos de aprendizaje automático. Aprenderemos a implementarlo usando Python, así como a aplicarlo en una aplicación real para ver cómo puede ayudarnos a elegir los mejores parámetros para nuestro modelo y mejorar su precisión. Así que comencemos.

Requisitos previos

Para seguir este tutorial, debe tener un conocimiento básico de Python o algún otro lenguaje de programación. Es preferible, pero no esencial, que también tenga algunos conocimientos básicos de aprendizaje automático. Aparte de eso, este artículo es apto para principiantes y cualquiera puede seguirlo.

Instalación

Para seguir el tutorial, debe tener las siguientes bibliotecas/marcos instalados en su sistema:

  1. python 3
  2. NumPy
  3. pandas
  4. Difícil
  5. Scikit-Aprender

Todos son bastante simples de instalar: puede hacer clic en cada uno para ir a sus respectivos sitios web donde se proporcionan instrucciones detalladas de instalación. Generalmente, los paquetes se pueden instalar usando pip:

1
$ pip install numpy pandas tensorflow keras scikit-learn

Si tiene algún problema, consulte la documentación oficial de cada paquete.

¿Qué es la búsqueda en cuadrícula?

La búsqueda en cuadrícula es esencialmente un algoritmo de optimización que le permite seleccionar los mejores parámetros para su problema de optimización de una lista de opciones de parámetros que proporciona, por lo tanto, automatiza el método de 'prueba y error'. Aunque se puede aplicar a muchos problemas de optimización, es más conocido por su uso en el aprendizaje automático para obtener los parámetros en los que el modelo ofrece la mayor precisión.

Supongamos que su modelo toma los siguientes tres parámetros como entrada:

  1. Número de capas ocultas [2, 4]
  2. Número de neuronas en cada capa [5, 10]
  3. Número de épocas [10, 50]

Si para cada entrada de parámetro deseamos probar dos opciones (como se menciona entre corchetes arriba), el total es de hasta 2^3^=8 combinaciones diferentes (por ejemplo, una combinación posible es [2,5,10] ). Hacer esto manualmente sería un dolor de cabeza.

Ahora imagine si tuviéramos 10 parámetros de entrada diferentes y quisiéramos probar 5 valores posibles para cada parámetro. Requeriría una entrada manual de nuestro lado cada vez que deseemos cambiar el valor de un parámetro, volver a ejecutar el código y realizar un seguimiento de los resultados para todas las combinaciones de parámetros. Grid Search automatiza ese proceso, ya que simplemente toma los valores posibles para cada parámetro y ejecuta el código para probar todas las combinaciones posibles, genera el resultado de cada combinación y genera la combinación que brinda la mejor precisión. Útil, no?

Implementación de búsqueda en cuadrícula

Muy bien, suficiente charla. Apliquemos Grid Search en una aplicación real. Discutir la parte de aprendizaje automático y preprocesamiento de datos está fuera del alcance de este tutorial, por lo que simplemente estaríamos ejecutando su código y hablando en profundidad sobre la parte en la que entra la búsqueda de cuadrícula. ¡Comencemos!

Usaremos el conjunto de datos Pima Indian Diabetes que contiene información sobre si un paciente es diabético o no en función de diferentes atributos, como la concentración de glucosa en sangre, la presión arterial, etc. Con el método read_csv() de Pandas, puede importar directamente el conjunto de datos desde un recurso en línea.

El siguiente script importa las bibliotecas requeridas:

1
2
3
4
5
6
7
8
from sklearn.model_selection import GridSearchCV, KFold
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.wrappers.scikit_learn import KerasClassifier
from keras.optimizers import Adam
import sys
import pandas as pd
import numpy as np

El siguiente script importa el conjunto de datos y establece los encabezados de columna para el conjunto de datos.

1
2
3
4
5
6
columns = ['num_pregnant', 'glucose_concentration', 'blood_pressure', 'skin_thickness',
           'serum_insulin', 'BMI', 'pedigree_function', 'age', 'class']

data_path = "https://raw.githubusercontent.com/mkhalid1/Machine-Learning-Projects-Python-/master/Grid%20Search/pima-indians-diabetes.csv"

df = pd.read_csv(data_path, names=columns)

Echemos un vistazo a las primeras 5 filas del conjunto de datos:

1
df.head()

Producción:

diabetes dataset

Como puede ver, estas 5 filas son todas etiquetas para describir cada columna (en realidad hay 9 de ellas), por lo que no nos sirven. Comenzaremos eliminando estas filas que no son de datos y luego reemplazaremos todos los valores NaN con 0:

1
2
3
4
5
6
7
8
9
# Remove first 9 non-data rows
df = df.iloc[9:]

# Replace NaN (Not a Number) values with 0 in each column
for col in columns:
    df[col].replace(0, np.NaN, inplace=True)

df.dropna(inplace=True) # Drop all rows with missing values
dataset = df.values # Convert dataframe to numpy array

El siguiente script divide los datos en conjuntos de características y etiquetas y aplica la escala estándar en el conjunto de datos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
X = dataset[:,0:8]
Y = dataset[:, 8].astype(int)

# Normalize the data using sklearn StandardScaler
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler().fit(X)

# Transform and display the training data
X_standardized = scaler.transform(X)

data = pd.DataFrame(X_standardized)

El siguiente método crea nuestro modelo simple de aprendizaje profundo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def create_model(learn_rate, dropout_rate):
    # Create model
    model = Sequential()
    model.add(Dense(8, input_dim=8, kernel_initializer='normal', activation='relu'))
    model.add(Dropout(dropout_rate))
    model.add(Dense(4, input_dim=8, kernel_initializer='normal', activation='relu'))
    model.add(Dropout(dropout_rate))
    model.add(Dense(1, activation='sigmoid'))

    # Compile the model
    adam = Adam(lr=learn_rate)
    model.compile(loss='binary_crossentropy', optimizer=adam, metrics=['accuracy'])
    return model

Este es todo el código que necesitaría ejecutar para cargar el conjunto de datos, preprocesarlo y crear su modelo de aprendizaje automático. Dado que solo estamos interesados ​​en ver la funcionalidad de Grid Search, no he realizado la división de entrenamiento/prueba y estaríamos ajustando el modelo en todo el conjunto de datos.

En la siguiente sección, comenzaremos a ver cómo Grid Search nos facilita la vida al optimizar nuestros parámetros.

Entrenamiento del modelo sin búsqueda en cuadrícula {#entrenamientodelmodelosinbúsqueda en cuadrícula}

En el siguiente código, crearemos un modelo usando valores de parámetros que decidimos al azar, o basados ​​en nuestra intuición, y veremos cómo funciona nuestro modelo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Declare parameter values
dropout_rate = 0.1
epochs = 1
batch_size = 20
learn_rate = 0.001

# Create the model object by calling the create_model function we created above
model = create_model(learn_rate, dropout_rate)

# Fit the model onto the training data
model.fit(X_standardized, Y, batch_size=batch_size, epochs=epochs, verbose=1)

Producción:

1
2
Epoch 1/1
130/130 [==============================] - 0s 2ms/step - loss: 0.6934 - accuracy: 0.6000

La precisión que obtuvimos, como puede ver a continuación, es 60.00%. Esto es bastante bajo, ¡pero nada de qué preocuparse! Todavía tenemos Grid Search para tratar de salvar el día. Vamos a por ello.

Optimización de hiperparámetros mediante la búsqueda en cuadrícula

Si no usa Grid Search, puede llamar directamente al método fit() en el modelo que hemos creado anteriormente. Sin embargo, para usar Grid Search, necesitamos pasar algunos parámetros a nuestra función create_model(). Además, debemos declarar nuestra cuadrícula con diferentes opciones que nos gustaría probar para cada parámetro. Hagámoslo por partes.

Primero modificamos nuestra función create_model() para aceptar parámetros de la función que llama:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def create_model(learn_rate, dropout_rate):
    # Create model
    model = Sequential()
    model.add(Dense(8, input_dim=8, kernel_initializer='normal', activation='relu'))
    model.add(Dropout(dropout_rate))
    model.add(Dense(4, input_dim=8, kernel_initializer='normal', activation='relu'))
    model.add(Dropout(dropout_rate))
    model.add(Dense(1, activation='sigmoid'))

    # Compile the model
    adam = Adam(lr=learn_rate)
    model.compile(loss='binary_crossentropy', optimizer=adam, metrics=['accuracy'])
    return model

# Create the model
model = KerasClassifier(build_fn=create_model, verbose=1)

Ahora, estamos listos para implementar nuestro algoritmo Grid Search y ajustar el conjunto de datos en él:

 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
# Define the parameters that you wish to use in your Grid Search along
# with the list of values that you wish to try out
learn_rate = [0.001, 0.02, 0.2]
dropout_rate = [0.0, 0.2, 0.4]
batch_size = [10, 20, 30]
epochs = [1, 5, 10]

seed = 42

# Make a dictionary of the grid search parameters
param_grid = dict(learn_rate=learn_rate, dropout_rate=dropout_rate, batch_size=batch_size, epochs=epochs )

# Build and fit the GridSearchCV
grid = GridSearchCV(estimator=model, param_grid=param_grid,
                    cv=KFold(random_state=seed), verbose=10)

grid_results = grid.fit(X_standardized, Y)

# Summarize the results in a readable format
print("Best: {0}, using {1}".format(grid_results.best_score_, grid_results.best_params_))

means = grid_results.cv_results_['mean_test_score']
stds = grid_results.cv_results_['std_test_score']
params = grid_results.cv_results_['params']

for mean, stdev, param in zip(means, stds, params):
    print('{0} ({1}) with: {2}'.format(mean, stdev, param))

Producción:

1
Best: 0.7959183612648322, using {'batch_size': 10, 'dropout_rate': 0.2, 'epochs': 10, 'learn_rate': 0.02}

En la salida, podemos ver que nos da la combinación de parámetros que produce la mejor precisión.

Es seguro decir que Grid Search fue bastante fácil de implementar en Python y nos ahorró mucho tiempo, en términos de trabajo humano. Simplemente puede enumerar todos los parámetros que le gustaría ajustar, declarar los valores a probar, ejecutar su código y olvidarse de eso. No se requieren más aportes de su parte. Una vez que se ha encontrado la mejor combinación de parámetros, simplemente puede usarla para su modelo final.

Conclusión

En resumen, aprendimos qué es Grid Search, cómo puede ayudarnos a optimizar nuestro modelo y los beneficios que conlleva, como la automatización. Además, aprendimos cómo implementarlo en unas pocas líneas de código usando Python Language. Para ver su eficacia, también entrenamos un modelo de Machine Learning con y sin realizar Grid Search, y la precisión fue un 19 % mayor con Grid Search.