Régression de paramétrage de l'angle de rotation

15

Disons que j'ai une image descendante d'une flèche et que je veux prédire l'angle de cette flèche. Ce serait entre et degrés, ou entre et . Le problème est que cette cible est circulaire, et degrés sont exactement les mêmes, ce qui est une invariance que j'aimerais incorporer dans ma cible, ce qui devrait aider à généraliser de manière significative (c'est mon hypothèse). Le problème est que je ne vois pas une manière propre de résoudre ce problème, y a-t-il des documents qui tentent de résoudre ce problème (ou des similaires)? J'ai quelques idées avec leurs inconvénients potentiels:360 0 2 π 0 360036002π0360

  • Utilisez une activation sigmoïde ou tanh, mettez-la à l'échelle ( et incorporez la propriété circulaire dans la fonction de perte. Je pense que cela échouera assez fort, car si c'est à la frontière (pire prédiction), seul un tout petit peu de bruit poussera les poids à aller dans un sens ou dans l'autre. De plus, les valeurs plus proches de la frontière de et seront plus difficiles à atteindre car la valeur absolue de pré-activation devra être proche de l'infini.0 2 π0,2π)02π

  • Régression à deux valeurs, une valeur et et calculez la perte en fonction de l'angle de ces deux valeurs. Je pense que celui-ci a plus de potentiel mais la norme de ce vecteur est illimitée, ce qui pourrait conduire à une instabilité numérique et entraîner des explosions ou aller à 0 pendant l'entraînement. Cela pourrait potentiellement être résolu en utilisant un régularisateur étrange pour éviter que cette norme ne s'éloigne trop de 1.yXy

D'autres options seraient de faire quelque chose avec les fonctions sinus et cosinus mais je pense que le fait que plusieurs préactivations soient mappées sur la même sortie rendra également l'optimisation et les généralisations très difficiles.

Jan van der Vegt
la source
Honnêtement, je pense qu'il sera plus facile d' essayer de prédire la rotation totale et d'obtenir de meilleurs résultats. Vous pouvez mapper par exemple de à π après coup si vous le souhaitez. Essayer de prédire l'angle sur le cercle unitaire après les multiplications, c'est essentiellement essayer de prédire le reste après la division par 2 π , et je ne vois pas comment cela serait plus facile que de prédire l'amplitude globale puis de soustraire des multiples de 2 π . 3ππ2π2π
Tom
1
Les options sont a) côté pas la périodicité: estimer le sin et cos de l'angle en utilisant une fonction d'activation sigmoïde. b) incorporer la symétrie dans la fonction de perte via un noyau comme celui-ci . Lisez les groupes de rotation et la thèse de Taco Cohen sur l'apprentissage des groupes de transformation . Malheureusement, je ne connais pas la théorie des groupes, je ne peux donc pas aider beaucoup plus.
Emre
@tom La chose à propos de cette approche est qu'il existe d'infinies pré-activations qui correspondent au même angle alors qu'elles n'ont rien en commun. Alors qu'un x1 positif fait toujours référence à un angle compris entre -1/2 et 1 \ 2 π . Et Emre, je vais me frayer un chemin à travers une théorie de groupe, cela m'a toujours intéressé, donc la combinaison de ML et de théorie de groupe me plairaππ
Jan van der Vegt

Réponses:

15

La deuxième façon, prédire et y = s i n ( α ) est tout à fait correcte.X=cos(α)y=sjen(α)

Oui, la norme du vecteur prévu n'est pas garantie d'être proche de 1 . Mais il est peu probable qu'il explose, surtout si vous utilisez des fonctions d'activation sigmoïdes (qui sont limitées par leur nature) et / ou régularisez bien votre modèle. Pourquoi votre modèle devrait-il prédire une grande valeur si tous les échantillons d'apprentissage étaient en [ - 1 , 1 ] ?(X,y)1[-1,1]

Un autre côté est le vecteur trop proche de ( 0 , 0 ) . Cela peut parfois se produire et pourrait en effet entraîner la prédiction de mauvais angles. Mais cela peut être considéré comme un avantage de votre modèle - vous pouvez considérer la norme de ( x , y ) comme une mesure de confiance de votre modèle. En effet, une norme proche de 0 signifie que votre modèle ne sait pas où est la bonne direction.(X,y)(0,0)(X,y)

Voici un petit exemple en Python qui montre qu'il vaut mieux prédire le péché et le cos, que prédire directement l'angle:

# predicting the angle (in radians)
import numpy as np
from sklearn.neural_network import MLPRegressor
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import r2_score
# generate toy data
np.random.seed(1)
X = np.random.normal(size=(100, 2))
y = np.arctan2(np.dot(X, [1,2]), np.dot(X, [3,0.4]))
# simple prediction
model = MLPRegressor(random_state=42, activation='tanh', max_iter=10000)
y_simple_pred = cross_val_predict(model, X, y)
# transformed prediction
joint = cross_val_predict(model, X, np.column_stack([np.sin(y), np.cos(y)]))
y_trig_pred = np.arctan2(joint[:,0], joint[:,1])
# compare
def align(y_true, y_pred):
    """ Add or remove 2*pi to predicted angle to minimize difference from GT"""
    y_pred = y_pred.copy()
    y_pred[y_true-y_pred >  np.pi] += np.pi*2
    y_pred[y_true-y_pred < -np.pi] -= np.pi*2
    return y_pred
print(r2_score(y, align(y, y_simple_pred))) # R^2 about 0.57
print(r2_score(y, align(y, y_trig_pred)))   # R^2 about 0.99

Vous pouvez continuer et tracer les prédictions, pour voir que les prédictions du modèle sinus-cosinus sont presque correctes, bien qu'elles puissent nécessiter un étalonnage supplémentaire:

import matplotlib.pyplot as plt
plt.figure(figsize=(12, 3))
plt.subplot(1,4,1)
plt.scatter(X[:,0], X[:,1], c=y)
plt.title('Data (y=color)'); plt.xlabel('x1'); plt.ylabel('x2')
plt.subplot(1,4,2)
plt.scatter(y_simple_pred, y)
plt.title('Direct model'); plt.xlabel('prediction'); plt.ylabel('actual')
plt.subplot(1,4,3)
plt.scatter(y_trig_pred, y)
plt.title('Sine-cosine model'); plt.xlabel('prediction'); plt.ylabel('actual')
plt.subplot(1,4,4)
plt.scatter(joint[:,0], joint[:,1], s=5)
plt.title('Predicted sin and cos'); plt.xlabel('cos'); plt.ylabel('sin')
plt.tight_layout();

entrez la description de l'image ici

πN2αcos(α)péché(α)z=péché(α+π4)w=cos(α+π4)

(X,y)(z,w)(X,y)arctan2

David Dale
la source
C'est parfait, merci beaucoup. Je vais m'y intéresser davantage, je vais devoir l'étendre à plus de dimensions
Jan van der Vegt
2

Travailler avec des coordonnées cartésiennes fonctionne bien comme mentionné ci-dessus. Pourtant, à mon avis, la conversion de données polaires en cartésiennes crée des dépendances entre les coordonnées X et Y qui n'étaient pas initialement présentes dans les données. Par exemple, le modèle de décision de trajectoire d'un robot est plus intuitif en coordonnées polaires que cartésien. La dépendance du vecteur vitesse du robot en coordonnées polaires entre l'angle et la magnitude peut même ne pas exister ou être différente de la dépendance en coordonnées cartésiennes.

Une solution de contournement que j'ai trouvée pour continuer à travailler avec les coordonnées polaires est de créer une fonction d'erreur personnalisée pour calculer la différence d'angle en utilisant la fonction angdiff () dans MATLAB et la différence de magnitude comme d'habitude.

Cette fonction renvoie '0' pour la différence entre -pi et pi. Voici un lien vers la page d'assistance des fonctions sur le site Web de Mathworks.

https://www.mathworks.com/help/robotics/ref/angdiff.html

Si vous utilisez l'activation sigmoïde et que vos données d'angles sont normalisées entre [0,1], vous devez les remettre dans la plage [-pi, pi] avant d'utiliser la fonction angdiff (), puis normaliser l'erreur sur la valeur [0,1 ] pour le processus de rétropropagation.

De plus, la fonction équivalente en Python serait:

import numpy as np


def angdiff(a, b):
    delta = np.arctan2(np.sin(b-a), np.cos(b-a))
    delta = np.around(delta, 4)  # Since np.sin(pi) result is 1.22e-16
    delta += 0.  # Since np.around return -0.
    return delta


pi = np.pi
a = np.asarray([pi/2, 3*pi/4, 0])
b = np.asarray([pi, pi/2, -pi])

print(angdiff(a, b))
print(angdiff(pi, -pi))
print(angdiff(-pi, pi))

Cela renvoie des résultats similaires à ceux de la fonction MATLAB et fonctionne également avec les tableaux:

[ 1.5708 -0.7854 -3.1416]
0.0
0.0

J'espère que cela pourra aider.

Stav Bar-Sheshet
la source