NLP10:基于SiameseNetwork的文本相似度计算

2024-09-01 08:18

本文主要是介绍NLP10:基于SiameseNetwork的文本相似度计算,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

公众号:数据挖掘与机器学习笔记

一、文本相似度简介

在上一篇文章中,简要介绍了孪生网络(siamese network)的基本原理及应用实战,这里再使用孪生网络来进行文本相似度计算。

文本的相似性计算是“文本匹配”的一种特殊情况。一般来说,文本相似度计算任务的输入,是两篇文档,比如下表的前两个句子;输出是两篇文档的相似程度,通常用[0,1]区间内的小数来表示。

文本相似度计算在许多NLP任务中都有用到,比如问答系统,通常用户给定一个问题,需要去答案库中匹配一个答案。此时,可以直接匹配到一个答案,也可以先匹配相似的问题,再给出问题的标准答案。那么该如何计算文本相似度呢?文本相似度计算方法有2个关键组件,即文本表示模型和相似度度量方法,如下表。前者负责将文本表示为计算机可以计算的数值向量,也就是提供特征;后者负责基于前面得到的数值向量计算文本之间的相似度。从文本表示模型和相似度度量方法中选择合适的,就可以组合出一个文本相似度计算方案。

上述文本相似度计算方法都是先把给定文档通过某种向量化方法表示成文档向量,然后使用指定的相似度计算方法计算两个文本的相似度(距离)。这些方法都是无监督方法,比较简单、计算高效,不需要标注语料,特征工程或者参数估计可以使用很大的数据;很多方法对语言的依赖比较小,可以应对多语种混杂的场景;距离计算环节复杂度较低。

此外,也可以使用有监督学习方法来计算文本相似度。就是用朴素贝叶斯分类器或者神经网络模型之类的有监督模型来判断文本相似性或者计算相似度。这类方法要求有一定数量的标注语料,构建的代价比较高;由于训练语料通常无法做得很大,模型的泛化性不够,实际用起来会有点麻烦;距离计算环节的复杂度会比较高。

这里只是简要介绍下文本相似度的基本原理和方法,详细的知识可以参考这篇文章。接下来就使用孪生网络来实现文本相似度算法。

二、使用siamese network进行文本相似度计算

2.1 数据介绍

数据使用的是拍拍贷智慧金融研究院主办的第三届“魔镜杯”中的数据,拍拍贷提供智能客服聊天机器人真实数据,以自然语言处理和文本挖掘技术为主要探索对象,希望比赛选手能利用这些资源开发一种算法,提高智能客服的识别能力和服务质量。

本次比赛使用了脱敏数据,所有原始文本信息都被编码成单字ID序列和词语ID序列,并提供由google word2vec训练的300维的word_embedding和char_embedding。训练数据包含3列,label, q1, q2,其中q1和q2表示要判断的两个问题,label=1表示是相同的问题,label=0表示不同的问题。比赛要求参赛选手预测测试数据中的每一对问题是否是同一个意思。

具体数据请查看第三届魔镜杯大赛数据介绍

训练数据

训练数据

image-20201004202047027

测试数据

image-20201004202134384

问题

image-20201004202257799

预训练的字符向量

image-20201004202348112

预训练的词向量

2.2 数据处理

把数据处理成训练需要的格式

import numpy as np
import pandas as pd
import os
import mathdef sentences_to_indices(X, word_to_index, max_len):"""把字符串数组转换为字符数值索引数组:param X:string 数组:param word_to_index::param max_len:最长的序列长度:return:"""m = X.shape[0]X_indices = np.zeros((m, max_len))for i in range(m):# split字符串sentence_words = X[i].split(" ")for j, w in enumerate(sentence_words):if j >= max_len:breakX_indices[i, j] = word_to_index[w]return X_indicesdef load_dataset(data_dir, max_seq_len, embed_dim, word_level=True):"""读取数据,对数据进行预处理,并生成embed_matrix:param data_dir:数据目录:param max_seq_len::param embed_dim:词向量维度:param word_level::return:"""question_path = os.path.join(data_dir, "question.csv")train_path = os.path.join(data_dir, "train.csv")if word_level:embed_path = os.path.join(data_dir, "word_embed.txt")  # 词向量else:embed_path = os.path.join(data_dir, "char_embed.txt")  # 字符向量# 读取数据question = pd.read_csv(question_path)train = pd.read_csv(train_path)# 把train里面的问题id匹配到句子train = pd.merge(train, question, left_on=["q1"], right_on=["qid"], how="left")  # 匹配第一个问题train = pd.merge(train, question, left_on=["q2"], right_on=["qid"], how="left")  # 匹配第二个问题if word_level:train = train[["label", "words_x", "words_y"]]else:train = train[["label", "chars_x", "chars_y"]]train.columns = ["label", "q1", "q2"]word_to_vec_map = pd.read_csv(embed_path, sep=" ", header=None, index_col=0)word = word_to_vec_map.index.values# word2id,id2wordword_to_index = dict([(word[i], i+1) for i in range(len(word))])index_to_word = dict([(i+1, word[i]) for i in range(len(word))])train_q1_indices = sentences_to_indices(train.q1.values, word_to_index, max_seq_len)train_q2_indices = sentences_to_indices(train.q2.values, word_to_index, max_seq_len)label = train.label.valuesvocab_len = len(word_to_index)+1embed_matrix = np.zeros((vocab_len, embed_dim))for word, index in word_to_index.items():embed_matrix[index, :] = word_to_vec_map.loc[word].valuesreturn train_q1_indices, train_q2_indices, label, embed_matrix, word_to_index, index_to_worddef load_test_data(data_dir, max_seq_len, word_level=True):"""读取测试数据:param max_seq_len::param word_level::return:"""question_path = os.path.join(data_dir, "question.csv")test_path = os.path.join(data_dir, "test.csv")if word_level:embed_path = os.path.join(data_dir, "word_embed.txt")else:embed_path = os.path.join(data_dir, "char_embed.txt")# 读取数据question = pd.read_csv(question_path)test = pd.read_csv(test_path)test = pd.merge(test, question, left_on=["q1"], right_on=["qid"], how="left")test = pd.merge(test, question, left_on=["q2"], right_on=["qid"], how="left")if word_level:test = test[["words_x", "words_y"]]else:test = test[["chars_x", "chars_y"]]test.columns = ["q1", "q2"]word_to_vec_map = pd.read_csv(embed_path, sep=" ", header=None, index_col=0)word = word_to_vec_map.index.values# word2id,id2wordword_to_index = dict([(word[i], i+1) for i in range(len(word))])index_to_word = dict([(i+1, word[i]) for i in range(len(word))])test_q1_indices = sentences_to_indices(test.q1.values, word_to_index, max_seq_len)test_q2_indices = sentences_to_indices(test.q2.values, word_to_index, max_seq_len)return test_q1_indices, test_q2_indices

2.3 模型网络结构搭建

使用LSTM作为基础网络组件

import numpy as np
import pandas as pdnp.random.seed(0)from tensorflow import keras
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Embedding, GaussianNoise, \Input, Dropout, LSTM, Activation, BatchNormalization, concatenate, Subtract, Dot, Multiply, Bidirectional, Lambda
from tensorflow.keras.initializers import glorot_uniform
from tensorflow.keras import optimizers
import tensorflow as tf
import tensorflow.keras.callbacks as kcallbacksnp.random.seed(1)
import warningswarnings.filterwarnings("ignore")MAX_SEQUENCE_LENGTH = 15  # 20 for character level and 15 for word level
EMBEDDING_DIM = 300
lstm_num = 64
lstm_drop = 0.5
BATCH_SIZE = 100def trainLSTM(train_q1, train_q2, train_label, embed_matrix):question1 = Input(shape=(MAX_SEQUENCE_LENGTH,), batch_size=BATCH_SIZE)question2 = Input(shape=(MAX_SEQUENCE_LENGTH,), batch_size=BATCH_SIZE)embed_layer = Embedding(embed_matrix.shape[0], EMBEDDING_DIM,weights=[embed_matrix]) #q1_embed = embed_layer(question1)q2_embed = embed_layer(question2)shared_lstm1 = LSTM(lstm_num, return_sequences=True)shared_lstm2 = LSTM(lstm_num)q1 = shared_lstm1(q1_embed)q1 = Dropout(lstm_drop)(q1)q1 = BatchNormalization()(q1)q1 = shared_lstm2(q1)q2 = shared_lstm1(q2_embed)q2 = Dropout(lstm_drop)(q2)q2 = BatchNormalization()(q2)q2 = shared_lstm2(q2)# 求distance (batch_size,lstm_num)d = Subtract()([q1, q2])distance = Multiply()([d, d])# 求angle (batch_size,lstm_num)angle = Multiply()([q1, q2])merged = concatenate([distance, angle])merged = Dropout(0.3)(merged)merged = BatchNormalization()(merged)merged = Dense(256, activation="relu")(merged)merged = Dropout(0.3)(merged)merged = BatchNormalization()(merged)merged = Dense(64, activation="relu")(merged)merged = Dropout(0.3)(merged)merged = BatchNormalization()(merged)res = Dense(1, activation="sigmoid")(merged)model = Model(inputs=[question1, question2], outputs=res)model.compile(loss=keras.losses.BinaryCrossentropy(), optimizer="adam", metrics=["accuracy"])model.summary()hist = model.fit([train_q1, train_q2],train_label,epochs=30, batch_size=BATCH_SIZE, validation_split=0.2,shuffle=True)

2.4 模型训练

train_q1_indices, train_q2_indices, train_label, embed_matrix, word_to_index, index_to_word = load_dataset("/content/drive/My Drive/data/text_similarity/data", MAX_SEQUENCE_LENGTH, EMBEDDING_DIM, False)
print('train_q1: ', train_q1_indices.shape)
print('train_q2: ', train_q2_indices.shape)
print('train_label: ', tf.one_hot(train_label,depth=2).shape)
print('embed_matrix: ', embed_matrix.shape)# 加载test 数据
test_q1, test_q2 = load_test_data("/content/drive/My Drive/data/text_similarity/data", MAX_SEQUENCE_LENGTH, word_level=False)
print('test_q1: ', test_q1.shape)
print('test_q2: ', test_q2.shape)
print("word_to_index len:",len(word_to_index))
trainLSTM(train_q1_indices[:243000], train_q2_indices[:243000], train_label[:243000], embed_matrix) #我这里使用的Colab,数据数量无法整除BATCH_SIZE时会报错

参考:

[1] https://zhuanlan.zhihu.com/p/88938220

[2] https://www.jianshu.com/p/827dd447daf9

github代码:https://github.com/chongzicbo/nlp-ml-dl-notes/blob/master/code/text_similarity/NLP10%EF%BC%9Asiamese_text_similarity.ipynb

在这里插入图片描述

这篇关于NLP10:基于SiameseNetwork的文本相似度计算的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1126411

相关文章

苹果macOS 26 Tahoe主题功能大升级:可定制图标/高亮文本/文件夹颜色

《苹果macOS26Tahoe主题功能大升级:可定制图标/高亮文本/文件夹颜色》在整体系统设计方面,macOS26采用了全新的玻璃质感视觉风格,应用于Dock栏、应用图标以及桌面小部件等多个界面... 科技媒体 MACRumors 昨日(6 月 13 日)发布博文,报道称在 macOS 26 Tahoe 中

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可

Java计算经纬度距离的示例代码

《Java计算经纬度距离的示例代码》在Java中计算两个经纬度之间的距离,可以使用多种方法(代码示例均返回米为单位),文中整理了常用的5种方法,感兴趣的小伙伴可以了解一下... 目录1. Haversine公式(中等精度,推荐通用场景)2. 球面余弦定理(简单但精度较低)3. Vincenty公式(高精度,

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

C#TextBox设置提示文本方式(SetHintText)

《C#TextBox设置提示文本方式(SetHintText)》:本文主要介绍C#TextBox设置提示文本方式(SetHintText),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录C#TextBox设置提示文本效果展示核心代码总结C#TextBox设置提示文本效果展示核心代

使用Python实现文本转语音(TTS)并播放音频

《使用Python实现文本转语音(TTS)并播放音频》在开发涉及语音交互或需要语音提示的应用时,文本转语音(TTS)技术是一个非常实用的工具,下面我们来看看如何使用gTTS和playsound库将文本... 目录什么是 gTTS 和 playsound安装依赖库实现步骤 1. 导入库2. 定义文本和语言 3

Python实现常用文本内容提取

《Python实现常用文本内容提取》在日常工作和学习中,我们经常需要从PDF、Word文档中提取文本,本文将介绍如何使用Python编写一个文本内容提取工具,有需要的小伙伴可以参考下... 目录一、引言二、文本内容提取的原理三、文本内容提取的设计四、文本内容提取的实现五、完整代码示例一、引言在日常工作和学