LSTM 句子相似度分析

使用句子中出现单词的Vector加权平均进行文本相似度分析虽然简单,但也有比较明显的缺点:没有考虑词序且词向量区别不明确。如下面两个句子:

  • “北京的首都是中国”与“中国的首都是北京”的相似度为1。
  • “学习容易”和“学习困难”的相似度很容易也非常高。
    为解决这类问题,需要用其他方法对句子进行表示,LSTM是常用的一种方式,本文简单使用单层LSTM对句子重新表示,并通过若干全连接层对句子相似度进行衡量。
数据准备

训练和测试数据包括两个待比较句子以及其相似度(0-1):

测试数据格式相似。

语料编码

自然语言无法直接作为神经网络输入,需进行编码该部分包括以下步骤:

  • 读人训练和测试数据,分词,并给每个词编号。
  • 根据词编号,进一步生成每个句子的编号向量,句子采用固定长度,不足的位置补零。
  • 保存词编号到文件,保存词向量矩阵方便预测使用。

中文分词使用jieba分词工具,词的编号则使用Keras的Tokenizer:

12345678
print("Fit tokenizer...")tokenizer = Tokenizer(num_words=MAX_NB_WORDS, lower=False)tokenizer.fit_on_texts(texts_1 + texts_2 + test_texts_1 + test_texts_2)if save:    print("Save tokenizer...")    if not os.path.exists(save_path):        os.makedirs(save_path)    cPickle.dump(tokenizer, open(os.path.join(save_path, tokenizer_name), "wb"))

其中texts_1 、texts_2 、test_texts_1 、 test_texts_2的元素分别为训练数据和测试数据的分词后的列表,如:

1
["我", "是", "谁"]

经过上面的过程 tokenizer保存了语料中出现过的词的编号映射。

12
> print tokenizer.word_index{"我": 2, "是":1, "谁":3}

利用tokenizer对语料中的句子进行编号

123
> sequences_1 = tokenizer.texts_to_sequences(texts_1)> print sequences_1[[2 1 3], ...]

最终生成固定长度(假设为10)的句子编号列表

123
> data_1 = pad_sequences(sequences_1, maxlen=MAX_SEQUENCE_LENGTH)> print data_1[[0 0 0 0 0 0 0 2 1 3], ...]

data_1即可作为神经网络的输入。

词向量映射

在对句子进行编码后,需要准备句子中词的词向量映射作为LSTM层的输入。这里使用预训练的词向量(这里)参数,生成词向量映射矩阵:

123456
word2vec = Word2Vec.load(EMBEDDING_FILE)embedding_matrix = np.zeros((nb_words, EMBEDDING_DIM))for word, i in word_index.items():    if word in word2vec.wv.vocab:        embedding_matrix[i] = word2vec.wv.word_vec(word)np.save(embedding_matrix_path, embedding_matrix)
网络结构

该神经网络采用简单的单层LSTM+全连接层对数据进行训练,网络结构图:

网络由Keras实现:

1234567891011121314151617181920212223242526272829303132 大专栏  LSTM 句子相似度分析
def ():    embedding_layer = Embedding(nb_words,                                EMBEDDING_DIM,                                weights=[embedding_matrix],                                input_length=MAX_SEQUENCE_LENGTH,                                trainable=False)    lstm_layer = LSTM(num_lstm, dropout=rate_drop_lstm, recurrent_dropout=rate_drop_lstm)

    sequence_1_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')    embedded_sequences_1 = embedding_layer(sequence_1_input)    y1 = lstm_layer(embedded_sequences_1)

    sequence_2_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')    embedded_sequences_2 = embedding_layer(sequence_2_input)    y2 = lstm_layer(embedded_sequences_2)

    merged = concatenate([y1, y2])    merged = Dropout(rate_drop_dense)(merged)    merged = BatchNormalization()(merged)

    merged = Dense(num_dense, activation=act)(merged)    merged = Dropout(rate_drop_dense)(merged)    merged = BatchNormalization()(merged)    preds = Dense(1, activation='sigmoid')(merged)

    model = Model(inputs=[sequence_1_input, sequence_2_input],                   outputs=preds)    model.compile(loss='binary_crossentropy',                  optimizer='nadam',                  metrics=['acc'])    model.summary()    return model

该部分首先定义embedding_layer作为输入层和LSTM层的映射层,将输入的句子编码映射为词向量列表作为LSTM层的输入。两个LSTM的输出拼接后作为全连接层的输入,经过Dropout和BatchNormalization正则化,最终输出结果进行训练。

训练与预测

训练采用nAdam以及EarlyStopping,保存训练过程中验证集上效果最好的参数。最终对测试集进行预测。

1234567891011
model = get_model()early_stopping = EarlyStopping(monitor='val_loss', patience=3)bst_model_path = STAMP + '.h5'model_checkpoint = ModelCheckpoint(bst_model_path, save_best_only=True, save_weights_only=True)

hist = model.fit([data_1, data_2], labels,                  validation_data=([val_1, val_2], labels),                  epochs=100, batch_size=10, shuffle=True, callbacks=[early_stopping, model_checkpoint])predicts = model.predict([data_1, data_2], batch_size=10, verbose=1)for i in range(len(test_ids)):    print "t1: %s, t2: %s, score: %s" % (test_1[i], test_2[i], predicts[i])
小结

该网络在Kaggle Quora数据集val验证可达到80%左右的准确率,应用于中文,由于数据集有限,产生了较大的过拟合。此外在Tokenizer.fit_on_texts应用于中文时,不支持Unicode编码,可以对其源码方法进行重写,加入Ascii字符和Unicode的转换。

12345678910111213141516
'''this part is solve keras.preprocessing.text can not process unicode'''def text_to_word_sequence(text,                          filters='!"#$%&()*+,-./:;<=>[email protected][\]^_`{|}~tn',                          lower=True, split=" "):    if lower: text = text.lower()    if type(text) == unicode:        translate_table = {ord(c): ord(t) for c, t in zip(filters, split * len(filters))}    else:        translate_table = keras.maketrans(filters, split * len(filters))    text = text.translate(translate_table)    seq = text.split(split)    return [i for i in seq if i]

keras.preprocessing.text.text_to_word_sequence = text_to_word_sequence
项目源码https://github.com/zqhZY/semanaly/

更多关注公众号:

原文地址:https://www.cnblogs.com/lijianming180/p/12259000.html

时间: 2024-10-03 14:55:44

LSTM 句子相似度分析的相关文章

中文句子相似度之計算與應用

原文:http://www.aclweb.org/anthology/O05-1008 中文句子相似度之计算与应用 郑守益 梁婷国立交通大学信息科学系 摘要 近年來受惠于国内外各项语料库资源的建置及网际网路上的大量中文语料,使计算机语文辅助教材的涵盖层面日趋广泛.因此如何产生大量且具高质量之辅助教材日益受到许多自然语言处理研究者的重视.有鉴于此,本論文提出以中文句子相似度为基础的研究与应用.相似度的计算乃考虑句子的组合及聚合性.我们实作此一应用,并提出解决未知词的语意计算问题的方法.实验结果显示

算法录 之 复杂度分析。

一个算法的复杂度可以说也就是一个算法的效率,一般来说分为时间复杂度和空间复杂度... 注意接下来说的均是比较YY的,适用与ACM等不需严格分析只需要大致范围的地方,至于严格的算法复杂度分析的那些数学证明,主定理什么的在<算法导论>这本书上有十分详细的讲解,网上应该也会有人写过,这里就不多说了(其实,是我不会而已o(╯□╰)o...). — 到底啥是复杂度呢?先来个栗子. 小明有10个苹果,有一天他饿了,然后准备吃掉一个苹果,但是小明有中二病,他要吃里面重量最大的那个,于是...他需要一个找到那

相似度分析的地址

相似度分析的,其中的分词可以采用HanLP即可: http://www.open-open.com/lib/view/open1421978002609.htm

Python 文本相似度分析

环境 Anaconda3 Python 3.6, Window 64bit 目的 利用 jieba 进行分词,关键词提取 利用gensim下面的corpora,models,similarities 进行语料库建立,模型tfidf算法,稀疏矩阵相似度分析 代码 # -*- coding: utf-8 -*- import jieba from gensim import corpora, models, similarities from collections import defaultdi

斐波那契数与二分法的递归与非递归算法及其复杂度分析

1. 什么是斐波那契数? 这里我借用百度百科上的解释:斐波那契数,亦称之为斐波那契数列(意大利语: Successione di Fibonacci),又称黄金分割数列.费波那西数列.费波拿契数.费氏数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=Fn-1+Fn-2(n>=2,n∈N*),用文字来说,就是斐波那契数列列由 0 和 1 开始,之后的斐波那契数列系数就由之前的两数相加.特别指出:0不是第一

递归算法复杂度分析方法

递归算法的复杂度分析方法. a.分析出复杂度公式(关于n的规模) b.求解这个公式 1.齐次 例如求fabonaci的第n项,f(n) = f(n-1)+f(n-2) => f(n)-f(n-1)-f(n-2)=0 =>特征方程:x^2-x-1=0 => x1,x2 => f(n)=a*x1n + b*x2n 2.master method T(n) = aT(n/b) + f(n) 3.采用分析树的方式 举个例子 f(n) = 2*f(n-1) + 1 1 1 ---------

杨辉三角(Pascal Triangle)的几种C语言实现及其复杂度分析

说明 本文给出杨辉三角的几种C语言实现,并简要分析典型方法的复杂度. 本文假定读者具备二项式定理.排列组合.求和等方面的数学知识. 一  基本概念 杨辉三角,又称贾宪三角.帕斯卡三角,是二项式系数在三角形中的一种几何排列.此处引用维基百科上的一张动态图以直观说明(原文链接http://zh.wikipedia.org/wiki/杨辉三角): 从上图可看出杨辉三角的几个显著特征: 1. 每行数值左右对称,且均为正整数. 2. 行数递增时,列数亦递增. 3. 除斜边上的1外,其余数值均等于其肩部两数

算法9-4:最大流算法复杂度分析

前面一节介绍了Ford-Fulkerson算法.那么这个算法是否一定能够在有限步骤内结束?要多少步骤呢? 这个问题的答案是,该算法确实能够在有限步骤之内结束,但是至于需要多少步骤,就要仔细分析. 为了分析问题,需要假定图中所有边的容量都是整数.但是有个严重的问题,比如下图中,如果使用Ford-Fulkerson算法,需要迭代200次才能结束. 首先将所有边的容量都初始化为0. 第一次迭代和第二次迭代之后,两条边各增加了1. 到最后200次迭代之后整个算法才结束. 这还不算最坏的情况.因为整数最多

汉语语义消歧之 -- 句子相似度

这里隆重推出介绍一种词义消歧的(简单)方法:句子相似度 虽然第一反应一定是介个,但是总不能说他们的相似度就是单词出现的重复次数吧= =||,怎么看都觉得不科学233 于是,我们想到了最简单却又好用的相似度判断方式,就是"余弦相似性"(cosine similiarity)了啦: 我们现在有两句话s1和s2,那么他们的余弦相似度怎么求呢? 现在令s1.s2词频向量为v1.v2(注意,是向量!),则我们"想象一下": 如果v1和v2方向相同,大致等价于s1.s2句子构成