Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
clase:iabd:pia:2eval:tema09 [2023/09/22 16:02] admin |
clase:iabd:pia:2eval:tema09 [2025/02/15 20:07] (actual) admin [Ejercicios] |
||
---|---|---|---|
Línea 1: | Línea 1: | ||
- | ====== 9. Redes Neuronales Recurrentes | + | ====== 9 Optimización de redes neuronales ====== |
+ | |||
+ | |||
+ | ===== Sobreajuste | ||
+ | El sobreajuste (en inglés Overfitting) es cuando nuestro modelo, en vez de aprender lo que hace es memorizar los resultados. Tambien existe el concepto de subajuste (en inglés underfitting) que es cuando el modelo no es lo suficientemente ponente para adecuarse a los datos. En redes neuronales suele darse menos el underfitting ya que las redes las podemos haces bastantes complejos y solemos pecar de modelos demasiado complejos. | ||
+ | |||
+ | En las siguientes gráficas se observas distintos redes neuronales que tienen sobreajuste: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | El sobreajuste se ve porque la red aprende cada vez más en entrenamiento pero aprende cada vez menos en validación. Es decir, disminuye la perdida en entrenamiento pero no disminuye en validación. | ||
+ | |||
+ | ¿Como podemos evitar el sobre ajuste? Hay varias formas: | ||
+ | * Dropout | ||
+ | * Regularización | ||
+ | |||
+ | |||
+ | ===== Regularización | ||
+ | Para hacer el modelo mas sencillo, la regularización intenta que los pesos sean mas pequeños. En una red neuronal tenemos una serie de pesos '' | ||
+ | |||
+ | Se consigue que el tener el '' | ||
+ | |||
+ | Existen 3 tipos de regularizadores (realmente existen más): | ||
+ | * **L1**: También llamada //Lasso//. Intenta hacer los pesos lo más pequeños posibles. | ||
+ | * **L2**: También llamada //Ridge//. Intenta eliminar correlaciones entre pesos. | ||
+ | * **L1 y L2**: También llamada // | ||
+ | |||
+ | $$ | ||
+ | \begin{array} | ||
+ | \\ | ||
+ | |||
+ | Loss \; con & | ||
+ | \\ | ||
+ | Loss \; con & | ||
+ | \\ | ||
+ | Losss \; con & | ||
+ | \\ | ||
+ | \end{array} | ||
+ | $$ | ||
+ | |||
+ | |||
+ | |||
+ | Más información: | ||
+ | * [[https:// | ||
+ | * [[http:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * {{ : | ||
+ | * [[https:// | ||
+ | * {{ : | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | |||
+ | |||
+ | ===== Regularización en Keras ===== | ||
+ | |||
+ | Los regularizadores se pueden aplicar tanto a los '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | <note tip>Lo normal es aplicar los regularizadores a los '' | ||
+ | |||
+ | Ejemplos de uso en Keras de '' | ||
+ | <sxh python> | ||
+ | from tensorflow.keras import regularizers | ||
+ | |||
+ | kernel_regularizer=regularizers.L1(l1=0.01) | ||
+ | kernel_regularizer=" | ||
+ | model.add(Dense(neuronas_capa, | ||
+ | </ | ||
+ | |||
+ | Ejemplos de uso en Keras de '' | ||
+ | <sxh python> | ||
+ | from tensorflow.keras import regularizers | ||
+ | |||
+ | kernel_regularizer=regularizers.L2(l2=0.01) | ||
+ | kernel_regularizer=" | ||
+ | model.add(Dense(neuronas_capa, | ||
+ | </ | ||
+ | |||
+ | Ejemplos de uso en Keras de '' | ||
+ | <sxh python> | ||
+ | from tensorflow.keras import regularizers | ||
+ | |||
+ | kernel_regularizer=regularizers.L1L2(l1=0.01, | ||
+ | kernel_regularizer=" | ||
+ | model.add(Dense(neuronas_capa, | ||
+ | </ | ||
+ | |||
+ | Los valores de '' | ||
+ | |||
+ | < | ||
+ | Como vemos el regularizador se puede indicar creando la clase para indicar el nivel de regularización o simplemente con un string e indicando el nombre. | ||
+ | </ | ||
+ | |||
+ | ===== Analizando la regularización ===== | ||
+ | |||
+ | Vamos a ver como funcionan los distintos regularizadores y con distintos valores: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | * En la siguiente gráfica vamos a mostrar el valor de la pérdida en la **última época** en función del nivel de regularización: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | La línea roja indica para la red sin regularizar el mejor valor de todas las épocas. Es decir es el valor cuando aun no hay sobre ajuste y por lo tanto pocas épocas. | ||
+ | La gráfica muestra la pérdida de la última época para cada tasa de regularización. | ||
+ | Se puede apreciar que con un poco de regularización se mejora la red , pero nunca llega a estar por debajo de la línea roja. Es decir se ve que entrenar más y aplicar regularización no supone ninguna mejora. | ||
+ | |||
+ | * En la siguiente gráfica vamos a mostrar el valor de la pérdida en la **mejor época** en función del nivel de regularización: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | Esta gráfica es similar a la anterior pero ahora se muestra la mejor pérdida (para cualquier época) en vez de la perdida de la última época.En ese caso la línea roja coincide con el primer punto de "Val loss" ya que es cuando no hay regularización. En ese caso también se ve que entrenar más y aplicar regularización no supone ninguna mejora en ninguna de las épocas. | ||
+ | |||
+ | |||
+ | <note > | ||
+ | La conclusión con estas gráficas es que hay que valorar entre 2 opciones: | ||
+ | * Entrenar pocas épocas antes de que haya sobreajuste y no necesitar ninguna regularización. | ||
+ | * Entrenar durante muchas épocas aunque haya sobreajuste y aplicar regularización | ||
+ | |||
+ | La opción a elegir dependerá del problema y hay que probar ambas opciones para saber cual es la mejor opción. | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | Aunque una regla es que si elegimos entrenar durante pocas épocas antes del sobre ajuste pero el rendimiento no es satisfactorio, | ||
+ | </ | ||
+ | |||
+ | ===== Dropout ===== | ||
+ | El Dropout consiste en hacer que ciertas neuronas se vayan desactivando cada vez en el **entrenamiento**. | ||
+ | |||
+ | Se hace añadiendo capas de '' | ||
+ | |||
+ | Uso de uso en Keras de Dropout: | ||
+ | <sxh python> | ||
+ | from tensorflow.keras.layers import Dropout | ||
+ | |||
+ | dropout_rate=0.02 | ||
+ | model.add(Dense(neuronas_capa, | ||
+ | model.add(Dropout(rate=dropout_rate)) | ||
+ | </ | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ===== Optimización ===== | ||
+ | Junto con las técnicas anteriores , existen otras para mejorar una red neuronal: | ||
+ | * Normalization | ||
+ | * Tamaño de Batch | ||
+ | * Batch Normalization | ||
+ | * Parada anticipada | ||
+ | |||
+ | |||
+ | ===== Normalization ===== | ||
+ | La normalización consiste es que los datos de entrada estén centrado en 0 y una desviación " | ||
+ | Esto se hace porque la red va a entrenarse mejor si los datos son " | ||
+ | |||
+ | Para normalizar los datos se usa la clase [[https:// | ||
+ | |||
+ | |||
+ | |||
+ | <sxh python> | ||
+ | from sklearn.preprocessing import StandardScaler | ||
+ | |||
+ | standard_scaler = StandardScaler() | ||
+ | standard_scaler.fit(x) | ||
+ | x_standard = standard_scaler.transform(x) | ||
+ | </ | ||
+ | |||
+ | Y sobre un ejemplo de datos sería lo siguiente: | ||
+ | <sxh python> | ||
+ | def get_datos_bread_cancer(): | ||
+ | datos=load_breast_cancer() | ||
+ | x=datos.data | ||
+ | y=datos.target | ||
+ | |||
+ | standard_scaler = StandardScaler() | ||
+ | standard_scaler.fit(x) | ||
+ | x = standard_scaler.transform(x) | ||
+ | |||
+ | x_train, x_test, y_train, y_test = train_test_split(x, | ||
+ | |||
+ | state={ | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | |||
+ | return x_train, x_test, y_train, y_test, state | ||
+ | |||
+ | |||
+ | |||
+ | x_train, x_test, y_train, y_test, | ||
+ | </ | ||
+ | |||
+ | |||
+ | Veamos un ejemplo de que es lo que realmente hace. | ||
+ | <sxh python> | ||
+ | from sklearn.preprocessing import StandardScaler | ||
+ | |||
+ | datos=np.random.normal(1000, | ||
+ | |||
+ | figure=plt.figure(figsize = (6, 9)) | ||
+ | axes = figure.add_subplot(3, | ||
+ | sns.histplot(x=datos.reshape(-1), | ||
+ | |||
+ | standard_scaler = StandardScaler() | ||
+ | standard_scaler.fit(datos) | ||
+ | |||
+ | datos_standarized = standard_scaler.transform(datos) | ||
+ | axes = figure.add_subplot(3, | ||
+ | sns.histplot(x=datos_standarized.reshape(-1), | ||
+ | figure.suptitle(" | ||
+ | </ | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | Un problema que hay al usar la clase '' | ||
+ | |||
+ | La forma de hacerlo es la siguiente: | ||
+ | <sxh python> | ||
+ | state={ | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | new_standard_scaler = StandardScaler() | ||
+ | new_standard_scaler.fit([[0]]) | ||
+ | new_standard_scaler.mean_=state[" | ||
+ | new_standard_scaler.var_=state[" | ||
+ | new_standard_scaler.scale_=state[" | ||
+ | new_datos_standarized = new_standard_scaler.transform(datos) | ||
+ | |||
+ | print(" | ||
+ | </ | ||
+ | |||
+ | |||
+ | <sxh base> | ||
+ | Iguales= True | ||
+ | </ | ||
+ | |||
+ | |||
+ | <sxh python> | ||
+ | class DataScaler: | ||
+ | def __init__(self, | ||
+ | self.x=x | ||
+ | self.y=y | ||
+ | self.scaler=scaler | ||
+ | |||
+ | if (np.ndim(x)==1): | ||
+ | self.x_ndim=1 | ||
+ | else: | ||
+ | self.x_ndim=x.shape[1] | ||
+ | |||
+ | |||
+ | if (np.ndim(y)==1): | ||
+ | self.y_ndim=1 | ||
+ | else: | ||
+ | self.y_ndim=y.shape[1] | ||
+ | |||
+ | |||
+ | def get_datos_escalados_entrenamiento(self): | ||
+ | self.x_scaler = self.scaler() | ||
+ | self.y_scaler = self.scaler() | ||
+ | |||
+ | x_scaled = self.x_scaler.fit_transform(self.x.reshape(-1, | ||
+ | y_scaled=self.y_scaler.fit_transform(self.y.reshape(-1, | ||
+ | |||
+ | return x_scaled, | ||
+ | |||
+ | def get_datos_reales(self): | ||
+ | return self.x, | ||
+ | |||
+ | def predict(self, | ||
+ | y_pred=self.y_scaler.inverse_transform(model.predict(self.x_scaler.transform(x_pred.reshape(-1, | ||
+ | return y_pred | ||
+ | |||
+ | </ | ||
+ | |||
+ | ===== Batch Normalization ===== | ||
+ | Hace que las salida sigan con valores alrededor de media 0 y desviación 1. | ||
+ | |||
+ | <sxh python> | ||
+ | model.add(Dense(neuronas_capa, | ||
+ | model.add(BatchNormalization()) | ||
+ | </ | ||
+ | |||
+ | ===== Tamaño del Batch ===== | ||
+ | <sxh python> | ||
+ | history=model.fit(x_train, | ||
+ | </ | ||
+ | |||
+ | |||
+ | <sxh python> | ||
+ | def fit(x, y_true, | ||
+ | #Divide los datos en batchs | ||
+ | x_batchs=np.split(x, | ||
+ | y_true_batchs=np.split(y_true, | ||
+ | num_batchs=len(x_batchs) | ||
+ | |||
+ | for epoch in range(epochs): | ||
+ | for i in range(num_batchs): | ||
+ | |||
+ | x_batch=x_batchs[i] | ||
+ | y_true_batch=y_true_batchs[i] | ||
+ | |||
+ | w_2, | ||
+ | |||
+ | return w_2, | ||
+ | </ | ||
+ | |||
+ | * [[https:// | ||
+ | |||
+ | |||
+ | ===== Callbacks ===== | ||
+ | |||
+ | ==== Guardar mejor modelo ==== | ||
+ | Al entrenar no siempre la última época es el mejor modelo, por ello hay un callback de keras que nos guarda el mejor modelo. Se llama '' | ||
+ | |||
+ | La clase contiene entre otros los siguientes parámetros: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | <sxh python> | ||
+ | from tensorflow.keras.callbacks import ModelCheckpoint | ||
+ | |||
+ | checkpoint_callback = ModelCheckpoint( | ||
+ | ' | ||
+ | monitor=' | ||
+ | save_best_only=True, | ||
+ | mode=' | ||
+ | ) | ||
+ | |||
+ | |||
+ | history=model.fit(x_train, | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== Parada anticipada ==== | ||
+ | La parada anticipada resuelve el problema de cuántas épocas debemos entregar nuestro modelo. Lo que hace es detener el entrenamiento si la métrica no mejora. Para ello se usa la clase de callback de keras llamado '' | ||
+ | |||
+ | La clase contiene entre otros los siguientes parámetros: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | <sxh python> | ||
+ | from tensorflow.keras.callbacks import EarlyStopping | ||
+ | |||
+ | earlystopping_callback = EarlyStopping( | ||
+ | monitor=' | ||
+ | min_delta=0.001, | ||
+ | patience=10, | ||
+ | mode=' | ||
+ | restore_best_weights=True # Restaurar los mejores pesos | ||
+ | ) | ||
+ | |||
+ | |||
+ | history=model.fit(x_train, | ||
+ | |||
+ | |||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | ¿Tiene sentido usar '' | ||
+ | </ | ||
+ | |||
+ | |||
+ | Más información: | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | |||
+ | |||
+ | ===== Ejercicios ===== | ||
+ | |||
+ | ==== Ejercicio 1.A ==== | ||
+ | Crea una red neuronal para predecir si una persona va a tener una enfermedad cardíaca. Para ello se han usado los datos de {{https:// | ||
+ | |||
+ | Las columnas del dataset son las siguientes: | ||
+ | |||
+ | * HeartDiseaseorAttack: | ||
+ | * HighBP: Indica si el individuo tiene presión arterial alta. | ||
+ | * HighChol: Indica si el individuo tiene niveles altos de colesterol. | ||
+ | * CholCheck: Indica si el individuo ha realizado chequeos de colesterol. | ||
+ | * BMI: Índice de Masa Corporal del individuo. | ||
+ | * Smoker: Indica si el individuo fuma. | ||
+ | * Stroke: Indica si el individuo ha experimentado un derrame cerebral. | ||
+ | * Diabetes: Indica si el individuo tiene diabetes. | ||
+ | * PhysActivity: | ||
+ | * Fruits: Consumo de frutas por parte del individuo. | ||
+ | * Veggies: Consumo de vegetales por parte del individuo. | ||
+ | * HvyAlcoholConsump: | ||
+ | * AnyHealthcare: | ||
+ | * NoDocbcCost: | ||
+ | * GenHlth: Estado general de salud del individuo. | ||
+ | * MentHlth: Estado de salud mental del individuo. | ||
+ | * PhysHlth: Estado de salud física del individuo. | ||
+ | * DiffWalk: Dificultad para caminar del individuo. | ||
+ | * Sex: Género del individuo. | ||
+ | * Age: Edad del individuo. | ||
+ | * Education: Nivel educativo del individuo. | ||
+ | * Income: Ingreso económico del individuo. | ||
+ | |||
+ | |||
+ | Los datos son los siguientes: {{ : | ||
+ | |||
+ | ==== Ejercicio 1.B ==== | ||
+ | Mejora la red normalizando los datos . Usa '' | ||
+ | |||
+ | ¿Ha mejorado la red? | ||
+ | |||
+ | ==== Ejercicio 1.C ==== | ||
+ | Modifica la red de forma que haya muchas neuronas y que haya sobreajuste. | ||
+ | |||
+ | Debes mostrar una gráfica en la que se vea el //loss// en entrenamiento y validación. | ||
+ | |||
+ | Ahora vamos a comprobar si es mejor regularizar (L1, L2 y L1L2) o simplemente no sobreentrenar para ello crea una gráficas similares a éstas: | ||
+ | |||
+ | {{clase: | ||
+ | |||
+ | |||
+ | ==== Ejercicio 1.D ==== | ||
+ | Repite ahora las gráficas pero en vez de regularizar, | ||
+ | |||
+ | ==== Ejercicio 1.E ==== | ||
+ | Usa ahora '' | ||
+ | |||
- | * [[https:// | ||
- | * [[https:// | ||
- | * [[https:// |