Si bien la configuración de cada proyecto de Machine Learning pueden ser radicalmente diferente y personalizada, hay generalidades que se pueden aplicar para impulsar la calidad de nuestros modelos. A continuación vamos a hablar de algunas de ellas en las diferentes etapas del desarrollo de algoritmos de IA.
Durante el preprocesamiento de los datos
En esta etapa temprana es de vital importancia entender la naturaleza de los datos y sus propósitos. Algunas de las recomendaciones son:
- Buscar datos null o archivos corruptos: estos datos aportarán basura al modelo y reducirán el rendimiento final si no son excluidos del dataset prematuramente.
- Balancear tu base de datos: intenta que la cantidad de ejemplos para cada etiqueta sea proporcional porque un desbalanceo terminará en un algoritmo que no clasificará correctamente pero dará (falsamente) buenas métricas.
- Aplicar normalización: normalizar los datos hará que sean más livianos de procesar y que se estandaricen frente al resto de features.
- Visualizar y entender los datos: la lógica de negocio lo es todo, si logramos entender la naturaleza y el propósito de nuestros datos podremos dar una dirección diferente a nuestros proyectos, nuestro valor como IA devs radicará en esto.
Ajuste de hiperparámetros
Estas configuraciones se hacen durante la creación de la arquitectura y la compilación de nuestro modelo y son más específicas con respecto a valores numéricos. Algunas recomendaciones son:
- Crear convoluciones de tamaño 3x3, de esta manera no perderemos información durante las operaciones.
- Definir la capa de Max Pooling en 2x2 para reducir la complejidad del modelo y no perder abruptamente muchas features por cada convolución.
- Aplanar las imágenes al final del proceso de convolución (capa flatten), esto combinará todos los features obtenidos de las convoluciones en un solo array lineal.
- Inicializar nuestros modelos con arquitecturas pequeñas de pocas neuronas, generalmente empezar desde 32 o 64 neuronas y crecer la cantidad por cada capa según las potencias de 2 (65/128/256/512).
- Inicializar el learning rate en 0.001 (sin embargo tunners como adam nos permiten iterar su valor según el rendimiento de la red), los regularizadores L1 y L2 en 1x10^-5 y el dropout en 0.2 (20%).
Regularizadores
Los regularizadores son un tipo de hiperparámetros que tienen sus propias intuiciones, algunas recomendaciones son:
- Determinar qué tipo de regularizador (L1, L2 o L1+L2) usar según la naturaleza de tus datos. Si crees que pueden haber features inútiles en tu red, entonces aplica L1, si crees que tienes features con alta correlación entre si, aplica L2, y si tienes un dataset con alta cantidad de datos y ambas situaciones aplican, usa L1+L2 (también conocido como ElasticNet).
- Si tu red no está rindiendo a nivel suficiente intenta con agregar más datos adquiriéndolos de su fuente original, si no es posible, puedes generar nuevos datos con data augmentation.
- El dropout obligará a tu modelo a generalizar patrones en vez de memorizar ejemplos, siempre es buena idea agregarlo (especialmente si notas overfitting).
- Puedes controlar el rendimiento de tu red con callbacks, específicamente los de Early Stopping (que detendrán el proceso de entrenamiento si no se detecta una mejoría con respecto a una métrica) y Model Checkpoint, que guardarán una instancia de tu modelo en su mejor época en caso de que hayas sobre entrenado tu red.
Funciones de activación
Las funciones de activación transforman los resultados lineales de nuestra red, su elección impactará directamente en el rendimiento de las predicciones y del entrenamiento, algunas recomendaciones son:
- Si debes clasificar entre más de 2 clases, entonces deberías usar la función Softmax.
- Si la clasificación es binaria, entonces la función sigmoidal funcionará (esta retorna valores entre 0 y 1 interpretables como probabilidades).
- Si vas a realizar una regresión en vez de una clasificación lo mejor será usar una función lineal (o en ocasiones no aplicar la función de activación en la capa final).
- Si tienes más de 0 clases siempre será óptimo usar la ReLU durante el uso de capas ocultas.
Durante la configuración de la red
Mientras configuras tu red puedes encontrar algunas mejoras que aplicar a tu modelo, algunas son:
- Siempre aplica capas de convolución y max pooling de ser posible. Estas se apilan como si fueran capas ocultas y son especialmente útiles en el procesamiento de imágenes.
- Varía y busca el learning rate óptimo para tu proyecto, es posible que en ocasiones apliques valores muy altos y tu modelo nunca alcance el mínimo global (porque salta mucho entre pasos) o que apliques valores muy bajos y te tome demasiadas iteraciones sacar conclusiones.
- Siempre almacena tu registro de entrenamientos. Es posible que durante alguna iteración de tu proyecto encuentres una configuración que te dio un excelente desempeño, pero al no guardar los datos la perdiste y debiste volver a empezar.
Con todo lo anterior, vamos a implementar mejoras a nuestro modelo que se reflejarán en la reducción del overfitting.
Ajustando el modelo
Para esta ocasión agregaremos una capa de convolución al modelo, sus especificaciones serán 75 filtros de tamaño 3x3 y con función de activación ReLU, además, por ser la nueva primer capa, recibirá las dimensiones de los datos de entrada.
Para reducir un poco la complejidad del modelo, hemos usado una capa de MaxPooling de 2x2 que abstraerá el pixel más relevante por cada 4 pixeles, mitigando el tamaño de salidas que generarán las convoluciones.
Finalmente aplanaremos las imágenes para procesarlas como lo estábamos haciendo en el modelo original.
```python
model_convolutional = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(75, (3,3), activation = "relu", input_shape = (28, 28, 1)),
tf.keras.layers.MaxPool2D((2,2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(256, kernel_regularizer = regularizers.l2(1e-5), activation = "relu"),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(128, kernel_regularizer = regularizers.l2(1e-5), activation = "relu"),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(len(classes), activation = "softmax")
])
model_convolutional.summary()
```
El resumen del código nos mostrará estas nuevas adiciones e incrementará la cantidad de parámetros entrenables.
```python
Model: "sequential_4"
Layer (type) Output Shape Param
conv2d (Conv2D) (None, 26, 26, 75) 750
max_pooling2d (MaxPooling2D (None, 13, 13, 75) 0
)
flatten_5 (Flatten) (None, 12675) 0
dense_13 (Dense) (None, 256) 3245056
dropout_4 (Dropout) (None, 256) 0
dense_14 (Dense) (None, 128) 32896
dropout_5 (Dropout) (None, 128) 0
dense_15 (Dense) (None, 24) 3096
=================================================================
Total params: 3,281,798
Trainable params: 3,281,798
Non-trainable params: 0
```
Compilaremos y entrenaremos el modelo bajo las mismas directrices del resto de ocasiones.
```python
model_convolutional.compile(optimizer = "adam", loss = "categorical_crossentropy", metrics = ["accuracy"])
history_convolutional = model_convolutional.fit(
train_generator,
epochs = 20,
validation_data = validation_generator
)
Epoch 20/20
215/215 [==============================] - 46s 214ms/step - loss: 0.0312 - accuracy: 0.9972 - val_loss: 0.9134 - val_accuracy: 0.8575
```
Podemos notar una importante reducción en el overfitting (aunque aún está vigente) junto a una mejora general del rendimiento de la red tanto en entrenamiento como en validación.
Recomendaciones finales
Es importante recalcar que una red más compleja (con más neuronas y más capas) no siempre dará un mejor resultado, todo lo contrario, el objetivo de modelar una red será el de generarla lo más sencilla posible, esto mejorará el tiempo de entrenamiento y evitará el overfitting.
Otra recomendación es que el uso de redes neuronales no siempre es la mejor solución, existe un gran abanico de algoritmos de machine learning más sencillos a nivel matemático que pueden serte de mayor utilidad dado que las redes neuronales requieren de altas cantidades de datos como materia prima y potenciales recursos de cómputo para ser entrenadas.
Finalmente, debes tener en cuenta la técnica de transfer learning que nos permite utilizar modelos ya entrenados para solucionar nuestros propios problemas, con un par de épocas extras podremos moldearlos a nuestros datos específicos y obtendremos resultados óptimos con poco gasto de recursos.
Contribución creada por Sebastián Franco Gómez.
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?