利用Fairseq訓練一個新的機器翻譯模型,官方機器翻譯(German-English)示例:Fairseq-Training a New Model。
數據預處理
進入fairseq/examples/translation
目錄下,執行sh prepare-iwslt14.sh
。prepare-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個數據,分別是英德雙語語料,以及mosesdecoder
和subword_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標簽。mosesdecoder
的scripts/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.***pref
和source-lang
,target-lang
組合起來查找語料,因此source-lang
,target-lang
需要和之前的語言簡寫保持一致。Fairseq尋找的語料位置:{args.***pref.xxx}-{lang}
,其中,***
為train
/valid
/test
,xxx
為source
/target
。另外,source-lang
,target-lang
指定字典命名,輸出的字典名為:dict.{xxx-lang}
,其中,xxx
為source
/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