在前序文章中分别介绍了文本匹配的基本应用场景以及两大主流匹配范式:表示型匹配模型和交互型匹配模型。本文介绍一款文本匹配的基本工具:MatchZoo,其囊括了常见的文本匹配模型,免去重复造轮子的麻烦,且提供了基于Tensorflow和Pytorch的两个版本。
本文按照【数据集准备】——>【模型训练】——>【模型使用】的常规顺序,介绍pytorch版本的基本使用。
MatchZoo
按照DataPack
——>Preprocessed
——>DataSet
——>DataLoader
的顺序来组织文本顺序。
显然,在文本问题中,包括text1
、text2
和relation
三个元素,而DataPack正是有对应的left
、right
和relation
三部分的数据结构,每部分都是一个单独的DataFrame
,其中relation
的每条记录中包括left
和right
相应的id
。
class DataPack(object):
def __init__(
self,
relation: pd.DataFrame,
left: pd.DataFrame,
right: pd.DataFrame
):
""":class:`DataPack` initializer."""
self._relation = relation
self._left = left
self._right = right
其中left
和right
的格式类似于:
而relation
的格式类似于:
对于DataPack对象,通过frame()
方法可将返回对应的DataFrame
对象。其包含id_left
、text_left
、id_right
、text_right
和label
五个字段。
反之,也可以通过顶级函数pack
将DataFrame
数据直接转换为DataPack
。其中,原始DataFrame
数据必须至少包含text_left
和 text_right
列,而id_left
和id_right
在转换中可自动生成,label
列任意(分为训练和测试阶段)。
此外在pack
函数中有个重要的参数:task
,其取决于我们对解决文本分类问题的思路:是定义为分类问题,还是定义为pair-wise的排序问题(具体解释见后文的tasks
部分)。该函数默认值为ranking
,即排序问题;此外,还设置为clsssification
,即分类问题,或设定为两者对应的类。在DataFrame——>DataPack过程中,该参数的不同会影响到label
字段值的类型,即ranking
变为float类型,而clsssification
变为int类型,这是由两类问题不同的损失函数所决定。
在训练/预测阶段,DataPack类型的数据会通过unpack
函数进行拆包,转变为(X, y)
元组(测试阶段无lable时,y=None),其中X
为{str: np.array}
的键值对,拆包后的数据可直接用于模型的fit
或fit_generator
函数进行。
matchzoo的preprocessors
中提供了一系列用于文本处理的基本类(如包含词频过滤、停用词过滤、长度截断的BasicPreprocessor
,可用于Bert
类模型数据预处理的BertPreprocessor
),而在各模型中可直接使用get_default_preprocessor
等方法调用进行适用于该模型的文本处理器,然后通过train
和trainsform
方法将文本转变为可用于训练的数字数据。
经过preprocessors
处理后的数据仍为DataPack
类型。
继承自torch.utils.data. Dataset
,对Preprocessed的数据进行采样、批量化、随机、排序、编号等操作,通过unpack方法返回(X, y)
元组
其中有几点需要注意:
(1)训练模式:matchzoo支持point-wise ranking,即classfication的训练模式,也支持pair-wise ranking的训练模式(暂未实现list-wise ranking)。对应参数分别为mode=point
和mode=pair
。
当mode=pair
时,如下参数需要设置:
mode=pair
时为真正的一个sample(2)不同于pytorch中默认的将批量化、随机等操作放在DataLoader阶段,MatchZoo将其前置到DataSet中,并通过其中的reset_index
和__getitem__
的方法进行实现
(3)样本的索引列表通过index_pool
进行保存,当mode=point
时,索引列表即为原始的索引列表,而mode=pair
会,每一个元素中的文本pair为1+num_neg。
将DataSet返回的DataPack
类型数据进行进一步处理,返回可迭代的batch。其中重要的参数包括:
(1)stage
: 用于控制模型的阶段,分为"train", “dev”,和"test";
(2)callback
: 一些处理函数,比如padding
操作。
tasks
是MatchZoo中定义的概念,用于指定文本匹配任务的类型,即是分类问题(classification)还是排序问题(pair-wise ranking)。
无论将其定义为哪一种问题,均需要设置如下的参数:
(1)losses
: 即损失函数
对于分类任务,可直接采用pytorch中内置的交叉熵等损失函数;
对于排序任务,MatchZoo自定义两种损失函数,分别为适用于排序的交叉熵损失RankCrossEntropyLoss
和用于区分正负样本margin的铰链损失RankHingeLoss
。
具体而言,RankCrossEntropyLoss
指对于每一组正、负样本计算其softmax后的交叉熵损失的均值;
-torch.mean(
torch.sum(
labels * torch.log(F.softmax(logits, dim=-1) + torch.finfo(float).eps),
dim=-1
)
RankHingeLoss
则是对于每一组正、负样本中的负样本先计算其平均值,在与正例的预测值进行HingeLoss
的计算。
(2)metrics
:即评价指标
分类任务常用的metrics有: accuracy、crossentropy
排序任务常用的metrics有:map、mrr、dcg和ndcg等
MatchZoo的models
模块中定义了许多经典的文本匹配模型以直接调用,在指定各params
后调用build
函数即可得到对应的模型架构和初始化参数。
与pytroch的惯用套路一样,这里不加详细说明。
MatchZoo对训练阶段的封装,可指定如下参数:
通过trainer.run()
进行训练。
通过trainer.predict()
进行预测,其输入数据为DataLoader。
这里给出官方的简单示例:
import torch
import matchzoo as mz
# 1. 指定任务类型(一般情况可放在model之前,无论如何注意前后问题定义的一致性)
ranking_task = mz.tasks.Ranking(losses=mz.losses.RankCrossEntropyLoss(num_neg=4))
# 1.1 定义任务的loss和metric
ranking_task.metrics = [
mz.metrics.NormalizedDiscountedCumulativeGain(k=3),
mz.metrics.MeanAveragePrecision()
]
# 2. 准备数据
# 2.1 封装成DataPack
train_pack = mz.datasets.wiki_qa.load_data('train', task=ranking_task)
valid_pack = mz.datasets.wiki_qa.load_data('dev', task=ranking_task)
# 2.2 经过preprocess处理
preprocessor = mz.models.ArcI.get_default_preprocessor()
train_processed = preprocessor.fit_transform(train_pack)
valid_processed = preprocessor.transform(valid_pack)
# 2.3 Dataset
trainset = mz.dataloader.Dataset(
data_pack=train_processed,
mode='pair',
num_dup=1,
num_neg=4,
batch_size=32
)
validset = mz.dataloader.Dataset(
data_pack=valid_processed,
mode='point',
batch_size=32
)
# 2.4 DataLoader
padding_callback = mz.models.ArcI.get_default_padding_callback() # padding策略
trainloader = mz.dataloader.DataLoader(
dataset=trainset,
stage='train',
callback=padding_callback
)
validloader = mz.dataloader.DataLoader(
dataset=validset,
stage='dev',
callback=padding_callback
)
# 3. 搭建模型
# 3.1 调用内置模型并初始化参数
model = mz.models.ArcI()
model.params['task'] = ranking_task
model.params['embedding_output_dim'] = 100
model.params['embedding_input_dim'] = preprocessor.context['embedding_input_dim']
model.guess_and_fill_missing_params()
model.build()
# 3.2 定义优化器等
optimizer = torch.optim.Adam(model.parameters())
# 3.3 封装训练器
trainer = mz.trainers.Trainer(
model=model,
optimizer=optimizer,
trainloader=trainloader,
validloader=validloader,
epochs=10
)
# 3.4 进行训练
trainer.run()
# 4. 进行预测
# trainer.predict()
【参考资料】:
(1)官方API文档
(2)关于文本匹配工具MatchZoo