XLNet 预训练模型及命名实体识别

介绍

在之前的实验中我们介绍和使用了 BERT 预训练模型和 GPT-2 预训练模型,分别进行了文本分类和文本生成实验。在本次实验中,我们将介绍 XLNet 预训练模型,并使用其进行命名实体识别实验。

知识点 XLNet

XLNet 在 BERT 和 GPT-2 上的改进
XLNet 模型结构

使用 XLNet 进行命名实体识别实验
GLUE
XLNet 预训练模型及命名实体识别

XLNet 在 BERT 和 GPT-2 上的改进

BERT 的缺点

可以说 XLNet 是 BERT 的增强版,但它与 BERT 又有许多不同之处。下面,我们将详细介绍一下。

在第一次实验中提到的,BERT 是自编码模型(Autoencoding),换一种说法来说就是,BERT 以遮蔽语言模型(Masked Language Model)为训练目标。训练自回归模型时,输入语句的一些词会被随机替换成 [MASK] 标签,然后训练模型预测被标签掩盖的词。

我们可以从这个过程中看到两个缺点:

错误地假设了被覆盖词与被覆盖词之间是独立的。
使预训练和微调时的输入不统一。

缺点 1 是指,在进行预测时,由于部分词被 [MASK] 覆盖,所以当 BERT 模型在预测一个被覆盖词时,忽略了其他的覆盖词对他的影响。也就是假设了所有被覆盖词是不相关的,很明显可以知道这个假设是错误的。

缺点 2 是指,在预训练是我们使用了 [MASK] 标签把部分词覆盖,而在微调预训练好的模型时,我们并不会使用到这个标签,这就导致了预训练过程和微调过程不符。

XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别
XLNet 预训练模型及命名实体识别

from torch.autograd import Variable
import time

pre = time.time()

epoch = 3

for i in range(epoch):
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = Variable(data).to(device), Variable(target).to(device)

        optimizer.zero_grad()

        # 生成掩膜
        mask = []
        for sample in data:
            mask.append([1 if i != 0 else 0 for i in sample])
        mask = torch.FloatTensor(mask).to(device)

        output = model(data, attention_mask=mask)
        
        # 得到模型预测结果
        pred = torch.argmax(output, dim=2)

        loss = loss_function(output, target, mask)
        loss.backward()

        optimizer.step()

        if ((batch_idx+1) % 10) == 1:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss:{:.6f}'.format(
                i+1, batch_idx, len(train_loader), 100. *
                batch_idx/len(train_loader), loss.item()
            ))

        if batch_idx == len(train_loader)-1:
            # 在每个 Epoch 的最后输出一下结果
            print('labels:', target)
            print('pred:', pred)

print('训练时间:', time.time()-pre)

XLNet 预训练模型及命名实体识别

# 这里使用和训练集同样的方式修改标签,不再赘述
input_ids = []
input_labels = []
for text, ori_labels in zip(eval_samples, eval_labels):
    l = text.split(' ')
    labels = []
    text_ids = []
    for word, label in zip(l, ori_labels):
        if word == '':
            continue
        tokens = tokenizer.tokenize(word)
        for i, j in enumerate(tokens):
            if i == 0:
                labels.append(int(label))
                text_ids.append(tokenizer.convert_tokens_to_ids(j))
            else:
                labels.append(9)
                text_ids.append(tokenizer.convert_tokens_to_ids(j))
    input_ids.append(text_ids)
    input_labels.append(labels)

del eval_samples
del eval_labels

for j in range(len(input_ids)):
    # 将样本数据填充至长度为 128
    i = input_ids[j]
    if len(i) != 128:
        input_ids[j].extend([0]*(128 - len(i)))

for j in range(len(input_labels)):
    # 将样本数据填充至长度为 128
    i = input_labels[j]
    if len(i) != 128:
        input_labels[j].extend([10]*(128 - len(i)))

# 构建数据集和数据迭代器,设定 batch_size 大小为 1
eval_set = TensorDataset(torch.LongTensor(input_ids),
                         torch.LongTensor(input_labels))
eval_loader = DataLoader(dataset=eval_set,
                         batch_size=1,
                         shuffle=False)
eval_loader

将模型设置为验证模式,输入验证集数据。

from tqdm.notebook import tqdm

model.eval()

correct = 0
total = 0

for batch_idx, (data, target) in enumerate(tqdm(eval_loader)):
    data = data.to(device)
    target = target.float().to(device)

    # 生成掩膜
    mask = []
    for sample in data:
        mask.append([1 if i != 0 else 0 for i in sample])
    mask = torch.Tensor(mask).to(device)

    output = model(data, attention_mask=mask)
    
    # 得到模型预测结果
    pred = torch.argmax(output, dim=2)

    # 将掩膜添加到预测结果上,便于计算准确率
    pred = pred.float()
    pred = pred * mask
    target = target * mask

    pred = pred[:, 0:mask.sum().int().item()]
    target = target[:, 0:mask.sum().int().item()]

    correct += (pred == target).sum().item()
    total += mask.sum().item()

print('正确分类的标签数:{},标签总数:{},准确率:{:.2f}%'.format(
    correct, total, 100.*correct/total))

XLNet 预训练模型及命名实体识别
XLNet: Generalized Autoregressive Pretraining for Language Understanding
XLNet 模型实现

来源:已购买的-蓝桥课程

上一篇:PostMan传参问题


下一篇:Element隐藏组件:scrollbar