用PaddlePaddle实现段文本语义匹配Simnet模型
https://aistudio.baidu.com/aistudio/projectdetail/124373
Hinge loss: https://blog.csdn.net/hustqb/article/details/78347713
原文链接:https://blog.csdn.net/qq_33187136/article/details/106770431
SimNeT优秀博客:https://www.jiqizhixin.com/articles/2017-06-15-5
短文本语义匹配/文本相似度框架(SimilarityNet, SimNet),基于bow_pairwise模式及框架原理介绍
短文本语义匹配(SimilarityNet, SimNet)是百度一个计算短文本相似度的框架,可以根据用户输入的两个文本,计算出相似度得分。
1.1 示例
句子1 句子2 相似度
车头 如何 放置 车牌 前 牌照 怎么装 0.8512318730354309
车头 如何 放置 车牌 如何 办理 北京 车牌 0.8042252361774445
车头 如何 放置 车牌 后 牌照 怎么装 0.8347993791103363
- 1
- 2
- 3
- 4
虽然三个句子的相似度区分度不是很大,但结果还是正确的,三个句子只有“前牌照怎么装”和“车头如何放置车牌”是最相似的,所以相似度相对较高。
1.2 小结
- 1.1种的示例是我用百度基于大规模语料训练并开源的模型simnet_bow_pairwise_pretrained_model推理的,这个模型可以作为预训练模型用自己的语料在它上面进行微调。
- 可以看到输入的句子都是分词后的,这也是SimNet预处理要做的工作——分词。
二、使用
详见SimNet源码,官方的readme介绍的比较清楚了。这里补充说明几点(可以先看完再去看官方说明):
- 环境依赖
- 要求Python 2 版本是 2.7.15+、Python 3 版本是 3.5.1+/3.6/3.7
我测试用的版本是3.7.4 - 要求深度学习框架paddlepaddle1.6+,参考安装指南
我测试用的版本是1.7.2.post107,107表示cuda10,cudnn7。因此我用的是gpu版的paddle框架,具体版本根据自己的配置选择,参考[安装指南] - 推荐使用conda管理环境
conda create -n paddle python==3.7.4
然后激活,到虚拟环境中安装其他库
conda activate paddle
- 输入必须分词
模型训练/推理的输入语料都必须是分完词的,不然就没有效果(模型内部是基于词的emb),分词工具在similarity_net同级的shared_modules/preprocess/tokenizer里,也可以使用其他分词工具例如jieba、hanlp等。
三、pairwise模式
本文我介绍的用法、原理以及最开始的例子都是基于pairwise模式的
3.1 训练集数据格式
句子Q\t句子D+\t句子D-,其中Q和D+是相似句,Q和D-是不相似句
这个不收费吧 这个是免费的吧 这个不好用吧
- 1
3.2 损失函数
损失函数使用HingeLoss,S(Q,D+)表示Q和D+的匹配得分(相似度)
max{0,margin-(S(Q,D+)-S(Q,D-))}
因此,优化目标是使得Q和D+的相似度与Q和D-的相似度的差异最大,也就是让正例和负例的得分差异最大。超参数margin的值,根据情况可以适当调整。
四、原理(基于bow词袋模型)
如果已经比较熟悉SimNet的使用了,可以进一步了解它的原理,以根据自己的需求改进具体的网络层结构。
4.1 原理简图
根据SimNet(基于bow词袋模型),我画了一个简图(如上,软件:XMind),框架主要流程为:
- 输入层:
将分完词的句子,首先查词表(term2id),将词转换为唯一的id(存储在张量tensor里)
例如:["你好 同学"]
–>[12345 23456]
- 词嵌入层:
将存储id的张量tensor通过词嵌入,映射为词向量emb - 表示层:
将词向量emb通过池化层压缩到最后一维(sum加和的方式),然后再进行softsign激活函数激活 - 匹配层:
上一步的激活后的张量tensor,首先通过一个全连接层(大概是用来增强语义表示吧),然后将经历同样过程的两个句子的向量进行cos_sim(余弦相似度)计算,得到相似度
4.2 改进思路
从原理可以看出来,SimNet(基于bow词袋模型)的结构是比较简单的,但有百度在该框架下开源的预训练模型(基于bow_pairwise)+预处理分词,最终效果还是可以的,但可能不适合高精度的应用场景。如果需要改进,可以从以下几点考虑:
- 表示层使用CNN、LSTM等,对语义特征提取的效果更好,官方也给写好了这几种方式,直接改参数config_path就可以换了
- 匹配层不直接对特征向量进行cos_sim(余弦相似度)计算,而是使用多层感知机MLP拟合出一个相似度
- 自定义网络层,主要是针对表示层
总结
SimNet是一个短文本语义相似度框架,模型比较简单容易理解,可以在熟悉使用方式的基础上进行微调/改进。
SimNet的讨论还是比较少的,可能是使用的人比较少吧。如果有什么见解欢迎和我交流,我也仅仅是使用了一段时间并没有完全深入底层。另外,想了解更多SimNet介绍可以参考SimNet优秀博客。
百度nlp的生态还是比较好的,除了语义相似度,还有情感分析、实体识别…另外比如部署模型可以使用paddle serving、使用paddle hub可以实现几行代码预测,还有像bert那种强大的预训练模型ernie…