Origin story about testers team which transformed to a team of programmers writing custom software for ML and AI testing. How we started, what mistakes we did and how we solved them.
5. 5
OpenVINO™ - Intel® DLDT
• Common API for CPU, GPU,
Movidius™, FPGA
• Pre-trained models
• And much more!
https://software.intel.com/en-us/openvino-toolkit/
Intel® Movidius™ NCS
Test it yourself!
https://developer.movidius.com
8. 8
Glossary
• Training – process of teaching the neural network model
• Inference – act of using trained network model to work
• Benchmarking (aka „testing”) – research for the conditions in which it’s the
fastest
13. 13
Difficulties in benchmarking DL software
• Lack of documentation
• Quality of DL software
• Working with dev branches
• Influence of software environment
• Influence of hardware environment
• Client’s use case scenarios
40. 40
Case study
• Install software stack
• Datasets sync
• Enabled in Jenkins
• New configuration in Scheduler
• 1200 unique configurations tested
• All remotly
24h
Cześć
Mam na imię Michał, jestem programistą w zespole benchmarkingu, w dziale Intel AI.
Nasz zespół jest odpowiedzialny za research, pomiary, i wspieranie klientów w uruchamianiu narzędzi AI w oparciu o rozwiązania Intela.
Dziś chciałbym Wam opowiedzieć jak zespół testerów przekształcił się w zespół programistów tworzących narzędzia do benchmarkingu AI.
AI jako dyscyplina nauki i tworzenia oprogramowania w ostatnich latach rośnie w niesamowitym tempie.
Duże korporacje inwestują w nią spore środki – tak Facebook, jak Google, Amazon, Microsoft, Baidu, oczywiście Intel!
Ale prawdziwą siłą tych jest społeczność, która napędza rozwój tych technologii, zwłaszcza w zakresie rozwoju frameworków do deep learningu.’
Dzięki temu zwiększaja się skuteczność tych narzędzi, ich wydajnosć i obszar możliwych zastosowań.
Wpływ na popularność tych technologii mają też dostawcy usług chmurowych, którzy udostępniają wiele narzędzi DL w całkiem przystępny sposób.
Powstaje jednak pytanie – w jakie rozwiązania opłaca się inwestować?
Albo – z punktu widzenia usługobiorcy – które rozwiązania dostarczą możliwie najlepszych rezultatów przy możliwie ograniczonych kosztach
Na te i wiele innych pytań nasz zespół pomaga znaleźć odpowiedzi.
Dla przykładu: nasz site w Gdańsku współpracuje ze szwajcarskim CERNem.
Dzięki pracy mojego kolegi CERN zastąpił analitykę opartą o algorytmy Monte Carlo, nowoczesnymi sieciami GANN.
Przy zachowanej precyzji prognozowania wyników obliczenia trwają 2000 razy szybciej.
Jeśli pracuje się z petabajtami nowych danych dziennie – to ma znaczenie.
Tyle tytułem wstępu.
Zanim jednak przejdziemy do spraw technicznych chciałem wyjasnić trzy najważniejsze terminy, które będą się przewijać.
Trening czyli proces nauczania.
Załóżmy, że potrzebujemy narzędzia do klasyfikacji emocji na podstawie zdjęć.
Składamy zestaw trzech elementów:
Frameworka DL (1)
Który korzystając z ogromnych zestawów danych referencyjnych, nazywanych datasetami (2)
będzie uczył sieć neuronową (3), czyli nadawał odpowiednim operacjom przez nią wykonywane odpowiednie wagi
Wnioskowanie, albo klasyfikacja, czyli po prostu używanie wcześniej wytrenowanej sieci do pracy, którą dla nie przewidzieliśmy
Benchmarkingiem albo testowaniem (wydajności) będę nazywał złożony proces poszukiwania warunków środowiska, w któych powyższe wykonują się najszybciej.
Gdy w zeszłym roku zaczynałem moją przygodę z benchmarkingiem AI nasz zespół zajmował się 3 frameworkami i zaczynaliśmy uruchmiać czwarty.
Dziś mamy tego znacznie więcej.
W ogóle Intel dość aktywnie uczestniczy i wspiera autorów zajmujących się Deep Learningiem.
Optymalizujemy istniejące na rynku rozwiązania, ściśle współpracując z firmami i społecznościami, które sie nimi opiekują
Dostarczamy bibliotekę MKL-DNN
Niskopoziomowa biblioteka optymalizująca operacje matematyczne z wykorzystaniem instrukcji AVX na procesorach Xeon.
nGraph
wysokopoziomowa biblioteka, która dostarcza zunifikowane api do wielu frameworków i modeli
Kompilator grafów dający dodatkow performance boost.
A my, nasz zespół, to wszystko cierpliwie badamy.
Jak to wygląda w liczbach
8,79,26,48,17
Te i kilka innych parametrów, które składają się na argumenty wejściowe każdego pomiaru nazywamy „konfiguracją”
Rok temu wykonywaliśmy pomiary dla 9 konfiguracji.
W czerwcu 2018 wykonaliśmy pomiary dla niemalże 11 tys różnych konfiguracji dla samej tylko inferencji.
Ale skąd pomysł, żeby napisać całe środowisko samodzielnie?
Oprogramowanie do Machine Learningu czy AI nie jest standaryzowane w żaden sposób.
Nie ma na rynku gotowych do użycia narzędzi.
Reagujemy na potrzeby klientów bez czekania na zewnętrznych dostawców.
Jesteśmy dzięki temu szybsi i bardziej elastyczni.
Pisaniu oprogramowania do mierzenia AI to przygoda.
Nieudokumentowane ficzery
Grzebanie po kodzie źródłowym frameworków
Frameworki, jak każdy soft mają błędy. regresje wydajnościowe, uniemożliwiały np. zbudowanie frameworkaBranche developerskich. Niestabilność + brak dokumentacji
Systemy operacyjne tylko o Linuxach Bare metalu vs Dockera..
Wpływ sprzętu. Różny typ kości ram Rozkład kości w bankach pamięci Różne typy dysków twardych
I jeszcze parę innych drobiazgów.
Klienci czy streamują Ile strumieni dane z dysku? w ramie? (n)instances vs (n) sockets
Dla waszej informacji – rozkład kości RAM w bankach może być bardzo ważny.
Dla czasu treningów sieci – rodzaj dysku twardego może być kluczowyc.
Aaa – i zwracajcie uwagę na temperatury jednostek obliczeniowych, z których korzystacie puszczając inferencje.
nie wszystkie aspekty, jest tego sporo.
masa ciekawych zagadnień,
codzienność kolorową
NIE mechaniczne testów autentyczny research.
Wszystko to musimy nie tylko rozumieć, ale i kontrolować, aby przygotować dobry soft, zwracający wiarygodne wyniki.
Ponieważ na koniec dnia od zespołu zajmującego się benchmarkingiem oczekuje się jednego.
Prawdy.
Nasz system do benchmarkowania AI opiera się na kilku komponentach.
Egzekutorów (kontrolowanych przez Jenkins)
Scheduler
I narzędzia, w którym zbierane są wyniki pomiarów – nazywamy go bardzo nietypowo, bo „Dashboardem”.
Plus kilka narzędzi towarzyszących, o których później.
ręcznie, bare metal
Dashboard
Super proste i działało
Szybkie błędy, szybki fix = uczyliśmy się benchmarkingu
Więcej konfiguracji, potrzeba inaczej
Potrzebowaliśmy czegoś co puszcza skrypty za nas
Zdecydowaliśmy się na Jenkinsa. W połączeniu z groovy’m okazał się całkiem elastycznym narzędziem i do dziś z niego korzystamy.
Groovy pipeline nasze skrypty
Fajne
Maszyny, lokalizacja, kontrola
OS wpływa
Docker, wpływ
dockerfile, maszyna, build, test suite
Nieźle, byliśmy zadowoleni z efektywności
Wydajność była na tyle dobra, że zaczęliśmy rozwijać Dashboard by był w stanie przetwarzać rosnącą pulę danych.
W pierwszej kolejności przenieślimy się z hosta pod biurkiem do firmowej chmury.
To pozwoliło nam na przykład łatwo skalować końcówki web’owe
Wóczas mogliśmy zacząć dodawać kolejne zabawki.
cache = mongo statyczne dane
awaria, failover, dodatkowa obsługa
Odbieranie danych priorytetem
Dwie kopie, tanio
Jedna mierzy stabilność, druga benchmarkuje
Wymieniają dane
Uruchomiliśmy więc kolejkę i asynchronicznego workera.
Każdy nowy wynik wyzwalał event, który przesyłany przez kolejkę dawał zajęcie naszemu workerowi.
Tem mógł wykonywać założone operacje w swoim tempie, bez szczególnego pośpiechu.
Typowe operacje związane z przetworzeniem nowego wyniku trwają ok 1.5 sekundy.
Czasami jednak mamy „sztormy” i schodzi naprawdę dużo wyników w krótkim okresie czasu.
Zdarza się wówczas, że worker jest przesunięty z obsługą kolejnych wyników nawet o kilka minut w stosunku do API odbierającego wyniki.
Wsystko zdawało się działać perfekcyjnie.
Do momentu gdy pojawiły się „szybkie zlecenia” oraz gdy niektóre konfiguracje stały się wazniejsze od innych.
Dużym problem było też to, że jeśli do skryptów uruchamiających suitę danego frameworka wkradł się błąd to dowiadywaliśmy się o tym np. po dwóch dniach, gdy przychodziła jego kolei.
Nawet szybka poprawka nie miała znaczenia, bo gdy framework wypadł z kolejki trafiał na koniec listy i musiał swoje odczekać.
W jednym, skrajnym przypadku problemów było tyle, że nie zebralismy wyników konkretnego frameworka przez prawie dwa tygodnie.
Nasz prosty i efektywny system kopnął nas w dupę.
Musieliśmy coś zmienić.
Jako rozwiązanie wybraliśmy kolejne narzędzie, które nazwaliśmy „Scheduler”.
Przechowuje on kompletną listę wszystkich konfiguracji przewidzianych do benchmarkowania., wraz z priorytetami.
Scheduler odbiera z Dashboardu informację kiedy były dostarczone wyniki dla konkretnej konfiguracji, porównuje to z własnymi wyliczeniami i decyduje jaka nastrępna konfiguracja powinna być pomierzona.
Żądanie wykonania pomiaru było wysyłane przez Rest API do Jenkinsa.
To oznaczało jednakże, że nasze pipeline’y i skrypty uruchhomieniowe trzeba było poważnie pozmieniać, tak by przyjmowały parametry.
Rzecz jasna nie było to dla nas żadną przeszkodą!
Przepisaliśmy wszystkie joby w jenkinsie aby przyjmowały parametry, i przekazywały je do skryptów uruchomienioych (argumenty dostępne przez formularz są z automatu dostepne przez pozostałe API Jenkinsa)
Wszystko
Naszym podstawowym błędem było rozgrzebanie trzech powiązanych narzędzi w tym samym czasie.
Głównym problemem Schedulera był słaby research jaki wpływ wywoła jego działanie na pozostałe elementy systemu.
Skupiliśmy się tylko na potrzebie priorytezacji zadań
Zapomniało się nam natomiast o takich detalach jak obciążenie maszyn testoweych jak i pozostałych węzłów w systemi pomiarowym, albo np. o tym jakie limity ma kolejka zadań w Jenkinsie.
Więc, oczywiście, w pierwszym strzale Scheduler zapchał kolejkę Jenkinsa pod korek.
Jenkins się złożył.
Naprawiliśmy to.
Od tego momentu Scheduler miał grzecznie pytać, czy może przypadkiem Jenkins ma akurat wolną maszynę danego typu, co by na niej puścić benchmark.
Tyle że potrafił pytać o to nawet kilkaset razy na minutę.
Jenkinsowi to wystarczyło.
Pożarł dostępny RAM i się złożył.
JAVA to jednak genialny język, wspaniały.
Ok, zmniejszyliśmy częstotliwość odpytywania Jenkinsa.
Maszyny testowe zaczęły się nudzić, bo testy szły szybciej niż trwał interwał Schedulera.
Efektywność naszych pomiarów spadła na pysk.
Co więcej konfiguracje, z których korzystał Scheduler opisywane były w plikach yamlowych.
Nadmierna wiara w ludzi dość szybko wróciła z zadaniem na napisanie prawdziwego mechanizmu obsługi błedów w plikach yaml.
Jednocześnie dzielnie poprawialiśmy nasze skrypty uruchamiające benchmarki.
Ponieważ całośc pisana była nadal w bashu więc długie suity testowowe wzbogaciły sie o cała masę fajnych if’ów, hacków i szczególnych przypadków., aby obsłużyć parametryzację.
Jak łatwo się domyślić – nie poprawiło to jakości kodu.
A przecież jednocześnie cały czas włączaliśmy do pomiarów nowe konfiuguracje!
To był przepis na katastrofę.
W konsekwencji regresje były na porządku dziennym, a kod powoli przestawał się nadawać do utrzymania.
Dashboard też zresztą miał swoje problemy.
Np, zdarzało mu się nie zdążyć odświeżyć snapshotów z datami wyników dla Schedulera.
W konsekwencji Scheduler potrafił puścić ten sam benchmark kilka razy pod rząd.
Ciekawego psikusa sprawiło nam Mongo, które w określonych warunkach potrafiło stworzyć dwa dokumenty z tym samym kluczem.
Nie muszę chyba udowadniać, że dawało to spektakularne efekty w logice biznesowej, która próbowała polegać na tych informacjach.
O czym nie wspomniałem, ale w międzyczasie dorobiliśmy się narzędzia, które budowało nam obrazy docker’owe dla frameworków.
W założeniu na daną maszynę pomiarową miał trafiać obraz z kompletnym środowiskiem testowym.
Na początku jednak okazało się, że niektóre obrazy miewają ponad 10GB.
Gdy próbujesz szybko ściągnąć taki obraz przez ocean na swoją maszynę – możesz być zawiedziony.
Sam proces budowania i testowania tych obrazów także nie zawsze działał tak jak tego od niego wymagaliśmy.
W efekcie od komendy wykonania pomiaru do zakończenia uruchamiania środowiska testowego mijało nierzadko ponad 30 min.
Dla ludzi, którzy mierzą jak szybko coś działa było to jak cioz z liścia w twarz.
A przy okazji to także wyraźnie wpłynęło na ilość danych, które mogliśmy zebrać w ciągu doby.
Osobną klasę problemów wprowadzało utrzymanie datasetów na maszynach. W konkretnych wersjach. W konkretnych miejscu. Z różnych poworód zajęło nam trochę czasu zanim to opanowaliśmy.
Datasety są o tyle ważne, że pełnią rolę danych referencyjnych. W miernictwie to dość kluczowe, aby dane rerencyjne były znane i zgodne z oczekiwaniami.
Przez moment chaos był nie do opisania, a nasza efektywność w zbieraniu wyników, ale i włączaniu nowych konfiiguracji do pomiarów leciała na łeb na szyję.
W lutym stwierdziliśmy, że mamy już dość.
Wykonaliśmy rachunek sumienia i zidentyfikowaliśmy źródła naszych problemów.
Nowa, lepsza lista wymagań wyglądała tak:
Aktualnie włączone testy muszą się uruchamiać na maszynie tak szybko jak to możliwe. Czas przygotowania środowiska powinien być jak najmniejszy
Skrypty do nowych konfiguracji pomiarowycj (zwłaszcza do nowycj modeli) powinny być pisane efektywnie, bez dotykania już istniejących
Dashboard powinien zapewniać stabilne i wiarygodne wsparcie dla Schedulera i osbierać wyniki benchmarków bez przerw.
Scheduler ma zapewnić możliwie wysoką utylizację maszyn pomiarowych, ale bez przeciążania Jenkinsa i Dashboardu.
Scheduler został wyposażony w lepszą, bardziej wysublimowaną logikę.
Pozwala mu to mądrzej zarządzać kolejką testów do wykonania bez zażynania Dashboardu i Jenkinsa zapytaniami.
Utylizacja maszyn zaczęła systematycznie wzrastać, choć jeszcze jest obszar do poprawy.
Dla dashboardu zbawieniem okazała się rezygnacją z MongoDB.
Możliwe, że używanie bazy relacyjnej do składowania statycznych danych jest nieco egzotyczne, ale okazało się szybkie i pewne w użyciu.
Lekką ręką przekreśliliśmy fajne gadżety na rzecz spełniania wymagań biznesowych.
Jednakże nawjiększą robotę wykonaliśmy przy skryptach uruchomieniowych.
Zidentyfikowalismy standardowe kroki testu.
Wywaliliśmy wszystkie skrypty w groovym przypisane do frameworków i zastąpiliśmy jednym, wspólnym dla wszystkich
Tym samym API skryptów wykonujących testów także musiało stać się identyczne dla wszystkich frameworków.
O ile dobre zaprojektowanie tego rozwiązania pochłonęło trochę czasu i kawy, o tyle sama implementacja była względnie łatwa.
Bądź co bądź mieilismy i wiedzę i skrypty, które pozwalały nam uruchamiać benchmarki. Trzeba było tylko wyjąć włażne rzeczy z bałaganiu i elegancko poukładać je na nowych, ładnych półkach.
Ale nauczeni poprzednimi doświadczeniami staliśmy się tak czujni, że nawet w obrębie tego jednego narzędzia zmiany wprowadzilimy framework-po frameworku, juz nie wszystko na raz.
Cała architektura była tak zaprojektowana, żeby konkretne komendy, specyficzne np. dla kombinacji framework-model lądowały w osobnych plikach (i przy okazji klasach).
To cudownie proste rozwiązanie załatwia kilka problemów:
dodawanie nowych modeli jest znów szybkie (jeden plik zawierający specyficzny dla modelu zestaw opcji i poleceń),
chroni przed regresjami
a w następnej wersji wprowadzi pokój na świecie.
Jednocześnie nowe podejście dało nam mozliwość korzystania z dokładnie tego samego API egzekutora tak do testów automatycznych jak i ręcznych.
Testy ręczne wykonujemy na przykład gdy developer poprosi o sprawdzenie jakiejś konkretnej zmiany, albo gdy przychodzą zlecenia od naszych klientów na szybkie sprawdzenie lub odtworzenie danego wyniku.
Nowy egzekutor został napisany w pythonie3.
Dlaczego? Bo jest na większości linuxów w zestawie, jest wystarczająco szybki (nie wprowadza mierzalnej regresji wydajnościowych przy benchmarkowaniu) i otwrozył nam drogę do testowalnego kodu, co w przyypadku czystego basha poganianego groovym było raczej trudne. Ponoć możliwe, ale nie znaleźliśmy kozaka, który to udowodnił nam przed oczami.
Jednocześnie uruchomilismy CI do automatycznego testowania zmian (wyzwalan pull requestem), a wprowadzone nieco wcześniej zasady robienia review zaczęły przynosić wreszcie zdrowe owoce.
Poprawiliśmy mechanizm budujący obraz, który w międzyczasie stał się niemalże samodzielnym narzędziem.
Nauczyliśmy się jak ograniczać rozmiar obrazu tak bardzo jak to możliwe
Kluczem okazało się zarówno czyszczenie śmieci po buildach, ale także wiedza o tym jak stosowanie komendy RUN w dockerfile wpływana budowanie i wielkość warstw okazała się bardzo ważna.
Ten sam podsystem dostarcza zintegorwaną suitę testującą nowe obrazy. Jeśli obraz przejdzie testy jest wypychany na wewnętrznego huba dockerowego i stamtąd trafia na kolejne maszyny pomiarowe.
Każda maszyna włączona do pomiarów przechowuje zestaw gotowych do użycia kontenerów bazujących na tych obrazach.
Tylko w przypadku aktualizacji obrazu mogą występować opóźnienia. W pozostałych przypadkach start środowiska testowego trwa sekundy.
Pro tip: use "yum clean all" or "" and "apt-get autoremove -y"
(memo: add this to slides)
Przyznam, że gdy przygotowując się do prezentacji zrobiłem tą ilustrację to sam się trochę zaskoczyłem.
Trochę tu się dzieje jak na to tak spojrzeć z dużego obrazka...
Tak czy inaczej – to wreszcie działa.
Mamy jeszcze sporo pomysłów na usprawnienia, ale możemy je mieć, bo system z nami współpracuje i są tego efekty.
Bardzo dobre efekty.
Niechcący wykonane stress testy wykazały, że cały system jest w stanie wykonać co najmniej 20 tys pomiarów tygodniowo.
Aktualnie nie wykorzystujemy pełnych możliwości, które sobie stworzyliśmy zadowalając się spełnianiem założeń co do interwału odświeżania wyników wg priotytetów.
Bufor, który zostaje wykorzystujemy na wykonywanie „wrzutek”, ale tak po prawdzie to czeka na kolejne modele i kolejne platformy, które będziemy uruchamiać w nadchodzących miesiącach.
Wykres który widzicie pokazuje rosnący trend jeśli chodzi o ilość zbieranych miesięcznie wyników. Warto tu zaznaczyć, że pod koniec maja wyłączyliśmy trzy maszyny z pomiarów. I nie spada...
Widać też tu wyraźnie gdzie się potknęliśmy :))
A propos nowych platform. W zeszłym tygodniu dostalismy prośbę o przetestowanie zestawu konfiguracji na platformie, której do tej pory nie używaliśmy.
W ciągu 24h
przygotowaliśmy ją pod nasze dockery
zsynchronizowaliśmy datasety
Podpięlismy ją do Jenkinsa i wprowadzliśmy do konfiguracji Schedulera
A następnie zebralismy 1200 wyników dla unikalnych konfiguracji
6 miesięcy temu nie moglismy nawet marzyć o takiej efektywności.
Co dalej?
Doroślejemy i zaczynamy wprowadzać standardy do naszych narzędzi.
Skrypty egzekutora jak wcześniej wspomniałem stały się testowalne a nawet korzystają w swojej implementacji z wzorców projektowych (np. fabryki).
Dashnboard (napisany w PHP7.1 nawiasem mówiąc) dorobi się Rest API, a GUI zostanie przepisane do Angulara.
Ustandaryzowanie metod komunikacji z główną bazą danych zawierającą wyniki bardzo pomoże nam w integracji z innymi zespołami dostarczającymi różne ciekawe dane.
Inną zaletą jest łatwiejsze wprowadzanie nowych funkcji, co aktualnie nie zawsze jest przyjemne.
Planujemy też dodać kolejne narzędzia analityczne i poszerzeyć możliwości istniejących.
Scheduler dostanie własne GUI i bazę danych.
Pozwoli to pozbyć się wrażliwości na błędy w plikach yaml’owych, a jednocześnie pozwoli nam monitorować wykonywanie tasków, kolejkę planowanych pomiarów i parę innych informacji, których Scheduler jest najlepszzym źródłem.
Dziś, po roku nauki, popełnienieu wielu błędów i cierpliwym szukaniu optymalnego dla nas sposobu pracy jako zespołu wreszcie jestey w stanie nie tylko robić dobry research i dobrze zbierać wyniki pomiarów, ale także produkować fajny soft, który automatyzuje i zapewnia wiarygodne testy performance’owe AI.
Zmierzajć do szczęśliwego zakończenia – kto korzysta z danych zbieranych z takim mozołem przez mały zespół w Gdańsku?
Markegin naszej grupy.
Nasi klienci.
Developerzy rozwijający frameworki i modele.
Ale również każdy, kto odwierdzi naszą stronę gdzie regularnie publikowane są wyniki różnych nowych osiągnięć w zakresie perfomance’u inferencji i treningów na platformach Intela.
Dziękuję Wam bardzo za wysłuchanie naszej historii.
Życzę Wam dobrej zabawy z Deep Learningiem!