Помню, как еще в школе на Basic я писал программу-переводчик. И это было то время, когда ты сам составлял словарь, зашивал перевод каждого слова, а затем разбивал строки на слова и переводил каждое слово в отдельности. В то время я, конечно же, не мог и представить, как сильно продвинутся технологии, и программы-переводчики станут в основе использовать механизмы глубокого обучения с архитектурой трансформера и блоками внимания.
В этот раз я решил окунуться немного в прошлое и сделать то, что хорошо сделать тогда у меня не получилось.
В современных задачах системы перевода нужны достаточно часто, а специалисту, занимающемуся машинным обучением, возможно чаще, чем в других видах деятельности. Потребность в переводчике стала мне необходима, и я решил прибегнуть к использованию облачных решений, в частности Google Translate.
Я программирую на python, и в python есть отличная библиотека translators. Данная библиотека позволяет использовать множество различных сервисов по переводу. Причем абсолютно бесплатно. Однако, все же данное решение не идеально по нескольким причинам:
Перевод выполняется достаточно долго.
При большом количестве запросов, переводчик начинает пропускать предложения, т.е. оставляет их в непереведенном виде. Причем никаких ошибок при этом не выводится.
Качество перевода не самое высокое, как я это проверял, я расскажу в своей статье ниже.
Конечно же, не стоит изобретать велосипед, поэтому я стал использовать отличное готовое решение 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 млн пар предложений.
Для последующей тренировки все данные нам необходимо собрать в файлы:
src-train.txt - все исходные предложения на русском языке,
tgt-train.txt - все переводы предложений на английском языке,
all.txt - все предложения корпуса на двух языках, данный файл необходим для генерации общего словаря,
src-val.txt - 2000 предложений для валидации,
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 2048 -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, необходимо выполнить ряд преобразований.
Конвертация модели из 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
Квантизация модели:
#!/bin/bash
ct2-opennmt-py-converter --model_path run/averaged.pt --output_dir run/model --quantization int8
Конвертация модели в формат 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.