Estoy entrenando una red neuronal (los detalles no son importantes) donde los datos objetivo son un vector de ángulos (entre 0 y 2 * pi). Estoy buscando consejos sobre cómo codificar estos datos. Esto es lo que estoy intentando actualmente (con éxito limitado):
1) Codificación 1-de-C: pongo los ángulos posibles configurados en aproximadamente 1000 ángulos discretos y luego indico un ángulo particular poniendo un 1 en el índice relevante. El problema con esto es que la red simplemente aprende a generar todos los 0 (ya que esto es casi exactamente correcto).
2) Escalado simple: escalé el rango de salida de la red ([0,1]) a [0,2 * pi]. El problema aquí es que los ángulos tienen naturalmente una topología circular (es decir, 0.0001 y 2 * pi están realmente uno al lado del otro). Con este tipo de codificación, esa información se pierde.
¡Cualquier sugerencia sera apreciada!
fuente
Respuestas:
Introducción
Encuentro esta pregunta realmente interesante, supongo que alguien ha publicado un documento sobre ella, pero es mi día libre, así que no quiero ir a buscar referencias.
Entonces podríamos considerarlo como una representación / codificación de la salida, lo que hago en esta respuesta. Sigo pensando que hay una mejor manera, donde puedes usar una función de pérdida ligeramente diferente. (Quizás la suma de las diferencias al cuadrado, utilizando el módulo de resta 2 ).π
Pero en adelante con la respuesta real.
Método
Propongo que un ángulo se represente como un par de valores, su seno y su coseno.θ
Entonces, la función de codificación es: y la función de decodificación es: Para arctan2 siendo las tangentes inversas, preservando la dirección en todos los cuadrantes)θ ↦ ( pecado( θ ) , cos( θ ) )
( y1, y2) ↦ arctan2 ( y1, y2)
En teoría, podría trabajar de manera equivalente directamente con los ángulos si su herramienta utiliza el soporte
atan2
como una función de capa (tomando exactamente 2 entradas y produciendo 1 salida). TensorFlow hace esto ahora y admite el descenso de gradiente en él , aunque no está destinado para este uso. Investigué el usoout = atan2(sigmoid(ylogit), sigmoid(xlogit))
con una función de pérdidamin((pred - out)^2, (pred - out - 2pi)^2)
. Descubrí que entrenaba mucho peor que usarouts = tanh(ylogit), outc = tanh(xlogit))
con una función de pérdida0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2
. Lo cual creo que puede atribuirse a que el gradiente es discontinuo paraatan2
Mi prueba aquí lo ejecuta como una función de preprocesamiento
Para evaluar esto, definí una tarea:
Implementé una función para generar aleatoriamente estas imágenes, con líneas en ángulos aleatorios (NB: las versiones anteriores de esta publicación usaban pendientes aleatorias, en lugar de ángulos aleatorios. Gracias a @Ari Herman por señalarlo. Ahora está arreglado). Construí varias redes neuronales para evaluar su desempeño en la tarea. Los detalles completos de la implementación se encuentran en este cuaderno Jupyter . El código está todo en Julia , y uso la biblioteca de red neuronal Mocha .
A modo de comparación, lo presento contra los métodos alternativos de escalado a 0,1. y para poner en 500 contenedores y usar softmax de etiqueta blanda. No estoy particularmente contento con el último, y siento que necesito modificarlo. Es por eso que, a diferencia de los otros, solo lo pruebo por 1,000 iteraciones, frente a los otros dos que se ejecutaron por 1,000 y por 10,000
Configuración experimental
Las imágenes eran píxeles, con la línea en el centro y hacia el borde. No había ruido, etc. en la imagen, solo una línea "negra", sobre un fondo blanco.101 × 101
Para cada recorrido, se generaron 1,000 entrenamientos y 1,000 imágenes de prueba al azar.
La red de evaluación tenía una sola capa oculta de ancho 500. Se usaron neuronas sigmoideas en la capa oculta.
Fue entrenado por Stochastic Gradient Decent, con una tasa de aprendizaje fija de 0.01 y un impulso fijo de 0.9.
No se usó regularización o abandono. Tampoco hubo ningún tipo de convolución, etc. Una red simple, que espero sugiera que estos resultados se generalizarán
Es muy fácil modificar estos parámetros en el código de prueba , y animo a las personas a que lo hagan. (y busca errores en la prueba).
Resultados
Mis resultados son los siguientes:
Cuando me refiero al error, este es el valor absoluto de la diferencia entre el ángulo de salida de la red neuronal y el ángulo verdadero. Entonces, el error medio (por ejemplo) es el promedio sobre los 1,000 casos de prueba de esta diferencia, etc. No estoy seguro de que no deba volver a escalarlo haciendo un error de decir ser igual a un error de ). π7 π4 4 π4 4
También presento la precisión en varios niveles de granularidad. La precisión es la parte de los casos de prueba que se corrigió. Entonces
accuracy_to_point01
significa que se contó como correcto si la salida estaba dentro de 0.01 del ángulo verdadero. Ninguna de las representaciones obtuvo resultados perfectos, pero eso no es sorprendente dado el funcionamiento de las matemáticas de coma flotante.Si echas un vistazo al historial de esta publicación, verás que los resultados tienen un poco de ruido, ligeramente diferente cada vez que lo vuelvo a ejecutar. Pero el orden general y la escala de valores siguen siendo los mismos; lo que nos permite sacar algunas conclusiones.
Discusión
Binning con softmax es, con mucho, el peor, ya que dije que no estoy seguro de no haber estropeado algo en la implementación. Sin embargo, funciona marginalmente por encima de la tasa de conjetura. si solo estuviera adivinando, obtendríamos un error medio deπ
La codificación sin / cos funciona significativamente mejor que la codificación 0-1 escalada. La mejora es en la medida en que con 1,000 iteraciones de entrenamiento, sin / cos se está desempeñando aproximadamente 3 veces mejor en la mayoría de las métricas que la escala en 10,000 iteraciones.
Creo que, en parte, esto está relacionado con la mejora de la generalización, ya que ambos obtuvieron un error cuadrático medio bastante similar en el conjunto de entrenamiento, al menos una vez que se ejecutaron 10,000 iteraciones.
Ciertamente, existe un límite superior para el mejor rendimiento posible en esta tarea, dado que el ángulo puede ser más o menos cualquier número real, pero no todos esos ángeles producen líneas diferentes con una resolución de píxeles. Entonces, dado que, por ejemplo, los ángulos 45.0 y 45.0000001 están vinculados a la misma imagen con esa resolución, ningún método obtendrá ambos perfectamente correctos.101 × 101
También parece probable que en una escala absoluta para ir más allá de este rendimiento, se necesite una mejor red neuronal. En lugar del muy simple descrito anteriormente en la configuración experimental.
Conclusión.
Parece que la representación sin / cos es, con mucho, la mejor de las representaciones que investigué aquí. Esto tiene sentido, ya que tiene un valor uniforme a medida que te mueves alrededor del círculo. También me gusta que lo inverso se pueda hacer con arctan2 , que es elegante.
Creo que la tarea presentada es suficiente en su capacidad para presentar un desafío razonable para la red. Aunque supongo que realmente está aprendiendo a hacer un ajuste de curva para así que tal vez sea demasiado fácil. Y quizás peor, puede estar favoreciendo la representación pareada. No creo que sea así, pero se está haciendo tarde aquí, así que podría haber perdido algo. Te invito nuevamente a que revises mi código . Sugerir mejoras o tareas alternativas.F( x ) = y1y2X
fuente
tan(angle)
vaya tan bien, dado que el bronceado no está definido para todos los ángulos (por ejemplo, ). Lo volveré a ejecutar con ángulos generados aleatoriamente y editaré las publicaciones.Aquí hay otra implementación de Python que compara la codificación propuesta de Lyndon White con un enfoque agrupado. El siguiente código produjo el siguiente resultado:
Como puede ver, mientras que el enfoque agrupado se desempeña admirablemente en esta tarea de juguete, la codificación funciona mejor en todas las configuraciones de entrenamiento, a veces por un margen considerable. Sospecho que la tarea específica se hizo más compleja, los beneficios del uso de Lyndon blanca 's representación sería más pronunciada.( sin ( θ ) , cos ( θ ) )(sin(θ),cos(θ)) (sin(θ),cos(θ))
fuente
Aquí está mi versión de Python de tu experimento. Mantuve muchos de los detalles de su implementación igual, en particular uso el mismo tamaño de imagen, tamaños de capa de red, tasa de aprendizaje, impulso y métricas de éxito.
Cada red probada tiene una capa oculta (tamaño = 500) con neuronas logísticas. Las neuronas de salida son lineales o softmax como se señaló. Usé 1,000 imágenes de entrenamiento y 1,000 imágenes de prueba que se generaron de forma independiente y aleatoria (por lo que puede haber repeticiones). El entrenamiento consistió en 50 iteraciones a través del conjunto de entrenamiento.
Pude obtener una precisión bastante buena usando binning y codificación "gaussiana" (un nombre que inventé; similar a binning excepto que el vector de salida de destino tiene la forma exp (-pi * ([1,2,3, ... , 500] - idx) ** 2) donde idx es el índice correspondiente al ángulo correcto). El código está abajo; Aquí están mis resultados:
Error de prueba para codificación (cos, sin):
1,000 imágenes de entrenamiento, 1,000 imágenes de prueba, 50 iteraciones, salida lineal
Media: 0.0911558142071
Mediana: 0.0429723541743
Mínimo: 2.77769843793e-06
Máximo: 6.2608513539
Precisión a 0.1: 85.2%
Precisión a 0.01: 11.6%
Precisión hasta 0.001: 1.0%
Error de prueba para la codificación [-1,1]:
1,000 imágenes de entrenamiento, 1,000 imágenes de prueba, 50 iteraciones, salida lineal
Media: 0.234181700523
Mediana: 0.17460197307
Mínimo: 0.000473665840258
Máximo: 6.00637777237
Precisión a 0.1: 29.9%
Precisión a 0.01: 3.3%
Precisión hasta 0.001: 0.1%
Error de prueba para codificación 1 de 500:
1,000 imágenes de entrenamiento, 1,000 imágenes de prueba, 50 iteraciones, salida softmax
Media: 0.0298767021922
Mediana: 0.00388858079174
Mínimo: 4.08712407829e-06
Máximo: 6.2784479965
Precisión a 0.1: 99.6%
Precisión a 0.01: 88.9%
Precisión hasta 0.001: 13.5%
Error de prueba para codificación gaussiana:
1,000 imágenes de entrenamiento, 1,000 imágenes de prueba, 50 iteraciones, salida softmax
No puedo entender por qué nuestros resultados parecen estar en contradicción entre sí, pero parece que vale la pena seguir investigando.
fuente
Otra forma de codificar el ángulo es como un conjunto de dos valores:
Esto tendría el problema similar a arctan2 en que el gradiente no está definido en theta = 0. No tengo tiempo para entrenar una red y compararla con las otras codificaciones, pero en este artículo la técnica parecía razonablemente exitosa.
fuente