Written by 12:58 am Deep Learning

Deep learningowy kalendarz adwentowy 2021

24 dni treści o sieciach neuronowych do analizy obrazu – rzecz się działa na Linkedinie w grudniu 2021 roku. Postanowiłem jednak te treści udostępnić również tutaj – w jednym miejscu, by ułatwić przejście przez nie (taki był plan). Zapraszam!

1. Do czego sieci neuronowe w analizie obrazu?

Czy chcemy policzyć obiekty czy wiedzieć o każdym pikselu?
Czy chcemy policzyć obiekty czy wiedzieć o każdym pikselu?

Mówiąc o sieciach neuronowych, oczywiście mam na myśli sieci głębokie, a potocznie spotkasz się częściej z określeniej AI, sztuczna inteligencja. Jednakże nie daj się zwieźć chwytliwym hasłom. To tylko sekwencja działań jakie są wykonywane aby uzyskać najlepszy wynik. Najlepszy wg jakiejś konkretnej metryki, na jakimś konkretnym zbiorze -> nie zadziała to zawsze.

No ale do czego te głębokie sieci neuronowe mogę wykorzystać w analizie obrazu!? Sporo możemy zrobić i sporo nie.

No alt text provided for this image

Mając przykłady par – wejście, wyjście, w teorii możemy to zautomatyzować siecią neuronową. W praktyce – nie do końca. Przydaje się by wyjścia zależały od wejść. Czyli by istniała funkcja która przekształci wyjście w wyjście, by była tam przyczynowość. Oczywiste? Tutaj niby tak, a w praktyce nie zawsze. Na szczęście w obrazie często tak. Najprostsze zadanie to predykcja jakiejś wartości na podstawie obrazu (regresja), albo klasyfikacja (multi-class – wybór 1 z n). Są też szczególne przypadki, jak np. klasyfikacja binarna (1 z 2) czy multi-label (wiele z n), a w ogólności możemy sobie wyobrazić zagadnienie multi-task (wiele wyjść, osobnych zadań – np. kilka klasyfikacji). Te techniki pozwalają odpowiedzieć na zagadnienie na podstawie całego obrazu.

Z tych prostych zadań możesz zbudować wiele zastosowań np. predykcję etykiety 1 z n dla każdego piksela (segmentacja semantyczna), czy klasyfikacja z regresją (wykrywanie obiektów). Więcej zagadnień poniżej – wpierw praktyczna lista z przykładami architektur – nie wszystkie są najnowsze niestety.

  • Wykrywanie obiektów (YOLOv5, YOLOv4, ScaledYOLOv4, YOLOR)
  • Segmentacja semantyczna (UNet, DeepLab v3+)
  • Segmentacja instancji (Mask RCNN, YOLACT, DETR)
  • Panoptic segmentation (Panoptic FPN, Panoptic DeepLab, DETR, SOGNet)
  • Wykrywanie punktów charakterystycznych (Alpha Pose, OpenPose, CrowdPose, Google MediaPipe)
  • Estymacja głębi (MegaDepth, Vid2depth)
  • Image 2 image (CycleGAN, Pix2PixHD)
  • Next frame prediction (Conv LSTM, Pix2Pix, PredNet)
  • Image matching (SuperPoint, SuperGlue)
  • Localization (Google PlaNet, DeepGeo)
  • SuperResolution (RealSR ncnn Vulkan)
  • Style Transfer (fast-style-transfer, StyleGAN3)
  • Image Colorization (InstColorization)
  • Image Inpainting (DMFN)
  • Image Captioning (Transform and Tell, CLIP)
  • OCR (Keras OCR, mmOCR)

Co rozumiemy przez termin wykrywanie obiektów (object detection)? Zaznaczenie prostokątami prostopadłymi do osi obrazu wszystkich obiektów, które nas interesują. Każdego człowieka, każdą tablicę rejestracyjną, każdy defekt, każdy obiekt który chcemy zliczyć, śledzić, itp. Może to być bakteria pod mikroskopem, dron na niebie, ryba w wodzie, intruz przed domem, osoby nie utrzymujące odległości w przestrzeni publicznej, produkty na półkach w sklepie, obecność paragonu z parkometru za szybą pojazdu, gwiazdy, planety, grzyby, muszelki na plaży. Wejściem jest obraz wyjściem jest zbiór ramek, każda z 4 współrzędnymi (np. xmin, xmax, ymin, ymax, albo xc, yc, width, height), prawdopodobieństwem i klasą. Jedna sieć może rozpoznawać wiele rodzajów obiektów np. człowiek, samochód, ciężarówka, motor, itd. Zdarza się i 500 kategorii (zobacz zbiór Open Images v6).

Segmentacja semantyczna (semantic segmentation) to zgoła inne zadanie. Tutaj otrzymujemy klasę dla każdego piksela obrazu. Brzmi super, jest super, ale nie pozwala policzyć obiektów, jeżeli te obiekty nachodzą na siebie otrzymamy jedną plamę. Do czego to się sprawdzi? Oszacowanie ile procent obrazu zajmuje jakaś klasa, gdzie jest droga, gdzie chodnik, wyznaczenie przejezdnej drogi, pomiar objętości na podstawie zdjęcia, zmiany w płucach, części ciała, gdzie jest próchnica na zębach, wykrywanie włosów by zmienić ich kolor, czy banknot jest prawdziwy – czy ma te wszystkie rzeczy, z drona – gdzie woda, drzewa itd. Wejściem jest obraz, a wyjściem jest klasa per piksel, a tak na prawdę N warstw z prawdopodobieństwami. Tu również znajdziesz wiele gotowców, na tę chwilę polecę DeepLab v3+ z ResNetem 101. Jeśli chodzi o trening własnej sieci – jest jeszcze gorzej – potrzebne są dane, gdzie każdy piksel jest poprawnie sklasyfikowany. Dobrze Ci się wydaje, to może trochę potrwać. Zwykle robi się to z wykorzystaniem poligonów – obklikujemy kształty, a co zostaje to jakieś tło, niebo czy cokolwiek tam jest w naszym zagadnieniu.

No dobrze, a co gdybyśmy chcieli rozróżniać obiekty i jednocześnie mieć ich kontury?Wtedy wchodzi Segmentacja instancji! Jako wynik otrzymujemy zbiór obiektów wraz z klasą i maską (no bardziej to maska niż kontur,bo to jest obraz wielkości całego obrazu z wartościami 0, 1 w zależności czy to dany obiekt czy nie). Co z tym zrobić można? Wycinać ludzi z tła dowolnego (telekonferencje bez green screena), zliczanie obiektów z informacją ile te obiekty zajmują pikseli na zdjęciu,bakterie może, drzewa i budynki z drona, wykrywanie zawartości półek sklepowych. Wejście możesz mieć jako zbiory poligonów/masek per obiekt, albo jako zdjęcie, obraz z klasami dla każdego piksela oraz obraz z numerami obiektu (tak by rozróżnić obiekty).

Poprzednie podejścia nie były kompletne – w segmentacji semantycznej brakuje rozróżnienia obiektów, natomiast segmentacja instancji nie rozpoznaje tła, rzeczy niepoliczalnych. Jest rozwiązanie, które łączy te 2 podejścia: Panoptic segmentation. Pierwsze rozwiązania faktycznie łączyły wyniki dwóch sieci, w nowszych modelach jest to już lepiej integrowane. To już kompleksowe rozwiązanie – dowiemy się gdzie są budynki, niebo, droga,a jednocześnie zliczymy samochody wiedząc, które piksele do nich należą. Masz może pomysł gdzie jeszcze to się może przydać? Tu podobnie – warto zwrócić uwagę na DETRa.

Czy znasz może sensor Kinect? Ten co zrewolucjonizował robotykę onegdaj. Otóż jest on kamerą głębi czyli RGBD (oprócz koloru jest odległość per piksel), mniejsza o działanie. Dzięki głębi otrzymywaliśmy z sensora pozę człowieka – położenia w 3D punktów charakterystycznych człowieka. Wykrywanie punktów charakterystycznych możemy zrobić bez informacji o głębi, wykorzystując głębokie sieci neuronowe. Co możemy zrobić – wykryć gdzie są kolana, łokcie, ramiona, oczy nos, kontur głowy, uszy, palce, źrenice. Także poza zwierząt czy owadów (tu są gotowce). Tu można by próbować wykrywać też punkty na jakichś interesujących nas obiektach, może w przemyśle, produkcji. Wspaniałą siecią do wykrywania punktów charakterystycznych była OpenPose, wciąż fajne rozwiązanie, warto zerknąć. Ale koniecznie spojrzyj też na MediaPipe od Google. MediaPipe to implementacje sieci na telefony komórkowe – między innymi wykrywanie punktów charakterystycznych – pozy człowieka, na dłoni, na twarzy, lokalizacja oczu.

Istnieją też sieci wytrenowane, aby na podstawie pojedynczego zdjęcia ocenić odległości do przedmiotów – Monocular depth estimation – jest takich rozwiązań wiele, choćby leciwy już MegaDepth.

No alt text provided for this image

Otwierającym oczy przykładem jest zamiana zdjęcia satelitarnego w mapę i na odwrót za pomocą sieci neuronowej Image 2 image. To jest na prawdę imponujące. Także takie rozwiązania jak zmiana dzień-noc, szkic-obraz, obraz czarnobiały-kolorowy,render kiepskiej jakości – render dobry (dzięki temu można renderować ray tracing z małą liczbą fotonów – szybko, a szum usuwa sieć), render z gry – zdjęcie z realnego świata (a propos pokonywania sim2real gap do np. autonomizacji samochodów). Co mogę w tym temacie polecić? Cóż by innego niż Pix2PixHD od Nvidii?! Swego czasu zrobiłem jeszcze z wersją pierwszą Pix2Pix w TF1: https://medium.com/@karol_majek/high-resolution-face2face-with-pix2pix-1024×1024-37b90c1ca7e8 Na bazie kodu Data Trana – zwiększyłem rozdzielczość do 1MPx. To był jeszcze 2017 rok, to w zasadzie prehistoria w DL.

Predykcja kolejnej klatki filmu – Next frame prediction – w najfajniejszym ujęciu, bardziej artystycznym niż praktycznym ale zawsze.Widok z okna pociągu: https://magenta.tensorflow.org/nfp_p2p W tych zastosowaniach wykorzystuje się także sieci Pix2Pix. Jest to podejście end to end, a są jeszcze sieci które wykonują predykcję dla poszczególnych obiektów, no i w sumie to możnaby je klasycznymi metodami śledzić i wykonywać predykcję ich położenia (choćby filtr Kalmana).

Image matching – czyli znajdowanie odpowiadających sobie punktów charakterystycznych pomiędzy zdjęciami. To się przydaje do lokalizowania na podstawie zdjęć, budowania modeli 3D ze zdjęć, łączenia zdjęć w panoramy, sprawdzania pokrycia pomiędzy zdjęciami. Tu koniecznie zobacz oba: SuperPoint, SuperGlue. Coś wspaniałego.

Odnośnie estymacji lokalizacji end to end na podstawie obrazu z wykorzystaniem głębokiego uczenia sprawdź Google PlaNet i DeepGeo. Myślę, że to bardziej ciekawostka, no chyba, że faktycznie masz taki problem (zdjęcia bez metadanych w EXIF).

Kojarzysz jak w serialach proszą o powiększenie tego zderzaka widzianego w odbiciu na okularach, by rozpoznać czyjąć twarz? W rzeczywistości możesz liczyć na powiększenie 4x, no może 16x. W tym pomoże Ci SuperResolution. Dzięki temu możesz kompresować filmy, powiększać kiepskiej jakości zdjęcia, wyniki algorytmów segmentacji skalować do większej rozdzielczości, no generalnie powiększać obrazy 🙂 Tu mocny konkret jeśli chodzi o implementację: RealSR ncnn VulkanW ogóle fajna rzecz NCNN od Tencent (na WSZYSTKIE platformy)

Modna onegdaj aplikacja na telefon Prisma pozwalała stylizować nasze zdjęcia na obrazy sztuki czy czego tam sobie nie wybierzemy jako źródło stylu. To zagadnienie nazywa się: Style Transfer. Jeśli szukasz implementacji by stylizować zdjęcia czy nawet filmy to spójrz na repozytorium fast-style-transfer na GitHubie. Czy są jakieś poza sztuką zastosowania przenoszenia stylu? Trening sieci neuronowncyh!

„Sami swoi” w kolorze. No teraz to z automatu takie rzeczy.Kolorowanie obrazu – Image Colorization. Koniecznie spójrz na tę implementację: https://github.com/ericsujw/InstColorizationz 2020, więc nie takie znowu stare, nawet python3 jest 🙂 Ta metoda wykorzystuje wykrywanie obiektów w celu poprawieniu wyników. Znacznie lepsze niż stare DeOldify.

Rekonstrukcja obrazu gdy mamy braki, albo celowo te braki tak wstawimy, by podmienić treść na wygenerowaną przez sieć. Nazywamy to Image Inpainting. Sieci rozwiązujące ten problem można wykorzystać choćby do anonimizacji zdjęć – wykrywamy twarze, maskujemy, sieć generuje twarze uzupełniając obraz.Także do usuwania okularów z twarzy, zmiany fryzury, usunięcia ludzi ze zdjęcia. Tak aby pokazać Ci jakie wyniki takie sieci uzyskują w 2020 roku: https://github.com/Zheng222/DMFN

Czy da się automatycznie wygenerować podpis pod obrazkiem? Da się! Zagadnienie Image Captioning just znane nie od dziś. Już w 2014 roku ukazał się artykuł „Show and Tell”, który adresował ten problem. W 2020 roku możesz oczekiwać opisu obrazy w kontekście do paragrafu tekstu dzięki „Transform and Tell”. Czy możnaby w ten sposób generować automatyczne diagnozy np. zdjęć rentgenowskich? Zapewne tak, ale to dalece niewyjaśnialne, a my chcemy znać przyczyny, przesłanki, więc raczej wolelibyśmy w tej sytuacji np. segmentację semantyczną. Zobacz też całkiem nowy model CLIP

OCR czyli Optical Character Recognition to rozpoznawanie znaków, odczytywanie tekstu wydrukowanego. Chcesz zrobić kolejna aplikację która automatycznie odczyta faktury?Wybierz KerasOCR, lub mmOCR! Niestety kiepsko w gotowym modelu że znakami polskimi, więc prawdopodobnie będziesz potrzebować wytrenować model z polskim alfabetem. Na wyjściu z KerasOCR otrzymasz lokalizację wraz z kątem (tekst może być obrócony)czyli taki prostokąt niekoniecznie prostopadły do ramki oraz tekst który z niego został odczytany. Dobry gotowiec wraz z procedurą uczenia, jeżeli potrzebujemy więcej znaków.

Czy zaskoczyłem Cię czymś nowym?

Może masz jakiś pomysł na podstawie powyższych przykładów? Pamiętaj, że pomysły są nic nie warte bez wykonania.

Więcej takich treści jest w mailingu DeepDrive.pl

2. Od zbioru danych do pierwszej sieci neuronowej

MNIST można zastąpić innymi MNISTami - warto przez to przejść
MNIST można zastąpić innymi MNISTami – warto przez to przejść

Pamiętam gdy bardzo chciałem wytrenować pierwszą własną sieć, żeby to tylko nie było na zbiorze MNIST. Chciałem móc mieć własne zdjęcia, do nich etykiety, jakkolwiek – w nazwie pliku, katalogu, czy też jako kolumna w csv. Cokolwiek, by tylko być w stanie wytrenować sieć, by rozpoznawała obiekty moje – wskazane przeze mnie.

Patrząc z perspektywy – zrozumienie jak działają sieci, ich trening jest mega ważne. Wyrobienie tej intuicji – co się stanie gdy zrobię x – co zrobić by stało się y – jest możliwe dzięki praktycznym eksperymentom. Super się sprawdza próba pokonania kolejnych swoich najlepszych wyników, poprzez zmianę architektury czy przetwarzania.

Tym razem chcę Ci przybliżyć wątpliwości i problemy które czekają Cię w procesie, zarówno nauki sieci neuronowych, jak i później w ich praktycznym stosowaniu. Wtedy też zaczynają mieć znacznie aspekty praktyczne, takie jak poniższe pytania:

  • Czy to nowy problem? Może ktoś to już robił? (raczej tak)
  • Czy istnieją rozwiązania? Może jest gotowy model na GitHubie? Zobacz koniecznie podobne problemy i rozwiązania (wyszukuj frazy po angielsku na GH)
  • Jak działają te rozwiązania dla naszych danych? Czy na pewno trzeba trenować sieć?
  • Czy mamy wiedzę domenową? Czy rozumiemy zagadnienie, rozwiązywany problem?
  • Czy znamy cel dla modelu? Ma być dokładny, szybki, czy może ma nie pominąć żadnego przypadku danej klasy?
  • Jakie błędy są ok, a jakie nie? Co tak na prawdę jest istotne?

Często przechodzimy od razu do implementacji własnego rozwiązania, które poprawiamy nie wiedzą co jest istotne. Można powiedzieć, że przyjmujemy kierunek ortogonalny do oczekiwanego, jak szybko byśmy nie szli nie przybliża nas to do celu ani trochę. Może warto nieco wolniej, a w dobrym kierunku?

Czy muszę zaprojektować własną sieć? Czy warto to robić? Do każdego problemu?! A czy można nie? Otóż można nie! Ale warto to zrobić by się nauczyć i zrozumieć jak one działają. Wiele architektur jest opracowanych i porównanych na dużych zbiorach danych przez dziesiątki osób w zespołach, wytrenowane przez wiele GPU-miesięcy, czy wręcz lat (!) Na szczęście community tworzące sieci neuronowe jest bardzo otwarte, także jeśli chodzi o udostępnianie kodów, ba, nawet wytrenowanych modeli (!) A jak być może wiesz nowe architektury sieci do klasyfikacji obrazu pojawiają się częściej niż comiesiąc (serio). Wykorzystując sprawdzoną architekturę otrzymujesz obietnicę sukcesu 🙂

Czy mój zbiór wystarczy? Ile potrzebuję mieć zdjęć? 100, 1000, a może wystarczy mi 1 lub 0? Czy do każdego zdjęcia potrzebuję mieć etykietę? Wielu naukowców pracuje nad tym aby zmniejszyć tę liczbę. Tu warto skorzystać, nie dość, że z gotowych archtiektur, to jeszcze z gotowych modeli (czyli sieci wytrenowanych na dużych zbiorach).

No, ale mój problem jest wyjątkowy! Jeżeli, Twoje zdjęcia pochodzą z kamer, to RACZEJ nie będą one zaskoczeniem. Można wykorzystać jeden z gotowych modeli dostosowując go wykorzystując transfer learning (podmieniamy końcówkę sieci – klasyfikator – i dotrenowujemy na naszym zbiorze). To jest jedno z podejść, które pomoże. A ile tych zdjęć potrzeba? No niestety nie ma prostej odpowiedzi, zależy to od tego czy Twoje obiekty występują w różnym:

  • oświetleniu (dzień, noc, cień, wiele źródeł światła, …)
  • barwie, nasyceniu, kontraście, teksturze (np. ubrania bywają różne)
  • otoczeniu (czy masz zdjęcia niedźwiedzia polarnego na sacharze?)
  • kształcie i rozmiarze (resorak, dwuosobowy Smart, Van, autobus czy ciężarówka – to wszystko samochody, nie?)

Im więcej tych różnic tym więcej potrzeba przykładów. Idealnie by mieć po równo przykładów per cechę (nawet, wręcz szczególnie, jeżeli jakaś cecha występuje mega rzadko – wtedy dobrze mieć jej tyle co tej częstej)

Jak i czy przetworzyć zdjęcia na wejściu sieci? Czy zmienić przestrzeń barw? Może wystarczy mi skala szarości, zamiast RGB? Jaką zastosować obróbkę obrazów?

  • usunięcie szumów (filtr medianowy, gaussian blur, a może odjęcie obrazu średniego?)
  • zmiana rozdzielczości (na mniejszą lub większą – zob. Super Resolution)
  • wyciąć obiekt precyzyjnie? (czy się nie rusza, czy łatwo go znaleźć?)
  • Zmiana przestrzeni barw (HSV, HSL, Lab, TSL, YUV, XYZ, YCbCr, …)
  • przekształcenie afiniczne (translacja, rotacja, skala), undistort; widok z góry itp.
  • może segmentacja semantyczna by coś wyszczególnić? Czyli rozwiążmy problem trudniejszy by rozwiązać prostszy.
  • Normalizacja vs standaryzacja
  • Enhancement – uwypuklenie cech – np. CLAHE, ZCA whitening

Jest wiele sposobów, które możesz wykorzystać by wstępnie przetworzyć dane. Dobrze jest wyrobić sobie intuicję odnośnie tych rozwiązań. Brakuje mi zdjęć, trudno je uzyskać, czy jest jakiś sposób? Co możesz zrobić w takiej sytuacji, bo warto o tym mówić, to zdarza się tak często, że raczej na pewno przytrafi się i Tobie.

Możesz próbować dane generować na podstawie przykładów, które już masz stosując techniki data augmentation!

Zastosuj zmiany:

  • kontrastu, jasności, gamma
  • nasycenia, balansu bieli, (uwaga – barwy nie ruszamy)
  • odbicia, obroty, scala, przesunięcia, przekoszenia
  • może symulowany brak kalibracji kamery?
  • wytnij/zasłoń losowy fragment obrazu
  • wykonaj style transfer
  • a może dodaj warunki pogodowe?

W tym celu oczywiście możesz skorzystać z pomocnych bibliotek, takich jak Albumentations oraz Kornia. [warto]

Jak zaprojektować architekturę sieci?

Po pierwsze – czy tego w zasadzie potrzebujesz skoro istnieje wiele dobry architektur? Jeżeli już – to koniecznie porównaj kluczowe parametry (czas obliczeń, accuracy, precision, a może recall?)

Kiedy raczej nie warto projektować własnej sieci?

  • gdy masz zdjęcia większe niż 64x64px
  • gdy twoje obiekty występują w bardzo wielu konfiguracjach
  • chcesz uzyskać najwyższą możliwą dokładność szybko
  • chcesz mieć dobre wyniki w racjonalnym czasie

Projektując własną sieć możesz skorzystać z warstw konwolucyjnych, tak, by zamienić obraz przestrzenny na jednowymiarowy wektor wartości, czyli wektor cech, który zostanie wykorzystany do klasyfikacji czy też regresji. Czyli ogólnie – budujesz model dzielący się na dwie części ekstrakcję cech oraz klasyfikację/regresję w zależności co jest Twoim celem.

Jaki framework użyć do uczenia?

Najpopularniejsze to oczywiście TensorFlow i PyTorch (PyTorch zdecydowanie do researchu, TF królował we wdrożeniach, ale sytuacja jest dynamiczna). W specyficznych przypadkach może wydać Ci się zasadne użycie Tencent NCNN, który jest dostępny na wielu architekturach sprzętowych. Kerasa (polecam) nie wymieniłem, bo to część TensorFlow od pewnego czasu. W ramach PyTorcha możesz użyć PyTorch Lightning (polecam), albo PyTorch Lightning Flash. Zaczynając warto korzystać z Kerasa lub PyTorch Lightninga. Jest jeszcze PyTorch Lightning Flash, ale jest to młoda biblioteka. Zdecydowanie warto zaczynać przygodę z Kerasem – pozwala łatwo budować własne architektury, w podstawowej wersji masz metodę fit, która robi całą magię treningu.

Dla pełniejszego zrozumienia co się dzieje warto zobaczyć „Keras: Writing a training loop from scratch”, albo zaimplementować pętlę treningu w PyTorchu.

Jeżeli chcesz używać najnowszych architektur, które powstają obecnie, to zdecydowanie sprawdź PyTorcha oraz repozytorium TIMM (PyTorch Image Models).

Czego potrzebuję by wytrenować sieć?

  • zdjęć z etykietami (albo w większości bez, do wykorzystania w podejściu Self-Supervised)
  • architektury sieci – własna/wybrana z gotowych
  • funkcji preprocessingu (minimum to normalizacja wartości)
  • definicji klas i ich liczby, albo specyfikacji regresji (pamiętaj by wyjście znormalizować do okolic zera!)
  • oczywiście kryterium optymalizacji – CE Loss dla klasyfikacji, np. MSE/MAE dla regresji
  • mocy obliczeniowej – przy obrazach warto mieć możliwość uruchomienia obliczeń na laptopie z kartą Nvidia (w serii GeForce – najlepiej z końcówką nazwy na 70/80/90), desktopa lub maszyny w chmurze z GPU Nvidia’i, ale nauczyć się możesz używając Google Colab
  • Warto śledzić wyniki eksperymentów, porównywać (TensorBoard, HParams, MLFlow, itp.)

O czym warto pamiętać podczas treningu?

  • o zapisywaniu wyników (!) i hiperparametrów także
  • o walidacji na jednym i tym samym zbiorze, na którym NIE trenujemy
  • o odłożeniu danych testowych jak najpóźniej (sprawdzamy na zbiorze do walidacji, a gdy już wszystkie możliwości poprawy modelu wyczerpiemy robimy test) – ważne – nie oglądamy danych testowych
  • o odpowiednim wysyceniu kart graficznych, by trening dobrze wykorzystywał dostępne zasoby
  • o zapisywaniu wynikowego modelu (co kilka epok, ostatniego, a może najlepszego?)
  • o zapisaniu decyzji podczas projektowania modelu, zmiany architektury czy zmiany parametrów
  • Wybór callbacków uruchamianych podczas treningu
  • Early Stopping – by zapobiec overfittingowi
  • Model checkpointer – by zapisywać modele często
  • live loss plot – jeżeli trenujesz w Colabie/notebooku
  • TensorBoard – aby porównywać kolejne sesje treningowe (jest wiele narzędzi wandb.ai czy Neptune)
  • HParams – by sprawdzić jaka kombinacja hiperparametrów dała najlepszy wynik
  • MLFlow – zamiast TB do śledzenia, ale nie tylko, bo to całe MLOps

Skąd będę wiedzieć czy to już? A może model może być dokładniejszy, gdyby coś? Koniecznie obserwuj metryki! Jeżeli wyświetlisz sobie parallel plot np. w HParams to od razu zauważysz, która kombinacja parametrów była najlepsza. Warto śledzić też koszt treningu na zbiorze walidacyjnym (rób walidację co jakiś czas, co epokę lub co kilka). Jeżeli loss zacznie wzrastać – może to świadczyć o overfittingu (możesz iść w stronę Deep Double Descent, ale warto po prostu zatrzymać trening, pokombinować z regularyzacją, z data augmentation itp.). Możesz też sobie postanowić, że wystarczy cokolwiek lepiej niż X. X – jakiś threshold biznesowy bądź inżynierski.

Co mam zrobić, by moja sieć działała lepiej na produkcji, danych testowych?

Jeśli Twoim zbiorem testowym są nowe dane pochodzące z produkcji – warto zwrócić uwagę na:

  • okresowość, sezonowość, a może wypadła jakaś globalna pandemia ostatnio?
  • degradację parametrów – zabrudzenie obiektywu, pogorszenie oświetlaczy, zmiana kompresji przy zapisie itp.
  • warto by data augmentation produkowało dane podobne do produkcji/testu

A czy to może działać szybciej?!

Zwykle spodziewasz się odpowiedzi, że owszem. Co możesz zrobić?

  • Kwantyzacja – wykorzystanie niższej precyzji obliczeń GPU – FP16, INT8 (inferencja i trening)
  • TensorRT – przyspieszenie inferencji modelu (ładne kilka razy)
  • Zwiększenie Batcha – niekoniecznie znacznie przyspieszy, ale na GPU raczej tak
  • Zidentyfikować wąskiego gardła (dysk, preproc, gpu, postproc) – działa zawsze, bo to uniwersalne podejście
  • Wybróbować Nvidia Triton Inference Server – zarządza GPU celem maksymalnego performance’u

3. y=ax+b w Kerasie

Minimalny przykład, serio
Minimalny przykład, serio

Co powiesz na prosty przykład?

Jak prosty?

Na rozgrzewkę najprostszy!

Sieć z jednym neuronem, z liniową funkcją aktywacji. Jakie ograniczenie wprowadza jeden neuron? Fakt, że jest jeden oznacza, że mamy 1 wyjście. To jest nasze ograniczenie. Nie mamy natomiast ograniczenia co do liczby wejść. Taki jeden neuron z liniową aktywacja realizuje funkcję liniowa wszystkich wejść. Dodatkowo mamy dodatkowy bias, offset, który może naszą funkcję przesunąć w górę, bądź w dół wykresu.

Tak możemy to zapisać:

y = a1*x1 + a2*x2 + … + an*xn + b

Widać, że 1 neuron ma n+1 zmiennych, parametrów (gdzie n to liczba wejść). Te wartości są ustalane w procesie optymalizacji, uczenia, treningu. Możesz się spotkać z zapisem biasu jako dodakowego wejścia z x=1 i dodatkowej wagi.

Poniżej m=n+1. Wtedy to wygląda fajnie, jak suma iloczynów.

y = a1*x1 + a2*x2 + … + an*xn + am*1

Miejmy 1 wejście, wtedy nasza funkcja to y=a*x+b. Nasz zbiór uczący przygotujemy łatwo. Zaczynamy. Piszemy w pythonie. W praktyce możesz wpisać wszystko do pliku liniowa.py a uruchomisz go z terminala, konsoli poprzez python liniowa.py

import tensorflow as tf

import numpy as np

Powyższy kodzik importuje 2 biblioteki. TensorFlow by móc trenować sieci, numpy by pracować na wektorach, macierzach. Wykorzystamy Kerasa który jest zintegrowany z TensorFlow 2. Zdefiniujmy naszą funkcję, którą wykorzystany do wygenerowania danych.

Niech a=3, a b=-1

def f(x):

return 3*x-1

Przygotujemy nasze dane do uczenia. Niech to będą liczby z zakresu -2..2 co 0.1. Dla nich też wyznaczmy wartości funkcji.

x = np.arange(-2,2,0.1)
print(x)
y = np.array([f(_) for _ in x])
print(y)

Dygresja: Jeśli poznajesz pythona, to wyszukaj „python list comprehension”. Nadużywam tego, bo lubię bardzo. Gdzieś ktoś pokazał, że działa całkiem szybko, więc nie jest źle. Czy da się inaczej owszem. Istnieje przynajmniej jeden sposób – funkcja map.

Tworzymy model:

model = tf.keras.models.Sequential([ tf.keras.layers.Dense(1, input_shape=(1,))])
model.summary()

I już!

Architektura gotowa!

Ba, nawet mamy summary, bardzo pomocne w zrozumieniu zaprojektowanej sieci. Aby uzyskać 1 neuron wykorzystujemy warstwę Dense z parametrem 1 czyli z liczbą neuronów. Domyślna funkcja aktywacji to funkcja liniowa. Specyfikujemy również, że wejście do sieci to będzie wektor o długości 1. Wykorzystujemy Sequential API – przydatne gdy nasz model ma jedną ścieżkę przetwarzania, wejście jest jedno, wielowymiarowe, ale jedno, podobnie z wyjściem.

model.compile(loss=’mse’, optimizer=tf.keras.optimizers.Adam(learning_rate=0.1))

Aby trenować sieć potrzebujemy funkcji kosztu którą trening, optymalizacja ma minimalizować oraz optymalizatora. Naszym wyborem jest błąd średniokwadratowy MSE. Jako optymalizator wybierzmy Adama. Nie jest on już aż tak super, w sumie tutaj SGD nadałby się doskonale. Teorii teraz nie wprowadzajmy.

model.fit(x,y, epochs=100)

W ten oto sposób trenujemy sieć. Tak, to tylko tyle! Epoka to 1 przejście przez wszystkie próbki zbioru uczącego.

preds = model.predict(x)

print(y)

print(preds.flatten())

Porównajmy predykcje modelu z oczekiwanymi wartościami. Gdybyśmy chcieli sprawdzić na wynikach spoza zbioru uczącego, to błąd nie będzie większy, bo nasz model jest idealnie dopasowany do zagadnienia. Tu nie nastąpi przeuczenie, overfitting. Gdyby mieć model wyższego rzędu np.

a*x*x*x + b*x*x + c*x + d

Wtedy prawidłowe rozwiązanie powinno mieć a=0, b=0. Tymczasem możemy otrzymać szlaczek dopasowany do punktów konkretnych, czyli sieć dobierze 4 parametry, nie zmniejszając rzędu funkcji, która nie będzie linia prostą. Wtedy to będzie overfitting, przeuczenie. Wyzerujemy błąd na zbiorze uczącym, a błąd w ewaluacji, teście będzie znaczny. Mimo wszystko sprawdźmy:

x_test = np.arange(-100,100,1)
print(x_test)
y_test = np.array([f(_) for _ in x_test])
print(y_test)
pred_test = model.predict(x_test)
print(pred_test.flatten())

Jeżeli chcesz sprawdzić bardziej złożony model to dodaj warstwy pomiędzy. Ostatnia warstwa musi mieć 1 neuron. To jedyne ograniczenie. Przykład:

model = tf.keras.models.Sequential([ tf.keras.layers.Dense(10, input_shape=(1,)), tf.keras.layers.Dense(10), tf.keras.layers.Dense(10), tf.keras.layers.Dense(1)])

Potem kompilacja i fit czyli trening. Wyniki nie powinny już wyjść takie super na teście. Czyżby w sieciach nie wystarczyło dać największego modelu i po sprawie?

SPOILER ALERT: No nie.

Najlepiej mieć model dopasowany do problemu, złożoność architektury do złożoności problemu. Dla wygody możesz pracować w Google Colab. Jest tam przygotowane środowisko TF, także z dostępem do karty graficznej. Natomiast w tym problemie ona się nie przyda.

W mailu z mailingu DeepDrive.pl/m dołączam jeszcze notatnik Google Colab, gdzie możesz powyższe uruchomić i sprawdzić w przeglądarce, niczego nie instalując.

Pomyślałem, że dam i tutaj dla wygody:

https://colab.research.google.com/drive/1nV9B0y9pq00jbTLMko4PWtT36IfHrtK_?usp=sharing

4. Trening w uczeniu nadzorowanym

Jak to jest, że sieć neuronowa uczy się na podstawie przykładów w uczeniu nadzorowanym?

Załóżmy na początek, że inicjujemy wartości wszystkich parametrów, wag sieci neuronowej w sposób losowy (to uproszczenie). Czyli gdyby nasza sieć neuronowa to był model y=ax+b to wartości a i b byłyby wybrane losowo. Wcale to nie jest blisko odpowiedzi.

Zmieniamy wartości parametrów a i b w taki sposób aby przybliżyć się do poprawnego rozwiązania dla przykładów na których trenujemy sieć. Aby zmienić wartości w ten sposób potrzebujemy kilku rzeczy – poprawnych wartości y, funkcji kosztu, czyli metody oceny odległości obecnego rozwiązania od rozwiązania poprawnego, wpływu parametrów na wynik (gradienty), oraz optymalizatora.

Pochodna y po parametrze a wyniesie x, natomiast po parametrze b wyniesie 1. To jest prosta sieć, więc można to policzyć w pamięci lub na kratce. W przypadku dużych sieci, korzystamy z faktu, że gradienty mnożymy i możemy policzyć je lokalnie dla każdej z warstw niezależnie. Ostatecznie znany już wpływ zmiennych na wynik.

Wykorzystujemy funkcję kosztu, loss, by obliczyć błąd – regresji może to być błąd średniokwadratowy lub na przykład MAE, klasyfikacje i najpewniej będzie to Cross Entropy Loss. Korzystając z optymalizatora zmieniany wartości parametrów a i b według wpływu na wynik i wartości błędu. Dodatkowo istotny jest krok uczenia Learning Rate – dodatkowy mnożnik, który pomniejsza poprawki parametrów. Ta aktualizacja odbywa się tak prosto w podstawowym algorytmie Stochastic Gradient Descent (SGD). Dodatkowo można uwzględniać momenty czy wygaszanie LR.

W ten oto sposób minimalizujemy błąd znajdując optymalne wartości parametrów podłóg przyjętej funkcji kosztu. Wynik jest najlepszy dla konfiguracji, hiperparametrów treningu (LR, optymalizator, architektura, data augmentation, itd.), co nie znaczy, że będziemy z niego zadowoleni.

Tak to działa w dużym uproszczeniu. Oczywiście wynik treningu np. accuracy – można poprawić zmieniając: architekturę, optymalizator, LR, data augmentation.

5. Overfitting – nadmierne dopasowanie

Trenując sieci neuronowe, optymalizując jakiekolwiek modele spotkasz się z hasłem „overfitting” – czyli nadmierne dopasowanie. To zjawisko oznacza, że model jest dopasowany do zbioru uczącego, nadmiernie – czyli jak? W taki sposób, że model podejmuje decyzję poprawnie tylko w tych punktach przestrzeni wielowymiarowej (obrazach wejściowych), a wystarczy minimalna zmiana (nawet 1 pixel – dygresja poniżej), a wynik zupełnie odbiega od poprawnego.

Dygresja – One Pixel Attack for Fooling Deep Neural Networks; Artykuł z 2019 pokazuje, że da się oszukać sieć – zmienić klasę top1 – modyfikując jedynie 1 pixel.

https://arxiv.org/abs/1710.08864

No alt text provided for this image

Wracając do Overfittingu – kiedy się zdarza?

  • Gdy korzystamy z dużego modelu, który jest w stanie zapamiętać cały zbiór
  • Gdy trenujemy długo*
  • Gdy mało jest przykładów

Skąd wiedzieć czy overfitting występuje?

  • obserwuj loss dla zbioru walidacyjnego (val loss)
  • gdy val loss przestanie spadać / zacznie wzrastać
  • a train loss wciąż spada (dąży do zera – zapamiętanie całego zbioru)
  • wtedy też val accuracy przestaje rosnąć/spada
  • a train acc dąży do 100% (zapamiętanie całego zbioru)

Jak można z tym walczyć?

  • Regularyzując model
  • Zmniejszając model
  • Zwiększając zbiór uczący
  • Zatrzymując trening wcześnie (Early stopping)

Jaką regularyzację możesz zastosować?

  • Batch/Layer normalization
  • Dropout
  • Pooling
  • Data augmentation
  • L1/L2 regularization

Zwiększenie regularyzacji zwiększy generalizację – zdolność modelu do uogólniania – do dawanie dobrych odpowiedzi na nowych, nieznanych danych.

To jak ten overfitting wygląda? Poniżej obraz z artykułu „Reconciling modern machine learning practice and the bias-variance trade-off” (https://arxiv.org/abs/1812.11118). Istnieje optymalna wielkość modelu (oś x) do danego problemu, dalesze zwiększanie modelu spowoduje wzrost błędu – gorsze wyniki. [SPOILER ALERT – wcale, że niekoniecznie, o tym w nastęnym wpisie)

No alt text provided for this image

Na koniec – czy zawsze unikać overfittingu?

Unikaj, chyba, że wiesz co robisz

6. Jak oszukać overfitting?

Unikać overfittingu czy płynąć z prądem?

Skoro pada pytanie, to pewnie jest możliwe, że overfitting nie jest zły. Owszem! Wyobraź sobie eksperyment w którym zwiększasz model – tutaj parametr width w ResNecie18. Każdy model trenujesz na tych samych danych – mnóstwo zasobów obliczeniowych. Na szczęście nie musisz już tego robić, bo wyniki znajdziesz poniżej.

Co się okazuje?

  • zwiększenie modelu do pewnego momentu poprawia wynik
  • następnie wyniki już się pogarszają – rośnie błąd
  • wtedy też model zapamiętuje wszystkie próbki (train error bliski zera)
  • natomiast powiększając model znacznie bardziej
  • wyniki na zbiorze testowym się poprawiają (!)
  • ogromny model radzi sobie lepiej niż mały
  • a mały radzi sobie lepiej niż średni

Powyższe zauważysz na wykresie z OpenAI:

No alt text provided for this image

Więcej zobacz tu: https://openai.com/blog/deep-double-descent/

Zawsze większy zbiór jest lepszy!

BYNAJMNIEJ! Okazuje się, że dla średnich modeli, zwiększenie zbioru pogarsza wyniki. wyobraź sobie, że dla różnych wielkości modelu wykonasz treningi z małym i dużym zbiorem. Wtedy spodziewasz się, że wyniki dla większego zbioru będą zawsze lepsze (kolor zielony). NIE SĄ. Dla średniej wielkości modeli zwiększenie zbioru może pogorszyć otrzymywane wyniki.

No alt text provided for this image

No ale, nie warto przecież zbyt długo trenować, bo istnieje overfitting!

Okazuje się, że mając ogromny model i trenując go mega długo – tysiące epok – odnajdziesz drugie, lepsze minimum błędu na zbiorze testowym.

No alt text provided for this image

Overfitting możesz oszukać:

  • znacznie zwiększając model (także, likwidując regularyzację (!))
  • wydłużając znacząco trening

Czy skończysz wtedy ze zbyt dużym modelem, który nie nada się do wdrożenia? Bardzo możliwe. Natomiast wtedy możesz próbować go optymalizować – pruning, knowledge distilation, itp.

Te rzeczy przeczą wszystkim podstawom, warto sobie zdawać sprawę. Wszystko zaczęło się od https://arxiv.org/abs/1812.11118 A żeby mieć pełny kontekst zobacz ostatni wpis: https://www.linkedin.com/pulse/overfitting-nadmierne-dopasowanie-karol-majek-phd

W tamtym wpisie ujrzysz rysunek a:

No alt text provided for this image

Rysunek b – jest uzupełnieniem zjawiska

Edit:

Tego dnia pojawił się artykuł, w którym wyznaczane są analitycznie wyniki otrzymane empirycznie w DDD. Więcej tu https://arxiv.org/abs/2112.03215v1

7. Transfer learning zaoszczędzi Twój czas

Trening od zera vs Transfer learning + fine-tuning dla EfficientNetB0
Trening od zera vs Transfer learning + fine-tuning dla EfficientNetB0

Rozmawialiśmy już o wielkości modelu i generalizacji, a teraz czas na wykorzystanie wytrenowanych już modeli do własnych zastosowań czyli transfer learning.

W tym podejściu zakładamy wykorzystanie wiedzy na temat obrazów wyglądających podobnie do zupełnie innego zagadnienia. Najczęściej wykorzystujemy sieć neuronową wytrenowaną na dużym zbiorze np. Imagenet (w zasadzie to tylko), a dotrenujemy ją do naszego zagadnienia na przykład klasyfikacji rodzajów roślin. Oczywiście musimy wykonać pewną modyfikację – podmienić klasyfikator, tak aby posiadał odpowiednią dla naszego zadania liczbę klas.

Korzystamy tutaj z tego, że pierwsze warstwy sieci neuronowej nauczyły się już na większym zbiorze jakie filtry są najlepsze, by wydobyć cechy z obrazu, a że wykorzystywać będziemy obrazy wyglądające podobnie bo będą to obrazy z kamer możemy skorzystać już z tej nabytej wiedzy. To istotne założenie i może się zdarzyć, że np. w aplikacjach med otrzymamy lepsze wyniki stosując Self-Supervised Learning jako punkt startowy, a może po prostu trenując od zera.

Transfer learning ma dwie zalety:

  • Możemy wykonać krótszy trening
  • Uzyskamy lepsze rezultaty
  • Nie potrzebujemy tak dużego zbioru danych
  • Architektura sieci została zaprojektowana i sprawdzona przez zespoły naukowców w intensywnych eksperymentach

No może 3, lub więcej.

Czy łatwo jest zdobyć taki model?

Zdecydowanie!

Jest mnóstwo miejsc w których można pobrać gotowe modele wytrenowane na zbiorze imagenet

  • Torch Image Models TIMM
  • Keras Applications
  • TF Hub
  • Paddle Hub
  • PyTorch Hub

Itd.

Wykonując transfer learning wymieniamy klasyfikator czyli ostatnią warstwę sieci neuronowej na adekwatny do naszego zadania na przykład z inną liczbą klas. Zamrażamy cały model oprócz nowo dodanej warstwy, czyli nie będziemy trenować już przygotowanej sieci a wy trenujemy tylko dołożoną warstwę. To jest pierwszy krok który wykonamy bardzo szybko bo modyfikować będziemy tylko wagi jednej warstwy. Następnie możemy odmrozić część warstw od góry czyli najbliżej klasyfikatora i do trenować je z mniejszą wartością learning rate.

Jako ostatni etap możemy wykonać fine-tuning czyli do trenować całą sieć wszystkie wagi z naprawdę małą wartością learning rate tak, aby nie stracić tego dobrego punktu startowego od którego zaczynaliśmy.

8. Data augmentation

https://github.com/albumentations-team/albumentations
https://github.com/albumentations-team/albumentations

Trenując sieć warto modyfikować zdjęcia w różny sposób, aby zwiększyć sztucznie liczbę przykładów danych. Takie techniki znajdziesz pod nazwą data augmentation. Możemy sprawić, by dobre zdjęcia, pogorszyć wizualnie, modyfikując kontrast czy kompresję obrazu. To zdecydowanie nie wszystko!

Rodzaje data augmentation:

Przekształcenia geometryczne (afiniczne)

  • Translacja
  • Rotacja
  • Pochylenie
  • Skala

Inne przekształcenia geometryczne

  • Optical distortion, lens distortion
  • Grid distortion
  • Elastic transform

Przekształcenia arytmetyczne – punktowe (globalne)

  • Jasność
  • Kontrast
  • Gamma

Przekształcenia barw

  • Zmiana barwy w HSV (wprowadza artefakty)
  • Zmiana balansu bieli
  • Zmiana kolejności kanałów

Operacje kontekstowe (lokalne) – sąsiedztwo

  • Kontrast lokalny – CLAHE
  • Operacje morfologiczne

Data augmentation możesz zastosować w każdym treningu, by poprawić wyniki, sztucznie zwiększając liczbę przykładów na którą wystawisz swój model. Modyfikując zdjęcia warto zacząć od prostych przekształceń obserwując czy wyniki treningu się poprawiają. Pierwsze mogą być obroty, przesunięcia czy odbicia lustrzane – przy czym uważaj czy te zmiany będą miały sens.

Czy warto odwracać o 90 lub 180 stopni zdjęcia z np. samochodu? Najpewniej nie, bo niebo w 99,99% przypadków jest na górze zdjęć, więc warto rozważyć obroty +/-5 stopni zamiast 90 czy 180. Odnośnie odbić lustrzanych – uważaj, gdy istnieje para klas w zbiorze, które są lustrzanymi odbiciami. Warto by zdjęcia po data augmentation przypominały zdjęcia rzeczywiste, ale warto też eksperymentować z trudniejszymi modyfikacjami.

Biblioteki z których możesz skorzystać:

  • TF Keras
  • PyTorch data augmentation
  • Keras ImageDataGenerator
  • Kornia (warte uwagi)
  • TorchIO (do med)
  • Albumentations (Zdecydowanie warte uwagi)

Korzystaj z powyższych bibliotek. Data augmentation poprawi twoje wyniki. Jeżeli potrzebujesz jedną bibliotekę, niezależnie od frameworku użyj Albumemtations.

9. Hiperparametry vs parametry

TB HParams, ale dziś nie o tym
TB HParams, ale dziś nie o tym

Często mówimy o wagach, czy też parametrach modelu. Mamy na myśli wartości, które zostaną dobrane w czasie treningu wykorzystując gradienty. W samym treningu są też inne parametry, hiperparametry, które jednak często potocznie, nieprecyzyjnie nazywamy parametrami (uwaga na pomyłki). Te hiperparametry, to np. wartość Learning Rate, rodzaj optymalizatora, parametry data augmentation, LR schedule itd.

Przestrzeń hiperparametrów zależy od liczby tychże oraz zbioru ich wartości. Niektóre parametry przyjmują 2 wartości, inne kilka, inne to liczby całkowite, a inne to liczby zmiennoprzecinkowe. Dobierając wartości parametrów częstą, najprostszą praktyką jest zastosowanie intuicji inżynierskiej – ot wpisujemy co nam się wydaje – to mimo wszystko może zawieźć.

W przypadku kilku wymiarów i ograniczenia dużych zakresów do kilku wartości – często chcemy przeszukać wszystkie możliwe kombinacje hiperparametrów i sprawdzić co lepiej zadziała. Zwykle „na szybko” wykonamy grid search – sprawdzimy wszystkie kombinacje, najpewnie korzystając z kilku zagnieżdżonych pętli po wartościach kolejnych hiperparametrów.

Grid search jest najprostszy do zaimplementowania, natomiast przynosi najgorsze wyniki i wymaga najwięcej czasu. Warto go zastąpić poprzez Random search – zamiast wybierać np. 3 wartości LR do sprawdzenia, wybierać będziemy losowo (tu biorąc pod uwagę skalę logarytmiczną). Random search pozwala znaleźć lepsze wartości niż te zgadywane przez nas, bo nie mamy założenia, że przeszukujemy siatkę wartości, a możemy trafić w dowolne miejsce.

W praktyce doboru hiperparametrów stosuj metody HPO (Hyperparameter Optimization) inne niż Grid czy Random search, bo warto brać pod uwagę jak rozkładają się zestawy hiperparametrów dające najlepsze wyniki.

HPO znajdziesz w bibliotekach takich jak np.:

  • KerasTuner
  • Optuna (polecam gorąco)
  • Hyperopt

Pracując z frameworkiem do HPO potrzebujesz zdefiniować funkcję która oceni zestaw hiperparametrów. Ta ocena to będzie oczywiście trening i ewaluacja, efektem ma być pojedyncza wartość np. Validation accuracy. Dla optuny przykłady znajdziesz na https://optuna.org/ dla wielu frameworków.

Dodatkowa super rzecz to pruning – wczesne zakończenie ewaluacji danego zestawu parametrów, gdy wyniki nie rokują. W Optunie wystarczy, że będziesz raportować wartrość metryki np. co epokę. Wtedy optuna może podpowiedzieć, że nie ma sensu kontynuować. Dzięki temu możesz trenować nawet np. na 100 epok i wiele treningów skończy się na mniej niż 5 epokach. Znakomicie to przyspieszy proces.

Może się okazać, że będziesz potrzebować cierpliwości w oczekiwaniu na dobre rezultaty:

No alt text provided for this image

A może się okazać, że dobre wyniki otrzymasz dość szybko:

No alt text provided for this image

Jak dobierasz hiperparametry w swoich modelach?

Wykorzystujesz już HPO czy wprowadzasz zmiany ręcznie?

10. Gradient, hessian i predykcja wag

Super-convergence (OneCycleLR) - czyli jak 10x przyspieszyć trening sieci
Super-convergence (OneCycleLR) – czyli jak 10x przyspieszyć trening sieci

Tym razem słowo o treningu. Treningu czyli optymalizacji wartości wag (parametrów), w taki sposób by zminimalizować funkcję kosztu. Funkcję kosztu, dla której możemy policzyć zależność błędu od każdego z parametrów sieci (wag) obliczając gradienty od wyniku do poszczególnych parametrów. Następnie propagujemy poprawki dla wszystkich parametrów (backpropagation) – w ten sposób sieć powinna osiągać coraz lepsze wyniki. Powinna!

No to teraz kilka aspektów

  • Krok uczenia – Learning Rate (LR) – wartość przez jaką przemnażamy poprawki – spowalniając trening. Zwykle są to wartości rzędu 1e-9…1e-2, często dobrym wyborem są okolice 3e-4; Jak w żarcie od Andreja. Dla wielu metod LR zależy od architektury, danych, wielkości batcha, problemu. Tak jest z najpopularniejszymi SGD, Adamem i RMSProp. Dla tych metod warto dobrać LR
No alt text provided for this image
  • LR finder – zmieniaj LR od małych wartości do najwyższych i szukaj minimum loss; Metodę znajdziesz gotową do wykorzystania w Fast.ai oraz PyTorch Lightningu
  • Lub po prostu użyj RAdama – ten optymalizator naprawia największy problem Adama, pozwalając na uzyskanie tak samo dobrych wyników niezależnie od wskazanej wartości LR
  • Czy już nie ma sensu korzystać z SGD? Czasem warto – oszczędza pamięć i szybciej się liczy. Łącząc z LR Schedulerem efekt może być zaskakująco dobry. Zob. OneCycleLR (paper: Super-Convergence https://arxiv.org/abs/1708.07120)
No alt text provided for this image
No alt text provided for this image
  • ostatnia opcja, dość ciekawa – to predykcja wartości wag, by otrzymać lepszy punkt startowy niż losowy, dla sieci, których nie mieliśmy jeszcze okazji trenować na dużym zbiorze np. Imagenecie (tu chętnie bym dał link do artykułu i kodu). Oczywiście mająć już model wytrenowany na ImageNecie raczej nie będzie potrzeby go nieużywać.

Podsumowując krótko – wybór optymalizatora, LR, LR Schedulera, czy starting pointu istotnie wpłynie na wyniki uczenia oraz oczywiście na czas treningu. Dobry optymalizator na start to RAdam, chyba, że Twój framework ma tylko Adama – wtedy Adam i dobierz LR eksperymentalnie (HPO bądź LR Finder)

11. Historia architektur CNN

https://josephpcohen.com/w/visualizing-cnn-architectures-side-by-side-with-mxnet/

Obraz reprezentowany jest jako wartości poszczególnych pikseli, wiersz po wierszu. Gdy obraz jest czarno biały (dosłownie, czyli bez szarego) możemy go zapisać jako listę zer i jedynek. Myślenie o obrazie jako o liście / wektorze liczb jest nie tylko niewygodne, ale zaniedbuje fakt, że piksele mają sąsiadów (4 albo 8, zależy jakie sąsiedztwo rozpatrujemy; czasem mniej, bo przecież jest ramka), a taka wiedza może nam pomóc w analizie (i pomaga od lat!). O obrazie myślimy jako o macierzy 3 wymiarowej. Czemu 3? Mamy przecież szerokość i wysokość, skąd trzeci wymiar? Trzeci wymiar / głębokość / liczba kanałów to w przypadku obrazu czarno białego 1,bo dla każdego piksela mamy tylko jedną wartość, na dodatek binarną (nie ma to w sumie znaczenia większego). Jak to wygląda dla obrazu kolorowego? Obraz na komputerze reprezentowany jest poprzez trzy składowe w przestrzeni RGB. Disclaimer: przestrzenie barw to szerokie zagadnienie, nam się przydadzą takie jak np. HSV, LAB; w wydruku przydaje się CMYK, ale z punktu widzenia analizy obrazu np. z kamer – nie przyda nam się [raczej; to zależy od zagadnień oczywiście].

Jak ocenić co widać na obrazie? Jak robimy to od prawie dwóch dekad? Zwykle pierwszy etap to wydobycie cech z obrazu, na podstawie tych cech później możemy wnioskować co jest widoczne na obrazie, a w jaki sposób? O tym za chwilę, wróćmy do pierwszego etapu – do ekstrakcji cech. Na początku tysiąclecia stosowano metody oparte o wykrywanie punktów charakterystycznych. Czym takie punkty mogły być na obrazie? Mogły to być np. narożniki. Czym taki narożnik się wyróżnia? Kontrastem z otoczeniem, charakterystycznym kształtem, krótko – otoczeniem piksela, który tym punktem charakterystycznym jest. Sama informacja gdzie taki punkt się znajduje na obrazie, a może być ich tysiące, nie wiele wnosi. Natomiast, jeśli dodamy deskryptor punktu – sposób opisywania otoczenia punktu jako wektor cech, będziemy mogli:

  • wydobyć cechy z obrazu (feature extraction)
  • porównać poszczególne punkty na kilku obrazach (image matching, panorama stitching)
  • wykrywać i lokalizować wzorce (template matching)

To pierwsze to nasz cel – znalezienie uproszczonego zapisu obrazu, który dobrze będzie mówić o tym co tam widać, w największym uproszczeniu docelowo chcemy przecież otrzymać etykietę np. „samolot” jako opis obrazu. W bibliotece OpenCV znajdziesz mnóstwo zaimplementowanych detektorów jak i deskryptorów punktów charakterystycznych. Mimo swojego wieku SIFT jest wciąż polecany – ciekawostka, minęła mu ochrona patentowa, więc w zastosowaniach komercyjnych można już go stosować. Warto spojrzeć także na SURF i ORB. Wszystkie powyższe są algorytmami zaprojektowanymi przez człowieka – zaproponowane cechy, sposoby wykrywania, opisu punktów. Obecnie zagadnienie wykrywania punktów charakterystycznych na obrazie również zostało zdominowane przez algorytmy wykorzystujące uczenie. Tu świetnym przykładem jest SuperPoint (detektor i deskryptor) i SuperGlue (matcher) od firmy Magic Leap nad którymi pracowali m.in. Daniel DeTone i Tomasz Malisiewicz. Niestety obie sieci są udostępnione tylko do zastosowań niekomercyjnych.

Wróćmy do naszego zagadnienia. Cały czas wspominam o starym podejściu do zagadnienia, gdzie na podstawie wektorów cech, które uzyskiwaliśmy z deskryptorów punktów charakterystycznych mogliśmy użyć technik machine learningowych by odpowiedzieć na pytanie co jest widoczne na obrazie. To się sprawdzało do 2012 roku w zadaniu rozpoznawania obrazu. Potem pojawiła się sieć AlexNet, to była rewolucja!

Pomijam LeNet-5 (1998) celowo, by skupić się na ImageNecie. Czy wiesz, że pierwszy artykuł z tą siecią pochodzi z 1989 roku? „Backpropagation Applied of Handwritten Zip Code Recognition”

Jak wyglądał AlexNet? Ekstrakcja cech z całego obrazu poprzez kolejne konwolucje (Conv2D) i zmniejszanie rozmiarów obrazów (MaxPool2D), wydobywanie cech (mniejsza szerokość i wysokość, większa głębokość). Spłaszczenie obrazu w wektor (warstwa Flatten) i jako klasyfikator na podstawie 9216 wartości w wektorze są dwie warstwy po 4096 neuronów i ostatnia wartswa z 1000 neuronów, bo tyle jest klas w zbiorze ImageNet. Dropouty oraz Batch Normalization poprawiają generalizację. W oryginale nie było BN, było Local Response Normalization – normalizacja bez wag, niepoprawiająca generalizacji, zastąpiona obecnie przez BN właśnie.

To też już jest prehistoria 🙂 Później była faza na dodawanie warstw w nieskończoność – to nie jest rozwiązanie niestety. Warto zobaczyć VGG – obie wersje 16 i 19.Nie korzystaj z nich, tak samo jak z AlexNeta. Wiele zmieniło wprowadzenie modułów Inception (v1 i v2,v3 oraz v4, a później Inception-ResNet v1 i v2). W module inception jeden obraz z poprzedniej warstwy jest przetwarzany jednocześnie na kilka sposobów, a następnie wyniki są agregowane (concatenation). Przykładowo w inception v1 obraz jest przetwarzany równolegle przez 4 ścieżki:1. Konwolucję 1×12. Konwolucję 1×1, a potem 3×33. Konwolucję 1×1, a potem 5×54. Max pooling 3×3, a potem konwolucję 1×1

Naturalną kontynuacją są sieci Inception są ResNety. Architektura ResNet jest jeszcze w miarę aktualna, ale pojawiło się już wiele wersji z ulepszeniami (choćby ResNeXt i ResNeSt).ResNet wprowadza bloki / moduły rezydualne. To takie moduły, które mają równoległą ścieżkę niewykonującą żadnych obliczeń. Wynikiem takiego modułu jest więc suma wejścia i funkcji realizowanej przez ścieżkę z obliczeniami, np. konwolucjami niezmieniającymi rozmiarów. W oryginalnym artykule „Deep Residual Learning for Image Recognition” z 2015 roku przedstawione są eksperymenty pokazujące, że niekoniecznie jest sens zwiększać liczbę warstw sieci.

Koniecznie zajrzyj tu: https://josephpcohen.com/w/visualizing-cnn-architectures-side-by-side-with-mxnet/ Świetna wizualizacja, a zarazem porównanie jak wiele warstw bywa w sieciach konwolucyjnych.

Z 2019 roku mogę polecić EfficientNet. Zestaw 8 architektur od B0 do B7, których modele mają kilkakrotnie mniej parametrów, uzyskując równie dobre wyniki co inne sieci. W tej sieci odkryto, że aby uzyskać najlepsze wyniki dla większych rozdzielczości, należy skalować wszystkie wymiary sieci jednocześnie – głębokość (liczbę warstw), szerokość (wielkość warstw) oraz rozdzielczość wejścia. Skalowanie pojedynczego wymiaru nie przynosi tak dobrych rezultatów jak jednoczesne zwiększenie wszystkich trzech. Polecam artykuł – jest to pokazane w eksperymentach.

Oczywiście wiele się wydarzyło w kolejnych latach! Z CNN choćby EfficientNetV2, a oprócz tego zastosowanie sieci MLP czy opartych na transformerze.

12. Frameworki

Obraz stąd: https://deepdrive.pl/co-wziac-pod-uwage-wybierajac-laptop-do-deep-learningu/
Obraz stąd: https://deepdrive.pl/co-wziac-pod-uwage-wybierajac-laptop-do-deep-learningu/

Wpierw disclaimer – nie odpowiem co wybrać, u różnych osób sprawdzają się różne rzeczy. To co zadziałało u mnie, może nie zadziałać u nikogo innego, a może u wszystkich oprócz Ciebie. Raczej powiem jak to wygląda z mojej perspektywy. Różne rzeczy się sprawdzają w różnych sytuacjach.

Jaki framework warto wybrać, by zacząć pracę z sieciami do analizy obrazu?

Według mnie, ale zaznaczę to ponownie, według mnie to będzie TensorFlow 2, a w nim Keras. Dlaczego tak uważam?

  • piszemy kod w pythonie (no ale przecież PyTorch jest też w Pythonie, nie? owszem, dodam parę rzeczy)
  • jest wiele dostępnych przykładów (TensorFlow jest dostępny od ponad 6 lat, ale to też problem, bo część przykładów jest dla TF1)
  • pozwala w kwadrans zrobić sieć do klasyfikacji obrazu, jeżeli mamy dane w katalogach per klasa
  • nie wymaga to wielu linii kodu – można to napisać z pamięci po 4 latach zapamiętywania (pewnie dasz radę zapamiętać to szybciej). To mi się właśnie podoba i z miłą chęcią to robię – na prawdę podstawowy eksperyment robi się bardzo szybko.

A dlaczego korzystam z PyTorcha zdecydowanie więcej?

Jeżeli chcesz być na bieżąco z architekturami sieci do rozpoznawania obrazu – większość State of the Art jest zintegrowana dość prosto z PyTorchem. Dlaczego tak uważam?

  • Zobacz repozytoria torchvision oraz TIMM (pytorch-image-models) – znajdziesz tam mnóstwo modeli zaimplementowanych
  • Łatwo zintegrujesz nowe modele, podmienisz backbone w modelach do detekcji/segmentacji
  • Większość nowych artykułów naukowych obecnie jest implementowana w PyTorchu
  • Tu też python, więc fajnie jeżeli ten język umiesz

Czemu Keras jest lepszy na początek, albo do szybkich rzeczy (w sensie masz godzinę na implementaję)?

  • W PyTorchu potrzebujesz dużo kodu – boilerplate – by uruchomić trening, nie sposób to z pamięci na szybko wpisać
  • Keras zdecydowanie pozwala szybko zestawić prosty trening (dobre na PoC czy hackathony)
  • Jeżeli chcesz zmniejszyć boiler plate w PyTorchu zobacz: PyTorch Lightning, Lightning Flash, trening w TIMM czy Fast.ai)

Jeżeli musisz mieć C++ to możesz spróbować z Darknetem (oczywiście PyTorch i TF mają opcję c++). W tym frameworku wytrenujesz sieć do klasyfikacji i do wykrywania obiektów (to tam jest zaimplementowane YOLO – You Only Look Once od v2 do scaled v4). Polecam szczególnie do wykrywania obiektów, nawet gdy nie masz doświadczenia z C++. Dlaczego tak uważam?

  • Framework ma API konsolowe, więc wystarczy, że go zbudujesz raz i możesz trenować i testować modele
  • zobacz automatyzację od BMW (tej firmy od samochodów): https://github.com/BMW-InnovationLab/BMW-YOLOv4-Training-Automation
  • warto, bo wsparcie community jest całkiem dobre
  • wygodny format etykiet do wykrywania obiektów (plik txt per zdjęcie)

Wszystkie powyższe frameworki działają na Windowsie i Linuxie, więc i na Macu też (raczej CPU only, ale pojawia się już wsparcie Metal czyli M1+), tu Ci gwarancji nie dam, bo nie znam nikogo, kto by to na Macu uruchamiał. Uważam, że nie bardzo jest sens na Macu z uwagi na brak karty graficznej (ani Intel, ani AMD się nie liczy jako karta graficzna niestety; pozostaje M1 albo …). Jednak nie wszystko jest stracone! Istnieje coś takiego jak eGPU – kupujesz skrzynkę za 2k PLN, wkładasz doń grafikę i podłączasz poprzez USB-C do laptopa/desktopa (USB-C zwane inaczej jako Thunderbolt 3 – złącze fizycznie takie samo, różnica jest tylko w max prędkości). Osobiście nie korzystałem, raczej kupuję laptopy z GPU (co do takowych zobacz post Magdy na DeepDrive.pl – kupiłem 2 takie dla siebie 15.6″ i 17″). Kiedyś jeden kolega twierdził, że się da na AMD trenować (zobacz ROCm zamiast CUDA’y) – po miesiącu kupił Nvidia’ę – to monopol jest (#dowódAngdotycznyNa100)

Co prawda pojawiło się wsparcie AMD w PyTorchu (ROCm) na początku 2021. Jak dla mnie to ciekawostka – wystarczająco dużo straciłem czasu na hardware Nvidia’i i sterowniki. Znane zło 🙂

Inferencja (uruchamianie do predykcji) na urządzeniach mobilnych – co wybierasz?

Zdziwię Cię być może – tu bezkonkurencyjny jest Tencent NCNN. Dlaczego tak uważam?

  • wsparcie CPU/GPU na Androida, iOS w kombinacjach 32/64bit
  • wsparcie dla klasyfikacji, wykrywania obiektów, tudzież twarzy, segmentacji
  • wsparcie Windows/Linux/iOS

Nie możemy pominąć Fast.ai. To jest superwygodny wrapper na PyTorcha – w kilku liniach kodu możesz uruchomić trening modeli z torchvision/TIMM. Warto gdy wiesz co robisz 🙂 Dlaczego tak uważam?

  • zespół Jeremy’ego Howarda i Rachel Thomas tworzy i rozwija ten framework
  • rozwój idzie podobnie jak NCNN, jest więcej kontrybutorów
  • znając co się dzieje na niskim poziomie abstrakcji możemy używać gotowców
  • znajdziesz wiele wygodnych narzędzi np. LR Finder

Wymiana sieci pomiędzy różnymi frameworkami, bądź do wdrożenia na urządzeniach Nvidia’a?

  • ONNX

Wizualizacja modeli różnych?

  • Netron

Monitorowanie treningu? O nie, zbyt wiele jest narzędzi (od TensorBoarda, przez MLFlow, Neptune do Wegihts and biases)

A co z SK Learn, CNTK, Matlabem, DL4J czy PaddlePaddle? Matlab jest typowo akademicki i lepiej szybko uciec do PyTorcha/TF. PaddlePaddle – spoza naszej bańki, może być problem z rozumieniem dokumentacji, ale warto zobaczyć czy nie ma tam czegoś, co się sprawdzi (jakiś gotowy model)

Według mnie jest dużym błędem całkowite pominięcie JAX, szczególnie gdy rozważamy wdrażanie modeli na produkcję. Poniższy wykres przedstawia rozkład który framework wykorzystuje kod udostępniony do artykułów w PapersWithCode (około 30% repozytoriów ma kod)

No alt text provided for this image
https://paperswithcode.com/trends

Używasz czegoś spoza powyższych?

13. Koniec prac nad wykrywaniem obiektów

2020-02-20
2020-02-20

Wpierw delikatnie wprowadzę w temat wykrywania obiektów (jako ramki – bounding boxy). W 2015/2016 roku pojawiły się pierwsze sieci do wykrywania obiektów i to dwa rodzaje.

Czyli:

  • single-stage – jednoetapowe (SSD, YOLO, YOLOv2, później YOLOv3, v4, v5, PP-YOLO itd.)
  • two-stage – dwuetapowe (RCNN, Fast RCNN, później Faster RCNN)

O co chodzi?

Przed sieciami – skanowano cały obraz oknem i klasyfikowano każde okno. Ewentualnie – wykrywano potencjalne obiekty i klasyfikowano je (to zostało wykorzystane w RCNN). Wracając do sieci:

Pierwsze były dwuetapowe – w pierwszym etapie następowało wykrywanie, gdzie znajdują się obiekty, ale dopiero w drugim etapie następowała klasyfikacja, co zostało znalezione. Sieci jednoetapowe od razu na podstawie zdjęcia wykonują predykcje lokalizacji i klasy obiektów. Naraz!

Podstawowa intuicja to – metody dwuetapowe są wolniejsze, często dokładniejsze.

Działanie powyżej 30 fps (klatek na sekundę) to była wyróżniająca cecha jednoetapowej sieci – YOLO. YOLO to oczywiście skrót – You Only Look Once. Najpewniej pojawiła się by podkreślić jednoetapowość. Oczywiście ważny był również walor związany z podobieństwem do popularnego hasła YOLO (You Only Live Once). Jak sądzisz w jakim frameworku działa oryginalne YOLO? Darknet, jakże mogłoby być inaczej. Jest to framework napisany w C/C++, do uczenia i inferencji wytrenowanych modeli, napisany przez Josepha Redmona.

Tak swoją drogą, to zajrzyj w wolnej chwili na jego serię wykładów z University of Washington z 2018 – jest mega: The Ancient Secrets of Computer Vision

Także wracając do YOLO – pjreddie (to jest nick Josepha na Githubie i twitterze) zakończył pracę nad YOLO przy wersji 3. Od tego momentu YOLO było rozwijane przez wiele osób, grup zależnie i niezależnie też.

Warto wspomnieć o Alexey’u, który to wprowadził wersję YOLOv4 w 2020 roku, w kwietniu. To czwarte wydanie, ma tak jak trzy poprzednie artykuł z opisem. v3 miało raczej raport na arxiv.org niż artykuł, warto przeczytać dla żartu, bo humor przedni! I tu zbliżamy się do tematu (czyli to jednak nie jest clickbait?!)

Otóż o 17:09 naszego czasu 20 lutego 2020 roku Joseph napisał tweeta o treści:

Joseph skończył badania nad widzeniem maszynowym, co stwierdził ze smutkiem. Tu się zgodzę (zobacz tamten wątek) – jaki jest zysk z rozpoznawania twarzy w porównaniu do potencjalnego złego wykorzystania?

Tu chyba nie chodzi o jeden konkretny przykład, chyba chodzi o całą naukę w widzeniu maszynowym. Najlepszym przykładem jest to, co zostało zintegrowane i normalnie sprzedawane jako cecha wyróżniająca produktu – ropoznawanie pochodzenia etnicznego. Firma Hikvision w 2018 roku chwaliła się rozwiązaniem Ethnicity Analytics, które pozwalało automatycznie rozpoznać Ujgurów – jedną z mniejszości zamieszkujących Chiny. Tu nie jestem specjalistą, więc możesz poszukać w Internecie więcej, ale w skrócie: Automatyzacja prześladowania mniejszości z wykorzystaniem głębokich sieci neuronowych.

https://ipvm.com/reports/hikvision-uyghur

Z tego co zapamiętałem z różnych źródeł, te przesiedlenia są sprzedawane jako pomoc, a rodziny są rozdzielane po kraju, czyli nawet o tysiące kilometrów. A wszystko po to, by mniejszość wyeliminować. To zdaje się, jest wciąż aktualne, ale staram się nie śledzić.

Mówiąc o etyce sztucznej inteligencji – myślę o etyce wykorzystania narzędzi, bo to człowiek projektuje i ma kontrolę nad skutkami, a na pewno odpowiedzialność. A myśląc o przykładach typu „kogo ma zabić samochód autonomiczny” – Jak często masz takie sytuacje w życiu? Raz na kilka pokoleń? W samochodach autonomicznych jesteśmy jeszcze daleko, a najdalej Tesla (w rocznicę miliona robotaxi nie ma nawet 1% gotowości jak dobrze podsumowuje Filip Piekniewski – poniżej w wątku)

Więcej o Tesli:

À propos obozów koncentracyjnych w Chinach obecnie:

i śledzenie ludzi:

Dość

14. Dlaczego tak?

Src: https://github.com/slundberg/shap
Src: https://github.com/slundberg/shap

Dziś skupię się na problemie, jak interpretować wyniki, jakie daje nam konwolucyjna sieć neuronowa. Co rozumiem jako interpretację wyniku? Odpowiedź na pytanie: na podstawie czego, którego fragmentu obrazu sieć neuronowa podjąć decyzję taką i taką. Tak w zasadzie to dlaczego chcemy odpowiadać na to pytanie, czemu ono jest tak istotne? Ano nierzadko się zdarza, że sieć neuronowa wykonuje predykcję na podstawie nieistotnego fragmentu obrazu. Na przykład rozpoznanie rasy psa na podstawie tła, na jakim pies się znajduje, stwierdza, że coś jest samolotem, bo znajduje się na tle nieba, nie jest człowiekiem, bo nie ma jasnej skóry, ma jakąś chorobę, według diagnozy zdjęcia z tomografu, a jest to tam wprost widoczne jako oznaczenie przez lekarza.

Nie zapominajmy o teorii, jest ona istotna, powinniśmy wiedzieć jak działają metody, które stosujemy. Dyskusja o podstawach teoretycznych w Data Science / Machine Learning / Deep Learning ciągle wraca.

Poniższe metody odpowiedzą na pytanie – który fragment obrazu jest istotny dla predykcji danej klasy?

  • Occlusion mapping
  • Gradient, Integrated Gradients, SmoothGrad, Backpropagation, Guided Backprop
  • Class Activation Mapping (CAM), GradCAM, Guided GradCAM
  • Attention Maps, Saliency Maps
  • SHAP

To o tyle dobre, że możemy uzyskać odpowiedź dla konkretnej próbki i spróbować wyjaśnić, na jakiej podstawie decyzja została podjęta. Trochę inna sprawa – czy wydobyte cechy z obrazu pozwalają na dobre rozdzielenie klas? Możemy to sprawdzić, wykorzystując techniki redukcji wymiarów takie jak: PCA, T-SNE, T-SNE Grid, UMAP (uważaj na hiperparaemtry i zniekształcenia przestrzeni). Często możesz zobaczyć reprezentację 2 wymiarową i rozmieszczone kolorowe punkty (kolor-klasa) lub nawet miniatury zdjęć (może być wygodniejsze do wyciągania wniosków). Wykorzystanie T-SNE Grid daje przyjemny dla oka efekt mozaiki zdjęć, natomiast wprowadza pewne zakłamanie odległości pomiędzy próbkami.

Sporo ciekawego znajdziesz w Building Blocks of Interpretability (Zobacz https://distill.pub/2018/building-blocks/ oraz bibliotekę TensorFlow Lucid https://github.com/tensorflow/lucid – uwaga tylko TF1!!!) znajdziesz tam wiele technik jak np. Semantic Dictionaries, Activation Grids, Spatial Attribution, Channel Attribution, Neuron Groups. Przy okazji – distill.pub to jest mega fajne miejsce.

Warto w projekcie wykorzystać SHAP, także dla obrazów https://github.com/slundberg/shap, działa z TF2 i PyTorchem. Znajdziesz tam wygodną bibliotekę do wyjaśniania działania modeli za pomocą SHAP (SHapley Additive exPlanations).

Z powyższych super jest sobie zaimplementować Occlusion mapping. Świetna rozrywka, a przy okazji uczymy się co nieco o modelu. Sprawa wygląda dość prosto – wykonujesz wiele predykcji wykorzystując swój model. Natomiast każdy z tych predykcji odbywa się z wykorzystaniem zdjęcia, które ma zasłonięty fragment – zasłonięty np. na czarno – wyzerowany. Jak duży fragment? Hiperparametr. Polecam poeksperymentować – to ma duże znaczenie dla wyników. Wykonując predykcje zapamiętujemy wartość prawdopodobieństwa dla oczekiwanej klasy, bądź dla wszystkich klas od razu. Wynik możemy pokazać jako heatmapę – obraz pokazujący za pomocą koloru, wartości w poszczególnych miejscach obrazu.

Z rzeczy, które warto również zobaczyć:

  • jak model radzi sobie z mniejszymi/większymi obrazami (oczywiście jeżeli ma Global Pooling, a nie Flatten) – może być mega różnica
  • One pixel attack – czyli czy wystarczy zmienić jeden piksel obrazu, by zmienić predykcję? Jeśli nie jeden to ile wystarczy?

Na koniec, dla formalności termin – XAI – eXplainable AI.

Czy stosujesz techniki wyjaśniania modelu?

Może wręcz Twoja aplikacja tego wymaga?

15. Poprawa klasyfikacji obrazu?

https://arxiv.org/abs/1905.04899
https://arxiv.org/abs/1905.04899
  • Trenując wykorzystaj LR schedule – zmniejszaj LR skokowo, a najlepiej wykorzystaj OneCycleLR; To pozwoli Ci przyspieszyć trening i uzyskać lepsze wyniki
  • Sprawdź czy SGD nie sprawdzi się w Twoim treningu lepiej; Na pewno zobacz też jak się sprawdzi RAdam, jeżeli korzystasz z Adama
  • Mixup – trenując sieć łączymy dwa zdjęcia przemnożone przez alfa (o wartości między 0 a 1) i 1-alfa i robimy predykcje – powinno wyjść dla alfa i 1-alfa, czyli nie oczekujemy, że sieć odpowie jedną klasą, a raczej pokaże podobną zależność, zgodną z wartością alfa
  • Label smoothing – zmieniamy etykiety z one-hot-encoding (np. 0,0,0,1,0,0,0,0,0,0 dla’3’ w MNIST) na wartości wygładzone – 0.9 i 0.1/9 dla reszty. Model w treningu już nie będzie tak pewny etykiet z danych – miejsce na błąd etykiet. Dzięki LS wzrasta generalizacja. Natomiast możesz zauważyć gorsze wyniki wykonując knowledge distillation (https://arxiv.org/abs/1906.02629)
  • Trenujemy na wielu rozdzielczościach; Zakładam, że Twój model korzysta z Global poolingu i uzyskuje zawsze tę samą liczbę cech na wyjściu; Trenując możesz w ramach kolejnych batchy zmieniać rozdzielczość, albo wręcz zwiększać ją wraz z postępem treningu
  • CutOut – zasłaniamy losowy fragment obrazu podczas treningu; w ten sposób zasłonimy w niektórych przykładach istotne fragmenty – to nie pomoże, ale zasłonimy też te nieistotne w innych przykładach. Dzięki temu sieć będzie miała szansę „zauważyć” istotną cechę obrazu. Zob. https://arxiv.org/abs/1708.04552v2
  • CutMix – wklejamy losowy fragment przykładu innej klasy. To może poprawić atrybucję, sieć będzie zwracać uwagę na prawidłowe fragmenty obrazu. Zob. https://arxiv.org/abs/1905.04899
  • Style Transfer augmentation – zabieg z https://arxiv.org/pdf/1811.12231.pdf; Sieci konwolucyjne doskonale rozpoznają tekturę i to na jej podstawie podejmują decyzje.Kot z teksturą słonia to słoń.

Czy stosujesz, a może chcesz zacząć stosować, wspomniane techniki i metody?

16. dużo zdjęć, mało etykiet, co robić?

Noroozi, Mehdi, and Paolo Favaro. "Unsupervised learning of visual representations by solving jigsaw puzzles."​ European conference on computer vision. Springer, Cham, 2016.
Noroozi, Mehdi, and Paolo Favaro. „Unsupervised learning of visual representations by solving jigsaw puzzles.”​ European conference on computer vision. Springer, Cham, 2016

Wyobraź sobie, że masz mnóstwo zdjęć, ale tylko niewielka część ma etykiety. Może brzmieć znajomo, bo przecież pozyskanie zdjęć może być już naturalnie działającym procesem w firmie. A czemu może brakować etykiet? Bo to osobny proces, często uruchamiany z opóźnieniem, często trwający dłużej, wymagający pracy ludzi, także do weryfikacji.

Czy są na to jakieś sposoby, by skorzystać z dużej liczby przykładów (u nas – zdjęć), nie musząc ich etykietować? Jak najbardziej tak!

Do tego możesz skorzystać z technik Self-Supervised Learning (SSL – uwaga z tym skrótem).

Jaki jest pomysł?

  • automatyczne etykiety
  • trening na dodatkowym zadaniu – pretext task
  • sieć uczy się wydobywania cech z obrazu
  • wykorzystanie wytrenowanego modelu wykorzystując transfer learning (korzystamy tylko z części warstw)

Jakie przykładowo mogą być zadania – pretext tasks:

  • Rotation prediction – predykcja rotacji; W tym zadaniu definiujemy 4 klasy – brak obrotu, obrót 90, 180 i 270 stopni; Znamy odpowiedzi, bo zbiór generujemy obracając zdjęcia; Bardzo łatwo to zaimplementować
  • Colorization – kolorowanie obrazu – dane generujemy na podstawie obrazów kolorowych ze zbioru bez etykiet, zmieniając obrazy na skalę szarości
  • Placing image patches in the right place – wzajemne lokalizowanie fragmentów obrazu – dla danego fragmentu zadaniem sieci jest wskazanie gdzie fragment powinien się znajdować względem drugiego (sąsiedztwo 3×3)
  • Solving jigsaw puzzle – rozwiązywanie układanki z 9 puzli (fragmentów obrazu) – czyli poprawne ich posortowanie
  • Ustawianie klatek filmu we właściwej kolejności – gdy dysponujemy filmami, znamy prawidłową kolejność, a sieć ma za zadanie się jej nauczyć
  • Inpainting – uzupełnianie brakującego fragmentu obrazu; łatwo jest przygotować dane z brakami zasłaniając fragment obrazu, który sieć musi odtworzyć (zob. LaMa – Resolution-robust Large Mask Inpainting with Fourier Convolutions)
  • Classify corrupted images – klasyfikacja zdjęć z błędami; artefakty wprowadzamy w generatorze danych; klasyfikacja binarna
  • oraz wszystkie metody contrastive learning, gdzie zadaniem sieci jest ocena odległości między zdjęciami (podobieństwa) – np. minimalizacja odległości pomiędzy zdjęciem bez data aug, a po data augmentation

Wykorzystanie SSL nie skróci czasu treningu – lepsze wyniki otrzymasz szybciej po prostu mając etykiety.

No, ale skoro ich nie masz to warto skorzystać z transfer learningu (na bazie modelu ImageNet), natomiast jeżeli chcesz oprócz tego dodatkowo skorzystać ze swoich zdjęć – wykonaj trening transfer learning modelu z ImageNet na pretext tasku, a następnie kolejny transfer learning na docelowym zagadnieniu.

Tak można postępować w przypadku gdy w zbiorze mało jest etykiet względem wszystkich danych np. mniej niż kilka procent/promili.

17. Pytorch Image Models

https://rwightman.github.io/pytorch-image-models/
https://rwightman.github.io/pytorch-image-models/

Tym razem słowo o TIMM – wspaniałej bibliotece modeli (i nie tylko modeli) do trenowania sieci do analizy obrazu. Z PyTorch Image Models skorzystasz tylko w PyTorchu – warto choćby z tego powodu się przesiąść, a przynajmniej dać szansę.

TIMM is a deep-learning library created by Ross Wightman and is a collection of SOTA computer vision models, layers, utilities, optimizers, schedulers, data-loaders, augmentations and also training/validating scripts with ability to reproduce ImageNet training results. https://fastai.github.io/timmdocs/

https://github.com/rwightman/pytorch-image-models

No alt text provided for this image

Czemu warto? Modele!

  • Wiele najnowszych modeli zintegrowanych w jednym miejscu; Integracja szybko po artykule/implementacji oryginalnej
  • Modele trenowane na ImageNecie 1k i 21k (gotowe do pobrania, by zacząć transfer learning)
  • Architektury CNN, MLP i transformery + wagi
  • Jest tam vit_large_patch16_384 (87.1% top-1) ale też tf_efficientnet_l2_ns (88.3% top-1) czy beit_large_patch16_512 (88.6% top-1) – możesz skorzystać z listy pod tym linkiem:

Czemu warto? Optymalizatory.

Jest ich wiele, więcej niż w torch.optim: SGD, Adam, AdamW, Nadam, Radam, AdamP, SGDP, Adadelta, Adafactor, ADAHESSIAN, RMSprop, NovoGrad, a oprócz nich znajdziesz 4 optymalizatory z Nvidia Apex, działające tylko na GPU.

No alt text provided for this image

Są jeszcze LR Schedulery (SGDR, StepLR, Tanh, Plateau), Augmentation (Mixup, CutMix, RandAugment, Random Erase, AutoAugment, Random Resized Crop And Interpolation) i skrypty do treningu i walidacji.

TIMM powstaje przy wsparciu Nvidia’i i programu TensorFlow Research Cloud (TFRC).

18. Modele jako aplikacje demo

Przygotowując model, możesz mieć potrzebę przygotowania aplikacji demo, aby wygodnie model przetestować. Jest na to jeden prosty sposób, który pozwoli Ci to zrobić w kilkunastu czy kilkudziesięciu liniach kodu.

Wystarczy, że przygotujesz 2 rzeczy:

  • wczytasz zapisany, wytrenowany model swojej sieci
  • przygotujesz funkcję predict, która otrzyma obraz wejściowy (bądź obrazy), wykona predykcję i zwróci wynik (wyniki)

Oprócz tego dodajesz jedną linię z definicją interfejsu użytkownika – wejście, wyjście, nazwa, opis…

O jakiej aplikacji/frameworku mowa? Gradio:

https://gradio.app/

Gradio jest już częścią Hugginface, co nastąpiło po niedługim czasie od kiedy w Hugginface Spaces możesz tworzyć proste dema swoich modeli do analizy obrazu. Tak, obrazu w hugginface, to już nie jest tylko NLP.

Tak wygląda schemat pisania kodu:

import gradio as gr

def image_classifier(image):
  # Implement image classification model here...
  # Return label of confidences

iface = gr.Interface(fn=image_classifier, inputs="webcam", outputs="label").launch()

Zobacz przykład segmentacji semantycznej na bazie SegFormera z Huggifnace.

Tak wygląda kod:

https://huggingface.co/spaces/karolmajek/SegFormer/blob/main/app.py

A tak wygląda aplikacja:

https://huggingface.co/spaces/karolmajek/SegFormer

No alt text provided for this image
No alt text provided for this image

Korzystając z higginface spaces możesz udostępnić model w formie aplikacji demo – model będzie uruchamiany na CPU, w wersji darmowej. Nie ma ograniczenia na liczbę modeli, jakie udostępnisz w formie spaces.

19. Czy klasyfikacja obrazu jest rozwiązana?

http://proceedings.mlr.press/v119/shankar20c.html

Na czym stoimy w klasyfikacji obrazu? Czy problem został już rozwiązany? Może tak jak samochody w 2016 wg Muska 🙂 No czyli ani trochę. Może z klasyfikacją jest znacznie lepiej, natomiast z samochodami autonomicznymi zdecydowanie nie.

Pytanie brzmi, jak naprawdę sobie radzą sieci neuronowe, czy rzeczywiście potrafią generalizować – klasyfikować dane w rzeczywistości, uogólniając koncepty znane ze zbioru treningowego.

W artykule “Evaluating Machine Accuracy on ImageNet” wykonano badanie z udziałem ludzi, których nauczono klasyfikowania zdjęć zgodnie z klasami z ImageNetu. Następnie porównano wyniki ludzi oraz sieci neuronowych na zbiorze ImageNetv2 – zbiorze testowym o 10,000 obrazów, przygotowanych 10 lat później niż oryginalny zbiór. Różnica dekady gwarantuje dobry test generalizacji.

Co się okazuje?

No alt text provided for this image

Jest znacząca różnica pomiędzy tym, jak radzą sobie modele i ludzie – po “treningu” na zbiorze ImageNetV1. Co więcej – nie pomaga nawet dodanie dodatkowych danych – wciąż modele układają się poniżej prostej y=x, pokazującej identyczny performance na obu zbiorach. Różnica pomiędzy sieciami, a ludźmi to blisko 10 punktów procentowych.

Co ciekawsze – etykiety w oryginalnym zbiorze mniej się podobają ludziom, niż predykcje modelu co widać w artykule: “Are we done with ImageNet?”. Dlatego też wprowadzono poprawione etykiety – ReaL (Reassessed Labels).

Jest znacząca różnica pomiędzy tym, jak radzą sobie modele i ludzie – po “treningu” na zbiorze ImageNetV1. Co więcej – nie pomaga nawet dodanie dodatkowych danych – wciąż modele układają się poniżej prostej y=x, pokazującej identyczny performance na obu zbiorach. Różnica pomiędzy sieciami, a ludźmi to blisko 10 punktów procentowych.

Co ciekawsze – etykiety w oryginalnym zbiorze mniej się podobają ludziom, niż predykcje modelu co widać w artykule: “Are we done with ImageNet?”. Dlatego też wprowadzono poprawione etykiety – ReaL (Reassessed Labels).

No alt text provided for this image

Podsumowując – to jeszcze nie koniec walki z klasyfikacją obrazu, wciąż nowe metody mają pewien zapas – na 1000 etykiet, jak i na pełnym zbiorze ponad 21 tysięcy klas.

20. Preprocessing kontra przestrzenie barw

https://scikit-image.org/docs/dev/auto_examples/edges/plot_active_contours.html
https://scikit-image.org/docs/dev/auto_examples/edges/plot_active_contours.html

Przetwarzając obrazy, zwykle reprezentujesz kolory jako składowe RGB. To oczywiście nie musi być ograniczeniem. Możesz przecież skorzystać z jednej z istniejących przestrzeni barw. Jest ich naprawdę dużo. Część z nich wyróżnia luminancję i chrominancję, część barwę, jasność i nasycenie. Pierwszą myślą może być, że warto byłoby skorzystać z przestrzeni HSV (Hue, Saturation, Value), która oferuje barwę jako osobny kanał. Tu przestrzegam – ten włąśnie kanał Hue wprowadza artefakty w reprezentacji. No ale to jest opcja.

Z ciekawych podejść – możesz wykorzystać na wejściu do sieci neuronowej dowolną liczbę kanałów obrazu (nie musi to być 1 lub 3 – RGB). Możesz np. użyć 6 kanałów – RGB+HSV. Wiele eksperymentów w tym temacie wykonano w artykule ColorNet:

ColorNet: Investigating the importance of color spaces for image classification

https://arxiv.org/abs/1902.00267

W artykule najlepsze wyniki uzyskano łącząc 5 (!) przestrzeni barw – RGB+HSV+YUV+LAB+HED. Także możesz sprawdzić podobne podejście, czy przypadkiem nie poprawi wyników u Ciebie, a może tak być, np. gdy klasy różnią się nasyceniem koloru.

Możesz również wykonać prostą segmentację, po nasyceniu korzystając z przestrzeni barw, albo wg innego kanału/przestrzeni. Segmentacja może pozwolić znaleźć istotny fragment zdjęcia i np. wyciąć/wykadrować na obiekcie, a może usunąć tło wokół obiektu?

Możesz zastosować techniki z Scikit-Segmentation – jest tam kilka “klasycznych metod” → niesieci:

https://scikit-image.org/docs/dev/api/skimage.segmentation.html

A oprócz tego wszystkiego warto zadbać by wejście do sieci neuronowej było w okolicy zera – by wartości nie były duże, na pewno, by nie były to wartości 0..255. Chodzi o stabilność numeryczną treningu. Zastosować możesz 2 techniki – prostą normalizację, by uzyskać wartości 0..1, albo -1..1, czy -0,5..0,5. Inną możliwością jest standaryzacja – wyzerowanie średniej i zapewnienie jednostkowej wariancji. Na pewno warto za każdym razem stosować dokładnie tę samą procedurę przygotowania wejścia sieci.

21. CNN vs MLP

https://arxiv.org/abs/2105.01601
https://arxiv.org/abs/2105.01601

Czy sieci konwolucyjne to idealne rozwiązanie do obrazu? Czy to faktycznie ostateczność i nie da się lepiej? Czy ta kwestia jest zamknięta? O tym za chwilę.

Przez ponad 2 dekady wydawało się, że to rozwiązanie, że tak już być musi. To przecież intuicyjne, że otoczenie pikseli jest istotne, by wydobyć cechy z obrazu. Cechy w różnej skali, czasem niezależne od rotacji. Czy można chcieć czegoś więcej?

Kwestia nie jest zamknięta. Pozostaje niezależność względem permutacji fragmentów obrazu. Tutaj ciekawym głosem są sieci MLP (Multi-Layer Perceptron), można by rzec, że klasyka sieci neuronowych, powrót do korzeni. MLP Mixer to architektura, która wprowadza przetwarzanie fragmentów obrazu za pomocą warstw MLP. Ciekawą obserwacją jest fakt, że sieć można trenować także na danych o przemieszanych wartościach pikseli. Globalne przemieszanie pikseli już wpływa na wynik, ale i tak znacznie mniej niż w przypadku sieci konwolucyjnych, które nie są gotowe na taki problem.

No alt text provided for this image

Nie warto lekceważyć tego powrotu MLP, mimo tego, że obecnie nie gwarantują wyników na poziomie sieci konwolucyjnych, czy sieci opartych na transformerze.

https://arxiv.org/abs/2105.01601v2

Tolstikhin, Ilya, et al. „Mlp-mixer: An all-mlp architecture for vision.” arXiv preprint arXiv:2105.01601 (2021).

22. Konwolucja vs transformer

Konwolucyjne sieci neuronowe podejmują decyzję przede wszystkim na podstawie tekstury. O tym możesz przeczytać w artykule “ImageNet-trained CNNs are biased towards texture; increasing shape bias improves accuracy and robustness” https://arxiv.org/abs/1811.12231

No alt text provided for this image

Czy ten shape bias spotkasz także w transformerze?

Transformer czy CNN – jakie architektury “bardziej ludzko patrzą” na obraz?

Wspaniały wykres znajdziesz w artykule “Are Convolutional Neural Networks or Transformers more like human vision?” https://arxiv.org/abs/2105.07197. Z podziałek na klsay możesz zaobserwować, które z podejść jest bliższe ludzkiej percepcji. Okazuje się, że transformery średnio częściej podejmują decyzje na podstawie kształtu, a nie tekstury.

No alt text provided for this image

To może być kluczowe w niektórych aplikacjach – jeżeli chcesz podejmować decyzję na podstawie tekstury, bo jest ona istotna – spróbuj z CNN, natomiast jeżeli chcesz klasyfikować niezależnie od tekstury – możliwe, że lepszym wyborem będzie transformer.

23. Obrazy vs 3D

Obraz z kamer to najczęściej 3 wartości per pixel, które kodują barwę, intensywność i jasność za pomocą położenia w przestrzeni RGB. Oczywiście to duże uproszczenie, bo przecież kamery rejestrują więcej zielonego i należy wykonać Debayer, by uzyskać postać RGB.

Natomiast nie o tym. Bardziej o różnego rodzaju danych. Np. RGBD – oprócz informacji o barwie, intensywności czy jasności kodowana jest również głębia – odległość przedmiotów od kamery. Tego typu dane spotkasz w sensorach głębi opartych o stereowizję, oświetlenie strukturalne (Kinect, Realsense), czy fuzję sensorów. Do przetwarzania takich danych wystarczą zwykłe konwolucje 2D, wzrośnie liczba map cech na wejściu z 3 kanałów na 4.

Przykład z kamery głębi Realsense D435

No alt text provided for this image

Innymi danymi jakie możesz spotkać są dane wolumetryczne. Obraz składający się z wielu warstw np. 512 warstw, a każda z nich o wielkości 512x512px. Minimalnym przykładem jest zbiór danych MedMNIST 3D (dowolny z 6 dostępnych podzbiorów) ze obrazami 28x28x28px z 2021 roku. Tego typu dane możesz spotkać w obrazowaniach, które odwzrorowują 1 cechę w przestrzeni 3d podzielonej na voxele. Częstym przypadkiem jest medycyna wraz z badaniami CT (Tomografia komputerowa) czy MRA (Angiografia metodą rezonansu magnetycznego). Do analizy takich danych warto korzystać z konwolucji 3D – która bierze pod uwagę sąsiedztwo pikseli w 3D

https://medmnist.com/

No alt text provided for this image

Powyższe zakłada wykorzystanie voxeli – natomiast są zastosowania, w których dane 3D są rzadkie, nie wykorzystujemy większości z istniejących voxeli, nie mamy o nich informacji. W takim przypadku mówimy o niezorganizowanej chmurze punktów. Analiza takich danych może być przeprowadzona na różne sposoby – poprzez rzutowanie na płaszczyznę i uzyskanie obrazu, jako voxele czy w formacie źródłowych jako chmura punktów (których kolejność można dowolnie zamienić bez wpływu na wynik). Dodatkowo każdy punkt 3D może mieć powiązane ze sobą dodatkowe informacje, jak intensywność odbicia wiązki laserowej (urządzenia mierzące czas powrotu wiązki)

24. Udostępnianie, wdrażanie modeli

https://developer.nvidia.com/nvidia-triton-inference-server
https://developer.nvidia.com/nvidia-triton-inference-server

Pominę fakt, że sposobów jest całe mnóstwo. Z rzeczy przydatnych do wersji demo to zajrzyj do jednego z poprzednich wpisów o Gradio – mega narzędzie. Do wdrożeń możesz skorzystać z TensorFlow Serving czy Torch Serve, w zależności od wykorzystywanego frameworku. Oczywiście w obu przypadkach możesz też przekonwertować model do ONNX i w ten sposób z niego korzystać.

Narzędzia do wdrażania modeli pozwalają wersjonować model – np. serwować tylko najnowszą, bądź wybraną wersję. Często możesz udostępniać wiele wersji, tak by móc łatwo porównać działanie przed i po zmianach.

Gdy korzystasz z karty graficznej (w domyśle Nvidia), warto wykorzystać TensorRT. Pozwoli Co zoptymalizować wykorzystanie karty graficznej, przyspieszając znacznie działanie modelu. Tu będziesz potrzebować konwersji do ONNX, by przekonwertować do TRT.

Mówiąc o GPU, warto wspomnieć o NVIDIA Triton Inference Server, który obsługuje wiele modeli, które możesz wersjonować. Jest to gotowe rozwiązania, które uruchomisz jako kontener, by móc natychmiast wysyłać żądania przez API.

Wiele firm tworzy też własne narzędzia, prostsze czy bardziej skomplikowane, ale dostosowane do logiki biznesowej, procesów, ulokowania i rodzaju infrastruktury. Jeżeli nie chcesz tworzyć własnych narzędzi – rozważ wykorzystanie dużych frameworków, ze względu na duże i zróżnicowane community.

Podsumowanie

Powyższe treści udostępniałem na Linkedinie w dniach 01-24.12.2021 i to była dobra przygoda! Oprócz tego pokazywałem te treści dla obserwujących mnie na instagramie. Mogę zachęcić do obserwowania mnie w mediach społecznościowych, ale znacznie bardziej mogę polecić dołączenie do mailingu DeepDrive.pl
Oto i link – do zobaczenia!

Close