Uczę sieci neuronowej (szczegóły nieważne), gdzie dane docelowe to wektor kątów (od 0 do 2 * pi). Szukam porady, jak zakodować te dane. Oto, co obecnie próbuję (z ograniczonym sukcesem):
1) Kodowanie 1-of-C: I bin ustawiam możliwe kąty na około 1000 dyskretnych kątów, a następnie wskazuję konkretny kąt, umieszczając 1 przy odpowiednim indeksie. Problem polega na tym, że sieć po prostu uczy się wyprowadzać wszystkie zera (ponieważ jest to prawie dokładnie poprawne).
2) Proste skalowanie: skalowałem zakres wyjściowy sieci ([0,1]) do [0,2 * pi]. Problem polega na tym, że kąty mają naturalnie topologię kołową (tj. 0,0001 i 2 * pi faktycznie znajdują się obok siebie). Przy tego rodzaju kodowaniu informacje te są tracone.
Wszelkie sugestie będą mile widziane!
źródło
Odpowiedzi:
Wprowadzenie
Uważam to pytanie za bardzo interesujące, zakładam, że ktoś opublikował na nim artykuł, ale to mój dzień wolny, więc nie chcę gonić za referencjami.
Możemy więc uznać to za reprezentację / kodowanie danych wyjściowych, co robię w tej odpowiedzi. Nadal myślę, że istnieje lepszy sposób, w którym można po prostu użyć nieco innej funkcji utraty. (Być może suma kwadratowych różnic przy użyciu odejmowania modulo 2 ).π
Ale z rzeczywistą odpowiedzią.
metoda
I proponują, że kąt być przedstawiony w postaci pary, jej wartości sinusa i kosinusa jej.θ
Zatem funkcja kodowania to: a funkcja dekodowania to: Dla arctan2, które są odwrotnymi stycznymi, zachowując kierunek we wszystkich ćwiartkach)θ ↦ ( grzech( θ ) , cos( θ ) )
( y1, y2)) ↦ arctan2 ( y1, y2))
Teoretycznie możesz równo pracować bezpośrednio z kątami, jeśli twoje narzędzie jest obsługiwane
atan2
jako funkcja warstwy (biorąc dokładnie 2 dane wejściowe i generując 1 wynik). TensorFlow robi to teraz i obsługuje opadanie gradientu , choć nie jest to przeznaczone do tego zastosowania. Badałem zaout = atan2(sigmoid(ylogit), sigmoid(xlogit))
pomocą funkcji stratymin((pred - out)^2, (pred - out - 2pi)^2)
. Przekonałem się, że trenował o wiele gorzej niż używanieouts = tanh(ylogit), outc = tanh(xlogit))
z funkcją utraty0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2
. Wydaje mi się, że można to przypisać nieciągłości gradientuatan2
Moje testy tutaj uruchamiają go jako funkcję przetwarzania wstępnego
Aby to ocenić, zdefiniowałem zadanie:
Zaimplementowałem funkcję losowego generowania tych obrazów, z liniami pod losowymi kątami (Uwaga: wcześniejsze wersje tego postu używały losowych nachyleń, a nie losowych kątów. Dzięki @Ari Herman za zwrócenie na to uwagi. Teraz jest naprawione). Zbudowałem kilka sieci neuronowych, aby ocenić wydajność na tym zadaniu. Pełne szczegóły implementacji znajdują się w tym notatniku Jupyter . Cały kod jest w Julii , a ja korzystam z biblioteki sieci neuronowej Mocha .
Dla porównania przedstawiam go w stosunku do alternatywnych metod skalowania do 0,1. oraz wkładanie do 500 pojemników i stosowanie softmax soft-label. Nie jestem szczególnie zadowolony z ostatniego i czuję, że muszę go ulepszyć. Dlatego, w przeciwieństwie do innych, testuję go tylko na 1000 iteracji, w porównaniu do dwóch pozostałych, które przeprowadzono na 1000 i na 10 000
Zestaw doświadczalny
Obrazy miały pikseli, a linia przesuwała się na środku i dochodziła do krawędzi. Na obrazie nie było szumu, tylko „czarna” linia na białym tle.101 × 101
Dla każdego szlaku losowo wygenerowano 1000 treningów i 1000 zdjęć testowych.
Sieć oceny miała jedną ukrytą warstwę o szerokości 500. W ukrytej warstwie zastosowano neurony sigmoidalne.
Został przeszkolony przez Stochastic Gradient Decent, ze stałą szybkością uczenia się 0,01 i stałym pędem 0,9.
Nie zastosowano regulacji ani rezygnacji. Nie było też żadnego rodzaju splotu itp. Prosta sieć, która, mam nadzieję, sugeruje, że wyniki te się uogólnią
Dostosowanie tych parametrów w kodzie testowym jest bardzo łatwe i zachęcam ludzi do tego. (i poszukaj błędów w teście).
Wyniki
Moje wyniki są następujące:
Gdy odnoszę się do błędu, jest to wartość bezwzględna różnicy między kątem wyjściowym sieci neuronowej a kątem rzeczywistym. Zatem średni błąd (na przykład) jest średnio ponad 1000 przypadków testowych tej różnicy itp nie jestem pewien, że nie powinno się go poprzez przeskalowanie błąd powiedzmy jest równa na błąd ). π7 π4 π4
Przedstawiam również dokładność na różnych poziomach szczegółowości. Dokładność jest częścią przypadków testowych, które uzyskały. Więc
accuracy_to_point01
oznacza, że został on liczony jako poprawne, jeśli wyjście było w 0,01 prawdziwego kątem. Żadne z przedstawień nie przyniosło żadnych doskonałych wyników, ale nie jest to wcale zaskakujące, biorąc pod uwagę, jak działa matematyka zmiennoprzecinkowa.Jeśli spojrzysz na historię tego postu, zobaczysz, że wyniki mają trochę hałasu, nieco inny za każdym razem, gdy go ponownie uruchamiam. Ale ogólny porządek i skala wartości pozostają takie same; co pozwala nam wyciągnąć pewne wnioski.
Dyskusja
Binning z softmaxem działa zdecydowanie najgorzej, ponieważ powiedziałem, że nie jestem pewien, czy coś nie spieprzyłem w implementacji. Działa jednak nieznacznie powyżej wskaźnika zgadywania. Gdyby tylko zgadywał, otrzymalibyśmy średni błądπ
Kodowanie sin / cos działa znacznie lepiej niż skalowane kodowanie 0-1. Poprawa polega na tym, że przy 1000 iteracjach treningowych sin / cos radzi sobie około 3 razy lepiej na większości metryk niż skalowanie przy 10.000 iteracji.
Myślę, że częściowo wiąże się to z poprawą uogólnienia, ponieważ oba miały dość podobny średni błąd kwadratowy na zestawie treningowym, co najmniej raz po uruchomieniu 10 000 iteracji.
Z pewnością istnieje górna granica najlepszej możliwej wydajności w tym zadaniu, biorąc pod uwagę, że Kąt może być mniej więcej dowolną liczbą rzeczywistą, ale nie wszystkie takie anioły wytwarzają różne linie w rozdzielczości pikseli. Ponieważ na przykład oba kąty 45.0 i 45.0000001 są powiązane z tym samym obrazem w tej rozdzielczości, żadna metoda nigdy nie uzyska obu poprawnych poprawności.101 × 101
Wydaje się również prawdopodobne, że w skali absolutnej, aby wyjść poza tę wydajność, potrzebna jest lepsza sieć neuronowa. Zamiast tego bardzo prostego opisanego powyżej w konfiguracji eksperymentalnej.
Wniosek.
Wydaje się, że reprezentacja sin / cos jest zdecydowanie najlepsza z reprezentacji, które badałem tutaj. Ma to sens, ponieważ ma płynną wartość podczas poruszania się po okręgu. Podoba mi się również, że odwrotność można wykonać za pomocą arctan2 , który jest elegancki.
Uważam, że przedstawione zadanie jest wystarczające, aby móc przedstawić rozsądne wyzwanie dla sieci. Chociaż tak naprawdę myślę, że to tylko nauka dopasowywania krzywej do więc być może jest to zbyt łatwe. A może gorzej może sprzyjać sparowanej reprezentacji. Nie sądzę, że tak jest, ale robi się już późno, więc mogłem coś przeoczyć. Zapraszam ponownie do przejrzenia mojego kodu . Zaproponuj ulepszenia lub alternatywne zadania.fa( x ) = y1y2)x
źródło
tan(angle)
Oto kolejna implementacja Pythona porównująca proponowane kodowanie Lyndona White'a z podejściem binowanym. Poniższy kod wygenerował następujące dane wyjściowe:
źródło
Oto moja wersja eksperymentu w języku Python. Zachowałem wiele szczegółów twojej implementacji bez zmian, w szczególności używam tego samego rozmiaru obrazu, rozmiarów warstwy sieci, szybkości uczenia się, tempa i wskaźników sukcesu.
Każda badana sieć ma jedną ukrytą warstwę (rozmiar = 500) z neuronami logistycznymi. Neurony wyjściowe są liniowe lub softmax, jak wspomniano. Użyłem 1000 obrazów treningowych i 1000 obrazów testowych, które zostały niezależnie, losowo wygenerowane (więc mogą być powtórzenia). Trening składał się z 50 iteracji w zestawie treningowym.
Byłem w stanie uzyskać całkiem dobrą dokładność za pomocą binowania i kodowania „gaussowskiego” (nazwa, którą wymyśliłem; podobny do binowania, z tym wyjątkiem, że docelowy wektor wyjściowy ma postać exp (-pi * ([1,2,3, ... , 500] - idx) ** 2) gdzie idx to indeks odpowiadający prawidłowemu kątowi). Kod znajduje się poniżej; oto moje wyniki:
Błąd testu dla kodowania (cos, sin):
1000 obrazów szkoleniowych, 1000 obrazów testowych, 50 iteracji, wyjście liniowe
Średnia: 0,0911558142071
Mediana: 0,0429723541743
Minimum: 2,77769843793e-06
Maksymalnie: 6,2608513539
Dokładność do 0,1: 85,2%
Dokładność do 0,01: 11,6%
Dokładność do 0,001: 1,0%
Błąd testu dla kodowania [-1,1]:
1000 obrazów szkoleniowych, 1000 obrazów testowych, 50 iteracji, wyjście liniowe
Średnia: 0,234181700523
Mediana: 0,17460197307
Minimum: 0,000473665840258
Maksymalnie: 6,00637777237
Dokładność do 0,1: 29,9%
Dokładność do 0,01: 3,3%
Dokładność do 0,001: 0,1%
Błąd testu dla kodowania 1 na 500:
1000 obrazów treningowych, 1000 obrazów testowych, 50 iteracji, wyjście softmax
Średnia: 0,0298767021922
Mediana: 0,00388858079174
Minimum: 4.08712407829e-06
Maksymalnie: 6,2784479965
Dokładność do 0,1: 99,6%
Dokładność do 0,01: 88,9%
Dokładność do 0,001: 13,5%
Błąd testu dla kodowania gaussowskiego:
1000 obrazów treningowych, 1000 obrazów testowych, 50 iteracji, wyjście softmax
Nie mogę zrozumieć, dlaczego nasze wyniki wydają się być ze sobą sprzeczne, ale wydaje się, że warto to zbadać.
źródło
Innym sposobem zakodowania kąta jest zestaw dwóch wartości:
Miałoby to podobny problem do arctan2, ponieważ gradient jest niezdefiniowany przy theta = 0. Nie mam czasu na szkolenie sieci i porównywanie z innymi kodowaniami, ale w tym artykule technika wydawała się dość skuteczna.
źródło