Jak sterować samochodem autonomicznym za pomocą sieci neuronowej?

Sterowanie samochodu autonomicznego za pomocą sieci neuronowej End to End to wspaniały eksperyment by rozpocząć przygodę z głębokimi sieciami neuronowymi i przetwarzaniem obrazu w zastosowaniu do samochodów autonomicznych. A zatem jak sterować samochodem autonomicznym?

W rzeczywistym świecie unikamy stosowania rozwiązania end to end z uwagi na brak uzasadnienia procesu decyzyjnego czy chęć planowania trasy. Mówiąc end to end mam tu na myśli sieć neuronową, której wejściem jest obraz z kamery (ew. chmura punktów z lasera), a wyjściem jest kąt skrętu kierownicy oraz poziom wciśnięcia hamulca czy gazu. Chodzi o to by na podstawie dużej liczby przykładów nauczyć zaprojektowaną sieć neuronową co najczęściej robi „ludzki kierowca”. Tu jest ważna rzecz – sieć wytrenowana na danych nagranych przez jednego kierowcę będzie prowadzić w jego stylu.

Musimy zadbać o zróżnicowanie danych – to jest duży problem.

Jeśli wyobrazimy sobie nagrany miesiąc naszych codziennych podróży praca-dom, to okaże się że najczęściej jedziemy prosto – na histogramie kąta skrętu kierownicy zobaczymy, że większość danych jest w zerze, albo tuż obok, co może wynikać z przesuniętego kąta 0°.

Co w takiej sytuacji możemy zrobić? Co zrobić by nasz sieć nie stwierdziła, że najczęściej to jednak jedziemy prosto, więc jeżeli dam na wyjściu 0° na stałe to na zbiorze trenującym uzyskam zadowalająco niski błąd i biedny człowiek pilnujący procesu uczenia stwierdzi, że 80-90% wyników się zgadza. W takiej sytuacji zbiór danych wykorzystywany do walidacji dawać może podobne wyniki – szczególnie jeśli jest to część jednego zbioru np. 10%, albo są to dane pozyskane w ten sam sposób, ale z innego miesiąca (tu uwaga na pory roku, pogodę itd.). Dopiero w praktyce zauważymy, że nasz pojazd po prostu nie skręca w ogóle!

Poświęć 90% uwagi na przygotowanie danych, a nie modeli i architektur!

W wielu problemach istnieją już architektury, które dają dobre wyniki i to od nich warto zacząć. W przypadku rozwiązania End to End dla problemu prowadzenia samochodu autonomicznego mamy tu artykuł Nvidii (artykuł znajdziesz na dole w linkach, tu dam wpis z bloga, bo to przystępniejsza forma):

PLinML 2018 – Deep Learning for Self-Driving Cars

W ramach PLinML 2018 prowadziłem całodniowy warsztat (4x 1.5h, kto był ten wie co to znaczy; serdecznie Was pozdrawiam!) na temat zastosowania głębokich sieci neuronowych, głębokiego uczenia w samochodach autonomicznych. Postanowiłem zrealizować 4 tematy:

Było to ambitne założenie, ale uważam, że to wyszło całkiem dobrze. Przy następnym warsztacie zapewne zmienię koncepcję, zobaczymy.

Tak wygląda wynik ankiety jaką przeprowadziłem po warsztacie.

Tutaj skupimy się na pierwszym z tematów.

Google Colab – WAŻNE!!!

Wejdź tu: http://bit.ly/PLinML18_EndToEnd. Wykonaj kopię i możesz działać!

Symulator samochodu autonomicznego

W ramach ćwiczenia wykorzystamy symulator opracowany przez Udacity, wykorzystywany przez nich w kursie Udacity Self-Driving Car Engineer Nanodegree. Symulator może pobrać tutaj:

https://github.com/karolmajek/self-driving-car-sim

Możesz pracować na Windowsie, Linuxie czy iOS, symulator jest dostępny na każdą platformę. Pobierz proszę z Available Game Builds (Precompiled builds of the simulator) Version 2, 2/07/17 wersję odpowiednią dla Twojego systemu operacyjnego.

Uruchamiając symulator ustaw detale i rozdzielczość na minimum, chyba że dysponujesz kartą graficzną. Prędkość symulacji wpływa na osiągane wyniki, warto o tym pamiętać. Prędkość działania naszej sieci neuronowej również ma wpływ na osiągane wyniki.

Aby uruchomić symulator na nieWindowsie – ustaw atrybut wykonywalności dla pliku z symulatorem (piszę tu o wersji 64bitów bo raczej masz 64bitowy system operacyjny):

chmod +x beta_simulator.x86_64

Następnie możemy uruchomić symulator poprzez

./beta_simulator.x86_64

Na Windowsie to klasycznie – po prostu klikamy dwukrotnie.

W tym ćwiczeniu będziemy pracować z trasą po prawej

Nagrywanie danych

Nagrywając dane polecam używać joystick (ja osobiście używam joysticka USB od XBOXa – działa na Ubuntu 16.04) z uwagi na to, że możemy uzystkiwać sterowania nie tylko binarne (max lewo, środek, max prawo) jak w przypadku klawiatury, ale wiele wartości między -1, a 1.

Nie musisz nagrywać danych, nagrałem jedno okrążenie na warsztat, ale jeżeli chcesz osiągnąć naprawdę dobre wyniki, przydadzą Ci się dodatkowe dane.

Dane wejściowe

Po przejściu kilku komórek związanych z pobraniem zbioru danych na maszynę w Google Colab, możesz zobaczyć film z danymi wejściowymi oraz przykładowy obraz jak poniżej.

Obraz z naszego zbioru danych

Obraz jest dość duży i zawiera nadmiarowe informacje – pixele u góry i dołu można usunąć bez negatywnych konsekwencji. Zmniejszymy też szerokość i wysokość by nasz model był kompatkowy. Możemy sobie na to pozwolić, gdyż pracujemy z danymi z symulatora.

Wykorzystamy poniższy kod który:

  • usuwa 10 linii z góry
  • usuwa 30 linii z dołu
  • zostawia co czwarty wiersz
  • zostawia co drugą kolumnę
  • liczy średnią z kanałów R, G, B
  • normalizuje wartości do przedziału -0.5, 0.5
def process_image(image):
    image=image[10:130:4,::2,:]
    image=np.mean(image,axis=2)
    image=(image-image.min())/255.0-0.5
    image=image.reshape(image.shape[0],image.shape[1],1)
    return image
Zmniejszony obraz, kanały RGB zredukowane do wartości średniej

Model – architektura

Przez to że zmniejszyliśmy zdjęcia, nie możemy wykorzystać oryginalnego modelu od Nvidia’i, ale możemy stworzyć podobny model, nieco uproszczony. Poniżej prezentuję opis modelu pochcodzący z biblioteki Keras – funkcja model.summary().

Image shape before processing: (160, 320, 3)
Image shape after processing: (30, 160, 1)

Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 28, 158, 64) 640
activation_1 (Activation) (None, 28, 158, 64) 0
conv2d_2 (Conv2D) (None, 26, 156, 32) 18464
activation_2 (Activation) (None, 26, 156, 32) 0
conv2d_3 (Conv2D) (None, 24, 154, 16) 4624
activation_3 (Activation) (None, 24, 154, 16) 0
conv2d_4 (Conv2D) (None, 22, 152, 8) 1160
activation_4 (Activation) (None, 22, 152, 8) 0
max_pooling2d_1 (MaxPooling2 (None, 11, 76, 8) 0
dropout_1 (Dropout) (None, 11, 76, 8) 0
-------------------------------------------------------------
flatten_1 (Flatten) (None, 6688) 0
-------------------------------------------------------------
dense_1 (Dense) (None, 16) 107024
activation_5 (Activation) (None, 16) 0
dense_2 (Dense) (None, 16) 272
activation_6 (Activation) (None, 16) 0
dense_3 (Dense) (None, 16) 272
activation_7 (Activation) (None, 16) 0
dropout_2 (Dropout) (None, 16) 0
dense_4 (Dense) (None, 1) 17
=================================================================
Total params: 132,473
Trainable params: 132,473
Non-trainable params: 0

Uczenie

Teraz właściwe uczenie. Nie trwa to długo z uwagi na wielkość problemu i to że wykorzystujemy kartę graficzną – tak, mamy za darmo możliwość wykorzystywania kart graficznych w Google Colab!

Tak wygląda przykładowy wykres uczenia. Mamy go dzięki Piotrowi Migdałowi i jego bibliotece do wizualizacji wykresów w notebookach https://github.com/stared/livelossplot

Nauczony model możemy pobrać i uruchomić, tak by samochód w symulatorze sam zaczął jeździć! Wystarczy pobrać wytrenowany model i ściągnąć kod http://bit.ly/drive_py. Aby uruchomić kod włączamy sumulator w trybie Autonomous i uruchamiamy drive.py z modelem:

python drive.py model.h5

Ten model nie powinien Cię zachwycić, przejedzie kilka metrów, chyba że mu pomożesz, wtedy i na górkę wjedzie! Powinniśmy zwiększyć rozmiar naszego zbioru trenującego. Jeździmy czy generujemy dane? (10 sekund na zastanowienie)

Generowanie danych

Możemy wykonać proste przekształcenia aby zwiększyć liczbę danych. Ten tutorial pokrywa tylko pogrubione metody:

  • zmiana jasności i kontrastu
  • odbicie w lustrze
  • translacja w poziomie wraz ze zmianą kąta
  • translacja w pionie wraz ze zmianą kąta
  • obrót wraz ze zmianą kąta
  • dodanie losowych cieni
obraz wejściowy; kąt -0.7
obraz wygenerowany po przesunięciu w x i y; kąt: -0.58

Mając generator danych do trenowania możemy wreszcie wytrenować kolejny model i sprawdzić jak sobie poradzi.

Tu zostawiam miejsce by wkleić Twoje wyniki – kod na Githubie/Colabie i/oraz film na Youtube z samochodem przejeżdżającym pełne okrążenie. Zgłoś się przez formularz kontaktowy.

Jeśli coś jest niejasne, albo wprost nie działa – pisz do mnie przez formularz kontaktowy, postaram się pomóc. Wybacz, że ten wpis nie jest super obszerny

Linki

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

This site uses Akismet to reduce spam. Learn how your comment data is processed.