Jacek Bzdak
Magalena Wójcik
Jacek:
Jestem jedyną osobą identyfikującą się jako programista w zespole Data Scientistek/ów, więc chcąc nie chcąc (głównie chcąc) odpowiadam za wszystkie rzeczy związane z jakością projektu i wdrożeniami. Wcześniej pracowałem w fizyce jądrowej z naukowcami i elektronikami.
Przez parę lat uczyłem studentów fizyki rozsądnych praktyk programistycznych.
Magda:
Przez lata kodowałam rzeczy webowe, ale odkrylam moje powołanie, kiedy zobaczyłam przedmiot "Narzędzia sztucznej inteligencji". Od tego czasu robię głównie Data Science, co znaczy, że skupiam się na zjawiskach i prawidłowościach w danych, a mniej na jakości kodu.
Jacek umiarkowanie mnie lubi ze względu na tę jakość.
Prezentację kierujemy do programistów i tech leadów, którzy nieuchronnie spotkają się w pracy z Data Scientistami (albo innymi specjalistami domenowymi). Mamy nadzieję ułatwić zorganizowanie takiej współpracy i uniknięcie konfliktów.
Przyjęliśmy rozróżnienie:
Bad programmers worry about the code. Good programmers worry about data structures and their relationships.
- Linus Torvalds
Data Scientists worry about subject matter,
spurious correlations and data leakages.- Magdalena Wójcik
Data Scientistka to taka programistka, która jest też statystyczką i analityczką w jednym.
Do jej zadań należy modelowanie problemów, projektowanie ekperymentów, implementacja i interpretacja wyników.
Dla programisty najważniejszy jest działający kod.
Dla Data Scientistki/ty najważniejsze są dane i wyniki działania modelu, który może produkować je parę dni.
Problem:
Bezproblemowa współpraca między częścią "data-science" a "programistyczną" (api, webaplikacja).
Rozwiązanie:
Ustalone API zrozumiałe dla wszystkich, przejrzane przez wszystkich i wszyscy uważają, że jest dobre i zdatne do użytku.
Praktyka:
Po pierwszej implementacji trzeba je zmienić, i to jest OK.
@dataclasses.dataclass(frozen=True)
class DetectorResultInstance:
"""Bazowa klasa na wiersz wyniku działania detektora."""
product_id: int
reported_value: float
correct_value: typing.Optional[float]
# ... 15 innych kolumn (potrzeby biznesowe)
class IDetector:
"""Międzymordzie dla szablonów detektorów."""
@abc.abstractmethod
def execute(
self, detector_input: DetectorInput, context: DetectorContext
) -> typing.Iterator[DetectorResultInstance]:
"""
Uruchamia detektor i zwraca jego wyniki. Operacja ta może trwać
długo i jest wykonywana asynchronicznie w kolejce zadań.
"""
raise NotImplementedError
Problem:
Przeglądy kodu mogą być uważane przez Data Scientistów/ki za niepotrzebne (o kod się nie liczy, liczą się dane) i być stresujące/irytujące.
Symptomy:
Czas przez jaki wiszą otwarte PR generuje problemy w projekcie (tj. nagminnie ludzie zaczynają branchować się od swoich PR)
Rozwiązanie:
Dbamy, żeby przeglądy kodu nie były okazją do gate keepingu, raczej do poprawy firmowych praktyk.
Nasza procedura przeglądania kodu:
Problem:
Sytuacja, kiedy dwa zespoły (u nas Data Science i Development) pracują zupełnie niezależnie, nie dzielą się informacjami i współpracują wyłącznie na podstawie formalnych procedur.
Rozwiązanie:
Wymuszamy komunikację i naukę przez wspólną pracę nad projektami, zawsze z udziałem programistów i DS.
Problem:
Wdrożenie aplikacji wykorzystującej model ML dla klienta zwykle leży daleko poza kompetencjami Data Scientista.
Razem z modelem często trzeba wdrożyć też wiele bibliotek w konkretnych wersjach, od których zależą modele ML. Wytrenowane modele są z reguły plikami w nieprzezroczystym formacie i często nie są łatwo portowalne między wersjami biblioteki.
Rozwiązanie:
Wytrenowane modele i zależności pakujemy do dockera, to gwarantuje że wersje się nie rozjadą.
Do zarządzania zależnościami używamy pip-tools.
$ cat requirements.in
Flask
$ pip-compile requirements.in
$ cat requirements.txt
click==6.7 # via flask
flask==0.12.2
itsdangerous==0.24 # via flask
jinja2==2.9.6 # via flask
markupsafe==1.0 # via jinja2
werkzeug==0.12.2 # via flask
Problem:
Do analiz i eksperymentów Data Scientiści korzystają z notebooków, które wewnętrznie są plikami JSON z zserializowanymi wykresami i wynikami obliczeń.
Nie nadają się do wdrożeń, przechowywania w repo, diffowania.
Rozwiązanie:
Korzystamy z biblioteki jupytext, która równolegle z zapisem pliku ipynb zapisuje też py.
W repo przechowujemy tylko pliki py, chyba, że mamy w notatniku ważne wyniki obliczeń.
Problem:
W projektach Data Science powstaje sporo kodu eksperymentalnego.
Przed startem projektu nie wiadomo:
Pierwsza faza projektu zaczyna się od EDA (Eksploracyjna Analiza Danych).
Choć często prototypy nie ograniczają się od EDA.
Rozwiązanie:
Problem:
Programista chce przetestować 100% projektu. Data Scientist wie, że to nie ma sensu. Przykładowo, modele najczęściej przychodzą zaimplementowane w bibliotekach i ekstremalnie rzadko są źródłem błędów.
Rozwiązanie:
Warto testować:
Problem:
Modele i dane często zajmują dziesiątki GB i nie mieszczą się na lokalnych maszynach. Data Scientiści mogą jednocześnie nie czuć się na tyle komfortowo z Linuxem, żeby pracować wygodnie na zdalnej instancji.
Rozwiązanie:
Elektronicy myślą głównie tym jakie urządzenie wyprodukują, ile będzie kosztować w produkcji i jak spełnić wszystkie wymogi stawiane urządzeniu.
- Daniel Kowalski