Как считать CER и WER для русского OCR: регистр, пробелы и цена ошибки
OCR распознаёт счёт. На изображении напечатано «СЧЁТ № 17», а система возвращает «счёт № 71». Человек сразу видит, что номер перепутан. Автоматическая метрика замечает также регистр и лишний пробел. Если команда смотрит только на общий процент ошибок, она может потратить время на оформление и пропустить опасную ошибку в номере документа.
Для проверки OCR сначала соберите пары «ручная эталонная строка — текст системы» на документах, которые ожидаются в работе. Привяжите пару к конкретной странице, блоку или полю: метрика по целой странице скрывает ошибку в сумме или идентификаторе. Затем определите правила сравнения до просмотра результатов. В одном продукте регистр и пробелы несущественны, в другом точная верстка нужна для дальнейшего разбора таблицы.
Символы и слова отвечают на разные вопросы
CER делит число вставок, удалений и замен символов на длину эталона в символах. WER делает то же на уровне слов. Ошибочное двузначное число «71» вместо «17» может дать две символьные замены и только одно ошибочное слово. Поэтому низкий CER сам по себе не означает, что ключевые поля документа верны.
Ниже код считает расстояние Левенштейна для последовательности символов и для списка слов. Второй прогон сворачивает подряд идущие пробелы и приводит регистр. Букву «ё» он сохраняет: для некоторых реквизитов и имён её замена может иметь значение, а для другого проекта допустимо явно добавить единое правило для «е/ё».
import re
def distance(a, b):
row = list(range(len(b) + 1))
for i, left in enumerate(a, 1):
new = [i]
for j, right in enumerate(b, 1):
new.append(min(new[-1] + 1, row[j] + 1,
row[j - 1] + (left != right)))
row = new
return row[-1]
def normalize(text):
return re.sub(r"\s+", " ", text.casefold()).strip()
reference = "СЧЁТ № 17"
prediction = "счёт № 71"
for label, ref, pred in [
("как есть", reference, prediction),
("регистр и пробелы", normalize(reference), normalize(prediction)),
]:
cer = distance(ref, pred) / len(ref)
wer = distance(ref.split(), pred.split()) / len(ref.split())
print(label, "CER", round(cer, 3), "WER", round(wer, 3))После нормализации эталон выглядит как счёт № 17, ответ — счёт № 71. Здесь WER составляет 1/3: неверно одно из трёх слов. CER составляет 2/9: переставленные цифры требуют двух символьных замен при девяти символах эталона, включая пробелы. Первый прогон показывает, сколько добавляют различия оформления. Нормализация полезна только тогда, когда эти различия действительно не влияют на следующий шаг обработки.
Считайте так, как будет работать продукт
Если результат OCR поступает в поиск, регистр и повторный пробел часто можно нормализовать и в эталоне, и в предсказании. Если из чека извлекают сумму, ошибку цифры нельзя растворять в длинном тексте. Считайте общие CER/WER для отслеживания качества распознавания, а отдельно — точное совпадение критичных полей после допустимой для них нормализации. Для номера документа сохраните символы и порядок цифр; для имени согласуйте обработку пробелов и «ё» с системой, которая будет сравнивать клиентов.
На наборе документов агрегируйте число правок и длину эталонов, затем делите суммы. Простое среднее CER по страницам даст короткой квитанции такой же вес, как длинному акту. Иногда это нужно по бизнес-правилу, но тогда назовите метрику средним по документам. Для пустого эталона не делите на ноль: отдельно посчитайте случаи, когда OCR вернул текст там, где его не должно быть. Показывайте также распределение по типам документов и полям: одна хорошая массовая форма может скрыть провал на редких актах. При множестве вставок CER или WER могут быть больше 1; искусственно обрезать результат до 100% не следует.
После оценки качества чтения текста проверьте, насколько ошибки мешают следующей операции. В разборе ошибок OCR в поиске по документам показано, почему испорченные токены влияют на поиск даже при в целом читаемой странице. Для документов с таблицами дополнительно проверьте порядок блоков и привязку суммы к строке: CER по плоскому тексту не видит перепутанные колонки.
Продолжение для документов и сервиса
В курсе «Computer Vision Engineer: от детекции и Doc-AI до продакшна» вы работаете с разметкой документов, OCR/Doc-AI, извлечением полей в JSON и доведением обработки до сервиса с метриками качества и задержки. Там проверка распознанного текста становится частью полного пути от скана до записи в базу. Откройте программу курса.
Продолжить на практике
- Computer Vision Engineer: от детекции и Doc-AI до продакшна ↗
Практический курс по Computer Vision. Соберёте продакшн-сервис: датасет → обучение (YOLO/RT-DETR, SAM), трекинг, OCR/Doc-AI, веб-приложение (UI+API) и мониторинг. Экспорт в ONNX/TensorRT/OpenVINO, батчинг/квантование под CPU/GPU. Плюс профессиональные блоки: mAP/IoU/Dice и калибровка доверия, QA разметки и аугментации, p95/стоимость, дрейф данных и алерты, guardrails (NMS/правила), A/B-тесты, Triton/gRPC/FastAPI.
