Эрзянский язык из финно-угорской семьи – один из официальных в республике Мордовия, и на нём говорят сотни тысяч людей, но для него до сих пор не было почти никаких технологий машинного перевода, кроме простых словарей. Я попробовал создать первую нейросеть, способную переводить с эрзянского на русский (и с натяжкой ещё на 10 языков) и обратно не только слова, но и целые предложения.

Пока её качество оставляет желать лучшего, но пробовать пользоваться уже можно.
Как я собирал для этого тексты и обучал модели – под катом.

Введение

В последние годы технологии обработки естественного языка совершили большой скачок. Но, увы, основной эффект этого скачка пришелся на так называемые высокоресурсные языки, такие как английский и русский, для которых регулярно публикуются новые датасеты и обученные модели. В последние годы всё больше языков освещаются в публикациях по NLP. Но для большинства из примерно 7000 языков мира до сих пор не создано технологий автоматического перевода. Для некоторых нет даже просто качественных и полных словарей.

Последние пару лет я создавал ресурсы в основном для своего родного русского языка, а недавно впервые попробовал заняться языком, который не знаю вообще, и для которого существует не так много готовых ресурсов. Я выбрал язык Эрзя (myv), один из официальных языков в Мордовии (ещё один - родственный ему язык Мокша) и попробовал обучить для него энкодер предложений и модель для машинного перевода.

На эрзянском говорят несколько сотен тысяч человек (точного числа никто не знает из-за особенностей переписи населения). Кроме Мордовии, эрзянские сообщества есть в других регионах РФ (например, в Самарской области) и других странах (например, в Украине). Язык считается находящимся под угрозой, ибо в крупных городах типа Саранска он всё больше вытесняется русским, однако в сельских сообществах эрзянский передаётся молодым поколениям вполне активно. Эрзянский язык (как и мокшанский) относится к финно-угорской семье; его родственники – финский, эстонский и венгерский (а в РФ – например, языки Мари и Коми). В России на эрзянском пишут в основном кириллицей, и я работаю пока только с ней. Но существует и орфография на основе латиницы, и если вы готовы помочь мне собрать тексты в этом правописании – пишите в личку, и я попробую добавить его в следующую версию моих моделей.

Несмотря на существенное число носителей и официальный статус эрзянского, систем машинного перевода для него почти не существует. Первое исключение, которое я нашел, это эрзянско-мокшанский переводчик (основанный на правилах) созданный Джеком Рюэтером. Второй пример – нейросеть от университета Хельсинки для перевода между несколькими финно-угорскими языками, включая эрзянский; на неё я наткнулся уже после своих экспериментов. Мне же хотелось создать первую систему, способную переводить между эрзянским и массовыми языками, типа русского и английского, и по возможности легко расширяемую на новые языки.

Чтобы прийти к этой цели, я собрал в интернете корпус текстов на эрзянском, и для части этих текстов сопоставил им русские переводы. В процессе мне пришлось обучить две модели: одну для детекции языка, и одну – для извлечения векторных представлений эрзянских предложений. С собранными текстами я сначала обучил пару моделей для перевода между русским и эрзянским, а потом расширил их на 10 других языков. Всё это я описал в статье. Качество получилось далеким от идеального, но я надеюсь, что моя работа станет бейзлайном, который кто-нибудь вскоре побьёт. Суммарно я потратил на эту работу около 10 рабочих дней и 10 долларов денег (на Google Colab): как видите, для создания моделей машинного перевода не обязательно обладать ресурсами масштаба Яндекса или Меты.

В остальном тексте поста я поведаю, как именно я собирал тексты и обучал модели. Возможно, вы вдохновитесь моим опытом и попробуете улучшить машинный перевод для эрзянского или даже создать его с нуля для каких-нибудь иных малоресурсных языков.

Сбор текстов

Я начал со словарей, ибо для эрзянского они существуют давно. Брал отсюда: 1 2 3 4 5 6. Парсил html с помощью beautifulSoup, pdf - посредством pdfminer; и с тем, и с другим пришлось повозиться. Суммарно мне удалось собрать 48 тысяч пар эрзянских и соответствующих им русских слов и словосочетаний. Увы, для автоматического перевода одних словарей мало: они не помогают ни с морфологией (изменением формы слова), ни с синтаксисом (построением из отдельных слов целых предложений). И то, и другое теоретически можно было бы описать правилами, но для этого надо быть лингвистом и хорошо знать оба языка. Поэтому я пошёл по пути машинного обучения: пусть нейросети сами разберутся, как формировать слова и составлять из них предложения.

Для обучения моделей машинного перевода используются так называемые параллельные корпуса, то есть большие наборы текстов с одинаковым смыслом на разных языках (как правило, сопоставленные друг с другом на уровне предложений). Обычно такие корпуса хорошо ищутся на сайте OPUS, но для эрзянского там нашлось всего 3 тысячи предложений, собранных с сайта Wikimedia и выровненных с русским. 3 тысячи – это очень мало для такой задачи; для хорошего машинного перевода нужно что-то ближе к миллиону. Поэтому остальные параллельные тексты мне пришлось искать самому. В общем-то, из всего моего подхода к созданию переводчика, этот этап - наиболее завязанный на человека и на конкретный язык. Всё остальное, кажется, можно воспроизводить для других языков практически вслепую.

Начал я с двух стандартных источников: Библии и Википедии. Библия переведена на большее число языков, чем любая другая книга, и в ней пронумерованы абзацы, что очень удобно для сопоставления текстов на разных языках. Википедия не так удобна для поиска параллельных текстов (статьи на одну тему на разных языках редко имеют полностью одинаковое содержание), зато она покрывает большой набор тем, и на эрзянском там 7719 статей (правда, в основном коротеньких).

На Википедии (93K случайно выбранных статей из 323 языков) и Библии (мокшанской и эрзянской) я обучил модель fastText для определения языка по тексту. Почему не воспользовался готовой? Потому что в ней нет мокшанского, и в ранней версии моих экспериментов эрзянский с ним сильно путался (и с другими языками с кириллическим алфавитом тоже). После сжатия модель весит 2.2 мегабайта и выложена тут. Дальше я пользовался ей для фильтрации предложений из некоторых источников, менее надежных, чем Википедия.

Очень много эрзянских текстов оказалось в проекте Wikisource, выкладывающем литературные произведения в открытый доступ. Кроме этого, я скачал много книг и газет в pdf отсюда и отсюда, а еще попарсил сайт издания Эрзянь Правда. Наконец, я насобирал эрзянских текстов в старом добром ЖЖ: воспользовался встроенным поиском по сайту и собрал 1132 постов, содержащих 100 наиболее употребительных эрзянских слов. Многие из этих текстов содержали и предложения на других языках или смесь языков, но модель для определения языка позволила их отфильтровать.

Таким образом, я оказался с кучей эрзянских текстов, для части которых был приблизительный русский аналог. Но для обучения модели «приблизительного аналога» на уровне текста недостаточно: нужно отобрать из корпуса пары предложений, которые соответствуют друг другу по смыслу наверняка. И для этого мне понадобилась еще одна модель: энкодер предложений.

Энкодер предложений для эрзянского

Энкодер предложений - это модель, которая на вход принимает короткий текст, а на выходе возвращает многомерный вектор, причем такой, что у текстов, похожих по смыслу, векторы близки друг к другу в математическом смысле. Про энкодеры предложений для русского языка я писал тут и здесь. А если такая модель понимает два языка, то её можно использовать для майнинга параллельных пар предложений из пары связанных текстов (например, из статей русской и эрзянской Википедии на одну и ту же тему). Алгоритм такой:

  1. Разбиваем тексты на предложения (пакет razdel).

  2. Вычисляем вектор каждого предложения, и считаем косинусную близость каждого предложения первого текста к каждому предложению второго.

  3. На случай, если модель не очень точная, вставляем два костыля. Чтобы отсечь пары предложений, сильно отличающихся по длине, домножаем косинусную близость каждой пары на отношение длины более короткого предложения к более длинному. А чтобы отсечь предложения, похожие на всё сразу (такие попадаются), вычитаем из близости для каждой пары по 0.2 средних близости составляющих её предложений к топ-10 своим ближайшим соседям. Число 0.2 я подбирал на глаз.

  4. Находим такие подпоследовательности предложений в русском и эрзянском тексте, что они идут в одном и том же порядке, и что сумма близостей пар предложений с одинаковым номером - максимальна.

  5. Если средняя близость друг к другу выбранных таким образом пар предложений выше порога (который я подбирал отдельно для каждого источника текстов), мы считаем их параллельными.

Проблема в том, что энкодера предложений для эрзянского не существовало. Но был LaBSE на основе BERT, который делает это для 100 языков, и логично было попробовать адаптировать его для еще одного. Для этого я сначала расширил словарь модели: прогнал алгоритм byte pair encoding на собранном мной эрзянском корпусе и отобрал им 20к новых токенов (слов либо кусочков слов), наиболее часто встречающихся в эрзянских текстах. Я добавил эти токены в модель (попутно выкинув токены для других языков, кроме русского и английского, как тут) и принялся дообучать её в несколько этапов:

  1. Обновлял только эмбеддинги токенов – так, чтобы эмбеддинги русских слов или предложений и соответствующих им эрзянских становились как можно более похожими друг на друга.

  2. Обновлял все параметры модели (токены и 12 трансформерных слоёв), обучая модель решать сразу три задачи: приближение векторов эрзянских предложений к соответствующим русским; угадывание пропущенных слов в эрзянском предложении; определение по паре предложений, совпадает у них смысл или нет.

Полученную модель я выложил на huggingface. Её можно скачивать и дообучать на разные задачи понимания эрзянского языка. Ну а сам я использовал её для майнинга параллельных текстов алгоритмом, описанным выше. Намайнить удалось 11К пар предложений из Википедии, и ещё столько же - из разных книг и художественных произведений. Думаю, намайнить можно было и больше, но я, как человек, не знающий эрзянского, настроил пороги фильтрации предложений построже, чтобы нечаянно не набрать мусора.

Три тысячи пар предложений я отложил в качестве валидационной и тестовой выборки. Я выбрал их случайным образом из 6 разнообразных и более-менее надёжных источников: Библии, сборника эрзянских сказов Шеяновой, советской конституции 1938 года, описаний мордовских народных игр Брыжинского, современных художественных произведений на эрзянском, и Википедии. Собранный и разбитый на части корпус можно скачать отсюда.

Обучение моделей для перевода

В качестве базовой модели для перевода я выбрал mBART-50: трансформерную нейросеть, обученный переводить между 50 языками. Вместо этого мог взять M2M-100 или даже NLLB-200 (хотя на момент начала моих экспериментов она ещё не вышла); наверняка качество могло бы от этого вырасти; в следующих экспериментах надо будет попробовать. Я добавил в неё 20К новых слов и кусочков слов для эрзянского языка, а потом обучил на своём корпусе две копии этой модели: одну для перевода с русского на эрзянский, другую – наоборот.

Качество перевода получилось вроде бы ненулевым, поэтому я решил обнаглеть и попробовать добавить в модель ещё 10 языков: арабский, немецкий, английский, испанский, финский, французский, хинди, турецкий, украинский, и китайский. Все эти языки mBART-50 уже видел при предобучении, поэтому ему должно быть не очень сложно. В итоге одна модель (myv-mul) у меня переводит с эрзянского на 11 других языков, а вторая (mul-myv) – с этих языков на эрзянский.

Пары предложений новых языков с русским я взял из датасета CCMatrix, и по ходу дообучения дополнял их эрзянскими переводами из своей русско-эрзянской модели, чтобы потом учить другую модель переводить эти эрзянские тексты на иностранный. Кроме этого, я переводил на 10 новых языков эрзянские тексты из своего русско-эрзянского или чисто эрзянского корпуса, и затем учил модель переводить эти переводы обратно уже на эрзянский. Таким образом, я использовал несколько вариантов обратного перевода:

Варианты обратного перевода, которые я использовал при обучении моделей
Варианты обратного перевода, которые я использовал при обучении моделей

Заняло это обучение несколько суток в Google Colab (результат сохранялся на Google disk, и блокноты каждый день приходилось перезапускать). В результате модель оказалась способна переводить примерно так:

Примеры перевода с эрзянского на русский/английский/финский и наоборот.
Примеры перевода с эрзянского на русский/английский/финский и наоборот.

Оценка качества

В какой-то момент мне захотелось закрепить успех и измерить качество своих моделей. Для эрзянско-русского перевода у меня уже был отложенная выборка из 6 разных источников. Для ещё двух языков, английского и финского, несколько сотен параллельных предложений нашлось в эрзянском корпусе Universal Dependencies, собранном всё тем же Jack'ом Rueter'ом. Все эти предложения я перевёл во всех возможных направлениях (с эрзянского на русский/английский/финский и наоборот) и сравнил мои переводы с человеческими с помощью двух метрик: BLEU и ChrF++. Они обе вычисляют долю совпадения между двумя предложениями, но BLEU сравнивает только слова и словосочетания, а ChrF++ – ещё и кусочки из нескольких букв (это помогает, если слово написано с опечаткой или в другом падеже). У обоих метрик максимальное значение 100, но на практике оно не достигается, ибо у одного и того же предложения может быть очень много корректных переводов.

Слева: оценка качества по 6 разным направлениям перевода. 
Справа: оценка качества перевода между эрзянским и русским по 6 разным источникам текстов.
Слева: оценка качества по 6 разным направлениям перевода. Справа: оценка качества перевода между эрзянским и русским по 6 разным источникам текстов.

Наблюдений можно сделать несколько. Во-первых, перевод между эрзянским и нерусскими языками пока очень слабенький: видимо, на обратном переводе уехать сложно, и стоит добавить в обучающих корпус хоть немного настоящих параллельных текстов для этих языков. Во-вторых, даже перевод между русским и эрзянским ещё расти и расти: у SOTA систем для высокоресурсных языков BLEU обычно где-то между 40 и 80. В-третьих, скоры BLEU очень разнятся в зависимости от домена: они высокие для конституции и Википедии, где много дословных переводов, и сильно ниже у художественных текстов, где переводы гораздо более разнообразные и непредсказуемые.

Имеет ли смысл вообще пользоваться моим переводчиком, или его качество пока настолько низкое, что переводить им бессмысленно? Чтобы понять это, я нашёл трёх волонтёров – носителей эрзянского, и попросил их оценить качество 29 случайно выбранных переводов между русским и эрзянским. Я предложил им пятибалльную шкалу, где 1 – бесполезный перевод, 5 – идеальный перевод, а 3 – приемлемый перевод без критических ошибок. Потом для каждого перевода я взял самую низкую из трёх оценок волонтёров. Оказалось, что 58% переводов с эрзянского на русский получили хотя бы тройку (средний балл 2.75). Для переводов с русского на эрзянский доля троек и выше вышла 53%, а средний балл – 2.71.

Короче говоря, модели выдают приемлемые переводы пока где-то в половине случаев.
Самостоятельно попробовать применить их вы можете тут.

И что дальше?

Задача машинного перевода для эрзянского языка пока явно не решена, но я хотя бы положил начало этому пути. Все мои результаты выложены в свободный доступ (список ссылок – тут), и я приглашаю вас пробовать улучшать их. Сам я тоже собираюсь улучшать модели сразу по нескольким направлениям:

  • Сбор большего количества эрзянских и параллельных текстов и их более качественная фильтрация;

  • Создание ещё большего количества обучающих текстов автоматическими средствами, например, с помощью словарей и пакета UralicNLP (как в этой статье);

  • Использование более крутых предобученных моделей, таких как NLLB-200.

Я открыт к сотрудничеству. Если вы владеете эрзянским и можете помочь мне с более аккуратным сбором текстов, или если вы хотите создать системы машинного перевода для какого-нибудь другого языка – пишите в комменты или сразу в личку.

Комментарии (20)


  1. imageman
    09.10.2022 21:10
    +4

    Спасибо, познавательно. Есть человечек https://github.com/averkij (тут @averkij) который занимается схожими темами (в телеграмме ведет свой канал "градиент обреченный" https://t.me/doomgrad) в котором пишет о машинном обучении (не реклама, не имею к нему отношения) - думаю найдете общие темы для беседы.


    1. cointegrated Автор
      09.10.2022 21:47
      +2

      Спасибо! Да, с Сергеем мы общаемся)


  1. GT21
    10.10.2022 08:24

    Это конечно хорошо, но думаю лучше было заниматься не в одиночку, а скооперироваться с крупной компанией - например яндекс переводит чувашский и якутский, у них есть в этом опыт


    1. averkij
      10.10.2022 08:54
      +2

      Привет! Тут как повезет, насколько я знаю башкирские энтузиасты (AigizK) сами собрали несколько сотен тысяч паралелльных текстов и писали в Яндекс, но ответа не получили. Писали в Сбердевайсы — башкирский добавили в мультиязычную модель mGPT (но это не переводчик, а генеративная модель). Ну а русско-башкирский переводчик помогли бесплатно сделать товарищи из glosbe, причем по словам ребят, он довольно качественный.


      1. irishmann
        10.10.2022 10:15
        +2

        Затестил переводчик, о качестве судите сами)

        текст на башкирском

        Тау бите текә. Уның түбәһенә таштар өйөлгән. Был таштар тауға шомло төҫ бирә. Улар алыҫтан төрлө кейектәрҙе хәтерләтә. Таштарҙан уңдараҡ - артыш өйөмө. Унан арыраҡ аҡ ҡайындар күренә. Улар тауҙы яҡтыртып торған төҫлө. Тауҙың һул яҡ башында ҡарағайҙар теҙелеп баҫҡан. Улар тауҙы тағы ла ҙурыраҡ, серлерәк күрһәтә кеүек. Тау итәге тулып һары мәтрүшкә үҫә. Улар шул тиклем күп. Әйтерһең һары диңгеҙ.

        перевод через glosbe

        А горы круто. И поднимут его плечи. Эти камни освещает тот волку. Они напоминают о самых разных оттенков. Встань рядом с бриллиантом Более того, как белые березы ожидают бечевку. Между собой они освежают свет, они освежают. На вершине горы выстроились из отборной сосны. Благодаря тому, что горы больше, может быть, даже большей загадкой, как это. У подножия горы растет желтая - желто-то, как много, так и мира. Они так много. Словно море бабочке.

        мой перевод

        Склон горы крутой. На его вершине сложены камни. Эти камни придают горе зловещий вид. Они издалека напоминают разных зверей. Неподалёку от камней куча можжевельника. А еще дальше виднеются белые берёзы. Они освещают гору. На левой вершине горы выстроились сосны. Из-за них гора кажется еще больше и загадочнее. У подножия горы цветет зверобой. Его очень много. Как будто желтое море.


        1. averkij
          10.10.2022 10:48
          +1

          Прикольно, есть, куда улучшаться :)

          Для полноты картины:

          Перевод через Bing
          Скала горы крутая. На его вершине были уложены камни. Эти камни придают горе неглубокий цвет. Они напоминают различную одежду издалека. Справа от камней находится отставание. Оттуда появляется березовая береза. Это цвет, который освещает крепление. С левой стороны горы выстроились сосны. Они, кажется, показывают гору еще больше и загадочнее. Предгорья заполнены и вырастают в желтые маты. Их так много. Можно сказать желтое море.

          Перевод через Яндекс
          Склоны крутые. На его вершину насыпана каменная глыба. Эти камни придают горе мрачный вид. Они образовывали своего рода своеобразное подобие дичи, издали напоминая различные виды дичи. Справа от камней расположены кучи можжевельника. Чуть дальше видны белые березы. Именно они составляют цвета, обозначающие гору. На левом склоне горы произрастают сосны. Они делают гору казаться еще больше, таинственнее. У подножья горы растет душистый перец. Вот как их много. Это словно желтое море.

          Перевод через NLLB (открытая модель от MetaAI, 1.3B параметров)
          Вершина горы крутая, на вершине которой находятся каменные скопления, которые издалека напоминают какую-то скалу. Справа от камней — куча арсиса, за ней — белые берёзы, окрашенные в свет горы, с левой стороны на вершине горы — ряды сосновых деревьев, которые показывают еще большую и более таинственную гору. У подножия горы — полное мерцание, растущее в таких количествах, как жёлтое море.


        1. AigizK
          10.10.2022 12:16
          +3

          Ну и добавим перевод от https://bashkortsoft.ru/

          Вершина горы крутая. Вершина его была завалена камнями. Эти камни придают горе тревожный оттенок. Они напоминают диких зверей издалека. Правее камней - можжевельник. Дальше видны белые березы. Они имеют вид света, который светит гору. На левом конце горы выстроились сосны. Казалось, они показывали гору еще больше, реже. Подножие горы заполнено жёлтым душицем. Их так много. Как будто желтое море.

          Как видно, ближе всего к вашему переводу этот результат. А построен он на этом коде: https://marian-nmt.github.io/ . Для обучения использовали больше 1M пар. Плюс сейчас то что мы собираем через телеграм бота, то же туда пойдет. Так что на вопрос, всегда ли только крупные корпорации могут сделать такое, ответ будет нет.

          К слову перевод от NLLB передает смысл почти полностью и при этом он собирает несколько предложений в одно предложение. То же очень прикольно. Тут получается использовали в основном вики-ресурсы. Так что, если даже у вас нет программистов, кто может сделать переводчик, благодаря вики и таким гигантам, у вас может появится хороший переводчик.


        1. imageman
          10.10.2022 19:23

          Тогда уж рядышком положим и гуглоперевод:
          Гора крутая. На его могилу положили камень. Скалы придают горе гладкий цвет. Издалека они напоминают различных оленей. Справа от стола находится стопка излишков. Вдалеке виднеются белые облака. Это волосы, из-за которых курица сияет. По ту сторону горы росли сосны. Они ищут более глубокое, более таинственное видение. Предгорья заполнены водой. У них такое отношение. Пожалуйста, скажите мне.


          1. AigizK
            10.10.2022 19:45
            +1

            если выбрали автоопределение, то гугл на самом деле детектить это как татарский. и видно, что качество татарского там то же хромает.


    1. cointegrated Автор
      10.10.2022 15:09

      Да, я знаю парочку человек из Яндекса, которые там занимаются машинным переводом. Если они возьмут мои наработки и доведут до продакшн-уровня, я буду только рад)


  1. arpadkomoly_nagyonkomoly
    10.10.2022 11:04

    написал в лс :)


    1. averkij
      10.10.2022 13:45

      Арпад, а вы активист венгерского языка?)


      1. arpadkomoly_nagyonkomoly
        10.10.2022 17:24
        +2

        я активист эрзянского и мансийского языка :)


      1. arpadkomoly_nagyonkomoly
        11.10.2022 14:40

        но венгерский тоже знаю и говорю


        1. cointegrated Автор
          11.10.2022 15:14
          +1

          О, интересно! А ты наблюдаешь какие-то параллели между венгерским и эрзянским языками? Они из одной Уральской семьи, но, насколько я себе представляю, очень далёкие. Интересно, как для носителя обоих языков это ощущается.


          1. arpadkomoly_nagyonkomoly
            11.10.2022 15:48
            +2

            Там всё очень сложно. Языки крайне далёкие, и взаимопонимания нет. Более того, взаимопонимание отсутствует между разными угорскими языками (хантыйским, мансийским и венгерским) и даже между отдельными диалектами хантыйского и мансийского. Равно как нет взаимопонимания между эрзянами и эстонцами (языки примерно как русский и литовский) Есть параллели как общефинноугорские (но их мало и они почти незаметны), так и параллели исключительно между эрзянским/мокшанским и венгерским (как будто венгерский заимствовал слова оттуда в эпоху миграций).


  1. chemyshev
    10.10.2022 11:13
    +2

    Я тоже собираю параллельные предложения. Русско-марийские. Пока собрали 369 тыс. предложений: https://cloud.mail.ru/public/apAp/pehZnrVU1


    1. averkij
      11.10.2022 11:03
      +1

      У вас пары текстов, которые нужно было бы выровнять? Например, какое-нибудь произведение на русском и его перевод на марийский или наоборот.


    1. averkij
      11.10.2022 13:37

      *есть пары текстов


  1. chemyshev
    10.10.2022 14:48
    +1

    Прошу прощения. Та ссылка битая. Обновил архив, забыл ссылку обновить: https://cloud.mail.ru/public/TgL1/Bj2LRU5ai