Prosty start:
Zanim zaczniemy zastanawiać się, jak nasz komputer może rozpoznawać np. ptaki, spróbujmy zacząć od czegoś prostszego − od rozpoznawania napisanej odręcznie cyfry 8.
Wyobraźmy sobie, że stworzyliśmy małą sieć neuronową (na podstawie z wiedzy z artykułu o tłumaczeniu maszynowym), aby oszacować ceny domów w zależności od liczby sypialni, powierzchni czy dzielnicy, w jakiej się znajdują:
Wiemy także, że sama koncepcja uczenia maszynowego polega na wielokrotnym posługiwaniu się algorytmami. Wystarczy podstawić nowe dane, aby rozwiązać inne problemy. Dlatego też w tym przypadku zmodyfikujemy tę samą sieć neuronową, aby rozpoznać napisany odręcznie tekst. Aby uprościć ten proces, naszym zadaniem będzie rozpoznanie jednej cyfry − 8.
Uczenie maszynowe działa tylko wtedy, gdy mamy odpowiednie dane, najlepiej w dużej ilości. Dlatego, aby rozpocząć proces, potrzebne nam są duże ilości zdjęć, na których znajduje się odręcznie napisana cyfra osiem. Na nasze szczęście badacze wykreowali MNIST, czyli bazę danych zawierającą ręcznie napisane cyfry, służącą właśnie do uczenia maszynowego. MNIST daje nam dostęp do 60 000 obrazów z ręcznie napisanymi cyframi o rozmiarze 18x18 pikseli.
Oto trochę przykładów cyfry 8 z bazy MNIST:
Jeśli przyjrzymy się bliżej, dane wejściowe w naszej przykładowej sieci neuronowej to cyfry − 3 sypialnie czy 185,80 metrów kwadratowych powierzchni itd.
Teraz jednak chcemy, aby nasza sieć przeglądała obrazy. W jaki sposób tego dokonać?
Odpowiedź na to pytanie jest niezwykle prosta. Sieć neuronowa pobiera liczby jako dane wejściowe. Dla komputera każdy obraz stanowi tak naprawdę wykres cyfr, które reprezentują dane informujące o natężeniu czerni w każdym pikselu:
Zatem aby obraz cyfry 8 mógł być przetworzony w naszej sieci neuronowej, zostanie on potraktowany jako zbiór 324 cyfr (324, ponieważ 18x18 piksel).
Aby było to możliwe, musimy zwiększyć naszą sieć, by miała 324 połączenia wejściowe:
Zauważmy, że nasza sieć neuronowa ma także dwa wyjścia (zamiast jednego). Pierwsze wyjście będzie przewidywało prawdopodobieństwo, że dany obraz reprezentuje cyfrę 8, a drugie wyjście będzie przewidywać prawdopodobieństwo, że dany obraz nie jest cyfrą 8. Stworzenie oddzielnych wyjść dla każdego typu obiektu, który chcemy rozpoznawać, umożliwia nam użycie sieci neuronowej do klasyfikacji obiektów w grupy.
Nasza sieć neuronowa jest o wiele większa niż poprzednia (324 wejścia zamiast 3!) Współczesne komputery, czy nawet telefony komórkowe są w stanie bez problemów przetwarzać takie ilości danych w sieci neuronowej.
Zostało więc tylko wytrenowanie naszej sieci neuronowej przy użyciu obrazów przedstawiających cyfrę osiem i inne cyfry, aby nauczyć ją rozpoznawania ósemki. Nauczymy ją, że prawdopodobieństwo obrazu z ósemką jest stuprocentowe, a obrazu zawierającego inną cyfrę − zero procent.
Oto przykład naszych danych uczących:
Jesteśmy w stanie wytrenować taki rodzaj sieci neuronowej w kilka minut na nowoczesnym laptopie. Kiedy ukończymy proces uczenia naszej sieci, będzie ona w stanie rozpoznawać obrazy odręcznie napisanej cyfry osiem z niezłą dokładnością.
Witajcie w erze rozróżniania obrazów późnych lat osiemdziesiątych!
Ograniczone pole widzenia
Czy to nie świetne, że jesteśmy w stanie po prostu pakować w naszą sieć neuronową piksele, aby otrzymać rozpoznawanie obrazu? Nie tak szybko, oczywiście, nie jest to aż takie proste.
Po pierwsze, korzystna wiadomość jest taka, że nasz „rozpoznawacz” cyfry 8 naprawdę nie ma problemu z prawidłowym rozpoznaniem znaków, gdy cyfra znajduje się na środku obrazu:
Po drugie, niestety, mam bardzo złą wiadomość, a mianowicie taką, że nasz „rozpoznawacz” kompletnie rozłożył się na rozpoznawaniu znaków, które nie są na środku obrazu. Wystarczy najmniejsza zmiana w pozycji cyfry 8, a sieć neuronowa kompletnie wysiada. Nie wspominając już o zmianie perspektywy itp.
Powodem jest to, że sieć nauczyła się wzoru rozpoznawania cyfry 8, gdy ta jest dokładnie na środku obrazu. I nie ma żadnego pojęcia o tym, co oznacza pozycja odbiegająca od środkowej. Nauczyła się rozpoznawania tylko jednego wzorca.
Widzimy więc, że nie jest to bardzo użyteczne rozwiązanie w naszej rzeczywistości. Problemy pojawiające się w realnym świecie nigdy nie są tak proste i jasne. Co musimy zatem zrobić, aby sieć neuronowa była w stanie rozpoznawać cyfrę 8, która nie jest umieszczona dokładnie na środku obrazu?
Prosty pomysł to wyszukiwanie za pomocą przesuwającego się okna. Co się stanie, gdy będziemy przeszukiwać cały obraz w poszukiwaniu ósemki fragment po fragmencie − aż do jej wykrycia?
To podejście nazywa się metodą przesuwającego się okna (sliding window). Jest to rozwiązanie prymitywne i sprawdzające się w ograniczonej liczbie przypadków, a do tego mało wydajne. Trzeba sprawdzać obraz w nieskończoność, wyszukując obiekty o różnych rozmiarach. Stać nas na więcej niż takie rozwiązanie!
Inny prymitywny pomysł to zwiększenie ilości danych wejściowych oraz zastosowanie głębokiej sieci neuronowej.
Podczas procesu uczenia naszej prostej sieci neuronowej stosowaliśmy dane przedstawiające wyśrodkowaną cyfrę 8. A co się stanie, gdy spróbujemy wytrenować sieć z większą ilością danych, dostarczając ósemek w różnych pozycjach i rozmiarach na obrazie?
Do tego celu nie musimy nawet zbierać dodatkowych danych. Napiszemy skrypt, aby wytworzyć ósemki w wielu różnorodnych pozycjach i rozmiarach przy użyciu obrazów z bazy danych, które już mamy:
W ten sposób możemy z dużą łatwością tworzyć nieskończone zasoby danych uczących.
Większa ilość danych komplikuje zadanie naszej sieci neuronowej, ale możemy sobie z tym poradzić przez powiększenie sieci i tym samym umożliwienie jej analizy bardziej złożonych wzorców.
Aby powiększyć naszą sieć, powielamy jej warstwy wraz z połączeniami:
Skonstruowaliśmy tak zwaną głęboką sieć neuronową − ma ona o wiele więcej warstw niż tradycyjna sieć.
To rozwiązanie jest dostępne od późnych lat sześćdziesiątych, ale jeszcze do niedawna uczenie maszynowe tak złożonych sieci neuronowych było zbyt wolne, aby mogło być praktyczne. Stało się użyteczne i możliwe do szerokiego zastosowania, dopiero gdy zastąpiono zwykłe procesory w komputerach kartami graficznymi (zaprojektowanymi do bardzo szybkiego powielania macierzy). Ta sama karta Nvidia GeForce GTX 1080Ti, której używasz do grania, choćby w Overwatch, może służyć do uczenia sieci neuronowej z niesamowitą szybkością.
Mimo że możemy powiększyć sieć neuronową oraz bardzo szybko wytrenować za pomocą karty graficznej 3D, to jeszcze nie jesteśmy w stanie uzyskać zadowalającego nas rezultatu w rozpoznawaniu obiektów. Musimy użyć innych rozwiązań, aby sieć wychwytywała wzorce w celu ich klasyfikacji.
Jeśli zastanowimy się przez chwilę, to tak naprawdę nie ma sensu osobne uczenie sieci, aby rozpoznawała ósemki w górnej części obrazu oraz ósemki w dolnej części, jakby to były kompletnie odrębne obiekty.
Potrzebny jest nam sposób, aby tak zaprojektować sieć neuronową tak, by umiała znaleźć ósemkę niezależnie od pozycji na obrazie, ale bez żadnych dodatkowych kroków uczenia. Na szczęście taki sposób już istnieje i nosi nazwę konwolucji.
Konwolucyjne sieci neuronowe
Intuicyjnie wiemy, że każdy obraz ma pewną hierarchię albo strukturę koncepcyjną.
Weźmy za przykład to oto zdjęcie:
- Drewniana podłoga.
- Na zdjęciu jest mydełko w kształcie dziecka.
- Dziecko leży na poduszce, która znajduje się na drewnianej podłodze.
Najważniejsze w wypadku tego zdjęcia jest to, że niezależnie od typu powierzchni jesteśmy pewni, że widzimy właśnie mydełko w kształcie dziecka. Dla ludzkiej percepcji niezależnie od jakiejkolwiek zmiany typu powierzchni mydełko będzie zawsze mydełkiem − nie musimy się ponownie zaznajamiać z koncepcją mydełka.
Niestety, jest to umiejętność, której nasza prosta sieć neuronowa nie ma. Dla niej cyfra 8 poza pozycją środkową na obrazie jest traktowana jako kompletnie inny obiekt. Nasza sieć nie pojmuje, że zmiana położenia cyfry nie wpływa na tę cyfrę. A zatem sieć musi mieć możliwość ciągłego uczenia się, aby rozpoznawać ósemkę w każdej możliwej pozycji na zdjęciu.
Trzeba więc dostarczyć sieci neuronowej możliwości translacji inwariancji − cyfra 8 pozostanie zawsze tą samą cyfrą niezależnie od pozycji, w jakiej pojawi się na zdjęciu.
Dokonamy tego, używając procesu, który nazywa się konwolucją. Pomysł konwolucji wziął się po części z nauk informatycznych, ale też po części z biologii (jacyś opętani naukowcy zgłębiali zasadę przetwarzania obrazów przez kocie mózgi).
Zasada działania konwolucji jest intuicyjna. Zamiast dostarczać do naszej sieci danych wejściowych w formie całych obrazów w postaci cyfrowej, dokonamy czegoś bardziej inteligentnego − wykorzystamy koncepcję, że dowolny obiekt pozostaje niezmiennie tym samym obiektem niezależnie od pozycji zajmowanej na obrazie.
Krok po kroku do naszego rozwiązania:
Etap 1: Podzielmy obraz na nakładające się na siebie kwadraty przypominające przesuwające się okno na ilustracji powyżej. Następnie przesuńmy sliding window nad każdym fragmentem i zapiszmy każdy wynik jako oddzielne dane:
W ten sposób zamieniliśmy nasz oryginalny obraz w 77 malutkich kwadracików o tych samych rozmiarach.
Etap 2: Załadujmy każdy mały fragment oddzielnie do sieci neuronowej. Wcześniej dostarczyliśmy cały obraz cyfry 8. Teraz zrobimy dokładnie to samo, ale będą to oddzielne fragmenty:
Ważne jest, abyśmy utrzymali te same wagi sieci neuronowej dla każdego elementu. Jednym słowem, traktujemy każdy pojedynczy fragment na równi z innymi. Jeśli pojawi się coś interesującego na którymkolwiek fragmencie, to możemy zaznaczyć, że jest on w jakiś sposób szczególny.
Etap 3: Zapiszmy wyniki z każdego wczytanego fragmentu w nowy zbiór, aby nie zatracić oryginalnego układu całości. Zachowamy informację z każdego fragmentu na siatce, która będzie wiernie odwzorowywała oryginalny obraz. Wygląda to następująco:
Inaczej to ujmując, zaczęliśmy od dużego obrazu, a skończyliśmy na niewiele mniejszym zbiorze małych elementów całości, które odwzorowują całość, ale niektóre z nich zaznaczone są jako najbardziej interesujące.
Etap 4: Przejdźmy do zmniejszania ilości danych. Wynikiem etapu 3 było uzyskanie zbioru elementów całego obrazu, ale z zaznaczonymi najbardziej interesującymi fragmentami oryginału. Ten zbiór jest ciągle dość duży.
Aby zmniejszyć ilość danych, posłużymy się algorytmem nazwanym warstwą zbiorczą (max pooling). Brzmi to skomplikowanie, ale tak naprawdę nie jest to wcale bardzo trudne.
Dokonaliśmy przeglądu każdego kwadratu 2x2 ze zbioru, zatrzymując największe numery.
Kierowaliśmy się zasadą, że gdy znaleźliśmy coś interesującego w każdym z czterech kwadratów stanowiących dane wejściowe fragmentów na siatce o wymiarach 2x2, to zatrzymujemy tylko te części, które nas najbardziej interesują.
To powoduje zmniejszenie zbioru danych i jednocześnie zachowanie najbardziej istotnych dla nas fragmentów całości.
Etap kończący: Teraz dokonamy wstępnego prognozowania. Do tej pory udało się nam zredukować ogromny obraz naszej cyfry do dość małego zbioru danych.
Ten zbiór to po prostu cyfry i możemy ich użyć jako danych wejściowych dla następnej sieci neuronowej. Ta ostatnia sieć neuronowa zadecyduje o tym, czy nasz obraz zgadza się z wzorcem, czy też nie. Aby odróżnić ten etap od konwolucji, określimy go jako sieć całkowicie podłączoną.
Od etapu początkowego do końcowego nasze działania można podsumować następująco:
Dodawanie jeszcze większej liczby etapów
Nasza linia produkcyjna przetwarzania obrazu składa się teraz z kolejnych etapów: konwolucji, warstwy zbiorczej oraz końcowej całkowicie połączonej sieci neuronowej.
Aby rozwiązywać skomplikowane zadania ze świata rzeczywistego, możemy łączyć i nakładać te wszystkie procesy w dowolnych ilościach. Możemy utworzyć więcej warstw sieci konwolucyjnej − od dwóch nawet do dziesięciu (więcej rzadko się stosuje). Za każdym razem można posłużyć się warstwami zbiorczymi, czyli ekstrakcją najistotniejszych informacji z równoczesną dyskryminacją innych danych, aby zmniejszyć ich ilość.
Podstawowym założeniem jest tutaj, aby zacząć od dużego obrazu i kontynuować jego zmniejszanie, krok po kroku, aż uzyskamy pożądany przez nas wynik. Dodawanie większej liczby warstw konwolucyjnych doprowadzi do większej ilości cech, które nasza głęboka sieć neuronowa będzie w stanie rozpoznać.
Dla przykładu można podać, że pierwszy etap konwolucji może rozpoznawać ostre krawędzie, w drugim etapie możemy dodać rozpoznawanie dziobów na podstawie wiedzy o ostrych krawędziach, trzecia warstwa konwolucyjna może już rozpoznać całego ptaka, opierając się na wiedzy o dziobie − i tak dalej.
Oto przykład bardziej realistycznej sieci konwolucyjnej:
W tym przypadku tworzenie sieci zapoczątkowano od obrazu o wymiarach 224x224 pikseli i dodano konwolucję oraz warstwę zbiorczą danych dwa razy. Następnie dodano trzy dodatkowe warstwy konwolucyjne oraz powtórzono utworzenie warstwy zbiorczej danych i dwóch warstw całkowicie połączonych. W rezultacie otrzymano klasyfikację danego obrazu bazującą na 1000 różnych kategorii!
A jak dowiemy się, które z tych etapów musimy połączyć, aby nasz „wykrywacz” obrazów działał jak najlepiej?
Szczerze mówiąc, jedyną dobrą odpowiedzią na to pytanie jest wykonanie wielu eksperymentów oraz prób. Może się okazać, że musimy nauczyć około 100 warstw sieci neuronowych, zanim osiągniemy optymalne parametry i strukturę dla zadania, które mamy rozwiązać. Uczenie maszynowe to ciągłe uczenie się na błędach.
Klasyfikator obrazów na Google Colaboratory
Podobnie jak w artykule o tłumaczeniu maszynowym przygotowaliśmy dla was interaktywne demo zakodowane w języku Python na platformie Google Colaboratory. Uruchamiamy je w analogiczny sposób, a niezbędne pliki można pobrać.
Spróbujemy stworzyć model, który będzie rozpoznawał marki starych polskich samochodów. Dostępnych jest 2400 oznakowanych zdjęć samochodów do szkolenia i 270 w zestawie testowym, które musimy spróbować opatrzyć etykietą. Spójrzmy zatem na kod.
Tutaj importujemy niezbędne biblioteki (do czego one służą, dowiemy się z dalszej lektury):
PATH jest ścieżką do twoich danych − jeśli użyjesz zalecanych metod konfiguracji przedstawionych w tym artykule, nie będziesz musiał tego zmieniać.
sz to rozmiar, do którego obrazy zostaną przeskalowane w celu zapewnienia szybkiego przebiegu uczenia. Zostawmy na razie 224 piksele.
Ważne jest, aby mieć działający układ GPU NVidia. Schemat programowania używany do pracy z procesorami graficznymi NVidia nosi nazwę CUDA. Dlatego zanim zaczniesz kontynuować, musisz upewnić się, że następująca linia zwraca wartość True. Jeśli masz z tym problemy, to znaczy, że Colaboratory nie został prawidłowo skonfigurowany.
Ponadto NVidia zapewnia specjalne funkcje zoptymalizowane do głębokiego uczenia zawarte w pakiecie o nazwie CuDNN. Chociaż nie jest to bezwzględnie konieczne, znacznie poprawi wydajność i jest domyślnie uwzględnione we wszystkich obsługiwanych konfiguracjach FastAI. Dlatego jeśli poniższy kod nie zwróci wartości True, warto sprawdzić, dlaczego.
Nasza biblioteka zakłada, że masz katalogi train i valid. Zakłada się także, że każdy katalog będzie zawierał podkatalogi dla każdej klasy, która ma zostać rozpoznana (w tym przypadku maluch, polonez itp.). Jest to wygodnie, bo jeżeli zechcesz rozpoznawać inne auta, wystarczy, że wgrasz je do folderów, bez konieczności kodowania.
Oto jak wyglądają dane surowe:
Użyjemy wstępnie wyszkolonego modelu, czyli modelu stworzonego przez kogoś innego, aby rozwiązać inny problem. Zamiast budować model od zera, aby rozwiązać analogiczny problem, jako punkt wyjścia wykorzystamy model przeszkolony na danych ImageNet (1,2 miliona obrazów i 1000 klas). Model ten to właśnie duża sieć konwolucyjna.
Będziemy używać modelu resnet34, który wygrał konkurs ImageNet 2015. Tutaj jest więcej informacji na temat modeli resnet.
Poniżej przedstawiono sposób szkolenia oraz ocenę marki starego polskiego samochodu w trzech liniach kodu i czasie poniżej 20 sekund z wykorzystaniem gotowego modelu:
Jak dobry jest ten model? Kilka lat temu w podobnym zadaniu stan techniki umożliwiał osiągnięcie 80-procentowej dokładności. Ale Kaggle spowodowało ogromny skok celności − do 98,9%, a autor popularnej biblioteki dogłębnej nauki zwyciężył w konkursie.
Warto przyjrzeć się nie tylko ogólnym wskaźnikom, ale też przykładom każdego z nich:
- Kilka poprawnych etykiet losowo
- Kilka nieprawidłowych etykiet losowo
- Najbardziej poprawne etykiety każdej klasy (tj. te z najwyższym prawdopodobieństwem poprawne)
- Najbardziej niepoprawne etykiety każdej klasy (tj. te z najwyższym prawdopodobieństwem nieprawidłowe)
- Najbardziej niepewne etykiety (tj. te z prawdopodobieństwem najbliższym 0,5)
Stąd wiemy, że maluch to etykieta 0, a polonez to etykieta 1.
To polecenie daje przewidywanie dla zestawu sprawdzania poprawności. Prognozy są w skali logarytmicznej
Kilka poprawnych etykiet losowo:
Kilka niepoprawnych etykiet losowo:
Etykiety dla malucha, które zostały rozpoznane z największą trafnością:
Etykiety dla poloneza, które zostały rozpoznane z największą trafnością:
Etykiety dla malucha, które zostały rozpoznane z najmniejszą trafnością:
Etykiety dla poloneza, które zostały rozpoznane z najmniejszą trafnością:
Najbardziej niepewne predykcje:
Taka analiza danych powinna nas naprowadzić na ścieżkę do poprawy danych celem zwiększenia precyzji.
Metoda learn.lr_find() pomaga znaleźć optymalną prędkość uczenia się. Wykorzystuje technikę opracowaną w 2015 roku i opisaną w publikacji Cyclical Learning Rates for Training Neural Networks. Technika ta polega na tym, że po prostu ciągle zwiększana jest szybkość uczenia z bardzo małej wartości, aż strata przestaje maleć. Możemy określić szybkość uczenia się dla różnych partii, aby zobaczyć, jak to wygląda.
Najpierw tworzymy nowego ucznia, ponieważ chcemy wiedzieć, jak ustawić tempo uczenia się dla nowego (niewytrenowanego) modelu.
W naszym obiekcie learn jest atrybut sched, który zawiera nasz program do planowania szybkości uczenia się i ma kilka wygodnych funkcji kreślenia, w tym:
Widzimy wykres straty w stosunku do wskaźnika uczenia się, aby zobaczyć, gdzie zmniejsza się nasza strata:
Strata wciąż wyraźnie poprawia się w lr = 1e-2 (0.01), więc tego używamy. Zwróć uwagę, że optymalna szybkość uczenia się może się zmieniać podczas treningu modelu, więc możesz chcieć ponownie uruchomić tę funkcję od czasu do czasu.
Jeśli spróbujesz treningu na większej liczbie epok, zauważysz, że zaczynamy przetrenowywać sieć, co oznacza, że model uczy się rozpoznawać konkretne obrazy w zbiorze treningowym, a nie generalizować tak, że uzyskujemy również dobre wyniki na zestawie walidacyjnym. Jednym ze sposobów rozwiązania tego problemu jest efektywne tworzenie większej ilości danych dzięki rozszerzeniu danych. Odnosi się to do losowej zmiany obrazów w sposób, który nie powinien wpływać na ich interpretację, taki jak przekręcanie w poziomie, powiększanie i obracanie z kadrowaniem.
Możemy to zrobić, przekazując aug_tfms (augmentation transforms) dotfms_from_model z listą funkcji do zastosowania, które losowo zmieniają obraz, jak tylko chcemy. W przypadku zdjęć, które są w dużej mierze robione z boku (np. większość zdjęć samochodów, w przeciwieństwie do zdjęć zrobionych od góry do dołu, takich jak zdjęcia satelitarne), możemy użyć wstępnie zdefiniowanej listy funkcji transforms_side_on. Możemy również określić losowe powiększanie obrazów do określonej skali, dodając parametr max_zoom.
Stwórzmy nowy obiekt data, który obejmuje to rozszerzenie transformacji.
Po ponownym treningu widzimy, że precyzja poprawiła się z 80% do 85,71%.
Domyślnie, gdy tworzymy ucznia, ustawia on wszystkie warstwy oprócz ostatniej na zamrożone. Oznacza to, że wciąż aktualizuje wagi tylko w ostatniej warstwie, a warstwy resnet34 nie są modyfikowane.
Czym jest parametr cycle_len? To, co tutaj zrobiliśmy, to technika zwana stochastycznym spadkiem gradientu z restartem (SGDR), wariantem wyżarzania szybkości uczenia, które stopniowo zmniejsza szybkość uczenia się w miarę postępu treningu. Jest to pomocne, ponieważ gdy zbliżamy się do optymalnych wag, chcemy podjąć mniejsze kroki.
Jednakże możemy znaleźć się w części przestrzeni wagi, która nie jest bardzo odporna − to znaczy niewielkie zmiany masy mogą spowodować duże zmiany w stratach. Chcemy zachęcić model do znalezienia części przestrzeni wagi, które są zarówno dokładne, jak i stabilne. Dlatego od czasu do czasu zwiększamy szybkość uczenia (jest to restart w SGDR), co zmusi model do przejścia do innej części przestrzeni wagi, jeśli obecny obszar jest „spiczasty”. Oto obraz tego, jak to może wyglądać, jeśli zresetujemy współczynniki uczenia się trzy razy (w tym dokumencie nazywa się to cyklicznym harmonogramem LR):
Liczba epok pomiędzy resetowaniem współczynnika uczenia się jest ustalana przez cykl_liczba, a liczba razy, kiedy to się dzieje, jest określana jako liczba cykli , i jest tym, co faktycznie przekazujemy jako drugi parametr do dopasowania. Oto jak wyglądały nasze rzeczywiste wskaźniki uczenia się:
Nasza strata w zakresie walidacji nie poprawia się w znacznym stopniu, więc prawdopodobnie nie ma potrzeby dalszego szkolenia ostatniej warstwy na własną rękę. Precyzja po tym zabiegu przekracza już 88%.
Ponieważ w tym momencie mamy całkiem niezły model, możemy chcieć go zapisać, abyśmy mogli go później załadować ponownie bez szkolenia od zera.
Teraz, gdy mamy już wytrenowaną dobrą warstwę końcową, możemy spróbować dopracować pozostałe warstwy, czyli nasz resnet34. Aby zakomunikować uczniowi, że chcemy odblokować pozostałe warstwy, wystarczy użyć Unfreeze ().
Zauważ, że pozostałe warstwy zostały już przeszkolone do rozpoznawania zdjęć ImageNetowych (podczas gdy nasze końcowe warstwy zostały losowo zainicjowane), więc powinniśmy uważać, aby nie zniszczyć dokładnie wyregulowanych wag, które już tam są.
Generalnie, wcześniejsze warstwy mają więcej funkcji ogólnego przeznaczenia. Dlatego oczekiwalibyśmy, że będą potrzebowały mniejszego dostrajania nowych zestawów danych. Z tego powodu użyjemy różnych współczynników uczenia dla różnych warstw: pierwsze kilka warstw będzie na poziomie 1e-4, środkowe warstwy na poziomie 1e-3, a nasze warstwy − 1e-2, tak jak poprzednio. Mówimy o tym jako o zróżnicowanych wskaźnikach uczenia się, chociaż nie ma standardowej nazwy dla tej technologii w literaturze, o której nam wiadomo.
Kolejną sztuczką, której tutaj użyliśmy, jest dodanie parametru cycle_mult.
Cykle są mierzone w epokach, więc cycle_len = 1 samo w sobie oznaczałoby ciągłe zmniejszanie szybkości uczenia się w trakcie jednej epoki, a następnie przeskakiwanie z powrotem do góry. Parametr cycle_mult mówi, aby pomnożyć długość cyklu przez coś (w tym przypadku przez 2), jak tylko ukończysz jeden cykl.
Zauważ, że to, co przedstawiono powyżej, to wskaźnik uczenia się ostatnich warstw. Współczynniki uczenia się wcześniejszych warstw są ustalane na tych samych wielokrotnościach ostatecznych poziomów warstw zgodnie z pierwotnym żądaniem (pierwsze warstwy mają 100x mniejsze, a warstwy średnie 10x mniejsze szybkości uczenia się, ponieważ ustawiamy lr = np.array ([ 1e-4,1e-3,1e-2]). To wszystko skutkuje precyzją przekraczającą 95%.
Jest jeszcze coś, co możemy zrobić z wcześniej dokonanym rozszerzeniem danych: użyjemy go w czasie wnioskowania (znanym również jako czas testu(TTA)).
TTA po prostu tworzy prognozy, nie tylko na obrazach w twoim zbiorze testowym, ale także tworzy prognozy dla pewnej liczby losowo rozszerzonych ich wersji (domyślnie używa oryginalnego obrazu wraz z czterema losowo rozszerzonymi wersjami). Następnie pobiera średnie prognozy z tych obrazów i wykorzystuje je. Aby użyć TTA w zestawie sprawdzania poprawności, możemy skorzystać z metody "TTA ()" ucznia.
Pozwala to zbliżyć się do 96%.
Dalszej poprawy możemy starać się uzyskać poprzez analizę wyników i wnioskowanie. Pomocna będzie macierz błędów (tablica pomyłek):
Popularnym sposobem analizy wyniku modelu klasyfikacyjnego jest użycie macierzy błędów. Scikit Learn ma wygodną funkcję, którą możemy wykorzystać do tego celu:
Możemy po prostu wydrukować macierz błędów lub wyświetlić widok graficzny (który jest przydatny głównie dla osób z większą liczbą kategorii).
Ponowne spojrzenie na zdjęcia:
Podsumowując: podjęliśmy proste kroki do wyszkolenia klasyfikatora obrazu światowej klasy.