目录
Question Generation(QG),即问题生成,指的是给定一段上下文,自动生成一个流畅且符合上下文主题的问句。问题生成通常可以分为,无答案问题生成和有答案问题生成,这里只关注应用更广的有答案问题生成。
问题生成技术在教育、咨询、搜索、推荐等多个领域均有着巨大的应用价值。具体来说,问题生成可广泛应用于问答系统语料库构建,事实性问题生成,教育行业题库生成,对话提问,聊天机器人意图理解,对话式搜索意图提问,闲聊机器人主动提问等等场景。
本项目是基于预训练语言模型UNIMO-Text的问题生成,具有以下优势:
- 效果领先。基于百度自研中文预训练语言模型UNIMO-Text,并提供基于模版策略和大规模多领域问题生成数据集训练的通用问题生成预训练模型
unimo-text-1.0-question-generation
。 - 开箱即用。本项目提供TaskFlow接口,无需训练,仅需几行代码便可预测。
- 高性能推理。本项目基于FasterTransformer进行推理加速,能够提供更高性能的推理体验,优化后的推理模型在dureader_qg开发集的推理耗时缩短为优化前的1/5。
- 训练推理部署全流程打通。本项目提供了全面的定制训练流程,从数据准备、模型训练预测,到模型推理部署,一应俱全。
PaddleNLP提供开箱即用的产业级NLP预置任务能力,无需训练,一键预测。
>>> from paddlenlp import Taskflow
# 默认模型为 unimo-text-1.0-dureader_qg
>>> question_generator = Taskflow("question_generation")
# 单条输入
>>> question_generator([
{"context": "奇峰黄山千米以上的山峰有77座,整座黄山就是一座花岗岩的峰林,自古有36大峰,36小峰,最高峰莲花峰、最险峰天都峰和观日出的最佳点光明顶构成黄山的三大主峰。", "answer": "莲花峰"}
])
'''
['黄山最高峰是什么']
'''
# 多条输入
>>> question_generator([
{"context": "奇峰黄山千米以上的山峰有77座,整座黄山就是一座花岗岩的峰林,自古有36大峰,36小峰,最高峰莲花峰、最险峰天都峰和观日出的最佳点光明顶构成黄山的三大主峰。", "answer": "莲花峰"},
{"context": "弗朗索瓦·韦达外文名:franciscusvieta国籍:法国出生地:普瓦图出生日期:1540年逝世日期:1603年12月13日职业:数学家主要成就:为近代数学的发展奠定了基础。", "answer": "法国"}
])
'''
['黄山最高峰是什么', '弗朗索瓦是哪里人']
'''
关键配置参数说明:
model
:可选模型,默认为unimo-text-1.0-dureader_qg,支持的模型有["unimo-text-1.0", "unimo-text-1.0-dureader_qg", "unimo-text-1.0-question-generation", "unimo-text-1.0-question-generation-dureader_qg"]。
具体参数配置可参考Taskflow文档。
- nltk
- evaluate
- tqdm
安装方式:pip install -r requirements.txt
以下是本项目主要代码结构及说明:
├── deploy # 部署
│ ├── paddle_inference # PaddleInference高性能推理部署
│ │ ├── inference_unimo_text.py # 推理部署脚本
│ │ └── README.md # 说明文档
│ └── paddle_serving
│ ├── config.yml # 配置文件
│ ├── pipeline_client.py # 客户端程序
│ ├── pipeline_service.py # 服务器程序
│ └── README.md # 说明文档
├── export_model.py # 动态图参数导出静态图参数脚本
├── train.py # 训练脚本
├── predict.py # 预测评估脚本
├── utils.py # 工具函数脚本
└── README.md # 说明文档
接下来,我们将按数据准备、训练、预测、推理部署等四个阶段对问题生成应用的全流程进行介绍。
- 数据准备
- 默认使用中文问题生成数据集DuReader_QG进行实验,该数据集已集成到PaddleNLP。
- 如果已有标注好的本地数据集,我们需要根据将数据集整理为文档要求的格式,请参考从本地文件创建数据集(可选)。
- 模型训练
- 数据准备完成后,可以开始使用我们的数据集对预训练模型进行微调训练。我们可以根据任务需求,调整可配置参数,选择使用GPU或CPU进行模型训练,脚本默认保存在开发集最佳表现模型。中文任务默认使用
unimo-text-1.0
模型,unimo-text-1.0还支持large模型。此外本项目还提供基于大规模多领域问题生成数据集训练的通用问题生成预训练模型unimo-text-1.0-question-generation
,详见UNIMO模型汇总,用户可以根据任务和设备需求进行选择。
- 模型预测
- 训练结束后,我们可以加载保存的最佳模型进行模型测试,打印模型预测结果。
- 模型转换部署
-
在现实部署场景中,我们通常不仅对模型的精度表现有要求,也需要考虑模型性能上的表现。我们可以使用模型裁剪进一步压缩模型体积,问题生成应用已提供裁剪API对上一步微调后的模型进行裁剪,模型裁剪之后会默认导出静态图模型。
-
模型部署需要将保存的最佳模型参数(动态图)导出成静态图参数,用于后续的推理部署。
-
问题生成应用提供了基于Paddle Serving的本地部署predictor,并且支持在GPU设备使用Faster Generation进行加速。
-
问题生成应用提供了基于Paddle Serving的服务端部署方案。
DuReader_QG数据集是一个中文问题生成数据集,我们使用该数据集作为应用案例进行实验。DuReader_QG中的数据主要由由上下文、问题、答案3个主要部分组成,其任务描述为给定上下文p和答案a,生成自然语言表述的问题q,且该问题符合段落和上下文的限制。
为了方便用户快速测试,PaddleNLP Dataset API内置了DuReader_QG数据集,一键即可完成数据集加载,示例代码如下:
from paddlenlp.datasets import load_dataset
train_ds, dev_ds = load_dataset('dureader_qg', splits=('train', 'dev'))
针对DuReader_QG数据集,我们需要将QA任务格式的数据进行转换从而得到text2text形式的数据,我们默认使用模版的方式构造输入数据,默认模版如下,其他形式输入数据用户可以在convert_example函数中自行定义。
答案: <answer_text> 上下文: <context_text>
问题: <question_text>
在许多情况下,我们需要使用本地数据集来训练我们的问题生成模型,本项目支持使用固定格式本地数据集文件进行训练。
使用本地文件,只需要在模型训练时指定train_file
为本地训练数据地址,predict_file
为本地测试数据地址即可。
本地数据集目录结构如下:
data/
├── train.json # 训练数据集文件
├── dev.json # 开发数据集文件
└── test.json # 可选,待预测数据文件
本地数据集文件格式如下:
- train.json/dev.json/test.json 文件格式:
{
"context": <context_text>,
"answer": <answer_text>,
"question": <question_text>,
}
...
- train.json/dev.json/test.json 文件样例:
{
"context": "欠条是永久有效的,未约定还款期限的借款合同纠纷,诉讼时效自债权人主张债权之日起计算,时效为2年。 根据《中华人民共和国民法通则》第一百三十五条:向人民法院请求保护民事权利的诉讼时效期间为二年,法律另有规定的除外。 第一百三十七条:诉讼时效期间从知道或者应当知道权利被侵害时起计算。但是,从权利被侵害之日起超过二十年的,人民法院不予保护。有特殊情况的,人民法院可以延长诉讼时效期间。 第六十二条第(四)项:履行期限不明确的,债务人可以随时履行,债权人也可以随时要求履行,但应当给对方必要的准备时间。",
"answer": "永久有效",
"question": "欠条的有效期是多久"
}
...
运行如下命令即可在样例训练集上进行finetune,并在样例验证集上进行验证。
# GPU启动,参数`--gpus`指定训练所用的GPU卡号,可以是单卡,也可以多卡
# 例如使用1号和2号卡,则:`--gpu 1,2`
unset CUDA_VISIBLE_DEVICES
python -m paddle.distributed.launch --gpus "1,2" --log_dir ./unimo/finetune/log train.py \
--dataset_name=dureader_qg \
--model_name_or_path="unimo-text-1.0" \
--save_dir=./unimo/finetune/checkpoints \
--output_path ./unimo/finetune/predict.txt \
--logging_steps=100 \
--save_steps=500 \
--epochs=20 \
--batch_size=16 \
--learning_rate=1e-5 \
--warmup_proportion=0.02 \
--weight_decay=0.01 \
--max_seq_len=512 \
--max_target_len=30 \
--do_train \
--do_predict \
--max_dec_len=20 \
--min_dec_len=3 \
--num_return_sequences=1 \
--template=1 \
--device=gpu
关键参数释义如下:
-
gpus
指示了训练所用的GPU,使用多卡训练可以指定多个GPU卡号,例如 --gpus "0,1"。 -
dataset_name
数据集名称,当train_file
和predict_file
为None时将加载dataset_name
的训练集和开发集,默认为dureader_qg
。 -
train_file
本地训练数据地址,数据格式必须与dataset_name
所指数据集格式相同,默认为None。 -
predict_file
本地测试数据地址,数据格式必须与dataset_name
所指数据集格式相同,默认为None。 -
model_name_or_path
指示了finetune使用的具体预训练模型,可以是PaddleNLP提供的预训练模型,或者是本地的预训练模型。如果使用本地的预训练模型,可以配置本地模型的目录地址,例如: ./checkpoints/model_xx/,目录中需包含paddle预训练模型model_state.pdparams。如果使用PaddleNLP提供的预训练模型,可以选择下面其中之一。可选预训练模型 unimo-text-1.0 unimo-text-1.0-large unimo-text-1.0-question-generation -
save_dir
表示模型的保存路径。 -
output_path
表示预测结果的保存路径。 -
logging_steps
表示日志打印间隔。 -
save_steps
表示模型保存及评估间隔。 -
seed
表示随机数生成器的种子。 -
epochs
表示训练轮数。 -
batch_size
表示每次迭代每张卡上的样本数目。 -
learning_rate
表示基础学习率大小,将于learning rate scheduler产生的值相乘作为当前学习率。 -
weight_decay
表示AdamW优化器中使用的weight_decay的系数。 -
warmup_proportion
表示学习率逐渐升高到基础学习率(即上面配置的learning_rate)所需要的迭代数占总步数的比例。 -
max_seq_len
模型输入序列的最大长度。 -
max_target_len
模型训练时标签的最大长度。 -
min_dec_len
模型生成序列的最小长度。 -
max_dec_len
模型生成序列的最大长度。 -
do_train
是否进行训练。 -
do_predict
是否进行预测,在验证集上会自动评估。 -
device
表示使用的设备,从gpu和cpu中选择。 -
template
表示使用的模版,从[0, 1, 2, 3, 4]中选择,0表示不选择模版,1表示使用默认模版。
程序运行时将会自动进行训练和验证,训练过程中会自动保存模型在指定的save_dir
中。如:
./unimo/finetune/checkpoints
├── model_1000
│ ├── model_config.json
│ ├── model_state.pdparams
│ ├── special_tokens_map.json
│ ├── tokenizer_config.json
│ └── vocab.txt
└── ...
NOTE: 如需恢复模型训练,model_name_or_path
配置本地模型的目录地址即可。
微调的模型在dureader_qg验证集上有如下结果(指标为BLEU-4),其中unimo-text-1.0-dureader_qg-w/o-template
表示不使用模版策略微调的结果,unimo-text-1.0-large-dureader_qg
表示使用large模型微调的结果,unimo-text-1.0-question-generation-dureader_qg
表示在通用问题生成预训练模型unimo-text-1.0-question-generation
上微调的结果:
model_name | DuReaderQG |
---|---|
unimo-text-1.0-dureader_qg-w/o-template | 39.61 |
unimo-text-1.0-dureader_qg | 41.08 |
unimo-text-1.0-large-dureader_qg | 41.51 |
unimo-text-1.0-question-generation-dureader_qg | 44.02 |
运行下方脚本可以使用训练好的模型进行预测。
export CUDA_VISIBLE_DEVICES=0
python -u predict.py \
--dataset_name=dureader_qg \
--model_name_or_path=your_model_path \
--output_path=./predict.txt \
--logging_steps=100 \
--batch_size=16 \
--max_seq_len=512 \
--max_target_len=30 \
--do_predict \
--max_dec_len=20 \
--min_dec_len=3 \
--template=1 \
--device=gpu
关键参数释义如下:
output_path
表示预测输出结果保存的文件路径,默认为./predict.txt。model_name_or_path
指示了finetune使用的具体预训练模型,可以是PaddleNLP提供的预训练模型,或者是本地的微调好的预训练模型。如果使用本地的预训练模型,可以配置本地模型的目录地址,例如: ./checkpoints/model_xx/,目录中需包含paddle预训练模型model_state.pdparams。
使用动态图训练结束之后,可以通过静态图导出脚本实现基于FasterTransformer的高性能预测加速,并将动态图参数导出成静态图参数,静态图参数保存在output_path
指定路径中。运行方式:
python export_model.py \
--model_name_or_path ./checkpoint \
--inference_model_dir ./export_checkpoint \
--max_dec_len 50 \
--use_fp16_decoding
关键参数释义如下:
model_name_or_path
:动态图训练保存的参数路径;默认为"./checkpoint"。inference_model_dir
:静态图图保存的参数路径;默认为"./export_checkpoint"。max_dec_len
:最大输出长度。use_fp16_decoding
:是否使用fp16解码进行预测。
执行命令后将会自动导出模型到指定的 inference_model_dir
中,保存模型文件结构如下所示:
├── unimo_text.pdiparams
├── unimo_text.pdiparams.info
└── unimo_text.pdmodel
本项目提供多种不同场景的部署方案,请根据实际情况进行选择:
部署方案 | 特色 | 场景 | 硬件 |
---|---|---|---|
Paddle Inference 服务端/云端 |
通用性 | 模型算法复杂 硬件高性能 |
X86 CPU NVIDIA 全系列 GPU 龙芯/飞腾等国产CPU 昆仑/昇腾/海光DCU等AI加速芯片 |
Paddle Serving 服务化 |
高并发 | 大流量、高并发、低延时、高吞吐 资源弹性调控应对服务流量变化 支持模型组合、加密、热更新等 |
X86/Arm CPU NVIDIA GPU 昆仑/昇腾等 |
问题生成应用已打通多种场景部署方案,点击链接获取具体的使用教程。
Zheng, Chujie, and Minlie Huang. "Exploring prompt-based few-shot learning for grounded dialog generation." arXiv preprint arXiv:2109.06513 (2021). Li, Wei, et al. "Unimo: Towards unified-modal understanding and generation via cross-modal contrastive learning." arXiv preprint arXiv:2012.15409 (2020).