Projekt

Jak porównałem 18 silników OCR na jednym korpusie

Metoda testu 18 silników OCR na korpusie 80 dokumentów: co mierzę, jak zbudowany jest zestaw i sześć błędów, które po cichu psuły wyniki. Plus gotowe stanowisko do powtórzenia pomiaru na własnych dokumentach.

Okładka wpisu: wydrukowane dokumenty i skany na biurku, w tle karta graficzna, napis "18 silników OCR, jeden korpus"
Na tej stronie
  1. Dlaczego nie wystarczyły gotowe benchmarki
  2. Co dokładnie mierzę i dlaczego akurat to
  3. Jak zbudowany jest korpus
  4. Na czym to chodzi
  5. Sześć błędów, które po cichu psuły mi wyniki
  6. Co dostaniesz, jeśli chcesz powtórzyć pomiar u siebie
  7. Kiedy wyniki

Przez ostatni tydzień przepuściłem osiemnaście silników OCR przez ten sam zestaw 80 dokumentów, ten sam sprzęt i ten sam pomiar. Ten wpis opisuje metodę i pułapki, na które trafiłem po drodze. Liczby z rankingu pokażę razem z materiałem wideo - tutaj zostaje to, co przyda się każdemu, kto chce zrobić taki test u siebie.

Dlaczego nie wystarczyły gotowe benchmarki

Bo mierzą coś innego, niż potrzebuję. Publiczne rankingi OCR liczą najczęściej dokładność znakową na anglojęzycznych zbiorach akademickich, a ja potrzebowałem odpowiedzi na pytanie z zupełnie innego świata: czy po przepuszczeniu polskiego pisma urzędowego przez ten silnik nadal znajdę w tekście numer sprawy.

Do tego dochodzi rzecz, której cudze wyniki nie powiedzą nigdy: ile to kosztuje na moim sprzęcie. Model, który wygrywa na klastrze z ośmioma kartami H100, może być bezużyteczny na pojedynczej karcie w szafie w piwnicy.

Co dokładnie mierzę i dlaczego akurat to

Trzy rzeczy naraz, bo żadna z nich osobno nie wystarcza do decyzji.

Recall kanarków to główna miara. Kanarek to krótki, unikalny ciąg wpisany w treść dokumentu - numer sprawy, kod produktu, nagłówek raportu. Jeśli silnik go zgubi, zgubił dokładnie to, po czym człowiek szuka dokumentu w archiwum. To miara użyteczności, nie ortografii, i dlatego stoi na pierwszym miejscu.

CER, czyli odsetek błędnych znaków wobec dokładnego wzorca, liczę tylko na dokumentach, dla których mam ground truth co do znaku. Niżej znaczy lepiej - odwrotnie niż przy recall, co jest najczęstszym źródłem pomyłek przy czytaniu takich tabel.

Czas na dokument podaję jako średnią i medianę osobno. To nie jest ozdoba statystyczna. Przy jednym z modeli mediana wyniosła niecałe 4 sekundy, a średnia przekroczyła minutę - bo dwa gęste raporty z całej osiemdziesiątki zjadły ponad połowę przebiegu. Kto planuje przepustowość ze średniej, przepłaci; kto planuje najgorszy przypadek z mediany, nie dowiezie.

Do tego trzy przekroje, bo profile silników się różnią: dokumenty polskie, dokumenty z tabelami, skany.

Jak zbudowany jest korpus

80 dokumentów, celowo niejednorodnych: natywne PDF-y, skany, formularze, tabele, arkusze i prezentacje, po polsku i po angielsku.

58 z nich wygenerowałem sam razem z dokładnym ground truth - dzięki temu CER liczy się wobec wzorca co do znaku, a nie wobec "mniej więcej takiego tekstu". Pozostałe 22 to materiały publiczne: prace z arXiv, publikacje GUS, teksty ustaw. Każdy dokument ma wpis w manifeście z formatem, językiem, informacją o tabelach i skanach oraz własną listę kanarków.

RodzajIleSkąd
generowane z dokładnym ground truth58własne, razem ze wzorcem tekstu
publiczne22arXiv, GUS, teksty ustaw

Podział ma znaczenie praktyczne: dokumenty generowane można rozdawać razem z zestawem testowym, publiczne dociąga się z adresów zapisanych w manifeście.

Na czym to chodzi

Jedna karta RTX 3090, jeden model naraz. Zrównoleglenie zafałszowałoby pomiar czasu, więc silniki idą sekwencyjnie, każdy dostaje kartę na wyłączność.

Klasyka chodzi lokalnie: pdfplumber, Tesseract 5, RapidOCR, PaddleOCR. Pipeline'y dokumentowe - Docling, MinerU, Marker - też. Modele wizyjno-językowe wchodzą przez vLLM w kontenerze: Surya 2, GLM-OCR, PaddleOCR-VL, LightOnOCR-2, DeepSeek-OCR-2, dots.mocr, Chandra OCR 2, olmOCR-2, MonkeyOCR-pro, a jako punkt odniesienia ogólny model Qwen3-VL, nietrenowany specjalnie pod OCR. GOT-OCR 2.0 wypadł poza ten schemat i chodzi lokalnie przez transformers, bo vLLM w wersji, której używam, nie ma jeszcze tej architektury w rejestrze.

Prompty biorę z kart modeli i repozytoriów autorów, nigdy z własnej głowy. Nie jest to formalność - wrócę do tego niżej.

Sześć błędów, które po cichu psuły mi wyniki

To jest część, dla której warto czytać ten wpis. Każdy z tych błędów wyglądał jak poprawny przebieg i każdy dałoby się przeoczyć.

① Kanarek, którego nie było w dokumencie. Dwa dokumenty miały w manifeście kanarek nieobecny ani w pliku, ani w ground truth. Efekt: każdy silnik dostawał tam zero, niezależnie od tego, jak dobrze przeczytał stronę. Po korekcie cała stawka podskoczyła o kilka punktów. Wniosek: kanarki trzeba weryfikować programowo przy dodawaniu dokumentu, nie wzrokowo.

② Sukces z pustym wyjściem. Adres serwera modelu bez końcówki /v1 przechodzi kontrolę zdrowia, ale właściwe zapytanie zwraca 404. Silnik oddawał wtedy pusty tekst ze statusem "ok" i wchodził do tabeli z zerowym wynikiem jako poprawny przebieg. To groźniejsze od awarii, bo awarię widać. Dziś pusty wynik ze wszystkich stron dokumentu jest twardym błędem.

③ Wznowienie gubiło pomiar czasu. Tryb wznawiania przepisywał gotowy wynik z dysku, ale zapisywał czas jako zero. Jeden z silników miał realny pomiar na zero dokumentów z trzydziestu siedmiu, a mimo to w tabeli widniała ładna, mała liczba. Dziś raport ma kolumnę mówiącą, na ilu dokumentach czas zmierzono naprawdę.

④ Zakres stron poza dokumentem. Sztywne "strony od 0 do 3" wywracało jeden z pipeline'ów na każdym pliku krótszym niż cztery strony i na wszystkich obrazach - łącznie na ponad połowie korpusu. Zakres trzeba liczyć z realnej liczby stron.

⑤ Limit kontekstu mniejszy niż żądanie. Model z kontekstem 8192 tokenów dostawał żądanie 8192 tokenów samego wyjścia i serwer odrzucał je błędem, zanim cokolwiek policzył. Konfiguracja serwera musi wynikać z konfiguracji modelu, nie z jednej wartości wpisanej dla wszystkich.

⑥ Prompt zmienia silnik nie do poznania. Ten sam model w trybie z opisem układu strony wpada w pętlę powtórzeń i wyczerpuje budżet tokenów, zanim dojdzie do końca tekstu. Po przełączeniu na prompt czystego OCR, wprost z karty modelu, wynik wzrósł o kilkanaście punktów. Ta sama waga, ten sam sprzęt, inny wiersz w konfiguracji.

Wspólny mianownik tych sześciu: żaden nie zgłosił się jako błąd. Wszystkie kończyły się przebiegiem, który wyglądał na udany. Dlatego w zestawie testowym siedzi dziś bramka, która przed pełnym przebiegiem puszcza jeden dokument i przerywa, jeśli wynik jest zerowy.

Co dostaniesz, jeśli chcesz powtórzyć pomiar u siebie

Całość jest spakowana jako gotowe stanowisko testowe. Nie jest to zrzut skryptów, tylko zestaw, który sam sprawdza środowisko, zanim pozwoli ruszyć.

  • korpus - 80 dokumentów, ground truth i manifest z opisem każdego pliku
  • rejestr silników - jeden plik z konfiguracją serwera dla każdego modelu:
limity kontekstu, flagi uruchomienia, licencja i pułapka charakterystyczna dla danego modelu
  • skrypty uruchomieniowe - osobno dla Windows i dla Linuksa, czytające tę samą
konfigurację, więc wyniki są porównywalne między systemami
  • preflight - sprawdza Pythona, biblioteki, komplet korpusu, kartę, Dockera
i wolny port, zanim zmarnujesz kilka godzin na przebieg, który i tak się wywróci

Najważniejsze jest to, co z tego wynika: ten sam pomiar da się powtórzyć na własnym zestawie dokumentów. Podmieniasz korpus i manifest, reszta zostaje bez zmian, a tabela na końcu jest liczona tym samym ground truth dla wszystkich silników. Jeśli pracujesz z fakturami, protokołami albo dokumentacją techniczną, Twój korpus powie Ci więcej niż mój.

Kiedy wyniki

Liczby, ranking i wnioski wdrożeniowe pokażę w materiale wideo. Tam też pokażę, który silnik wybrałbym do produkcji, a który tylko do weryfikacji trudnych stron - bo to nie jest ten sam wybór i różnica w koszcie jest większa, niż się spodziewałem.

Stan opisany w tym wpisie: 31 sierpnia 2026.

Wszystkie wpisy Strona główna

Następny krok

Wolisz, żeby ktoś to wdrożył za Ciebie?

Bezpłatna rozmowa, 30 minut. Sprawdzimy, gdzie u Ciebie ucieka czas i czy da się go odzyskać.