La prueba de unidad es tu amiga
Hay un dicho entre los escritores que dice: "Toda escritura es reescritura", es decir, la mayor parte de la escritura está revisando. Para los programadores (o al menos científicos de datos), la expresión podría reformularse como "Toda la codificación es depuración".
Cada vez que está escribiendo código, debe verificar que funcione según lo previsto. El mejor método que he encontrado para verificar la corrección es dividir el código en segmentos pequeños y verificar que cada segmento funcione. Esto se puede hacer comparando la salida del segmento con lo que sabe que es la respuesta correcta. Esto se llama prueba unitaria . Escribir buenas pruebas unitarias es una pieza clave para convertirse en un buen estadístico / científico de datos / experto en aprendizaje automático / profesional de redes neuronales. Simplemente no hay sustituto.
¡Debe verificar que su código esté libre de errores antes de poder ajustar el rendimiento de la red! De lo contrario, también podría reorganizar las tumbonas en el RMS Titanic .
Hay dos características de las redes neuronales que hacen que la verificación sea aún más importante que para otros tipos de aprendizaje automático o modelos estadísticos.
Las redes neuronales no son algoritmos "listos para usar" en la forma en que lo son los bosques aleatorios o la regresión logística. Incluso para redes simples de alimentación, la responsabilidad recae principalmente en el usuario para tomar numerosas decisiones sobre cómo se configura, conecta, inicializa y optimiza la red. Esto significa escribir código, y escribir código significa depurar.
Incluso cuando se ejecuta un código de red neuronal sin generar una excepción, ¡la red puede tener errores! Estos errores pueden incluso ser del tipo insidioso para el que se entrenará la red, pero se atascan en una solución subóptima, o la red resultante no tiene la arquitectura deseada. ( Este es un ejemplo de la diferencia entre un error sintáctico y semántico ).
Esta publicación mediana , " Cómo probar el código de aprendizaje automático de la unidad ", de Chase Roberts, analiza las pruebas unitarias para modelos de aprendizaje automático con más detalle. Tomé prestado este ejemplo de código con errores del artículo:
def make_convnet(input_image):
net = slim.conv2d(input_image, 32, [11, 11], scope="conv1_11x11")
net = slim.conv2d(input_image, 64, [5, 5], scope="conv2_5x5")
net = slim.max_pool2d(net, [4, 4], stride=4, scope='pool1')
net = slim.conv2d(input_image, 64, [5, 5], scope="conv3_5x5")
net = slim.conv2d(input_image, 128, [3, 3], scope="conv4_3x3")
net = slim.max_pool2d(net, [2, 2], scope='pool2')
net = slim.conv2d(input_image, 128, [3, 3], scope="conv5_3x3")
net = slim.max_pool2d(net, [2, 2], scope='pool3')
net = slim.conv2d(input_image, 32, [1, 1], scope="conv6_1x1")
return net
¿Ves el error? Muchas de las diferentes operaciones no se utilizan realmente porque los resultados anteriores se sobrescriben con nuevas variables. El uso de este bloque de código en una red seguirá entrenando y los pesos se actualizarán y la pérdida podría incluso disminuir, pero el código definitivamente no está haciendo lo que se pretendía. (El autor también es inconsistente sobre el uso de comillas simples o dobles, pero eso es puramente estilístico).
Los errores de programación más comunes relacionados con las redes neuronales son
- Las variables se crean pero nunca se usan (generalmente debido a errores de copiar y pegar);
- Las expresiones para las actualizaciones de gradiente son incorrectas;
- Las actualizaciones de peso no se aplican;
- Las funciones de pérdida no se miden en la escala correcta (por ejemplo, la pérdida de entropía cruzada se puede expresar en términos de probabilidad o logits)
- La pérdida no es apropiada para la tarea (por ejemplo, usar la pérdida categórica de entropía cruzada para una tarea de regresión).
Rastrear antes de caminar; Camina antes de correr
Las redes neuronales anchas y profundas, y las redes neuronales con cableado exótico, son lo más importante en este momento en el aprendizaje automático. Pero estas redes no surgieron plenamente formadas; sus diseñadores construyeron para ellos desde unidades más pequeñas. Primero, construya una red pequeña con una sola capa oculta y verifique que funcione correctamente. A continuación, agregue de forma incremental la complejidad del modelo adicional y verifique que cada uno de ellos también funcione.
Muy pocas neuronas en una capa pueden restringir la representación que la red aprende, causando una falta de adaptación. Demasiadas neuronas pueden causar un sobreajuste porque la red "memorizará" los datos de entrenamiento.
Incluso si se puede demostrar que no es, matemáticamente, sólo un pequeño número de neuronas necesarias para modelar un problema, es a menudo el caso de que tener "un poco más" neuronas hace que sea más fácil para el optimizador para encontrar una configuración de "bueno". (Pero no creo que nadie entienda completamente por qué este es el caso.) Proporciono un ejemplo de esto en el contexto del problema XOR aquí: ¿No son necesarias mis iteraciones para entrenar NN para XOR con MSE <0.001 demasiado alto? .
Elegir el número de capas ocultas permite a la red aprender una abstracción de los datos sin procesar. El aprendizaje profundo está de moda en estos días, y las redes con una gran cantidad de capas han mostrado resultados impresionantes. Pero agregar demasiadas capas ocultas puede hacer que se sobreajuste el riesgo o dificultar la optimización de la red.
Elegir un cableado de red inteligente puede hacer mucho del trabajo por usted. ¿Su fuente de datos es susceptible de arquitecturas de red especializadas? Las redes neuronales convolucionales pueden lograr resultados impresionantes en fuentes de datos "estructurados", imágenes o datos de audio. Las redes neuronales recurrentes pueden funcionar bien en tipos de datos secuenciales, como el lenguaje natural o los datos de series temporales. Las conexiones residuales pueden mejorar las redes de alimentación profunda.
El entrenamiento de redes neuronales es como abrir cerraduras
Para lograr resultados de vanguardia, o incluso simplemente buenos, debe haber configurado todas las piezas para que funcionen bien juntas . Establecer una configuración de red neuronal que realmente aprenda es muy parecido a abrir una cerradura: todas las piezas deben alinearse correctamente. Así como no es suficiente tener un solo vaso en el lugar correcto, tampoco es suficiente tener solo la arquitectura, o solo el optimizador, configurados correctamente.
Ajustar las opciones de configuración no es tan simple como decir que un tipo de opción de configuración (p. Ej., Tasa de aprendizaje) es más o menos importante que otra (p. Ej., Número de unidades), ya que todas estas opciones interactúan con todas las demás opciones, por lo que uno La elección puede funcionar bien en combinación con otra elección realizada en otro lugar .
Esta es una lista no exhaustiva de las opciones de configuración que no son también opciones de regularización u opciones de optimización numérica.
Todos estos temas son áreas activas de investigación.
La inicialización de la red a menudo se pasa por alto como fuente de errores de red neuronal. La inicialización en un intervalo demasiado grande puede establecer pesos iniciales demasiado grandes, lo que significa que las neuronas individuales tienen una influencia descomunal sobre el comportamiento de la red.
La diferencia clave entre una red neuronal y un modelo de regresión es que una red neuronal es una composición de muchas funciones no lineales, llamadas funciones de activación . (Ver: ¿Cuál es la diferencia esencial entre la red neuronal y la regresión lineal )
Los resultados clásicos de la red neuronal se centraron en las funciones de activación sigmoidea (funciones logísticas o ). Un resultado reciente ha encontrado que las unidades ReLU (o similares) tienden a funcionar mejor porque tienen gradientes más pronunciados, por lo que las actualizaciones se pueden aplicar rápidamente. (Ver: ¿Por qué usamos ReLU en redes neuronales y cómo lo usamos? ) Una advertencia sobre ReLUs es el fenómeno de "neurona muerta", que puede obstaculizar el aprendizaje; relus con fugas y variantes similares evitan este problema. Vertanh
Hay varias otras opciones. Ver: lista completa de funciones de activación en redes neuronales con pros / contras
Las conexiones residuales son un desarrollo ordenado que puede facilitar el entrenamiento de redes neuronales. "Aprendizaje residual profundo para el reconocimiento de imágenes"
Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun En: CVPR. (2016) Además, cambiar el orden de las operaciones dentro del bloque residual puede mejorar aún más la red resultante. " Mapeos de identidad en redes residuales profundas " por Kaiming He, Xiangyu Zhang, Shaoqing Ren y Jian Sun.
La optimización no convexa es difícil
La función objetivo de una red neuronal es solo convexa cuando no hay unidades ocultas, todas las activaciones son lineales y la matriz de diseño es de rango completo, porque esta configuración es idénticamente un problema de regresión ordinario.
En todos los demás casos, el problema de optimización es no convexo y la optimización no convexa es difícil. Los desafíos de entrenar redes neuronales son bien conocidos (ver: ¿Por qué es difícil entrenar redes neuronales profundas? ). Además, las redes neuronales tienen una gran cantidad de parámetros, lo que nos restringe a métodos exclusivamente de primer orden (ver: ¿Por qué el método de Newton no se usa ampliamente en el aprendizaje automático? ). Esta es un área de investigación muy activa.
Establecer una tasa de aprendizaje demasiado grande hará que la optimización difiera, ya que saltará de un lado del "cañón" al otro. Establecer esto demasiado pequeño evitará que realices un progreso real y posiblemente permita que el ruido inherente en SGD supere tus estimaciones de gradiente.
El recorte de degradado reescala la norma del degradado si está por encima de algún umbral. Solía pensar que este era un parámetro de establecer y olvidar, generalmente en 1.0, pero descubrí que podía hacer un modelo de lenguaje LSTM dramáticamente mejor al configurarlo en 0.25. No sé por qué es eso.
La programación de la tasa de aprendizaje puede disminuir la tasa de aprendizaje en el transcurso de la capacitación. En mi experiencia, tratar de usar la programación es muy similar a la expresión regular : reemplaza un problema ("¿Cómo aprendo a continuar después de cierta época?") Con dos problemas ("¿Cómo aprendo a continuar después de cierta época? ? "y" ¿Cómo elijo un buen horario? "). Otras personas insisten en que la programación es esencial. Te dejaré decidir.
Elegir un buen tamaño de minibatch puede influir indirectamente en el proceso de aprendizaje, ya que un mini lote más grande tenderá a tener una variación menor ( ley de los números grandes ) que un mini lote más pequeño. Desea que el mini lote sea lo suficientemente grande como para ser informativo sobre la dirección del gradiente, pero lo suficientemente pequeño como para que SGD pueda regularizar su red.
Hay una serie de variantes en el descenso de gradiente estocástico que utilizan el impulso, las tasas de aprendizaje adaptativo, las actualizaciones de Nesterov, etc. para mejorar el SGD de vainilla. Diseñar un mejor optimizador es en gran medida un área activa de investigación. Algunos ejemplos:
Cuando salió por primera vez, el optimizador Adam generó mucho interés. Pero algunas investigaciones recientes han encontrado que SGD con impulso puede superar los métodos de gradiente adaptativo para redes neuronales. " El valor marginal de los métodos de gradiente adaptativo en el aprendizaje automático " por Ashia C. Wilson, Rebecca Roelofs, Mitchell Stern, Nathan Srebro, Benjamin Recht
Pero, por otro lado, este artículo muy reciente propone un nuevo optimizador de tasa de aprendizaje adaptativo que supuestamente cierra la brecha entre los métodos de tasa de adaptación y el SGD con impulso. " Cerrar la brecha de generalización de los métodos de gradiente adaptativos en el entrenamiento de redes neuronales profundas " por Jinghui Chen, Quanquan Gu
Se ha observado que los métodos de gradiente adaptativo, que adoptan información histórica de gradiente para ajustar automáticamente la tasa de aprendizaje, generalizan peor que el descenso de gradiente estocástico (SGD) con impulso en el entrenamiento de redes neuronales profundas. Esto deja un problema abierto sobre cómo cerrar la brecha de generalización de los métodos de gradiente adaptativo. En este trabajo, mostramos que los métodos de gradiente adaptativo como Adam, Amsgrad, a veces están "sobre adaptados". Diseñamos un nuevo algoritmo, llamado Método de estimación de momento parcialmente adaptativo (Padam), que unifica el Adam / Amsgrad con SGD para lograr lo mejor de ambos mundos. Los experimentos en puntos de referencia estándar muestran que Padam puede mantener una tasa de convergencia rápida como Adam / Amsgrad mientras generaliza y SGD en el entrenamiento de redes neuronales profundas.
Normalización
La escala de los datos puede marcar una gran diferencia en el entrenamiento.
Antes de presentar los datos a una red neuronal, la estandarización de los datos para tener 0 media y varianza de la unidad, o estar en un intervalo pequeño como puede mejorar el entrenamiento. Esto equivale a un preacondicionamiento y elimina el efecto que tiene una elección en unidades sobre los pesos de la red. Por ejemplo, longitud en milímetros y longitud en kilómetros representan el mismo concepto, pero están en diferentes escalas. Los detalles exactos de cómo estandarizar los datos dependen de cómo se vean sus datos.[ - 0.5 , 0.5 ]
La normalización de la capa puede mejorar el entrenamiento de la red al mantener una desviación estándar y media en ejecución para las activaciones de las neuronas. No se comprende bien por qué esto ayuda a la capacitación y sigue siendo un área activa de investigación.
- " Comprender la normalización de lotes " por Johan Bjorck, Carla Gomes, Bart Selman
- " Hacia una comprensión teórica de la normalización de lotes " por Jonas Kohler, Hadi Daneshmand, Aurelien Lucchi, Ming Zhou, Klaus Neymeyr, Thomas Hofmann
- " ¿Cómo ayuda la normalización por lotes a la optimización? (No, no se trata del cambio covariable interno) " por Shibani Santurkar, Dimitris Tsipras, Andrew Ilyas, Aleksander Madry
Regularización
Elegir y ajustar la regularización de la red es una parte clave de la construcción de un modelo que se generalice bien (es decir, un modelo que no se ajuste demasiado a los datos de entrenamiento). Sin embargo, en el momento en que su red está luchando para disminuir la pérdida de datos de capacitación, cuando la red no está aprendiendo, la regularización puede ocultar cuál es el problema.
Cuando mi red no aprende, apago toda la regularización y verifico que la red no regularizada funciona correctamente. Luego agrego cada pieza de regularización y verifico que cada una de ellas funcione en el camino.
Esta táctica puede determinar dónde se puede establecer mal cierta regularización. Algunos ejemplos son
L2 regularización (también conocida como disminución de peso) o la regularización se establece demasiado grande, por lo que los pesos no pueden moverse.L1
Dos partes de la regularización están en conflicto. Por ejemplo, se observa ampliamente que la normalización de capa y el abandono son difíciles de usar juntos. Dado que, por sí solo, es muy útil, comprender cómo usar ambos es un área activa de investigación.
Mantenga un libro de registro de experimentos
Cuando configuro una red neuronal, no codifico ninguna configuración de parámetros. En cambio, lo hago en un archivo de configuración (por ejemplo, JSON) que se lee y se utiliza para completar los detalles de configuración de la red en tiempo de ejecución. Mantengo todos estos archivos de configuración. Si hago alguna modificación de parámetros, hago un nuevo archivo de configuración. Finalmente, adjunto como comentarios todas las pérdidas por época para capacitación y validación.
La razón por la que estoy tan obsesionado con retener los resultados antiguos es que esto hace que sea muy fácil regresar y revisar experimentos anteriores. También protege contra la repetición errónea del mismo experimento sin salida. Psicológicamente, también te permite mirar hacia atrás y observar "Bueno, el proyecto podría no estar donde quiero que esté hoy, pero estoy progresando en comparación con donde estaba hace semanas".k
Como ejemplo, quería aprender sobre los modelos de lenguaje LSTM, así que decidí hacer un bot de Twitter que escriba nuevos tweets en respuesta a otros usuarios de Twitter. Trabajé en esto en mi tiempo libre, entre la escuela de posgrado y mi trabajo. Me llevó alrededor de un año, e iteré más de 150 modelos diferentes antes de llegar a un modelo que hizo lo que quería: generar un nuevo texto en inglés que (más o menos) tiene sentido. (Un punto clave, y parte de la razón por la que tomó tantos intentos, es que no fue suficiente simplemente obtener una baja pérdida fuera de la muestra, ya que los primeros modelos de baja pérdida habían logrado memorizar los datos de entrenamiento, por lo tanto, solo estaba reproduciendo bloques de texto relacionados textualmente en respuesta a las indicaciones: se necesitaron algunos ajustes para que el modelo sea más espontáneo y aún tenga poca pérdida).