Параметризация регрессии угла поворота

15

Допустим, у меня есть стрелка сверху вниз, и я хочу предсказать угол, под которым эта стрелка. Это будет от до градусов или от до . Проблема в том, что эта цель круговая, и градусов - это одно и то же, что является инвариантностью, которую я хотел бы включить в свою цель, что должно значительно помочь в обобщении (это мое предположение). Проблема в том, что я не вижу четкого способа решения этой проблемы, есть ли какие-либо документы, которые пытаются решить эту проблему (или подобные)? У меня есть некоторые идеи с их потенциальными недостатками:036002π0360

  • Используйте сигмовидную или коричневую активацию, масштабируйте ее до ( диапазона и включите свойство округления в функцию потерь. Я думаю, что это будет довольно сложно, потому что, если он находится на границе (худший прогноз), лишь небольшой шум подтолкнет весы к тому или иному пути. Кроме того, значения ближе к границе и будет труднее достичь, поскольку абсолютное значение предварительной активации должно быть близко к бесконечности.0,2π)02π

  • Вернитесь к двум значениям, значениям и и рассчитайте потери на основе угла, который составляют эти два значения. Я думаю, что у этого есть больший потенциал, но норма этого вектора не ограничена, что может привести к нестабильности чисел и может привести к взлетам или к нулю во время тренировки. Это может быть потенциально решено с помощью некоторого странного регуляризатора, чтобы предотвратить слишком большое отклонение этой нормы от 1.xy

Другими вариантами было бы что-то делать с функциями синуса и косинуса, но я чувствую, что тот факт, что несколько предварительных активаций отображаются на один и тот же вывод, также усложнит оптимизацию и обобщения.

Ян ван дер Вегт
источник
Честно говоря, я думаю, что попытка предсказать общую ротацию будет легче и даст вам лучшие результаты. Вы можете отобразить, например, от до после факта, если хотите. Попытка предсказать угол на единичной окружности после умножения - это, по сути, попытка предсказать остаток после деления на , и я не могу понять, как это было бы проще, чем предсказать общую величину и затем вычесть из кратных , 3ππ2π2π
Том
1
Возможны следующие варианты: а) шаг за шагом периодичности: оцените sin и cos угла, используя функцию активации сигмоида. б) включить симметрию в функцию потерь через ядро, как это . Прочитайте о группах ротации и тезисе Тако Коэна об обучении групп трансформации . К сожалению, я не разбираюсь в теории групп, поэтому не могу больше помочь.
Эмре
@tom Суть этого подхода в том, что существуют бесконечные предварительные активации, которые отображаются на один и тот же угол, в то время как они не имеют ничего общего. В то время как положительное значение x1 всегда относится к углу между -1/2 и 1 \ 2 π . И Эмре, я буду пробираться через некоторую теорию групп, она всегда интересовала меня, так что сочетание ML и теории групп мне понравитсяππ
Ян ван дер Вегт

Ответы:

15

Второй способ, прогнозирование и y = s i n ( α ) , вполне приемлемо.x=cos(α)y=sin(α)

Да, норма предсказанного вектора не гарантируется равной 1 . Но это вряд ли взорвется, особенно если вы используете функции активации сигмоида (которые ограничены по своей природе) и / или хорошо упорядочиваете свою модель. Почему ваша модель должна прогнозировать большое значение, если все обучающие образцы были в [ - 1 , 1 ] ?(x,y)1[1,1]

Другая сторона - вектор слишком близко к ( 0 , 0 ) . Это может иногда случаться, и действительно могло привести к предсказанию неправильных углов. Но это может рассматриваться как преимущество вашей модели - вы можете рассматривать норму ( x , y ) как показатель достоверности вашей модели. Действительно, норма, близкая к 0, означает, что ваша модель не уверена в правильном направлении.(x,y)(0,0)(x,y)

Вот небольшой пример в Python, который показывает, что лучше прогнозировать sin и cos, чем непосредственно прогнозировать угол:

# 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

Вы можете продолжить и составить график прогнозов, чтобы увидеть, что прогнозы модели синус-косинус почти верны, хотя, возможно, потребуется дополнительная калибровка:

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();

введите описание изображения здесь

πN2αcos(α)sin(α)z=sin(α+π4)w=cos(α+π4)

(x,y)(z,w)(x,y)arctan2

Дэвид Дейл
источник
Это прекрасно, спасибо большое. Я посмотрю на это больше, мне нужно будет расширить его до большего размера
Ян ван дер Вегт
2

Работа с декартовыми координатами работает хорошо, как указано выше. Тем не менее, на мой взгляд, преобразование полярных данных в декартово создает зависимости между координатами X и Y, которые изначально не присутствовали в данных. Например, модель выбора пути робота является более интуитивной в полярных координатах, чем декартова. Зависимость вектора скорости робота в полярных координатах между углом и величиной может даже не существовать или отличаться от зависимости в декартовых координатах.

Обходной путь, который я нашел для продолжения работы с полярными координатами, - это создание пользовательской функции ошибок для вычисления разности углов с помощью функции angdiff () в MATLAB и разности величин, как обычно.

Эта функция возвращает '0' для разницы между -pi и pi. Вот ссылка на страницу поддержки функций на веб-сайте Mathworks.

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

Если вы используете активацию Sigmoid и ваши углы нормализованы между [0,1], вы должны вернуть их в диапазон [-pi, pi] перед использованием функции angdiff (), а затем нормализовать ошибку обратно до [0,1 ] диапазон для процесса обратного распространения.

Кроме того, эквивалентная функция в Python будет:

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))

Это возвращает результаты, аналогичные функции MATLAB, а также работает с массивами:

[ 1.5708 -0.7854 -3.1416]
0.0
0.0

Надеюсь, это поможет.

Став Бар-Шешет
источник