Pod koniec maja tego roku, załoga Data Science Club PJATK zawitała na hackathonie organizowanym przez Urząd Komisji Nadzoru Finansowego – #Supervision_Hack 2023. Ten artykuł będzie zarówno podsumowaniem całego wydarzenia oczami uczestników, jak i opisem zaprezentowanego przez nas rozwiązania. Nie zabraknie także wzmianki o sukcesie naszego zespołu na tym wydarzeniu.
O wydarzeniu
Druga odsłona tego wydarzenia odbyła się w formie hybrydowej. W trakcie piątkowej inauguracji on-line organizatorzy przybliżyli formę wydarzenia, przedstawili informacje organizacyjne, oraz omówili wyzwania, z jakimi zmierzą się uczestnicy. W tej części nie zabrakło również wzmianki o poprzedniej edycji oraz o nagrodzonych rozwiązaniach. Warto podkreślić, jak istotne są problemy poruszane na hackathonach, czemu dowodzi fakt, że zwycięskie pomysły zostały rozwinięte, a następnie wdrożone, aby służyły nie tylko pracownikom UKNF, ale przede wszystkim nam wszystkim. Powiedzieć, że po to właśnie organizowane są hackathony to oczywiście frazes. Powszechnie znanym jest jednak proceder porzucania takich rozwiązań, stąd trzeba nadmienić, jak bardzo odpowiedzialne jest podejście UKNF w tym zakresie.
Kolejne dwa dni eventu odbyły się stacjonarnie, w prestiżowym budynku The Tides, gdzie organizatorzy postarali się o zapewnienie wszelkich udogodnień, jakie tylko mogli sobie wyobrazić uczestnicy – ciepłe posiłki, przekąski słodkie i słone, zimne napoje, kawa, herbata, oraz, legendarna na każdym hackathonie, pizza! Dodatkowo, w budynku została wydzielona specjalna strefa relaksacyjna, gdzie hackerzy mogli znaleźć wygodne leżaki, worki do niezbędnego chill-out’u, a nawet stacje gier VR. W budynku znaleźli się również wystawcy wielu firm, gdzie przy udekorowanych stoiskach można było porozmawiać z reprezentantami na tematy pracy oraz zgarnąć brandowe długopisy, notatniki, butelki, i tego typu niezbędniki. Nie zabrakło również miejsca, gdzie uczestnicy mogli się spokojnie zdrzemnąć i naładować baterie do dalszego hackowania.
Wyzwanie #FakeJobHunter
Z samego rana w sobotę, każdy ze zgłoszonych zespołów został gorąco powitany gift bagami od organizatorów z drobnymi przedmiotami dnia codziennego z logotypemhackathonu. Nasz zespół, w skład którego wchodzili Paweł Saniewski, Igor Winek, Stanisław Raczkiewicz, Piotr Kojałowicz, i Jacek Jackowski, podjął się jednego z dwóch zadań – #FakeJobHunter. Zadanie miało na celu rozwiązanie coraz bardziej powszechnego problemu wyłudzeń, wykorzystującego internetowych ogłoszeń o pracę. Wykrycie potencjalnych oszustw znacząco poprawiłoby bezpieczeństwo Polaków w sieci. Organizatorzy przygotowali w tym zakresie zbiór przykładowych, fałszywych ofert pracy, a łączyły je takie cechy, jak ponadprzeciętne, wysokie zarobki, brak wymaganych kompetencji, oraz zdalna forma pracy, często prezentowana w nieco skąpym opisie.
Pierwsze kroki
Nasz pięcioosobowy zespół rozpoczął pracę od najważniejszej rzeczy – kawy. Bez wątpienia był to pierwszy, istotny krok w kierunku znalezienia rozwiązania.
Od początku było wiadomo, że nasz zespół musi się zmierzyć z problemem klasyfikacji tekstu. Po wstępnej analizie zbioru danych otrzymanego od organizatorów pewne było jedno – danych było za mało. Wobec tego drużyna podjęła się poszerzenia zbioru o oferty dostępne na wielu portalach w internecie. Staszek, Jacek i Igor skupili się na napisaniu web crawlerów i scrapperów, które w pierwszej kolejności zgromadzą linki do interesujących nas ofert pracy, a następnie pobiorą ich treści i zapiszą w odpowiednim formacie. Równolegle, Paweł przygotował scrapper do ofert pracy opublikowanych na jednej z najpowszechniejszych społecznościówek słynącej z szerokiej gamy ogłoszeń. Zespół skorzystał tutaj przede wszystkim z Selenium i BeautifulSoup. W tym samym czasie, Piotrek – nasz specjalista od infrastruktury – zajął się przygotowywaniem warstwy abstrakcyjnej i orchestratora do scrapperów o znamienitej nazwie “uber scrapper”. Część zespołu do teraz utrzymuje, że to właśnie ta nazwa zawiozła nas do znalezienia rozwiązania! Piotr przygotował również instancję wektorowej bazy danych Qdrant w kontenerze Docker’owym, jednak ta nie została wykorzystana w finalnej wersji.
Po około trzech godzinach od rozpoczęcia konkursu, zespołowi udało się zebrać ponad trzy i pół tysiąca ofert pracy z różnorodnych portali. Dane, oczywiście, wymagały obróbki i w tym celu przeprowadzono preprocessing który ustandaryzował zbiory ofert pochodzące z wielu portali w jeden zbiór mający te same, niezbędne kolumny. Do tego zadania wykorzystano bardzo popularną bibliotekę Pandas.
Podział zadań i efektywne zarządzanie czasem
Następnie, drużyna DSC PJATK podzieliła się na dwie grupy. Jedna (Jacek i Igor) skupiła się na przygotowaniu dashboardu prezentującego działanie aplikacji do wykrywania wyłudzeń, a druga (Staszek, Paweł, Piotrek) skupiła się na przygotowaniu modeli rozwiązujących problem klasyfikacji tekstu.
Podzielony w ten sposób zespół był w stanie pracować nad dwoma niezbędnymi zagadnieniami jednocześnie. Dzięki pracy pierwszej grupy nasz zespół był przygotowany na prezentację live demo z działania aplikacji, a drugi zespół mógł skupić się wyłącznie na modelach klasyfikacji, które miały dawać finalny wynik predykcji. Podział zadań według kompetencji i umiejętności poszczególnych członków zespołu wraz z efektywnym zarządzaniem czasem jest kluczowy w tego typu wyzwaniach, gdzie czas jest ograniczony, a pomysł na rozwiązanie i – przynajmniej – proof of concept, muszą być dowiezione przed upłynięciem dwudziestu czterech godzin. Szczęśliwie, reprezentacja DSC tworzyła zgrany zespół, który nie ugiął się pod presją czasu i stanął na wysokości zadania, co dało efekty opisane w kolejnej części artykułu.
Dashboard
Do utworzenia prototypu aplikacji wykorzystano popularne narzędzie, jakim jest Streamlit. Pozwala ono na bardzo proste i szybkie utworzenie interaktywnej aplikacji webowej, a wszystko to wyłącznie w kodzie Python. Poszczególne instrukcje tworzą schludnie ostylowany layout w HTML’u, logikę z łatwością można podpiąć do poszczególnych komponentów, a całość uruchamia jedno polecenie w terminalu.
Powstała w ten sposób apka webowa pozwalała na uruchomienie modelu i przekazanie do niego treści oferty pracy. Wynik klasyfikacji wyświetlał się w postaci komunikatu ostrzegającym o potencjalnej próbie wyłudzenia lub informującym o braku takiego podejrzenia. Tekst ogłoszenia, w pierwszej wersji, był wyłącznie wklejany do odpowiedniego pola na stronie przez użytkownika, jednak dzięki wspomnianej dobrej organizacji pracy oraz wcześniejszym doświadczeniom Igora i Jacka w użytej technologii, grupie wystarczyło czasu na dodanie bardzo pożądanej funkcjonalności, jaką było pobieranie treści ogłoszeń ze wskazanego linku w czasie rzeczywistym. Do tego wykorzystane zostały mechanizmy zaimplementowane wcześniej w scrapperach. Oto, jak upiec dwie pieczenie na jednym ogniu!
Pierwsze komplikacje, data augmentation
Do utworzenia prototypu aplikacji wykorzystano popularne narzędzie, jakim jest Streamlit. Pozwala ono na bardzo proste i szybkie utworzenie interaktywnej aplikacji webowej, a wszystko to wyłącznie w kodzie Python. Poszczególne instrukcje tworzą schludnie ostylowany layout w HTML’u, logikę z łatwością można podpiąć do poszczególnych komponentów, a całość uruchamia jedno polecenie w terminalu.
Powstała w ten sposób apka webowa pozwalała na uruchomienie modelu i przekazanie do niego treści oferty pracy. Wynik klasyfikacji wyświetlał się w postaci komunikatu ostrzegającym o potencjalnej próbie wyłudzenia lub informującym o braku takiego podejrzenia. Tekst ogłoszenia, w pierwszej wersji, był wyłącznie wklejany do odpowiedniego pola na stronie przez użytkownika, jednak dzięki wspomnianej dobrej organizacji pracy oraz wcześniejszym doświadczeniom Igora i Jacka w użytej technologii, grupie wystarczyło czasu na dodanie bardzo pożądanej funkcjonalności, jaką było pobieranie treści ogłoszeń ze wskazanego linku w czasie rzeczywistym. Do tego wykorzystane zostały mechanizmy zaimplementowane wcześniej w scrapperach. Oto, jak upiec dwie pieczenie na jednym ogniu!
Transformacja tekstu i klastrowanie wektorów
W pierwszym kroku Paweł miał przeprowadzić klastrowanie całego datasetu. W wyniku miały powstać dwa klastry, w których znacząca większość była nieopisana, natomiast między nie opisanymi elementami klastrów znajdowały się opisane dane, które mogły sugerować ogólną klasę każdego z klastrów.
W tym celu, na początku przeprowadzono transformację tekstu na reprezentację liczbową w postaci wektorów embedding’ów. W tym celu wykorzystano bardzo popularny model do transformacji tekstu w języku polskim – “dkleczek/bert-base-polish-uncased-v1”. Operacje modelu obsłużono za pomocą biblioteki oferowanej przez Hugging Face.
Tak uzyskane wektory pozwalały na przeprowadzenie klastrowania. Do tego wykorzystano prosty i skuteczny model KMeans z biblioteki scikit-learn. Jako parametr przyjęto K = 2, ponieważ klastrowanie miało oddzielić oferty potencjalnie prawdziwe od potencjalnie fałszywych.
Po przeanalizowaniu klastrów pod kątem występowania ofert sklasyfikowanych jako prawdziwe i tych, które są nieprawdziwe, drużyna mogła z dokładnością (accuracy) ok. 67% i metryką F1 ≈ 69% stwierdzić który klaster reprezentuje oferty prawdziwe, a który nieprawdziwe. Tak opisane dane posłużyły do przeprowadzenia uczenia nadzorowanego kolejnego modelu, którym zajął się Staszek.
Tf-idf oraz klasyfikacja lasem losowym
Gdy koncepcja rozwiązania była już ustalona, Staszek przejął zadanie dotyczące klasyfikacji nadzorowanej. Swoją pracę rozpoczął przetwarzając treści ofert na dane liczbowe, tabelaryczne reprezentujące istotę każdego słowa w dokumencie w ramach zebranego korpusu. W tym celu posłużył się techniką znaną jako “tf-idf” (term frequency–inverse document frequency) zaimplementowaną w bibliotece scikit-learn. Tak otrzymane dane wykorzystane zostały w procesie trenowania modelu klasyfikacji nadzorowanej.
Finalnie zastosowanym modelem był model lasu losowego, który również posiadaliśmy w zasięgu dzięki bibliotece scikit-learn. Las losowy, przyjmując na wejściu liczby reprezentujące istotę każdego słowa z korpusu w dokumencie, utworzył esemble drzew decyzyjnych, których uśrednione wyniki dawały wynik lasu losowego reprezentujący, czy podana na wejściu oferta pracy jest wiarygodna, czy może być podejrzana jako próba wyłudzenia.
Uzyskany w ten sposób model dawał wyniki przewyższające oczekiwania zespołu DSC – metryka F1 na danych testowych wyniosła ok. 98%.
Ostatnie szlify i prezentacja
Całe rozwiązanie udało się przygotować w szesnaście godzin, co dało naszym bohaterom możliwość powrotu do domów, regenerację i powrót do The Tides na prezentację i ogłoszenie wyników. Końcową prezentację przygotował Piotrek, który jeszcze w pociągu powrotnym o godzinie 02:00 w nocy wykazał wielkie zaangażowanie w projekt.
Termin na oddanie prac upływał w niedzielę o godzinie 09:00 rano. Po niedługim czasie organizatorzy ogłosili finalistów, którzy mieli za zadanie przedstawić pięciominutowy pitch przed jury omawiający problem, propozycję rozwiązania oraz pomysły na dalszy rozwój projektu. Prezentację około południa wygłosił Piotr, który w opisie dalszych planów nadmienił, że nasze rozwiązanie świetnie sprawdziłoby się jako rozszerzenie do przeglądarki, które automatycznie wykrywałoby treść oferty pracy na odwiedzanej stronie i informowałoby o potencjalnym zagrożeniu oszustwa.
Ogłoszenie wyników
Po niedługim czasie od zakończenia prezentacji jury ogłosiło zwycięzców. Zespół reprezentujący Data Science Club PJATK, w składzie: Paweł Saniewski, Igor Winek, Stanisław Raczkiewicz, Piotr Kojałowicz i Jacek Jackowski, zostali wyróżnieni drugim miejscem na podium w wyzwaniu #FakeJobHunter i nagrodzeni nie tylko czekiem na 25 tysięcy złotych ale przede wszystkim satysfakcją z dobrze wykonanej i dającej świetne efekty pracy. Łączna pula nagród z obu wyzwań wyniosła 150 tysięcy złotych.
Po ogłoszeniu wyników nastąpił czas na wywiady, liczne sesje zdjęciowe, oraz dopełnienie formalności.
W imieniu redakcji Data Science Club PJATK serdecznie gratulujemy reprezentantom naszego koła naukowego oraz pozostałym drużynom nagrodzonym w #Supervision_Hack 2023!