В первой статье серии я писал, что у крымскотатарского не было ни одного датасета, пригодного для серьёзной работы, и что начинал я с существующего речевого набора, который пришлось чистить. Во второй распознавалка научилась слышать нашу речь, в третьей синтезированный голос прочитал целый роман. Отсюда вопрос, который мне задавали чаще всего: если данных нет, на чём всё это училось?
Эта статья про данные. Оговорка та же, что и раньше, только строже: я не называю источники, архивы, издания, каналы, людей и организации, которые нам что-то передали, и не рассказываю о договорённостях с ними. Нет здесь и названий моделей, порогов фильтров и внутренних скриптов. Объёмы даю порядками величин. Зато будут метрики, методика проверки и грабли, на которые я наступил, и все цифры взяты из отчётов экспериментов, а не по памяти.
Что было на руках
Если перечислить честно, получается не так мало. Напечатанные книги и периодика разных лет: проза, стихи, учебники, журналы, газеты. Записи эфиров: новости, передачи, студийные разговоры, интервью. Аудиокниги с профессиональными дикторами. Словари. Мои собственные записи. И то, что приносят учителя: диалоги, правки, записи голоса.
Датасетом по отдельности не было почти ничего. Книга остаётся PDF на полке. Эфир состоит из часов звука без единой строки текста. У аудиокниги звук и текст живут отдельно, и текст ещё надо найти, убедиться, что это то же издание, и выровнять со звуком. А у части аудиокниг цифрового текста нет вовсе. Задача сводилась к двум продуктам: пары «звук — текст» для распознавания и синтеза и чистый текст для языковой модели. Каждый тип материала принёс свой класс ошибок, и почти все они были не в моделях, а в данных.
Отправной точкой был тот самый исправленный речевой набор из первой статьи. Первая модель, обученная на нём, показала, что игра стоит свеч, и дальше началась добыча.
Текстовые слои: вопрос был поставлен немного неправильно
Исходный план выглядел очевидным. Большая часть старых крымскотатарских книг существует только в виде сканов, значит, их надо гнать через OCR. На нашем языке распознавание ошибается, особенно на буквах, которых нет в русском, и работа эта долгая и дорогая.
Прежде чем что-то запускать, я посчитал, что на самом деле лежит в архиве. Доли страниц по категориям (после дедупликации по файлам):
|
категория |
доля страниц |
|---|---|
|
крымскотатарский, кириллица, с текстовым слоем |
28.2 % |
|
крымскотатарский, латиница, с текстовым слоем |
3.9 % |
|
крымскотатарские сканы без слоя (оценка) |
8.5 % |
|
прочие сканы без слоя (оценка) |
11.8 % |
|
русские книги |
32.2 % |
|
турецкие книги |
13.9 % |
|
латиница 1928–1938 годов |
1.6 % |
|
арабская графика |
< 0.1 % |
Если оставить только крымскотатарские страницы, около четырёх пятых из них (79 %) уже несли текстовый слой: под картинкой страницы лежит настоящий текст, который достаётся без всякого распознавания. OCR нужен только для оставшейся пятой части. Дорогая ветка оказалась меньшей половиной добычи.
Три поломки, и ни одна не наша
«Текст есть» не значит «текст хороший». Первый же проход выявил три класса дефектов. Важно, что ни один из них не был ошибкой нашего распознавания: слой когда-то сделала чужая программа, часто старый OCR, и текст испортился ещё тогда или при переносе из файла в файл.
Мягкий знак вместо твёрдого. къаплангьан вместо къаплангъан, догьрумы вместо догърумы. Это фирменная порча нашего языка движком, натренированным на русском. Сочетаний кь и гь в крымскотатарской кириллице нет вообще, поэтому замена механическая и обратимая. Но прежде чем применять её к архиву, я прогнал её по заведомо здоровому тексту как отрицательный контроль: починка обязана не изменить там ни одного символа. Метрика страниц до и после совпала до четвёртого знака, изменений ноль. После этого починка ушла на весь архив и исправила десятки тысяч страниц. Нь я не трогал: оно законно встречается в русских заимствованиях, и механическая замена здесь испортила бы правильный текст.
Не та кодировка. Латинские страницы выглядели как tatarlýq, þöyle, qorquya tüþüp. Текст под ними был верный, просто байты турецкой кодировки прочитали как западноевропейскую, и ı превратилась в ý, ş в þ, ğ в ð. Тоже полностью обратимо: tatarlıq, şöyle, qorquya tüşüp.
Дубли. Одни и те же произведения лежали в разных изданиях, сборниках и под разными именами файлов. Во второй статье была та же ловушка со звуком: четыре аудиокниги, которые хранились у меня дважды под несвязанными именами. С текстом повторилось то же самое. По именам файлов копии почти не ловились. По содержимому, когда каждая новая страница сравнивается с уже принятыми по шинглам из восьми слов, нашлось 7.0 % повторов. Доля отброшенных страниц росла по ходу прогона, как и должна: поздние книги встречали уже заполненный индекс, а первые сравнивать было почти не с чем. Без этого шага модель видела бы их дважды, а при оценке ещё и узнавала бы тексты, которые должна была видеть впервые.
Решение по странице, а не по книге
Единицей решения стала страница. В одном томе кириллическая часть была чистой, а латинская оказалась старым неудачным OCR, слой которого был шумом. Оценка «по книге» заставила бы либо выбросить хорошие страницы, либо принять плохие.
Как оценить страницу, которую никто не вычитывал? Здесь пригодился наш словарь, с которого начинался весь проект. Для каждой страницы считается доля токенов, которые начинаются со словарного слова. Именно префикс, а не точное совпадение: язык агглютинативный, к корню клеится окончание за окончанием, и точное совпадение со словарём не отличало хорошую книгу (3 % попаданий) от сломанной (2 %). С префиксным правилом это уже нормальный прибор. Рядом считаются доля мусорных символов и доля кь/гь/нь среди всех къ/гъ/нъ/кь/гь/нь (только на страницах, где таких диграфов достаточно, иначе отношение превращается в шум). Эти сигналы в одно число не усредняются.
Пороги я не выбирал, а калибровал на четырёх популяциях: заведомо чистый цифровой текст, заведомо хороший OCR с измеренным CER около 0.3 %, иллюстрированный словарь (законно разреженный текст) и заведомо испорченная книга, где латиницу читала кириллическая модель. Плюс отрицательные контроли. Шесть случайных русских книг: отклонено 100 % страниц. Шесть турецких: отклонено 74 % страниц, но две книги из шести прошли. Турецкий протекает через словарь родственного языка, и это честный предел метода. К этой утечке я ещё вернусь.
Итог шага: текста, пригодного для обучения, стало примерно в десять раз больше, чем в ядре корпуса до него, и большая часть прироста не потребовала распознавания вовсе. Самой дорогой частью работы оказался не OCR, а проверка того, можно ли верить тексту, который уже есть.
Текст, который притворялся нашим
Самая коварная находка была про язык, а не про символы.
Однажды наша языковая модель ответила мне: «Ayt, men dinlemeye hazırım». По-крымскотатарски надо «Ayt, men diñlemege azırım». Корни те же, форма турецкая. Жалоба «отвечает всё больше по-турецки» превратилась в замер: на одном и том же наборе из 524 проверочных запросов доля латинских токенов с турецкой формой у новой версии была 2.02 % против 0.27 % у предыдущей, в 7.5 раза больше. Прибор при этом откалиброван с обеих сторон: на заведомо чистой крымскотатарской прозе он даёт 0.03 %, на настоящей турецкой 11.75 %. На самом большом наборе свободных переводов почти каждое десятое отглагольное имя в дательном падеже выходило с турецким -meye вместо нашего -mege.
Причина нашлась в данных, и нашёл я её тем же прибором, направленным на корпус. В срезе корпуса, на котором училась эта версия, доля турецких форм составляла 0.41 %, а в следующем, уже собранном срезе выросла до 0.93 %, в 2.3 раза. Из него ничего не удалялось, просто добавлялись новые тексты. И порча была сконцентрирована: на три источника приходилось 46 % всех помеченных токенов, на четырнадцать 76 %. Широкие веб-обходы, на которые я грешил первым делом, оказались как раз самыми чистыми из крупных источников.
Этими источниками оказалась периодика, которая выходит за пределами Крыма. В ней есть настоящие крымскотатарские страницы и есть целые страницы на турецком, иногда в одном номере, а крымскотатарский текст там часто записан на турецкий манер. Для человека, не знающего обоих языков, это похоже. Для программы тоже.
Урок отсюда простой: прибор, которым меряешь ответы модели, надо сразу прогонять и по обучающим данным с разбивкой по источникам. Если проблема сидит в нескольких источниках, это видно за один проход.
Почему language ID здесь слеп
Обычный фильтр языка отвечает на вопрос «это крымскотатарский или нет?» и смотрит на служебные слова, окончания и частоты символов. Для турецкого ответ почти всегда «скорее да»: слишком много общих корней и служебных слов. Мой фильтр по абзацам, прогнанный по всему корпусу, нашёл больше десяти тысяч кусков, которые стоило убрать: русский, украинский, английский. Признаки турецкого были только у 40 из них. Турецкий он не видел в принципе, и дело не в настройке: задача «наш язык против всех» не различает языки, у которых пересекается большая часть словаря.
Поэтому детекторы пришлось строить от противного: искать формы, которых в крымскотатарском не бывает.
|
турецкая форма |
у нас |
|---|---|
|
настоящее время на |
такой формы нет |
|
|
|
|
|
|
|
дательный отглагольного имени |
|
Каждый детектор проверялся в обе стороны: на чистом крымскотатарском тексте он не должен срабатывать, на настоящем турецком обязан.
Отдельный маркер при этом не вердикт. Окончание -yor нашлось в нескольких сотнях строк корпуса, и ни одна из них при разборе не оказалась турецкой строкой: это были смешанные строки, строки с испорченным текстом и обычный крымскотатарский текст. Решение принимается по строке целиком, а спорные строки уходят на ручной просмотр, а не в корзину.
Позже появился ещё один, для примесей других тюркских языков, и он нашёл в корпусе несколько десятков кусков, целиком написанных на казахском, татарском или узбекском. Их не видел ни языковой фильтр, ни турецкий детектор.
Несколько тысяч фрагментов ушли в карантин. Не удалены, а именно отложены: каждый сохранён как был, с пометкой происхождения и сработавшего правила, чтобы любое решение можно было пересмотреть. Из корпуса на этом шаге не удалено ничего.
Почему я не стал исправлять автоматически
Соблазн был: не выбрасывать турецкое написание, а нормализовать его, k → q, n → ñ и так далее. Правило выглядело осторожным: замена разрешена, только если исходной формы в словаре нет, а получившаяся есть. Я собрал несколько сотен таких замен, применил их к черновому срезу, посмотрел дифф и откатил.
Проблема в том, что такая проверка спрашивает, является ли результат крымскотатарским словом, но не спрашивает, тем ли словом, которое имелось в виду. Правило n → ñ производило не неправильные формы, а неправильные значения. balaların («детей», родительный падеж) превращалось в balalarıñ, а это уже «твои дети»; правильно было бы balalarnıñ. atın становилось atıñ, «твоя лошадь», вместо atnıñ, «лошади». А olgan морфологический анализатор после замены разобрал как личное имя Ольга с притяжательным окончанием. Турецкий родительный падеж -ın после согласной у нас -nıñ, а не притяжательное -ıñ, и словарная проверка эту разницу не видит. Заодно нашлась мелочь: шаг, сохраняющий регистр, ломал слова, набранные целиком заглавными.
Каждая такая правка давала настоящее крымскотатарское слово с другим значением, и ни словарь, ни детекторы её бы не поймали. Нормализатор, который производит правдоподобные ошибки, хуже нормализатора, который не делает ничего. Замены остались в отдельном файле как предложение, а не как изменение корпуса.
Диалекты остаются
Обратная сторона. В наших словарях есть слова с пометкой «диалектное», например южнобережное ben вместо литературного men. Турецкие детекторы к ним, естественно, придираются. Я проверил весь список и решил: это разные наречия нашего языка, и из корпуса они не вычищаются, даже если часть из них совпадает с турецким. Разница учтена на стороне оценки: диалектные формы в корпусе остаются, а в ответах модели считаются отдельной категорией. От модели я жду литературного языка, но учиться она может на всём, чем язык живёт.
Звук, у которого не было текста
Аудиокнига без книги
Была аудиокнига на несколько часов: хороший диктор, чистая запись. Напечатанного текста этого издания в цифре я так и не нашёл. Значит, forced alignment по известному тексту, с которого начинался проект (первая статья), здесь неприменим.
Схема получилась такая: запись расшифровывает наша распознавалка, затем тот же звук независимо расшифровывает вторая модель совсем другой архитектуры, обученная отдельно. В корпус идёт только сегмент, где две расшифровки совпали почти полностью. Модели, которые ошибаются по-разному, редко ошибаются одинаково. Когда основная распознавалка стала лучше, а сегментация точнее, из той же книги удалось взять в 2.6 раза больше пригодного звука, а сегменты, где старая модель уходила в петлю и повторяла одну фразу по полсотни раз, исчезли полностью.
Ограничение я держу в голове: согласие двух моделей не доказательство. Две неправильные модели могут согласиться, а сверить с книгой нельзя, потому что книги нет. Такие куски можно только слушать, поэтому спорные фрагменты мы и начали проверять вручную.
Эфиры: фильтр по уверенности как источник смещения
Дальше были записи эфиров, больше тысячи часов. Принцип тот же: машина расшифровывает, в обучение идёт только то, в чём она уверена и с чем согласна вторая модель. Строгий фильтр оставил примерно четверть.
Потом я посмотрел, что именно прошло. Доли часов речи по типу содержимого:
|
|
новости |
разговоры, передачи, интервью |
прочее |
|---|---|---|---|
|
дошло до фильтра |
65.4 % |
25.9 % |
8.7 % |
|
прошло строгий фильтр |
83.9 % |
10.2 % |
5.9 % |
|
доля класса, которая прошла |
35.8 % |
10.9 % |
18.9 % |
Новости проходили втрое охотнее разговоров. Показательный пример из отброшенного: живой разговорный скетч, машинная расшифровка которого выглядит правильной, и обе проверяющие модели с ней согласились. Отбросило его одно правило: средняя уверенность распознавалки оказалась чуть ниже порога. Модель была права, просто не была в себе уверена, а неуверенна она как раз там, где речь не похожа на новости. Дикторы читают по написанному, чётко, и распознавалка их и так хорошо слышит. Разговорная речь, где люди перебивают друг друга, сбиваются и говорят как в жизни, прошла лишь малой частью. Фильтр по уверенности систематически оставляет то, что модель уже умеет, и отбрасывает ровно то, чему ей нужно учиться. Для интервью картина ещё резче, но там основная причина в другом: большую часть интервью я убрал правилом ещё до фильтра. Устные истории отложены как экзамен, а интервью вперемешку с другими языками исключены.
В следующем раунде доля новостей была ограничена сверху, а разговорная речь шла с более мягким порогом.
Когда эталон делала машина
Оставалась методическая проблема. Проверочные тексты для живой речи раньше делала сама машина, старая версия распознавалки. Любая новая модель, которая с ней расходилась, автоматически получала штраф, даже если была права.
Я взял сегменты, где модели расходились, и прослушал их сам вслепую. Устроено это просто: на странице клип и две расшифровки в случайном порядке, под буквами A и B, без указания, где чья. Я слушаю, выбираю, какая ближе, и записываю свой текст того, что слышу. Ключ лежит отдельно и открывается только после того, как все вердикты сохранены. Мой текст потом становится эталоном для этих клипов вместо машинного. Ушло на это много часов. Выяснилось, что машинные эталоны ошибались примерно в 15 % слов, а новая модель на самом деле была права заметно чаще старой. С тех пор там, где эталон машинный, я считаю его гипотезой, а не истиной.
Что сейчас работает
На нашем сервере работает распознавалка, обученная на живой речи, и партнёры ею активно пользуются. На 40 коротких живых записях с обычного микрофона, где эталоном служит мой текст, WER упал с 18.8 % до 12.1 %, примерно на треть. На длинных разговорах (80 фрагментов из трёх записей) старая и новая модели вровень, 30.5 % и 30.7 % ошибок в словах, и это честное состояние дел. Следующий раунд, где часов разговорной речи было уже в несколько раз больше, на автоматических наборах сравнялся с действующей моделью, а в моём слепом сравнении на длинной форме вышло 25 : 24 без значимого перевеса. «Добавить ещё часов» здесь не сработало, и это тоже результат: дальше упираемся не в объём, а в качество разметки разговорной речи.
Люди
Всё описанное держится на людях, и найти их оказалось одним из самых трудных этапов. Дело не в нежелании, а во времени: согласились многие, работают единицы, и это сильно замедляет работу. Мы размещали объявления в соцсетях, и откликались неравнодушные люди. Искать продолжаем.
Правило для голосов простое: голоса и записи, которые звучат в наших примерах и в синтезированных голосах, используются с согласия их владельцев. Если кто-то передумает, голос убираем, без споров.
Учителя крымскотатарского работают с нами через специальный портал. Пишут диалоги, на которых модель учится разговаривать. Проверяют строки корпуса и отмечают, где текст не крымскотатарский. Разбирают словарные пометки: где слово турецкое, а где наше. Правят машинные черновики. И записывают свой голос. Эти записи ни разу не попали в обучение, они стали экзаменом: запись учителя на обычный микрофон, а не студийный, ближе всего к тому, как с машиной будут говорить реальные люди. Учить на экзамене нельзя, поэтому мы их бережём: в манифестах такие записи помечены как предназначенные только для оценки, и в обучающую выборку они не попадают. Это та же логика, что и с дублями книг: экзамен, который модель уже видела, ничего не измеряет.
Есть партнёры, которые записывают устные истории: люди рассказывают о своей жизни на родном языке, часто с местным говором. Они передали нам запись интервью с субтитрами, которые сами выверили вручную. Это один из самых трудных наших экзаменов: разговорная речь, диалект, паузы, и текст, написанный человеком, а не машиной. На нём модель тоже не учится.
И мой голос. Им машина прочитала вторую книгу в нашей библиотеке, об этом была третья статья. А ещё мои уши: спорные куски, где автоматическая проверка не может решить, кто прав, я слушаю сам.
Синтетика: где помогла, а где нет
Когда данных мало, хочется произвести их самому. Инструментов было два: наш синтез речи и большие языковые модели.
Синтетическая речь в обучении ASR
Синтетическая запись приходит с идеальной транскрипцией: текст выбран до того, как машина его прочитала. Я добавил в обучение синтезированную речь нескольких голосов. Каждый синтезированный клип перед этим расшифровывался распознавалкой, и клипы, не совпавшие с задуманным текстом, отбрасывались по порогу, зафиксированному заранее. Отсеялось около 5 %.
Прогноз я записал до запуска: немного синтетики, может, поможет, а половина навредит. Вышло наоборот. Экзамен из двух аудиокниг, которых модель не слышала, по одному прогону на вариант:
|
вариант |
WER |
CER |
|---|---|---|
|
только живая речь |
17.0 % |
7.0 % |
|
20 % синтетики |
16.2 % |
6.5 % |
|
50 % синтетики |
15.7 % |
6.3 % |
Выигрыш сохранился на всех шести испорченных копиях экзамена: в шуме, в эхе, в телефонной полосе, при ускорении и замедлении речи. Но это общий выигрыш, а не особая устойчивость к шуму: многоголосый фон как был главным провалом, так и остался.
Вторая половина правды. Экзамен состоит из аудиокниг, то есть из чистого чтения в тихой комнате. На записях, которые ближе к жизни, модель с синтетикой выглядела хуже той, что училась только на живой речи. Окончательной эту проверку считать нельзя: её эталоны тоже делала старая модель (см. выше, почему это смещает сравнение), и каждый вариант обучался один раз. Но в работу модель с синтетикой не пошла.
Машинный текст для языковой модели
Правило для текста у меня такое: неважно, кто его написал, человек или машина. Важно, чтобы это был чистый, правильный крымскотатарский. Каждая порция проходит проверки по словарю, на турецкие формы, на корректную транслитерацию и выборочно глазами.
Я попросил несколько больших языковых моделей написать диалоги на крымскотатарском и прочитал 26 из них вслепую, не зная, где чья модель. Как есть не годился ни один. Лучшие можно было спасти правками, остальные были в основном турецким с примесью узбекского и казахского. Хуже другое: автоматические метрики эти модели почти не различали. Одну, которую я забраковал полностью, приборы оценили на уровне остальных, потому что детекторы тогда видели турецкий, но не видели казахский и узбекский. Детектор других тюркских языков из раздела выше я сделал как раз после этого случая. И даже он отделил забракованную модель лишь слабо: на всех её диалогах нашлось четыре токена, Sağat вместо нашего saat и Qalaysıñız? вместо Nasılsıñız?. Основная причина, по которой я её отверг, была в турецких словах, которые турецкий детектор пропускал, потому что их форма ничем не выдаёт язык. Прибор объяснил вердикт уха лишь на малую долю.
Вторая попытка была строже: длиннее, по подробному заданию, и все диалоги прошли каждую автоматическую проверку без единого замечания. Я прочитал вслепую шесть. Ни один не годился даже для правки: два я переписал сам, четыре были безнадёжны, «много непонятных слов и неверная форма». Автоматика сказала «чисто», ухо сказало «не наш язык».
Я тогда расстроился: решить проблему синтетикой не получилось, а учителей пока не хватает. Вывод одинаковый для звука и для текста: синтетика полезна как добавка под контролем, но главную задачу не решает. Нужны люди, которые пишут диалоги с красками языка, с его колоритом.
Что я вынес
Тексты нашлись там, где их не искали: в слоях под сканами, которые надо было не распознавать, а чинить и проверять. Звук нашёлся в эфирах и аудиокнигах, но текст к нему пришлось добывать двумя моделями, которые проверяют друг друга, и следить, чтобы фильтр не выбирал только лёгкое. Синтетика добавила немного и только там, где за ней следил человек.
Инженерных уроков для себя я записал несколько. Любую механическую починку сначала прогоняю на заведомо здоровом тексте, и она обязана ничего не изменить. Дубли ищу по содержимому, а не по именам. Языковой фильтр не различает родственные языки, для них нужны детекторы форм, которых в твоём языке не бывает. Фильтр по уверенности смещает данные к тому, что модель уже умеет, и состав прошедшего надо смотреть по классам. Машинный эталон остаётся гипотезой, пока его не послушал человек.
А самые важные решения во всей этой истории принимало ухо носителя. Оно отличило турецкий от диалекта, услышало, что проверочные тексты ошибаются в каждом шестом-седьмом слове, и сказало «не наш язык» диалогам, которые приборы признали чистыми. Ни один фильтр этого не сделал.
Аудиопримеры к этой статье — https://ai.ana-yurt.dev/ru/blog/2026-10-otkuda-dannye/. Версия статьи для ana-yurt.com, попроще и с меньшим количеством цифр: https://ana-yurt.com/otkuda-berutsya-dannye-dlya-yazyka-kotorogo-pochti-net-v-internete
Если вы носитель крымскотатарского и готовы помогать, напишите на ai@ay.mw или в Telegram: t.me/ana_yurt_dev. Нужно слушать короткие записи и говорить, правильно ли машина их расшифровала, читать страницы текста и отмечать, где слово турецкое, а где наше, диалектное, начитывать несколько минут текста своим голосом. Программировать не нужно; в этой статье самые важные решения приняло именно ухо носителя. Поддержать работу материально можно на ko-fi.com/anayurt.
ссылка на оригинал статьи https://habr.com/ru/articles/1100892/