Laboratorio 4 - Parte 1. Redes neuronales artificiales - perceptrón multicapa#
!wget -nc --no-cache -O init.py -q https://raw.githubusercontent.com/jdariasl/Intro_ML_2025/master/init.py
import init; init.init(force_download=False); init.get_weblink()
from local.lib.rlxmoocapi import submit, session
import inspect
session.LoginSequence(endpoint=init.endpoint, course_id=init.course_id, lab_id="L04.01", varname="student");
#configuración del laboratorio
# Ejecuta esta celda!
from Labs.commons.utils.lab4 import *
_ = part_1()
Este ejercicio tiene como objetivo implementar una red neuronal artificial de tipo perceptrón multicapa (MLP) para resolver un problema de regresión. Usaremos la librería sklearn. Consulte todo lo relacionado con la definición de hiperparámetros, los métodos para el entrenamiento y la predicción de nuevas muestras en el siguiente enlace: http://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPRegressor.html#sklearn.neural_network.MLPRegressor
Para este ejercicio usaremos la base de datos sobre calidad del aire, que ha sido usada en laboratorios previos, pero en este caso trataremos de predecir dos variables en lugar de una, es decir, abordaremos un problema de múltiples salidas.
#cargamos la bd que está en un archivo .data y ahora la podemos manejar de forma matricial
db = np.loadtxt('Labs/commons/utils/data/AirQuality.data',delimiter='\t') # Assuming tab-delimiter
#Esta es la base de datos AirQuality del UCI Machine Learning Repository. En el siguiente URL se encuentra toda
#la descripción de la base de datos y la contextualización del problema.
#https://archive.ics.uci.edu/ml/datasets/Air+Quality#
x = db[:,0:11]
y = db[:,11:13]
Para calcular los errores, vamos a explorar y usar el modulo de metricas de sklearn.
Podemos observar que el modulo tiene metricas para regresión y clasificación.
Ejercicio 1 - Experimentar con MLP para regresión#
Para porder implementar nuestra función, lo primero que debemos entender es la estructura de la red.
Como mencionamos, vamos a solucionar un problema de multiples salidas. Estas salidas contienen valores continuos. Por lo tanto debemos garantizar que la capa de salida de nuestra red tenga la capacidad de modelar este tipo de datos.
#@title Pregunta Abierta
#@markdown ¿De acuerdo al problema planteado, que función de activación debe usar el MLP para un problema de regresión?
respuesta = "" #@param {type:"string"}
Una característica de los modelos de sklearn, es que ciertos tipos de atributos solo pueden ser accedidos cuando se entrena el modelo. Vamos a desarrollar una pequeña función para comprobar cuál es la función de activación de los modelos MLP para regresión de sklearn.
# ejercicio de código
def output_activation():
"""funcion que entrena un modelo
con datos aleatorios para confirmar la función
de activación de la ultima capa
"""
mlp = MLPRegressor()
# fit with some random data
xrandom = np.random.rand(10,2)
yrandom = np.zeros(10)
# llamar el metodo adecuado para entrenar
# el mlp con los x y 'y' random
mlp.fit(, )
# retornar el atributo de mlp adecuado
return (mlp.)
Registra tu solución en línea
student.submit_task(namespace=globals(), task_id='T1');
print("la función de activación para un problema de regresion es:", output_activation())
Ejercicio 2 Experimentar con MLP para regresión#
Una vez comprobado que sklearn usa la función de activación correcta, vamos a crear la función para realizar los experimentos.
Completa la función con el código necesario para usar una red neuronal tipo MLP para solucionar el problema de regresión propuesto.
Como función de activación en las capas ocultas use la función ‘tanh’.
Ajuste el número máximo de épocas a 300.
Dejamos como variables el número de capas ocultas y el número de neuronas por capa
debemos seleccionar la función adecuada del modulo de sklearn para calcular el Error Porcentual Absoluto Medio (MAPE en sigla en ingles). Tener en cuenta qué parametros usar.
Tenga en cuenta que para instanciar los modelos no se usan parámetros posicionales.
# ejercicio de código
def experimentar_mlpr(num_hidden_layers, num_neurons, X,Y):
""" función para realizar experimentos con el MLP
num_hidden_layers: list de enteros con el número de capdas
ocultas a usar
num_neurons: list de enteros con el número de neuronas a usar
X: matriz de numpy con los datos de entrada [muestras,variables]
Y: matriz numpy con las variables a predecir
Retorna: dataframe con 6 columnas:
- número de capas, número de neuronas
- promedio de error prueba variable 1 y desviación estandar
- promedio de error prueba variable 2 y desviación estandar
"""
#Validamos el modelo
Folds = 3
ss = ShuffleSplit(n_splits=Folds, test_size=0.2, random_state=1)
resultados = pd.DataFrame()
idx = 0
for hidden_layers in num_hidden_layers:
for neurons in num_neurons:
for j, (train, test) in enumerate(ss.split(X)):
# para almacenar errores intermedios
ErrorY1 = np.zeros(Folds)
ErrorY2 = np.zeros(Folds)
Xtrain= X[train,:]
Ytrain = Y[train,:]
Xtest = X[test,:]
Ytest = Y[test,:]
#Normalizamos los datos
scaler = StandardScaler().fit(X= Xtrain)
Xtrain = scaler.transform(Xtrain)
Xtest = scaler.transform(Xtest)
#Haga el llamado a la función para crear y entrenar el modelo usando los datos de entrenamiento
#Ajuste la semilla del modelo a 1 para garantizar la reproducibilidad de los resultados.
hidden_layer_sizes = tuple()
mlp = MLPRegressor()
# entrena el MLP
mlp
# Use para el modelo para hacer predicciones sobre el conjunto Xtest
Yest = ...
# Mida el MAPE para cada una de las dos salidas
errors =
ErrorY1[j] = ...
ErrorY2[j] =...
print('error para salida 1 = ' + str(np.mean(ErrorY1)) + '+-' + str(np.std(ErrorY1)))
print('error para salida 2 = ' + str(np.mean(ErrorY2)) + '+-' + str(np.std(ErrorY2)))
resultados.loc[idx,'capas ocultas'] = hidden_layers
resultados.loc[idx,'neuronas en capas ocultas'] = neurons
resultados.loc[idx,'error de prueba y1(media)'] = np.mean(ErrorY1)
resultados.loc[idx,'intervalo de confianza y1'] = np.std(ErrorY1)
resultados.loc[idx,'error de prueba y2(media)'] = np.mean(ErrorY2)
resultados.loc[idx,'intervalo de confianza y2'] = np.std(ErrorY2)
idx+=1
return (resultados)
Registra tu solución en línea
student.submit_task(namespace=globals(), task_id='T2');
vamos a realizar los experimentos
# tarda unos minutos!!
resultados_mlpr = experimetar_mlpr(num_hidden_layers = [1,2,3], num_neurons = [8,12,16], X=x, Y=y)
# ver los resultados.
import seaborn as sns
sns.relplot(data = resultados_mlpr, x='neuronas en capas ocultas', y = 'error de prueba y1(media)', style= 'capas ocultas', kind = 'line')
sns.relplot(data = resultados_mlpr, x='neuronas en capas ocultas', y = 'error de prueba y2(media)', style= 'capas ocultas', kind = 'line')
plt.show()
#@title Pregunta Abierta
#@markdown Qué ocurre si cambiamos el valor de random state? ¿deberían los resultados ser iguales?
respuesta = "" #@param {type:"string"}
Ejercicio 3 Experimentar con MLP para clasificación#
A continuación se leen los datos de un problema de clasificación. El problema corresponde a la clasifiación de dígitos escritos a mano. Usaremos únicamente 4 de las 10 clases disponibles. Los datos fueron preprocesados para reducir el número de características.
digits = load_digits(n_class=4)
#--------- preprocesamiento--------------------
pca = PCA(0.99, whiten=True)
data = pca.fit_transform(digits.data)
#---------- Datos a usar ----------------------
Xd = data
Yd = digits.target
#@title Pregunta Abierta
#@markdown ¿Qué tipo de función de activación debe usar el modelo en la capa de salida para un problema de clasificación?
respuesta = "" #@param {type:"string"}
como lo hicmos antes, vamos a comprobar con la libreria la función de activación
# ejercicio de código
def output_activation_MPC():
"""funcion que entrena un modelo
con data aleatoria para confirmar la funcion
de activacion de la ultima capa
"""
mlp = MLPClassifier()
# fit with some random data
xrandom = np.random.rand(10,2)
yrandom = np.zeros(10)
# llamar el metodo adecuado para entrenar
# el mlp con los x y 'y' random
mlp.fit(, )
# retornar el atributo de mlp adecuado
return (mlp)
print("la función de activación para un problema de clasificación es:", output_activation_MPC())
Ahora en nuestro siguiente ejercicio vamos a implementar una red neuronal artificial de tipo perceptrón multicapa (MLP) para resolver un problema de clasificación. Usaremos la librería sklearn. Consulte todo lo relacionado con la definición de hiperparámetros, los métodos para el entrenamiento y la predicción de nuevas muestras en el siguiente enlace: http://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPClassifier.html#sklearn.neural_network.MLPClassifier
Vamos completar la función con el código necesario para usar una red neuronal tipo MLP para solucionar el problema de clasificación propuesto.
Como función de activación en las capas ocultas use la función relu.
Ajuste el número máximo de épocas a 350.
Dejamos como variables el número de capas ocultas y el número de neuronas por capa
Seleccione la función adecuada del modulo de sklearn para calcular la exactitud del clasificador.
# ejercicio de código
def experimentar_mlpc(X,Y, num_hidden_layers, num_neurons):
""" función para realizar experimentos con el MLP
x: matriz de numpy con las muestras de entrada [muestras,variables]
y: vector numpy con las variables a predecir
num_hidden_layers: list de enteros con el número de capas
ocultas a usar
num_neurons: list de enteros con el número de neuronas a usar
Retorna: dataframe con 4 columnas:
- número de capas, número de neuronas
- promedio de error prueba (exactitud/eficiencia) de claisficación y desviación estandar
"""
#Validamos el modelo
Folds = 4
skf = StratifiedKFold(n_splits=Folds)
resultados = pd.DataFrame()
idx = 0
for hidden_layers in num_hidden_layers:
for neurons in num_neurons:
for j, (train, test) in enumerate(skf.split(X, Y)):
# para almacenar errores intermedios
Error = np.zeros(Folds)
Xtrain= X[train,:]
Ytrain = Y[train]
Xtest = X[test, :]
Ytest = Y[test]
#Normalizamos los datos
scaler = StandardScaler().fit(X= Xtrain)
Xtrain = scaler.transform(Xtrain)
Xtest = scaler.transform(Xtest)
#Haga el llamado a la función para crear y entrenar el modelo usando los datos de entrenamiento
#Ajuste la semilla del modelo a 1 para garantizar la reproducibilidad de los resultados.
hidden_layer_sizes = ...
mlp =
# entrenar el MLP
mlp...
#Use para el modelo para hacer predicciones sobre el conjunto Xtest
Yest = mlp.
# recordar usar la medida adecuada de acuerdo a las instrucciones
Error[j] =
print('error para configuracion de params = ' + str(np.mean(Error)) + '+-' + str(np.std(Error)))
resultados.loc[idx,'capas ocultas'] = hidden_layers
resultados.loc[idx,'neuronas en capas ocultas'] = neurons
resultados.loc[idx,'error de prueba(media)'] = np.mean(Error)
resultados.loc[idx,'intervalo de confianza'] = np.std(Error)
idx+=1
return (resultados)
Registra tu solución en línea
student.submit_task(namespace=globals(), task_id='T3');
# tarda unos minutos!!
resultados_mlpc = experimetar_mlpc(X = Xd, Y=Yd, num_hidden_layers=[1,2,3], num_neurons=[12,16,20])
# ver los resultados
# notar como las capas ocultas y el # de neuronas influyen
import seaborn as sns
sns.relplot(data = resultados_mlpc, x='neuronas en capas ocultas', y = 'error de prueba(media)', style= 'capas ocultas', kind = 'line')
plt.show()
#@title Pregunta Abierta
#@markdown ¿Cuántas neuronas en la capa de salida tiene el modelo? ¿Porqué debe tener ese número?
respuesta = "" #@param {type:"string"}
Ejercicio 4. Usar PyTorch para definir una arquitectura de red para clasificación.#
Como se discutió en clase, los frameworks actuales para el diseño de redes neuronales artificales permiten mucha mayor flexibilidad a la hora de crear redes con diversas arquitecturas, diseñar funciones de coste o incluso nuevos tipos de capas. Uno de esos frameworks es PyTorch.
Una red neuronal de tipo MLP es una red compuesta únicamente por capas Densas, llamadas en PyTorch capas lineales (Linear
](https://pytorch.org/docs/stable/generated/torch.nn.Linear.html)).
Lea la documentación del modulo Sequential de PyTorch
Complete la siguiente función para crear un modelo de red neuronal para el problema de clasificación de digitos usando el modulo Sequential. Las funciones de activiación de las capas ocultas deben ser tipo ‘relu’.
Tenga en cuenta que Ud puede primero crear una lista de módulos (capas, activaciones, etc.) y luego crear el modelo
nn.Sequential(*modules)
. Las activaciones serán tratadas como capas adicionales.No incluya la función de activación de la capa de salida
#ejercicio de código
def MLP_classifier_pytorch(X,Y, neurons_per_layer):
"""
Entrada:
X: matriz de numpy con las muestras de entrada [muestras,variables]
Y: vector numpy con las variables a predecir
neurons_per_layer: list de enteros con el número de neuronas a usar por
capa una de las capas ocultas
Retorna:
Modelo de PyTorch con la arquitectura deseada
"""
import torch.nn as nn
modules = []
for ...
model = nn.Sequential(*modules)
return model
Registra tu solución en línea
student.submit_task(namespace=globals(), task_id='T4');
#Experimentar con el modelo creado en PyTorch
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
import torch
#Data partition
train_indx, test_indx = train_test_split(np.arange(Xd.shape[0]), train_size=0.7, random_state=1)
Xtrain = Xd[train_indx,:]
Ytrain = Yd[train_indx]
Xtest = Xd[test_indx,:]
Ytest = Yd[test_indx]
#Normalization
scaler = StandardScaler().fit(X= Xtrain)
Xtrain = scaler.transform(Xtrain)
Xtest = scaler.transform(Xtest)
#Tensor transformation
Xtrain = torch.tensor(Xtrain, dtype=torch.float32)
Ytrain = torch.tensor(Ytrain, dtype=torch.long)
Xtest = torch.tensor(Xtest, dtype=torch.float32)
#Set the loss function
#En PyTorch la función de crossentropia aplica la activación Softmax, por eso no
# se debe incluir en la construcción del modelo.
loss_fn = torch.nn.CrossEntropyLoss()
model = MLP_classifier_pytorch(X = Xtrain, Y=Ytrain, neurons_per_layer=[20,10])
#Definimos el optimizador
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
max_epochs = 100
model.train()
for i in range(max_epochs):
out_put = model(Xtrain)
loss = loss_fn(out_put, Ytrain)
print(f'epoch = {i}, loss = {loss}')
optimizer.zero_grad()
loss.backward()
optimizer.step()
model.eval()
Yest = model(Xtest)
Yest = torch.argmax(Yest, axis=1)
print(f'Test accuracy = {accuracy_score(Ytest, Yest)}')