Pasos para entrenar una red neuronal profunda

Avatar Tutor | abril 25, 2019

En esta implementación de Deep Learning, nuestro objetivo es predecir el desgaste de los clientes o la rotación de un determinado banco, y es probable que los clientes abandonen este servicio bancario. El conjunto de datos utilizado es relativamente pequeño y contiene 10000 filas con 14 columnas. Puedes descargarlo aquí.

Estamos utilizando la distribución de Anaconda y marcos como Theano, TensorFlow y Keras. Keras está construido sobre Tensorflow y Theano que funcionan como backends.

# Artificial Neural Network
# Installing Theano
pip install --upgrade theano

# Installing Tensorflow
pip install –upgrade tensorflow

# Installing Keras
pip install --upgrade keras

Paso 1

Preprocesamiento de datos

In[]:

# Importing the libraries
   import numpy as np
   import matplotlib.pyplot as plt
   import pandas as pd
 
# Importing the database
   dataset = pd.read_csv('Churn_Modelling.txt')

Paso 2

Creamos matrices de las características del conjunto de datos y la variable de destino, que es la columna 14, etiquetada como “Salido”.

El aspecto inicial de los datos se muestra a continuación:

In[]:
X = dataset.iloc[:, 3:13].values
Y = dataset.iloc[:, 13].values

Paso 3

Hacemos el análisis más simple codificando variables de cadena. Estamos utilizando la función ScikitLearn ‘LabelEncoder’ para codificar automáticamente las diferentes etiquetas en las columnas con valores entre 0 y n_classes-1.

from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder_X_1 = LabelEncoder() 
X[:,1] = labelencoder_X_1.fit_transform(X[:,1]) 
labelencoder_X_2 = LabelEncoder() 
X[:, 2] = labelencoder_X_2.fit_transform(X[:, 2])

Paso 4

Etiquetado de datos codificados

Usamos la misma biblioteca ScikitLearn y otra función llamada OneHotEncoder para simplemente pasar el número de columna creando una variable ficticia.

onehotencoder = OneHotEncoder(categorical features = [1])
X = onehotencoder.fit_transform(X).toarray()
X = X[:, 1:]

Ahora, las dos primeras columnas representan el país y la cuarta columna representa el género.

Siempre dividimos nuestros datos en parte de entrenamiento y pruebas; capacitamos a nuestro modelo en los datos de entrenamiento y luego verificamos la precisión de un modelo en los datos de prueba que ayudan a evaluar la eficiencia del modelo.

Paso 5

Estamos utilizando la función train_test_split de ScikitLearn para dividir nuestros datos en el conjunto de entrenamiento y el conjunto de prueba. Mantenemos la relación de división de tren a prueba en 80:20.

#Splitting the dataset into the Training set and the Test Set
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)

Algunas variables tienen valores en miles, mientras que otras tienen valores en decenas o en unidades. Escalamos los datos para que sean más representativos.

Paso 6

En este código, estamos ajustando y transformando los datos de entrenamiento utilizando la función StandardScaler. Normalizamos nuestra escala de modo que utilicemos el mismo método ajustado para transformar / escalar datos de prueba.

# Feature Scaling
fromsklearn.preprocessing import StandardScaler 
sc = StandardScaler() 
X_train = sc.fit_transform(X_train) 
X_test = sc.transform(X_test)

Los datos ahora se escalan correctamente. Finalmente, hemos terminado con nuestro preprocesamiento de datos. Ahora, vamos a empezar con nuestro modelo.

Paso 7

Importamos los módulos requeridos aquí. Necesitamos el módulo secuencial para inicializar la red neuronal y el módulo denso para agregar las capas ocultas.

# Importing the Keras libraries and packages 
import keras 
from keras.models import Sequential 
from keras.layers import Dense

Paso 8

Nombraremos el modelo como Clasificador, ya que nuestro objetivo es clasificar la rotación de clientes. Luego usamos el módulo secuencial para la inicialización.

#Initializing Neural Network 
classifier = Sequential()

Paso 9

Añadimos las capas ocultas una a una usando la función densa. En el código de abajo, veremos muchos argumentos.

Nuestro primer parámetro es output_dim. Es el número de nodos que agregamos a esta capa. init es la inicialización del gradiente estocástico. En una red neuronal asignamos ponderaciones a cada nodo. En la inicialización, los pesos deben estar cerca de cero e inicializamos los pesos aleatoriamente usando la función uniforme. El parámetro input_dim es necesario solo para la primera capa, ya que el modelo no conoce el número de nuestras variables de entrada.

Aquí, el número total de variables de entrada es 11. En la segunda capa, el modelo conoce automáticamente el número de variables de entrada de la primera capa oculta.

Ejecute la siguiente línea de código para agregar la capa de entrada y la primera capa oculta:

classifier.add(Dense(units = 6, kernel_initializer = 'uniform', 
activation = 'relu', input_dim = 11))

Ejecute la siguiente línea de código para agregar la segunda capa oculta:

classifier.add(Dense(units = 6, kernel_initializer = 'uniform', 
activation = 'relu'))

Ejecute la siguiente línea de código para agregar la capa de salida:

classifier.add(Dense(units = 1, kernel_initializer = 'uniform', 
activation = 'sigmoid'))

Paso 10

Compilando la ANN

Hemos añadido varias capas a nuestro clasificador hasta ahora. Ahora los compilaremos usando el método de compilación. Los argumentos agregados en el control de compilación final completan la red neuronal. Por lo tanto, debemos tener cuidado en este paso.

Aquí hay una breve explicación de los argumentos.

El primer argumento es Optimizer. Este es un algoritmo utilizado para encontrar el conjunto óptimo de ponderaciones. Este algoritmo se llama el Descenso Estocástico de Gradiente (SGD). Aquí estamos usando uno entre varios tipos, llamado “optimizador de Adam”. El SGD depende de la pérdida, por lo que nuestro segundo parámetro es la pérdida. Si nuestra variable dependiente es binaria, usamos la función de pérdida logarítmica llamada “binary_crossentropy”, y si nuestra variable dependiente tiene más de dos categorías en la salida, entonces usamos “categorical_crossentropy”. Queremos mejorar el rendimiento de nuestra red neuronal en función de la precisión, por lo que agregamos métricas como precisión.

# Compiling Neural Network 
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])

Paso 11

Se deben ejecutar varios códigos en este paso.

Ajuste de la ANN al conjunto de entrenamiento
Ahora entrenamos nuestro modelo en los datos de entrenamiento. Utilizamos el método de ajuste para ajustar nuestro modelo. También optimizamos los pesos para mejorar la eficiencia del modelo. Para ello, tenemos que actualizar los pesos. El tamaño del lote es el número de observaciones después de lo cual actualizamos los pesos. Época es el número total de iteraciones. Los valores de tamaño de lote y época se eligen mediante el método de prueba y error.

classifier.fit(X_train, y_train, batch_size = 10, epochs = 50)

Haciendo predicciones y evaluando el modelo.

# Predicting the Test set results
y_pred = classifier.predict(X_test)
y_pred = (y_pred > 0.5)

Predecir una sola observación nueva

# Predicting a single new observation
"""Our goal is to predict if the customer with the following data will leave the bank:
Geography: Spain
Credit Score: 500
Gender: Female
Age: 40
Tenure: 3
Balance: 50000
Number of Products: 2
Has Credit Card: Yes
Is Active Member: Yes

Paso 12

Predecir el resultado del conjunto de pruebas

El resultado de la predicción le dará la probabilidad de que el cliente abandone la empresa. Convertiremos esa probabilidad en binario 0 y 1.

# Predicting the Test set results 
y_pred = classifier.predict(X_test) 
y_pred = (y_pred > 0.5)
new_prediction = classifier.predict(sc.transform
(np.array([[0.0, 0, 500, 1, 40, 3, 50000, 2, 1, 1, 40000]])))
new_prediction = (new_prediction > 0.5)

Paso 13

Este es el último paso donde evaluamos el rendimiento de nuestro modelo. Ya tenemos resultados originales y, por lo tanto, podemos crear una matriz de confusión para verificar la precisión de nuestro modelo.

Haciendo la Matriz de Confusión

from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
print (cm)
Output
loss: 0.3384 acc: 0.8605
[ [1541 54]
[230 175] ]

Desde la matriz de confusión, la precisión de nuestro modelo se puede calcular como:

Accuracy = 1541+175/2000=0.858

Logramos un 85.8% de precisión, lo cual es bueno.

El algoritmo de propagación hacia adelante

En esta sección, aprenderemos cómo escribir código para hacer una propagación (predicción) hacia adelante para una red neuronal simple:

Cada punto de datos es un cliente. La primera entrada es cuántas cuentas tienen, y la segunda es cuántos hijos tienen. El modelo predecirá cuántas transacciones realizará el usuario en el próximo año.

Los datos de entrada se cargan previamente como datos de entrada, y los pesos están en un diccionario llamado pesos. La matriz de pesos para el primer nodo en la capa oculta está en pesos [‘node_0’], y para el segundo nodo en la capa oculta están en pesos [‘node_1’] respectivamente.

Los pesos que se alimentan en el nodo de salida están disponibles en pesos.

La función de activación lineal rectificada

Una “función de activación” es una función que funciona en cada nodo. Transforma la entrada del nodo en alguna salida.

La función de activación lineal rectificada (llamada ReLU) se usa ampliamente en redes de muy alto rendimiento. Esta función toma un solo número como entrada, devolviendo 0 si la entrada es negativa, e ingresa como salida si la entrada es positiva.

Aquí hay algunos ejemplos:

relu (4) = 4
relu (-2) = 0
Completamos la definición de la función relu () –

Usamos la función max () para calcular el valor de la salida de relu ().
Aplicamos la función relu () a node_0_input para calcular node_0_output.
Aplicamos la función relu () a node_1_input para calcular node_1_output.

import numpy as np
input_data = np.array([-1, 2])
weights = {
   'node_0': np.array([3, 3]),
   'node_1': np.array([1, 5]),
   'output': np.array([2, -1])
}
node_0_input = (input_data * weights['node_0']).sum()
node_0_output = np.tanh(node_0_input)
node_1_input = (input_data * weights['node_1']).sum()
node_1_output = np.tanh(node_1_input)
hidden_layer_output = np.array(node_0_output, node_1_output)
output =(hidden_layer_output * weights['output']).sum()
print(output)

def relu(input):
   '''Define your relu activation function here'''
   # Calculate the value for the output of the relu function: output
   output = max(input,0)
      # Return the value just calculated
   return(output)
# Calculate node 0 value: node_0_output
node_0_input = (input_data * weights['node_0']).sum()
node_0_output = relu(node_0_input)

# Calculate node 1 value: node_1_output
node_1_input = (input_data * weights['node_1']).sum()
node_1_output = relu(node_1_input)

# Put node values into array: hidden_layer_outputs
hidden_layer_outputs = np.array([node_0_output, node_1_output])

# Calculate model output (do not apply relu)
odel_output = (hidden_layer_outputs * weights['output']).sum()
print(model_output)# Print model output



Output
0.9950547536867305
-3

Aplicando la red a muchas observaciones / filas de datos.

En esta sección, aprenderemos cómo definir una función llamada predict_with_network (). Esta función generará predicciones para múltiples observaciones de datos, tomadas de la red anterior, tomadas como input_data. Se están utilizando los pesos dados en la red anterior. La definición de la función relu () también se está utilizando.

Definamos una función llamada predict_with_network () que acepta dos argumentos, input_data_row y pesos, y devuelve una predicción de la red como salida.

Calculamos los valores de entrada y salida para cada nodo, almacenándolos como: node_0_input, node_0_output, node_1_input, y node_1_output.

Para calcular el valor de entrada de un nodo, multiplicamos las matrices relevantes y calculamos su suma.

Para calcular el valor de salida de un nodo, aplicamos la función relu () al valor de entrada del nodo. Utilizamos un ‘for loop’ para iterar sobre input_data –

También utilizamos nuestro predict_with_network () para generar predicciones para cada fila de input_data – input_data_row. También anexamos cada predicción a los resultados.

# Define predict_with_network()
def predict_with_network(input_data_row, weights):
   # Calculate node 0 value
   node_0_input = (input_data_row * weights['node_0']).sum()
   node_0_output = relu(node_0_input)
   
   # Calculate node 1 value
   node_1_input = (input_data_row * weights['node_1']).sum()
   node_1_output = relu(node_1_input)
   
   # Put node values into array: hidden_layer_outputs
   hidden_layer_outputs = np.array([node_0_output, node_1_output])
   
   # Calculate model output
   input_to_final_layer = (hidden_layer_outputs*weights['output']).sum()
   model_output = relu(input_to_final_layer)
# Return model output
   return(model_output)

# Create empty list to store prediction results
results = []
for input_data_row in input_data:
   # Append prediction to results
   results.append(predict_with_network(input_data_row, weights))
print(results)# Print results

Output
[0, 12]

Aquí hemos usado la función relu donde relu (26) = 26 y relu (-13) = 0 y así sucesivamente.

Redes neuronales multicapa profundas

Aquí estamos escribiendo código para hacer una propagación hacia adelante para una red neuronal con dos capas ocultas. Cada capa oculta tiene dos nodos. Los datos de entrada se han cargado previamente como input_data. Los nodos en la primera capa oculta se llaman node_0_0 y node_0_1.

Sus pesos se cargan previamente como weights[‘node_0_0’] y weights[‘node_0_1’] respectivamente.

Los nodos en la segunda capa oculta se llaman node_1_0 y node_1_1. Sus pesos se cargan previamente como weights[‘node_1_0’] y weights[‘node_1_1’] respectivamente.

Luego creamos una salida de modelo a partir de los nodos ocultos usando ponderaciones precargadas como weights[‘output’].

Calculamos node_0_0_input utilizando sus ponderaciones weights[‘node_0_0’] y los datos de entrada especificados. Luego aplique la función relu() para obtener node_0_0_output.

Hacemos lo mismo que anteriormente para node_0_1_input para obtener node_0_1_output.

Calculamos node_1_0_input utilizando sus ponderaciones weights[‘node_1_0’] y los resultados de la primera capa oculta: hidden_0_outputs. Luego aplicamos la función relu() para obtener node_1_0_output.

Hacemos lo mismo que anteriormente para node_1_1_input para obtener node_1_1_output.

Calculamos model_output utilizando weights[‘output’] y las salidas de la segunda capa oculta en la matriz hidden_1_outputs. No aplicamos la función relu() a esta salida.

import numpy as np
input_data = np.array([3, 5])
weights = {
   'node_0_0': np.array([2, 4]),
   'node_0_1': np.array([4, -5]),
   'node_1_0': np.array([-1, 1]),
   'node_1_1': np.array([2, 2]),
   'output': np.array([2, 7])
}
def predict_with_network(input_data):
   # Calculate node 0 in the first hidden layer
   node_0_0_input = (input_data * weights['node_0_0']).sum()
   node_0_0_output = relu(node_0_0_input)
   
   # Calculate node 1 in the first hidden layer
   node_0_1_input = (input_data*weights['node_0_1']).sum()
   node_0_1_output = relu(node_0_1_input)
   
   # Put node values into array: hidden_0_outputs
   hidden_0_outputs = np.array([node_0_0_output, node_0_1_output])
   
   # Calculate node 0 in the second hidden layer
   node_1_0_input = (hidden_0_outputs*weights['node_1_0']).sum()
   node_1_0_output = relu(node_1_0_input)
   
   # Calculate node 1 in the second hidden layer
   node_1_1_input = (hidden_0_outputs*weights['node_1_1']).sum()
   node_1_1_output = relu(node_1_1_input)
   
   # Put node values into array: hidden_1_outputs
   hidden_1_outputs = np.array([node_1_0_output, node_1_1_output])
   
   # Calculate model output: model_output
   model_output = (hidden_1_outputs*weights['output']).sum()
      # Return model_output
   return(model_output)
output = predict_with_network(input_data)
print(output)

Output
364


Written by Tutor