Как создать переводчик, который переводит лучше, чем Google Translate +46


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

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

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

Я программирую на python, и в python есть отличная библиотека translators. Данная библиотека позволяет использовать множество различных сервисов по переводу. Причем абсолютно бесплатно. Однако, все же данное решение не идеально по нескольким причинам:

  1. Перевод выполняется достаточно долго.

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

  3. Качество перевода не самое высокое, как я это проверял, я расскажу в своей статье ниже.

Конечно же, не стоит изобретать велосипед, поэтому я стал использовать отличное готовое решение Argos Translate. Это open-source бесплатное решение для машинного перевода. Поддерживается огромное количество языков. Может работать в разных режимах: и как десктоп приложение, и как веб приложение, и как библиотека к python.

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

Автор проекта Argos Translate поставляет свой скрипт обучения, доступный всем желающим. Для обучения своей модели я взял его за основу, однако в процессе несколько его видоизменил. Далее я покажу основные составляющие процесса обучения модели машинного перевода и разобью их на составные части для лучшего понимания.

Этап 1: Подготовка данных для обучения

Для обучения модели машинного перевода необходимо большое количество параллельных корпусов текстов, к счастью, в сети есть очень большое количество параллельных корпусов текста, за основу я взял датасеты с сайта https://opus.nlpl.eu/

В качестве данных для обучения я использовал список корпусов текстов: ada83.en-ru, bible-uedin.en-ru, Books.en-ru, CCMatrix.en-ru, ELRC_2922.en-ru, EUbookshop.en-ru, GlobalVoices.en-ru, GNOME.en-ru, infopankki.en-ru, KDE4.en-ru, MultiUN.en-ru, News-Commentary.en-ru, OpenSubtitles.en-ru, ParaCrawl.en-ru, PHP.en-ru, QED.en-ru, Tanzil.en-ru, Tatoeba.en-ru, TED2013.en-ru, TED2020.en-ru, tico-19.en-ru, TildeMODEL.en-ru, Ubuntu.en-ru, UN.en-ru, WikiMatrix.en-ru, wikimedia.en-ru, WMT-News.en-ru

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

Для последующей тренировки все данные нам необходимо собрать в файлы:

  1. src-train.txt - все исходные предложения на русском языке,

  2. tgt-train.txt - все переводы предложений на английском языке,

  3. all.txt - все предложения корпуса на двух языках, данный файл необходим для генерации общего словаря,

  4. src-val.txt - 2000 предложений для валидации,

  5. tgt-val.txt - 2000 переводов предложений для валидации.

Этап 2: Генерация словаря токенов

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

Библиотека для тренировки использует yml конфигурационные файлы, в которых описываются параметры тренировки модели.

Я использовал стандартный конфиг из репозитория argos-train: https://github.com/argosopentech/argos-train/blob/master/config.yml

В моделях перевода argos translate используется общий словарь для обоих языков.

Для генерации словаря, используется следующий скрипт, в нем берутся первые 10 млн случайных предложений из корпуса, и генерируется из них словарь размером в 50 тысяч токенов.

#!/bin/bash
spm_train --input=run/split_data/all.txt --model_prefix=run/sentencepiece --vocab_size=50000 --character_coverage=0.9995 --input_sentence_size=10000000 --shuffle_input_sentence=true --split_digits

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

Для перевода модели токенизатора SentencePiece в словарь модели используется команда:

#!/bin/bash
onmt_build_vocab -config config.yml -n_sample -1

и часть конфига отвечающая за формирование словаря:

#config.yml

## Where the samples will be written
save_data: run/opennmt_data
## Where the vocab(s) will be written
src_vocab: run/opennmt_data/openmt.vocab
tgt_vocab: run/opennmt_data/openmt.vocab


# Should match the vocab size for SentencePiece
# https://forum.opennmt.net/t/opennmt-py-error-when-training-with-large-amount-of-data/4310/12?u=argosopentech
src_vocab_size: 50000
tgt_vocab_size: 50000

share_vocab: True

# Corpus opts:
data:
    corpus_1:
        path_src: run/split_data/src-train.txt
        path_tgt: run/split_data/tgt-train.txt
        transforms: [sentencepiece, filtertoolong]
    valid:
        path_src: run/split_data/src-val.txt
        path_tgt: run/split_data/tgt-val.txt
        transforms: [sentencepiece, filtertoolong]


### Transform related opts:
#### https://opennmt.net/OpenNMT-py/FAQ.html#how-do-i-use-the-transformer-model
#### Subword
src_subword_model: run/sentencepiece.model
tgt_subword_model: run/sentencepiece.model
src_subword_nbest: 1
src_subword_alpha: 0.0
tgt_subword_nbest: 1
tgt_subword_alpha: 0.0
#### Filter
src_seq_length: 150
tgt_seq_length: 150

Этап 3: Тренировка модели

В качестве архитектуры обучаемой модели используется архитектура трансформера, состоящая из кодировщика и декодировщика, каждый размером 6 слоев. 8 голов самовнимания. Размером эмбединга – 512, и размером скрытого связующего состояния между кодировщиком и декодировщиком – 2048.

#config.yml

# Model
encoder_type: transformer
decoder_type: transformer
position_encoding: true
enc_layers: 6
dec_layers: 6
heads: 8
rnn_size: 512
word_vec_size: 512
transformer_ff: 2048
dropout_steps: [0]
dropout: [0.1]
attention_dropout: [0.1]

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

Для запуска процесса обучения используется команда:

#!/bin/bash
onmt_train -config config.yml

Обучение моей модели длилось 100 000 шагов и в общем случае занимает от 2 до 5 дней, в зависимости от конфигурации оборудования.

Этап 4: Тестирование качества модели

После обучения нам необходимо проверить, насколько хорошо переводит наша модель.

Для оценки качества модели я использовал отдельный параллельный корпус "Yandex Translate corpus 1m version 1.3" размером в 1 млн пар предложений, в качестве метрики я использовал метрику BLEU Score.

Я использовал следующий скрипт для тестирования модели

#!/bin/bash
#тестирование модели по метрике BLEU
#https://opennmt.net/OpenNMT-py/examples/Translation.html?highlight=bleu

echo "Step 001 Токенизируем наш корпус тестирования" 

spm_encode --model=run/sentencepiece.model \
     < argos-train/csv/test_crps/src-test.txt \
     > argos-train/csv/test_crps/src-test.txt.sp
spm_encode --model=run/sentencepiece.model \
     < argos-train/csv/test_crps/tgt-test.txt \
     > argos-train/csv/test_crps/tgt-test.txt.sp

echo "Step 002 Переведем наш корпус с помощью модели"

for checkpoint in run/openmt.model_step*.pt; do
    echo "# Translating with checkpoint $checkpoint"
    base=$(basename $checkpoint)
    onmt_translate \
        -gpu 0 \
        -batch_size 8192 -batch_type tokens \
        -beam_size 5 \
        -model $checkpoint \
        -src argos-train/csv/test_crps/src-test.txt.sp \
        -tgt argos-train/csv/test_crps/tgt-test.txt.sp \
        -output run/wmt/test.ru.hyp_${base%.*}.sp
done

echo "Step 003 Декодируем перевод из токенов обратно в текст"

for checkpoint in run/openmt.model_step*.pt; do
    base=$(basename $checkpoint)
    spm_decode \
        -model=run/sentencepiece.model \
        -input_format=piece \
        < run/wmt/test.ru.hyp_${base%.*}.sp \
        > run/wmt/test.ru.hyp_${base%.*}
done

echo "Step 004 Сравним два корпуса по оценке BLEU Score"

for checkpoint in run/openmt.model_step*.pt; do
    echo "$checkpoint"
    base=$(basename $checkpoint)
    sacrebleu argos-train/csv/test_crps/tgt-test.txt < run/wmt/test.ru.hyp_${base%.*}
done

echo "Step End"

По итогам обучения моя модель получила метрику BLEU: 21.6

Для сравнения с другим переводчиком, я перевел 1 млн предложений из тестового корпуса Yandex через библиотеку translators, переводчиком Google Translate.

Отдельно сравнил качество с помощью команды:

#!/bin/bash
sacrebleu argos-train/csv/test_crps/tgt-test.txt < argos-train/csv/test_crps/tgt-test_google.txt

В итоге получил метрику BLEU Score полученного перевода бесплатного Google переводчика BLEU: 18.7

Что означает, что полученная мною модель переводит с русского на английский лучше, чем бесплатный Google Translate.

Этап 5: Упаковываем модель в Argos Translate

Для упаковки модели в формат Argos Translate, необходимо выполнить ряд преобразований.

  1. Конвертация модели из checkpoint:

    #!/bin/bash
    ./../OpenNMT-py/tools/average_models.py -m run/openmt.model_step_100000.pt run/openmt.model_step_100000.pt -o run/averaged.pt
  2. Квантизация модели:

#!/bin/bash
ct2-opennmt-py-converter --model_path run/averaged.pt --output_dir run/model --quantization int8
  1. Конвертация модели в формат argos translate:

    #!/usr/bin/env python3
    
    from pathlib import Path
    import json
    import subprocess
    import shutil
    import sys
    
    import argostrain
    from argostrain.dataset import *
    from argostrain import data
    from argostrain import opennmtutils
    from argostrain import settings
    
    import stanza
    
    from_code = input("From code (ISO 639): ")
    to_code = input("To code (ISO 639): ")
    from_name = input("From name: ")
    to_name = input("To name: ")
    version = input("Version: ")
    package_version = version
    argos_version = "1.5"
    
    package_version_code = package_version.replace(".", "_")
    model_dir = f"translate-{from_code}_{to_code}-{package_version_code}"
    model_path = Path("run") / model_dir
    
    subprocess.run(["mkdir", model_path])
    
    subprocess.run(["cp", "-r", "run/model", model_path])
    
    subprocess.run(["cp", "run/sentencepiece.model", model_path])
    
    # Include a Stanza sentence boundary detection model
    stanza_model_located = False
    stanza_lang_code = from_code
    while not stanza_model_located:
        try:
            stanza.download(stanza_lang_code, dir="run/stanza", processors="tokenize")
            stanza_model_located = True
        except:
            print(f"Could not locate stanza model for lang {stanza_lang_code}")
            print(
                "Enter the code of a different language to attempt to use its stanza model."
            )
            print(
                "This will work best for with a similar language to the one you are attempting to translate."
            )
            print(
                "This will require manually editing the Stanza package in the finished model to change its code"
            )
            stanza_lang_code = input("Stanza language code (ISO 639): ")
    
    
    subprocess.run(["cp", "-r", "run/stanza", model_path])
    
    subprocess.run(["cp", "run/metadata.json", model_path])
    subprocess.run(["cp", "run/README.md", model_path])
    
    package_path = (
        Path("run") / f"translate-{from_code}_{to_code}-{package_version_code}.argosmodel"
    )
    
    shutil.make_archive(model_dir, "zip", root_dir="run", base_dir=model_dir)
    subprocess.run(["mv", model_dir + ".zip", package_path])
    
    # Make .argoscheckpoint zip
    
    latest_checkpoint = opennmtutils.get_checkpoints()[-1]
    print(latest_checkpoint)
    print(latest_checkpoint.name)
    print(latest_checkpoint.num)
    
    print(f"Package saved to {str(package_path.resolve())}")

Далее мы получаем готовую модель файла в виде "translate-en_ru-1_7.argosmodel", которую можно подгрузить и использовать в продукте Argos Translate.

В качестве заключения

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

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

Так как продукт Argos Translate является бесплатным, то я поделился с сообществом своей обученной моделью в комьюнити продукта. Разработчики Argos Translate приняли мою модель Russian - English и включили в основной репозиторий моделей машинного перевода в качестве основной модели под версией 1.7.

Если у вас есть идеи, как еще можно улучшить качество перевода данной модели, пишите их в комментариях, и мы вместе сможем еще сильнее улучшить данную модель!

Эксперт по Машинному обучению в IT-компании Lad.




Комментарии (17):

  1. SmallDonkey
    /#24758152 / +2

    Попробовал en > ru, шикарно переводит кстати.

  2. sukhe
    /#24758200 / +4

    В OpusMT есть готовая пара английский-русский с BLEU выше 23.5.
    Вы Opus не рассматривали или Argos оказался лучше?

    • UtrobinMV
      /#24759432 / +1

      Спасибо за предложение, да можно посмотреть на модель OpusMT и сравнить.

      В данном случае метрика меряется на каждом корпусе пар предложений. Даже в приведенной вами ссылке видно, что у модели разные метрики для каждого корпуса. Я свою метрику получил, после того как протестил на корпусе от Яндекса в 1 млн пар предложений. Для того, чтобы сравнить модель OpusMT нужно её прогнать через корпус от Yandex, но с этим нужно время чтобы разобраться.

      Мне бы больше подошел вариант, прогнать мою модель через корпус один или несколько из Benchmark от OPUS, например newstest2013.en.ru и посмотреть на метрики. Постараюсь сделать это в ближайшее время и отпишусь с результатом.

      Однако в данном случае в плане применимости Argos Translate точно удобнее, так как это готовое решение по переводу.

      • BInc
        /#24761162 / +1

        В плане применимости Argos Translate точно удобнее, так как это готовое решение по переводу.

        Для меня OPUS — намного более готовое решение. Для него уже написаны модули для основных CAT-программ, в которых обычно выполняется перевод, в частности Trados Studio и memoQ. Применить в них Argos можно, но это требует дополнительных усилий.

    • UtrobinMV
      /#24762814 / +3

      Как и обещал я протестировал свою модель на корпусе newtest2013.en.ru

      И метрика BLEU показала 24.0, что в целом несколько лучше чем результаты из бенчмарка от модели OpusMT 23.5, по приведенной ссылке

  3. niccolo2019
    /#24759636 / +1

    Скачал и посмотрел несколько TMX из набора - и первое, не трогая алгоритмы — исходное сырьё не очень... Я с коллегой веду топик по техническим ТМХ здесь http://forum.ru-board.com/topic.cgi?forum=93&topic=4071&start=100#lt. Можете заходить пообщаться.

    Поэтому первое, что можно/нужно сделать — тщательно проверить ТМХ и очистить их от дубликатов и мусора. Учитывая то, что менеджментом копилок переводов часто занимаются люди, очень слабо понимающие суть вопроса, я не видел больших беспроблемных TMX.

    Второе - учитывая разную стилистику разнотипных документов - художка, инструкции/руководства, стандарты, научпоп, реклама, локализация софта — очевидно необходимо развести эти специализации/направления, как сделано в Промт.
    Очевидно - разработкой некоторых направлений, например - стандартов - можно заинтересовать серьёзных госзаказчиков.... Насколько знаю - сейчас в Росатоме занимаются чем-то подобным для оффлайна/ЛВС, начиная от распознавания изображений и до перевода.

    Третье - для контроля/выявления слабых мест - крайне желательно привести GUI приложения к стандартному табличному виду большинства CAT-tools (или добавить такой вид) и добавить поддержку основных обменных форматов - 2-колоночного RTF и Xliff во всех его разновидностях, либо написать плагины для CAT - для выявления огрехов/пополнения баз в процессе работы.

    1. По опыту с CAT - огромную роль для правильного перевода играет правильная сегментация - разбивка текста на самодостаточные для перевода логические единицы - обычно предложения... ТМХы как раз часто содержат переводы предложений, разбитых абы как.... Опять таки - табличный вид позволяет лучше видеть эту проблему...


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

    А гуйный портабельный (exe) вариант Аргуса для W7 - можно как-то или где-то увидеть? А то не силён я во всём этом, особенно учитывая то, что последние версии Питона на W7 уже не ставятся...

  4. Wesha
    /#24759730 / +2

    У меня к этому переводчику один вопросик: как там мухи времени, всё ещё любят стрелу?

  5. snakers4
    /#24759946 / +1

    Неплохо!

    Когда рассматривал чем заниматься в ML, не занимался машинным переводом, как раз потому, что мне казалось, что он стал commodity и что задача "решена". Судя по всему commodity он еще не стал, но с появлением CC matrix и собранном в одном месте списком корпусов, все стало сильно проще. Это очень круто!

    А в процессе работы с моделью, вы не интересовались, какой вообще максимальной возможный BLEU на этом датасете на этой языковой паре? Может вы замеряли точность какого-то платного переводчика, Яндекса или deepl?

    Обучение моей модели длилось 100 000 шагов и в общем случае занимает от 2 до 5 дней, в зависимости от конфигурации оборудования.

    Если не секрет, какое это железо? Хочется примерно прикинуть стоимость такой модели.

    И самый интересный вопрос, вы замеряли скорость инференса на CPU и на GPU? Обычно рекуррентные модели довольно медленные.

  6. vtal007
    /#24760070 / +1

    А обратно сможет? с англ на русский? или это разные задачи

    • niccolo2019
      /#24760078

      Сможет. Нужно только датасет и обучить машину. Как вариант датасета - реверс текущего

  7. konst90
    /#24760196 / +2

    Тогда возникает резонный вопрос: если это так просто, почему этого не сделал Google?

    • niccolo2019
      /#24763308

      Чёт я вас не понимаю - модель для перевода EN-RU - англо-русский? У гугля эта пара давно есть. Была и обратная (насколько помню по использованию Qtranslate)...

      • vtal007
        /#24763450

        вопрос наверно в том

        1. Почему гугл не может также прогнать нейросеткой и улучшить свой перевод

        2. Или же у гугла ещ лучше показатели. Тогда зачем это делать (что делал автор) Правда перевод гугла желает лучшего Из переводчиков, мне сейчас Deepl больше всех нравится. Без понятия, какие там результаты по бенчмаркам, но ощутимо лучше чем яндекс или гугл

      • konst90
        /#24763790

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

        • niccolo2019
          /#24764398

          А что в гугле одни гении работают? Глядя на некоторые книги «digitized by Google» — таких рукожопов ещё надо поискать...

          Гугл сейчас во многих вещах - у семи нянек дитя без глазу..... — Говёнские хромбуки, деградация с Пикселем, Edge начинает превосходить Хром, Дипл с его гораздо меньшими ресурсами, но направленными на одну цель тоже обошёл гугл......
          Типичная беда больших компаний....
          Осталось дождаться, когда китайцы развернутся во всю мощь и просто перестанут ставить андроид на свои смарты.....Дальше начнётся медленное забивание гвоздей в гроб гугля.

  8. niccolo2019
    /#24763646

    1. Почему гугл не может также прогнать нейросеткой и улучшить свой перевод

      Объяснений может быть масса
      1) Состав контрольного датасета - чем сильнее он отличается от датасета для натаскивания - тем хуже будет результат

      2) Более совершенные алгоритмы. Русский язык довольно проблемный для МП и наличие в команде грамотных русских специалистов легко может вывести команду вперёд именно на данном направлении, что мы видим по Finereader - по качеству распознавания, по работе с восточными языками, по разным откликам, он уже уступает конкурентам, но для работы с русским языком он пока остаётся лучшим.

      3) В разной степени неудачные датасеты для тренировки МП, а может намеренно испорченные или «отравленные» (poisoned -как говорят в ИТ). Про проблемы датасетов, полученных от переводческих компаний я уже писал.

      Если вы воспитаны на советской литературе - МП, натаскиваемый в большинстве своём на более слабых современных переводах, может и вообще не зайти.


      4) А судьи кто - кому-то нравится Блок, кому-то Маяковский.... Под такой русский и будут затачивать МП создатели. И вот представьте - вы поклонник Блока, сталкиваетесь с МП, натасканной поклонником Маяковского...

    2. Зачем делать? Ситуацию сегодняшнего дня вы прекрасно видите... Качество МП, если еще не идеальное, то уже можно сказать - годное для работы/обработки и сокращающее затраты времени на перевод. В технике МП часто даёт результат лучше, чем выпускники ИИЯ. Поэтому интерес к нему растёт, но не всех устраивают ОНЛАЙН-платформы МП из-за проблем с конфиденциальностью. Поэтому есть довольно большой интерес к ОФФЛАЙН МП...
      Полагаю подготовка датасета РУС-КИТ и натаскивание МП на нём сегодня является очень актуальной и, вероятнр коммерчески выгодной, задачей....

    3. Deepl ..... ощутимо лучше чем яндекс или гугл — Опять таки чисто на ваших примерах и под ваше понимание ХОРОШЕГО РУССКОГО ЯЗЫКА.

      Я когда-то сравнивал Гугл с Диплом на абзаце из технической книжки - и кардинальных отличий не заметил. Где-то гугл угадал терминологию, где-то Дипл. Построение предложений в обеих системах было одинаковым....

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