机器学习与数据挖掘自然语言学习与实践Python

Keras蚂蚁金服大赛实战——自然语言处理技术(4)

2019-01-18  本文已影响1086人  王同学死磕技术

之前在自然语言处理技术系列的第一篇NER实战的结语中介绍过:序列标注(分词,NER),文本分类(情感分析),句子关系判断(语意相似判断),句子生成(机器翻译)是NLP领域的四大任务,之后我又陆续简单介绍了情感分析实战,和Seq2Seq生成对联。今天我们来到这个系列的终章篇——语义相似判断。语义相似判断就是判断两个句子是否具有相同的语义,其应用场景多用于问答系统:

当然也可以用于其他场景比如判断两幅图片是否是一样——人脸识别,所以从广义上来说,就是语义相识判断就是判断两个东西是否具有某种相似度的任务。

语义相似判断任务简介

语义相似可以转化为一个分类问题。给模型输入两个句子,然后希望模型判断出两个句子语义是否相似。具体输入输出细节如下:
输入:

输出:1
如果输出0表示不相似,输出1表示相似。

语义相似判断算法简介

语义相似还是NLP中的老问题,如何将句子映射到到向量空间中同时保持语义,然后我们就可以通过各种距离去衡量句子的相似程度。

蚂蚁金服大赛实战

读入数据

数据格式如下,每条数据都是两个句子和一个标签。


data

执行下方代码读入数据。

import pandas as pd
train_data = pd.read_csv("./huabei/train.csv",encoding="utf-8",header=None,sep="\t")
val_data = pd.read_csv("./huabei/val.csv",encoding="utf-8",header=None,sep="\t")
train_data[1] = train_data[1].apply(lambda x : [char for char in x])
train_data[2] = train_data[2].apply(lambda x : [char for char in x])
train_data

生成字典

执行下方代码,为后续的文本转ID构建一个字典。

from itertools import chain
train_data_1 = list(chain.from_iterable(train_data[1]))
train_data_2 = list(chain.from_iterable(train_data[2]))
all_words = set(train_data_1 + train_data_2)
print(len(all_words))
vocab = { j:i+1 for i, j in enumerate(all_words)}
vocab["unk"] = 0

数据预处理

做一些简单的文本转ID,然后padding,之后方便喂给模型。

from keras.preprocessing.sequence import pad_sequences
import numpy as np
train_data[1] = train_data[1].apply(lambda x:[vocab.get(i,0) for i in x])
train_data[2] = train_data[2].apply(lambda x:[vocab.get(i,0) for i in x])
Sens_1 = pad_sequences(train_data[1],maxlen=100)
Sens_2 = pad_sequences(train_data[2],maxlen=100)
labels = np.array(train_data[3])
labels = labels.reshape(*labels.shape,1)

构建模型

下面定义了一个构建模型的function。

def SiameseBiLSTM(vocab,max_length):
    K.clear_session()
    embedding = Embedding(input_dim = len(vocab),output_dim = 200, input_length=max_length)
    bilstm = Bidirectional(LSTM(128))

    sequence_input1 = Input(shape=(max_length,))
    embedded_sequences_1 = embedding(sequence_input1)
    x1 = bilstm(embedded_sequences_1)

    sequence_input2 = Input(shape=(max_length,))
    embedded_sequences_2 = embedding(sequence_input2)
    x2 = bilstm(embedded_sequences_2)

    merged = concatenate([x1, x2])
    merged = BatchNormalization()(merged)
    merged = Dropout(0.5)(merged)
    merged = Dense(100, activation="relu")(merged)
    merged = BatchNormalization()(merged)
    merged = Dropout(0.5)(merged)
    preds = Dense(1, activation='sigmoid')(merged)
    model = Model(inputs=[sequence_input1,sequence_input2], outputs=preds)
    model.compile(loss='binary_crossentropy', optimizer='adam')
    model.summary()
    return model

model = SiameseBiLSTM(vocab,100)

执行上方代码,从Keras的模型架构可视化输出可以清楚的看到embedding_1和bidirectional_1这辆层会被两个输入共享。


keras模型可视化

其架构示意图如下,两个输入通过BiLSTM编码成两个向量之后,直接将他们拼接一下,喂给下游的全连结层去做相识度判断。


Siamese BiLSTM Network

训练模型

model.fit([Sens_1,Sens_2],labels,batch_size=32,epochs=5,validation_split=0.2)

构建完模型后,将要判断相似度的句子,和标签喂给模型,定义好,batch_size,和训练轮数epoch,就让它跑起来,其模型训练过程如下图。


train

模型预测

model.predict([sen_pre_1,sen_pre_2])

通过上述代码就可以进行预测了,sen_pre_1和sen_pre_2是经过数据预处理,padding后的100维向量,模型会输出一个(0,1)之间的值,你可以定义一个阈值将这个值转换为[0,1]标签。

结语

至此,四大任务的自然语言处理(NLP)技术实战全部完结。任务看起来都很有趣,keras用起来也简单易上手,baseline的构建也不是很难。但是想要做好,还有大量工作要做。
这四个任务,还有很多可以优化的地方,比如

四个任务的flow都不是特别完美。笔者希望通过这个系列让大家感受到深度学习做NLP的乐趣。若想成为大神,从好奇,喜爱开始,然后苦读论文,多思考,勤做实验,多创新,这个过程就很枯燥了,坚持下去,才能有所建树。(后会有期)

参考:
https://github.com/amansrivastava17/lstm-siamese-text-similarity
https://www.jianshu.com/p/92d7f6eaacf5

上一篇 下一篇

猜你喜欢

热点阅读