Zagadkowe embeddingi
Ci, którzy wcześniej nie zetknęli się z technicznymi szczegółami dotyczącymi Modeli Językowych, szybko natrafią na pojęcie embeddingów. Jeden z pierwszych istotnych elementów składających się na maszynerię Modeli Językowych - Embedding to siłacz, który obok Mechanizmu Uwagi stoi za oszałamiającymi sukcesami AI!
Przyjrzyjmy się im od strony praktycznej. Czy można w domu, na małym laptopie z linuxem użyć tych embeddingów do czegokolwiek sensownego? Przynajmniej po to, żeby zobaczyć – jak działają?
Takie intencje przyświecały mi podczas pierwszych eksperymentów, które chcę tu opisać. Zobaczymy jak można użyć embeddingów z API genai lub z ollama do trenowania i inferencji za pomocą regresorów i klasyfikatorów ze scikit-learn. To pouczające i inspirujące doświadczenie, które prowadzi do stu kolejnych pomysłów, z moim wykluwającym się pomysłem na „Transformer Dla Ubogich” na czele (o którym napiszę w przyszłości).
Skąd brać embeddingi?
Na laptopie z linuksem mamy co najmniej dwie proste ścieżki otrzymania embeddingów, zarówno na poziomie wyrazów, jak i dla całych wypowiedzi:
- API Modeli Językowych - na przykład
genaiod Google posiada metody pobierania embeddingów, zarówno pojedynczo, jak w paczkach do 100 sztuk naraz. Nawet w trybie free tier modelembedding-001potrafi wykonać obliczenia szybko, czasem nawet dla setki tekstów w ciągu sekundy. Jest to podstawowy dostępny model, wyspecjalizowany do liczenia embeddingów - jest tak dzisiaj, gdy to piszę, czyli w lipcu 2025. - API
ollama. Gdy piszę te słowa,ollamajest całkiem funkcjonalnym systemem - łatwo się instaluje, a na małym laptopie z dowolnym GPU uruchamia małe modele dialogowe wielkości kilku miliardów parametrów. Tym bardziej dostępne są modele embeddingowe, takie jaknomic-embed-text,bg3-m3,paraphrase-multilingual.
Gdy eksperymentujemy, warto sprawdzać różne modele. Niektóre z nich są szybsze, z kolei inne „znają” język polski.
Stolice Państw – minimalne zadanie. Proof Of Concept
Co można z tym zrobić? Prostym pomysłem, który wpadł mi do głowy, było połączenie embeddingów z „Machine Learning” w lekkiej formie, czyli ze scikit-learn! Wymyśliłem, że sprawdzę wiedzę geograficzną, jaka jest wdrukowana w embeddingi.
Przygotowałem kilka przykładów zdań na temat stolic:
| Zdanie | Wartość |
|---|---|
| Praga jest stolicą Włoch. | 0 |
| Rzym jest stolicą Włoch. | 1 |
| Grecja jest stolicą Hagi. | 0 |
| Warszawa jest stolicą Polski. | 1 |
Był to mikro-korpus, który następnie przedstawiłem Modelowi Językowemu z prośbą o rozszerzenie do wielkości ok 100. Dostałem w ten sposób mini-korpus, który zamieniłem na embeddingi, a następnie, po podzieleniu na zbiór treningowy i testowy w stosunku 60:40, pokazałem „wyjętemu z pudełka” (czyli bez parametrów, bez tuningu) klasyfikatorowi ze scikit-learn. Próbowałem LogisticRegression, a potem SVC.
Najpierw wyniki były słabe: 60% trafności.
Przyjrzałem się jednak bliżej i zauważyłem, że pierwszy model embeddingowy, którego użyłem nie był polskojęzyczny! Wynikało to z dokumentacji.
Po przejściu na model bg3-m3 (wielojęzyczny) i skupieniu się na SVC dostałem 100% na zbiorze testowym.
Radość w obozie zwycięzców panowała do samego rana. – To działa! Jeszcze nawet zanim to „rano” nadeszło, pojawiły się nowe pomysły!
Jak trenować systemy dla większych zadań? KLEJ!
Zapytałem AI o dostępność benchmarków modeli językowych dla języka polskiego, dowiedziałem się o Kompleksowej Liście Ewaluacji Językowych stworzonej przez ludzi z Allegro i AGH (nazwa jest tak dobrana, żeby akronim mógł być odpowiednikiem GLUE, co z kolei oznacza General Language Understanding Evaluation).
Szybko zorientowałem się, że KLEJ składa się z dziewięciu dobrze określonych zadań, dane treningowe i – częściowo – testowe są dostępne do pobrania i – co dla mnie bardzo ważne – są małe! Kilka tysięcy przykładów na każde zadanie. W sumie - nieco ponad 65000 tekstów. Od razu zrozumiałem że to liczba całkowicie wygodna z punktu widzenia mojego laptopa.
Rzeczywiście - obliczenie embeddingów dla tych wszystkich tekstów zajęło kilkanaście minut za pomocą modeli embedding-001 z genai. Więcej mi zajęło napisanie kodu, który w wygodny sposób cache-uje te embeddingi!
Druga rzecz, również bardzo ważna - rodzaj tych zadań całkowicie odpowiada moim potrzebom. Są to zadania klasyfikacji (dwie lub kilka etykiet), niektóre tylko wymagają regresji, a większość w sensowny sposób może być do regresji sprowadzona, bo etykiety można uporządkować.
Last but not least, autorzy KLEJ precyzyjnie określili sposób obliczania metryk, jaki stosują przy budowaniu leaderboardu, a więc - moje wyniki mogę bezpośrednio porównywać z „wielkimi”, a z drugiej strony (może to ważniejsze) – z „baseline”.
Wyniki
Policzywszy to wszystko, porównałem swoje wyniki do dwóch wybranych modeli z leaderboardu KLEJ.:
| Zadanie | Polish RoBERTa-v2 | HerBERT - KLEJ | embedding-001/SVR | metrics |
|---|---|---|---|---|
| NKJP-NER | 95.8 | 92.7 | 68.53 | Accuracy |
| CDSC-E | 94.3 | 92.5 | 76.30 | Spearman corr. |
| CDSC-R | 95.1 | 91.9 | 44.44 | Accuracy |
| CBD | 74.3 | 50.3 | 48.97 | F1 |
| PolEmo2.0-IN | 93.1 | 89.2 | 79.25 | Accuracy |
| PolEmo2.0-OUT | 84.0 | 76.3 | 46.36 | Accuracy |
| DYK | 75.4 | 52.1 | 54.91 | F1 |
| PSC | 98.8 | 95.3 | 85.70 | F1 |
| AR | 89.2 | 84.5 | 79.76 | 1 - wMAE |
| Średnia | 88.89 | 80.53 | 64.91 |
Autorzy zaprojektowali metryki w ten sposób, że można wziąć z nich średnią, bo 100 oznacza “geniusza”, 0 oznacza “antygeniusza”, a 25 oznacza np. “losowy wybór 1 z 4”, czyli – wszystkie skale są podobne, co wynika z zaprojektowania metryk.
Moja średnia jest dużo niższa niż tamtych modeli, ale i tak jest niezła, jak na „składak” wykonany z publicznie dostępnych elementów, policzony na laptopie.
Wnioski
- Całkiem dużo da się zrobić w domu, istnieje wiele ciekawych ścieżek dalszych prób!
- KLEJ jest świetnym narzędziem mierzenia jakości własnych rozwiązań, jeśli dotyczą języka polskiego.
Eksplozja pomysłów. Co dalej…
W przyszłości myślę o tym, żeby czymś własnym zastąpić embeddingi. Mam kilka ścieżek pomysłów, generalnie polegają na tym, żeby embeddingi dla pojedynczych słów języka polskiego stabelaryzować, a potem jakoś je składać, korzystając ze spaCy, Morfeusz2 itp, szukać możliwości kodowania formy gramatycznej zamiast pozycji w zdaniu, co pozwoliłoby wykorzystać specyfikę języka polskiego. Albo - może - trenować podmodele, które za pomocą embeddingów słów będą jakoś konstruować embeddingi fraz.
Może cechy języka polskiego, które utrudniają nieco bezpośrednie stosowanie algorytmów powstających w głównym nurcie NLP – są szansą dla nas, żeby zbudować coś specyficznego, ciekawego, nowatorskiego?
W kolejnych odcinkach będę pisać – co udało się zrobić. Zachęcam wszystkich do samodzielnych eksperymentów – to niesamowicie satysfakcjonująca, nowa, obiecująca – i superciekawa dziedzina! A w domu można wiele uzyskać!.