Паща о̄лэн, Хабр! (Привет, Хабр!)
На связи снова Югорский НИИ информационных технологий (ЮНИИИТ). Продолжаем цикл статей о проекте «Корпус мансийского языка». В первой части мы рассказывали, как с нуля собрали 300 тысяч параллельных предложений и обучили нейросеть переводить с русского на мансийский и обратно. Сегодня поговорим о модели, которая умеет читать мансийский печатный текст. Это OCR, оптическое распознавание символов.
Сразу о главном. Мы дообучили открытый движок Tesseract 5, и доля ошибочных символов упала с 18,5% до 0,85%. Это примерно в 20 раз меньше ошибок. Модель лежит в открытом доступе на Hugging Face, ей уже можно пользоваться.
В статье расскажем:
-
почему готовые OCR-движки не справляются с мансийским текстом;
-
как собрать обучающую выборку, когда отсканированных книг почти нет;
-
как мы дообучали Tesseract и как проверяли качество;
-
какой точности удалось добиться и где взять модель.
Зачем мансийскому языку OCR
Большая часть мансийских текстов до сих пор существует только на бумаге. Это книги, учебники, сборники фольклора, подшивки газет. Чтобы эти тексты попали в корпус и стали обучающими данными для нейросетевого переводчика или языковой модели, их нужно превратить в цифровой текст. Перепечатывать вручную долго и дорого. Носителей языка мало, и их время лучше тратить на перевод и экспертизу.
OCR решает эту задачу. Сканируем страницу, получаем текст, который можно искать, редактировать и добавлять в датасеты. Это работает не только у нас. Исследователи показали, что OCR помогает улучшить машинный перевод для 60 малоресурсных языков.
Почему готовые движки не справляются
Мансийская письменность построена на кириллице, но со своими особенностями. Из-за них у стандартного OCR возникают две проблемы:
Проблема 1. Буквы, которых нет в русском алфавите
Это долгие гласные с макроном (чертой над буквой), например а̄, о̄, ӯ, э̄, ы̄. Есть и отдельная буква ӈ, которой обозначают звук «нг». Долгота гласной в мансийском важна, и потеря макрона может превратить одно слово в другое.
Мы попробовали стандартную русскую модель Tesseract. Буквы с макроном и ӈ она просто не знает. Черту над буквой модель теряет, а иногда превращает знакомую букву в мусор. На мансийском тексте русская модель ошибается примерно в 18 символах из 100. Для оцифровки корпуса это не годится.
Проблема 2. Одна буква, разные коды
Вторая проблема менее заметна глазу. Одну и ту же букву с макроном можно записать в Unicode разными способами. Мы уже сталкивались с этим при сборе корпуса для переводчика. Для человека буквы выглядят одинаково, а для модели это разные последовательности символов. Как мы с этим справились, расскажем в шаге 1 следующего раздела.
Где взять данные, если сканов почти нет
Современной нейросетевой OCR-модели нужны сотни тысяч примеров. Каждый пример состоит из картинки со строкой текста и правильного ответа. Готовой коллекции мансийских сканов такого размера не существует. Размечать сканы вручную пришлось бы годами.
Поэтому мы пошли другим путём и сгенерировали данные сами. Берём настоящий мансийский текст и рисуем его на картинке разными шрифтами. Правильный ответ при этом известен заранее, ведь мы сами написали эту строку. Для генерации нам пришлось немного покодить. Мы написали на Python скрипты, которые чистят тексты, рендерят картинки и готовят разметку. Разберём их работу по шагам.
Шаг 1. Собираем тексты и наводим порядок в Unicode
Исходным материалом стали тексты из печатных и электронных изданий на мансийском языке. Все их объединили в один набор и нормализовали по форме Unicode NFC.
Зачем это нужно, проще показать на примере. Букву ӯ можно хранить как один готовый символ. А можно как обычную «у» плюс отдельный комбинируемый макрон. Обычно на экране разницы не видно, а строки при сравнении не совпадут.
Звучит как придирка? Откройте консоль Python и проверьте сами.
import unicodedataa = "ӯ" # ӯ одним символомb = "ӯ" # у + комбинируемый макронprint(a, b) # ӯ ӯ выглядят почти одинаковоprint(len(a), len(b)) # 1 2 а длина разнаяprint(a == b) # Falseb = unicodedata.normalize("NFC", b) # эта строка и есть наше решениеprint(len(b), a == b) # 1 True
Кстати, в некоторых консолях макрон во втором варианте заметно съезжает. Это та же проблема рендеринга, из-за которой нам пришлось поправлять рамки символов в шаге 3. В наших скриптах такая нормализация выполняется для каждого текста перед рендерингом. После неё у каждой буквы остаётся ровно одно представление. Модель видит одинаковые коды для одинаковых букв и не учится лишнему.
Шаг 2. Рисуем строки разными шрифтами
Печатные издания набраны очень по-разному. Чтобы модель не привыкла к одному шрифту, мы взяли несколько десятков гарнитур. Среди них FreeSerif, DejaVu Sans, Arial, Calibri и Times New Roman. Каждую строку рендерили в нескольких размерах (12, 14, 24 и 26 pt) и начертаниях (обычное, полужирное, курсив). Так модель учится узнавать букву, а не конкретную картинку буквы.
Шаг 3. Размечаем каждый символ
Tesseract 5 может учиться и на целых строках, без разметки отдельных букв. Но мы дополнительно размечали каждый символ рамкой, то есть box-файлом с её координатами. Так мы проверяли, что буква попадает в разметку целиком, вместе с макроном, и черта над ней не теряется. Обычно координаты считаются автоматически по метрикам шрифта. Для букв с диакритикой такие расчёты часто ошибаются, потому что макрон выступает над строкой. К тому же каждый шрифт рисует его по-своему.
Мы исправили это попиксельными поправками. Для этого завели три словаря:
-
CHAR_OFFSETS. Смещения для отдельных символов.
-
CHAR_SIZE. Поправки в зависимости от кегля.
-
RATE. Коэффициенты для конкретной гарнитуры.
Значения подбирали экспериментально, глядя на результат. В итоге рамки легли точно на символы, включая буквы с макроном (рис. 1).
Рисунок 1. Рамки вокруг каждого символа после коррекции.Шаг 4. Режем текст на строки
Длинный текст нужно разбить на фрагменты, которые помещаются в ширину генерируемого изображения. Для этого в наших скриптах есть функция split_by_width. Она режет строку так, чтобы ни один символ не вылез за край картинки. Так текст на картинке и текст в разметке совпадают один к одному.
В итоге скрипты сгенерировали 1,3 млн пар файлов. Каждая пара состоит из картинки строки в формате .tif и текстового файла .gt.txt с правильным ответом.
Как мы дообучали Tesseract
Почему Tesseract
Tesseract это open-source движок OCR, который развивается уже много лет. Он бесплатный, работает локально, у него есть готовые модели для сотни языков и штатные инструменты для дообучения. Для малоресурсного языка это удобная стартовая точка. Не нужно обучать модель с нуля, можно доучить готовую.
Как он читает строку
Внутри Tesseract 5 работает нейросеть CRNN. Её свёрточная часть находит на картинке штрихи, изгибы и черты над буквами. Рекуррентная часть (LSTM) читает эти признаки слева направо, примерно как человек читает строку. Размечать вручную, где кончается каждая буква, не нужно. Это берёт на себя функция потерь CTC.
Трансферное обучение
В качестве основы мы взяли официальную русскую модель rus.traineddata из репозитория tessdata_best. Она уже хорошо знает кириллицу. Мансийский алфавит почти целиком совпадает с русским, поэтому модели нужно выучить в основном новые буквы с макроном и ӈ. Похоже на человека, который читает по-русски и узнаёт, что буква с чертой сверху это отдельная буква.
Для дообучения мы использовали tesstrain, официальный набор скриптов для обучения Tesseract. Ему достаточно передать стартовую модель и папку с парами «картинка + текст». Получив rus.traineddata как исходную точку, tesstrain сам делает три вещи.
-
Достаёт из русской модели LSTM-часть с уже обученными весами.
-
Просматривает обучающие данные и собирает полный список символов мансийского алфавита.
-
Создаёт новую модель с весами русской и расширяет выходной слой под объединённый алфавит. Так у модели появляются «места» для а̄, э̄, ӯ, ӈ и других новых букв.
Самым важным параметром оказалось число итераций. Если учить мало, модель не успевает освоить новые буквы. Если учить слишком долго, она переобучается на синтетике и хуже читает реальные тексты. Число итераций мы подбирали по качеству на валидационной выборке. Чтобы не переобучиться, использовали раннюю остановку. Обучение прерывалось, как только метрики на валидации переставали расти или начинали ухудшаться. На выходе получилась специализированная модель mns.traineddata.
Что в результате
Качество OCR обычно оценивают двумя стандартными метриками. CER (Character Error Rate) показывает, какая доля символов распознана с ошибкой. WER (Word Error Rate) показывает то же самое для слов. Чем ниже значение метрик, тем лучше. Чтобы оценить вклад дообучения, мы сравнили нашу модель с исходной rus.traineddata из tessdata_best.
Модель
CER
WER
rus.traineddata (базовая)
18,5%
42,1%
mns.traineddata (наша)
0,85%
1%
Наша модель ошибается меньше чем в одном символе из 100 и в одном слове из 100. Русская модель на том же тексте ошибалась в 18 символах и 42 словах из 100. Ошибок по символам стало примерно в 20 раз меньше.
Откуда такая разница, хорошо видно на одной строке.
Вариант
Текст
Исходная строка
Хӯл тэ̄нутыг ва̄рнэ ма̄гыс
rus.traineddata (базовая)
Хул тэнутыг варнэ магьгс
mns.traineddata (наша)
Хӯл тэ̄нутыг ва̄рнэ ма̄гыс
У базовой модели пропали все макроны, а буква «ы» превратилась в «ьг». Дообученная модель прочитала строку без единой ошибки. Главное, чему она научилась, это отличать а от а̄, у от ӯ и узнавать букву ӈ.
Такой точности уже достаточно, чтобы использовать модель для оцифровки печатных мансийских текстов. Человеку остаётся вычитать результат, а не набирать его заново.
Где найти модель
Модель открыта и доступна на Hugging Face, вот её страница URIIT/mns-tesseract. Чтобы подключить её к своему Tesseract 5, достаточно скопировать файл mns.traineddata в папку tessdata и указать язык mns при запуске. Попробовать распознавание в браузере можно на Этнопортале.
Учтите возможные ограничения. Модель уверенно читает чистый типографский текст кеглем от 12 до 26 pt. Хуже она справляется с очень мелким или крупным шрифтом, с латиницей и со старыми изданиями, где печать стёрлась.
Резюме
Для OCR малоресурсного языка не обязательно годами размечать сканы. Нам хватило трёх шагов.
-
Привести все буквы с макронами к единому виду в Unicode.
-
Сгенерировать синтетический датасет из настоящих мансийских текстов, нескольких десятков шрифтов и точной разметки каждого символа.
-
Дообучить готовую русскую модель Tesseract 5 вместо обучения с нуля.
В результате доля ошибочных символов снизилась с 18,5% до 0,85%, а ошибочных слов с 42,1% до 1%. Печатные мансийские тексты теперь можно быстро переводить в цифру. Они пополняют корпус, на котором обучаются нейросетевой переводчик, языковая модель и другие модели проекта.
Думаем, тот же рецепт может подойти и для других языков с диакритикой на кириллице, например, для хантыйского или ненецкого.
Планы на будущее
Следующий шаг для модели связан с настоящими архивными сканами. Старые издания со стёртой печатью и устаревшими шрифтами пока даются ей хуже всего. Мы хотим добавить такие сканы в обучение, чтобы модель увереннее справлялась и с ними.
В следующих статьях цикла расскажем о других моделях проекта. Впереди языковая модель, распознавание и синтез мансийской речи.
Подробное научное описание работы опубликовано в журнале «Вестник ЮУрГУ. Серия Математическое моделирование и программирование» (DOI 10.14529/mmp260206). Там есть обзор литературы и детали методики.
Полезные ссылки:
-
Часть 1. Нейронный переводчик
-
Этнопортал с моделями проекта
-
Документация по обучению Tesseract 5
Оставайтесь с нами. Нейросети помогают нам не только в работе с языком, и об этом мы тоже расскажем.
Источник: habr.com