Już od jakiegoś czasu nosiłem się z zamiarem przejścia z Tensorflow na PyTorch. Poziom skomplikowania, jaki osiągnął TF zaczął mi przeszkadzać, a tych, których uczyłem wręcz przerażał. Przejście na Pytorch było jedną z lepszych decyzji.
Wpis ten zapoczątkował serię artykułów o PyTorch, w każdym artykule opisuję pewien aspekt tej biblioteki oraz przykłady najpopularniejszych architektur sieci neuronowych.
Moja historia przyjaźni z Pytroch’em sięga roku 2017, gdzie na konferencji PyData Warsaw Adam Paszke opowiadał o nowej bibliotece do uczenia maszynowego. Ja wtedy zapalony użytkownik Tensorflow siedziałem i z otwartą gębą słuchałem, jak Adam po kolei zadaje ciosy na korpus dla TF. Każdy punkt dokładnie trafiał w moje dotychczasowe doświadczenia z pracy z biblioteką od Google.
Co prawda słyszałem już wcześniej o Pytorch, ale nigdy wcześniej nie byłem na tyle zmotywowany, aby zacząć się jej uczyć. Dopiero prezentacja oraz krótka rozmowa po prezentacji zmotywowała mnie, aby zacząć ją poznawać.
Co mnie przekonało do Pytorch?
Swoje odczucia opisuję po ponad 8 miesiącach nauki i pracy z Pytorch głównie w wersji 0.4 (obecnie już 1.0).
To, co mnie zachwyciło to prostota oraz filozofia zgodna z Zen Python. W Tensorflow miałem wrażenie pisania w innym języku, w czymś, co tylko przypomina Pythona. Tak jakby był on na siłę dostawioną fasadą.
Dostęp do zmiennych
Na pierwszym miejscu muszę wymienić możliwość łatwego wyświetlenia zawartości zmiennych. Nawet nie wiecie jak mi szczęka opadła, gdy zobaczyłem, że mogę podejrzeć macierz wag w prostej sieci. Z pozoru tak błaha cecha a tak potężna. U mnie rozwiązało to niemal 90% problemów związanych z nauką oraz debugowaniem własnej architektury.
Możliwość podejrzenia zmiennej w debuggerze lub zwyczajne wyprintowanie jej stanu to dla mnie killer feature .
Integracja z numpy
Pracując z danymi na którymś etapie na pewno będziecie zmuszeni do trzymania danych w tablicy numpy. Możliwość łatwego przekazania lub transformowania tych danych do algorytmu uczącego znacząco ułatwia sprawę. Dwie proste funkcje tensor.numpy i from_numpy pozwalają na proste i co ważne szybkie przekształcenie tensora na tablicę numpy lub tablicy na tensor.
Pytorch idzie nawet dalej, bo prócz prostej integracji z numpy dostajemy w pakiecie całą filozofię pracy. To, co mogliśmy zrobić z tablicami możemy w większości zrobić z tensorami: indeksowanie, slicing, zmiana rozmiarów, stacking itp. Mnie to bardzo ułatwiło zrozumienie niektórych aspektów Pytorch oraz samą naukę. Po prostu część API była już mi znajoma już z numpy.
Dynamiczne budowanie grafu obliczeniowego
W odróżnieniu od Tensorflow, który opiera się na podejściu deklaratywnym, w PyTorch w naturalny sposób można dynamicznie (czyli np. z użyciem 'if’) zmieniać architekturę sieci. Pozwala to na dużą elastyczność i ułatwia implementację wielu nowych architektur.
Dostęp do danych – Datasets i Dataloaders
Dla mnie zawsze było bolączką pisanie kodu, który ma wczytać zbiór danych. Każda szanująca się biblioteka ma już gotowe klasy dostępu do popularnych zbiorów jak MNIST, CIFAR czy IMDB. Niestety, gdy chcesz wczytać swój własny dataset to w wielu przypadkach trzeba było napisać coś samemu.
W Pytorch też trzeba napisać trochę kodu, ale poprzez dostarczenie dobrych abstrakcji łatwiej wepniemy się w cały flow. Klasa Dataset dostarcza dobrze zdefiniowany interfejs dostępu do danych. Nie trzeba pisać własnych konstrukcji a tylko podziedziczyć po niej i nadpisać dwie metody (__len__ i __getitem__) . Proste i czytelne, a zarazem dające dużą elastyczność.
Resztę związaną z podziałem na 'batch-e’, wielowątkowym dostępem do danych, kolejkowaniem dostępu, randomizacją, grupowaniem egzemplarzy w ramach paczek oraz transformacją (augumentacja zdjęć, tokenizacja tekstu itp) załatwia Dataloader. Polecam przykład, w którym zadanie polega na wczytywaniu punktów charakterystycznych twarzy https://pytorch.org/tutorials/beginner/data_loading_tutorial.html
Ułatwione uruchamianie na GPU
Gotowy produkcyjny model trenujemy na GPU, ale zanim to nastąpi większość czasu spędzałem na testowaniu sieci na CPU. W Pytorch’u jedną linijką na początku skryptu mogę określić na jakim 'device’ chcę uruchomić.
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
Przystępniejsze API
Ten punkt jest bardzo subiektywny, bo tyczy się konwencji nazewniczych, sposobu projektowania i interakcji. Nazwy metod, klas oraz cała architektura Pytorch jest dla mnie przystępniejsza niż u Tensorflow. Byłem pozytywnie zaskoczony podejściem do obliczania wstecznej propagacji błędów. Jawne wywołanie funkcji .backprop() odpowiada mojej filozofii programowania i projektowania API. Lubię czyste, proste interfejsy wraz z pewną nadmiarowością nazewniczą. Wolę nadmiarowość niż auto-magiczne działanie.
Niektórym może przeszkadzać, że musimy pamiętać, aby np. jawnie wyzerować gradienty. Dla mnie takie explicite podejście jest w zgodzie z filozofią pythona a daje poczucie większej kontroli.
Pytorch community
Bardzo aktywna i chętna do pomocy społeczność dostępna pod adresem https://discuss.pytorch.org/ . Samo forum jest pokaźnym zbiorem wiedzy na temat sposobów implementacji różnych architektur. Odpowiedzi na swoje pytania albo znajdowałem w innych wątkach, albo uzyskiwałem odpowiedź w przeciągu 6h.
Inne zalety, których nie testowałem
Prócz wymienionych zalet, które odczułem na swojej skórze dla kompletności przytoczę te które są także wymieniane:
- obliczenia rozproszone w modelu podobnych do MPI
- torch.jit – jeszcze w fazie beta
Podsumowanie
Tak z ciekawości porównałem Pytorch i Tensorflow na Google Trends. Widać że TF się jeszcze dobrze trzyma, ale dostrzegam już tendencję spadkową. Pytorch idzie w górę i sądzę że rok 2019 będzie zdecydowanie należał tej biblioteki (u mnie na pewno).
Poniżej wklejam aktualizację z 2.12.2019, tak jak sądziłem Pytroch sukcesywnie wspina się w górę. Na pewno na to miał wielki wpływ powstanie bibliotek takich jak: Pytorch-Transformers, Pytorch-Lightning
Z drugiej strony Tensorflow także się trzyma, szczególnie po wydaniu wersji 2.0.
A co znajduje się w waszej skrzynce narzędziowej badacza danych? Pytorch, Tensorflow, fastai, czy jeszcze coś innego?
Jeżeli uważasz ten wpis za wartościowy to Zasubskrybuj bloga. Dostaniesz informacje o nowych artykułach.
PS. Photo by Brendan Church on Unsplash
A fastAi nie jest oparty na Pytorchu?
Tak i jest to dla mnie też argument za pytroch, bo można w fastai pisać własne nn.modules i to działa.
Cześć. Ciekawy wpis. Mozesz zatem powiedzieć osobie, która startuje z ML aby poszła w stronę pytorcha? Czy lepiej za ciosem wpadać do tensorflow i keras a rownoczesnie robić pytorcha? Pozdro!
Ja teraz szedłbym w Pytroch, ciekawy ekosystem, dobre community, dużo nowych architektur jest w nim implementowanych.
Ponadto mam doświadczenia z nauczania innych i łatwiej uczy się Pytorch’a.
Cześć. Ciekawy wpis. Mozesz zatem powiedzieć osobie, która startuje z ML aby poszła w stronę pytorcha? Czy lepiej za ciosem wpadać do tensorflow i keras a rownoczesnie robić pytorcha? A może fast.ai skoro wyszedł kurs v3?Pozdro!
Tak fastai jest na pytorch i to jest moim zdaniem kolejny argument za Pytorch.
Co prawda z fastai miałem krótki romans i brakuje jej jeszcze dobrej dokumentacji.
Łatwość i szybkość implementacji najnowszych technik i modeli bije chyba nawet KERAS.
Cześć!
Wiele rzeczy, które wymieniłeś jako wyższość mają mieć również swoje miejsce w TF 2.0. Jeśli będą spełniać twoje wymagania, jesteś w stanie porzucić PyTorch i wrócić do tensorflow?
Bartek, chyba już nie.
Nie chodzi mi o same funkcjonalności ale lepiej przemyślaną konwencję i architekturę.
Polecam dyskusję na reddit
https://www.reddit.com/r/MachineLearning/comments/9kys38/r_frameworks_mentioned_iclr_20182019_tensorflow/
Ciekawy jest przyrost artykułów w 2019 wykorzystujący pytorch.
Bardzo ciekawy wpis. Sam postaram się coś podziałać z Pytorch!
Pozdrawiam, Mateusz.
Dzięki Mateusz. Ja już wsiąkłem w Pytroch, obecnie zdobył już tak bogaty ekosystem że ciężko mi się przestawić z powrotem na Tensorflow.
Dzięki za blog. Dodaję go do blogów czytanych.
Ze swojej strony dodam, że jakoś nie potrafię się przekonać do Pytorch.
Uczyłem się DL na Tensor (np rozpoznawanie MINST) i kod TF wydaje mi się jakoś bardziej czytelny i bardziej logiczny…