infoxlm_paddle

June 16, 2022 · View on GitHub

使用飞桨PaddlePaddle-源于产业实践的开源深度学习平台 深度学习框架复现InfoXLM 论文的实验结果。复现概要:

  • Sentence Retrieval 结果与原始论文一致;
  • XNLI 推理与原始论文结果接近。

[TOC]

0. 环境配置

我们推荐在一个新的虚拟环境中使用飞桨PaddlePaddle。

conda create -n infoxlm_paddle python=3.9.6
source activate infoxlm_paddle
conda install paddlepaddle-gpu==2.3.0 cudatoolkit=11.2 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/Paddle/ -c conda-forge -n infoxlm_paddle

1. 准备原始权重

微软团队给出的原始模型权重可以使用如下的命令导出为飞桨PaddlePaddle的权重文件。

  1. Huggingface/InfoXLM下载所有的文件,并放置在目录model_checkpoints/original_pytorch_huggingface下,完成后,目录应该如下:

    model_checkpoints/
        original_pytorch_huggingface/
            config.json
            pytorch_model.bin
            sentencepiece.bpe.model
            tokenizer.json
    
  2. 确认已经进入刚才创建的infoxlm_paddle虚拟环境,执行如下操作:

    cd model_checkpoints
    python converter.py --torch original_pytorch_huggingface/pytorch_model.bin --paddle converted_paddle/model_state.pdparams
    

    转换后的权重保存在 converted_paddle/model_state.pdparams, 命令行的输出应该与 model_checkpoints/conversion_log.txt一致.

  3. 执行如下命令,运行自动化测试脚本,确保模型权重已经转换成功:

    python -m pytest ./tests/
    

    您应该能看到大多数的测试都能通过,这意味着您的模型权重已经转换成功。(有部分测试函数针对的是微调后的模型)

2. 针对下游任务微调模型

按照原始InfoXLM论文,我们提供了针对下游任务微调InfoXLM的程序,其中,在调用数据方面,我们使用了方便的paddlenlp.datasetsAPI。不过使用paddlenlp.trainer相关的API时有时候会出现loss=nan的情况,所以我们手动实现了相关的训练过程,如trainer_manual.py所示。

训练模型

python trainer_manual.py \
    --train_batch_size=8 \
    --max_length=128 \
    --learning_rate=5e-5 \
    --fp16 \
    --train_lang=en \
    --gradient_accumulation_steps 8

微调过的权重通过网盘提供,下载信息在"model_checkpoints\finetuned_paddle\download.txt".

快速验证训练和微调效果

以下命令会直接加载网盘提供的权重,并且训练模型两步,然后直接运行validation和test推理,并且计算出gap_score。

python trainer_manual.py \
    --train_batch_size=4 \
    --max_length=64 \
    --learning_rate=1e-8 \
    --train_lang=en \
    --eval_lang=zh \
    --logging_steps=2 \
    --fp16 \
    --save_steps=2 \
    --quick_verify

日志中会多出一行global_steps 2 loss: 0.24736906,loss较低是因为模型已经训练好了,这里只是验证梯度流是完整的。同时,程序会自动完成15个语言的XNLI 验证集、测试集效果检验。并且计算出gap_score(英文的性能减去其他语言的平均性能,越接近0越说明模型跨语言泛化能力好):

我们提供的权重有如下的gap_score,10.28%的分数略好于论文报告。

Step 2 val_gap_score -0.1034 test_gap_score -0.1028, the lower the better

3. 评估模型

3.1 XNLI 任务

我们提供了在15个语言的数据集上进行评估的程序eval.py,评估结果如下:

python eval.py

The results are shown here, comparing to the original paper report:

语言Paddle VersionOriginal Paper
AR0.7310.742
BG0.7870.793
DE0.7810.793
EL0.7710.778
EN0.8540.864
ES0.8050.809
FR0.7990.803
HI0.7110.722
RU0.7680.776
SW0.6740.675
TH0.7410.746
TR0.7500.756
UR0.6680.673
VI0.7580.771
ZH0.7600.770
平均**0.760 **( 误差 0.5%)0.765

Non-English 平均分是0.751,English的分数是0.854,两者相差10.3%,与原文一致。

讨论

我们认为两个关键的差异在于:

  • 原始论文微调使用的batch_size = 256,而我们复现的版本因为硬件限制,实际有效的batch_size是32
  • 原始论文每5000步即评估一次val set精度,我们只在每个epoch结束的时候评估了。

更小的batch_size 影响了一些性能,我们注意到有些epoch中,中文的精度可以达到77.0%,比起实际提交的微调版本高出一个点,但是这个epoch在其他语言上的表现平均不如提交的版本。可见更小的batch_size 导致的性能波动还是可观的。

3.2 Tatoeba Sentence Retrieval任务

该任务不需要训练,只需要使用导出的原始预训练权重即可完成。原文中给出了参考的Tatoeba数据集使用的论文:[1812.10464] Massively Multilingual Sentence Embeddings for Zero-Shot Cross-Lingual Transfer and Beyond (arxiv.org),我们阅读论文后找到了论文开源的数据集合和评测方法,来源:facebookresearch/LASER: Language-Agnostic SEntence Representations (github.com),并且将评测过程使用paddle重现了;

Sentence Retrieval任务是评测跨语言的同样含义的句子(例如一对互译的句子),经过预训练模型编码后,其表征是否有足够的相似度。InfoXLM论文使用了Tatoeba里与XNLI的14个语言 -- 英文互译的数据集;每个语言和英语的互译句子有1000句。针对一个语言评测时,我们执行以下操作:

  • 将这1000句话的英文和外语版本(共2000句)encode,取出InfoXLM第7层transformer输出的向量,并沿token的方向取平均,得到1 * 768的向量,并作L2标准化;
  • 对En->X 计算句子取回的准确率:
    • 针对每个英语的句子,计算该句子的向量与X语言1000句的向量的余弦相似度,取出余弦相似度最高的句子;
    • 计算取出的句子确实是对应译文的平均概率,为准确率。
  • 对X-> En 计算句子取回的准确率:
    • 与上述过程类似,针对每个X语言句子计算英语1000句中的相似度

我们已经在git中附带了要用到的Tatoeba数据,位于experiments/sentence_retrieval/datasets。如果您完成了原始权重的转换,您可以通过以下命令行复现上述实验的过程:

python experiments/sentence_retrieval/run_experiments.py

执行后会输出log.txt 和 sentence_retrieval_results.csv,结果如下,表格中所有指标与论文报告(table-2)完全一致。

Xen->xx->en
ar0.6860.591
bg0.7870.787
de0.9510.939
el0.7260.622
es0.8720.882
fr0.840.794
hi0.8830.871
ru0.8570.838
sw0.4080.395
th0.9120.850
tr0.8470.832
ur0.7330.73
vi0.920.896
zh0.8640.864
Average0.8060.778

4. 模型推理部署

4.1 导出模型

我们提供了模型的导出和部署程序,如果您下载了微调后的权重(finetuned_paddle),您可以直接使用这个权重部署模型,如下:

python TIPC/export_paddle/export_model.py --model_path=model_checkpoints/finetuned_paddle --save_inference_dir ./xnli_exported_model

导出成功后,目标文件夹xnli_exported_model会保存如下文件:

xnli_exported_models/
    added_tokens.json
    inference.pdiparams
    inference.pdiparams.info
    inference.pdmodel
    special_tokens_map.json
    spiece.model
    tokenizer_config.json

4.2 使用模型推理

使用这个模型进行推理的操作如下:

python TIPC/inference_paddle/infer.py --model_dir ./xnli_exported_models --use_gpu True --warmup 1 --text "You don't have to stay here.<sep>You can not leave."

其中--text参数提供了本次推理的输入数据,格式为"前提<sep>假设",语言无需额外指定,所有语言输入都能通过提供的sentencepiece模型进行分词。推理输出如下:

[2022-06-05 23:07:24,056] [    INFO] - Adding <pad> to the vocabulary
[2022-06-05 23:07:24,057] [    INFO] - Adding <mask> to the vocabulary
[2022-06-05 23:07:24,057] [    INFO] - Adding <pad> to the vocabulary
[2022-06-05 23:07:24,058] [    INFO] - Adding <mask> to the vocabulary
[2022-06-05 23:07:24,058] [    INFO] - Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.
text: You don't have to stay here. <sep> You can not leave., label_id: 0, prob: 0.8804811835289001, label: contradiction

推理成功,结果为contradiction(概率0.880),与模型本身一致。

5. Serving 部署

5.1 安装Serving依赖

详情请参考Serving 安装。在这里我们推荐使用linux docker的方式来安装,原生版本无论在windows还是unix环境中不可控因素较难排查。我们提供的Git代码经测试可以在windows + linux docker cpu only 的版本中成功部署。

为了方便,启动的时候可以挂载上当前的目录

# 启动 CPU Docker
docker pull registry.baidubce.com/paddlepaddle/serving:0.9.0-devel
docker run -p 9292:9292 --name test_cpu -v ${PWD}:/home/infoxlm_paddle -dit registry.baidubce.com/paddlepaddle/serving:0.9.0-devel bash
docker exec -it test_cpu bash
git clone https://github.com/PaddlePaddle/Serving

并完成页面内其他的步骤,安装依赖项目

5.2 部署推理服务

使用4.1章节中导出的模型,部署推理服务,如下: