XVI wiek (beta) API Github Twitter

Zapiski

Zapiski, notatki i ciekawostki dotyczące programowania związanego z historią, archeologią czy tzw. humanistyką cyfrową. Czyli o praktycznym wykorzystaniu różnych narzędzi i bibliotek.

Spis treści:

2022-09-25 OpenRefine - własny serwis rekoncyliacji/uspójniania
2022-10-01 spaCy, NER i półautomatyczne tworzenie indeksu postaci
2022-10-03 spaCy, POS i Matcher - czyli do czego przydają się rzeczowniki
2022-10-05 spaCy - jak poprawić wyniki NER czyli Barnim XI to też osoba...
2022-10-06 Artykuły, kursy, filmy - o NLP w badaniach historycznych
2022-10-07
Anotacja tekstów w Doccano i trenowanie własnego modelu
2022-10-10
Skrypty w poszukiwaniu wydarzeń
2022-10-17 spaCy, NEL - łączenie rozpoznanych encji z wikidata.org
2022-10-22 spaCy i automatyczne tagowanie encji w TEI Publisherze
2022-10-30 spaCy i koreferencje, czyli Jerzy bawił we Włoszech a jego włości popadały w ruinę
2023-01-?? Kraken, czyli HTR to jest to
2023-01-29 Dżin z czarodziejskiej lampy czyli GPT 3.5
2023-06-08 Podręczny OCR. Jak odczytywać fragmenty tekstu z obrazów
2023-07-02 Duże modele językowe a grafy wiedzy

Tłumaczenia i nowe wpisy pojawiają się też na platformie Medium, na przykład:
"Extracting information from historical studies. How to ask GPT?" link.


OpenRefine - własny serwis rekoncyliacji/uspójniania (25.09.2022)

OpenRefine jest popularnym narzędziem do oczyszczania i przekształcania danych. Polecam artykuły na temat OpenRefine: Oczyszczanie danych z użyciem OpenRefine oraz Cleaning Data with OpenRefine Jedną z jego ciekawszych funkcji jest możliwość rekoncyliacji danych przy wykorzystaniu zewnętrznych serwisów udostępniających dane do uspójniania. Często zdarzają  się w danych historycznych różnorakie sposoby zapisu imion i nazwisk postaci, lub nazw geograficznych. Nazwy miejscowości mogą występować w brzmieniu współczesnym, w formie używanej w XVI wieku, lub po prostu w formie błędnie zapisanej w źródle. Mechanizm uspójniania w OpenRefine pozwala uzgodnić nazwę występującą w naszych danych z nazwą pochodzącą z pewnego źródła. Np. powiązać "Zbigniewa Oleśnickiego" z identyfikatorem z bazy VIAF, lub powiązać miejscowość Brzozowa (występująca w źródłach także jako Brosoua) z identyfikatorem z Atlasu Historycznego Polski (Brzozowa_sdc_krk).

Problemem może być znalezienie odpowiedniego serwisu rekoncyliacji. O ile popularne źródła w rodzaju VIAF czy wikidata.org są dostępne Lista dostępnych serwerów rekoncyliacji. , o tyle uspójnianie z bazą miejscowości AHP lub naszą lokalną bazą osób może wymagać uruchomienia własnego serwisu. Nie jest to jednak takie trudne, istnieją bowiem gotowe narzędzia, które można wykorzystać do tego celu. Jednym z nich jest Reconcile-csv udostępniony (na otwartej licencji BSD-2) na stronie Open Knowledge Lab. Program ten pozwala na dopasowanie szukanej przez nas nazwy do nazw w swojej bazie poprzez mechanizm przybliżonego (rozmytego) porównywania (fuzzy matching), nazwy nie muszą być identyczne, mogą być podobne, program będzie wówczas proponował listę zbliżonych do podanej nazw wraz ze współczynnikiem podobieństwa. Bazą dla Reconcile-csv jest plik tekstowy w formacie CSV.  

Program jest plikiem *.jar, (warto pobrać z githuba też plik index.html.tpl, który jest szablonem wyświetlanym jako główna strona serwisu) do uruchomienia potrzebuje więc zainstalowanej Javy (JRE), potrzebny jest oczywiście plik CSV z danymi (plik w którym każdy wiersz jest rekordem danych, pola rozdzielone są przecinkami a pierwszy wiersz zawiera nazwy kolumn).

Polecenie uruchamiające serwer:
java -Xmx2g -jar reconcile-csv-0.1.2.jar plik.csv search_column id_column

gdzie plik.csv to nazwa naszego pliku z danymi, search_columm to nazwa pola w pliku z danymi, które będzie służyło do rekoncyliacji w OpenRefine, id_column to nazwa pola w pliku z danymi, które zawiera jednoznaczny identyfikator danych.

Po uruchomieniu serwis dostępny jest pod adresem http://localhost:8000/reconcile, i taki adres należy wprowadzić w OpenRefine (zwraca on zawartość w formacie json, czytelną dla programu - odbiorcy danych z serwisu). Adres główny serwisu (http://localhost:8000) wyświetli o nim podstawowe informacje w formie czytelnej dla człowieka.

serwis reconcile-csv

Lokalny serwis rekoncyliacji podłącza się do OpenRefine podobnie jak serwisy zewnętrzne, po uruchomieniu rekoncyliacji na wybranej kolumnie danych przycisk Add Standard Service wyświetli okienko w którym można podać adres serwisu, zaakceptowany serwis pojawi się na liście. Standardowa nazwa serwisu będzie różnić się od pokazanej na ilustracji i wygląda tak: 'CSV Reconciliation service'. Jest niestety zaszyta w kodzie źródłowym Reconcile-csv i jej zmiana wymaga rekompilacji programu (zob. dalszą część artykułu).

add standard service

Można wówczas rozpocząć proces uspójniania. Dane które według mechanizmu zostały pewnie dopasowane (współczynnik > 0.85) zostaną od razu przypisane do komórek kolumny dla której przeprowadzamy rekoncyliację, w innych przypadkach wyświetlona zostanie lista wraz z wartościami dopasowania. Dla każdej z pozycji można wyświetlić informacje z pliku csv będącego źródłem danych serwisu, na przykładzie poniżej są to dane miejscowości z Atlasu Historycznego Polski. Dostępne publicznie na licencji CC BY-ND 4.0: AHP 2.0 (IH PAN).

reconcile_view

Jak zmodyfikować program reconcile-csv: zarówno zmiana nazwy serwisu (nazwy wyświetlanej w OpenRefine), jak i dostosowanie programu Reconcile-csv do pracy na serwerze, wymaga zmian w jego kodzie źródłowym Repozytorium aplikacji w serwisie github. a w związku z tym pewnych umiejętności 'programistycznych'. Sama zmiana nazwy serwisu wymaga jednak tylko modyfikacji 50 wiersza pliku /src/reconcile_csv/core.clj: {:name "CSV Reconciliation service", zmiany tekstu "CSV Reconciliation service" na nowy i rekompilacji programu. Aplikacja została stworzona w języku clojure. Najłatwiejszym sposobem zarządzania i kompilacji projektu w języku clojure jest użycie systemu Leiningen, który w systemie Ubuntu można zainstalować poleceniem: sudo apt install leiningen. Rekompilacja projektu Reconcile-csv i budowa nowego pliku *.jar sprowadza się do uruchomienia polecenia: lein uberjar w katalogu z plikiem project.cli, skompilowany plik *.jar powinien znajdować się w podkatalogu /target.

Modyfikacja kodu i rekompilacja za każdym razem kiedy chcemy zmienić np. nazwę serwisu rekoncyliacji wyświetlaną w OpenRefine może być jednak dość niewygodna. Dlatego przygotowałem małą modyfikację programu reconcile-cvs która obsługuje cztery dodatkowe parametry uruchamiania z linii komend: adres_serwera, port, nazwa_serwisu_rekoncyliacji i nazwa_typu. W razie potrzeby wystawiania naszego serwisu na serwerze dostępnym w internecie można to zrobić za pośrednictwem serwera nginx, który będzie służył jako proxy dla wbudowanego w reconlice-csv jetty, wówczas reconcile-csv będzie pracował pod adresem np. localhost:8080, a o obsługę żądań zewnętrznych zadba nginx. Dodatkowo serwis wyświetla trochę bardziej czytelny podgląd danych z pliku csv, podczas uspójniania (widoczne ramki tabeli). reconcile_view

Przykładowe wywołanie:
java -Xmx2g -jar reconcile-csv-0.1.2.jar plik.csv search_column id_column "http://moj_serwer.org" "80" "Miasta-Osoby Serwis Rekoncyliacji" "miasta_osoby"

lub (obecnie port inny niż 80 trzeba podać także w adresie serwera):
java -Xmx2g -jar reconcile-csv-0.1.2.jar plik.csv search_column id_column "http://localhost:8000" "8000" "Miasta-Osoby Serwis Rekoncyliacji" "miasta_osoby"

Kod źródłowy modyfikacji można pobrać z github, skompilowany plik jar również: releases.


spaCy, NER i półautomatyczne tworzenie indeksu postaci (01.10.2022)

Postęp rozwoju metod przetwarzania języka naturalnego (NLP) w ciągu ostatnich kilku lat pozwala na coraz szersze ich użycie, także w odniesieniu do tekstów w języku polskim. Jedną z technik NLP jest rozpoznawanie jednostek nazwanych (NER - named entity recogition), w czystym, pozbawionym struktury tekście poddanym analizie NER można oznaczyć np. osoby, miejsca czy daty. Do czego może się to przydać w przypadku publikacji historycznych? Jednym z najprostszych przypadków użycia jaki przychodzi do głowy jest stworzenie indeksu osób dla publikacji gdzie takiego indeksu brakuje.

Do testu posłuży artykuł (właściwie książka, sądząc po objętości) Stanisława Bodniaka, "Polska a Bałtyk za ostatniego z Jagiellona" wydana w 1946 roku (Pamiętnik Biblioteki Kórnickiej 3, 42-276, 1939-46). Dzieło to ma zresztą ciekawą historię gdyż pierwszy druk i rękopis zostały utracone w wyniku działań wojennych, autor z zachowanych korekt i notatek odtworzył i wydał je po wojnie. Publikacja została zdigitalizowana przez Muzeum Historii Polski i udostępniona w bazie bazhum.muzhp.pl w formie pdf.

Sytuacja jednak nie jest idealna - pdf nie ma indeksu (nie wiem czy jest w papierowym wydaniu), ma warstwę OCR więc jest przeszukiwalny, jednak jakość OCR nie jest perfekcyjna, w tekście pojawiają się np. przypadkowe spacje wewnątrz słów. Aby to poprawić można proces ocr przeprowadzić powtórnie. Ponieważ na codzień pracuję w systemie Linux, narzędzia których używam związane są z tym systemem, jednak wiele z nich pracuje także pod Windows/Mac lub istnieją odpowiedniki dla tych środowisk.

reconcile_view

Ciekawym narzędziem do wprowadzania warstwy tekstowej ocr do plików pdf jest ocrmypdf, może on rówież nadpisać istniejącą warstwę tekstową czy zapisać rozpoznany przez ocr na nowo tekst w osobnym pliku tekstowym (warstwa tekstowa zapisana przez ten program w pdf również nie była rewelacyjna, ale sam plik z tekstem okazał się niezły i nadawał się do dalszej obróbki). Silnikiem OCR używanym przez omawianą aplikację jest Tesseract, uważany za najlepszy mechanizm OCR open source.

Polecenie uruchamiające przetwarzanie pdf-a wygląda tak:
ocrmypdf -l pol --force-ocr --sidecar output.txt Bodniak_input.pdf Bodniak_output.pdf

gdzie opcja: -l pol odpowiada za obsługę języka polskiego, --force-ocr wymusza nadpisanie istniejącej warstwy ocr w pdf, zaś opcja --sidecar output.txt powoduje zapisanie tekstu z pdf w pliku tekstowym. Nazwy plików pdf na końcu to odpowiednio oryginalny plik oraz wyjściowy zmodyfikowany plik pdf.

Oryginalny plik pdf pobrany z repozytorium bazhum.muzhp.pl może wymagać wstępnego przetworzenia (program ocrmypdf zgłasza błąd "EncryptedPdfError: Input PDF is encrypted. The encryption must be removed to perform OCR"), służy do tego program qpdf uruchamiany z linii komend: qpdf --decrypt plik_wejściowy.pdf plik wyjściowy.pdf.

Innym narzędziem, które może posłużyć do wydobycia tekstu z pliku pdf jest program gImageReader będący graficzną nakładką na silnik OCR Tesseract, oprócz samego procesu OCR ma on dodatkowe funkcje pozwalające usunąć znaki końca wiersza ze środka akapitów oraz połączyć wyrazy podzielone między wiersze (komercyjne programy OCR mają z pewnością dużo większe możliwości w zakresie oczyszczania i poprawiania tekstu po procesie OCR).

tekst_gimage_reader

Mając plik z tekstem (z zachowanymi numerami stron, które zamieniłem na tagi w postaci [PAGE: 45] na początku każdej strony) możemy poddać go próbnej analizie NER. Istnieje wiele narzędzi i modeli, które można wykorzystać do tego celu, dostępna jest np. kolekcja narzędzi projektu CLARIN-PL (analiza NER do przetestowania także: on-line z wykorzystaniem narzędzia Liner2). W tym teście skorzystam jednak z popularnej biblioteki NLP: spaCy i skryptów w języku Python.

Najwygodniejszym sposobem testowania różnych rozwiązań w Pythonie jest środowisko Jupyter Notebook Sama instalacja i konfiguracja Pythona, Jupytera i spaCy mogłaby być tematem osobnej zapiski, ale procudury ich instalacji są przystępnie opisane na podanych wyżej stronach.

Po uruchomieniu środowiska Jupyter i utworzeniu nowego notatnika należy zaimportować bibliotekę spaCy oraz dodatkowo mechanizm wizualizacji displacy. Kolejnym krokiem będzie załadowanie tekstu do analizy oraz modelu dla języka polskiego. Standardowo spaCy oferuje 3 modele (zob. https://spacy.io/models/pl), mały, średni i duży, różniące się wielkością (od 20 do 500 MB) i dokładnością. Do celów tego testu wystarczy model średni 'pl_core_news_md' (Polish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, lemmatizer (trainable_lemmatizer), tagger, senter, ner.).

import spacy
from spacy import displacy

nlp = spacy.load('pl_core_news_md')
with open('../data/bodniak_baltyk_small.txt', 'r', encoding='utf-8') as f:
text = f.read()

doc = nlp(text)
displacy.render(doc, style='ent')

Kod podany powyżej przeprowadza analizę NER wczytanego tekstu (jest to fragment artykułu S. Bodniaka, str. 43) oraz wyświetla wynik w bardzo przystępnej wizualnie formie, gdzie znalezione jednostki nazwane (osoby, daty i miejsca) oznaczone są kolorami i etykietą ('persName', 'date', 'placeName'). Jak widać mechanizm radzi sobie całkiem nieźle z typowymi przypadkami osób, znajduje określenia temporalne i miejscowości.

jupyter_spacy

Niektóre z postaci, np. Barnim XI (książę pomorski, w dolnej części tekstu na załączonym zrzucie ekranu) pozostają jednak nierozpoznane, jako osoby rozpoznawane są natomiast błędnie wyrażenia typu: 'Odstraszała' czy 'Podniosłyby', model użyty do testu był przygotowany na podstawie bardziej współczesnych tekstów stąd imion i innych określeń używanych historyczne po prostu może nie znać. Analizowany tekst dotyczy XVI wieku, ale gdyby występowały w nim postacie średniowieczne typu 'Jan z Goźlic' jako osoba zostałoby uznane prawdopodobnie tylko imię Jan a nie całe wyrażenie. Zdarzają się też błędne rozpoznania miejsc jako osób itp. Czy można model 'przekonać' do bardziej poprawnego rozpoznawania takich określeń? Oczywiście, istnieją także zapewne lepsze modele, ale jest to temat na inny wpis.

Mając tekst z informacjami o numerach stronach, możliwość rozpoznania postaci analizą NER, możemy przygotować ich indeks, posłuży do tego skrypt pythonowy create_index.py Do pobrania z serwisu github. w którym najpierw wczytywana jest treść każdej strony, wykonywana analiza NER, wyniki dopisywanie do słownika wyników, na koniec wyświetlana jest posortowana lista znalezionych postaci (266 osób, z tym że niektóre występują czasem podwójnie lub potrójnie z powodu np. literówek czy błędnie ustalonej formy podstawowej imienia i nazwiska) wraz z numerami stron. Lista nie jest z pewnością dokładna, wymaga oczyszczenia przez człowieka (występują wspomniane już wyżej błędne rozpoznania, problemy z odmianą imion i nazwisk, jakość ocr też wpływa na błędy wynikające z literówek) jednak z pewnością jest dużym ułatwieniem przy tworzeniu indeksu, no i jej przygotowaniem zajął się komputer, dając człowiekowi czas na zadania, których komputer na dziś nie jest w stanie się podjąć. Poniżej fragment przygotowanego indeksu po wstępnym oczyszczeniu.

Achacy Czema [262]
Adam Konarski [190, 273]
Adolf (holsztyński) [157]
Albrecht Giese [88, 120, 171]
Albrecht Wilkowski [116]
Albrecht (Hohenzollern) [43, 44, 51, 52, 56, 57, 58, 70, 134]
Aleksander Połubieński [216]
Andrzej Swarożyński [74, 81, 84, 104, 274]
Antoni Angela [44]
Bajerski [93, 94]
Barnim XI [126, 187]
Bąkowski [138]
Birsen [46]
Bogusław XIII [187]
Boleman [177, 178]
Chodkiewicz [101, 191, 207, 228, 263, 270, 271]
[...]
Łukasz Górnicki [43]
Łukasz Podoski [190, 222, 273]
Maciej Scharping [58, 60, 67, 74, 83]
Maciej Strubicz [77, 271]


spaCy, POS i Matcher - czyli do czego przydają się rzeczowniki (03.10.2022)

Mając indeks postaci występujących w publikacji Zob. poprzednią zapiskę. wiemy kto występuje w tekście, ale czy wiemy kim był? W przypadku osób powszechnie znanych kojarzymy, że Zygmunt August był królem, Albrecht Hohenzollern władcą Prus, ale jakie funkcje pełnili, jakich zawodów byli przedstawicielami ci pozostali, mniej znani? Czy analizy NLP mogą nam pomóc w odpowiedzi na te pytania? Tak i to nawet najbardziej podstawowe metody, jak określenia części mowy (POS - part of speech) oraz Matcher - silnik dopasowywania wzorców.

Podczas przetwarzania tekstu spaCy dzieli go na zdania oraz tokeny, każdy token jest zwykle słowem lub znakiem interpunkcyjnym. Dla każdego z tokenów spacy określa jaką jest częścią mowy, można więc dzięki temu odseparować same rzeczowniki występujące w tekście i posortować je w kolejności występowania. Taką pracę wykonuje skrypt popular_noun.py Do pobrania z serwisu github. .

Najpopularniejszy rzeczownik w publikacji Stanisława Bodniaka (Polska a Bałtyk za ostatniego Jagiellona) to słowo 'król' występujące w różnych formach ('królów, królach, króla, królu, królowi, królem, Króla, Król, król') 435 razy, kolejne zaś to 'rok', 'statek', 'straż', 'kapitan', 'komisja', 'okręt', 'żegluga', 'miasto', 'morze' - co nie jest zaskakujące biorąc pod uwagę tematykę artykułu. Wśród nich mamy dwa reprezentujące funkcję: król i kapitan. Przykład fragmentu wyników działania skryptu w tabelce poniżej:

FunkcjaLiczba wystąpieńTypowe formy
król 435 królów, królach, króla, królu, królowi, królem, Króla, Król, król
kapitan 192 kapitanowie, kapitan, kapitanów, kapitanach, Kapitan, kapitanami, kapitana, kapitanowi, kapitanem, kapitanom
komisarz 130 komisarzom, komisarze, komisarzem, Komisarze, komisarza, komisarzy, komisarz

Kolejna część pracy należy do człowieka, z otrzymanej listy należy wybrać inne funkcje i zawody, znajdziemy tam między innymi funkcje: komisarz, strażnik, kapr, poseł, car, kupiec, żołnierz, cesarz, senator, członek, kasztelan, urzędnik, admirał, delegat, mistrz, żeglarz, prezes, sekretarz, armator, władca, kanclerz, marynarz, właściciel, dowódca, podkanclerzy, namiestnik, książę, ks., starosta, sługa, wojownik, mocodawca, burmistrz. Mając listę funkcji można wykorzystując mechanizm Matcher - silnik dopasowywania wzorców biblioteki spaCy - wyszukać powiązania funkcji i osób Rule-based matching. .

Wzorzec według którego spaCy dopasowywuje tekst może wyglądać na przykład tak:
[{"LEMMA": {"IN": lista}}, {"POS":"ADJ", "OP":"?"},{"POS":"PROPN", "OP":"+"}],
gdzie lista jest wyżej wypisaną listą funkcji, LEMMA - oznacza formę podstawową wyrazu, "POS":"ADJ" oznacza wyraz będący przymiotnikiem, "POS":"PROPN" - oznacza wyraz będący jednostką nazwaną (np. osobą wymienioną z imienia i nazwiska), "OP":"?" to operator wskazujący, że poprzedni wzorzec może wystąpić 0 lub 1 raz, "OP":"+" zaś jest operatorem oczekującym wystąpienia wzorca co najmniej raz (lub więcej razy).

Efektem przetworzenia tekstu badanej publikacji S. Bodniaka przez zestaw podobnych reguł (skrypt funkcje_zawody.py - pod tym samym adresem co poprzedni skrypt) jest lista wyrażeń zawierających osoby i ich funkcje/zawody np.

  • "kasztelana chełmińskiego Jerzego Oleskiego"
  • "kanclerz Nils Gyllenstierna"
  • "admirałem szwedzkim Klausem Flemmingiem"
  • "namiestnik Inflant Jan Chodkiewicz"
  • "sekretarz królewski Kasper Geschkau"
  • "Michała Brunowa kanclerza Gotarda Kettlera"

Możemy stąd uzyskać np. listę występujących w tekście kapitanów i kaprów: Figenow, Gendtrichsen, Michał Starosta, Paweł Glasow, Jan Munckenbeck, Kersten Rode, Marcin Śchele, Mateusz Scharping, Marek Wilde.

Unikalnych znalezisk jest niespełna 90 czyli tylko dla 1/3 osób z indeksu postaci stworzonego w poprzedniej zapisce znaleziono ich funkcje lub zawód, ale jest to bardzo prosta metoda (pominąłem np. zawody/funkcje występujące mniej niż 10 razy), algortym można zapewne udoskonalić, poza tym te informacje dostajemy bez potrzeby ręcznego przeglądania 230 stron publikacji...


spaCy - jak poprawić wyniki NER czyli Barnim XI to
też osoba... (05.10.2022)

Rozpoznawanie jednostek nazwanych przeprowadzone na fragmencie publikacji S. Bodniaka zob. zapiskę z 1.10.2022. dało całkiem niezłe rezultaty w zakresie rozpoznawania osób, zdarzały się jednak takie nazwy, które mechanizm pominął. Na przykład 'Barnim XI' - książę pomorski. Czy można nauczyć spaCy rozpoznawania takich nietypowych imion? Tak, i nie musi się to wiązać z trenowaniem własnego modelu. EntityRuler jest komponentem potoku przetwarzania spaCy służącym do rozpoznawania jednostek nazwanych poprzez reguły Dokumentacja komponentu EntityRuler. i może zostać użyty do polepszenia wyników modelu statystycznego NER.

tekst bez rozpoznania imienia Barnim

Aby użyć komponentu należy dodać go metodą:
nlp.add_pipe("entity_ruler") oraz zdefiniować wzorce dla encji, które chcemy rozpoznawać w badanym tekście, mogą to być proste wzorce, np. pasujący do naszego przypadku:

pattern = [{"label":"persName", "pattern": "Barnim XI"}]

Mogą to także być bardziej zaawansowane wzorce oparte na tokenach:

[{"label": "persName", "pattern": [{"LOWER": "barnim"}, {"LOWER": "wielki"}]}]

Korzystamy w tym przypadku z istniejącej w modelu pl_core_news_md etykiety persName oznaczającej imiona i nazwiska osób.

Powtórne przetworzenie analizowanego fragmentu tekstu powoduje już poprawne rozpoznanie wyrażenia 'Barnim XI' jako osoby (label = persName)

tekst z rozpoznanym imieniem Barnim

Komponent EntityRuler potrafi jednak znacznie więcej, możemy z jego pomocą poprosić spaCy o rozpoznawanie nowej kategorii obiektów np. funkcji pełnionych przez osoby występujące w tekście. Zakładając, że interesują nas funkcje: król, hetman, senator oraz chcemy odnaleźć nie tylko dokładnie takie wystąpienia słów (np. 'senator') ale i wersję w liczbie mnogiej ('senatorowie') lub w formie odmienionej ('senatorowi') należy użyć bardziej zaawansowanego sposobu definiowana wzorca:
[{"label":"OCCUPATION", "pattern": [{"LEMMA": {"IN":["hetman","senator","marszałek", "król"]}}]}]

Nowa etykieta to 'OCCUPATION', 'LEMMA' oznacza formę podstawową słowa, np. dla wyrazów 'senator' i 'senatorowie' forma podstawowa będzie równa 'senator', zamiast jednej funkcji np. "LEMMA":"hetman" można we wzorcu wskazać od razu całą listę funkcji korzystając z zapisu: {"LEMMA": {"IN":["hetman","senator","marszałek", "król"]}. Efekt działania tak zdefiowanego wzorca wraz z całym fragmentem kodu widoczny jest dla zrzucie ekranu poniżej, a wszystko to bez trenowania własnego modelu. Notatnik jupytera z kodem ze zrzutu ekranu jest na githubie. Należy oczywiście zdawać sobie sprawę z ograniczeń, dla języka polskiego będą występować problemy z lematyzacją, lemma od słowa podkanclerzy to wg spacy 'podkancler', ale już lemma od słowa podkanclerzego to 'podkanclerzy'.

EntityRuler - funkcje i zawody

Artykuły, kursy, filmy - o NLP w badaniach historycznych (06.10.2022)

Internet jest pełen świetnych materiałów na temat NLP, uczenia maszynowego, programowania w pythonie czy konkretnych narzędzi i bibliotek, w tym miejscu chciałbym gromadzić linki przede wszystkim do tych z nich, które dotyczą humanistyki cyfrowej, wykorzystania NLP w badaniach historycznych lub były przygotowane z myślą o początkujących humanistach cyfrowych.

Kurs Natural Language Processing with spaCy & Python - Course for Beginners by Dr. William Mattingly na kanale freeCodeCamp.org: LINK oraz kurs Introduction to spaCy 3 w formie podręcznika online: LINK

Więcej świetnych filmów i kusrów tego samego autora dostępnych jest na jego własnym kanale YT: "Python Tutorials for Digital Humanities" LINK oraz na jego stronie np.: "Introduction To Named Entity Recognition With a Case Study of Holocaust NER" LINK

Yvonne Gwerder Named Entity Recognition in Digitized Historical Texts (praca magisterska, Universitat Zurich) PDF

Felipe Álvarez de Toledo López-Herrera Automated Tagging of Historical, Non-English Sources with Named Entity Recognition (NER): A Resource LINK

Vatsala Nundloll, Robert Smail, Carly Stevens, Gordon Blair Automating the extraction of information from a historical text and building a linked data model for the domain of ecology and conservation science LINK

Claire Grover, Sharon Givon, Richard Tobin, Julian Ball Named Entity Recognition for Digitised Historical Texts PDF

Helena Hubková, Named-entity recognition in Czech historical texts PDF

Blog NLP for Historical Texts https://nlphist.hypotheses.org/ prowadzony przez Michaela Piotrowskiego, autora książki Natural Language Processing for Historical Texts (2012) LINK

Asarsa Kunal Analysis of named entity recognition & entity linking in historical text (Masters theses, Northeastern University) PDF

Kimmo Kettunen, Eetu Mäkelä, Teemu Ruokolainen, Juha Kuokkala, Laura Löfberg Old Content and Modern Tools – Searching Named Entities in a Finnish OCRed Historical Newspaper Collection 1771–1910 LINK

Christian Henriot Rethinking historical research in the age of NLP (blog) LINK

Magdalena Turska: Informatyk wśród humanistów czyli krótka historia zderzenia światów i co z tego wynikło (video, nie dotyczy bezpośrednio NLP, ale wielu ciekawych aspektów styku informatyki i humanistyki) LINK

E. Oliveira, G. Dias, J. Lima, J.P.C. Pirovani: Using Named Entities for Recognizing Family Relationships LINK

Sam Fields, Camille Lyans Cole, Catherine Oei, Annie T Chen: Using named entity recognition and network analysis to distinguish personal networks from the social milieu in nineteenth-century Ottoman–Iraqi personal diaries LINK

Audrey Holmes: Named Entity Resolution for Historical Texts (praca magisterska, University of Washington, 2019) LINK

Nicolas Eymael Da Silva: Extraction of entities and relations in Portuguese from the Second HAREM Golden Collection (praca licencjacka, Universidade Federal Do Rio Grande Do Sul) PDF

N. Abadie, E. Carlinet, J. Chazalon, and B. Dumenieu: A Benchmark of Named Entity Recognition Approaches in Historical Documents Application to 19th Century French Directories PDF

Marcella Tambuscio, Tara Lee Andrews: Geolocation and Named Entity Recognition in Ancient Texts: A Case Study about Ghewond’s Armenian History PDF

Leonardo Zilio, Maria Jos´e Bocorny Finatto, and Renata Vieira: Named Entity Recognition Applied to Portuguese Texts from the XVIII Century PDF

Alistair Plum, Tharindu Ranasinghe, Spencer Jones, Constantin Orasan, Ruslan Mitkov: Biographical: A Semi-Supervised Relation Extraction Dataset PDF

Nitisha Jain, Alejandro Sierra-Múnera, Julius Streit, Simon Thormeyer, Philipp Schmidt, Maria Lomaeva and Ralf Krestel: Generating Domain-Specific Knowledge Graphs: Challenges with Open Information Extraction PDF

Fabio Chiusano: Building a Knowledge Base from Texts: a Full Practical Example (blog) LINK

Tomaz Bratanic: Extract knowledge from text: End-to-end information extraction pipeline with spaCy and Neo4j (blog) LINK


Anotacja tekstów w Doccano i trenowanie własnego
modelu (07.10.2022)

Wykorzystanie reguł do wyszukiwania encji nazwanych poprzez komponent EntityRuler biblioteki spaCy jest całkiem skutecznym sposobem poprawienia wyników NER. Możemy zastosować ten mechanizm jeżeli w używanym modelu brakuje np. jednej etykiety i łatwo jest uzupełnić ten brak za pomocą zestawu słów kluczowych, tworząc odpowiednie reguły. W trakcie prac nad tekstami spotkamy się jednak na pewno z bardziej skomplikowanymi przypadkami, a wówczas niezbędne stanie się wytrenowanie własnego modelu, dopasowanego do specyfiki naszych problemów. Przed procesem trenowania niezbędne jest jednak przejście przez trzy wstępne etapy: 1) należy zgromadzić zestaw danych (tekstów) do uczenia, 2) przygotować anotacje tych tekstów, 3) zdecydować, czy będziemy trenować własny model od zera, czy też dotrenowywać już istniejący. Krok drugi wiąże się też z wyborem oprogramowania do anotacji oraz przygotowaniem jej wyników do formy akceptowalnej przez spaCy.

Celem testu będzie przygotowanie danych, a następnie wytrenowanie modelu rozpoznającego zawody/funkcje (dla uproszczenia będzie to mały model trenowany 'od zera'). Próbką tekstów do anotacji w naszym teście będzie zbiór fragmentów artykułu S. Bodniaka Zob. zapiskę z 1.10.2022. , pochodzących z różnych części tej publikacji, lecz zawsze zawierających określenia nazw zawodów lub funkcji. Zbiór liczy w sumie 105 zdań, czyli parę procent całego tekstu, zapewne dla osiągnięcia naprawdę dobrych wyników powinien być wyraźnie większy (wspomina się o minimum 100 przykładach dla każdej uczonej encji). Najlepszą aplikacją do anotacji współpracującą z spaCy jest z pewnoścą Prodigy Strona aplikacji prodigy. , narzędzie przygotowane przez autorów spaCy - firmę Explosion. Jest to jednak oprogramowanie komercyjne i, choć w realnej sytuacji z pewnością warto w nie zainwestować (ceny zaczynają się od 390 USD za licencję), to w naszym teście użyjemy narzędzia dostępnego bezpłatnie. Istnieje ich co najmniej kilka, np. ner-annotator, TagEditor (aplikacja desktopowa dla systemu Windows), brat, INCEpTION czy doccano. Każde z nich na pewno dobrze się sprawdzi przy wprowadzaniu etykiet, jednak najlepsze wrażenie zrobiło na mnie doccano, aplikacja webowa, którą można w prosty sposób zainstalować lokalnie korzystając z dockera. Opis instalacji znajduje się na stronie projektu, polecam ścieżkę z wykorzystaniem docker-compose. doccano - instalacja poprzez docker-compose.

Praca w aplikacji doccano zaczyna się od zalogowania na nasze konto (podczas instalacji zakładane jest konto użytkownika będącego administratorem, wraz z hasłem, później można utworzyć dodatkowe konta nadając im role np. anotatora, czy osoby akceptującej anotacje) i utworzenia projektu. Zakładając nowy projekt należy wskazać typ projektu (rodzaj zadania), w naszym przypadku chcemy  rozpoznawać jednostki nazwane (NER), należy więc wybrać sequence labeling.

doccano lista projektów

Do utworzonego projektu można zaimportować dane do anotacji (menu Dataset), doccano akceptuje różne pliki tekstowe (lub zestawy plików), zaimportowane dane będą widoczne w formie tabeli.

doccano lista dokumentów

Przed rozpoczęciem anotowania niezbędne jest jeszcze utworzenie etykiet, którymi będzie oznaczany tekst. Biorąc pod uwagę cel testu jedyną używaną etykietą będzie occupation na oznaczenie zawodu lub funkcji pełnionej przez postaci występujące w tekście.

doccano tworzenie etykiet

Sam proces anotacji w doccano jest bardzo zbliżony do pracy w innych aplikacjach tego typu. Zaznaczamy słowo lub wyrażenie, program wyświetla wówczas podręczne menu, z którego można wybrać właściwą etykietę. Każda z etykiet ma swój kolor (definiowany przez użytkownika na etapie tworzenia etykiet) i takim kolorem doccano podkreśla oznaczony fragment tekstu (wyświetla również nazwę etykiety).

doccano w trakcie anotacji

Po zakończonym procesie anotacji można otagowany zbiór danych wyeksportować do formatu JSONL, w którym znajduje się anotowany tekst oraz etykiety i ich pozycje w tekście. Niestety, nie jest to gotowy plik, który możemy użyć do trenowania modelu z użyciem spaCy. W obecnej wersji (3.4 w momencie pisania zapiski) spaCy oczekuje pliku binarnego z przyjętym zwyczajowo rozszerzeniem *.spacy (format DocBin). Na szczęście konwersja pliku *.jsonl na *.spacy nie jest skomplikowana, można do tego celu użyć przykładowego skryptu doccano2spacy.py, który wywoływany jest z nazwą pliku jsonl jako jedynym parametrem. Skrypt można pobrać z repozytorium github.

doccano fragment pliku jsonl

Mając zbiór uczący, można przystąpić do trenowania nowego modelu. Proces trenowania wywoływany jest z linii komend poleceniem spacy train, należy również  podać nazwę pliku konfiguracyjnego (np. config.cfg) z parametrami uczenia, spaCy ułatwi jego utworzenie z domyślnymi parametrami. Procedura opisana jest na stronie spacy.io (tak, opis jest długi - to jest skomplikowane!). Należy też podać ścieżkę do zbioru uczącego i walidacyjnego (aby zachować reguły gry należałoby także przygotować zbiór walidujący, tu dla uproszczenia skorzystam z kopii zbioru uczącego). Parametr --output polecenia wskazuje, gdzie będą zapisane wytrenowane modele (spacy zapisuje ostatni i najlepszy z modeli).
python -m spacy train config.cfg --output ./output --paths.train ./bodniak.spacy --paths.dev ./bodniak.spacy
Podczas działania (dla większych zbiorów czas wykonywania obliczeń może być spory, w tym przypadku będzie to kilkadziesiąt sekund) wyświetlany jest stan kolejnych iteracji uczenia (zob. zrzut ekranu poniżej).

proces trenowania modelu

Po zakończeniu trenowania można przystąpić do weryfikacji działania modelu. Wykorzystamy do tego środowisko jupyter i mechanizm wizualizacji displacy. Wczytanie nowego modelu w spaCy odbywa się podobnie jak w przypadku modelu standardowego z tym, że zamiast nazwy należy, podać ścieżkę do katalogu z zapisanym modelem: nlp = spacy.load('../output/model-best/').
Wynik działania na spreparowanym zdaniu, w którym występują nazwy funkcji/zawodów widać na załączonym niżej zrzucie ekranu z fragmentem notebooka aplikacji jupyter. Notebook test_ner_model.ipynb do pobrania z repozytorium. Można zauważyć poprawne rozpoznanie słów 'król', 'kapitan', 'kanclerzem', jednak wyrażenie 'podstarościm' pozostało niezauważone, najwyraźniej model nie zdołał się go nauczyć, w materiale uczącym występowało ono faktycznie niezbyt często.

test modelu ner

I jeszcze dwa przydatne linki: do dokumentacji aplikacji doccano LINK, oraz do artykułu, który dużo obszerniej opisuje tę aplikację LINK.


Skrypty w poszukiwaniu wydarzeń (10.10.2022)

Strona xvi-wiek.pl to przede wszystkim kalendarium ciekawych wydarzeń z XVI wieku, niektórych bardziej znanych, innych zaś zupełnie egzotycznych. Skąd jednak te informacje pochodzą? Spora część (także) z wikipedii, ale większość z drukowanych książek i artykułów a sposób ich wyszukiwania nie polegał najczęściej na spędzaniu wieczorów z herbatą i książką (choć to przyjemne zajęcie), lecz miał coś wspólnego z cyfrową humanistyką. Wiele współcześnie wydawanych publikacji jest już dostępnych od razu w formie elektronicznej, coraz więcej starszych jest digitalizowanych i udostępnianych w formie plików pdf (już rzadziej jako DjVu). Jeżeli zaś publikacja ma postać cyfrowego pliku (z tekstem), to pozwala na przetwarzanie jej przez narzędzia informatyczne.

Wpisy w kalendarium są faktami i wydarzeniami związanymi z konkretną datą dzienną. W przypadku xvi-wieku.pl przyjęte też zostały określone ramy czasowe: od 1490 do 1586 roku włącznie. Daty dzienne mogą być zapisane w różnej formie, bardziej nowoczesnej np. 12.08.1560, trochę bardziej tradycyjnej np. 12 VIII 1560, lub z wprost podaną nazwą miesiąca: 12 sierpnia 1560 r. Mogą to też być fragmenty dat typu "12 stycznia" gdyż z kontekstu wynika o jaki rok chodzi.

Posiadając zgromadzoną kolekcję plików pdf (pochodzących główne z repozytoriów cyfrowych RCIN, bazhum.muzhp.pl i innych źródeł o otwartym dostępie) można wyszukać w nich daty dzienne z wymaganego okresu, nie chodzi oczywiście o ręczne przeszukiwanie w przegladarce PDF-ów każdego oczekiwanego wariantu daty, można skorzystać z tzw. wyrażeń regularnych Definicja wyrażeń regularnych w Wikipedii oraz ładne wprowadzenie do tematu. i jednego z narzędzi, które na przeszukiwanie plików pdf w taki sposób pozwalają. Dla osób  pracujących w środowisku linuksowym pierwszym wyborem będzie zwykle narzędzie konsolowe np. pdfgrep (w systemie Windows na pewno istnieją równie dobre i wygodniejsze odpowiedniki np. dnGrep). Program pozwala na przetworzenie bieżącego katalogu, lub całego drzewa katalogów zawierającego pliki pdf i przeszukanie tekstowej zawartości pdf-ów wg zadanego wzorca.

Zakładając, że wzorzec powinien uwzględniać dzień - 1 lub 2 cyfry, miesiąc w formie liczby rzymskiej lub nazwy oraz rok czerocyfrowy, parametry wywołania programu pdfgrep mogłyby wygladać np. tak:

pdfgrep -rnPH "\s+\d{1,2}\s+([a-z]{3,}|[XVI]+)\s+(15|149)" *.pdf

gdzie -rnPH to parametry programu decydujące o wyszukiwaniu rekurencyjnym plików (czyli program będzie szukał w podkatalogach i podkatalogach katalogów), o wypisywnaiu w wynikach numerów stron, o użyciu wyrażeń regularnych i podawaniu w wyniku nazw plików pdf, pozostała część polecenia to wyrażenie zwracające daty oraz ścieżka do plików (z maską). Wyrażenie regularne ma trzy części \d{1,2} poszukuje liczby o długości od jednej do 2 cyfr, fragment ([a-z]{3,}|[XVI]+) szuka rzymskiego numeru miesiąca lub nazwy miesiąca, ostatnia część (15|149) odpowiada za rok, poszukiwana jest liczba 15 lub 149 będąca początkiem roku (co jest drobnym problemem bowiem oznacza, że wpadną w wynikach także lata 1587-99).

Uruchomienie powyższego polecenia w katalogu z publikacją S. Bodniaka zwraca 24 wyniki (zob. zrzut ekranu poniżej). Program wypisuje nazwę pliku pdf w którym znaleziono wzorzec, numer strony (zielona liczba), oraz krótki fragment tekstu ze znalezionym wzorcem, gdzie wzorzec jest wyróżniony czerwonym kolorem. Pozostaje zweryfikować datę na podanej stronie w pliku pdf, być może jest to data wydarzenia, które może trafić do kalendarium.

pdfgrep wyniki przeszukiwania.png

Co jednak, gdyby wyszukiwanie miało bardziej ambitny cel, na przykład znalezienie dat dziennych, ale występujących w tym samym zdaniu co postać historyczna i może jednocześnie z jakąś nazwą geograficzną? Takie zadanie może być trudne do wykonania za pomocą samych wyrażeń regularnych, ale będzie świetnym ćwiczeniem z wykorzystaniem biblioteki spaCy. Dla uproszczenia testowi poddany zostanie fragment tekstu, w którym tylko jedno ze zdań pasuje do określonych założeń.

przykładowy fragment tekstu

Przetworzenie tekstu przy pomocy biblioteki pozwoli rozpoznać nazwy własne i wyrażenia temporalne.

daty analiza ner

spaCy zadba także o podział tekstu na zdania. Aby wyszukać te z nich, które spełniają określone wyżej kryteria wystarczy zbadać dla każdego zdania, czy występuje w nim osoba, nazwa geograficzna i data. Każda rozpoznana encja posiada przypisaną etykietę, te mogą się różnić zależnie od użytego modelu (w tym przykładzie wczytany został największy standardowy model dostępny dla języka polskiego - pl_core_news_lg). Encje osób oznaczane są etykietą 'persName', encje miejsc jako 'placeName', a wyrażenia temporalne jako 'date'. Prosty kod filtrujący wraz z wynikiem widoczny jest na zrzucie ekranu poniżej. Program dodatkowo sprawdza czy znaleziona data jest datą dzienna z lat 1490-1599, oraz czy encja 'placeName' jest nazwą zaczynającą się z dużej litery (aby pominąć znaleziska typu 'król szwedzki').

kod filtrujący i wynik działania

Wydrukowane zdanie jest jedynym z przetwarzanego fragmentu tekstu zawierającym osobę (lub osoby), miejscowość lub inną nazwę geograficzną oraz datę - z dokładnością  do konkretnego dnia. Można teraz tę samą metodę zastosować do całej treści publikacji Stansława Bodniaka, przy czym ponieważ spaCy pracuje raczej na tekstach (a nie plikach binarnych) użyty zostanie nie plik pdf, ale plik tekstowy z zawartością pdf-a, przygotowany w jednej z poprzednich zapisek. zob. zapiskę z 1.10.2022. Kod przygotowany w notebooku można zapisać w formie funkcji, która będzie wywoływana dla każdej strony przetwarzanego tekstu, wynik w postaci numeru strony i znalezionego zdania spełniającego przyjęte warunki będzie wypisywany na ekran konsoli. Notebook wyszukiwanie_dat.ipynb i skrypt events_finder.py do pobrania z repozytorium. Efekt działania skryptu to około 20 znalezisk, które mogą być potencjalnymi wydarzeniami, wartymi opisania w kalendarium (fragment wyniku na zrzucie ekranu zamieszczonym poniżej).

wynik działania skryptu event_finder.py

spaCy, NEL - łączenie rozpoznanych encji z wikidata.org (17.10.2022)

Rozpoznanie w tekście nazw własnych może być wstępem do następnego kroku - połączenia znalezionych encji np. osób z bazą wiedzy, uzyskujemy wówczas identyfikację danej osoby, pojawiający się w analizowanej publikacji Fryderyk II staje się tożsamy z duńskim królem żyjącym w XVI wieku, który w bazie wiedzy np. wikidata.org posiada jednoznaczny identyfikator Q154041. Proces łączenia encji z identyfikatorami z baz wiedzy określany jest często jako named-entity linking (czyli NEL) Entity linking. lub named-entity disambiguation i nie jest tak prostym zadaniem jak się pozornie wydaje. Fryderyków II czy miejscowości o nazwie 'Warszawa' może w bazie wiedzy istnieć wiele, nazwa miejscowości w publikacji może być  zniekształcona (może być jednym z używanych wariantów nazwy), może być nazwą używaną w XVI wieku, lub nazwą polską używaną przed 1939 rokiem dla miejscowości dziś leżącej poza Polską. Zygmunt II August może w analizowanym tekście występować także jako Zygmunt August, lub po prostu jako król Zygmunt.Trudność polega właśnie na automatycznym dopasowaniu właściwego elementu z bazy wiedzy do encji z publikacji, z uwzględnieniem drobnych różnic w pisowni oraz kontekstu.

Jednym z możliwych rozwiązań problemu łączenia encji z tekstu z bazami wiedzy jest obecny w bibliotece spaCy komponent EntityLinker Dokumentacja na stronie spaCy. . Pozwala on na wytrenowanie własnego modelu, który na podstawie przygotowanej bazy wiedzy, rozpoznanej encji nazwanej i kontekstu w której wystąpiła będzie potrafił wskazywać właściwy dla niej identyfikator.

W ramach testu Test przygotowany na bazie tutorialu z repozytorium przykładów spaCy opartego jak zwykle na tekście publikacji S. Bodniaka rozpoznawane i łączone z bazą  wiedzy będą dwie postacie: króla Zygmunta II Augusta i cara Ivana IV Groźnego, źródłem bazy wiedzy będzie zaś wikidata.org. Identyfikatory z Wikidata (QID) dla obu postaci to odpowiednio Q54058 i Q7996. W przypadku analizowanej publikacji nie ma właściwie jakiejś wieloznaczności w encjach osób, Zygmunt August będzie zawsze tym Zygmuntem, królem Polski, Iwan będzie carem Rosji. Większym wyzwaniem byłoby gdyby w tekście występował np. Mateusz Scharping jako kaper i inna postać np. Ernest Scharping będącą np. niemieckim dyplomatą, wówczas dla encji będących samym nazwiskiem łączenie z identyfikatorami z wikidata.org musiałoby następować na podstawie kontekstu. Tu jednak nie ma takiej sytuacji, do bazy można natomiast dodać dodatkowe aliasy naszych postaci, również pewnie identyfikowalne z elementami wikidata np. 'Zygmunt August', 'Iwan IV', 'Iwan Groźny'.

tworzenie bazy wiedzy

Oprócz obiektu KnowledgeBase (naszej bazy wiedzy) potrzebne są również próbki tekstów do trenowania modelu - przygotowane dane treningowe na podstawie zdań z artykułu Stanisława Bodniaka zawierających wzmianki na temat analizowanych postaci. Dane treningowe zawierają w przypadku tego testu około 30 zdań (zapewne powinno być trochę więcej). Tak jak w przypadku anotacji dla trenowania modelu NER tu również anotacja została przeprowadzona w programie doccano, a dane wyjściowe z doccano wymagały przetworzenia na format oczekiwany przez spaCy (tu z pliku *.jsonl dane importowane są bezpośrednio do skryptu w pythonie). Ponieważ jednak doccano nie wspiera bezpośrednio anotacji pod kątem NEL, a przynajmniej nie widzę takiej opcji, zastosowane zostało małe obejście problemu - ze względu na małą liczbę anotowanych postaci w roli etykiet użyto identyfiktorów QID z wikidata.

anotacja doccano nel

Mając przygotowany do trenowania dataset należy go podzielić na cześć treningową i część walidującą, zwykle 20% zbioru wystarcza do walidacji. Proces trenowania dla tak małego zestawu danych nie powinien trwać dłużej niż 30 sekund.

proces trenowania nel

Wynik zaś można zweryfikować na testowym fragmencie artykułu, który nie był częścią zbioru uczącego. Jak widać na zrzucie poniżej, zarówno Zygmunt August jak i Iwan Groźny zostali rozpoznani i zidentyfikowani poprawnie, jednak po przetworzeniu całej publikacji można zauważyć, że wyniki dla cara są jednak słabsze, model nie zawsze przypisuje identyfikator z wikidata do rozpoznanej encji tej postaci. Problemem oprócz może zbyt małej próbki treningowej może być język polski, trudniejszy w przetwarzaniu od angielskiego choćby ze względu na fleksję. Notebook NEL_test.ipynb do pobrania z repozytorium. wyniki analizy nel

Sposób łączenia i identyfikacji z bazami wiedzy dostępny w spaCy jest jednak tylko jedną z wielu możliwości Zob. także narzędzie elinker przygotowane przez konsorcjum Clarin-PL. . Przed dołączeniem do biblioteki komponentu EntityLinker powstawały rozwiązania przygotowane przez użytkowników spaCy np. pakiet spacy-entity-linker Zobacz opis. . Pomysł zakładał przygotowanie lokalnej bazy wiedzy (w formacie sqlite) opartej na wikidata i dopasowywanie pojęć w przetwarzanym tekście do etykiet i aliasów elementów w wikidata. Takie podejście nie wymagało trenowania modelu, nie uwzględniało jednak kontekstu w którym występowało badane wyrażenie. Przygotowana baza wiedzy oparta jest na angielskiej instancji wikidata a jej zmiana na inną, jak opisano w dokumentacji pakietu, nie jest niestety prosta.

Można za to przetestować zbliżone, ale mniej wydajne rozwiązanie w postaci bezpośredniego odpytywania przez API serwisu wikidata.org. Rozpoznawaniu i łączeniu będą poddawane tylko postacie (encje z etykietą persName ropoznane przez spaCy), tylko w polskiej wersji językowej wikidata, a otrzymane wyniki będą dodatkowo weryfikowane poprzez sprawdzenie czy znaleziony element posiada właściwość instance of = 'human' oraz czy właściwość date of death (P570) z wikidata wskazuje na okres historyczny tożsamy z chronologią  tematyki artykułu. Funkcja wikilinker, której kod jest dostępny w notebooku wspomianym wyżej, ma trzy obowiązkowe argumenty: string z nazwą szukanej postaci, najwcześniejsza data śmierci postaci, najpóźniejsza data śmierci postaci (oraz opcjonalny czwarty argument z liczbą rozważanych elementów wyszukanych w wikidata - zwykle wyszukiwanie zwraca więcej niż 1 pozycję, szczególnie dla mniej precyzyjnych tekstów np. 'Albrecht' ta liczba może być spora, domyślnie przyjęto 10). Znając tematykę artykułu i okres historyczny jakiego dotyczy możemy w wyszukiwaniu uwzlgędnić zakres lat 1550-1625, co znacznie poprawi precyzję wyszukiwania. Fragment kodu i efekt wyszukiwania widoczny jest na zrzucie poniżej.

wikilinker wyszukiwanie

W 9 przypadkach na 10, funkcja wikilinker znalazła prawidłowy identyfikator postaci w wikidata.org, udało się to nawet dla imienia 'Albrechta', zapewne trochę przypadkiem dla podanego zakresu lat (zakresu dla daty śmierci postaci) i imienia pierwszy znaleziony element to właśnie Albrecht Hohenzollern. Jedyna nieznaleziona postać to Szymon Maricjus-Czystochlebski - prawdopodobnie jest to Q9352684 (Szymon Marycjusz, alias: Szymon Maricjusz z Pilzna) Zobacz w wikidata. , ale różnica między encją NER w tekście a etykietą w wikidata.org jest zbyt duża by identyfikator mógł zostać znaleziony. Można też podejrzewać, że nawet gdyby etykieta lub alias tego elementu w wikidata miały formę taką jak występuje w tekście, to ze względu na fleksję wyszukiwanie również by się nie powiodło Przed wyszukiwaniem w wikidata.org skrypt dokonuje lematyzacji encji (przekształca imię i nazwisko postaci do formy podstawowej) jednak ta funkcjonalność w używanym modelu spaCy nie jest doskonała, dla rzadszych imion, nazwisk będzie raczej niepoprawna. .

Oczywiście proste funkcje tego typu nie zastąpią prawdziwych mechanizmów NEL, jednak gdy możemy z góry sprecyzować zakres łączenia (tylko osoby, tylko polska wikidata, tylko określony zakres chronologiczny) rezulat bywa całkiem znośny.

Eksperymenty z automatyczną anotacją i łączeniem z bazą wiedzy można przeprowadzić bez programowania, np. dzięki stronie wikifier.org, która analizuje wklejony przez użytkownika tekst, łącząc znalezione encje/pojęcia z hasłami wikipedii. Wikifier obsługuje 100 języków, w tym polski, jego sposób działania opisany jest w artykule Annotating Documents With Relevant Wikipedia Concepts. Na zrzucie ekranu poniżej widoczny jest efekt przetworzenia przez Wikifier fragmentu publikacji S. Bodniaka.

strona wikifier.org

spaCy i automatyczne tagowanie encji w TEI Publisherze (22.10.2022)

Czy trzeba programować by zajmować się przetwarzaniem języka naturalnego? Prosta odpowiedź brzmi: nie, można przecież wynająć programistę lub specjalistę data science. Ale ponieważ czas programistów kosztuje, a komunikacja między humanistami a specjalistami technicznymi bywa skądinąd wyzwaniem i często rzutuje na jakość wyników, można skorzystać z innej ścieżki - istnieją narzędzia nie wymagające umiejętności programowania. Choć nadal należy rozumieć co się robi, co jest możliwe a co niekoniecznie. NLP jest bardzo dynamicznie rozwiającą się technologią, ale stopień jej rozwoju jest inny dla każdego języka naturalnego (to co dziś jest możliwe dla tekstu angielskiego, niekoniecznie będzie możliwe dla tekstu polskiego).

Jednym z popularnych narzędzi wśród humanistów cyfrowych jest TEI Publisher Oficjalna strona aplikacji TEI Publisher. , aplikacja znacznie ułatwiająca przygotowanie edycji cyfrowych na bazie dokumentów xml w standardzie TEI. Program ten od jakiegoś czasu posiadał możliwość ręcznej anotacji tekstu podstawowymi eykietami typu osoba i miejsce Zobacz video: TEI Publisher Annotation Facility: Flexible, Browser Based Annotations for TEI. . Od wersji 8.00 (jeszcze nie opublikowanej) TEI Publisher będzie miał także możliwość anotacji automatycznej przy użyciu metod NLP (NER), a wykorzystuje w tym celu bibliotekę spaCy Artykuł na blogu e-editiones. .

Obecnie jedyną metodą przetestowania rozwojowej wersji TEI Publishera jest jego instalacja we własnym zakresie. Autorzy aplikacji udostępniają jednak repozytorium Zobacz repozytorium eeditiones. z przygotowanymi plikami konfiguracyjnymi do utworzenia i uruchomienia własnej instancji opartej na kontenerach dockera. Ten sposób instalacji uwalnia nas od potrzeby ręcznego konfigurowania wszystkich komponentów: javy, pythona, eXist-db, spaCy itd. Po pobraniu (sklonowaniu) repozytorium należy uruchomić budowę obrazów dockera ze źródeł poleceniem:
docker-compose build --build-arg ADMIN_PASS=my_pass
gdzie 'my_pass' oznacza hasło admina serwera eXist-db.

Budowanie może potrwać kilka minut, po jego zakończeniu można uruchomić rozwojową wersję aplikacji poleceniem: docker-compose up -d, co znów zajmie kilka-kilkanaście sekund, po czym aplikacja będzie widoczna w przeglądarce pod adresem http://localhost. Co prawda w stopce strony będzie ciągle widoczna wersja 7.10, ale w rzeczywistości działa wersja rozwojowa z gałęzi master repozytorium. Aby się o tym przekonać wystarczy wejść w kolekcję dokumentów 'Annotation Samples' dostarczoną z aplikacją, następnie w dowolny dokument, np. Letter #20 from Robert Graves to William Graves (at Oundle School) November 8, 1957, w pasku narzędzi po lewej stronie ekranu wśród ikon widoczna jest czarna ikonka z symbolem osób i plusem. To znak, że w systemie dostępna jest usługa NER. Po jej uruchomieniu aplikacja wyświetla okno dialogowe pozwalające wybrać model do przetwarzania tekstu. Standardowo dostępne są dwa: de_core_news_sm dla języka niemieckiego i en_code_web_sm dla języka angielskiego.

modele spaCy w TEI Publisherze

Przykładowy dokument jest po angielsku należy więc wybrać ten drugi model i przycisk Run. Po przetworzeniu można będzie zobaczyć nowe anotacje typu person lub organization.

wynik NER w TEI Publisherze

Przełączenie się na widok źródeł TEI dokumentu pokaże, że postacie np. Juanito zostały poprawnie otagowane znacznikiem .

kod XML-TEI

Tekst, który jest analizowany w tym cyklu zapisek jest jednak tekstem w języku polskim. Czy da się w podobny sposób jak przykładowy dokument przetworzyć publikację Stanisława Bodniaka? W nieoficjalnej wersji rozwojowej wymaga to pewnych zabiegów. W przypadku uruchomionej już instancji aplikacji niezbędna jest ingerencja w zawartość jednego z kontenerów obsługujących system TEI Publisher, ten w którym działa serwis NER oparty na bibliotece spaCy. Domyślnie po uruchomieniu nazywa się on teipublisher-docker-compose-ner-1 co można zobaczyć na liście kontenerów uruchamiając w konsoli komendę:
docker container ps
Do działającego kontenera można dostać się poleceniem exec dockera np.:
docker exec -it teipublisher-docker-compose-ner-1 bash,
po którego wywołaniu znajdziemy się w linuksowym środowisku kontenera (w tym przypadku opartym na debianie). To co jest niezbędne do obsługi języka polskiego to polski model spaCy, który można zainstalować poleceniem: python -m spacy download pl_core_news_md. Sama instalacja modelu nie spowoduje jeszcze jego dostępności na liście modeli w TEI Publisherze, konieczny jest jeszcze restart kontenera a najpierw wyjście z niego poleceniem exit. Do zatrzymania zestawu kontenerów obsługujących TEI Publishera wystarczy w linii komend wpisać: docker-compose stop, a po chwili ponownie uruchomić system poleceniem docker-compose start. Można by uniknąć konieczności modyfikowania zawartości kontenera, gdyby polski model instalowany był domyślnie, odpowiada za to plik konfiguracyjny Dockerfile w repozytorium serwisu NER TEI Publishera. Zobacz repozytorium. dodanie do polecenia RUN w tym pliku dodatkowego kodu:
&& python3 -m spacy download pl_core_news_md
rozwiązałoby sprawę.

Jednak dostępność polskiego modelu na liście modeli w interfejsie użytkownika TEI Publishera nie oznacza niestety, że potrafi on z tego modelu skorzystać. Problemem są odmienne etykiety, którymi model oznacza znalezione encje nazwane (named entity). Autorzy TEI Publishera przewidzieli mapowanie z etykiet używanych w modelach angielskich i niemieckich np. "person": ("PER", "PERSON") jednak w standardowych modelach spaCy dla języka polskiego etykiety są nieco inne: np. 'persName' dla osób czy 'orgName' dla organizacji. zob. na stronie spaCy , dla modelu pl_core_news_md należy rozwinąć sekcję Label Scheme i przewinąć do punktu NER, gdzie znajduje się lista etykiet NER używanych w tym modelu.

Aby to zmienić konieczna jest modyfikacja kodu źródłowego serwisu NER TEI Publishera, konkretnie pliku main.py w podkatalogu workspace/tei-publisher-ner/scripts, znów w działającym kontenerze (być może w oficjalnej wersji aplikacji będzie to już uwzględnione?) Tymczasowy fork z modyfikacją jest w repozytorium. . W pliku należy zmienić zawartość słownika MAPPINGS z:

            MAPPINGS = {
                "person": ("PER", "PERSON"),
                "place": ("LOC", "GPE"),
                "organization": ("ORG"),
                "author": ("AUT")
            }
        

na:

            MAPPINGS = {
                "person": ("PER", "PERSON", "persName"),
                "place": ("LOC", "GPE", "placeName", "geogName"),
                "organization": ("ORG", "orgName"),
                "author": ("AUT")
            }
        

Tym razem restart kontenerów nie będzie potrzebny, wywołanie narzędzia NER w TEI Publisherze wyświetla już znalezione w polskim tekście encje, na poniższym zrzucie ekranu widać też przygotowany przez TEI Publishera kod pliku XML w standardzie TEI Uwaga: zmiany wprowadzane bezpośrednio w kontenerach nie znikną po zatrzymaniu i ponownym uruchomieniu kontenera, oczywiście znikną jednak przy ponownym utworzeniu kontenerów z obrazów dockera. .

wynik NER w TEI Publisherze, tekst w języku polskim

Można spodziewać się, że pewne niedogodności wersji rozwojowej zostaną w przyszłości dopracowane, a sama instalacja może być przecież przeprowadzona na serwerze przez specjalistę. Lektura artykułu zlinkowanego w przypisie na początku zapiski pokazuje także, że w rozwojowej wersji aplikacji przewidziano bardziej zaawansowane możliwości np. trenowanie własnego modelu w oparciu o korpus tekstów anotowanych właśnie w TEI Publisherze Inną ciekawą aplikacją obsługującą 'wzbogacanie' tagowania plików TEI o rozpoznane jednostki nazewnicze dzięki NER i uczeniu własnych modeli jest NEISS - TEI Entity Enricher. . Aplikacja ta już dziś jest cennym narzędziem w arsenale cyfrowego humanisty, po ukazaniu się oficjalnej wersji 8.00 stanie się też systemem ułatwiającym praktyczne korzystanie z niektórych metod (NER) przetwarzania języka naturalnego bez potrzeby programowania i z pożytkiem w postaci łatwiejszego tworzenia edycji cyfrowych.


spaCy i koreferencje, czyli Jerzy bawił we Włoszech
a jego włości popadały w ruinę (30.10.2022)

Jednym z problemów podczas przetwarzania tekstów pisanych z myślą o ludzkim czytelniku a nie algorytmie wykonywanym przez komputer są informacje odnoszące się  do tej samej postaci, ale wyrażone nie wprost, lecz choćby poprzez zaimki osobowe lub dzierżawcze, czyli koreferencje. Czytając na przykład tekst:

"Jan Tarnowski, syn Jana Amora Iuniora i Barbary z Rożnowa, wnuczki Zawiszy Czarnego, pochodził z wpływowej szlacheckiej rodziny Leliwitów Tarnowskich...
Wychowywał się na dworach kardynała Fryderyka Jagiellończyka...
Odtąd też trwały: jego spór z siostrzeńcem Piotrem Kmitą i żale względem dworu."
Fragmenty biogramu Jana Tarnowskiego z polskiej wersji Wikipedii.

Można obawiać się, czy fakty podane w taki sposób będą czytelne dla skryptu przetwarzającego tekst. Wychowywał się - ale kto? Jego czyli kogo?

Wiedza na temat tego, kto kryje się pod wyrażeniem "jego", czy kogo dotyczy czasownik "wychowywał się" jest szczególnie przydatna przy próbach rozpoznawania relacji między encjami (np. osobami) w tekście, wiedząc że chodzi o Jana Tarnowskiego, możemy uzyskać informację iż ważną postacią dla niego byli Piotr Kmita i Ferdynad Jagiellończyk. Czy spaCy jest w stanie w tym pomóc i przede wszystkim czy to będzie działać dla języka polskiego? Okazuje się, że tak. W repozytorium należącym do Explosion AI, firmy rozwijającej spaCy znajduje się dodatkowa biblioteka Coreferee, przeznaczona do rozwiązywania koreferencji w języku angielskim, francuskim, niemieckim i polskim. Instalacja opisana jest na stronie repozytorium Zob. repozytorium github. , dokumentacja zawiera też opis działania biblioteki, wyjaśnienie decyzji podjętych podczas jej tworzenia Coreferee powstało w ramach projektu Holmes (zobacz wpis na blogu Explosion AI, Holmes niestety obsługuje tylko j. angielski i niemiecki), co jest przyczyną pewnych specyficznych cech narzędzia, np. pracuje raczej na pojednycznych tokenach. , także tabelę dokładności modeli dla poszczególnych języków (dla polskiego to 72-76%).

Jak użyć Coreferee? Poniżej prosty program przetwarzający wspomniany fragment biogramu hetmana Jana Amora Tarnowskiego.

biblioteka coreferee

Jak wydać na powyższym zrzucie ekranu sformułowania Wychowywał, Otrzymał, zajmował, jego zostały prawidłowo powiązane z encją 'Jan' Notebook koreferencje.ipynb do pobrania z repozytorium. .

Coreferee wychwytuje klastry (przykład powyżej zawiera akurat tylko jeden) tokenów odwołujących się do tej samej postaci, słowo jego mogłoby zostać zastąpione przez Jana Tarnowskiego, otrzymał przez Jan Tarnowski otrzymał (zob. zrzut ekranu poniżej), ale takie liczne powtórzenia byłyby męczące dla ludzkiego czytelnika, który świetnie sobie radzi z odczytywaniem informacji z kontekstu. Sprecyzowanie o kogo chodzi jest jednak niezbędne przy maszynowym przetwarzaniu treści, dlatego powstają narzędzia w rodzaju Coreferee.

zdanie z przetworzonymi koreferencjami

Parę tygodni temu firma Explosion AI opublikowała nowy komponent biblioteki spaCy Coreference Resolution, szczegółowy opis tego mechanizmu jest dostępy na blogu Explosion, niestety obsługuje na razie tylko język angielski Dostępny jest też krótki film Coreference Resolution in spaCy. .


Kraken, czyli HTR to jest to (??.01.2023)

O ile rozpoznawanie druku nie jest dziś wielkim problemem i radzą sobie z nim liczne programy komercyjne, jak i open source Istnieją także systemy przygotowane specjalnie do odczytywania starodruków np. OCR4all ocr4all.org. , to rozpoznawanie pisma ręcznego, szczególnie pochodzącego sprzed paru lub kilku stuleci jest ciągle sporym wyzwaniem. Duży postęp w tej dziedzinie zawdzięczamy rozwojowi uczenia maszynowego, szczególnie zaś uczenia głębokiego. Jedną z aplikacji przeznaczonych do odczytywania pisma ręcznego (choć druku także) dzięki konwolucyjnym i rekurencyjnym sieciom neuronowym jest Kraken. Program oparty na wcześniejszym systemie OCRopus, dostępny bezpłatnie wraz z kodem źródłowym na otwartej licencji (Apache 2.0).

Aplikację można zainstalować w systemie Linux Lub Mac OSX, procedura instalacji jest typowa dla pakietów języka Python i została opisana na stronie Krakena. Nie jest to aplikacja z interfejsem użytkownika - obsługuje się ją z linii komend. Obliczenia wykonywane podczas tzw. treningu modeli - sieci neuronowych ropoznających pismo, są dosyć czasochłonne. Kraken potrafi skorzystać z mocy obliczeniowej karty graficznej komputera, o ile taka jest dostępna (chodzi o dedykowaną kartę GPU np. NVIDIA GeForce). Brak takiej karty nie uniemożliwia skorzystania z aplikacji, wydłuża jednak czas trenowania własnych modeli.

Kraken jest wykorzystywany do rozpoznawania wielu rodzajów pisma w wielu językach, skryptów pisanych od lewej do prawej - jak w piśmie europejskim, od prawej do lewej (jak w hebrajskim czy arabskim), czy od góry do dołu. W przypadku braku gotowego modelu do rozpoznawania jakiegoś pisma, użytkownik może przygotować własny, operając się na materiałach treningowych - skanach rękopisów i manualnie przygotowanej transkrypcji. Czym w ogóle są modele? Wiedza na temat rozpoznawanego pisma nie jest zaszyta w aplikacji, lecz zapisana w binarnch pilkach w formacie *.mlmodel. Plik taki, zwykle o objętości 15-25 MB zawira szczegółową definicję warstw sieci neuronowej wytrenowanej wcześniej do rozpoznawania danego pisma. Kraken wczytując dane takiego modelu jest w stanie przetworzyć skan rękopisu i zwrócić rozpoznany tekst. Istnieje katalog gotowych modeli udostępnionych na otwartej licencji przez ich autorów (zob. zenodo). Są tam m.in. modele rozpoznające pismo średniowieczne z XII-XV wieku: 'HTR Model - Medieval Latin and French 12th-15th c. expanded (no abbr.)' czy model rozpoznający fransuskie pismo ręczne z XVIII-XX wieku 'LECTAUREP Contemporary French Model (Administration)' trenowany na dokumentach notarialnych. Jeżeli posiadamy rękopisy zbliżone materiałów na których trenowano jeden z dostępnych publicznie modeli możemy go wykorzystać do rozpoznawania prawdopodobnie z niezłym rezultatem.

Kraken posiada wbudowaną obsługę pobierania modeli z katalogu na stronie zenodo.org. Polecenie kraken list wyświetla listę modeli dostępnych do pobrania, wśród wyświetlanych informacji jest identyfikator pliku np. '10.5281/zenodo.6542744' (to wspomniany wcześniej model oparty na pismach notarialnych). Kolejne polecenie kraken get w którym należy wskazać taki identyfikator pobiera model na dysk użytkownika (np. do katalogu ~/.config/kraken w systemie Ubuntu).

Pobrany model może być od razu użyty do rozpoznawania pisma. W przykładowym poleceniu:

kraken -i image.png image_text.txt segment -bl ocr -m HTR-United-Manu_McFrench.mlmodel

parametr -i image.png image_text.txt oznacza nazwę wejściowego pliku ze skanem rękopisu, oraz nazwę wyjściowego pliku tekstowego, segment -bl oznacza przygotowanie segmentacji, podziału skanu na regiony i rozpoznaniu wierszy, zaś ocr -m HTR-United-Manu_McFrench.mlmodel jest poleceniem użycia do rozpoznawania pisma jednego z wcześniej pobranych modeli.

c.d.n.


Dżin z czarodziejskiej lampy czyli GPT 3.5 (29.01.2023)

Kiedy w listopadzie 2022 roku firma OpenAI Strona firmy openai.com. udostępniła publicznie wersję beta swojego nowego produktu ChatGPT potrzeba było zaledwie kilku dni by liczba jego użytkowników osiągnęła milion. Dziś jest ich z pewnością wielokrotnie więcej, perspektywa porozmawiania ze sztuczną inteligencją lub zlecenia jej jakiejś pracy jest trudna do odparcia. Jakie jednak praktyczne znaczenie może mieć ChatGPT czy ogólnie duże modele językowe (LLM) dla cyfrowego historyka?

Czym w ogóle jest GPT (Generative Pretrained Transformer), którego najnowszą odsłonę okresla się często jako wersję GPT-3.5 (nazywaną też InstructGPT)? To właśnie tzw. duży model językowy (LLM) zob. Language model: Wikipedia. wytrenowany przez firmę OpenAI na bazie ogromnego zbioru tekstów oraz udoskonalony poprzez uczenie wzmacniające na podstawie informacji zwrotnych od ludzi Aligning Language Models to Follow Instructions. . Modele tego typu są używane do generowania tekstów, tłumaczenia, tworzenia streszczeń, ale też do zadań wymagających pewnego rozumienia tekstu. Można na przykład poprosić model o przygotowanie konspektu artykułu na jakiś temat, oraz listy z podstawową bibliografią, internet jest już pełen artykułów i filmów na temat tego jak ChatGPT wpłynie na pracę akademicką i badania naukowe zob. How Will ChatGPT Change Research Paper Writing?, ChatGPT: A game changer for researchers?, Harness the power of AI for research: How ChatGPT is changing the game. . Trzeba jednak brać pod uwagę, że jest to bardzo wczesny etap fascynacji nową technologią i zarówno wiele możliwości wykorzystania jak i wiele pułapek związanych z wykorzystaniem GPT/LLM nie zostało jeszcze rozpoznanych. Pytanie, na które dziś można spróbować odpowiedzić, brzmi: czy tak zaawansowany model, rozumiejący całkiem dobrze język polski, mógłby wykonywać zadania związane z masowym przetwarzaniem tekstów publikacji i źródeł historycznych?

ChatGPT dostępny jest (obecnie) jedynie w formie interaktywnej. Można z nim porozmawiać o historii, sprawdzić poziom wiedzy, a równie często też niewiedzy (czy Jan Amor Tarnowski był konfederatą barskim? Chyba jednak nie...). Ale z modeli GPT można również korzystać poprzez sprzedawane przez OpenAI usługi API API jest usługą płatną, jednakże każdy nowy użytkownik otrzymuje bezpłatnie do wykorzystania tokeny o wartości 18$, zob. OpenAI API. , co umożliwia tworzenie prostych skryptów, które przetwarzają teksty z wykorzystaniem modeli o różnej mocy, a także eksperymentowanie z różnymi parametrami zmieniającymi ich charakterystykę. Skrypty te mogą nie tyle pytać model o jego wewnętrzną wiedzę, ale mogą wykorzystać umiejętności językowe LLM (Large Language Model) właśnie do przetwarzania podanych mu tekstów. Tak naprawdę można to zrobić także podczas sesji z ChatGPT, ale wykorzystanie skryptów i kolekcji tekstów jest chyba wygodniejsze Istnieje jeszcze tzw. OpenAI Playground gdzie można testowac modele dostępne przez API w formie bardziej interaktywniej, narzędzie wymaga zalogowania się kontem OpenAI, a jego używanie kosztuje tyle samo co korzystanie z API. .

Jak GPT radzi sobie z wyszukiwaniem słów kluczowych, osób, miejsc? Czy potrafi wyszukiwać informacje o relacjach rodzinnych między postaciami występującymi w tekście? Rozpoznać funkcje, stanowiska i urzędy pełnione przez głównego bohatera przesłanej publikacji? Jak model sprawdzi się w roli narzędzia automatycznie przetwarzającego całe pakiety tekstów w celu wydobycia kluczowych informacji? Takie i inne eksperymenty opisuję także na stronie repozytorium: gpt_historical_text.

Czy GPT poradzi sobie na przykład z wyciągnięciem z publikacji Stanisława Bodniaka listy osób? Po przesłaniu do modelu kilku akapitów tekstu ("Polska a Bałtyk za ostatniego Jagiellona" Wybrany fragment. ) oraz zapytania (promptu):

prompt: W podanym tekście wyszukaj informacje o osobach, znalezione osoby wypisz w formie listy, jeżeli są znane funkcje lub urzędy osób umieść te informacje w nawiasach obok osób

model text-davnci-003 (uruchomiony z parametrami: temperature=0.0, top_p=1.0, frequency_penalty=0.0, presence_penalty=0.0) zwraca całkiem niezły wynik:

  • - Zygmunt August (król)

  • - Jan Tarnowski (hetman)

  • - Piotr Kmita (marszałek koronny)

  • - Stanisław Hozjusz (bp)

  • - Jan Ocieski (kanclerz)

  • - Jan Przerębski (podkanclerzy)

  • - Marcin Kromer

  • - Szymon Maricjus-Czystochlebski

  • - Łukasz Górnicki

  • - Barnim XI (książę)

pomijając jedynie ks. Albrechta.

Inny przykład:
prompt: W podanym tekście wyszukaj słowa kluczowe będące nazwami własnymi, znalezione słowa kluczowe wypisz w formie listy, w nawiasach obok słowa kluczowego umieść informację o typie słowa kluczowego np. osoba, miejsce, rzeka, morze.

Wynik:

  • - Zygmunt August (osoba)

  • - Malbork (miejsce)

  • - Królewiec (miejsce)

  • - Albrecht (osoba)

  • - Jan Tarnowski (osoba)

  • - Piotr Kmita (osoba)

  • - Stanisław Hozjusz (osoba)

  • - Jan Ocieski (osoba)

  • - Jan Przerębski (osoba)

  • - Marcin Kromer (osoba)

  • - Szymon Maricjus-Czystochlebski (osoba)

  • - Łukasz Górnicki (osoba)

  • - Gdańsk (miejsce)

  • - Wisła (rzeka)

  • - Barnim XI (osoba)

  • - Lębork (miejsce)

  • - Bytów (miejsce)

  • - Bałtyk (morze)

A może coś bardziej skomplikowanego? Na przykład czy model GPT mógłby na podstawie przekazanego tekstu ustalić powiązania rodzinne jego głównego bohatera? Do testu wykorzystany zostanie artykuł na temat Ludwika Wejhera pochodzący z Wikipedii Ludwik Wejher (zm. 1656) wojewoda pomorski. . Zapytanie (podpowiedź), która ma skłonić model 'davinci' do poprawnej odpowiedzi wygląda tym razem tak:

prompt: Na podstawie podanego tekstu wyszukaj wszystkie relacje rodzinne głównego bohatera (tylko jego krewnych, powinowatych, teściów, szwagrów, szwagierek). Wynik wypisz w formie listy nienumerowanej z rodzajem pokrewieństwa w nawiasie. Na przykład:
- Jan Kowalski (brat)
- Anna (siostra)
Jeżeli w tekście nie ma takich informacji napisz: brak danych.

Wynik:

  • - Jan Wejher (ojciec)

  • - Anna ze Szczawińskich (matka)

  • - Mikołaj Wejher (brat)

  • - Jakub Wejher (brat)

  • - Gerard Denhoff (teść)

  • - Katarzyna Jadwiga z Denhoffów (żona)

  • - brak danych (szwagrów, szwagierek)

Przykład listy stanowisk lub urzędów dla tej samej postaci (i z tego samego tekstu):

Prompt: Na podstawie podanego tekstu wymień wszystkie stanowiska i urzędy głównego bohatera tekstu. Wynik wypisz w formie listy.

  1. 1. Pułkownik od 1647

  2. 2. Kasztelan elbąski od 1648

  3. 3. Wojewoda pomorski od 1649

  4. 4. Starosta skarżewski

  5. 5. Starosta wałecki

  6. 6. Starosta nowodworski w 1650 roku

Jak w ogóle model językowy to robi, jak radzi sobie z zadaniami z zakresu NLP, użyte powyżej zapytania albo nie zawierają w ogóle przykładów albo jedynie proste przykłady wyników? Możliwości modelu GPT wynikają z rozmiarów architektury sieci (175 miliardów parametrów) oraz rozmiarów danych treningowych, użytych do uczenia - zbiór tekstów liczył około biliona słów Jak wygląda i działa architektura transformerów np. modelu GPT można przeczytać w artykule na blogu Mirosława Mamczura Czym jest i jak działa transformer (sieć neuronowa)? . Niektóre z cech modelu GPT-3 były niespodzianką nawet dla jego twórców na przykład umiejętność wykonywania poleceń w języku innym niż angielski Jan Leike tweet . Mimo, że 93% użytego do trenowaia GPT-3 materiału uczącego to teksty w języku angielskim, model `davinci-003` radzi sobie całkiem dobrze także z innymi językami np. z polskim, a materiały polskie stanowiły zaledwie 0.25% całości!

Skoro jest tak dobrze... a może wcale nie jest?

Modele GPT-3.5 takie jak 'davinci' są bardzo dobrymi modelami językowymi, nie są jednak sztuczną inteligencją, język nie jest przecież tożsamy z myśleniem. Wiedza modelu trenowanego wieloma gigabajtami tekstów również nie jest całkiem pewna i ścisła. Pytany o fakty model 'davinci' (lub ChatGPT) jest często całkiem poprawny w swoich odpowiedziach, ale potrafi fakty tworzyć, czasami wbrew zwykłej logice, na przykład wspomniane wyżej rzekome uczestnictwo hetmana Tarnowskiego w konfederacji barskiej, mimo iż żył ponad 200 lat wcześniej i nie było to możliwe. Innym problemem są ograniczenia techniczne, model może przetworzyć w jednym zapytaniu 4000 tokenów, przy czym chodzi o sumę długości zapytania i wyniku. A ponieważ token to często mniej niż wyraz (dłuższe wyrazy dzielone są na kilka tokenów), to realny tekst możliwy do jednorazowego przetworzenia to np. 6 tys. znaków, przy założeniu odpowiedzi o długości 500-800 tokenów. Dłuższe teksty wymagałyby albo wstępnego skrócenia, albo podzielenia.

Nie przeszkadza to przy generowaniu tekstów, udzielaniu łudząco przypominających ludzkie odpowiedzi na zadanie pytania, jednak przy wyciąganiu informacji np. z przekazanych modelowi biografii oczekiwana jest precyzja, powtarzalność wyników, pewność informacji. Model, zależnie od parametrów uruchomienia, może mieć skłonnośc do większego lub mniejszego interpretowania danych i zmyślania faktów, zjawisko to określa się czasem mianem halucynacji. Może też na przykład udzielić odpowiedzi wynikającej z kontekstu - o ile dotyczy to informacji, że syn córki bohatera biografii jest jego wnukiem, to jest cenna umiejętność. Natomiast ustalanie miejsca urodzenia osoby na podstawie informacji, iż bohater pochodził z rodu wywodzącego się z miejscowości X, jest już przesadną interpretacją danych, która może, ale nie musi być prawdą.

Próby wykorzystania dużych modeli językowych do ekstrakcji informacji z tekstów napotykają często problem, którego źródłem jest sam przetwarzany tekst. Język używany w opracowaniach bywa po prostu trudny do interpretacji dla modelu. Przykładem może być  biogram Mariana Świeykowskiego, żyjącego w XIX wieku marszałka szlachty guberni wołyńskiej, pochodzący z Polskiego Słownika Biograficznego (PSB t. 51, 2016-17, s. 377-379) Polski Słowik Biograficzny dostępny jest online w repozytoriach RCIN, aczkolwiek jest to dostęp limitowany. . Człowiek nie będzie miał problemu z interpretacją informacji podanych w tym tekście, jednak 'davinci-003' poproszony o wypisanie krewnych i powinowatych, wraz z rodzajem relacji rodzinnych, popełnia uparcie błąd dla jednej z 12 spokrewnionych osób, nazywając Rocha Kossowskiego babcią bohatera biogramu. Można podejrzewać, że wynika to z konstrukcji zdania i przyjętego w PSB sposobu zapisywania informacji z unikaniem powtarzania nazwisk czy stosowaniem skrótów. Problematyczne zdanie brzmi: "Ur. prawdopodobnie w Kołodnie (pow. krzemieniecki), był wnukiem Leonarda (Leona) Marcina (zob.) i Rocha Kossowskiego (zob.), synem Adama Macieja (ok. 1780 — 1858), kapitana 1. p. huzarów wojsk[...]" gdzie mamy wymienionych dwóch dziadków bohatera, w tym pierwszy z nich bez podania nazwiska (w domyśle Świeykowski).

Po uproszczeniu tekstu (w tym powyższego fragmentu do:"Był wnukiem Leonarda Marcina Świeykowskiego a także Rocha Kossowskiego.") model zwraca całkowicie poprawne dane krewnych Mariana Świeykowskiego. Tym razem zapytanie zadano w języku angielskim, stąd angielskie nazwy rodzajów pokrewieństwa.

Prompt: Based on the given text, search for all relatives and affinities of the main character. List the result in the form of an unnumbered list with the type of kinship in parentheses. For example:
- John Kowalski (brother)
- Anna (sister)
If there is no information in the text about some types of kinship omit these types.

Wynik:

  • - Adam Maciej Świeykowski (father)

  • - Krystyna Świeykowski (mother)

  • - Leonard Marcin Świeykowski (grandfather)

  • - Roch Kossowski (grandfather)

  • - Olga Świeykowski (sister)

  • - Cezary Poniatowski (brother-in-law)

  • - Jadwiga Świeykowski (sister)

  • - Izabela Janina Sobańska (wife)

  • - Hieronim Sobański (father-in-law)

  • - Olga Maria Zofia Świeykowski (daughter)

  • - Stefan Grocholski (son-in-law)

  • - Maria Świeykowski (daughter)

  • - Leon Ledóchowski (son-in-law)

A przecież podczas automatycznego przetwarzania tekstów poszukujemy faktów, 'automatyczność' wyklucza z góry jakąś wstępną interpretacje przez człowieka, chodzi właśnie o przeniesienie pracy na narzędzia informatyczne, by uzyskane dane szybciej i sprawniej wykorzystać np. do tworzenia baz wiedzy. Czy model językowy nie mógłby najpierw uprościć, streścić przetwarzanego tekstu a dopiero potem przystąpić do ekstrakcji informacji? Niestety, należy się spodziewać że błędy interpretacyjne, które model popełnia, przeniesie po prostu do uproszczonej wersji. . Problem lepszego przetwarzania bardziej zawiłych tekstów być może zostanie rozwiązany w kolejnych wersjach modeli LLM, plotki głoszą, że GPT-4 pojawi się już w tym roku (i że to ta nowa wersja obsługuje niedawno zaprezentowaną przez Microsoft integrację  AI z wyszukiwarką Bing) Kiedy rozpoczęto prace nad integracją GPT z githubem, początkowo model w 70% przypadków generował błędny kod, dziś wielu programistów nie wyobraża sobie pracy bez usługi Github Copilot, zob. wywiad z Natem Friedmanem. . Z kolei przed nadinterpretacją lub skłonnościami 'halucynacyjnymi' modelu można się  częściowo zabezpieczać używając odpowiednio jego parametrów, można też zadbać o jak najlepszy tekst zapytania (promptu). Wyniki działania modeli będą jednak zawsze wymagały weryfikacji. GPT-3.5 nie jest więc narzędziem bezproblemowym, ale czy dżiny zamieszkujące czarodziejskie lampy nie bywały kłopotliwe?


Podręczny OCR. Jak odczytywać fragmenty tekstu z obrazów (08.06.2023)

Skopiowanie tekstu nie jest problemem w przypadku współczesnych plików pdf, czy stron internetowych, ciągle jednak spotyka się źródła zapisane w fomie pdf-ów bez warstwy tekstowej, czy też w plikach graficznych w rodzaju jpg, djvu. Można je oczywiście poddać  pełnemu rozpoznawaniu OCR w jednym z popularnych programów przeznaczonych do tego celu jak FineReader, jednak często potrzebujemy tylko małego fragmentu tekstu i przydałoby się spontanicznie zaznaczyć go na ekranie komputera i skopiować tekst do schowka.

Z pomocą przychodzą narzędzia komercyjne w rodzaju ABBY ScreenReader, ale także liczne programy typu opensource, oparte najczęściej na popularnym silniku ocr - tesseract. Jednym z nich jest textshot, którego używam w systemie Ubuntu. Jego instalacja nie jest najprostsza, chyba że na codzień używa się języka programowania Python, wówczas instalacja przebiega podobnie do zwykłych bibliotek rozszerzających możliwości Pythona:

pip install textshot

Wcześniej należy zadbać o instalację samego tesseracta, oraz jego pakietów językowych np.:

sudo apt install tesseract-ocr
sudo apt install tesseract-ocr-all

Powyższe polecenia zainstalują silnik ocr i wszystkie dostępne języki, listę języków można wyświetlić poprzez komendę:

tesseract --list-langs

Samą aplikację można uruchomić z linii poleceń, dodając język (lub języki) tekstu, który będzie rozpoznawany:

textshot pol

Ale dużo praktyczniej jest podpiać jej wywołanie pod skrót klawiszowy w systemie (w Ubuntu Settings -> Keyboard Shortcuts). Po uruchomieniu ekran komputera ulega przyciemnieniu a za pomocą myszy można zaznaczyć fragment, który ma zostać rozpoznany przez OCR. Proces rozpoznawania przeprowadzany jest lokalnie na komputerze użytkownika i nie trwa długo, po chwili wyświetlane jest powiadomienie, a odczytany tekst trafia do systemowego schowka, skąd można go wkleić do pola bazy danych, czy też do notatnika.

textshot w akcji

Powyżej ilustracja z przykładem rozpoznawania fragmentu pliku w formacje djvu, z rozpoznanym już tekstem w edytorze tekstowym.

Czy textshot będzie działać w systemie Windows? Prawdopodobnie tak, ale istnieją też inne, prostsze w instalacji programy, również wykorzystujące tesseract ocr, np. dpScreenOCR, czy też korzystający do rozpoznawania ocr z API systemu Windows TextExtractor, będący częścią serii PowerToys.


Duże modele językowe a grafy wiedzy (02.07.2023)

"The right way to think of the models that we create is a reasoning engine, not a fact database. They can also act as a fact database, but that's not really what's special about them – what we want them to do is something closer to the ability to reason, not to memorize."
Sam Altman, OpenAI Zob. wywiad w ABS News: "OpenAI CEO Sam Altman says...".

Pojawienie się sztucznej inteligencji (AI), z którą można rozmawiać w języku naturalnym wywołało naturalny odruch testowania jej wiedzy, skłonność do traktowania modeli GPT trochę jak inteligentnych komputerów z książek i filmów S&F. Dość szybko jednak pojawiło się rozczarowanie, bowiem duże modele językowe (LLM) nie wiedzą wszystkiego a jeżeli nie mają jakichś informacji bardzo chętnie je tworzą, czyli zmyślają (problem tzw. halucynacji). W końcu są przecież modelami generującymi treści i w tym są naprawdę dobre.

Wiedza i fakty są natomiast domeną encyklopedii (np. Wikipedii), a w szczególności baz (grafów) wiedzy (knowledge graph - KG), takich jak wikidata.org. Można w ciągu ostatnich kilku miesięcy intensywnego rowoju AI zauważyć kilka trendów próbujących łączyć te dwa światy: LLM i grafy wiedzy. Dość oczywistym pomysłem było zaprzęgnięcie modeli GPT do generowania zapytań w języku SPARQL - języku zapytań wykorzystywanym w m.in. Wikidata Query Service (WQS), który - szczególnie dla humanistów - nie jest technologią prostą i łatwą w użyciu. I skorzystanie ze zdolności modelu językowego do przełożenia pomysłów w języku naturalnym na zapytanie w SPARQL jest dziś możliwe, model GPT-4 generuje je całkiem poprawnie. Poproszony na przykład o przygotowanie zapytania zwracającego listę królów Polski, z ograniczeniem do tych, którzy zmarli między rokiem 1300 a 1650, przygotowuje działający kod SPARQL, który można wkleić i uruchomić w WQS:

SELECT ?król ?królLabel ?data_śmierci
WHERE
{
  ?król wdt:P39 wd:Q3273712.
  ?król wdt:P570 ?data_śmierci.
  FILTER(YEAR(?data_śmierci) >= 1300 && YEAR(?data_śmierci) <= 1650).
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],pl". }
}
ORDER BY ?data_śmierci

Gotowe do uruchomienia zapytanie: link

Integracja LLM jako silnika generującego kod SPARQL na podstawie zwykłych pytań użytkowników jest więc możliwa i jest przedmiotem badań firm i instytucji zajmujących się bazami wiedzy. Ciekawy artykuł na ten temat można przeczytać między innymi na stronie firmy wisecube.ai "SPARQL queries, GPTs and Large Language Models – where are we currently?" ( Link). Jednym z wyzwań jest zaznajomienie modelu ze strukturą danych grafu wiedzy, np. właściwościami i podstawowymi elementami w wikidata.org (te GPT częściowo zna, ale nie zna struktury np. niezależnych instancji wikibase). Innym - weryfikacja poprawności wygenerowanego zapytania, które może zawierać nie tylko łatwe do wychwycenia błędy formalne, skutkujące błędem wykonania (niełatwe z kolei do poprawienia przez osobę słabo znającą SPARQL), ale także zapytania formalnie poprawne lecz zwracające nie całkiem poprawne i oczekiwane wyniki. Można jednak spodziewać się, że takie mechanizmy będą w niedługim czasie dostępne i popularne, uzupełniając możliwości oferowane przez wizualne kreatory zapytań w rodzaju Sparnatural czy Wisecube Visual Query Builder.

Na ostatniej konferencji "Knowledge Graph Conference 2023" Denny Vrandečić (wikidata.org) przedstawił wykład o tytule "The Future of Knowledge Graphs in a World of Large Language Models", którego omówienie wrzucił też na Youtube, warto posłuchać jak świat LLM i możliwości efektywnego wykorzystania modeli językowych wyglądają z punktu widzenia twórców największej publicznej bazy wiedzy.

Jednym z pomysłów testowanych przez specjalistów od KG są próby douczania (fine-tuning) modeli językowych na podstawie faktów zawartych w grafach wiedzy. Podejście takie może być w pewnym stopniu skuteczne Można o nim poczytać np. w artykule: "Large Language Model = Knowledge Graph Store? Yes, by Fine-Tuning LLM With KG" ( Link). , jednak na dłuższą metę wydaje się niepraktyczne. Pierwszym problemem jest koszt procesu douczania a później koszt korzystania z douczonego modelu. Jeżeli mowa o skorzystaniu z modeli firmy OpenAI dochodzi do tego jakość modelu bazowego, OpenAI udostępnia do douczania jedynie starsze ze swoich modeli, czyli w najlepszym przypadku gpt-3 o wyraźnie gorszych możliwościach niż gpt-4, natomiast cena korzystania z douczonego już modelu będzie już wyraźnie wyższa niż w przypadku standardowego (i lepszego) gpt-4. Innym problemem jest samo douczanie, dane w grafach wiedzy zmieniają się, są dodawane, poprawiane, jak przeprowadzać  ciągłe douczanie modelu? Czy wielokrotne powtarzany fine-tuning nie spowoduje 'zapominania' informacji nauczonych w poprzednich sesjach douczania? A może douczać model bazowy cyklicznie od zera, na podstawie aktualizowanej całej bazy wiedzy? Obecnie trudno powiedzieć czy to byłoby wykonalne i skuteczne, na pewno byłoby kosztowne.

Innym trendem są próby udostępnienia wiedzy zawartej w grafach wiedzy dużemu modelowi językowemu tak, by generując odpowiedź na zapytanie użytkownika mógł skorzystać z faktów zawartych w grafie wiedzy a powstały wynik był dużo lepszej jakości, niż w przypadku korzystania tylko z wewnętrznej wiedzy modelu. Pomysł jest w pewnym stopniu zbliżony do stosowanych już powszechnie baz wektorowych zawierających osadzenia (embeddings) z korpusów tekstów/dokumentów, gdzie model językowy może otrzymać wyfiltrowane dane z bazy wektorowej jako element kontekstu zapytania i na tej podstawie udzielić odpowiedzi w języku naturalnym, nawet jeżeli tekst będący podstawą odpowiedzi nie był elementem korpusu uczącego w czasie trenowania modelu. Korzystają z takiego mechanizmu na przykład firmy, które mogą użyć swoich wewnętrznych dokumentów i tekstów niedostępnych publicznie. Model LLM obsługujący firmowy chat może w ten sposób stać się np. asystentem użytkownka skomplikowanego systemu informatycznego i mając dostęp do jego dokumentacji udzielać konkretnej odpowiedzi na zadawane przez użytkowników pytania. Można też w ten sam sposób stworzć asystenta udzielającego porad na temat przepisów prawnych, podpowiadającego informacje z raportów badań naukowych itp. Model nie musi znać tych wszystkich informacji, wykorzystywane są jedynie jego zdolności językowe i pewne (ograniczone na razie) umiejętności wnioskowania.

Przykład takiego rozwiązania jest opisywany na blogu firmy Neo4j - twórców grafowej bazy danych o tej samej nazwie (Link). Artykuł omawia tworzenie chatbota, który jest w stanie skorzystać z danych zawartych w bazie neo4j. Pytanie użytkownka jest tłumaczone przez gpt na instrukcje języka Cypher służące do komunikacji z neo4j, następnie mechanizm chatbota wykorzystuje wygenerowane instrukcje i pobiera informacje z bazy neoj4, wyniki przesyłane są ponownie do gpt, by ten utworzył na ich podstawie odpowiedź  w języku naturalnym, dopiero ta jest prezentowana użytkownikowi.

Ciekawy artykuł tego samego autora (Tomaz Bratanic) - "Knowledge Graphs & LLMs: Fine-Tuning Vs. Retrieval-Augmented Generation" (Link) omawia oba podejścia do rozszerzania wiedzy modelu - fine-tuning i rozszerzanie z użyciem zewnętrznych informacji (retrieval-augmented), zalety i wady obu rozwiązań, oraz niektóre narzędzia, które są wykorzystywane do pobierania danych z zewnętrznych źródeł i przekazywania ich do kontekstu zapytania dla modelu (LangChain, LlamaIndex).

Warto zauważyć, że korzystanie z zewnętrznego źródła danych podczas pracy z modelem GPT nie musi ograniczać się do jednego źródła, jednego grafu wiedzy, można wyobrazić sobie korzystanie równolegle z wielu baz wiedzy i zindekswanych korpusów tekstów, krytyczną rolę pełnią tu mechanizmy wyszukiwania w tekstach i grafach, od ich jakości zależy jakość odpowiedzi. Ograniczeniem jest oczywiście wielkość kontekstu przetwarzanego przez model, można jednak przyjąć, patrząc na prowadzone w tym kierunku prace, że wielkość kontekstu będzie się w nowych modelach systematycznie zwiększać.

Opublikowane niedawno nowe wersje modeli GPT obsługują nową możliwość , którą również da się wykorzystać do połączenia modelu z informacjami np. z grafów wiedzy Function calling and other API updates. . Tzw. function calling pozwala zdefiniować funkcje przekazywane w zapytaniu do modelu, z których ten może skorzystać jeżeli taka opcja zostanie uznana za korzystną w wyniku analizy zapytania. Model zwraca wówczas wynik z nazwą funkcji i sugerowanymi na podstawie zapytania parametrami. Na przykład nazwiskiem postaci historycznej której dotyczy zapytanie. System korzystający z GPT może wówczas uruchomić daną funkcję pobierając dane np. z wikidata.org dotyczące tej postaci i przekazać je w kolejnej iteracji zapytania do modelu, który na ich podstawie sformułuje odpowiedź w języku naturalnym. To kolejna funkcjonalność rozszerzająca możliwości modeli GPT.

Patrząc z zewnątrz, spoza świata specjalistów od wielu lat zajmujących się grafami wiedzy zob. świeży i ciekawy przekrojowy artykuł na temat współpracy LLM i KG "Unifying Large Language Models and Knowledge Graphs: A Roadmap". , można jeszcze zadać sobie jedno (naiwne) pytanie. Swiat KG i LLM może oczywiście współistnieć i współpracować. Ale czy wobec gwałtownego rozwoju modeli językowych, dostępności szybkich baz wektorowych pracochłonne tworzenie grafów wiedzy ma sens? Czy model przetwarzający teksty i wyszukujący w nich potrzebną wiedzę, a następnie udzielający odpowiedzi w języku naturalnym nie jest bardziej oczekiwanym przez użytkowników narzędziem, niż skomplikowane grafy wiedzy z ich zawiłymi językami zapytań? Nawet jeżeli ten sam model mógłby skorzystać  z danych zawartych w grafie, to jeżeli mechanizmy korzystające z samych korpusów tekstów będą szybkie i skuteczne, czy praca włożona w tworzenie ustrukturyzowanej wiedzy zwróci się w postaci np. lepszych wyników?

Pytanie jest oczywiście przekorne. A patrząc jeszcze z innej strony, czy duże modele językowe, potrafiące wydobywać ustrukturyzowane dane z nieustrukturyzowanych tekstów mogłyby obniżyć pracochłonność tworzenia grafów wiedzy np. budując dane dla nich automatycznie? Jednym z narzędzi, które to umożliwiają jest komponent GraphIndexCreator z biblioteki LangChain a prosty przykład testu na fragmencie biogramu postaci PSB można zobaczyć pod linkiem: Automatyczne tworzenie grafów wiedzy