1. 程式人生 > 實用技巧 >利用Fairseq訓練新的機器翻譯模型

利用Fairseq訓練新的機器翻譯模型

利用Fairseq訓練一個新的機器翻譯模型,官方機器翻譯(German-English)示例:Fairseq-Training a New Model

資料預處理

進入fairseq/examples/translation目錄下,執行sh prepare-iwslt14.shprepare-iwslt14.sh主要執行以下幾個步驟。

下載資料

echo 'Cloning Moses github repository (for tokenization scripts)...'
git clone https://github.com/moses-smt/mosesdecoder.git

echo 'Cloning Subword NMT repository (for BPE pre-processing)...'
git clone https://github.com/rsennrich/subword-nmt.git

...

URL="https://wit3.fbk.eu/archive/2014-01/texts/de/en/de-en.tgz"
GZ=de-en.tgz

...

wget "$URL"

主要下載3個數據,分別是英德雙語語料,以及mosesdecodersubword_nmt兩個工具庫。

  • mosesdecoder是機器翻譯中常用的工具,裡面包含了很多有用的指令碼。

  • subword_nmt根據訓練資料建立subword詞表,以及對訓練集、測試集、驗證集切分成subword的形式。

資料清洗


SCRIPTS=mosesdecoder/scripts
TOKENIZER=$SCRIPTS/tokenizer/tokenizer.perl
LC=$SCRIPTS/tokenizer/lowercase.perl
CLEAN=$SCRIPTS/training/clean-corpus-n.perl

...

src=de
tgt=en
lang=de-en
prep=iwslt14.tokenized.de-en
tmp=$prep/tmp

...

echo "pre-processing train data..."
for l in $src $tgt; do
    f=train.tags.$lang.$l
    tok=train.tags.$lang.tok.$l

    cat $orig/$lang/$f | \
    grep -v '<url>' | \
    grep -v '<talkid>' | \
    grep -v '<keywords>' | \
    sed -e 's/<title>//g' | \
    sed -e 's/<\/title>//g' | \
    sed -e 's/<description>//g' | \
    sed -e 's/<\/description>//g' | \
    perl $TOKENIZER -threads 8 -l $l > $tmp/$tok
    echo ""
done
perl $CLEAN -ratio 1.5 $tmp/train.tags.$lang.tok $src $tgt $tmp/train.tags.$lang.clean 1 175
for l in $src $tgt; do
    perl $LC < $tmp/train.tags.$lang.clean.$l > $tmp/train.tags.$lang.$l
done

在該任務中,使用sed清除HTML標籤。mosesdecoderscripts/tokenizer/tokenizer.perl對句子進行分詞。scripts/training/clean-corpus-n.perl清理訓練集中過長的句子,以及一些src和tgt的長度比過大的句子。scripts/tokenizer/lowercase.perl將所有文字轉化為小寫。

切分訓練集、驗證集和測試集


echo "creating train, valid, test..."
for l in $src $tgt; do
    awk '{if (NR%23 == 0)  print $0; }' $tmp/train.tags.de-en.$l > $tmp/valid.$l
    awk '{if (NR%23 != 0)  print $0; }' $tmp/train.tags.de-en.$l > $tmp/train.$l

    cat $tmp/IWSLT14.TED.dev2010.de-en.$l \
        $tmp/IWSLT14.TEDX.dev2012.de-en.$l \
        $tmp/IWSLT14.TED.tst2010.de-en.$l \
        $tmp/IWSLT14.TED.tst2011.de-en.$l \
        $tmp/IWSLT14.TED.tst2012.de-en.$l \
        > $tmp/test.$l
done

從訓練語料中學習BPE,並對資料集進行BPE切分


TRAIN=$tmp/train.en-de
BPE_CODE=$prep/code
rm -f $TRAIN
for l in $src $tgt; do
    cat $tmp/train.$l >> $TRAIN
done

echo "learn_bpe.py on ${TRAIN}..."
python $BPEROOT/learn_bpe.py -s $BPE_TOKENS < $TRAIN > $BPE_CODE

for L in $src $tgt; do
    for f in train.$L valid.$L test.$L; do
        echo "apply_bpe.py to ${f}..."
        python $BPEROOT/apply_bpe.py -c $BPE_CODE < $tmp/$f > $prep/$f
    done
done

  • learn_bpe.py的功能是從原始的訓練集中學習一個subword的詞表。

  • apply_bpe.py的功能是將剛才學到的詞表對訓練資料進行subword化。

  • BPE在NLP領域的應用:https://zhuanlan.zhihu.com/p/86965595

資料規範化

值得說明的是,上述步驟在不同的任務上,資料處理步驟可能有所差異。在該步驟中,將上述用shell指令碼初步處理的資料進行規範化,規範化之後的資料作為模型的最終輸入。

安裝了Fairseq之後,Fairseq就會把fairseq-preprocess等註冊到控制檯,如setup.py中所示:


    entry_points={
        'console_scripts': [
            'fairseq-eval-lm = fairseq_cli.eval_lm:cli_main',
            'fairseq-generate = fairseq_cli.generate:cli_main',
            'fairseq-interactive = fairseq_cli.interactive:cli_main',
            'fairseq-preprocess = fairseq_cli.preprocess:cli_main',
            'fairseq-score = fairseq_cli.score:cli_main',
            'fairseq-train = fairseq_cli.train:cli_main',
            'fairseq-validate = fairseq_cli.validate:cli_main',
        ],
    }

按照官方教程,可以執行:


TEXT=examples/translation/iwslt14.tokenized.de-en
fairseq-preprocess --source-lang de --target-lang en \
    --trainpref $TEXT/train --validpref $TEXT/valid --testpref $TEXT/test \
    --destdir data-bin/iwslt14.tokenized.de-en

但是在實際使用過程中,發現有時候呼叫的Python版本不對,特別是使用了conda環境時,因此不如直接執行對應的Python指令碼。此外,可以指定dataset-impl raw以生成文字形式的訓練語料,便於理解和檢查問題:

TEXT=examples/translation/iwslt14.tokenized.de-en
python fairseq-cli/preprocess.py --source-lang de --target-lang en \
    --trainpref $TEXT/train --validpref $TEXT/valid --testpref $TEXT/test \
    --destdir data-bin/iwslt14.tokenized.de-en \
    --dataset-impl raw

在該步驟中,主要是將訓練語料放置到目標位置destdir,建立token-索引值詞典,並且對訓練語料進行二進位制化。

除此之外,

  • Fairseq需要將args.***prefsource-lang,target-lang組合起來查詢語料,因此source-lang,target-lang需要和之前的語言簡寫保持一致。Fairseq尋找的語料位置:{args.***pref.xxx}-{lang},其中,***train/valid/testxxxsource/target。另外,source-lang,target-lang指定字典命名,輸出的字典名為:dict.{xxx-lang},其中,xxxsource/target

  • destdir用於指定輸出的訓練語料位置。

訓練

建立存放模型的資料夾


mkdir -p checkpoints/fconv

啟動訓練

同樣地,直接執行對應的Python指令碼:

CUDA_VISIBLE_DEVICES=0 python fairseq-cli/train.py data-bin/iwslt14.tokenized.de-en \
    --lr 0.25 --clip-norm 0.1 --dropout 0.2 --max-tokens 4000 \
    --dataset-impl raw \
    --arch fconv_iwslt_de_en --save-dir checkpoints/fconv

預設情況下,Fairseq使用機器上的所有GPU,在這個例子中,通過指定CUDA_VISIBLE_DEVICES=0使用機器上編號為0的GPU。由於上一個步驟中,指定資料集形式為raw,因此在這一步驟中,訓練集的形式應明確指定為raw。另外,通過指定max-tokens,Fairseq自行決定batch_size

除此之外,在上述的示例中,

  • 第一個無名引數data-bin/iwslt14.tokenized.de-en用於指定訓練語料的父目錄。

  • lr指定學習率,clip-norm指定梯度的最大範數,參見:torch.nn.utils.clip_grad_norm_dropout指定dropout的丟棄率。

  • arch指定訓練的具體模型,可在fairseq/models尋找到定義的模型結構。model定義抽象模型,arch定義具體的模型結構,比如多少詞嵌入維度,多少個隱藏層等。

生成

在該步驟中,不使用官方教程上面的generate,因為其無法指定輸入檔案,改用interactive,並使用--input指定輸入的測試文字。

python fairseq-cli/interactive.py data-bin/iwslt14.tokenized.de-en \
    --input evalution.txt \
    --path checkpoints/fconv/checkpoint_best.pt \
    --batch-size 128 --beam 5
  • 第一個無名引數data-bin/iwslt14.tokenized.de-en用於指定語料的父目錄。

  • input指定用於預測的語料路徑。

  • path指定訓練好的模型路徑。

  • beam指定束搜尋(beam search)的束大小。參見:https://www.jianshu.com/p/c2420ff9744a