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

    Introducción

    En este tutorial, vamos a hablar de 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 Machine Learning. Aprenderemos cómo implementarlo usando Python, así como 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 empecemos.

    Prerrequisitos

    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 Machine Learning. Aparte de eso, este artículo es para principiantes y cualquier persona puede seguirlo.

    Instalación

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

    Todos son bastante sencillos 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:

    $ pip install numpy pandas tensorflow keras scikit-learn
    

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

    ¿Qué es Grid Search?

    La búsqueda de 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 usted proporciona, automatizando así 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 Machine Learning para obtener los parámetros en los que el modelo ofrece la mejor precisión.

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

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

    Si para cada entrada de parámetro deseamos probar dos opciones (como se menciona entre corchetes arriba), totaliza hasta 23 = 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 nuestra parte cada vez que deseamos cambiar el valor de un parámetro, volver a ejecutar el código y realizar un seguimiento de los resultados de 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 para 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 Machine Learning y preprocesamiento de datos está fuera del alcance de este tutorial, por lo que simplemente ejecutaremos su código y hablaremos en profundidad sobre la parte donde entra Grid Search. ¡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. Uso de Pandas read_csv() método puede importar directamente el conjunto de datos desde un recurso en línea.

    El siguiente script importa las bibliotecas necesarias:

    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
    

    La siguiente secuencia de comandos importa el conjunto de datos y establece los encabezados de columna para el conjunto de datos.

    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:

    df.head()
    

    Salida:

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

    # 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:

    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 de aprendizaje profundo simple:

    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 Machine Learning. Dado que solo nos interesa ver la funcionalidad de Grid Search, no he realizado la división de tren / 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 optimizando nuestros parámetros.

    Entrenamiento del modelo sin búsqueda de cuadrícula

    En el código a continuación, crearemos un modelo usando valores de parámetros que decidimos al azar, o según nuestra intuición, y veremos cómo funciona nuestro modelo:

    # 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)
    

    Salida:

    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 no hay nada de qué preocuparse! Todavía tenemos Grid Search para intentar salvar el día. Vamos a por ello.

    Optimización de hiperparámetros usando Grid Search

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

    Primero modificamos nuestro create_model() función para aceptar parámetros de la función de llamada:

    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:

    # 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))
    

    Salida:

    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. Puede simplemente enumerar todos los parámetros que le gustaría ajustar, declarar los valores que se probarán, ejecutar su código y olvidarse de él. No se requiere más información de su lado. Una vez que se haya 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 efectividad, 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.

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *