Использование OpenNMT-py для создания базовых моделей NMT

Последовательность-последовательность (seq2seq) [1] - это универсальная структура, способная на многие вещи (языковой перевод, резюмирование текста [2], субтитры к видео [3] и т. Д.). Вот несколько хороших постов для краткого введения в seq2seq: [4] [5].

Учебная тетрадь [6] Шона Робертсона и лекции Джереми Ховарда [6] [7] - отличные отправные точки, чтобы получить твердое представление о технических деталях seq2seq. Однако я бы старался не реализовывать все эти детали самостоятельно при решении реальных проблем. Обычно не стоит изобретать велосипед, особенно если вы новичок в этой области. Я обнаружил, что проект OpenNMT очень активен, имеет хорошую документацию и может использоваться сразу после установки:



Есть также несколько более общих фреймворков (например, [8]), но, возможно, потребуется некоторая настройка, чтобы заставить их работать с вашей конкретной проблемой.

Есть две официальные версии OpenNMT:

OpenNMT-Lua (он же OpenNMT): основной проект, разработанный с LuaTorch.
Оптимизированный и стабильный код для производства и крупномасштабных экспериментов.

OpenNMT-py: облегченная версия OpenNMT с использованием PyTorch.
Первоначально созданная исследовательской группой Facebook AI в качестве образца проекта для PyTorch, эта версия легче расширяется и подходит для исследовательских целей, но не включает все функции.

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

Шаг 1. Получите OpenNMT-py

Клонируйте репозиторий OpenNMT-py git на Github в локальную папку:



Возможно, вы захотите разветвить репозиторий на Github, если планируете позже настроить или расширить его. Также в README предлагается:

Codebase приближается к стабильной версии 0.1. В настоящее время мы рекомендуем форк, если вам нужен стабильный код.

Шаг 2. Загрузите набор данных

Здесь мы собираемся использовать набор данных из AI Challenger - англо-китайский конкурс машинного перевода. Это набор данных с 10 миллионами пар предложений английский-китайский. English copora - это разговорный английский, извлеченный из веб-сайтов, изучающих английский, и субтитров к фильмам. Насколько я понимаю, большая часть переводов представлена ​​энтузиастами, не обязательно профессионалами. Переведенные китайские предложения проверяются аннотаторами.



Для загрузки набора данных требуется регистрация аккаунта и, возможно, подтверждение личности (не помню, является ли последнее обязательным). Если для вас это проблема, вы можете попробовать наборы данных из WMT17.

С набором данных AI Challenger есть некоторые проблемы: 1. Качество перевода нестабильно. 2. Поскольку многие предложения взяты из субтитров фильмов, перевод часто зависит от контекста (связан с предыдущим или следующим предложением). Однако в наборе данных нет доступной контекстной информации.

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

(Предположим, вы поместили набор данных в папку challenger в корневом каталоге OpenNMT.)

Шаг 3. Преобразуйте набор данных в обычный текст

Набор данных для проверки и тестирования поставляется в формате XML. Нам нужно преобразовать его в простые текстовые файлы, где строка состоит из одного предложения. Простой способ сделать это - использовать BeautifulSoup. Вот образец кода:

with open(input_file, "r") as f:
    soup = BeautifulSoup(f.read(), "lxml")
    lines = [
      (int(x["id"]), x.text.strip()) for x in soup.findAll("seg")]
    # Ensure the same order
    lines = sorted(lines, key=lambda x: x[0])

Шаг 4. Токенизация предложений на английском и китайском языках

Входное предложение должно быть размечено токенами, разделенными пробелами.

Для английского языка есть несколько токенизаторов на выбор. Один из примеров - nltk.tokenize.word_tokenize:

with open(output_file, "w") as f:
    f.write(
        "\n".join([
             " ".join(word_tokenize(l[1]))
             for l in lines
         ])
    )

Получается: «Отличный раз, два. Уокер - Бертону. в «Это аккуратный один - два. Уокер - Бертону ».

Для китайского языка мы используем простейшую токенизацию на уровне символа, то есть обрабатываем каждый символ как токен:

with open(output_file, "w") as f:
    f.write(
        "\n".join([
            " ".join([c if c != " " else "<s>" for c in l[1]])
            for l in lines
        ])
    )

Он превращает «就 一天 24 小时 都得 在 她 眼皮 子 底下。» в «就 一 天 2 4 小 时 都 得 在 眼 皮 子 下。». (Обратите внимание, поскольку токены разделены пробелами, нам нужен специальный токен «‹s›» для представления пробелов.)

(Я не предоставил полный код для шагов 3 и 4, потому что это действительно программирование на Python для начинающих. Вы должны быть в состоянии выполнить эти задачи самостоятельно.)

Шаг 5. Предварительная обработка набора данных

Просто запустите следующую команду в корневом каталоге:

python preprocess.py -train_src challenger/train.en.sample \
      -train_tg challenger/train.zh.sample \
      -valid_src challenger/valid.en \
      -valid_tgt challenger/valid.zh  \
      -save_data challenger/opennmt -report_every 10000

Сценарий предварительной обработки просматривает набор данных, отслеживает частоту токенов и создает список словаря. У меня возникла проблема с памятью, и мне пришлось уменьшить выборку обучающего набора данных до 1 миллиона строк, но я думаю, что необработанный набор данных должен уместиться в 16 ГБ памяти с некоторой оптимизацией.

Шаг 6. Обучите модель

python train.py -data challenger/opennmt \
    -save_model models/baseline -gpuid 0 \
    -learning_rate 0.001 -opt adam -epochs 20

Он будет использовать ваш первый графический процессор для обучения модели. Структура модели по умолчанию:

NMTModel (
  (encoder): RNNEncoder (
    (embeddings): Embeddings (
      (make_embedding): Sequential (
        (emb_luts): Elementwise (
          (0): Embedding(50002, 500, padding_idx=1)
        )
      )
    )
    (rnn): LSTM(500, 500, num_layers=2, dropout=0.3)
  )
  (decoder): InputFeedRNNDecoder (
    (embeddings): Embeddings (
      (make_embedding): Sequential (
        (emb_luts): Elementwise (
          (0): Embedding(6370, 500, padding_idx=1)
        )
      )
    )
    (dropout): Dropout (p = 0.3)
    (rnn): StackedLSTM (
      (dropout): Dropout (p = 0.3)
      (layers): ModuleList (
        (0): LSTMCell(1000, 500)
        (1): LSTMCell(500, 500)
      )
    )
    (attn): GlobalAttention (
      (linear_in): Linear (500 -> 500)
      (linear_out): Linear (1000 -> 500)
      (sm): Softmax ()
      (tanh): Tanh ()
    )
  )
  (generator): Sequential (
    (0): Linear (500 -> 6370)
    (1): LogSoftmax ()
  )
)

Объем словарного запаса исходного и целевого корпусов составляет 50 002 и 6 370 соответственно. Исходный словарь явно сокращен до 50 000. Целевой словарный запас относительно невелик, потому что в нем не так много распространенных китайских иероглифов.

Шаг 7. Переведите предложения по тестированию / проверке

python translate.py \
    -model models/baseline_acc_58.79_ppl_7.51_e14  \
    -src challenger/valid.en -tgt challenger/valid.zh \
    -output challenger/valid_pred.58.79 -gpu 0 -replace_unk

Замените models/baseline_acc_58.79_ppl_7.51_e14 своей собственной моделью. Название модели должно быть очевидным: это модель после 14 эпох обучения с точностью 58,79 и недоумением 7,51 на проверочном наборе.

Вы также можете рассчитать балл BLEU следующим образом:

wget https://raw.githubusercontent.com/moses-smt/mosesdecoder/master/scripts/generic/multi-bleu.perl
perl multi-bleu.perl challenger/valid.zh \
     < challenger/valid_pred.58.79

Теперь у вас есть работающая система перевода!

Шаг 8: (Необязательно) Детокенизация и преобразование вывода

Если вы хотите отправить перевод в AI Challenger, вам нужно отменить Шаг 4, а затем Шаг 3. Опять же, они должны быть довольно простыми в реализации.

Некоторые примеры

Английский: Ты знал в глубине души, что не мыл волосы
Китайский (пред.): 你 心里 清楚 你 没 洗头发
Китайский (золотой): 你 心里 知道 你 压根 就没 洗过 头

Английский: Я никогда не мечтал, что один из моих учеников поступит в университет, но вот я стою,
Китайский (пред.): 我 从来 没 梦到 的 的 一个 人 会 去 大学 , 但是 我 站在 这里 ,
Китайский (золотой): 我 从没 想过 我 的 孩子 会上 大学 , 但 我 站在 这 ,

Английский: У нас просто нет времени тратить не на того человека.
Китайский (пред.): 我们 只是 没 时间 浪费 人。
Китайский (золотой): 如果 找 错 了 人 我们 可玩 不 起。

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

Следующий шаг

Если вы отправите результат, вы должны получить около .22 BLEU. Текущий наивысший показатель BLEU - 0,33, так что есть много возможностей для улучшения. Дополнительные параметры встроенной модели можно найти в opts.py в корневой папке. Или погрузитесь в кодовую базу, чтобы понять, как все работает и что можно улучшить.

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

(Обновление от 2017/10/14: если вы используете jieba и jieba.cut с настройками по умолчанию для токенизации китайского предложения, вы получите .20 BLEU на общедоступном лидере. Одна из возможных причин падения оценок - это гораздо больший объем китайского словаря. Об этом можно судить по количеству ‹unk› в выводе.)

Использованная литература:

  1. Суцкевер, И., Виньялс, О., и Ле, К. В. (2014). Последовательность для последовательного обучения с помощью нейронных сетей .
  2. Наллапати, Р., Чжоу, Б., душ Сантуш, К., и Сян, Б. (2016). Резюмирование абстрактного текста с использованием RNN «последовательность-последовательность и не только ».
  3. Венугопалан, С., Рорбах, М., Донахью, Дж., Муни, Р., Даррелл, Т., и Саенко, К. (2015). От последовательности к последовательности
  4. От последовательности к модели последовательности: Введение и концепции
  5. Seq2seq: клоунская машина глубокого обучения
  6. Практический PyTorch: перевод с последовательности на последовательность последовательностей и внимание
  7. Передовое глубокое обучение для программистов, часть 2, лекция 12 - Модели внимания
  8. Передовое глубокое обучение для программистов, часть 2, лекция 13 - Нейронный перевод
  9. Google / seq2seq: универсальный фреймворк кодировщика-декодера для Tensorflow
  10. Словарь произношения CMU