/simple-nmt

This repo contains a simple source code for advanced neural machine translation based on sequence-to-sequence.

Primary LanguagePython

Simple Neural Machine Translation (Simple-NMT)

This repo contains a simple source code for advanced neural machine translation based on sequence-to-sequence. Most open sources are unnecessarily too complicated, so those have too many features more than people's expected. Therefore, I hope that this repo can be a good solution for people who doesn't want unnecessarily many features.

In addition, this repo is for lecture and book, what I conduct. Please, refer those site for further information.

Features

Implemented Optimization Algorithms

Maximum Likelihood Estimation (MLE)

Minimum Risk Training (MRT)

Dual Supervised Learning (DSL)

Pre-requisite

Usage

I recommend to use corpora from AI-Hub, if you are trying to build Kor/Eng machine translation.

Training

>> python train.py -h
usage: train.py [-h] --model_fn MODEL_FN --train TRAIN --valid VALID --lang
                LANG [--gpu_id GPU_ID] [--off_autocast]
                [--batch_size BATCH_SIZE] [--n_epochs N_EPOCHS]
                [--verbose VERBOSE] [--init_epoch INIT_EPOCH]
                [--max_length MAX_LENGTH] [--dropout DROPOUT]
                [--word_vec_size WORD_VEC_SIZE] [--hidden_size HIDDEN_SIZE]
                [--n_layers N_LAYERS] [--max_grad_norm MAX_GRAD_NORM]
                [--iteration_per_update ITERATION_PER_UPDATE] [--lr LR]
                [--lr_step LR_STEP] [--lr_gamma LR_GAMMA]
                [--lr_decay_start LR_DECAY_START] [--use_adam] [--use_radam]
                [--rl_lr RL_LR] [--rl_n_samples RL_N_SAMPLES]
                [--rl_n_epochs RL_N_EPOCHS] [--rl_n_gram RL_N_GRAM]
                [--rl_reward RL_REWARD] [--use_transformer]
                [--n_splits N_SPLITS]

optional arguments:
  -h, --help            show this help message and exit
  --model_fn MODEL_FN   Model file name to save. Additional information would
                        be annotated to the file name.
  --train TRAIN         Training set file name except the extention. (ex:
                        train.en --> train)
  --valid VALID         Validation set file name except the extention. (ex:
                        valid.en --> valid)
  --lang LANG           Set of extention represents language pair. (ex: en +
                        ko --> enko)
  --gpu_id GPU_ID       GPU ID to train. Currently, GPU parallel is not
                        supported. -1 for CPU. Default=-1
  --off_autocast        Turn-off Automatic Mixed Precision (AMP), which speed-
                        up training.
  --batch_size BATCH_SIZE
                        Mini batch size for gradient descent. Default=32
  --n_epochs N_EPOCHS   Number of epochs to train. Default=20
  --verbose VERBOSE     VERBOSE_SILENT, VERBOSE_EPOCH_WISE, VERBOSE_BATCH_WISE
                        = 0, 1, 2. Default=2
  --init_epoch INIT_EPOCH
                        Set initial epoch number, which can be useful in
                        continue training. Default=1
  --max_length MAX_LENGTH
                        Maximum length of the training sequence. Default=100
  --dropout DROPOUT     Dropout rate. Default=0.2
  --word_vec_size WORD_VEC_SIZE
                        Word embedding vector dimension. Default=512
  --hidden_size HIDDEN_SIZE
                        Hidden size of LSTM. Default=768
  --n_layers N_LAYERS   Number of layers in LSTM. Default=4
  --max_grad_norm MAX_GRAD_NORM
                        Threshold for gradient clipping. Default=5.0
  --iteration_per_update ITERATION_PER_UPDATE
                        Number of feed-forward iterations for one parameter
                        update. Default=1
  --lr LR               Initial learning rate. Default=1.0
  --lr_step LR_STEP     Number of epochs for each learning rate decay.
                        Default=1
  --lr_gamma LR_GAMMA   Learning rate decay rate. Default=0.5
  --lr_decay_start LR_DECAY_START
                        Learning rate decay start at. Default=10
  --use_adam            Use Adam as optimizer instead of SGD. Other lr
                        arguments should be changed.
  --use_radam           Use rectified Adam as optimizer. Other lr arguments
                        should be changed.
  --rl_lr RL_LR         Learning rate for reinforcement learning. Default=0.01
  --rl_n_samples RL_N_SAMPLES
                        Number of samples to get baseline. Default=1
  --rl_n_epochs RL_N_EPOCHS
                        Number of epochs for reinforcement learning.
                        Default=10
  --rl_n_gram RL_N_GRAM
                        Maximum number of tokens to calculate BLEU for
                        reinforcement learning. Default=6
  --rl_reward RL_REWARD
                        Method name to use as reward function for RL training.
                        Default=gleu
  --use_transformer     Set model architecture as Transformer.
  --n_splits N_SPLITS   Number of heads in multi-head attention in
                        Transformer. Default=8

example usage:

Seq2Seq

>> python train.py --train ./data/corpus.shuf.train.tok.bpe --valid ./data/corpus.shuf.valid.tok.bpe --lang enko \
--gpu_id 0 --batch_size 128 --n_epochs 30 --max_length 100 --dropout .2 \
--word_vec_size 512 --hidden_size 768 --n_layers 4 --max_grad_norm 1e+8 --iteration_per_update 2 \
--lr 1e-3 --lr_step 0 --use_adam --rl_n_epochs 0 \
--model_fn ./model.pth

To continue with RL training

>> python continue_train.py --load_fn ./model.pth --model_fn ./model.rl.pth \
--init_epoch 31 --iteration_per_update 1 --max_grad_norm 5

Transformer

>> python train.py --train ./data/corpus.shuf.train.tok.bpe --valid ./data/corpus.shuf.valid.tok.bpe --lang enko \
--gpu_id 0 --batch_size 128 --n_epochs 30 --max_length 100 --dropout .2 \
--hidden_size 768 --n_layers 4 --max_grad_norm 1e+8 --iteration_per_update 32 \
--lr 1e-3 --lr_step 0 --use_adam --use_transformer --rl_n_epochs 0 \
--model_fn ./model.pth

Dual Supervised Learning

LM Training:

>> python lm_train.py --train ./data/corpus.shuf.train.tok.bpe --valid ./data/corpus.shuf.valid.tok.bpe --lang enko \
--gpu_id 0 --batch_size 256 --n_epochs 20 --max_length 64 --dropout .2 \
--word_vec_size 512 --hidden_size 768 --n_layers 4 --max_grad_norm 1e+8 \
--model_fn ./lm.pth

DSL using pretrained LM:

>> python dual_train.py --train ./data/corpus.shuf.train.tok.bpe --valid ./data/corpus.shuf.valid.tok.bpe --lang enko \
--gpu_id 0 --batch_size 64 --n_epochs 40 --max_length 64 --dropout .2 \
--word_vec_size 512 --hidden_size 768 --n_layers 4 --max_grad_norm 1e+8 --iteration_per_update 4 \
--dsl_n_warmup_epochs 30 --dsl_lambda 1e-2 \
--lm_fn ./lm.pth \
--model_fn ./model.pth

Note that I recommend to use different 'max_grad_norm value' (e.g. 5) for after warm-up training. You can use 'continue_dual_train.py' to change 'max_grad_norm' argument.

Inference

You can translate any sentence via standard input and output.

>> python translate.py -h
usage: translate.py [-h] --model_fn MODEL_FN [--gpu_id GPU_ID]
                    [--batch_size BATCH_SIZE] [--max_length MAX_LENGTH]
                    [--n_best N_BEST] [--beam_size BEAM_SIZE] [--lang LANG]
                    [--length_penalty LENGTH_PENALTY]

optional arguments:
  -h, --help            show this help message and exit
  --model_fn MODEL_FN   Model file name to use
  --gpu_id GPU_ID       GPU ID to use. -1 for CPU. Default=-1
  --batch_size BATCH_SIZE
                        Mini batch size for parallel inference. Default=128
  --max_length MAX_LENGTH
                        Maximum sequence length for inference. Default=255
  --n_best N_BEST       Number of best inference result per sample. Default=1
  --beam_size BEAM_SIZE
                        Beam size for beam search. Default=5
  --lang LANG           Source language and target language. Example: enko
  --length_penalty LENGTH_PENALTY
                        Length penalty parameter that higher value produce
                        shorter results. Default=1.2

example usage:

>> python translate.py --model_fn ./model.pth --gpu_id 0 --lang enko < test.txt > test.result.txt

You may also need to change the argument parameters.

Evaluation

Setup

In order to evaluate this project, I used public dataset from AI-HUB, which provides 1,600,000 pairs of sentence. I randomly split this data into train/valid/test set by following number of lines each. In fact, original test set, which has about 200000 lines, is too big to take bunch of evaluations, I reduced it to 1,000 lines. (In other words, you can get better model, if you put removed 200,000 lines into training set.)

set lang #lines #tokens #characters
train en 1,200,000 43,700,390 367,477,362
ko 1,200,000 39,066,127 344,881,403
valid en 200,000 7,286,230 61,262,147
ko 200,000 6,516,442 57,518,240
valid-1000 en 1,000 36,307 305,369
ko 1,000 32,282 285,911
test-1000 en 1,000 35,686 298,993
ko 1,000 31,720 280,126

Each dataset is tokenized with Mecab/MosesTokenizer and BPE. After preprocessing, each language has vocabulary size like as below:

en ko
20,525 29,411

Also, we have following hyper-parameters for each model to proceed a evaluation.

parameter seq2seq transformer
batch_size 320 4096
word_vec_size 512 -
hidden_size 768 768
n_layers 4 4
n_splits - 8
n_epochs 30 30

Below is a table for hyper-parameters for each algorithm.

parameter MLE MRT DSL
n_epochs 30 30 + 40 30 + 10
optimizer Adam SGD Adam
lr 1e-3 1e-2 1e-2
max_grad_norm 1e+8 5 1e+8 $\rightarrow$ 5

Please, note that MRT has different optimization setup.

Results

Following table shows a evaluation result for each algorithm.

enko koen
Sequence-to-Sequence 32.53 29.67
Sequence-to-Sequence (MRT) 34.04 31.24
Sequence-to-Sequence (DSL) 33.47 31.00
Transformer 34.96 31.84
Transformer (MRT) - -
Transformer (DSL) 35.48 32.80

As you can see, Transformer outperforms in ENKO/KOEN task. I couldn't run MRT on Transformer, due to lack of memory.

Following table shows the result based on beam-size on Sequence-to-Sequence model. Table shows that beam search improve BLEU score without data adding and model change.

beam_size enko koen
1 31.65 28.93
5 32.53 29.67
10 32.48 29.37

Samples

Below table shows that result from both MLE and MRT in Korean-English translation task.

INPUT REF MLE MRT
우리는 또한 그 지역의 생선 가공 공장에서 심한 악취를 내며 썩어가는 엄청난 양의 생선도 치웠습니다. We cleared tons and tons of stinking, rotting fish carcasses from the local fish processing plant. We also had a huge stink in the fish processing plant in the area, smelling havoc with a huge amount of fish. We also cleared a huge amount of fish that rot and rot in the fish processing factory in the area.
회사를 이전할 이상적인 장소이다. It is an ideal place to relocate the company. It's an ideal place to transfer the company. It's an ideal place to transfer the company.
나는 이것들이 내 삶을 바꾸게 하지 않겠어. I won't let this thing alter my life. I'm not gonna let these things change my life. I won't let these things change my life.
사람들이 슬퍼보인다. Their faces appear tearful. People seem to be sad. People seem to be sad.
아냐, 그런데 넌 그렇다고 생각해. No, but I think you do. No, but I think you do. No, but you think it's.
하지만, 나는 나중에 곧 잠들었다. But I fell asleep shortly afterwards. However, I fell asleep in a moment. However, I fell asleep soon afterwards.
하지만 1997년 아시아에 외환위기가 불어닥쳤다. But Asia was hit hard by the 1997 foreign currency crisis. In 1997, however, the financial crisis in Asia has become a reality for Asia. But in 1997, the foreign currency crisis was swept in Asia.
메이저 리그 공식 웹사이트에 따르면, 12월 22일, 추씨는 텍사스 레인져스와 7년 계약을 맺었다. According to Major League Baseball's official website, on Dec. 22, Choo signed a seven year contract with the Texas Rangers. According to the Major League official website on December 22, Choo signed a seven-year contract with Texas Rangers in Texas According to the Major League official website on December 22, Choo made a seven-year contract with Texas Rangers.
한 개인. a private individual a person of personal importance a personal individual
도로에 차가 꼬리를 물고 늘어서있다. The traffic is bumper to bumper on the road. The road is on the road with a tail. The road is lined with tail on the road.
내가 그렇게 늙지 않았다는 점을 지적해도 될까요. Let me point out that I'm not that old. You can point out that I'm not that old. You can point out that I'm not that old.
닐슨 시청률은 15분 단위 증감으로 시청률을 측정하므로, ABC, NBC, CBS 와 Fox 의 순위를 정하지 않았다. Nielsen had no ratings for ABC, NBC, CBS and Fox because it measures their viewership in 15-minute increments. The Nielsen ratings measured the viewer's ratings with increments for 15-minute increments, so they did not rank ABC, NBC, CBS and Fox. Nielson ratings measured ratings with 15-minute increments, so they did not rank ABC, NBC, CBS and Fox.
다시말해서, 학교는 교사 부족이다. In other words, the school is a teacher short. In other words, school is a teacher short of a teacher. In other words, school is a lack of teacher.
그 다음 몇 주 동안에 사태가 극적으로 전환되었다. Events took a dramatic turn in the weeks that followed. The situation has been dramatically changed for the next few weeks. The situation was dramatically reversed for the next few weeks.
젊은이들을 물리학에 대해 흥미를 붙일수 있게 할수 있는 가장 좋은 사람은 졸업생 물리학자이다. The best possible person to excite young people about physics is a graduate physicist. The best person to be able to make young people interested in physics is a self-thomac physicist. The best person to make young people interested in physics is a graduate physicist.
5월 20일, 인도는 팔로디 마을에서 충격적인 기온인 섭씨 51도를 달성하며, 가장 더운 날씨를 기록했습니다. On May 20, India recorded its hottest day ever in the town of Phalodi with a staggering temperature of 51 degrees Celsius. On May 20, India achieved its hottest temperatures, even 51 degrees Celsius, in the Palrody village, and recorded the hottest weather. On May 20, India achieved 51 degrees Celsius, a devastating temperature in Paldydy town, and recorded the hottest weather.
내말은, 가끔 바나는 그냥 바나나야. I mean, sometimes a banana is just a banana. I mean, sometimes a banana is just a banana. I mean, sometimes a banana is just a banana.

References