加载中…
个人资料
Swind_dc
Swind_dc
  • 博客等级:
  • 博客积分:0
  • 博客访问:750
  • 关注人气:0
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

Attention_Is_All_You_Need机器翻译实验

(2019-12-04 21:39:31)
分类: Blog备份

一、实验环境配置
基本配置:

  • Ubuntu 14/16
  • CUDA 8.0
  • tensorflow 1.4. 虽然tensorflow官网介绍tf 1.5支持CUDA 8.0,但是实际安装中发现tf 1.5需要CUDA 9.0,所以安装了tensorflow 1.4
  • eager execution:tf_nightly_gpu 1.5, eager是tf动态图库。能够找到的最低版本为1.5,安装后默认将tf升级到1.5,但是意外发现这个tf 1.5支持CUDA 8.0驱动。不确定tensor2tensor究竟是否必须要安装eager。
  • tensor2tensor 1.5.6

二、数据下载
虽然从WMT2014下载到了ENGLISH-GERMAN的4.5M数据集,具体4.5M pairs的由来在文章Stanford University’s Submissions to the WMT 2014 Translation Task有说明。但是这样得到的数据集是两个文件.en和.de,目前还没有研究明白如何将原始数据集输入到模型中,在github有相关回复issues-691,缺乏细节。
tensor2tensor提供了4.5M EN-DE数据集的生成,参照:github walkthrough

PROBLEM=translate_ende_wmt32k #32k表示vocab规模,这个problem指的就是EN-DE 4.5M
MODEL=transformer
HPARAMS=transformer_base_single_gpu #有多种setting,在transformer.py中有参数说明
DATA_DIR=$HOME/t2t_data
TMP_DIR=/tmp/t2t_datagen
TRAIN_DIR=$HOME/t2t_train/$PROBLEM/$MODEL-$HPARAMS
# Generate data
t2t-datagen \
    --data_dir=$DATA_DIR \
    --tmp_dir=$TMP_DIR \
    --problem=$PROBLEM

注意: 需要注意的是,在论文的实验中EN-DE实验使用了byte-pair encoding即PROBLEM=translate_ende_wmt_bpe32k,而PROBLEM=translate_ende_wmt32k使用word-piece,所以如果要重现论文结果,应该使用前者。
在使用t2t-datagen生成bpe数据集时,需要翻墙,所以需要手动下载数据集:https://drive.google.com/uc?export=download&id=0B_bZck-ksdkpM25jRUN2X2UxMm8,将下载好的文件放置在TMP_DIR中,重新运行t2t-datagen即可。
之后的做法除特别说明外,两者相同。

测试集: 使用WMT2014官网的Cleaned Test sets,然后通过以下代码将.sgm文件处理成正常格式:          

# coding: utf-8
# vim :set fileencoding 查看文件编码
from bs4 import BeautifulSoup, SoupStrainer
import codecs
f = codecs.open("newstest2014-deen-src.en.sgm", "r", "utf-8")
data = f.read()
soup = BeautifulSoup(data)
contents = soup.findAll("seg")
of = codecs.open("newstest2014.en", "w+", "utf-8")
for seg in contents:
    of.write(seg.text+"\n")
of.close()
f.close()

三、生成后可以用t2t-trainer直接训练

CUDA_VISIBLE_DEVICES=1 t2t-trainer \
    --data_dir=$DATA_DIR \
    --problems=$PROBLEM \
    --model=$MODEL \
    --hparams_set=$HPARAMS \
    --output_dir=$TRAIN_DIR \
    --hparams="batch_size=$BATCH_SIZE" \
    --train_steps=500000

这样默认会存储最近的20个checkpoints,每隔1000steps存两个checkpoints。在eval的时候画图不是很好画,所以一般增加以下两个参数,修改存储checkpoints的方式(但是要注意存储的checkpoints个数,每个checkpoint的空间开销~700MB,还是很大的。):

--save_checkpoints_secs=3600 
--keep_checkpoint_max=100

另外,如果重现论文的结果,还有一个参数需要设置(默认值为continous_train_and_eval):

--schedule=train_and_evaluate

二者的区别在于continous_train_and_eval会保存xxx000、xxx001两个checkpoints,而后者只保存一个。

这里要注意,原论文中使用了batch size 4096,8张GPU,训练了多少step不确定。参考issues-444,4096指的是每张GPU的batch size,所以要想有相似的performance,要保证每个step的batch size相等。即batch_size * num_gpu == 4096 * 8. 在GPU资源有限的时候,尽可能增加batch size。在M40测试时,batch size为10240时,运行多个step会OOM。

GPUs Batch Steps BLEU BLEU script Settings
1 2048 250k 24.79 t2t-bleu word-piece, continuous_train_and_eval, no avg
1 8192 277k 28.14 t2t-bleu word-piece, continuous_train_and_eval, no avg
1 8192 277k 26.59 get_ende_bleu.sh word-piece, continuous_train_and_eval, no avg
1 8192 243k 26.60 get_ende_bleu.sh word-piece, train_and_eval, no avg
1 8192 305k 27.15 get_ende_bleu.sh word-piece, train_and_eval, avg last 20
1 8192 370k 27.46 get_ende_bleu.sh word-piece, train_and_eval, avg last 18
1 8192 57k 23.25 bpe_get_ende_bleu.sh bpe, train_and_eval, no avg
1 8192 183k 25.56 bpe_get_ende_bleu.sh bpe, train_and_eval, no avg
1 8192 225k 25.75 bpe_get_ende_bleu.sh bpe, train_and_eval, no avg
1 8192 225k 26.11 bpe_get_ende_bleu.sh bpe, train_and_eval, avg last 10
1 8192 231k 26.18 bpe_get_ende_bleu.sh bpe, train_and_eval, avg last 20
1 8192 379k 26.71 bpe_get_ende_bleu.sh bpe, train_and_eval, avg last 10
1 8192 500k 26.89 bpe_get_ende_bleu.sh bpe, train_and_eval, avg last 10
1 8192 500k 26.84 bpe_get_ende_bleu.sh bpe, train_and_eval, avg last 20
1 8192 500k 26.67 bpe_get_ende_bleu.sh bpe, train_and_eval, no avg
1 4096 600k 25.87 bpe_get_ende_bleu.sh bpe, train_and_eval, avg last 20
GPUs Batch Steps BLEU BLEU script Settings
1 4096 775k 26.72 bpe_get_ende_bleu.sh bpe, train_and_eval, no avg

四、测试

BEAM_SIZE=4
ALPHA=0.6
CUDA_VISIBLE_DEVICES=4 t2t-decoder --data_dir=data \
    --problems=$PROBLEM \
    --model=$MODEL \
    --hparams_set=$HPARAMS \
    --output_dir=$TRAIN_DIR \
    --decode_hparams="beam_size=$BEAM_SIZE,alpha=$ALPHA" \
    --decode_from_file=$DECODE_FILE \
    --decode_to_file=translation.de \
    --worker_gpu_memory_fraction=0.2
t2t-bleu --translation=translation.de --reference=data/newstest2014.de

以上的测试方式默认使用output_dir中checkpoint文件里的最后一个ckpt做测试,可以通过

--checkpoint_path=model.ckpt-xxxxxx

指定测试使用的ckpt。

但是在github中有提到,论文中的测试是使用了 https://github.com/tensorflow/tensor2tensor/blob/master/tensor2tensor/utils/get_ende_bleu.sh。 不同的BLEU script产生的结果差异很大, 在issue-317中有说明。
使用get_ende_bleu.sh需要安装mosesdecoder。
使用get_ende_bleu.sh时,可以对.en和.de文件做相同的处理,也可以使用tok好的.de文件,通过以下命令下载gsutil cp gs://tensor2tensor-checkpoints/transformer_ende_test/newstest2014.tok.de ./,但两种方法的结果略有不同,建议使用第二种方法。
做相同处理:

#!/bin/bash
mosesdecoder=~/Music/mosesdecoder
targets_file=data/test/newstest2014.de
decodes_file=$1

# Replace unicode.
perl $mosesdecoder/scripts/tokenizer/replace-unicode-punctuation.perl -l de  < $decodes_file > $decodes_file.n
# Tokenize.
perl $mosesdecoder/scripts/tokenizer/tokenizer.perl -l de < $decodes_file.n > $decodes_file.tok

perl $mosesdecoder/scripts/tokenizer/replace-unicode-punctuation.perl -l de < $targets_file > $targets_file.n
perl $mosesdecoder/scripts/tokenizer/tokenizer.perl -l de < $targets_file.n > $targets_file.tok

# Put compounds in ATAT format (comparable to papers like GNMT, ConvS2S).
# See https://nlp.stanford.edu/projects/nmt/ :
# 'Also, for historical reasons, we split compound words, e.g.,
#    "rich-text format" --> rich ##AT##-##AT## text format."'
perl -ple 's{(\S)-(\S)}{$1 ##AT##-##AT## $2}g' < $targets_file.tok > $targets_file.tok.atat
perl -ple 's{(\S)-(\S)}{$1 ##AT##-##AT## $2}g' < $decodes_file.tok > $decodes_file.tok.atat

# Get BLEU.
perl $mosesdecoder/scripts/generic/multi-bleu.perl $targets_file.tok.atat < $decodes_file.tok.atat

使用预先处理好的tok.de:

#!/bin/bash
mosesdecoder=~/Music/mosesdecoder
tok_gold_targets=data/test/newstest2014.tok.de
decodes_file=$1

# Replace unicode.
perl $mosesdecoder/scripts/tokenizer/replace-unicode-punctuation.perl -l de  < $decodes_file > $decodes_file.n
# Tokenize.
perl $mosesdecoder/scripts/tokenizer/tokenizer.perl -l de < $decodes_file.n > $decodes_file.tok

# Put compounds in ATAT format (comparable to papers like GNMT, ConvS2S).
# See https://nlp.stanford.edu/projects/nmt/ :
# 'Also, for historical reasons, we split compound words, e.g.,
#    "rich-text format" --> rich ##AT##-##AT## text format."'
perl -ple 's{(\S)-(\S)}{$1 ##AT##-##AT## $2}g' < $tok_gold_targets > $tok_gold_targets.atat
perl -ple 's{(\S)-(\S)}{$1 ##AT##-##AT## $2}g' < $decodes_file.tok > $decodes_file.tok.atat

# Get BLEU.
perl $mosesdecoder/scripts/generic/multi-bleu.perl $tok_gold_targets.atat < $decodes_file.tok.atat

五、average checkpoints
在github的讨论中,很多人提到可以通过多个model的平均提高bleu,大约可以提高~1 bleu。
average 的方法:

CUDA_VISIBLE_DEVICES=6 t2t-avg-all --model_dir=$TRAIN_DIR/ \
    --output_dir=$TRAIN_DIR/avg-models/ #保存平均后的model\
    --min_steps=200000 \ #忽略小于这个step的checkpoints
    --n=10 # 使用多少个checkpoints做avg,需要和--min_steps符合

但是在我的实验过程中,发现avg后的模型会生成过多的“#”符号,bleu值也会下降的非常厉害,在第三部分的表格中有所体现,但是在删除这些“#”后,bleu会有明显的提高,略微高于非avg的模型。当然非avg的模型中的“#”并没有删除,对比并不是特别公平。
问题: 为什么会产生这些“#”?Follow issues-317

六、使用tensorboard可视化
通过以下代码启动tensorboard,但是会报错,因为$TRAIN_DIR下有train和eval两个event文件。貌似不影响使用。

tensorboard --logdir=$TRAIN_DIR --host=127.0.0.1 --port=16666

一定要注意浏览器需要关闭proxy。

七、t2t-translate-all和t2t-bleu,以及对BLEU_uncased做可视化
首先通过t2t-translate-all把保存下来的所有checkpoints都在test数据集上做decoder,然后运行t2t-bleu测试BLEU_uncased,生成event文件,用于可视化。

DECODE_FILE=data/newstest2014.en
BEAM_SIZE=4
ALPHA=0.6
PROBLEM=translate_ende_wmt32k
MODEL=transformer
HPARAMS=transformer_base_single_gpu
TRAIN_DIR=models/$PROBLEM/$HPARAMS/mb2048-250k

CUDA_VISIBLE_DEVICES=6 t2t-translate-all \
    --data_dir=data \
    --problems=$PROBLEM \
    --model=$MODEL \
    --hparams_set=$HPARAMS \
    --model_dir=$TRAIN_DIR \
    --beam_size=$BEAM_SIZE \
    --alpha=$ALPHA \
    --source=$DECODE_FILE \
    --translations_dir=${TRAIN_DIR}/translations/ \
    --t2t_usr_dir="" \
    --worker_gpu_memory_fraction=0.2

t2t-bleu --translations_dir=${TRAIN_DIR}/translations/ \
    --reference=data/newstest2014.de \
    --event_dir=${TRAIN_DIR}/translations/

这里需要特别注意的是--t2t_usr_dir=""一定要加上,否则默认--t2t_usr_dir=None会报错。

tensorboard --logdir=models/xxxxx/ --port=xxxx

0

阅读 评论 收藏 禁止转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有