这篇post主要构建一个BERT的五分类模型,然后研究使用TrackIn来确定样本在模型训练中,对模型inference的影响。

MS MARCO

MS MARCO是微软发布的一个NLP问答数据集,里头含有100000个真实的在bing上提出的问题,以及问题的答案,可作为QnA问题的数据集,此后还陆续提出了多种问题的数据集。

格式的介绍在这里:https://microsoft.github.io/MSMARCO-Passage-Ranking/

MARCO数据集中,比较重要的文件有:

  • triples.train.small.tsv,他的文件格式为:<query,doc1,doc2>,第一个doc1是positive,第二个doc2是negative。

  • top1000.dev.tsv:<query_id ,doc_id,query,doc>,即query和doc对

  • qrels.dev.small.tsv:<query_id,0,doc_id,1>,用来判断query和doc是否是相互关联的。

triples.train.small.tsv中query是重复的。

STSB数据集

用1到5的分数来表征两个句子的语义相似性,本质上是一个回归问题,但依然可以用分类的方法做,因此可以归类为句子对的文本五分类任务。

数据集的格式为:

1
index	genre	filename	year	old_index	source1	source2	sentence1	sentence2	score

其中我们用到的数据是:

1
2
sentence1	sentence2	score
A plane is taking off. An air plane is taking off. 5.000

数据首先经过wordembedding,每个词变成长度为768的向量,每个句子通过pad_sequence变成长度为512,因此输出为【512 x 768】随后将【512 x 768】加上position embedding输入BERT模型中。

dataloader部分

使用一个数据存储数据,格式为<query,doc,label>,然后将数组存储为dataloader。其中label = 0 表示负类,label = 1 表示你正类。

其具体的实现过程如下:

首先将数据query与doc分别经过tokenizer分词化,然后组成一个输入:

[CLS] + tokens_query + [SEP] + tokens_doc + [SEP]

随后将分词转换为vocab中的word id,构建一个segments_tensor,长度与输入长度相同,其中query部分为0,doc部分为1。如果我们希望返回一个batch,需要将所有的tensor通过前面填充0 的方式,将tensor维度变成一直(pad_sequence),同时构建一个mask,mask的维度与batch的维度相同,其中用零填充的部分为0,不是0填充的部分为1。

最终dataloader将返回:

<tokens_tensors, masks_tensors,segments_tensors, labels_ids>

tensor的维度为:tokens_tensor为:32x128

模型

模型使用transformers.BertForSequenceClassification

该模型的网络结构如下:

image-20200314021335605

即BERT的基础上加上一层全连接层,全链接层输入为768,输出为label class的个数,最后通过一个交叉熵得出最后的loss。

STSB评价指标

1
2
3
4
5
6
7
8
def pearson_and_spearman(preds, labels):
pearson_corr = pearsonr(preds, labels)[0]
spearman_corr = spearmanr(preds, labels)[0]
return {
"pearson": pearson_corr,
"spearmanr": spearman_corr,
"corr": (pearson_corr + spearman_corr) / 2,
}

pearson:是衡量向量相似度的一种方法。输出范围为-1到+1, 0代表无相关性,负值为负相关,正值为正相关。
$$
\rho(X, Y)=\frac{E\left[\left(X-\mu_{X}\right)\left(Y-\mu_{Y}\right)\right]}{\sigma_{X} \sigma_{Y}}=\frac{E\left[\left(X-\mu_{X}\right)\left(Y-\mu_{Y}\right)\right]}{\sqrt{\sum_{i=1}^{n}\left(X_{i}-\mu_{X}\right)^{2}} \sqrt{\sum_{i=1}^{n}\left(Y_{i}-\mu_{Y}\right)^{2}}}
$$
相关系数 0.8-1.0 极强相关

0.6-0.8 强相关

0.4-0.6 中等程度相关

0.2-0.4 弱相关

0.0-0.2 极弱相关或无相关

spearmanr:斯皮尔曼相关系数表明X(独立变量)和Y(依赖变量)的相关方向:
$$
\rho=\frac{\sum_{i}\left(x_{i}-\bar{x}\right)\left(y_{i}-\bar{y}\right)}{\sqrt{\sum_{i}\left(x_{i}-\bar{x}\right)^{2} \sum_{i}\left(y_{i}-\bar{y}\right)^{2}}}
$$

trackIn 理解

TrackIn核心的观点在于model经过当前样本训练迭代后,更新参数得到的新模型在验证集上loss与未更新前下降的数值之差。

样本影响力的定义如下(z为指定的样本,z’为验证集):

img

理想状态:即在某次迭代,能够指定一个训练样本。

在理想状态下,所有训练数据对验证集样本的影响如下:

img

上述公式,默认条件是每次迭代仅在一个训练样本上进行训练。

作者使用一阶近似来估计迭代t中,测试示例的损失变化:

img

其中梯度的计算是在验证集数据上的。

SGD梯度下降法计算参数迭代如下:

img

将两个公式结合,忽略高阶项得到:

img

因此我们固定一个样本z,可以算出利用z的所有迭代次数的影响力之和:

img

当我们训练数据不是一个样本,而是一个batch的时候:

img

作者在实际的应用中,在每次迭代仅使用单个样本,保存学习率不变,模型每次在训练集上训练一次后保存一个检查点checkpoint,因此两个checkpoint之间样本仅训练过一次。作者利用检查点的参数,作为近似参数向量:

img

上式的含义是模型参数wt 到wt+1之间,样本z对验证集的影响。通过对这个影响是positive或negative的判断,得到样本对模型的影响力,一个应用就是用来判断是否存在样本误标注的问题。

作者论文中给出一个NLP例子是文本分类问题,证明这种方法也是可以用在NLP中的。

trackIn的一点尝试

  1. 使用STS-B数据集:五分类数据集,数据示例如下:

    sentence1 sentence2 similar_score(0-4)
    A plane is taking off. An air plane is taking off. 4
    A man is playing a large flute. A man is playing a flute. 3
    A man is smoking. A man is skating. 0

  2. 使用huggingface中的BertForSequenceClassification类,调整网络的输出为五分类,该网络的结构为:
    Bert + dropout + linear(768x5)+ corssentropy

  3. 原始版本训练10个epoch后,得到了检测的指标指标:
    corr = 0.8668199467352331
    pearson = 0.8680211975793752
    spearmanr = 0.865618695891091
    这个成绩在glue排行版上top20左右,top10以上基本你上90分。

  4. fix BERT部分参数,仅训练linear层,10个epoch之后的指标为:
    corr = 0.46851795469199176
    pearson = 0.4883897702565989
    spearmanr = 0.44864613912738466

  5. 由于Bert后的分类结构过于简单,因此在原始网络后面添加linear层。fix bert部分,训练得到结果:
    Bert + linear(768x100) + linear(100x5) + crossentropy
    corr = 0.4874025699052884
    pearson = 0.48976918410773407
    spearmanr = 0.4850359557028428

  6. bert + linear(768,300) + linear(300,50) + linear(50,5):
    corr = 0.4901503255725512
    pearson = 0.49249477605462705
    spearmanr = 0.48780587509047535

  7. Bert + linear(768,300) + linear(300,100) + linear(100,50) + linear(50,5)

    1
    2
    3
    corr = 0.5010257366795687
    pearson = 0.5034574745457592
    spearmanr = 0.49859399881337824
  8. 训练bert最后一层以及linear层得到的结果:
    bert + linear(768,300) + linear(300,100) + linear(100,50) + linear(50,5)

    corr = 0.7648302644703243
    pearson = 0.7663893373697331
    spearmanr = 0.7632711915709155

pearson:输出范围为-1到+1, 0代表无相关性,负值为负相关,正值为正相关。
相关系数 0.8-1.0 极强相关
0.6-0.8 强相关
0.4-0.6 中等程度相关
0.2-0.4 弱相关
0.0-0.2 极弱相关或无相关

分析trackIn函数

$$
\operatorname{TrackIn}\left(z, z^{\prime}\right)=\sum_{t: z_{t}=z} \eta_{t} \nabla \ell\left(w_{t}, z^{\prime}\right) \cdot \nabla \ell\left(w_{t}, z\right)
$$

如上,作者经过一些推导之后得到TrackIn的表达式,表达式表明,在第t步迭代的时候,训练样本z 对 待测试样本$z^`$ 的影响的计算方法是: 待测样本在$w_t$上的梯度与训练样本在$w_t$上的梯度的乘积。

这时候有一个问题,就是$w_t$是一个矩阵,而TrackIn是loss的差,是一个标量,我的想法是矩阵对应位置相乘后相加,得到最后的结果。可以把t次数调大一点,使得效果能够明显一点。

因此思路如下:

  1. 将训练样本和测试样本输入网络,然后将Bert最后一层以及classifier层的梯度拿出来
  2. 计算梯度相乘,然后求和得到trackIn的值
  3. 记录一个表,表中的内容是target example 和 对应的一些列 train example,然后每个train example有一个trackIn的值。

因此要做的事情是:

  1. 重新设计数据集,dataset,dataloader
  2. 对训练数据和测试数据迭代t次网络,然后将每次的梯度记到txt中
  3. 写一个矩阵相乘的代码,得到trackIn的值

明天做!

测试数据:

aa: A plane is taking off. An air plane is taking off. 5.000

trackIn训练数据(假样本对数据的影响):

b1: A plane is taking off. A man wearing a hard hat is dancing. 5.000 :11326.170552326665

b2: A plane is taking off. The plane is about to take off. 5.0 done :11326.172044273939

b3: A plane is taking off. Spaceship is about to take off. 3.0 done :11326.17223393679