美文网首页机器学习与数据挖掘自然语言学习与实践Python
Keras蚂蚁金服大赛实战——自然语言处理技术(4)

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

作者: 王同学死磕技术 | 来源:发表于2019-01-18 14:50 被阅读1086次

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

    • 判断两个问句是否具有相同的语义。
    • 判断问题和检索出的答案是否匹配。

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

    语义相似判断任务简介

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

    • 1.为何我无法申请开通花呗信用卡收款
    • 2.支付宝开通信用卡花呗收款不符合条件怎么回事

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

    语义相似判断算法简介

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

    • 上古时期的方式是通过bag of words,tf-idf这种词袋模型去映射句子。
    • 之后出现了word2vector技术,我们就可以将一句话中每个词的的词向量求平均来表示句子向量,后面又出现了借用word2vector的思路实现的sen2vector技术。
    • 最近比较火的当然就是使用深度学习技术将句子映射到向量空间。
      这里我简要的介绍一下我在实战中使用的深度学习模型Siamese Network架构。
      Siamese在英语中是“孪生”、“连体”的意思,而Siamese Network,如下图所示就是两个共享参数的神经网络,其中神经网络部分可以任意构建,使用CNN,RNN之类的都可以。通过同一网络将两个输入映射到向量空间,然后在去计算它们的相似性,相似性度量可以通过:
    • 欧式距离,
    • 余弦距离,
    • 或者给数据打上标签,通过神经网络去判断相似性等。


      Siamese Network

      本次实战就是采用的Siamese-BiLSTM,意思就是用双向的LSTM做共享参数的network部分。

    蚂蚁金服大赛实战

    读入数据

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


    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的构建也不是很难。但是想要做好,还有大量工作要做。
    这四个任务,还有很多可以优化的地方,比如

    • 在输入部分,我很少预训练词向量(除了情感分析实战),对于模型的输入我也是以字为单位,要知道中文以词为单位时其表达才准确;
    • 在模型上的使用,我基本上全用的LSTM或者GRU,没有加任何attention,也没使用更复杂的网络;(需要扎实的领域知识和脑洞)
    • 模型训练部分,超参数的调优和模型的evaluation我基本上没做。(极其耗时耗力)

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

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

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/hsvgdqtx.html