J'entraîne un réseau neuronal (détails non importants) où les données cibles sont un vecteur d'angles (entre 0 et 2 * pi). Je recherche des conseils sur la façon de coder ces données. Voici ce que j'essaie actuellement (avec un succès limité):
1) Encodage 1-of-C: je regroupe les angles possibles configurés dans environ 1000 angles discrets, puis indique un angle particulier en mettant un 1 à l'index approprié. Le problème avec cela, c'est que le réseau apprend simplement à sortir tous les 0 (car c'est presque exactement correct).
2) Mise à l'échelle simple: j'ai mis à l'échelle la plage de sortie des réseaux ([0,1]) à [0,2 * pi]. Le problème ici est que les angles ont naturellement une topologie circulaire (c'est-à-dire que 0,0001 et 2 * pi sont en fait l'un à côté de l'autre). Avec ce type d'encodage, ces informations sont perdues.
Toute suggestion serait appréciée!
la source
Réponses:
introduction
Je trouve cette question vraiment intéressante, je suppose que quelqu'un a publié un document à ce sujet, mais c'est mon jour de congé, donc je ne veux pas aller à la recherche de références.
Nous pourrions donc le considérer comme une représentation / encodage de la sortie, ce que je fais dans cette réponse. Je continue de penser qu'il existe une meilleure façon, où vous pouvez simplement utiliser une fonction de perte légèrement différente. (Peut-être somme des différences au carré, en utilisant la soustraction modulo 2 ).π
Mais en avant avec la réponse réelle.
Méthode
Je propose qu'un angle soit représenté par une paire de valeurs, son sinus et son cosinus.θ
La fonction d'encodage est donc: et la fonction de décodage est:θ ↦ ( péché( θ ) , cos( θ ) ) ( y1, y2) ↦ arctan2 ( y1, y2)
Pourarctan2étant les tangentes inverses, préservant la direction dans tous les quadrants)
Vous pourriez, en théorie, travailler de manière équivalente directement avec les angles si votre outil utilise pris
atan2
en charge comme fonction de couche (en prenant exactement 2 entrées et en produisant 1 sortie). TensorFlow le fait maintenant et prend en charge la descente de gradient dessus , bien qu'il ne soit pas destiné à cette utilisation. J'ai étudié l'utilisationout = atan2(sigmoid(ylogit), sigmoid(xlogit))
d'une fonction de pertemin((pred - out)^2, (pred - out - 2pi)^2)
. J'ai trouvé qu'il s'entraînait bien pire que l'utilisationouts = tanh(ylogit), outc = tanh(xlogit))
avec une fonction de perte0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2
. Ce qui, je pense, peut être attribué au gradient étant discontinu pouratan2
Mes tests ici l'exécutent comme une fonction de prétraitement
Pour évaluer cela, j'ai défini une tâche:
J'ai implémenté une fonction générant aléatoirement ces images, avec des lignes à angles aléatoires (NB: les versions antérieures de ce post utilisaient des pentes aléatoires, plutôt que des angles aléatoires. Merci à @Ari Herman de le signaler. Il est maintenant corrigé). J'ai construit plusieurs réseaux de neurones pour y évaluer les performances de la tâche. Les détails complets de l'implémentation se trouvent dans ce bloc-notes Jupyter . Le code est entièrement dans Julia , et j'utilise la bibliothèque du réseau de neurones Mocha .
À titre de comparaison, je le présente par rapport aux méthodes alternatives de mise à l'échelle à 0,1. et mettre dans 500 bacs et utiliser softmax soft-label. Je ne suis pas particulièrement satisfait de ce dernier et je pense que je dois le modifier. C'est pourquoi, contrairement aux autres, je ne le teste que pour 1000 itérations, contre les deux autres qui ont été exécutées pour 1000 et pour 10000
Montage expérimental
Pour chaque piste, 1 000 formations et 1 000 images de test ont été générées de manière aléatoire.
Le réseau d'évaluation avait une seule couche cachée de largeur 500. Des neurones sigmoïdes ont été utilisés dans la couche cachée.
Il a été formé par Stochastic Gradient Decent, avec un taux d'apprentissage fixe de 0,01 et un moment fixe de 0,9.
Aucune régularisation ou abandon n'a été utilisé. Il n'y avait pas non plus de convolution, etc. Un réseau simple, qui j'espère suggère que ces résultats généraliseront
Il est très facile de modifier ces paramètres dans le code de test , et j'encourage les gens à le faire. (et recherchez les bogues dans le test).
Résultats
Mes résultats sont les suivants:
Je présente également la précision à différents niveaux de granularité. La précision étant la partie des cas de test, elle a été corrigée.
accuracy_to_point01
Cela signifie donc qu'il a été considéré comme correct si la sortie était à moins de 0,01 de l'angle réel. Aucune des représentations n'a obtenu de résultats parfaits, mais ce n'est pas du tout surprenant étant donné le fonctionnement des mathématiques en virgule flottante.Si vous jetez un œil à l'historique de ce post, vous verrez que les résultats ont un peu de bruit, légèrement différents à chaque fois que je le relance. Mais l'ordre général et l'échelle des valeurs restent les mêmes; nous permettant ainsi de tirer quelques conclusions.
Discussion
Le codage sin / cos fonctionne bien mieux que le codage 0-1 mis à l'échelle. L'amélioration est dans la mesure où à 1 000 itérations d'entraînement, sin / cos fonctionne environ 3 fois mieux sur la plupart des mesures que la mise à l'échelle est à 10 000 itérations.
Je pense que cela est en partie lié à l'amélioration de la généralisation, car les deux obtenaient une erreur quadratique moyenne assez similaire sur l'ensemble d'entraînement, au moins une fois que 10 000 itérations ont été exécutées.
Il semble également probable qu'à une échelle absolue pour aller au-delà de cette performance, un meilleur réseau neuronal soit nécessaire. Plutôt que celui très simple décrit ci-dessus dans la configuration expérimentale.
Conclusion.
Il semble que la représentation sin / cos soit de loin la meilleure des représentations que j'ai étudiées ici. Cela a du sens, car il a une valeur lisse lorsque vous vous déplacez autour du cercle. J'aime aussi que l'inverse se fasse avec arctan2 , qui est élégant.
la source
tan(angle)
Voici une autre implémentation de Python comparant le codage proposé par Lyndon White à une approche groupée. Le code ci-dessous a produit la sortie suivante:
la source
Voici ma version Python de votre expérience. J'ai conservé la plupart des détails de votre implémentation, en particulier j'utilise la même taille d'image, les tailles de couche réseau, le taux d'apprentissage, l'élan et les mesures de réussite.
Chaque réseau testé a une couche cachée (taille = 500) avec des neurones logistiques. Les neurones de sortie sont soit linéaires soit softmax comme indiqué. J'ai utilisé 1 000 images d'entraînement et 1 000 images de test qui ont été générées de manière indépendante et aléatoire (il peut donc y avoir des répétitions). La formation consistait en 50 itérations à travers l'ensemble de formation.
J'ai pu obtenir une assez bonne précision en utilisant le binning et le codage "gaussien" (un nom que j'ai inventé; similaire au binning sauf que le vecteur de sortie cible a la forme exp (-pi * ([1,2,3, ... , 500] - idx) ** 2) où idx est l'indice correspondant à l'angle correct). Le code est ci-dessous; voici mes résultats:
Erreur de test pour le codage (cos, sin):
1 000 images d'entraînement, 1 000 images de test, 50 itérations, sortie linéaire
Moyenne: 0,0911558142071
Médiane: 0,0429723541743
Minimum: 2.77769843793e-06
Maximum: 6.2608513539
Précision à 0,1: 85,2%
Précision à 0,01: 11,6%
Précision à 0,001: 1,0%
Erreur de test pour l'encodage [-1,1]:
1 000 images d'entraînement, 1 000 images de test, 50 itérations, sortie linéaire
Moyenne: 0,234181700523
Médiane: 0,17460197307
Minimum: 0,000473665840258
Maximum: 6.00637777237
Précision à 0,1: 29,9%
Précision à 0,01: 3,3%
Précision à 0,001: 0,1%
Erreur de test pour l'encodage 1 sur 500:
1000 images d'entraînement, 1000 images de test, 50 itérations, sortie softmax
Moyenne: 0,0298767021922
Médiane: 0,00388858079174
Minimum: 4.08712407829e-06
Maximum: 6.2784479965
Précision à 0,1: 99,6%
Précision à 0,01: 88,9%
Précision à 0,001: 13,5%
Erreur de test pour le codage gaussien:
1000 images d'entraînement, 1000 images de test, 50 itérations, sortie softmax
Je ne peux pas comprendre pourquoi nos résultats semblent être en contradiction les uns avec les autres, mais cela semble mériter une enquête plus approfondie.
la source
Une autre façon de coder l'angle est un ensemble de deux valeurs:
Cela aurait le même problème avec arctan2 en ce que le gradient n'est pas défini à thêta = 0. Je n'ai pas le temps de former un réseau et de comparer avec les autres encodages mais dans cet article, la technique semblait raisonnablement réussie.
la source