Вступление
Я нахожу этот вопрос действительно интересным, я полагаю, что кто-то выпустил статью по нему, но это мой выходной, поэтому я не хочу гоняться за ссылками.
Таким образом, мы могли бы рассматривать это как представление / кодирование вывода, что я и делаю в этом ответе. Я продолжаю думать, что есть лучший способ, где вы можете просто использовать немного другую функцию потерь. (Возможно, сумма квадратов разностей, используя вычитание по модулю 2 ).π
Но далее с фактическим ответом.
метод
Я предлагаю представить угол в виде пары значений, его синуса и косинуса.θ
Таким образом, функция кодирования:
а функция декодирования: Для arctan2, являющегося обратными касательными, сохраняя направление во всех квадрантах)θ ↦ ( грех( θ ) , cos( θ ) )
( у1, у2) ↦ арктан2 ( у1, у2)
Теоретически, вы можете эквивалентно работать напрямую с углами, если ваш инструмент поддерживает atan2
функцию слоя (беря ровно 2 входа и получая 1 выход).
TensorFlow делает это сейчас и поддерживает градиентный спуск , хотя и не предназначен для этого использования. Я исследовал использование out = atan2(sigmoid(ylogit), sigmoid(xlogit))
с функцией потерь min((pred - out)^2, (pred - out - 2pi)^2)
. Я обнаружил, что он тренируется гораздо хуже, чем outs = tanh(ylogit), outc = tanh(xlogit))
с функцией потери 0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2
. Что, я думаю, можно объяснить прерывистостью градиентаatan2
Мое тестирование здесь запускает его как функцию предварительной обработки
Чтобы оценить это, я определил задачу:
Учитывая черно-белое изображение, представляющее одну линию на пустом фоне. Выведите, под каким углом эта линия находится к «положительной оси X»
Я реализовал функцию случайного генерирования этих изображений со линиями под случайными углами (примечание: в более ранних версиях этого поста использовались случайные наклоны, а не случайные углы. Спасибо @Ari Herman за указание на это. Теперь это исправлено). Я построил несколько нейронных сетей, чтобы оценить эффективность выполнения задачи. Полная информация о реализации находится в этой записной книжке Jupyter . Код целиком на Юлии , и я использую библиотеку нейронных сетей Mocha .
Для сравнения я представляю его против альтернативных методов масштабирования до 0,1. и положить в 500 бункеров и использовать softmax. Я не особенно доволен последним, и чувствую, что мне нужно его настроить. Вот почему, в отличие от других, я тестирую его только на 1000 итераций, в отличие от двух других, которые были запущены на 1000 и на 10000
Экспериментальная установка
Изображения были пикселей, с линией, начинающейся в центре и идущей к краю. На изображении не было никаких шумов и т. Д., Только «черная» линия на белом фоне.101 × 101
Для каждого следа 1000 тренировок и 1000 тестовых изображений были сгенерированы случайным образом.
Оценочная сеть имела один скрытый слой шириной 500. В скрытом слое использовались сигмовидные нейроны.
Он обучался Stochastic Gradient Decent с фиксированной скоростью обучения 0,01 и фиксированным импульсом 0,9.
Регуляризация или отсев не использовались. Также не было никакого вида свертки и т. Д. Простая сеть, которая, я надеюсь, предполагает, что эти результаты будут обобщать
Эти параметры очень легко настроить в тестовом коде , и я призываю людей сделать это. (и искать ошибки в тесте).
Результаты
Мои результаты следующие:
| | 500 bins | scaled to 0-1 | Sin/Cos | scaled to 0-1 | Sin/Cos |
| | 1,000 Iter | 1,000 Iter | 1,000 iter | 10,000 Iter | 10,000 iter |
|------------------------|--------------|----------------|--------------|----------------|--------------|
| mean_error | 0.4711263342 | 0.2225284486 | 2.099914718 | 0.1085846429 | 2.1036656318 |
| std(errors) | 1.1881991421 | 0.4878383767 | 1.485967909 | 0.2807570442 | 1.4891605068 |
| minimum(errors) | 1.83E-006 | 1.82E-005 | 9.66E-007 | 1.92E-006 | 5.82E-006 |
| median(errors) | 0.0512168533 | 0.1291033982 | 1.8440767072 | 0.0562908143 | 1.8491085947 |
| maximum(errors) | 6.0749693965 | 4.9283551248 | 6.2593307366 | 3.735884823 | 6.2704853962 |
| accurancy | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
| accurancy_to_point001 | 2.10% | 0.30% | 3.70% | 0.80% | 12.80% |
| accurancy_to_point01 | 21.90% | 4.20% | 37.10% | 8.20% | 74.60% |
| accurancy_to_point1 | 59.60% | 35.90% | 98.90% | 72.50% | 99.90% |
Когда я ссылаюсь на ошибку, это абсолютная величина разницы между углом, выведенным нейронной сетью, и истинным углом. Таким образом, средняя ошибка (например) - это среднее значение для 1000 тестовых случаев этой разницы и т. Д. Я не уверен, что мне не следует масштабировать ее, сделав ошибку, скажем, равной к ошибке ). π7 π4π4
Я также представляю точность на разных уровнях детализации. Точность, являющаяся частью тестовых случаев, была исправлена. Таким accuracy_to_point01
образом, это означает, что он был посчитан как правильный, если результат был в пределах 0,01 от истинного угла. Ни одно из представлений не дало идеальных результатов, но это не удивительно, учитывая, как работает математика с плавающей запятой.
Если вы посмотрите на историю этого поста, то увидите, что результаты немного шумят, немного меняются каждый раз, когда я перезапускаю его. Но общий порядок и шкала ценностей остаются прежними; что позволяет нам сделать некоторые выводы.
обсуждение
Биннинг с softmax работает намного хуже, поскольку я сказал, что не уверен, что ничего не испортил в реализации. Это работает чуть выше, чем скорость догадки, хотя. если бы это было только предположение, мы получили бы среднюю ошибкуπ
Кодирование sin / cos работает значительно лучше, чем масштабированное кодирование 0-1. Улучшение в том, что при 1000 обучающих итерациях sin / cos работает примерно в 3 раза лучше по большинству показателей, чем масштабирование при 10000 итераций.
Я думаю, что отчасти это связано с улучшением обобщения, так как оба получали довольно схожую среднеквадратичную ошибку в обучающем множестве, по крайней мере, один раз было выполнено 10 000 итераций.
Безусловно, существует верхний предел наилучшей возможной производительности в этой задаче, учитывая, что Угол может быть больше или меньше любого действительного числа, но не все такие ангелы выдают разные линии с разрешением пикселей. Так как, например, углы 45.0 и 45.0000001 оба связаны с одним и тем же изображением с таким разрешением, ни один метод никогда не получит оба совершенно правильных.101 × 101
Также представляется вероятным, что в абсолютном масштабе, чтобы выйти за рамки этой производительности, необходима лучшая нейронная сеть. Вместо очень простого, описанного выше в экспериментальной установке.
Вывод.
Кажется, что представление sin / cos является безусловно лучшим из представлений, которые я исследовал здесь. Это имеет смысл, поскольку оно имеет плавное значение при перемещении по кругу. Мне также нравится, что обратное можно сделать с помощью arctan2 , что элегантно.
Я полагаю, что поставленная задача достаточна в ее способности представить разумную проблему для сети. Хотя я полагаю, что на самом деле это просто обучение подгонке кривой к так что, возможно, это слишком просто. И, возможно, хуже, это может быть в пользу парного представления. Я не думаю, что это так, но здесь уже поздно, поэтому я мог что-то упустить, и я приглашаю вас снова просмотреть мой код . Предлагайте улучшения или альтернативные задачи.е( х ) = у1Y2Икс