[[NLP]基于Simaese LSTM的句子相似度计算
2017-11-02 17:13
375 查看
句子相似度计算在问答系统以及客服机器人当中应用比较频繁,比对针对对话模型中比较频繁的问句可以先进行过滤,之后再进行对话理解。在文本检测方面也有所应用,比如作家写作风格的检测。
本文叙述的句子相似度计算方法来自论文Siamese Recurrent Architectures for Learning Sentence Similarity,论文是基于Simaese LSTM网络对成对相似句进行训练,通过encode得到句子的向量表示之后计算曼哈顿距离(0-1之间)。
模型结构如下:
从上图可以看到模型分为a、b两个LSTM网络,分别对待测的两个句子进行encode得到待测句子的表示向量,最后将得到的两个向量进行距离计算,这里采用的是曼哈顿距离。
可以看到其实模型很简单,下面本文就尝试着实现一个这样的模型。
然后对他们进行两两自由组合,组合的结果如下所示:
得到语料之后,下一步的结果就是构造词典,单词索引。
下面结合具体的代码进行解释:
对齐之后的语料长下面这样:
得到的结果:[[ 0.91436553]],从感官上看还是合理的。
本文叙述的句子相似度计算方法来自论文Siamese Recurrent Architectures for Learning Sentence Similarity,论文是基于Simaese LSTM网络对成对相似句进行训练,通过encode得到句子的向量表示之后计算曼哈顿距离(0-1之间)。
模型结构如下:
从上图可以看到模型分为a、b两个LSTM网络,分别对待测的两个句子进行encode得到待测句子的表示向量,最后将得到的两个向量进行距离计算,这里采用的是曼哈顿距离。
可以看到其实模型很简单,下面本文就尝试着实现一个这样的模型。
语料预处理
本文使用的数据都是编造的,长下面这样:你们这个卡的号码要咋看 这个号码是经常变动的么 那下次再用号码会变吗 手机会显示电话号码吗 我这个卡的号码在哪里看 我怎么查我的卡的号码 怎么才能知道电话号码是什么呢 怎么看卡的电话号码 卡的电话号码应该怎么看呢 卡的电话号码在哪里可以查到呢 在哪里可以看到电话号码 卡的电话号码如何查询 卡的电话号码怎么才能知道 我买的电话卡号码怎么知道 我怎么知道我电话号码是什么 卡身上可以找到号码吗 sim卡上有号码吗 咋查手机号啊 别人要打我手机但我怎么查手机号多少啊 如何查看我这张卡的号码呀 怎么查询卡的号码 如何知道电话卡的号码 香港电话卡的号码应该怎么知道呢 香港电话卡的号码怎么被知道
然后对他们进行两两自由组合,组合的结果如下所示:
你们这个卡的号码要咋看 这个号码是经常变动的么 你们这个卡的号码要咋看 那下次再用号码会变吗 你们这个卡的号码要咋看 手机会显示电话号码吗 你们这个卡的号码要咋看 我这个卡的号码在哪里看 你们这个卡的号码要咋看 我怎么查我的卡的号码 你们这个卡的号码要咋看 怎么才能知道电话号码是什么呢 你们这个卡的号码要咋看 怎么看卡的电话号码 你们这个卡的号码要咋看 卡的电话号码应该怎么看呢 你们这个卡的号码要咋看 卡的电话号码在哪里可以查到呢 ....
得到语料之后,下一步的结果就是构造词典,单词索引。
下面结合具体的代码进行解释:
path='./data/qa_test.txt'#数据的路径 path_word2vec='/home/ruben/data/nlp/word2vec_wx'#word2vec路径 #造数据 fake_data=open(path,'r').readlines() tain_data_l=[] tain_data_r=[] for line in fake_data: for line2 in fake_data: if(line is not line2): print(line.replace('\n',''),line2.replace('\n','')) tain_data_l.append(line.replace('\n','')) tain_data_r.append(line2.replace('\n','')) print('left length:',len(tain_data_l)) print('right length:',len(tain_data_r)) import jieba #构造字典和weight矩阵 list_word=['UNK'] dict_word={} tain_data_l_n=[]#左边LSTM的输入 tain_data_r_n=[]#右边LSTM的输入 for data in [tain_data_l,tain_data_r]: for line in data: words=list(jieba.cut(line)) for i,word in enumerate(words): if word not in dict_word: dict_word[word]=len(dict_word) print(dict_word)#字典构造完毕 id2w={dict_word[w]:w for w in dict_word}#word的索引 embedding_size=256 embedding_arry=np.random.randn(len(dict_word)+1,embedding_size)#句子embedding矩阵 embedding_arry[0]=0 word2vector=KeyedVectors.load(path_word2vec) for index,word in enumerate(dict_word): if word in word2vector.wv.vocab: embedding_arry[index]=word2vector.wv.word_vec(word) print('embedding_arry shape:',embedding_arry.shape) del word2vector #将词组替换为索引 for line in tain_data_l: words = list(jieba.cut(line)) for i,word in enumerate(words): words[i]=dict_word[word] tain_data_l_n.append(words) print('tain_data_l_n length:',len(tain_data_l_n)) y_train=np.ones((len(tain_data_l_n),)) for line in tain_data_r: words = list(jieba.cut(line)) for i,word in enumerate(words): words[i]=dict_word[word] tain_data_r_n.append(words) print('tain_data_r_n length:',len(tain_data_r_n)) #得到语料中句子的最大长度 max_length=0 for line in tain_data_r_n: if max_length<len(line): max_length=len(line) print('max length:',max_length) # 对齐语料中句子的长度 tain_data_l_n = pad_sequences(tain_data_l_n, maxlen=max_length) tain_data_r_n = pad_sequences(tain_data_r_n, maxlen=max_length)
对齐之后的语料长下面这样:
tain_data_l_n:[[ 0 0 0 ..., 5 6 7] [ 0 0 0 ..., 5 6 7] [ 0 0 0 ..., 5 6 7] ..., [ 0 0 0 ..., 24 57 27] [ 0 0 0 ..., 24 57 27] [ 0 0 0 ..., 24 57 27]] tain_data_r_n:[[ 0 0 0 ..., 10 3 11] [ 0 0 0 ..., 4 15 16] [ 0 0 0 ..., 19 20 16] ..., [ 0 0 0 ..., 55 3 4] [ 0 0 0 ..., 38 3 4] [ 0 0 0 ..., 24 27 29]]
模型构建
#模型参数 n_hidden = 50 gradient_clipping_norm = 1.25 batch_size = 5 n_epoch = 15 #相似度计算 def exponent_neg_manhattan_distance(left, right): return K.exp(-K.sum(K.abs(left - right), axis=1, keepdims=True)) #输入层 left_input = Input(shape=(max_length,), dtype='int32') right_input = Input(shape=(max_length,), dtype='int32') embedding_layer = Embedding(len(embedding_arry), embedding_size, weights=[embedding_arry], input_length=max_length, trainable=False) #对句子embedding encoded_left = embedding_layer(left_input) encoded_right = embedding_layer(right_input) #两个LSTM共享参数 shared_lstm = LSTM(n_hidden) left_output = shared_lstm(encoded_left) right_output = shared_lstm(encoded_right) malstm_distance = Merge(mode=lambda x: exponent_neg_manhattan_distance(x[0], x[1]), output_shape=lambda x: (x[0][0], 1))([left_output, right_output]) # model malstm = Model([left_input, right_input], [malstm_distance]) optimizer = Adadelta(clipnorm=gradient_clipping_norm) malstm.compile(loss='mean_squared_error', optimizer=optimizer, metrics=['accuracy']) #train malstm.fit(x=[np.asarray(tain_data_l_n), np.asarray(tain_data_r_n)], y=y_train, batch_size=batch_size, epochs=n_epoch, validation_data=([np.asarray(tain_data_l_n), np.asarray(tain_data_r_n)], y_train) )
预测
print(malstm.predict([np.array([1,2,3,4,5,6,7,7,0,0,0,0]).reshape(-1,12),np.array([1,2,23,4,12,6,7,22,0,0,0,0]).reshape(-1,12)]))
得到的结果:[[ 0.91436553]],从感官上看还是合理的。
相关文章推荐
- 基于Simase_LSTM的计算中文句子相似度经验总结与分享
- 基于语义依存的汉语句子相似度计算.JPG
- 基于gensim模块的中文句子相似度计算工具
- 对“基于语义依存的汉语句子相似度计算”的优化。
- 基于VSM计算相似度(含Python代码)
- 基于编辑距离和最长公共子串计算字符串相似度
- 关于word2vec 句子相似度计算
- 智能语言处理之依存树计算句子结构相似度计算
- 余弦定理的应用:基于文字的文本相似度计算
- 基于《知网》的词汇语义相似度计算(上)(作者:刘群 李素建)
- LSF-SCNN:一种基于 CNN 的短文本表达模型及相似度计算的全新优化模型
- 计算l两个句子之间的余弦相似度
- 深度学习解决NLP问题:语义相似度计算——DSSM
- 【JAVA实现】基于欧几里得度量的相似度计算
- Mahout基于对数似然比更好的计算相似度
- 基于Map-Reduce的相似度计算
- 句子语义相似度计算
- 关于word2vec 句子相似度计算
- 一个基于特征向量的近似网页去重算法——term用SVM人工提取训练,基于term的特征向量,倒排索引查询相似文档,同时利用cos计算相似度
- NLP入门(一)词袋模型及句子相似度