短文本语义匹配/文本相似度框架(SimilarityNet, SimNet),基于bow_pairwise模式及框架原理介绍

用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介绍的比较清楚了。这里补充说明几点(可以先看完再去看官方说明):

  1. 环境依赖
  • 要求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
  1. 输入必须分词
    模型训练/推理的输入语料都必须是分完词的,不然就没有效果(模型内部是基于词的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 原理简图

短文本语义匹配/文本相似度框架(SimilarityNet, SimNet),基于bow_pairwise模式及框架原理介绍_第1张图片
根据SimNet(基于bow词袋模型),我画了一个简图(如上,软件:XMind),框架主要流程为:

  1. 输入层:
    将分完词的句子,首先查词表(term2id),将词转换为唯一的id(存储在张量tensor里)
    例如:["你好 同学"]–> [12345 23456]
  2. 词嵌入层:
    将存储id的张量tensor通过词嵌入,映射为词向量emb
  3. 表示层:
    将词向量emb通过池化层压缩到最后一维(sum加和的方式),然后再进行softsign激活函数激活
  4. 匹配层:
    上一步的激活后的张量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…

你可能感兴趣的:(ppython,自然语言处理,字符串,短文本语义匹配,文本相似度,pairwise,pointwise,SimNet)