中科院深度文本匹配开源项目MatchZoo简单上手

MatchZoo是一个Python环境下基于TensorFlow开发的开源文本匹配工具,让大家更加直观地了解深度文本匹配模型的设计、更加便利地比较不同模型的性能差异、更加快捷地开发新型的深度匹配模型。就我的理解,MatchZoo是实现了主要思想为孪生网络的深度模型

文本匹配包含了文本相似度、文本蕴含、问答匹配等问题,在这里,我会简单的使用微软公开的MSR数据集进行相似度计算解说,代码由本人参考matchzoo官方的解说完成的,如果有什么错误,请大胆指出,我会进一步改进。

数据集说明:MSR数据集是英文短文本相似度计算的标准数据集,其中训练集有4076个句子,其中包含2753个相似度为1,即为正例句子;测试集有1725个句子,其中包含1147个正例句子。
下载链接:https://www.microsoft.com/en-us/download/details.aspx?id=52398&from=http%3A%2F%2Fresearch.microsoft.com%2Fen-us%2Fdownloads%2F607d14d9-20cd-47e3-85bc-a2f65cd28042%2Fdefault.aspx
如果觉得麻烦,我已经下载好分享出来:https://download.csdn.net/download/weixin_40902563/12047069
赚积分不容易,如果没有积分,可以私聊并发邮箱,我会免费发送给你们(前提是我有看消息哈,大概两天一看)

官方提供的数据集是这样的格式:在这里插入图片描述
说它是tsv文件,但是用pandas去读的话,会有点错误,所以我采用readlines方式,分隔符用\t来切割每一行。
接下来代码开始,虽然我不是这种写代码的风格,但为了每一步说清楚,我会一段段解释一下。
导入的模块和定义数据处理器:

#!/usr/bin/python3
# -*- coding:utf-8 -*-
# Author:ChenYuan

import matchzoo as mz
import pandas as pd
import re  # 这个可以不用
from sklearn import preprocessing  # 用于正则化
import numpy as np 
preprocessor = mz.preprocessors.BasicPreprocessor()  # 定义一个数据处理器,有四种处理器,Basic是通用的、基础的数据处理器,可看官方文档,这里不做解说

数据格式转换:

data = []
data_type = 'train'
with open('msr_paraphrase_%s.txt' % data_type, 'r', encoding='utf-8')as f:
    for line in f.readlines()[1:]:  # 这个是为了忽略标题
        line = line.strip().split('\t')
        data.append([line[1], line[3], line[2], line[4], line[0]])  # 是为了方便matchzoo的输入格式
data = pd.DataFrame(data)
data.to_csv(train_data_path, header=False, index=False, sep='\t')

读取数据:

def load_data(data_path):
	df_data = pd.read_csv(data_path, sep='\t', header=None)
	df_data = pd.DataFrame(df_data.values, columns=['id_left', 'text_left', 'id_right', 'text_right', 'label'])
	df_data = mz.pack(df_data)
	reture df_data

train_data = load_data(train_data_path)  # 这里就是上面数据格式转换的训练集和测试集路径
test_data = load_data(test_data_path)

数据处理:

train_dev_split = int(len(train_data) * 0.9)  # 验证集占训练数据的0.1
train = train_data[:train_dev_split]
dev = train_data[train_dev_split:]
train_pack_processed = preprocessor.fit_transform(train)  # 其实就是做了一个字符转id操作,所以对于中文文本,不需要分词
dev_pack_processed = preprocessor.transform(dev)  
test_pack_processed = preprocessor.transform(test_data)
train_data_generator = mz.DataGenerator(train_pack_processed, batch_size=32, shuffle=True)  # 训练数据生成器

test_x, test_y = test_pack_processed.unpack()
dev_x, dev_y = dev_pack_processed.unpack()

定义模型:

def build():
    model = mz.models.DUET()  # 同样,DUET网络可看官网的论文,这里不做解释;同样,模型的参数不做解释,官方文档有
    ranking_task = mz.tasks.Ranking(loss=mz.losses.RankCrossEntropyLoss(num_neg=1))  # 定义损失函数,这里采用的是排序交叉熵损失函数,它还有一个分类交叉熵损失函数,看你如何定义你的数据
    model.params['input_shapes'] = preprocessor.context['input_shapes']
    model.params['embedding_input_dim'] = preprocessor.context['vocab_size']  # 如果版本较老,这里需要加1,因为要考虑一个UNK的字符,如果版本较新,这个以更新解决
    model.params['embedding_output_dim'] = 300 
    model.params['task'] = ranking_task
    model.params['optimizer'] = 'adam'
    model.params['padding'] = 'same'
    model.params['lm_filters'] = 32
    model.params['lm_hidden_sizes'] = [32]
    model.params['dm_filters'] = 32
    model.params['dm_kernel_size'] = 3
    model.params['dm_d_mpool'] = 3
    model.params['dm_hidden_sizes'] = [32]
    model.params['activation_func'] = 'relu'
    model.params['dropout_rate'] = 0.32
    model.params['embedding_trainable'] = True
    model.guess_and_fill_missing_params(verbose=0)
    model.params.completed()
    model.build()
    model.backend.summary()
    model.compile()
    return model

训练:

model = build()
batch_size = 32

evaluate = mz.callbacks.EvaluateAllMetrics(model, x=dev_x, y=dev_y, batch_size=batch_size)
model.fit_generator(train_data_generator, epochs=5, callbacks=[evaluate], workers=5, use_multiprocessing=False)
y_pred = model.predict(test_x)

left_id = test_x['id_left']
right_id = test_x['id_right']
assert (len(left_id) == len(left_id))
assert (len(left_id) == len(y_pred))
assert (len(test_y) == len(y_pred))
Scale = preprocessing.MinMaxScaler(feature_range=(0, 1))  # 对结果做规范化
y_pred = Scale.fit_transform(y_pred)

至此,代码结束,最后的这个结果y_pred是一个规范到0-1之间的分数,代表左句子和右句子的相似度打分,因为matchzoo生成的分数有大于1和小于0,就相似度来讲,大于1理论上不可能,相似度最大应该是1,最小小于0,所以采用了规范化,以便阈值的取值(也可以不用,直接取阈值也可以)。
对于MSR数据,评价指标有F1-macro和准确率(accuracy),需要将结果变成0和1再去和测试集结果求分数。这里就不给这个代码了,剩下的评价只是数组操作问题,最难的数据读取和模型训练已给出。

总结一下:

  1. matchzoo的Embedding层是采用keras的Embedding层来随机训练word2id序列,而且官方也提供了导入自己预训练词向量模型的方法,本人用Wiki的中文预训练模型尝试过很多次,一个是效率较低,一个是结果并不佳,所以在此也不写这份代码了。
  2. 为什么写了DUET?在我的机器中,这个模型效率是比较高的,而且效果是最好的,即便是只使用官方的初始模型参数。
  3. 我们实验并非采用这个数据集,我是特意找了这份数据集来写博客,也就是说,我的代码已经run通了。
  4. 对于DSSM和CDSSM模型的数据处理器,我们的机器无法运行,所以对于这两个模型,没有进行实验,但是我们自己复现了DSSM和CDSSM的模型。
  5. 学习matchzoo最大的宝藏我觉得不是会打代码,而且了解这些孪生网络结果,并自己复现才是最好的。
  6. 感谢大家能看到这里,谢谢支持。
发布了12 篇原创文章 · 获赞 3 · 访问量 2046

猜你喜欢

转载自blog.csdn.net/weixin_40902563/article/details/103663689