Technika Jedi redukcji sieci konwolucyjnych — pruning

Technika Jedi redukcji sieci konwolucyjnych — pruning

Przed Tobą znowu zadanie detekcji obiektów. Priorytetem jest szybkość działania przy akceptowalnej precyzji. Użyj architektury YOLOv3 i dokonaj dalszego treningu. Precyzja (mAp75) powinna wynosić ponad 0,95. Jednak prędkość działania nadal jest zbyt niska. Cholera.

Dziś pominiemy kwantyzację. A w rozwinięciu przyjrzymy się Model Pruning — przycinanie zbędnych części sieci w celu przyspieszenia działania bez utraty precyzji. Przykładowo — skąd, ile i jak można usunąć. Zbadamy, jak zrobić to ręcznie i gdzie można to zautomatyzować. Na końcu — repozytorium na keras.

Wprowadzenie

W poprzedniej pracy, w permiskim Macroscopie, nabrałem nawyku — zawsze śledzić czas działania algorytmów. A czas działania sieci zawsze sprawdzać przez filtr adekwatności. Zazwyczaj state-of-the-art w produkcji nie przechodzi tego filtr, co doprowadziło mnie do Pruning.

Pruning — temat stary, o którym mówiono na wykładach ze Stanfordu w 2017 roku. Główna idea — zmniejszenie rozmiaru wytrenowanej sieci bez utraty precyzji poprzez usunięcie różnych węzłów. Brzmi świetnie, ale rzadko słyszę o jego zastosowaniach. Może brakuje implementacji, nie ma artykułów w języku rosyjskim, albo po prostu wszyscy uważają pruning za tajemnicę i milczą.
Ale przejdźmy do rozbioru.

Zerknijmy na biologię.

Lubię, gdy w Deep Learning zaglądają pomysły, które przyszły z biologii. Można im zaufać, tak jak ewolucji (a czy wiesz, że ReLU jest bardzo podobna do funkcji aktywacji neuronów w mózgu??)

Proces Model Pruning jest również bliski biologii. Reakcję sieci można porównać do plastyczności mózgu. Kilka ciekawych przykładów można znaleźć w książce Normana Doidge'a.:

  1. Mózg kobiety, która od urodzenia miała tylko jedną półkulę, sam przearanżował się, by pełnić funkcje brakującej półkuli.
  2. Chłopak odgryzł sobie część mózgu, odpowiadającą za wzrok. Z czasem inne części mózgu przejęły te funkcje. (nie próbujemy tego powtarzać)

Tak i z Twojego modelu można usunąć część słabych splotów. W ostateczności pozostałe sploty pomogą zastąpić usunięte.

Lubisz Transfer Learning czy uczysz od podstaw?

Opcja numer jeden. Używasz Transfer Learning z Yolov3, Retina, Mask-RCNN lub U-Net. Jednak najczęściej nie musimy rozpoznawać 80 klas obiektów, jak w COCO. W mojej praktyce wszystko ogranicza się do 1-2 klas. Można założyć, że architektura dla 80 klas jest w tym przypadku nadmierna. Nasuwa się myśl, że architekturę trzeba zmniejszyć. Chciałbym to zrobić bez utraty istniejących wcześniej wyuczonych wag.

Opcja numer dwa. Może masz dużo danych i zasobów obliczeniowych lub po prostu potrzebujesz super dostosowanej architektury. To nie ma znaczenia. Ale uczysz sieć od podstaw. Zwykły porządek — patrzymy na strukturę danych, dobieramy NADMIERNIE mocną architekturę i wprowadzamy drop-outy, aby zapobiec przeuczeniu. Widziałem drop-outy na poziomie 0.6, Karl.

W obu przypadkach sieć można zmniejszyć. Zostało to udowodnione. Teraz przejdźmy do wyjaśnienia, co to jest odcinanie pruning.

Ogólny algorytm

Postanowiliśmy, że możemy usunąć niektóre konwolucje. Wygląda to bardzo prosto:

Technika Jedi redukcji sieci konwolucyjnych — pruning

Usunięcie dowolnej konwolucji to stres dla sieci, który zwykle prowadzi do pewnego wzrostu błędu. Z jednej strony, ten wzrost błędu jest wskaźnikiem tego, jak dobrze usuwamy konwolucje (na przykład, duży wzrost mówi, że coś robimy źle). Ale niewielki wzrost jest jak najbardziej dopuszczalny i często usuwa się go dzięki lekkiej dalszej nauce z małym LR. Dodajemy krok dalszej nauki:

Technika Jedi redukcji sieci konwolucyjnych — pruning

Teraz musimy zrozumieć, kiedy chcemy zatrzymać nasz cykl Uczenia<->Odcinania. Możliwe są egzotyczne warianty, gdy musimy zmniejszyć sieć do określonego rozmiaru i szybkości działania (na przykład dla urządzeń mobilnych). Jednak najczęściej jest to kontynuacja cyklu, dopóki błąd nie wzrośnie powyżej dopuszczalnego poziomu. Dodajemy warunek:

Technika Jedi redukcji sieci konwolucyjnych — pruning

Tak więc algorytm staje się jasny. Pozostaje nam rozwiązać, jak określić usuwane konwolucje.

Wyszukiwanie usuwanych konwolucji

Musimy usunąć niektóre konwolucje. Rwać się na oślep i »strzelać« do wszelkich - to zła idea, chociaż może działać. Ale skoro mamy głowę, można pomyśleć i spróbować wyróżnić do usunięcia „słabe” konwolucje. Opcji jest kilka:

  1. Najmniejszy wskaźnik L1 lub low_magnitude_pruning. Idea głosi, że konwolucje o małych wartościach wag wnoszą niewielki wkład w ostateczne podejmowanie decyzji.
  2. Najmniejszy wskaźnik L1 z uwzględnieniem średniej i odchylenia standardowego. Uzupełniamy oceną charakteru rozkładu.
  3. Maskowanie konwolucji i wykluczenie tych o najmniejszym wpływie na końcową dokładność. Bardziej precyzyjna identyfikacja mało znaczących konwolucji, ale bardzo czasochłonna i kosztowna w zasoby.
  4. Inne

Każda z opcji ma prawo do życia i swoje cechy realizacji. Tutaj omówimy wariant z najmniejszą miarą L1

Ręczny proces dla YOLOv3

W pierwotnej architekturze znajdują się bloki resztkowe. Jednak niezależnie od tego, jak świetne są dla głębokich sieci, mogą nam w pewnym stopniu przeszkadzać. Problematyczne jest to, że nie można usuwać konwolucji z różnymi indeksami w tych warstwach:

Technika Jedi redukcji sieci konwolucyjnych — pruning

Dlatego wyodrębniamy warstwy, z których możemy swobodnie usuwać konwolucje:

Technika Jedi redukcji sieci konwolucyjnych — pruning

Teraz zbudujmy cykl pracy:

  1. Zrzucamy aktywacje
  2. Szacujemy, ile wyciąć
  3. Wycinamy
  4. Uczymy przez 10 epok z LR=1e-4
  5. Testowanie

Zrzucanie konwolucji jest przydatne, aby ocenić, jaką część możemy usunąć na danym etapie. Przykłady zrzutów:

Technika Jedi redukcji sieci konwolucyjnych — pruning

Widzimy, że praktycznie wszędzie 5% konwolucji ma bardzo niską normę L1 i możemy je usunąć. Na każdym etapie taki zrzut powtarzano i dokonywano oceny, z jakich warstw i ile można wyciąć.

Cały proces zmieścił się w 4 krokach (tu i wszędzie liczby odnoszą się do RTX 2060 Super):

KrokmAp75Liczba parametrów, mlnRozmiar sieci, mbOd pierwotnego, %Czas przetwarzania, msWarunek cięcia
00.965660241100180
10.962255218911755% wszystkich
20.962550197831685% wszystkich
30.9633391556415515% dla warstw z 400+ konwolucjami
40.9555311245114610% dla warstw z 100+ konwolucjami

W 2 kroku pojawił się jeden pozytywny efekt — w pamięci zmieścił się rozmiar batcha 4, co znacząco przyspieszyło proces dalszego uczenia.
W 4 kroku proces został zatrzymany, ponieważ nawet długotrwałe dalsze uczenie nie podniosło mAp75 do dawnych wartości.
Ostatecznie udało się przyspieszyć inference o 15%, zmniejszyć rozmiar o 35% i nie stracić dokładności.

Automatyzacja dla prostszych architektur

Dla prostszych architektur sieci (bez warunkowych bloków add, concatenate i residual) można spokojnie kierować się przetwarzaniem wszystkich warstw konwolucyjnych i zautomatyzować proces wycinania konwolucji.

Taki wariant zaimplementowałem tutaj.
Jest to proste: potrzebujesz tylko funkcji strat, optymalizatora i generatorów batchy:

import pruning
from keras.optimizers import Adam
from keras.utils import Sequence

train_batch_generator = BatchGenerator...
score_batch_generator = BatchGenerator...

opt = Adam(lr=1e-4)
pruner = pruning.Pruner("config.json", "categorical_crossentropy", opt)

pruner.prune(train_batch, valid_batch)

W razie potrzeby można zmienić parametry konfiguracji:

{
    "input_model_path": "model.h5",
    "output_model_path": "model_pruned.h5",
    "finetuning_epochs": 10, # liczba epok do treningu między krokami przycinania
    "stop_loss": 0.1, # strata do zatrzymania procesu
    "pruning_percent_step": 0.05, # część konwolucji do usunięcia na każdym kroku przycinania
    "pruning_standart_deviation_part": 0.2 # przesunięcie do ograniczenia części przycinania
}

Dodatkowo wprowadzono ograniczenie na podstawie odchylenia standardowego. Celem jest ograniczenie liczby usuwanych, wykluczając konwolucje o już 'wystarczających' miarach L1:

Technika Jedi redukcji sieci konwolucyjnych — pruning

W ten sposób pozwalamy usunąć tylko słabe konwolucje z rozkładów podobnych do prawego i nie wpływać na usuwanie z rozkładów podobnych do lewego:

Technika Jedi redukcji sieci konwolucyjnych — pruning

W miarę zbliżania się rozkładu do normalnego, współczynnik pruning_standart_deviation_part można dostosować do:

Technika Jedi redukcji sieci konwolucyjnych — pruning
Rekomenduję tolerancję na poziomie 2 sigm. Można również nie kierować się tą cechą, pozostawiając wartość < 1.0.

Na wyjściu otrzymujemy wykres rozmiaru sieci, strat i czasu przetwarzania sieci przez cały test, znormalizowany do 1.0. Na przykład tutaj rozmiar sieci został zmniejszony prawie dwukrotnie bez utraty jakości (mała sieć konwolucyjna z 100k wagami):

Technika Jedi redukcji sieci konwolucyjnych — pruning

Czas przetwarzania podlega normalnym fluktuacjom i praktycznie się nie zmienił. Istnieje na to wyjaśnienie:

  1. Liczba konwolucji zmienia się z wygodnych (32, 64, 128) na mniej wygodne dla kart graficznych — 27, 51 itd. Mogę się mylić, ale prawdopodobnie ma to wpływ.
  2. Architektura nie jest szeroka, ale sekwencyjna. Zmniejszając szerokość, nie ingerujemy w głębokość. W ten sposób zmniejszamy obciążenie, ale nie zmieniamy szybkości.

Dlatego poprawa przejawia się w zmniejszeniu obciążenia CUDA podczas przetwarzania o 20-30%, ale nie w zmniejszeniu czasu przetwarzania.

Podsumowanie

Pochylmy się nad tym. Rozważaliśmy 2 warianty przycinania — dla YOLOv3 (kiedy trzeba działać ręcznie) i dla sieci z prostszymi architekturami. Widać, że w obu przypadkach można osiągnąć zmniejszenie rozmiaru sieci i przyspieszenie bez utraty dokładności. Wyniki:

  • Zmniejszenie rozmiaru
  • Przyspieszenie przetwarzania
  • Zmniejszenie obciążenia CUDA
  • W konsekwencji, ekologiczność (Optymalizujemy przyszłe wykorzystanie zasobów obliczeniowych. Gdzieś cieszy się jedna Greta Thunberg)

Aneks

  • Po kroku przycinania można również przeprowadzić kwantyzację (na przykład z TensorRT)
  • Tensorflow oferuje możliwości dla low_magnitude_pruning. Działa.
  • Repozytorium chcę rozwijać i będę wdzięczny za pomoc

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster