基于无监督训练SimCSE+In-batch Negatives策略有监督训练的语义索引召回

语义索引(可通俗理解为向量索引)技术是搜索引擎、推荐系统、广告系统在召回阶段的核心技术之一。语义索引模型的目标是:给定输入文本,模型可以从海量候选召回库中快速、准确地召回一批语义相关文本。语义索引模型的效果直接决定了语义相关的物料能否被成功召回进入系统参与上层排序,从基础层面影响整个系统的效果。

1.In-batch negatives策略以及其他策略详解

In-batch negatives是一种用于训练推荐系统或图像检索模型的策略。该策略的核心思想是在一个训练批次(batch)中,为每个正样本(目标样本)引入一些负样本(非目标样本),以增强模型的学习能力。

具体来说,In-batch negatives策略首先从当前批次中选择出正样本,然后从同一批次中随机选择出一些负样本。这些负样本可以是与正样本相似但被错误标记的样本,也可以是完全不相关的样本。通过将正样本与负样本一起输入模型进行训练,模型需要学会区分正样本和负样本,从而提高推荐或检索的准确性。

  • 类似的算法策略还有以下几种:

    • Negative Sampling(负采样):该策略通过从全局样本集中采样出一些负样本,与正样本一起构成训练集。负样本的选择可以基于一定的概率分布,例如使用频率、TF-IDF权重等。

    • Hard Negative Mining(困难样本挖掘):这种策略着重挑选那些与正样本相似度较高但被错误标记的负样本。通过引入这些难以区分的负样本,模型能够更好地学习样本间的差异。

    • Contrastive Learning(对比学习):该策略通过最大化正样本对的相似度,以及最小化正样本与负样本对的相似度之间的差异来进行训练。这样可以使模型更好地将正样本聚集在一起,同时将负样本分散开。

    • Triplet Loss:这种策略使用三元组(triplet)的方式进行训练,每个三元组由一个锚点样本、一个正样本和一个负样本组成。目标是使得正样本与锚点样本间的距离小于负样本与锚点样本间的距离,从而达到更好的样本区分效果。

这些算法策略都旨在通过引入负样本或调整样本间的相似度关系,从而提高模型对目标样本的识别和检索能力。具体选择哪种策略取决于具体的任务和数据特点。

  • 常见的策略对比:
模型 策略简要说明
Baseline 标准 pair-wise 训练范式,通过随机采样产生负样本
In-batch negatives 在 Batch 内同时使用 batch_size 个负样本进行训练
HardestNeg 在 Batch 内先挖掘最难负样本,然后进行 pair-wise 训练

1.1 In-batch negatives 核心思路

在召回阶段,最常见的方式是通过双塔模型,学习Document(简写为Doc)的向量表示,对Doc端建立索引,用ANN召回。我们在这种方式的基础上,引入语义索引策略 In-batch Negatives,以如下Batch size=4的训练数据为例:

  1. 我手机丢了,我想换个手机 我想买个新手机,求推荐
  2. 学日语软件手机上的 手机学日语的软件
  3. 侠盗飞车罪恶都市怎样改车 侠盗飞车罪恶都市怎么改车

In-batch negatives 策略核心是在 1 个 Batch 内同时基于 N 个负例进行梯度更新,将Batch 内除自身之外其它所有 Source Text 的相似文本 Target Text 作为负例,例如: 上例中 我手机丢了,我想换个手机 有 1 个正例(1.我想买个新手机,求推荐),2个负例(1.手机学日语的软件2.侠盗飞车罪恶都市怎么改车)。

1.2 HardestNeg 核心思路

HardestNeg 策略核心是在 1 个 Batch 内的所有负样本中先挖掘出最难区分的负样本,基于最难负样本进行梯度更新。例如: 上例中 Source Text: 我手机丢了,我想换个手机 有 3 个负例(1.手机学日语的软件2.侠盗飞车罪恶都市怎么改车),其中最难区分的负例是 手机学日语的软件,模型训练过程中不断挖掘出类似这样的最难负样本,然后基于最难负样本进行梯度更新。

2. 技术方案和评估指标

2.1技术方案

双塔模型,在召回训练阶段引入In-batch Negatives 策略,使用hnswlib建立索引库,进行召回测试。

2.2 评估指标

采用 Recall@1,Recall@5 ,Recall@10 ,Recall@20 和 Recall@50 指标来评估语义索引模型的召回效果。

Recall@K召回率是指预测的前topK(top-k是指从最后的按得分排序的召回列表中返回前k个结果)结果中检索出的相关结果数和库中所有的相关结果数的比率,衡量的是检索系统的查全率。

效果评估展示

策略 模型 Recall@1 Recall@5 Recall@10 Recall@20 Recall@50
In-batch Negatives ernie 1.0 51.301 65.309 69.878 73.996 78.881
In-batch Negatives rocketqa-zh-base-query-encoder 59.271 74.387 78.82 82.831 86.955
In-batch Negatives SimCSE+rocketqa-zh-base-query-encoder 59.607 75.094 79.487 83.445 87.763

3. 环境依赖&代码结构

3.1 环境依赖

推荐使用GPU进行训练,在预测阶段使用CPU或者GPU均可。

环境依赖

  • python >= 3.6.2
  • paddlepaddle >= 2.2.3
  • paddlenlp >= 2.2
  • hnswlib >= 0.5.2
  • visualdl >= 2.2.2
  1. #安装环境
  2. !pip install -r requirements.txt
  1. !pip install --pre --upgrade paddlenlp==2.6.0rc0 -f https://www.paddlepaddle.org.cn/whl/paddlenlp.html
  1. !pip install protobuf==3.20.0

3.2 代码结构

  1. |—— data.py # 数据读取、数据转换等预处理逻辑
  2. |—— base_model.py # 语义索引模型基类
  3. |—— train_batch_neg.py # In-batch Negatives 策略的训练主脚本
  4. |—— batch_negative
  5. |—— model.py # In-batch Negatives 策略核心网络结构
  6. |—— ann_util.py # Ann 建索引库相关函数
  7. |—— recall.py # 基于训练好的语义索引模型,从召回库中召回给定文本的相似文本
  8. |—— evaluate.py # 根据召回结果和评估集计算评估指标
  9. |—— predict.py # 给定输入文件,计算文本 pair 的相似度
  10. |—— export_model.py # 动态图转换成静态图
  11. |—— scripts
  12. |—— export_model.sh # 动态图转换成静态图脚本
  13. |—— predict.sh # 预测 bash 版本
  14. |—— evaluate.sh # 评估 bash 版本
  15. |—— run_build_index.sh # 构建索引 bash 版本
  16. |—— train_batch_neg.sh # 训练 bash 版本
  17. |—— export_to_serving.sh # Paddle Inference 转 Serving 的 bash 脚本
  18. |—— deploy
  19. |—— python
  20. |—— predict.py # PaddleInference
  21. |—— deploy.sh # Paddle Inference 部署脚本
  22. |—— rpc_client.py # Paddle Serving 的 Client 端
  23. |—— web_service.py # Paddle Serving 的 Serving 端
  24. |—— config_nlp.yml # Paddle Serving 的配置文件
  25. |—— inference.py # 动态图抽取向量
  26. |—— export_to_serving.py # 静态图转 Serving
  1. #解压代码
  2. # !unzip /home/aistudio/in_batch_negative.zip

4. 数据准备

4.1 数据集说明

我们基于某文献检索平台数据,构造面向语义索引的训练集、测试集、召回库。

训练集验证集 格式一致,训练集4k条,测试集2w条,每行由一对语义相似的文本Pair构成,以tab符分割,第一列是检索query,第二列由相关文献标题(+关键词)构成。样例数据如下:

  1. 宁夏社区图书馆服务体系布局现状分析 宁夏社区图书馆服务体系布局现状分析社区图书馆,社区图书馆服务,社区图书馆服务体系
  2. 人口老龄化对京津冀经济 京津冀人口老龄化对区域经济增长的影响京津冀,人口老龄化,区域经济增长,固定效应模型
  3. 英语广告中的模糊语 模糊语在英语广告中的应用及其功能模糊语,英语广告,表现形式,语用功能
  4. 甘氨酸二肽的合成 甘氨酸二肽合成中缩合剂的选择甘氨酸,缩合剂,二肽

召回库 用于模拟业务线上的全量语料库,评估模型的召回效果,计算相应的Recall指标。召回库总共30万条样本,每行由一列构成,文献标题(+关键词),样例数据如下:

  1. 陕西省贫困地区城乡青春期少女生长发育调查青春期,生长发育,贫困地区
  2. 五丈岩水库溢洪道加固工程中的新材料应用碳纤维布,粘钢加固技术,超细水泥,灌浆技术
  3. 木塑复合材料在儿童卫浴家具中的应用探索木塑复合材料,儿童,卫浴家具
  4. 泡沫铝准静态轴向压缩有限元仿真泡沫铝,准静态,轴向压缩,力学特性

4.2 数据集下载

  1. ├── milvus # milvus建库数据集
  2. ├── milvus_data.csv. # 构建召回库的数据
  3. ├── recall # 召回(语义索引)数据集
  4. ├── corpus.csv # 用于测试的召回库
  5. ├── dev.csv # 召回验证集
  6. ├── test.csv # 召回测试集
  7. ├── train.csv # 召回训练集
  8. ├── train_unsupervised.csv # 无监督训练集
  9. ├── sort # 排序数据集
  10. ├── test_pairwise.csv # 排序测试集
  11. ├── dev_pairwise.csv # 排序验证集
  12. └── train_pairwise.csv # 排序训练集
  1. #解压数据集
  2. !unzip -d /home/aistudio/literature_search_data /home/aistudio/data/data225060/literature_search_data.zip

5. 模型训练

语义索引训练模型下载链接:

以下模型结构参数为: TrasformerLayer:12, Hidden:768, Heads:12, OutputEmbSize: 256

Model 训练参数配置 硬件 MD5
batch_neg ernie 1.0 margin:0.2 scale:30 epoch:3 lr:5E-5 bs:64 max_len:64 4卡 v100-16g f3e5c7d7b0b718c2530c5e1b136b2d74
  • 训练环境说明

    • NVIDIA Driver Version: 440.64.00
    • Ubuntu 16.04.6 LTS (Docker)
    • Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz

5.1 单机单卡训练/单机多卡训练

这里采用单机多卡方式进行训练,通过如下命令,指定 GPU 0,1,2,3 卡, 基于 In-batch Negatives 策略训练模型,数据量比较小,几分钟就可以完成。如果采用单机单卡训练,只需要把--gpus参数设置成单卡的卡号即可。

如果使用CPU进行训练,则需要吧--gpus参数去除,然后吧device设置成cpu即可,详细请参考train_batch_neg.sh文件的训练设置

然后运行下面的命令使用GPU训练,得到语义索引模型:

  1. #进入目录
  2. %cd in_batch_negative
  1. /home/aistudio/in_batch_negative
  1. # !python -u -m paddle.distributed.launch --gpus "0,1,2,3" \ 多卡
  2. #单卡
  3. !python -u -m paddle.distributed.launch --gpus "0" \
  4. train_batch_neg.py \
  5. --device gpu \
  6. --save_dir ./checkpoints/inbatch \
  7. --batch_size 32 \
  8. --learning_rate 5E-5 \
  9. --epochs 3 \
  10. --output_emb_size 256 \
  11. --model_name_or_path rocketqa-zh-base-query-encoder \
  12. --save_steps 10 \
  13. --max_seq_length 64 \
  14. --margin 0.2 \
  15. --train_set_file "/home/aistudio/literature_search_data/recall/train.csv" \
  16. --recall_result_dir "recall_result_dir" \
  17. --recall_result_file "recall_result.txt" \
  18. --hnsw_m 100 \
  19. --hnsw_ef 100 \
  20. --recall_num 50 \
  21. --similar_text_pair_file "/home/aistudio/literature_search_data/recall/dev.csv" \
  22. --corpus_file "/home/aistudio/literature_search_data/recall/corpus.csv"

输出结果预览:

  1. [2023-07-07 17:08:32,340] [ INFO] - tokenizer config file saved in ./checkpoints/inbatch/model_360/tokenizer_config.json
  2. [2023-07-07 17:08:32,340] [ INFO] - Special tokens file saved in ./checkpoints/inbatch/model_360/special_tokens_map.json
  3. global step 370, epoch: 3, batch: 120, loss: 0.15921, speed: 5.84 step/s
  4. [2023-07-07 17:08:34,041] [ INFO] - tokenizer config file saved in ./checkpoints/inbatch/model_370/tokenizer_config.json
  5. [2023-07-07 17:08:34,042] [ INFO] - Special tokens file saved in ./checkpoints/inbatch/model_370/special_tokens_map.json
  6. LAUNCH INFO 2023-07-07 17:08:36,702 Pod completed
  7. LAUNCH INFO 2023-07-07 17:08:36,702 Exit code 0

参数含义说明

  • device: 使用 cpu/gpu 进行训练
  • save_dir: 模型存储路径
  • batch_size: 训练的batch size的大小,note:参数别设置太大
  • learning_rate: 训练的学习率的大小
  • epochs: 训练的epoch数
  • output_emb_size: Transformer 顶层输出的文本向量维度
  • model_name_or_path: 预训练模型,用于模型和Tokenizer的参数初始化
  • save_steps: 模型存储 checkpoint 的间隔 steps 个数
  • max_seq_length: 输入序列的最大长度
  • margin: 正样本相似度与负样本之间的目标 Gap
  • train_set_file: 训练集文件
  • evaluate: 是否开启边训练边评估模型训练效果,默认开启
  • recall_result_dir: 召回结果存储目录
  • recall_result_file: 召回结果的文件名
  • hnsw_m: hnsw 算法相关参数,保持默认即可
  • hnsw_ef: hnsw 算法相关参数,保持默认即可
  • recall_num: 对 1 个文本召回的相似文本数量
  • similar_text_pair_file: 由相似文本对构成的评估集
  • corpus_file: 召回库数据 corpus_file
  • use_recompute: 使用Recompute策略,用于节省显存,是一种以时间换空间的技术
  • use_gradient_cache: 使用Gradient Cache策略,用于节省显存,是一种以时间换空间的技术
  • chunk_numbers: 使用Gradient Cache策略的参数,表示的是同一个批次的样本分几次执行

也可以使用bash脚本:

  1. sh scripts/train.sh

6. 模型评估

效果评估分为 4 个步骤:

  • a. 获取Doc端Embedding

    基于语义索引模型抽取出Doc样本库的文本向量。

  • b. 采用hnswlib对Doc端Embedding建库

    使用 ANN 引擎构建索引库(这里基于 hnswlib 进行 ANN 索引)

  • c. 获取Query的Embedding并查询相似结果

    基于语义索引模型抽取出评估集 Source Text 的文本向量,在第 2 步中建立的索引库中进行 ANN 查询,召回 Top50 最相似的 Target Text, 产出评估集中 Source Text 的召回结果 recall_result 文件。

  • d. 评估

    基于评估集 dev.csv 和召回结果 recall_result 计算评估指标 Recall@k,其中k取值1,5,10,20,50。

运行如下命令进行 ANN 建库、召回,产出召回结果数据 recall_result

  1. #查看模型生成多少个了
  2. # %cd /home/aistudio/in_batch_negative/checkpoints/inbatch
  3. # !ls
  1. /home/aistudio/in_batch_negative/checkpoints/inbatch
  2. model_10 model_30 model_50 model_70 model_90
  3. model_20 model_40 model_60 model_80 recall_log
  1. # %cd ../../
  1. /home/aistudio/in_batch_negative
  1. !python -u -m paddle.distributed.launch --gpus "0" --log_dir "recall_log/" \
  2. recall.py \
  3. --device gpu \
  4. --recall_result_dir "recall_result_dir" \
  5. --recall_result_file "recall_result.txt" \
  6. --params_path "checkpoints/inbatch/model_90/model_state.pdparams" \
  7. --model_name_or_path rocketqa-zh-base-query-encoder \
  8. --hnsw_m 100 \
  9. --hnsw_ef 100 \
  10. --batch_size 32 \
  11. --output_emb_size 256\
  12. --max_seq_length 60 \
  13. --recall_num 50 \
  14. --similar_text_pair_file "/home/aistudio/literature_search_data/recall/dev.csv" \
  15. --corpus_file "/home/aistudio/literature_search_data/recall/corpus.csv"

参数含义说明

  • device: 使用 cpu/gpu 进行训练
  • recall_result_dir: 召回结果存储目录
  • recall_result_file: 召回结果的文件名
  • params_path: 待评估模型的参数文件名
  • model_name_or_path: 预训练模型,用于模型和Tokenizer的参数初始化
  • hnsw_m: hnsw 算法相关参数,保持默认即可
  • hnsw_ef: hnsw 算法相关参数,保持默认即可
  • output_emb_size: Transformer 顶层输出的文本向量维度
  • recall_num: 对 1 个文本召回的相似文本数量
  • similar_text_pair: 由相似文本对构成的评估集
  • corpus_file: 召回库数据 corpus_file

也可以使用下面的bash脚本:

  1. sh scripts/run_build_index.sh

run_build_index.sh还包含cpu和gpu运行的脚本,默认是gpu的脚本

成功运行结束后,会在 ./recall_result_dir/ 目录下产出 recall_result.txt 文件

  1. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 热处理对尼龙6及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响尼龙6,聚酰胺嵌段共聚物,芳香聚酰胺,热处理 0.9831992387771606
  2. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 热处理方法对高强高模聚乙烯醇纤维性能的影响聚乙烯醇纤维,热处理,性能,热拉伸,热定型 0.8438636660575867
  3. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 制备工艺对PVC/ABS合金力学性能和维卡软化温度的影响PVC,ABS,正交试验,力学性能,维卡软化温度 0.8130228519439697
  4. .....

接下来,运行如下命令进行效果评估,产出Recall@1, Recall@5, Recall@10, Recall@20 和 Recall@50 指标:

  1. #查看生成数据
  2. with open('/home/aistudio/in_batch_negative/recall_result_dir/recall_result.txt', 'r', encoding='utf-8') as file:
  3. for i in range(10):
  4. line = file.readline()
  5. if not line:
  6. break
  7. print(line.rstrip())
  1. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 热处理对尼龙6及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响尼龙6,聚酰胺嵌段共聚物,芳香聚酰胺,热处理 0.9818969368934631
  2. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 热处理方法对高强高模聚乙烯醇纤维性能的影响聚乙烯醇纤维,热处理,性能,热拉伸,热定型 0.7950249314308167
  3. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 尼龙66的改性研究及注塑模流分析尼龙66;环氧树脂;综合性能;熔融共混;注塑模流分析;扩链改性 0.7899066805839539
  4. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 外场作用下介晶态聚丙烯的结构演变研究介晶态聚丙烯;微观结构;介晶相;乙烯共聚单元;温度作用;应力作用 0.773107647895813
  5. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 热塑性结晶型全芳族聚酯酰亚胺的制备与聚集态结构聚酯酰亚胺,熔融双峰,热塑性,聚集态结构 0.7728450894355774
  6. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 微量氧化石墨烯改性聚酯的结构及热性能分析改性聚酯,氧化石墨烯,结构,热稳定性,结晶度 0.7625532150268555
  7. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 等规聚丙烯结晶机理研究等规聚丙烯;结晶机理;β-成核剂;微观形貌;剪切强度 0.7597315907478333
  8. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 高等级聚乙烯管材料的结构与性能研究聚乙烯管材料;分子结构;力学性能;流变性能 0.7588903903961182
  9. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 MC尼龙/改性氧化石墨复合材料的制备与性能研究聚丙烯;二元胺接枝;改性氧化石墨;尼龙;复合材料;机械性能;冲击强度 0.7560845613479614
  10. 热处理对尼龙6 及其与聚酰胺嵌段共聚物共混体系晶体熔融行为和结晶结构的影响 链长对无定型聚乙烯导热性能影响的NEMD研究非平衡分子动力学,聚乙烯分子链,导热 0.755224347114563
  1. !python -u evaluate.py \
  2. --similar_text_pair "/home/aistudio/literature_search_data/recall/dev.csv" \
  3. --recall_result_file "/home/aistudio/in_batch_negative/recall_result_dir/recall_result.txt" \
  4. --recall_num 50
  1. recall@1=59.607
  2. recall@5=75.094
  3. recall@10=79.487
  4. recall@20=83.445
  5. recall@50=87.763

也可以使用下面的bash脚本:

  1. sh scripts/evaluate.sh

参数含义说明

  • similar_text_pair: 由相似文本对构成的评估集 semantic_similar_pair.tsv
  • recall_result_file: 针对评估集中第一列文本 Source Text 的召回结果
  • recall_num: 对 1 个文本召回的相似文本数量

成功运行结束后,会输出如下评估指标:

  1. recall@1=59.271
  2. recall@5=74.387
  3. recall@10=78.82
  4. recall@20=82.813
  5. recall@50=86.955

7. 预测

我们可以基于语义索引模型预测文本的语义向量或者计算文本 Pair 的语义相似度。

7.1 功能一:抽取文本的语义向量

修改 inference.py 文件里面输入文本 id2corpus 和模型路径 params_path :

  1. params_path='checkpoints/inbatch/model_40/model_state.pdparams'
  2. id2corpus={0:'国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据'}

然后运行:

  1. !python inference.py

预测结果为256维的向量:

  1. [1, 256]
  2. [[-5.50949238e-02 8.43941122e-02 6.79432228e-02 -5.83942570e-02
  3. 3.46402712e-02 5.86730465e-02 3.02802827e-02 -6.04058355e-02
  4. 3.81579484e-05 -1.62589997e-02 -5.91990687e-02 7.68813044e-02
  5. -7.33192125e-03 -7.04482794e-02 6.05499111e-02 3.85251977e-02
  6. .....

7.2 功能二:计算文本 Pair 的语义相似度

  • 准备预测数据

待预测数据为 tab 分隔的 csv 文件,每一行为 1 个文本 Pair,部分示例如下:

  1. 试论我国海岸带经济开发的问题与前景 试论我国海岸带经济开发的问题与前景海岸带,经济开发,问题,前景
  2. 外语阅读焦虑与英语成绩及性别的关系 外语阅读焦虑与英语成绩及性别的关系外语阅读焦虑,外语课堂焦虑,英语成绩,性别
  3. 数字图书馆 智能化图书馆
  4. 网络健康可信性研究 网络成瘾少年
  • 开始预测

以上述 demo 数据为例,运行如下命令基于我们开源的 In-batch Negatives 策略语义索引模型开始计算文本 Pair 的语义相似度:

  1. #训练好的模型也可以自主选择添加
  2. # !unzip /home/aistudio/inbatch_model.zip
  1. Archive: /home/aistudio/inbatch_model.zip
  2. creating: model_40/
  3. inflating: model_40/model_state.pdparams
  4. inflating: model_40/vocab.txt
  5. inflating: model_40/tokenizer_config.json
  1. !python -u -m paddle.distributed.launch --gpus "0" \
  2. predict.py \
  3. --device gpu \
  4. --params_path "checkpoints/inbatch/model_90/model_state.pdparams" \
  5. --model_name_or_path rocketqa-zh-base-query-encoder \
  6. --output_emb_size 256 \
  7. --batch_size 128 \
  8. --max_seq_length 64 \
  9. --text_pair_file "/home/aistudio/literature_search_data/recall/test.csv"

参数含义说明

  • device: 使用 cpu/gpu 进行训练
  • params_path: 预训练模型的参数文件名
  • model_name_or_path: 预训练模型,用于模型和Tokenizer的参数初始化
  • output_emb_size: Transformer 顶层输出的文本向量维度
  • text_pair_file: 由文本 Pair 构成的待预测数据集

也可以运行下面的bash脚本:

  1. sh scripts/predict.sh

predict.sh文件包含了cpu和gpu运行的脚本,默认是gpu运行的脚本

产出如下结果

  1. 0.9086097478866577
  2. 0.2573563754558563
  3. 0.0023693442344665527
  4. 0.7471159100532532
  5. 0.9782603979110718
  6. 0.993239164352417
  7. .....

8. 部署

8.1 动转静导出

首先把动态图模型转换为静态图:

  1. python export_model.py --params_path checkpoints/inbatch/model_40/model_state.pdparams \
  2. --model_name_or_path rocketqa-zh-base-query-encoder \
  3. --output_path=./output

也可以运行下面的bash脚本:

  1. sh scripts/export_model.sh
  1. !python export_model.py --params_path checkpoints/inbatch/model_90/model_state.pdparams \
  2. --model_name_or_path rocketqa-zh-base-query-encoder \
  3. --output_path=./output
  1. [32m[2023-07-07 17:45:08,502] [ INFO][0m - We are using <class 'paddlenlp.transformers.ernie.modeling.ErnieModel'> to load 'rocketqa-zh-base-query-encoder'.[0m
  2. [32m[2023-07-07 17:45:08,502] [ INFO][0m - Model config ErnieConfig {
  3. "attention_probs_dropout_prob": 0.1,
  4. "enable_recompute": false,
  5. "fuse": false,
  6. "hidden_act": "gelu",
  7. "hidden_dropout_prob": 0.1,
  8. "hidden_size": 768,
  9. "initializer_range": 0.02,
  10. "intermediate_size": 3072,
  11. "layer_norm_eps": 1e-12,
  12. "max_position_embeddings": 2048,
  13. "model_type": "ernie",
  14. "num_attention_heads": 12,
  15. "num_hidden_layers": 12,
  16. "pad_token_id": 0,
  17. "paddlenlp_version": null,
  18. "pool_act": "tanh",
  19. "task_id": 0,
  20. "task_type_vocab_size": 3,
  21. "type_vocab_size": 4,
  22. "use_task_id": true,
  23. "vocab_size": 40000
  24. }
  25. [0m
  26. W0707 17:45:10.404314 8461 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 8.0, Driver API Version: 11.2, Runtime API Version: 11.2
  27. W0707 17:45:10.407172 8461 gpu_resources.cc:91] device: 0, cuDNN Version: 8.2.
  28. [33m[2023-07-07 17:45:11,056] [ WARNING][0m - Some weights of the model checkpoint at rocketqa-zh-base-query-encoder were not used when initializing ErnieModel: ['classifier.bias', 'classifier.weight']
  29. - This IS expected if you are initializing ErnieModel from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).
  30. - This IS NOT expected if you are initializing ErnieModel from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).[0m
  31. [32m[2023-07-07 17:45:11,056] [ INFO][0m - All the weights of ErnieModel were initialized from the model checkpoint at rocketqa-zh-base-query-encoder.
  32. If your task is similar to the task the model of the checkpoint was trained on, you can already use ErnieModel for predictions without further training.[0m
  33. [32m[2023-07-07 17:45:11,056] [ INFO][0m - We are using <class 'paddlenlp.transformers.ernie.tokenizer.ErnieTokenizer'> to load 'rocketqa-zh-base-query-encoder'.[0m
  34. [32m[2023-07-07 17:45:11,056] [ INFO][0m - Already cached /home/aistudio/.paddlenlp/models/rocketqa-zh-base-query-encoder/ernie_3.0_base_zh_vocab.txt[0m
  35. [32m[2023-07-07 17:45:11,078] [ INFO][0m - tokenizer config file saved in /home/aistudio/.paddlenlp/models/rocketqa-zh-base-query-encoder/tokenizer_config.json[0m
  36. [32m[2023-07-07 17:45:11,078] [ INFO][0m - Special tokens file saved in /home/aistudio/.paddlenlp/models/rocketqa-zh-base-query-encoder/special_tokens_map.json[0m
  37. Loaded parameters from checkpoints/inbatch/model_90/model_state.pdparams
  38. [0m

8.2 Paddle Inference预测

预测既可以抽取向量也可以计算两个文本的相似度。

修改id2corpus的样本:

  1. #抽取向量
  2. id2corpus={0:'国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据'}
  3. #计算相似度
  4. corpus_list=[['中西方语言与文化的差异','中西方文化差异以及语言体现中西方文化,差异,语言体现'],
  5. ['中西方语言与文化的差异','飞桨致力于让深度学习技术的创新与应用更简单']]

然后使用PaddleInference

  1. !python deploy/python/predict.py \
  2. --model_dir=./output \
  3. --model_name_or_path rocketqa-zh-base-query-encoder

也可以运行下面的bash脚本:

  1. sh deploy.sh

最终输出的是256维度的特征向量和句子对的预测概率:

  1. (1, 256)
  2. [[-0.0394925 -0.04474756 -0.065534 0.00939134 0.04359895 0.14659195
  3. -0.0091779 -0.07303623 0.09413272 -0.01255222 -0.08685658 0.02762237
  4. 0.10138468 0.00962821 0.10888419 0.04553023 0.05898942 0.00694253
  5. ....
  6. [0.959269642829895, 0.04725276678800583]

8.3 Paddle Serving部署

Paddle Serving 的详细文档请参考 Pipeline_DesignServing_Design,首先把静态图模型转换成Serving的格式:

如果报错:ModuleNotFoundError: No module named 'paddle_serving_client'

  1. !pip install -U paddlenlp
  1. #安装依赖
  2. !pip install paddle_serving_client
  1. !python export_to_serving.py \
  2. --dirname "output" \
  3. --model_filename "inference.get_pooled_embedding.pdmodel" \
  4. --params_filename "inference.get_pooled_embedding.pdiparams" \
  5. --server_path "./serving_server" \
  6. --client_path "./serving_client" \
  7. --fetch_alias_names "output_embedding"
  1. # !python export_to_serving.py \
  2. # --dirname "output" \
  3. # --model_filename "inference.get_pooled_embedding.pdmodel" \
  4. # --params_filename "inference.get_pooled_embedding.pdiparams" \
  5. # --server_path "./serving_server_2" \
  6. # --client_path "./serving_client_2" \
  7. # --fetch_alias_names "predict"

参数含义说明

  • dirname: 需要转换的模型文件存储路径,Program 结构文件和参数文件均保存在此目录。
  • model_filename: 存储需要转换的模型 Inference Program 结构的文件名称。如果设置为 None ,则使用 __model__ 作为默认的文件名
  • params_filename: 存储需要转换的模型所有参数的文件名称。当且仅当所有模型参数被保>存在一个单独的二进制文件中,它才需要被指定。如果模型参数是存储在各自分离的文件中,设置它的值为 None
  • server_path: 转换后的模型文件和配置文件的存储路径。默认值为 serving_server
  • client_path: 转换后的客户端配置文件存储路径。默认值为 serving_client
  • fetch_alias_names: 模型输出的别名设置,比如输入的 input_ids 等,都可以指定成其他名字,默认不指定
  • feed_alias_names: 模型输入的别名设置,比如输出 pooled_out 等,都可以重新指定成其他模型,默认不指定

也可以运行下面的 bash 脚本:

  1. sh scripts/export_to_serving.sh

Paddle Serving的部署有两种方式,第一种方式是Pipeline的方式,第二种是C++的方式,下面分别介绍这两种方式的用法:

8.4 Pipeline方式

修改模型需要用到的Tokenizer

  1. self.tokenizer = AutoTokenizer.from_pretrained("rocketqa-zh-base-query-encoder")

然后启动 Pipeline Server:

  1. cd deploy/python
  2. python web_service.py

启动客户端调用 Server。

首先修改rpc_client.py中需要预测的样本:

  1. list_data = [
  2. "国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据",
  3. "试论翻译过程中的文化差异与语言空缺翻译过程,文化差异,语言空缺,文化对比"
  4. ]

然后运行:

  1. python deploy/python/rpc_client.py

注意:需要打开两个终端运行:效果如下

  1. # #查看当前路径
  2. # !pwd
  3. # %cd deploy/python
  1. /home/aistudio/in_batch_negative
  2. /home/aistudio/in_batch_negative/deploy/python
  1. !pip install --user paddle-serving-app
  2. !pip install --user paddle-serving-client
  3. !pip install --user paddle-serving-server
  1. !pip install exceptiongroup
  2. !pip install iniconfig
  3. !pip install func_timeout
  1. # !pip install --user pydantic==1.10.7
  1. #cd /home/aistudio/in_batch_negative/deploy/python
  2. # !python web_service.py
  1. # !python rpc_client.py

模型的输出为:

  1. {'0': '国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据', '1': '试论翻译过程中的文化差异与语言空缺翻译过程,文化差异,语言空缺,文化对比'}
  2. PipelineClient::predict pack_data time:1641450851.3752182
  3. PipelineClient::predict before time:1641450851.375738
  4. ['output_embedding']
  5. (2, 256)
  6. [[ 0.07830612 -0.14036864 0.03433796 -0.14967982 -0.03386067 0.06630666
  7. 0.01357943 0.03531194 0.02411093 0.02000859 0.05724002 -0.08119463
  8. ......

可以看到客户端发送了2条文本,返回了2个 embedding 向量

8.5 C++的方式

启动C++的Serving:

  1. python -m paddle_serving_server.serve --model serving_server --port 9393 --gpu_id 0 --thread 5 --ir_optim True --use_trt --precision FP16

也可以使用脚本:

  1. sh deploy/cpp/start_server.sh

Client 可以使用 http 或者 rpc 两种方式,rpc 的方式为:

  1. python deploy/cpp/rpc_client.py

运行的输出为:

  1. I0209 20:40:07.978225 20896 general_model.cpp:490] [client]logid=0,client_cost=395.695ms,server_cost=392.559ms.
  2. time to cost :0.3960278034210205 seconds
  3. {'output_embedding': array([[ 9.01343748e-02, -1.21870913e-01, 1.32834800e-02,
  4. -1.57673359e-01, -2.60387752e-02, 6.98455423e-02,
  5. 1.58108603e-02, 3.89952064e-02, 3.22783105e-02,
  6. 3.49135026e-02, 7.66086206e-02, -9.12970975e-02,
  7. 6.25643134e-02, 7.21886680e-02, 7.03565404e-02,
  8. 5.44054210e-02, 3.25332815e-03, 5.01751155e-02,
  9. ......

可以看到服务端返回了向量

或者使用 http 的客户端访问模式:

  1. python deploy/cpp/http_client.py

运行的输出为:

  1. (2, 64)
  2. (2, 64)
  3. outputs {
  4. tensor {
  5. float_data: 0.09013437479734421
  6. float_data: -0.12187091261148453
  7. float_data: 0.01328347995877266
  8. float_data: -0.15767335891723633
  9. ......

可以看到服务端返回了向量

  1. !pip install --user paddle-serving-app
  2. !pip install --user paddle-serving-client
  3. !pip install --user paddle-serving-server

遇到下述报错自行查看下述资料解决一下即可

  1. from .serving_client import PredictorRes
  2. ImportError: libcrypto.so.10: cannot open shared object file: No such file or directory

【linux缺失库文件】libssl.so.10: cannot open shared object file: No such file or directory

9. FAQ:SimCSE+IBN

9.1 基于无监督SimCSE训练出的模型参数作为参数初始化继续做有监督 In-Batch Negative 训练

使用场景:

  1. 数据需求:如果你拥有大量的无标注数据但是没有相应的标注数据,使用基于SimCSE的初始化会更有优势

    • 直接有监督训练:需要有标注的训练数据,以便进行监督学习。这意味着你需要拥有带有正确标签的数据集。
    • 基于SimCSE初始化的IBN训练:只需要无标注的训练数据。这对于大多数实际场景更具可行性,因为标注数据往往难以获取且成本较高。
  2. 训练速度:
    • 直接有监督训练:由于从随机初始化开始,模型需要通过反向传播和梯度下降逐步优化参数,收敛所需时间可能较长。
    • 基于SimCSE初始化的IBN训练:由于使用已经包含一定语义信息的SimCSE初始化参数,模型初始化时已经处于更好的状态,可能更快地收敛到较好的性能。这可以节省训练时间并加速模型的收敛。
  3. 效果改进:
    • 直接有监督训练:从随机初始化开始训练,模型必须在有标注的数据上进行学习,逐渐学习任务特定的特征和表示。在初始阶段可能效果较差,需要更多的数据和时间来优化。
    • 基于SimCSE初始化的IBN训练:由于使用SimCSE进行无监督预训练,模型在初始化时已经学习到了一定的语义信息和句子表示。这种初始化可以为模型提供更丰富的语义表示能力,并且更容易找到一个相对较好的局部最优点。通过IBN训练,模型可以进一步微调参数以适应特定的有监督任务,从而获得更好的性能。
  • 使用 --init_from_ckpt 参数加载即可,下面是使用示例:
  1. # %cd ../../
  1. /home/aistudio/in_batch_negative
  1. !python -u -m paddle.distributed.launch --gpus "0" \
  2. train_batch_neg.py \
  3. --device gpu \
  4. --save_dir ./checkpoints/simcse_inbatch_negative \
  5. --model_name_or_path rocketqa-zh-base-query-encoder \
  6. --batch_size 32 \
  7. --learning_rate 5E-5 \
  8. --epochs 3 \
  9. --output_emb_size 256 \
  10. --save_steps 100 \
  11. --max_seq_length 64 \
  12. --margin 0.2 \
  13. --init_from_ckpt simcse/model_24000/model_state.pdparams \
  14. --train_set_file /home/aistudio/literature_search_data/recall/train.csv \
  15. --recall_result_dir "recall_result_dir" \
  16. --recall_result_file "recall_result.txt" \
  17. --hnsw_m 100 \
  18. --hnsw_ef 100 \
  19. --recall_num 50 \
  20. --similar_text_pair_file "/home/aistudio/literature_search_data/recall/dev.csv" \
  21. --corpus_file "/home/aistudio/literature_search_data/recall/corpus.csv"
  1. [2023-07-11 11:43:10,198] [ INFO] - tokenizer config file saved in ./checkpoints/simcse_inbatch_negative/model_300/tokenizer_config.json
  2. [2023-07-11 11:43:10,198] [ INFO] - Special tokens file saved in ./checkpoints/simcse_inbatch_negative/model_300/special_tokens_map.json
  3. global step 310, epoch: 3, batch: 60, loss: 0.25565, speed: 3.26 step/s
  4. global step 320, epoch: 3, batch: 70, loss: 0.61337, speed: 5.28 step/s
  5. global step 330, epoch: 3, batch: 80, loss: 0.53147, speed: 5.40 step/s
  6. global step 340, epoch: 3, batch: 90, loss: 1.36987, speed: 5.32 step/s
  7. global step 350, epoch: 3, batch: 100, loss: 0.22996, speed: 5.39 step/s
  8. global step 360, epoch: 3, batch: 110, loss: 0.45635, speed: 5.22 step/s
  9. global step 370, epoch: 3, batch: 120, loss: 0.17504, speed: 5.23 step/s
  10. LAUNCH INFO 2023-07-11 11:43:26,332 Pod completed
  11. LAUNCH INFO 2023-07-11 11:43:26,332 Exit code 0
  1. !python -u -m paddle.distributed.launch --gpus "0" --log_dir "recall_log/" \
  2. recall.py \
  3. --device gpu \
  4. --recall_result_dir "recall_result_dir" \
  5. --recall_result_file "recall_result.txt" \
  6. --params_path "checkpoints/simcse_inbatch_negative/model_300/model_state.pdparams" \
  7. --model_name_or_path rocketqa-zh-base-query-encoder \
  8. --hnsw_m 100 \
  9. --hnsw_ef 100 \
  10. --batch_size 32 \
  11. --output_emb_size 256\
  12. --max_seq_length 60 \
  13. --recall_num 50 \
  14. --similar_text_pair_file "/home/aistudio/literature_search_data/recall/dev.csv" \
  15. --corpus_file "/home/aistudio/literature_search_data/recall/corpus.csv"
  1. [2023-07-11 11:44:05,795] [ INFO] - start build index..........
  2. [2023-07-11 11:52:51,990] [ INFO] - Total index number:300000
  3. LAUNCH INFO 2023-07-11 11:53:35,724 Pod completed
  4. LAUNCH INFO 2023-07-11 11:53:35,724 Exit code 0
  1. !python -u evaluate.py \
  2. --similar_text_pair "/home/aistudio/literature_search_data/recall/dev.csv" \
  3. --recall_result_file "/home/aistudio/in_batch_negative/recall_result_dir/recall_result.txt" \
  4. --recall_num 50
  1. recall@1=59.607
  2. recall@5=75.094
  3. recall@10=79.487
  4. recall@20=83.445
  5. recall@50=87.763

9.2 总结

语义索引(可通俗理解为向量索引)技术是搜索引擎、推荐系统、广告系统在召回阶段的核心技术之一。语义索引模型的目标是:给定输入文本,模型可以从海量候选召回库中快速、准确地召回一批语义相关文本。语义索引模型的效果直接决定了语义相关的物料能否被成功召回进入系统参与上层排序,从基础层面影响整个系统的效果。本项目基于In-batch negatives是一种用于训练推荐系统或图像检索模型的策略。该策略的核心思想是在一个训练批次(batch)中,为每个正样本(目标样本)引入一些负样本(非目标样本),以增强模型的学习能力。

策略 模型 Recall@1 Recall@5 Recall@10 Recall@20 Recall@50
In-batch Negatives ernie 1.0 51.301 65.309 69.878 73.996 78.881
In-batch Negatives rocketqa-zh-base-query-encoder 59.271 74.387 78.82 82.831 86.955
In-batch Negatives SimCSE+rocketqa-zh-base-query-encoder 59.607 75.094 79.487 83.445 87.763

SimCSE+ In-batch Negatives可以自行继续优化,整体效果提升不少。

更多优质内容请关注公号&知乎:汀丶人工智能;会提供一些相关的资源和优质文章,免费获取阅读。

  • Reference

    [1] Vladimir Karpukhin, Barlas Oğuz, Sewon Min, Patrick Lewis, Ledell Wu, Sergey Edunov, Danqi Chen, Wen-tau Yih, Dense Passage Retrieval for Open-Domain Question Answering, Preprint 2020.

基于无监督训练SimCSE+In-batch Negatives策略有监督训练的语义索引召回的更多相关文章

  1. 学习笔记CB008:词义消歧、有监督、无监督、语义角色标注、信息检索、TF-IDF、隐含语义索引模型

    词义消歧,句子.篇章语义理解基础,必须解决.语言都有大量多种含义词汇.词义消歧,可通过机器学习方法解决.词义消歧有监督机器学习分类算法,判断词义所属分类.词义消歧无监督机器学习聚类算法,把词义聚成多类 ...

  2. 基于无锁队列和c++11的高性能线程池

    基于无锁队列和c++11的高性能线程池线程使用c++11库和线程池之间的消息通讯使用一个简单的无锁消息队列适用于linux平台,gcc 4.6以上   标签: <无>   代码片段(6)[ ...

  3. 一文读懂神经网络训练中的Batch Size,Epoch,Iteration

    一文读懂神经网络训练中的Batch Size,Epoch,Iteration 作为在各种神经网络训练时都无法避免的几个名词,本文将全面解析他们的含义和关系. 1. Batch Size 释义:批大小, ...

  4. 谷歌BERT预训练源码解析(三):训练过程

    目录前言源码解析主函数自定义模型遮蔽词预测下一句预测规范化数据集前言本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BERT针对两个任务同 ...

  5. 基于按annotation的hibernate主键生成策略

    基于按annotation的hibernate主键生成策略 博客分类: Hibernate HibernateJavaJPAOracleMySQL  这里讨论代理主键,业务主键(比如说复合键等)这里不 ...

  6. 基于无锁的C#并发队列实现(转载)

    最近开始学习无锁编程,和传统的基于Lock的算法相比,无锁编程具有其独特的优点,Angel Lucifer的关于无锁编程一文对此有详细的描述. 无锁编程的目标是在不使用Lock的前提下保证并发过程中共 ...

  7. 基于无锁的C#并发队列实现

    最近开始学习无锁编程,和传统的基于Lock的算法相比,无锁编程具有其独特的优点,Angel Lucifer的关于无锁编程一文对此有详细的描述. 无锁编程的目标是在不使用Lock的前提下保证并发过程中共 ...

  8. 基于无域故障转移群集 配置高可用SQLServer 2016数据库

    基于上次的文章搭建的环境,可以在这里:http://www.cnblogs.com/DragonStart/p/8275182.html看到上次的文章. 演示环境 1. 配置一览 Key Value ...

  9. 化繁为简,弱监督目标定位领域的新SOTA - 伪监督目标定位方法(PSOL) | CVPR 2020

    论文提出伪监督目标定位方法(PSOL)来解决目前弱监督目标定位方法的问题,该方法将定位与分类分开成两个独立的网络,然后在训练集上使用Deep descriptor transformation(DDT ...

  10. Intel 的 MKL是可以用来训练的——官方的实验也提到了训练

    TensorFlow如何充分使用所有CPU核数,提高TensorFlow的CPU使用率,以及Intel的MKL加速 转载 2017年09月07日 16:34:58 标签: cpu / gpu   转载 ...

随机推荐

  1. SpringBoot 引用仓库中没有 第三方包 - 将jar 包安装本地 maven

    命令如下: mvn install:install-file -Dfile="D:\Projects\lib\com.ibm.mq-7.0.1.3.jar" -DgroupId=c ...

  2. CPU推理|使用英特尔 Sapphire Rapids 加速 PyTorch Transformers

    在 最近的一篇文章 中,我们介绍了代号为 Sapphire Rapids 的第四代英特尔至强 CPU 及其新的先进矩阵扩展 (AMX) 指令集.通过使用 Amazon EC2 上的 Sapphire ...

  3. SSL 证书变革之时已至,这些变化你都清楚吗?

    现代社会最离不开的是"安全",无论是生命.财产.数据还是其他任何事物都需要各种手段来保证安全,互联网自然也无法免俗.HTTP 协议作为无法加密数据,让所有通信数据都在网络中明文&q ...

  4. MyBatis(2):深入学习

    请注意,本文学习自 @我没有三颗心脏 编写日志输出环境配置文件 在开发过程中,最重要的就是在控制台查看程序输出的日志信息,在这里我们选择使用 log4j 工具来输出: 准备工作: 将[MyBatis] ...

  5. Vue第一篇 ES6的常用语法

    01-变量的定义 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  6. Dubbo入门1:Spirngboot+Dubbo2.6.0整合

    整合springboot+dubbo2.6.0 demo 本文简要说明了springboot和dubbo整合的配置文件的写法 目录结构 整体目录 如下图所示:整体项目是一个父子工程,common作为一 ...

  7. 【rt-thread】构建自己的项目工程 -- 初始篇

    现以stm32f429igt6芯片的板子 & Keil5编译环境为例,记述构建适配自己板子的rt-thread工程的过程 1.拿到rt-thread源码,进入bsp/stm32/librari ...

  8. Kubernerts - 概览

    1. Kubernerts K8s,是用于自动部署.扩容和管理容器化应用程序的开源系统 1.1 特性 自动化上线与回滚 分步骤针对应用或者配置更改上线,监控应用的运行状态同时不会终止所有实例,若出现问 ...

  9. Go-单链表-栈和队列

    package main import ( "errors" "fmt" "log" ) // 单链表 // 特征: // 1. 每个节点都 ...

  10. [转帖]ASH、AWR、ADDM区别联系

    ==================================================================================================== ...