WMT14 en-de翻譯數據集預處理步驟


fairseq提供了一份wmt14英德數翻譯據集的預處理腳本,簡單結合其代碼分析一下其處理步驟:

  1. 下載mosesdecoder。mosesdecoder的使用文檔在這里
echo 'Cloning Moses github repository (for tokenization scripts)...'
git clone https://github.com/moses-smt/mosesdecoder.git
  1. 下載subword nmt。這個開源庫是用於構造bpecodes及其字典的。
echo 'Cloning Subword NMT repository (for BPE pre-processing)...'
git clone https://github.com/rsennrich/subword-nmt.git
SCRIPTS=mosesdecoder/scripts      # 定義SCRIPTS變量,指向mosesdecoder的腳本文件夾
TOKENIZER=$SCRIPTS/tokenizer/tokenizer.perl      # 定義TOKENIZER變量,指向mosesdecoder的tokenizer.perl, 用來分詞
CLEAN=$SCRIPTS/training/clean-corpus-n.perl      # 定義CLEAN變量,指向mosesdecoder的clean-corpus-n.perl,clean的主要作用是保留指定長度的數據
NORM_PUNC=$SCRIPTS/tokenizer/normalize-punctuation.perl      # 定義NORM_PUNC變量,指向normalize-punctuation.perl,用來將標點符號規范化
REM_NON_PRINT_CHAR=$SCRIPTS/tokenizer/remove-non-printing-char.perl      # 定義REM_NON_PRINT_CHAR變量,指向remove-non-printing-char.perl,去除語料中的非打印字符 
BPEROOT=subword-nmt/subword_nmt      # 定義BPEROOT變量,指向subword_nmt根目錄。
BPE_TOKENS=40000      # 指定BPE TOKENS的數量為40000
# 指定語料來源,其中包括了訓練、驗證、測試語料
URLS=(
    "http://statmt.org/wmt13/training-parallel-europarl-v7.tgz"
    "http://statmt.org/wmt13/training-parallel-commoncrawl.tgz"
    "http://data.statmt.org/wmt17/translation-task/training-parallel-nc-v12.tgz"
    "http://data.statmt.org/wmt17/translation-task/dev.tgz"
    "http://statmt.org/wmt14/test-full.tgz"
)
# 指定文件名,和上面URLS對應
FILES=(
    "training-parallel-europarl-v7.tgz"
    "training-parallel-commoncrawl.tgz"
    "training-parallel-nc-v12.tgz"
    "dev.tgz"
    "test-full.tgz"      # 只要test-full是測試集,上面四個都是訓練+驗證集。
)
CORPORA=(
    "training/europarl-v7.de-en"
    "commoncrawl.de-en"
    "training/news-commentary-v12.de-en"
)
# This will make the dataset compatible to the one used in "Convolutional Sequence to Sequence Learning"
# https://arxiv.org/abs/1705.03122
# 如果指定參數--icml17,就將語料2替換成wmt14的語料,而不是使用wmt17的語料,這是為了和ConvS2S論文保持一致
if [ "$1" == "--icml17" ]; then
    URLS[2]="http://statmt.org/wmt14/training-parallel-nc-v9.tgz"
    FILES[2]="training-parallel-nc-v9.tgz"
    CORPORA[2]="training/news-commentary-v9.de-en"
    OUTDIR=wmt14_en_de      # 指定輸出文件夾名
else
    OUTDIR=wmt17_en_de
fi
src=en      # 源語言為英文
tgt=de      # 目標語言是德語
lang=en-de      # 語言對為英德
prep=$OUTDIR      # 文件夾前綴為$OUTDIR
tmp=$prep/tmp      # 文件夾$OUTDIR內有一個tmp文件夾
orig=orig      # orig=orig
dev=dev/newstest2013      # 開發集使用newstest2013

mkdir -p $orig $tmp $prep      # 遞歸創建上面定義的文件夾,包括orig文件夾,$OUTDIR/tmp文件夾,$OUTDIR文件夾

cd $orig      # 切換到orig文件夾中
for ((i=0;i<${#URLS[@]};++i)); do      # 迭代每一個URLS
    file=${FILES[i]}
    if [ -f $file ]; then
        echo "$file already exists, skipping download"      # 如果文件之前已經下載下來了,就跳過
    else
        url=${URLS[i]}      
        wget "$url"      # 否則下載
        if [ -f $file ]; then      
            echo "$url successfully  downloaded."       # 下載完文件存在表示下載成功
        else
            echo "$url not successfully downloaded."  # 查無此人,下載失敗
            exit -1
        fi
        if [ ${file: -4} == ".tgz" ]; then      # 對於.tgz格式的文件,用zxvf命令解壓
            tar zxvf $file
        elif [ ${file: -4} == ".tar" ]; then      # 對於.tar格式的文件,用xvf命令解壓
            tar xvf $file
        fi
    fi
done
cd ..
  1. 重點來了
echo "pre-processing train data..."      # 預處理訓練語料
for l in $src $tgt; do
    rm $tmp/train.tags.$lang.tok.$l      # 如果存在,先移除
    for f in "${CORPORA[@]}"; do      
        cat $orig/$f.$l | \
            perl $NORM_PUNC $l | \      # 先標准化符號
            perl $REM_NON_PRINT_CHAR | \      # 移除非打印字符
            perl $TOKENIZER -threads 8 -a -l $l >> $tmp/train.tags.$lang.tok.$l  # 分詞
    done
done

echo "pre-processing test data..."      # 預處理測試語料
for l in $src $tgt; do
    if [ "$l" == "$src" ]; then      
        t="src"
    else
        t="ref"
    fi
    grep '<seg id' $orig/test-full/newstest2014-deen-$t.$l.sgm | \      #這一塊操作沒看懂
        sed -e 's/<seg id="[0-9]*">\s*//g' | \      
        sed -e 's/\s*<\/seg>\s*//g' | \
        sed -e "s/\’/\'/g" | \
    perl $TOKENIZER -threads 8 -a -l $l > $tmp/test.$l      # 分詞
    echo ""
done
echo "splitting train and valid..."      # 划分訓練集和驗證集
for l in $src $tgt; do
    awk '{if (NR%100 == 0)  print $0; }' $tmp/train.tags.$lang.tok.$l > $tmp/valid.$l      # 從訓練集中,每100個句子抽1個句子作為驗證集
    awk '{if (NR%100 != 0)  print $0; }' $tmp/train.tags.$lang.tok.$l > $tmp/train.$l
done

TRAIN=$tmp/train.de-en      # 訓練語料(包含src和tgt)
BPE_CODE=$prep/code      # BPECODE文件
rm -f $TRAIN      # train.de-en如果存在就刪掉
for l in $src $tgt; do      
    cat $tmp/train.$l >> $TRAIN  # 其實就是簡單地將src語料和tgt語料按順序放到一個文件中,方便后面聯合學習bpe
done

echo "learn_bpe.py on ${TRAIN}..."      # 學習BPE
python $BPEROOT/learn_bpe.py -s $BPE_TOKENS < $TRAIN > $BPE_CODE       # 這里是將源語言和目標語言的語料聯合起來學BPE的,因為我們用的是train.de-en

for L in $src $tgt; do
    for f in train.$L valid.$L test.$L; do      # 用學到的bpecode應用到三份語料中(訓練語料,驗證語料,測試語料)
        echo "apply_bpe.py to ${f}..."
        python $BPEROOT/apply_bpe.py -c $BPE_CODE < $tmp/$f > $tmp/bpe.$f      # 輸出到tmp中對應的文件,以bpe.作為前綴
    done
done

perl $CLEAN -ratio 1.5 $tmp/bpe.train $src $tgt $prep/train 1 250      # 按照長度對訓練語料和驗證語料進行clean,只保留前250個token,並將結果輸出到output文件夾中
perl $CLEAN -ratio 1.5 $tmp/bpe.valid $src $tgt $prep/valid 1 250

for L in $src $tgt; do
    cp $tmp/bpe.test.$L $prep/test.$L      # 對於test語料,不進行clean,直接放到output文件夾。
done

結束


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM