
Синтез речи на длинной дистанции: роман на 1 ч 58 мин против 14 проверочных фраз
В первой статье серии была таблица про то, как синтезированный голос прочитал целую книгу: роман Шамиля Алядина «Merdiven» («Лестница»), 16 глав, 15 444 слова, 1 ч 58 мин звучания. Во второй я обещал отдельно рассказать, что ломалось на длинной дистанции. Рассказываю.
Если коротко, голос держался ровно все два часа. Почти всё, что ломалось, сидело не в модели, а в обвязке вокруг неё: в нарезке текста на предложения, склейке коротких фраз, обрезке вдохов, извлечении текста из файла книги и разметке времени. А проверочный набор из 14 фраз, по которому я до этого сравнивал версии модели, ни одной из этих проблем не увидел, а в одном случае не смог отличить хорошую правку от вредной.
Оговорка, как и в прошлых статьях серии: названий моделей, источников данных, внутренних скриптов и параметров обучения и декодирования здесь не будет. Будут метрики, методика проверки и грабли.
Чем и на чём я мерил
Основной прибор — обратная вычитка. Синтезируем предложение, прогоняем звук через нашу распознавалку (ту самую, из второй статьи) и считаем CER гипотезы против текста, который ушёл на вход синтезу. Цифра на главу корпусная: сумма правок на сумму символов эталона, а не среднее по клипам. Клипы, на которых распознавалка ушла в петлю и наделала правок больше, чем слов в эталоне, харнесс помечает отдельно. Это поле появилось ещё в ASR-эксперименте, и здесь оно пригодилось, об этом ниже.
Слепые пятна у прибора известны заранее. Он не слышит ударения и вдохов, не умеет проверять числа, и он сам модель, у которой бывают свои сбои. Всё это пришлось закрывать ухом.
Проверка шла в трёх масштабах:
набор |
объём |
что он может показать |
|---|---|---|
проверочные фразы |
14 фраз, нарочно набитых къ, гъ, нъ, дж |
разницу между версиями модели на трудных звуках |
первая глава |
1 608 слов, 195 предложений, 12.3 мин |
связную прозу: диалоги, короткие реплики, вдохи, темп |
книга целиком |
16 глав, 15 444 слова, 118.4 мин |
редкие сбои, извлечение текста, сборку, устойчивость от главы к главе |
Перед главой нужна была проверка на утечку: если текст был в обучении, модель не читает, а вспоминает. Я сравнивал словные 6-граммы. Обе стороны перед сравнением сводятся к общему грубому латинскому скелету: учебные материалы у меня в кириллице, книга в латинице. Такая свёртка теряет различия только в сторону лишних совпадений, поэтому ноль у неё честный. Первая глава: 0 совпадений из 1 545 шестисловных цепочек против примерно 1.38 млн слов учебного корпуса. Позже ту же проверку прошла вся книга: 0 из 14 656.
Первый же замер на главе стал уроком. На проверочных фразах CER был около 14 %, на прозе главы меньше 2 %. Модель за ночь лучше не стала. Проверочный набор нарочно враждебный, а обычный текст нет, и на обычном тексте модель для распознавалки почти прозрачна. Цифру с проверочного набора я с тех пор не выдаю за качество реального чтения. Годится она только для сравнения версий между собой, и ниже будет случай, где она не справилась и с этим.
Общий вердикт по первой главе получился неожиданным. Голос держался: сходство голосовых эмбеддингов с первой минутой главы оставалось в пределах 0.96–0.98 все двенадцать минут, темп ровный. Ошибки нашлись не в самой модели, а в подготовке текста и звука вокруг неё. Эту часть я писал сам, и это была хорошая новость: такое чинится без переобучения.
Основа и голос, в двух абзацах
Подробно это было в первой статье, здесь только то, что нужно для дальнейшего. Готовые модели от соседних языков читают наш къ как обычное к. Поэтому основу для голоса я выбирал по одному признаку: она уже должна уметь произносить этот звук. Нашлась многоязычная модель, которая много слышала казахский, уйгурский и башкирский. Крымскотатарского в ней нет, и это обходится письмом: наши къ, гъ, нъ переписываются в башкирские ҡ, ғ, ң, которые модель знает, и дальше она читает наш текст как башкирский.
Голос берётся отдельно. Дообученная модель учится языку, а не тембру: тембр она берёт из короткого образца, нескольких секунд записи с точным текстом. «Merdiven» прочитан голосом Sevil, и каждое предложение книги озвучено по одному и тому же семисекундному образцу. Модель, тембр и обвязка вокруг них оказались вещами независимыми, и чинить их можно было по отдельности.
Первая глава: три починки, и ни одной в модели
Склейка коротких предложений
Самые короткие клипы в учебных записях длились 2.94 с. Отсюда логика, казавшаяся железной: реплику короче 43 кириллических букв лучше не давать модели отдельно, а приклеить к соседней. Проверять это допущение я не стал. Зря.
В первом прогоне из 147 фрагментов 38 содержали больше одного предложения. И на них модель начала выбрасывать целые предложения:
что просили прочитать |
что прочитано |
|---|---|
Men yañılğanım. O, oca degil eken. |
O, oca degil eken. |
– Yoq. Siz yañlışasıñız. Meni bir daa iç bir yerde köralmaycaqsıñız. |
Meni bir daa iç bir yerde köralmaycaqsıñız. |
«Я ошибся. Он, оказывается, не учитель» превратилось в «Он, оказывается, не учитель». Склеенные фрагменты занимали 25 % символов главы и давали 43 % ошибок.
Тогда я наконец проверил само допущение: прочитал главу без склейки и разложил ошибки по длине предложения.

Первая глава без склейки, длина в кириллических буквах, то есть в том виде, в каком текст видит модель. Серая зона — то, что раньше приклеивалось к соседям. Обрыва на 43 буквах нет, а улучшение идёт примерно до 70.
Короткие предложения действительно хуже: ошибок в них примерно в два с половиной раза больше. Но обрыва на 43 буквах, ради которого склейка и задумывалась, нет: корзины 0–24 и 25–42 одинаковы, а CER продолжает падать примерно до 70 букв. Граница склейки была проведена не там, где проходит настоящий порог. И главное, цены у двух зол разные: штраф за короткие реплики стоит около 2 процентных пунктов CER на 15 % текста, а склейка стоила 3.3 пункта на 25 % текста и вдобавок теряла целые предложения. Склейку я выключил.
Обрезка вдохов
Синтез иногда начинает фразу со вдоха, как живой диктор, и я написал обрезку. Как она резала первое слово, я уже рассказывал в первой статье: она искала первый звонкий кадр, а глухие согласные до него считала вдохом. Ещё пример из той же главы: «Çañ qaqıldı» превращалось в «Qaqıldı». В 111 предложениях из 147 срез приходился внутрь первого слова. Новая обрезка смотрит на громкость: согласный тихий, но намного громче паузы перед ним.
Здесь интереснее, как склейка и обрезка выглядят вместе. Я прогнал обе конфигурации текста со всеми тремя вариантами обрезки:
CER первой главы |
без обрезки |
старая обрезка |
новая обрезка |
|---|---|---|---|
со склейкой, 147 фрагментов |
2.13 % |
2.57 % |
2.06 % |
без склейки, 195 предложений |
1.92 % |
2.41 % |
1.84 % |
Старая обрезка хуже, чем никакой, в обоих режимах. Новая лучше, чем никакой, тоже в обоих. Отказ от склейки выигрывает в каждом столбце. Ни одна из двух починок не маскирует другую, и это видно только потому, что они мерились крест-накрест, а не по очереди.
Вдохи: 89 %, которых не было
Первая проверка сообщила, что вдохом начинается 131 предложение из 147, то есть 89 %. Цифра пугала, пока не выяснилось, что это обрезка отчитывалась сама о себе: вдохом она считала всё до первого звонкого кадра, то есть те же глухие согласные. Когда я определил вдох как устойчивый слышимый шум перед словом и померил по уровню, их осталось 30 из 147, один на пять предложений.
Только этот замер, как и сама обрезка, смотрел исключительно на начало фразы. Сканирование всей волны нашло вдохи между словами в 76 предложениях из 195, ровно там, куда до этого не смотрел ни один мой детектор. Их я научился приглушать до уровня фона, не сдвигая ни одной отметки времени. Цена для разборчивости нулевая: 68 из 76 изменённых предложений распознаются байт в байт так же, как до приглушения, а ни одно из 119 нетронутых не сдвинулось.
Темп и паузы
Машина читает быстрее живого диктора: 17.4 кириллической буквы в секунду против 14.5. Глава, которую я ждал на 14.9 минуты, уложилась в 12.3. Для аудиокниги это звучит немного торопливо.
Паузы между фразами я не придумывал, а померил у живого диктора на десяти минутах чтения: 129 пауз, медиана 288 мс, и только три за все десять минут длиннее 0.6 с. Отсюда мои 300 мс между предложениями, чуть больше при смене говорящего и ещё чуть больше между абзацами. Важная деталь: это фактические паузы, а не вставки. У каждого клипа по краям уже есть своя тишина, поэтому сборщик меряет её у обоих соседей и добивает только разницу. Эта деталь ещё всплывёт в разделе про разметку.
Итог по главе: CER 1.84 % вместо 2.56 % в первом прогоне (в перемере для таблицы выше та же конфигурация дала 2.57 %). Модель та же самая. Изменилось только то, что я ей подавал, и то, что делал со звуком после.
Дж: разница, которую 14 фраз не увидели
История с «нидже», которое машина прочитала как «ниже», есть в первой статье. Причина была в переписывании букв: у него было четвёртое правило, дж → ж, и модели буквально подавали русское слово. Здесь важно продолжение.
Для починки я сравнил пять способов записать этот звук. На 14 проверочных фразах два лучших варианта, обычное дж и татарская буква җ, были неразличимы: оба исправляли слово в трёх рендерах из трёх. Но выбирать по фразам было нельзя по ещё одной причине. Убрав правило, я сознательно разводил вход модели с тем, как текст был записан в обучении: при дообучении модель дж в таком виде не видела ни разу. Поэтому решение принималось на целой главе. Все 195 предложений я переозвучил с каждым кандидатом и сравнил на сырых файлах, до обрезки, чтобы отличалось только написание:
написание |
WER главы |
CER главы |
что показали 14 фраз |
|---|---|---|---|
ж (как было) |
9.35 % |
1.92 % |
«ниже» вместо «нидже» |
дж |
9.03 % |
1.86 % |
слово исправлено, 3 из 3 |
җ |
10.32 % |
2.43 % |
слово исправлено, 3 из 3 |
У дж 43 предложения стали лучше, 39 хуже, 113 не изменились. Это шум, а от правки, которая чинит одно слово, большего и не требуется: главное, что она ничего не портит. җ исправлял злополучное слово и делал хуже всю остальную главу: +10 % относительных по WER и +27 % по CER. Катил я дж.
Если бы решение принималось на проверочном наборе, я с равной вероятностью выбрал бы любой из двух, а 195 предложений сразу показали, что один из них вредит.
Книга: конвейер по главам
Остальные пятнадцать глав шли через тот же конвейер, по главе за раз: синтез, сборка, чистка вдохов, разметка слов по времени, выборочная проверка отметок с контролем, полная обратная вычитка и упаковка для читалки. У каждой главы свой журнал этапов, поэтому оборвавшееся соединение или уснувший ноутбук стоят одного этапа, а не книги. Первую главу я заново не озвучивал: её текст после всех поправок совпал с прежним байт в байт.
Целая книга нашла то, чего не нашла одна глава, и всё это оказалось в извлечении текста. Три звёздочки, которыми в книге разделены сцены, уходили модели как текст, и она их честно «читала». Последний абзац романа, авторскую дату «1940 s.», фильтр пропустил, потому что это не голое число, и роман заканчивался произнесённым вслух годом. А пять предложений рвались пополам там, где абзац обрывался на многоточии и продолжался в следующем.
Сборка, которая отказалась собирать
У формата читалки есть контракт: слова предложения, склеенные обратно через одиночный пробел, обязаны давать исходный текст предложения байт в байт. Сборщик проверяет это для каждого предложения и при нарушении ничего не пишет.
В седьмой главе он отказался. В файле книги внутри одного предложения стоял двойной пробел. Со звуком всё было в порядке, на экране тоже ничего не было бы видно. Но читалка, которая рисует текст по словам, молча потеряла бы этот пробел. Чинил я в источнике: извлечение теперь схлопывает пробелы (это задело седьмую и четырнадцатую главы), и седьмая глава была переозвучена с исправленного текста. Это был уже второй раз, когда программа, отказавшаяся работать, нашла то, чего никакое прослушивание не нашло бы.
Заодно поменялся порядок работы. Сработавшая защита в одной главе больше не останавливает очередь: сбой записывается, остальные главы идут дальше, а код возврата несёт ошибку. Книга, остановившаяся ночью на седьмой главе, это потерянная ночь.
Глава IV, и почему одно среднее на книгу было бы неправильной цифрой
Каждую главу я проверял отдельно, и одна выглядела плохо: CER четвёртой главы 8.28 %, вчетверо выше медианы по книге. Я полез слушать, и глава оказалась нормальной. Всю ошибку дала одна реплика из двух слов, «– dep tüşündi.»: проверяющая распознавалка зациклилась и записала её двадцать пять раз подряд, CER одного этого клипа 30.7, то есть больше трёх тысяч процентов. Без него у главы около 2 %, как у всех. Та же реплика подвела проверку и во второй главе (4.44 % → 2.50 %), и ещё один такой сбой был в тринадцатой. Ошиблась не читающая машина, а проверяющая, и как раз на очень коротком клипе.

CER обратной вычитки по главам. Штриховка — то, что добавили клипы, на которых зациклилась проверяющая распознавалка, а не само чтение; почти вся она приходится на одну реплику «– dep tüşündi.» в четвёртой и второй главах. Пунктир — медиана без таких клипов.
Одна такая реплика портит среднее и ничего не говорит о чтении, поэтому по книге я публикую распределение по главам, а не одно число. Без зацикленных клипов: медиана 2.15 %, лучшая глава 1.51 % (III), худшая 2.70 % (XIV), разброс меньше чем в два раза. Ни к концу книги, ни с длиной главы качество не плывёт. Самая длинная, вторая, звучит девятнадцать с половиной минут и читается с CER 2.50 %.
Во что это обходится
Вся книга: 177 минут работы машины на 118.4 минуты звучания, то есть ×1.5 к длительности звука, на той же домашней видеокарте, что и в первой статье. По журналам глав II–XVI время раскладывается так:
этап |
минут |
|---|---|
синтез |
63.5 |
разметка слов по времени |
74.9 |
проверки: выборочные отметки, контроль, полная обратная вычитка |
28.3 |
всего, с мелкими этапами |
168.3 |
Сам синтез занимает меньше половины. Больше уходит на то, чтобы привязать каждое слово ко времени и всё проверить. Накладные расходы при этом считаются на главу, а не на слово: глава XIII на 337 слов обошлась в 7.1 минуты, глава II на 2 549 слов — в 20.6. Если в библиотеке окажется много коротких глав, их выгоднее размечать пачкой.
Читалка: выравнивание по тексту, который знает синтез
Книга была нужна не только как звуковой файл. Я хотел читалку: текст на экране, голос читает, текущее слово подсвечивается, щелчок по слову переносит чтение туда.
Для этого нужно время каждого слова, и здесь пригодился приём, с которого начинался весь проект: forced alignment, совмещение звука с заранее известным текстом. Только теперь известный текст — это ровно то, что синтез получил на вход. Двенадцатиминутный файл главы я не выравниваю. Каждое предложение выравнивается отдельно, по своему тексту, а потом переводится в общее время главы через единственную таблицу смещений, которой владеет сборщик. Выравниватель отказывается что-либо писать, если не хватает предложения, число слов не совпадает с текстом, время идёт не монотонно, слово заканчивается за концом собственного файла или таблица предложений разъехалась с файлом главы.
Результат по всей книге: на экране 15 449 токенов, время есть у 100 % слов во всех 16 главах, без отметок остались только тире и знаки, которые не произносятся. Таблица предложений сходится с файлом главы с точностью 0–1 мс. Ниже порога уверенности оказались 83 слова из 15 449.
Эти сомнительные отметки не разбросаны случайно. Больше всего их на первом слове после тире в диалоге, и именно там же спотыкается обратная вычитка. Два независимых прибора показывают на одни и те же места. Низкая оценка слова для меня теперь повод послушать предложение, а не удалить отметку.
Сами отметки проверялись контролем, который обязан провалиться: короткие куски, вырезанные строго по записанным временам, распознаются, а те же куски со сдвигом на 0.4 с нет. Цифры по книге были в первой статье, повторять их не буду.
Ещё две защиты родом из прошлых граблей. Первая — из истории про разметку, которая к концу главы разъехалась на 44 секунды (тоже первая статья). Один и тот же таймлайн тогда независимо считали два куска кода, и один из них учитывал собственную тишину клипов дважды: та самая разница между целевой и фактической паузой. Теперь у таймлайна один владелец, а сборка сравнивает конец последнего предложения с длиной звукового файла и отказывается работать, если они расходятся больше чем на полсекунды.
Вторая — из истории с дж. Первую сборку читалки я сделал на старой озвучке, ещё до исправления, и единственным признаком этого было то, что голос говорил «ниже». Теперь каждая глава хранит SHA-256 своего звукового файла и идентификатор озвучки, на которой её мерили. Устаревшую озвучку видно по данным, а не только на слух.
Читалка работает на ana-yurt.com, одна страница и для чтения, и для слушания. «Merdiven» можно открыть и прослушать целиком: ana-yurt.com/kutuphane/3444/read.
Почему именно «Merdiven»? Я очень люблю Шамиля Алядина, и мне хотелось, чтобы первой книгой, которую прочитает машина, стало одно из его произведений. К тому же роман подходил по стилю: ровная повествовательная проза. Юмористические рассказы или детские книги, где нужна игра голосом, модель тогда читать ещё не была готова.
Голос: образец решает больше, чем кажется
Раз тембр берётся из образца, выбор голоса сводится к выбору нескольких секунд записи. И образец оказался важнее, чем я думал.
Паузы. Свой голос я сначала пробовал на отдельных фразах и услышал длинные неуместные паузы посреди предложений. Подозревал модель, а виноват был образец: в 10.72 с записи было 0.77 с тишины перед словами и 1.77 с после. Модель берёт из образца не только тембр, но и темп, то есть сколько времени тратить на каждую букву. С таким образцом клон читал примерно на 22 % медленнее и раскладывал лишнее время паузами внутри фраз. Я обрезал тишину по краям, и медиана суммарных пауз внутри предложения упала с 930 до 85 мс (27 предложений по 6 сидов), а доля предложений совсем без внутренних пауз выросла с 4 % до 41 %. Слепое сравнение старого и обрезанного образца при прочих равных дало 7 : 6, p = 1.000: на слух не отличить. Для такой починки это идеальный исход: дефект ушёл, голос остался.
Глухость. Потом голос показался мне глухим. Виноват был микрофон: петличка на груди стоит сбоку от рта и теряет как раз полосу 2–8 кГц, которой не хватало, а плоская настройка этого не исправляла. На выходе синтеза это около 4.8 дБ. Фильтром такое не дорисуешь: чего микрофон не записал, того в записи нет. Пришлось записать образцы заново.
Больше мужской речи в обучении. Была и попытка помочь мужскому голосу данными: я добавил в учебные материалы больше мужской речи. Слепое сравнение: новая версия проиграла прежней 3 : 11 при девяти ничьих, p = 0.057. Строго говоря, это не доказательство того, что она хуже. Но и оставлять её было не за что, тем более что весь отрыв дал один голос, женский, со счётом 7 : 1. Замер основного тона я заранее отложил и вскрыл только после подсчёта: у этого же голоса тон сместился вниз, с 208 до 199 Гц. Ухо и прибор показали на один и тот же голос. Эту версию я не оставил.
Когда с паузами и микрофоном разобрался, я решил попробовать для целой книги свой собственный голос. Так вторую книгу в нашей библиотеке — Юнус Къандым, «Куреш мейданыны от басмаз», 28 глав, 43 701 слово, 6 ч 29 мин звучания — машина прочитала моим голосом. Её тоже можно послушать: ana-yurt.com/kutuphane/3516/read. Читала её уже нынешняя версия модели, а «Merdiven» — более ранняя. Сравнивать версии по этим двум книгам нельзя: тексты разные и голоса разные.
Эту книгу я тоже выбрал не случайно. Её автор, Юнус Къандым, — мой дядя, и мне очень хотелось, чтобы его книга прозвучала именно моим голосом.
Обычно, когда слышишь свой голос в записи, он кажется чужим и странным. Здесь всё было иначе. Когда я услышал первое предложение в своей озвучке, моему счастью не было границ: качество оказалось очень хорошим.
Что пока не получилось
Ударение
Эта история шла по кругу, и она мне дороже остальных. Я заметил, что имя «Риза» машина иногда читает как «Рыза». Проверка на восьми разных предложениях для каждого имени подтвердила: «Риза» уходит в заднюю гласную в 4 предложениях из 8, «Азиз» в 5 из 8, в контрольных предложениях ни разу из 16 (точный тест Фишера, p = 0.0066 и 0.0013). У «Сабри» и «Дилявера» дефекта нет совсем.
Нашлась и починка: писать на входе «ий» вместо «и». Задняя гласная после этого пропадала полностью, ни одного случая из 16 на каждое имя, а CER самого имени падал: у «Ризы» с 0.125 до 0.103, у «Азиза» с 0.300 до 0.169. Остальная часть предложения не сдвинулась, как и должно быть. Приборы были довольны.
Я послушал вслепую и не принял. Счёт вышел 4 : 3 в пользу того, что было, то есть монетка, а в заметке к слепой странице я написал: «если слышу И, то ударение неверное». Починка возвращала правильную гласную и при этом утаскивала ударение на первый слог, а у нас оно на последнем. Обе версии были неправильными, каждая по-своему.
Сильно я не расстроился. Это первые модели, и такие ошибки я в них допускаю. Я решил вернуться к этой проблеме позже.
Вернулся я к ней с другой стороны: стал мерить само ударение, а не гласную. В нашем языке последний слог слова обычно немного тянется, причём у живых дикторов одни слова тянутся сильно, а другие почти никак. Чтобы сравнение было честным, модель читала те же предложения из учебных записей, что и дикторы, так что у каждого слова есть человеческая пара с тем же текстом.
В среднем модель тянет последний слог столько же, сколько люди: 1.143 против 1.156 по 125 парам, p = 0.33. На этом можно было остановиться с выводом «всё в порядке», и это был бы неверный вывод. Если построить регрессию растяжения у модели на растяжение у людей по 22 ячейкам «слово × позиция во фразе» (в логарифмах), наклон получается 0.556 ± 0.115. Модель воспроизводит только около шести десятых человеческого размаха: недотягивает как раз те слова, которые дикторы тянут сильнее всего, и перетягивает плоские. Дефект не в среднем, а в сжатии.
Дальше я по очереди исключал подозреваемых:
подозреваемый |
что показал замер |
|---|---|
образец голоса |
меняет только общий темп, на растяжение не влияет |
учебные данные |
у людей зависимость есть: внутри записей они следуют норме слова с наклоном 0.938, учиться было у кого |
настройки декодирования |
две ручки, гасящие разброс, крутил в обе стороны: наклон в пределах шума, зависимости от дозы нет; контроль совпал с релизом байт в байт, 375 из 375 рендеров |
моё дообучение |
исходная модель без адаптера так же ровная, то есть адаптер этого не создал и не исправил |
Остался следующий подозреваемый: то, как модель заранее отмеряет длину всей фразы. Для одного и того же текста общая длина рендера от сида к сиду меняется всего на 0.46 %. Худшей ячейке не хватает примерно 69 мс на последнем гласном, это около 1.4 % пятисекундной фразы, втрое больше всей свободы, которую оставляет такой бюджет. Если длина задана наперёд, удлинить последний слог можно только за счёт соседних. Пока это гипотеза, и проверять её — уже работа с самой моделью, а не с текстом на входе.
Вдохи
Чистка вдохов ни разу ничего не ухудшила: на слепой странице 8 ничьих, 2 в пользу очищенного варианта, 0 против. Но жалобу она не снимает. Короткие вдохи по 60–120 мс чистка достаёт плохо, 42 % из них остаются. Больше всего вдохов у моего голоса: в одном замере 15.5 % звучания против 1.0 % у Sevil. Обрезка тишины в образце сама по себе сократила долю вдохов больше чем вдвое, с 12.1 % до 5.1 %, но не до нуля.
Паузы на эмоциональных репликах
Мне казалось, что там, где текст эмоциональнее, машина делает паузы длиннее. Проверял я это на 27 предложениях в трёх корзинах эмоциональности, которые на этапе отбора уравнены по длине и числу знаков препинания, по 6 сидов на каждое. Связи с эмоциональностью нет: ρ = +0.076, p = 0.70. Паузы следуют за длиной предложения (ρ = +0.886) и числом знаков препинания внутри него (ρ = +0.658), а эмоциональные фразы в прозе просто чаще длиннее и богаче запятыми. Двадцать семь предложений исключают сильный эффект; чтобы поймать слабый, понадобилось бы около 85.
Для меня вопрос всё равно не закрыт. Померить я смог только общую длину пауз, а не то, где они стоят, а пауза не на месте в восклицании режет слух сильнее, чем та же пауза у запятой.
Диалоги и числа
Тире перед репликой модель видит, но смену говорящего читает как новое предложение, а не как новый голос. Разницу пока несёт только чуть более длинная пауза при смене говорящего.
Числа я заранее превращаю в слова, но проверить их прочтение обратной вычиткой нельзя: распознавалка записывает услышанное цифрами, и «1924» возвращается как «19124». Числа пока проверяет только ухо.
Что я вынес из этой книги
Голос оказался самой надёжной частью всей цепочки. Почти всё, что ломалось, было в подготовке текста и звука вокруг модели: склейка, обрезка, буквы, разметка, двойной пробел. Часть этого нашли приборы и защиты, и ухо не нашло бы её никогда: настоящий порог длины в 70 букв, двойной пробел, зацикленную проверку в четвёртой главе. Часть нашло ухо, а прибор не умел её даже оценить: «нидже», ударение в «Ризе», вдохи между словами.
Практических выводов для себя я сделал два. Проверочный набор годится для сравнения версий, но решение, что катить, я теперь принимаю на целой главе. А сборка, которая умеет отказаться собирать, окупается: двойной пробел в седьмой главе не нашло бы никакое прослушивание.
Когда я дослушал книгу до конца, я почувствовал гордость: проделанная работа была не впустую и дала отличный результат. Но это не повод расслабляться. В книге всё ещё слышны места, которые нужно доработать, а значит, работы у нас ещё много.
Это третья статья серии. Дальше расскажу подробнее, как я выбирал основу для голоса, которая уже умеет произносить наш къ, и почему соседний турецкий для этого не годится. А потом, как и обещал, про облачные видеокарты.
Аудиопримеры и текущее состояние проекта — https://ai.ana-yurt.dev/. Версия этой статьи для ana-yurt.com, попроще и с меньшим количеством цифр: https://ana-yurt.com/golos-kotoryy-prochital-celuyu-knigu.
Если вы носитель крымскотатарского и готовы помогать, напишите на support@ana-yurt.com. Нужно слушать главы и отмечать, где ударение не на своём месте, где имя прочитано не так, где пауза разрывает фразу. Программировать для этого не нужно; в этой книге самые важные находки сделало именно живое ухо. Поддержать работу материально можно на ko-fi.com/anayurt.