GPT/GPT2/DialoGPT 详解对比与应用-文本生成与对话

2022-01-22 16:55:01 浏览数 (1)

1. 背景

GPT 的全名:Generative Pre-Training,其论文标题是 Improving Language Understanding by Generative Pre-Training。

相信大家都在有看到GPT系列在文本生成任务类等任务又刷新记录取得成绩如下图,这篇文章主要来看看GPT与GPT的结构与任务是怎么样的。

2. GPT

GPT的底层架构是transformer,是由pre-training和fine-tuning两部分构成的

预训练数据GPT 使用 BooksCorpus 数据集,它包含了7000本书,共计 5GB 文字。这样超大的数据规模,是 GPT 成功的关键之一。Elmo 所使用的 1B Word Benchmark 数据集与之体量相当,但被重新整理成单句,因而丢失了长序列的样本,是它没有被 GPT 选用的原因。

2.1 pre-training

pre-training是采用transformer框架进行的,不过对transformer改动了一下。transformer在之前的博客中讲过,详见https://cloud.tencent.com/developer/article/1868051

我们知道transformer里有encoder层和decoder层,而GPT里主要用的是decoder层,不过做了一点改变,去掉了中间的Encoder-Decoder Attention层(因为没有encoder层,所以也不需要Encoder-Decoder Attention层)如下图

整个过程如上图所示,词向量(token embedding)和位置向量(position embedding)的和作为输入,经过12层的Masked Multi-Head Attention和Feed Forward(当然中间也包括Layer Norm),得到预测的向量和最后一个词的向量,最后一个词的词向量会作为后续fine-tuning的输入。

GPT本质上是自回归模型,自回归的意思是指,每次产生新单词后,将新单词加到原输入句后面,作为新的输入句。

模型会将语句输入上图所示的结构中,预测下一个词,然后再将新单词加入,作为新的输入,继续预测。损失函数会计算预测值与实际值之间的偏差。

训练目标:

在预训练阶段,只以语言模型为训练目标,即图中的 Text Prediction。

公式1描述了这个典型的从左到右的语言模型:在给定上文的条件下预测下一个词。

L_1(u)=sum_ilogP(u_i|u_{i-k},...,u_{i-1};Theta)

在公式2中,h0 表示网络第一个隐层,U 表示输入序列,We 表示 token embedding 矩阵,Wp 表示 position embedding。h1 到 hn 是各层 Transformer block 的输出隐层。最终以 sotfmax 计算下一个词的概率。

h_0=UW_e W_p
h_1=transformer_block(h_{l-1}) forall i in [1,n]
P(u)=softmax(h_nW^T_e)

问题:无监督训练的终止条件是什么呢?训练到什么时候可以停止呢?像聚类是训练到分类比较稳定的情况下就停止了

我们可以通过准确率来评价训练何时停止。训练的时候生成的文本和原文本进行比对,得到准确率,通过准确率是否达到预期值或是准确率是否一直上下波动等来确定是否该停止训练。

2.2 有监督fine-tuning

在 Fine-Tune 阶段,输入的样本是(序列 x1...xm,标签 y)。给定一个序列,预测标签的概率如下所示。

P(y|x^1,...,x^m)=softmax(h_l^mW_y)

Task Classifier 的训练目标是最大化全体有监督训练样本出现的概率,即图1中的 Task Classifier。

L_2(C)=sum_{(x,y)}logP(y|x^1,...,x^m)

在这个阶段,语言模型的训练目标也被一并启用。

L_3(C)=L_2(C) lambda*L_1(C)

重新看一遍网络结构和 Fine-Tune阶段的公式,就会发现,引入的参数,只有 Wy。

先将大部分的参数通过无监督预训练训练好,然后通过微调确定最后一个参数w的值,以适应不同的任务。利用无监督最后一个词的向量作为微调的输入(个人认为其实可以整句话的词向量作为输入,但是没必要)。

上图展示了对于不同NLP任务的微调过程:

分类任务:输入就是文本,最后一个词的向量直接作为微调的输入,得到最后的分类结果(可以多分类)

推理任务:输入是 先验 分隔符 假设,最后一个词的向量直接作为微调的输入,得到最后的分类结果,即:是否成立

句子相似性:输入是 两个句子相互颠倒,得到的最后一个词的向量再相加,然后进行Linear,得到最后分类结果,即:是否相似

问答任务:输入是上下文和问题放在一起与多个回答,中间也是分隔符分隔,对于每个回答构成的句子的最后一个词的向量作为微调的输入,然后进行Linear,将多个Linear的结果进行softmax,得到最后概率最大的

问题:对于问答任务,最后多个Linear的结果如何进行softmax?

对于问答任务来说,一个问题对应多个回答,而最后我要取最准确的回答(分值最高)作为结果,我通过对多对问题答案做transformer后,再分别做linear,可以将维度统一,然后对多个linear进行softmax~之前都是对一个linear做softmax,直接取概率值最大的即可,但是现在多个linear如何进行softmax呢?

以上就是GPT的大致描述,采用无监督的预训练和有监督的微调可以实现大部分的NLP任务,而且效果显著,但是还是不如Bert的效果好。不过GPT采用单向transformer可以解决Bert无法解决的生成文本任务,具体原因可见后续总结。

2.3 效果

3. GPT-2

GPT-2希望在完全不理解词的情况下建模,以便让模型可以处理任何编码的语言。GPT-2主要针对zero-shot问题。它在解决多种无监督问题时有很大提升,但是对于有监督学习则差一些。

GPT-2依然沿用GPT单向transformer的模式,只不过做了一些改进与改变。那GPT-2相对于GPT有哪些不同呢?看看下面几方面:

  1. GPT-2去掉了fine-tuning层:不再针对不同任务分别进行微调建模,而是不定义这个模型应该做什么任务,模型会自动识别出来需要做什么任务。这就好比一个人博览群书,你问他什么类型的问题,他都可以顺手拈来,GPT-2就是这样一个博览群书的模型。
    1. 在Pretrain部分基本与GPT方法相同,在Fine-tune部分把第二阶段的Fine-tuning有监督训练具体NLP任务,换成了无监督训练具体任务,这样使得预训练和Fine-tuning的结构完全一致。当问题的输入和输出均为文字时,只需要用特定方法组织不同类型的有标注数据即可代入模型,如对于问答使用“问题 答案 文档”的组织形式,对于翻译使用“英文 法文”形式。用前文预测后文,而非使用标注数据调整模型参数。这样既使用了统一的结构做训练,又可适配不同类型的任务。虽然学习速度较慢,但也能达到相对不错的效果。
  2. 增加数据集:这是一个比更大还更大的数据集。GPT-2 构造了一个新数据集,WebText。这些无监督样本,全部来自于 Reddit 的外链,而且是那些获得至少三个赞的外链,共计4500万链接。使用 Dragnet 和 Newspaper 两种工具来抽取网页内容。过滤 2017 年12月之后的网页。删去来自 Wikipedia 的网页。去重。最后还做一些琐碎的没有明说的所谓启发式清洗工作。如此得到8百万网页共计 40GB 文本数据。WebText 数据集的特点在于全面而干净。全面性来源于 Reddit 本身是一个门类广泛的社交媒体网站。干净来源于作者的有意筛选,至少三赞意味着获取的外链是有意义的或者有趣的。
  3. 增加网络参数:GPT-2将Transformer堆叠的层数增加到48层,隐层的维度为1600,参数量更是达到了15亿。(Bert的参数量也才只有3亿)
  4. 调整transformer:将layer normalization放到每个sub-block之前,并在最后一个Self-attention后再增加一个layer normalization。
c389GPT-2的输入是完全的文本,什么提示都不加吗?

它也会加入提示词,比如:“TL;DR:”,GPT-2模型就会知道是做摘要工作了输入的格式就是 文本 TL;DR:,

模型

Layers

d_size

ff_size

Heads

Parameters

GPT2-base

12

768

3072

12

117M

GPT2-medium

24

1024

4096

16

345M

GPT2-large

36

1280

5120

20

774M

GPT2-xl

48

1600

6400

25

1558M

3.1 效果

注意到,标准模型 1542M 在8个测试集上斩获7个记录,而最小的模型 117M 也能在其中4个测试集上挑起大梁。而且GPT-2 没有 Fine-Tune

4. DialoGPT

DialoGPT扩展了GPT-2来应对对话神经响应生成(conversational neural response generation model)遇到的挑战。神经响应生成是文本生成的子问题,任务是迅速生成自然的文本(与训练文本不一致)。人类对话包含了两个对话者的竞争目标,潜在的响应(回复)更加多样化。因此,相比于其他文本生成的任务,对话模型提出了一个更大的一对多的任务。并且人类的对话通常也不正式,经常包含缩写或错误,这些都是对话生成的挑战。

类似于GPT-2,DialoGPT也表示为一个自回归(autoregressive, AR)语言模型,利用多层transformer模型架构。但是不同于GPT-2,DialoGPT在从Reddit讨论链中提取的大规模会话对上进行训练。作者的假设是这可以让DialoGPT捕捉到更细粒度的对话流中的联合概率分布P(Target, Source)。在实践中观测到,DialoGPT产生的句子是多样的,并且包含了针对源句子的信息。作者将预训练好的模型在公开的基准数据集DSTC-7上进行了评估,又从Reddit提取了新的6000 条作为参考测试数据。无论在自动评估还是人类评估中,DialoGPT都展示了最先进的结果,将表现提升到接近人类回复的水平。

4.1 模型架构

作者在GTP-2架构的基础上训练DialoGPT模型。参考OpenAI GPT-2将多轮会话作为长文本,将生成任务作为语言模型。

首先,把一次会话中的所有对话合并为一个长文本,以文本结束符作为结尾。源句子(source sentence)表示为S,目标句子(target sentence)表示为T,条件概率可写为

对于一个多轮对话,(1)式可被写为,这本质上是条件概率的乘积。因此,优化单个目标可被视为所有的“源-目标”对。

作者分别训练了参数大小为117M、345M、761M的模型,模型使用了50257个词条(entry)。

使用了Noam学习率,学习率是根据验证损失来选择的。为了加速训练,作者将所有的训练数据压缩到懒加载数据库文件中,数据仅在被需要时才被加载,用独立的异步数据处理来训练。

作者进一步采用了动态批处理策略,将相似长度的会话分组到同一批中,从而提高了训练吞吐量。经过以上调整,训练时间随着GPU数量的增加近似线性下降。

4.2 互信息最大化

作者实现了最大化互信息(maximum mutual information,MMI)评分方程。MMI采用预训练反馈模型来预测给定响应的源句子,即P(Source|target)。作者首先使用top-K采样生成了一些假设,然后利用概率P(Source|Hypothesis)来对全部假设重新排名。从直觉上来说,最大化反馈模型概率惩罚了那些温和的假设,这是由于频繁的和重复的假设可以与许多可能的查询关联,因此得到的概率都比较低。

作者尝试使用强化学习的策略梯度方法优化reward,其把reward定义为P(Source|Hypothesis)。验证集的reward在稳定提高,但是不像RNN模型架构训练的那样.作者观察到强化学习训练很容易地收敛到退化的局部最优解,这种情况下假设在重复源句子(鹦鹉学舌)和互信息最大化。作者认为transformers模型由于具有强大的表示能力,因此会陷入局部最优解。因此作者把RL的规范化训练留给未来的工作。

4.3 评价指标:DSTC-7对话系统技术竞赛

DSTC(Dialog System Technology Challenges)中有一个端到端的对话建模任务,任务的目标是通过注入基于外部知识的信息来产生超越闲聊(chitchat)的对话。这个任务不同于通常认为的面向目标的、面向任务的或任务完成的对话,因为它没有特定的或预定义的目标(例如预订航班、餐馆预定餐桌等)。相反,它针对的是类似人类的对话,在这种对话中,潜在的目标通常是不明确的或事先未知的,就像在工作和生产环境(如头脑风暴会议)中人们共享信息时看到的那样。

DSTC-7测试数据包含了Reddit数据对话。为了创建一个多引用(multi-reference)测试集,作者使用了包含6次或更多回复的对话。经过其它条件的过滤,得到了大小为2208的“5-引用”测试集。

DialoGPT与Team B、PERSONALITYCHAT对比

作者利用了标准的机器翻译评价BLEU、METEOR、NIST来进行自动评估,并用Entropy和Dist-n来评估词汇多样性。

作者将DialoGPT与“Team B”(竞赛的优胜模型)、GPT、PERSONALITYCHAT(一种seq2seq模型,已应用于生产环境作为微软Azure的认知服务)行了比较,结果如表1所示,在各项都是目前最先进的水平。

5. GPT-2 应用-文本生成

5.1 字节对编码

GPT-2 模型在数据预处理时使用了字节对编码(Byte Pair Encoding,简称 BPE)方法,BPE 是一种能够解决未登录词问题,并减小词典大小的方法。它综合利用了单词层面编码和字符层面编码的优势,举例来说,我们要对下面的字符串编码,

代码语言:javascript复制
aaabdaaabac

字节对 aa 出现的次数最多,所以我们将它替换成一个没在字符串中被用过的字符 Z

代码语言:javascript复制
ZabdZabac
Z=aa

然后我们重复这个过程,用 Y 替换 ab

代码语言:javascript复制
ZYdZYac
Y=ab
Z=aa

继续,用 X 替换 ZY

代码语言:javascript复制
XdXac
X=ZY
Y=ab
Z=aa

这个过程重复进行,直到没有字节对出现超过一次。当需要解码时,就将上述替换过程反向进行。

PT-2 就是一个语言模型,能够根据上文预测下一个单词,所以它就可以利用预训练已经学到的知识来生成文本,如生成新闻。也可以使用另一些数据进行微调,生成有特定格式或者主题的文本,如诗歌、戏剧。所以接下来,我们会用 GPT-2 模型进行一个文本生成。

5.2 预训练模型生成新闻

想要直接运行一个预训练好的 GPT-2 模型,最简单的方法是让它自由工作,即随机生成文本。换句话说,在开始时,我们给它一点提示,即一个预定好的起始单词,然后让它自行地随机生成后续的文本。

但这样有时可能会出现问题,例如模型陷入一个循环,不断生成同一个单词。为了避免这种情况, GPT-2 设置了一个 top-k 参数,这样模型就会从概率前 k 大的单词中随机选取一个单词,作为下一个单词。下面是选择 top-k 的函数的实现,

代码语言:javascript复制
import random

def select_top_k(predictions, k=10):
    predicted_index = random.choice(
        predictions[0, -1, :].sort(descending=True)[1][:10]).item()
    return predicted_index

下面引入 GPT-2 模型,我们将使用在 PyTorch-Transformers 模型库中封装好的 GPT2Tokenizer()GPT2LMHeadModel() 类来实际看一下 GPT-2 在预训练后的对下一个词预测的能力。首先,需要安装 PyTorch-Transformers。

代码语言:javascript复制
!pip install pytorch_transformers==1.0  # 安装 PyTorch-Transformers

使用 PyTorch-Transformers 模型库,先设置好准备输入模型的例子,使用 GPT2Tokenizer() 建立分词器对象对原句编码。

代码语言:javascript复制
import torch
from pytorch_transformers import GPT2Tokenizer

import logging
logging.basicConfig(level=logging.INFO)

# 载入预训练模型的分词器
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')

# 使用 GPT2Tokenizer 对输入进行编码
text = "Yesterday, a man named Jack said he saw an alien,"
indexed_tokens = tokenizer.encode(text)
tokens_tensor = torch.tensor([indexed_tokens])
tokens_tensor.shape

接下来使用 GPT2LMHeadModel() 建立模型,并将模型模式设为验证模式。由于预训练模型参数体积很大,且托管在外网,所以本次先从网盘下载预训练模型,本地无需此步骤。

代码语言:javascript复制
from pytorch_transformers import GPT2LMHeadModel

# 读取 GPT-2 预训练模型
model = GPT2LMHeadModel.from_pretrained("./")
model.eval()

total_predicted_text = text
n = 100  # 预测过程的循环次数
for _ in range(n):
    with torch.no_grad():
        outputs = model(tokens_tensor)
        predictions = outputs[0]

    predicted_index = select_top_k(predictions, k=10)
    predicted_text = tokenizer.decode(indexed_tokens   [predicted_index])
    total_predicted_text  = tokenizer.decode(predicted_index)

    if '<|endoftext|>' in total_predicted_text:
        # 如果出现文本结束标志,就结束文本生成
        break

    indexed_tokens  = [predicted_index]
    tokens_tensor = torch.tensor([indexed_tokens])

print(total_predicted_text)

运行结束后,我们观察一下模型生成的文本,可以看到,大致感觉上这好像是一段正常的文本,不过,仔细看就会发现语句中的逻辑问题,这也是之后研究人员会继续攻克的问题。

除了直接利用预训练模型生成文本,我们还可以使用微调的方法使 GPT-2 模型生成有特定风格和格式的文本。

5.3 微调生成戏剧文本

接下来,我们将使用一些戏剧剧本对 GPT-2 进行微调。由于 OpenAI 团队开源的 GPT-2 模型预训练参数为使用英文数据集预训练后得到的,虽然可以在微调时使用中文数据集,但需要大量数据和时间才会有好的效果,所以这里我们使用了英文数据集进行微调,从而更好地展现 GPT-2 模型的能力。

首先,下载训练数据集,这里使用了莎士比亚的戏剧作品《罗密欧与朱丽叶》作为训练样本。数据集已经提前下载好并放在云盘中,链接:https://pan.baidu.com/s/1LiTgiake1KC8qptjRncJ5w 提取码:km06

代码语言:javascript复制
with open('./romeo_and_juliet.txt', 'r') as f:
    dataset = f.read()

len(dataset)

预处理训练集,将训练集编码、分段。

代码语言:javascript复制
indexed_text = tokenizer.encode(dataset)
del(dataset)

dataset_cut = []
for i in range(len(indexed_text)//512):
    # 将字符串分段成长度为 512
    dataset_cut.append(indexed_text[i*512:i*512 512])
del(indexed_text)

dataset_tensor = torch.tensor(dataset_cut)
dataset_tensor.shape

这里使用 PyTorch 提供的 DataLoader() 构建训练集数据集表示,使用 TensorDataset() 构建训练集数据迭代器。

代码语言:javascript复制
from torch.utils.data import DataLoader, TensorDataset

# 构建数据集和数据迭代器,设定 batch_size 大小为 2
train_set = TensorDataset(dataset_tensor,
                          dataset_tensor)  # 标签与样本数据相同
train_loader = DataLoader(dataset=train_set,
                          batch_size=2,
                          shuffle=False)
train_loader

检查是否机器有 GPU,如果有就在 GPU 运行,否则就在 CPU 运行。

代码语言:javascript复制
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device

开始训练。

代码语言:javascript复制
from torch import nn
from torch.autograd import Variable
import time

pre = time.time()

epoch = 30  # 循环学习 30 次

model.to(device)
model.train()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-5)  # 定义优化器

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

        optimizer.zero_grad()

        loss, logits, _ = model(data, labels=target)

        total_loss  = loss

        loss.backward()
        optimizer.step()

        if batch_idx == len(train_loader)-1:
            # 在每个 Epoch 的最后输出一下结果
            print('average loss:', total_loss/len(train_loader))

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

训练结束后,可以使模型生成文本,观察输出。

代码语言:javascript复制
text = "From fairest creatures we desire"  # 这里也可以输入不同的英文文本
indexed_tokens = tokenizer.encode(text)
tokens_tensor = torch.tensor([indexed_tokens])

model.eval()
total_predicted_text = text

# 使训练后的模型进行 500 次预测
for _ in range(500):
    tokens_tensor = tokens_tensor.to('cuda')

    with torch.no_grad():
        outputs = model(tokens_tensor)
        predictions = outputs[0]

    predicted_index = select_top_k(predictions, k=10)

    predicted_text = tokenizer.decode(indexed_tokens   [predicted_index])
    total_predicted_text  = tokenizer.decode(predicted_index)
    if '<|endoftext|>' in total_predicted_text:
        # 如果出现文本结束标志,就结束文本生成
        break

    indexed_tokens  = [predicted_index]

    if len(indexed_tokens) > 1023:
        # 模型最长输入长度为1024,如果长度过长则截断
        indexed_tokens = indexed_tokens[-1023:]

    tokens_tensor = torch.tensor([indexed_tokens])

print(total_predicted_text)

从生成结果可以看到,模型已经学习到了戏剧剧本的文本结构。但是仔细读起来会发现缺少逻辑和关联,这是因为由于时间和设备的限制,对模型的训练比较有限。如果有条件可以用更多的数据,训练更长的时间,这样模型也会有更好的表现。

5.4 评价指标

https://zhuanlan.zhihu.com/p/88502676

模型A:

融合模型,主要目标有两个:生成长文本,增加生成的故事和提示语的相关性。使用了门限自注意力机制和融合机制((Sriram et al., 2018),融合机制的含义:第一个seq2seq模型进行训练,第二个seq2seq在训练时使用第一个模型的隐层。

模型B:

GPT-2模型,采用117M的预训练模型。作者说明为啥要采用117M的,而不是340M的呢。在做实验的时候,更大的预训练模型还没有放出来呢。 gpt-2详细介绍,从简。网上的资料很多,比如:

解码算法:

起源于机器翻译的发明,大部分生成任务都是采用beam search算法。(Shang et al., 2015; Serbanet al., 2016)。但是研究表明,beam search算法在开放领域的文本生成中,容易出现重复,一般性词汇。 见(Holtzman et al., 2019)。

top-k采样,在解码的每一步,先在整个词汇表的概率分布上取k个token,然后重新规范化,然后从中选择一个作为解码的token。

top-k采样中,k值的影响:

在无条件生成长文本的深度模型中,大的k值代表跟高的熵。更小的k值,生成的文本,往往更简单,重复度高。同时发现,更小的k值,GPT2-117更易于从引导语中复制,包含更多的动词和代词,更少的名词和形容词,名词更具体,更小范围的句式。

如果将k值设为很大,比如词汇表的大小。在大多数指标上和人类的指标相似,但是在常识推理,世界知识,句子之间的连贯性等表现不佳。

5.4.1 困惑度

ppl表示词级别的困惑度,是在WritingPrompts-1024(引导语不超过1024个词)数据子集上。

困惑度(perplexity)的基本思想是:给测试集的句子赋予较高概率值的语言模型较好,当语言模型训练完之后,测试集中的句子都是正常的句子,那么训练好的模型就是在测试集上的概率越高越好,公式如下:

由公式可知,句子概率越大,语言模型越好,迷惑度越小。困惑度p可以理解为,如果每个时间步都根据语言模型计算的概率分布随机挑词,那么平均情况下,挑多少个词才能挑到正确的那个

5.4.2 Prompt ranking accuracy

这个指标的定义和评价方法,来自《Hierarchical Neural Story Generation》。主要是关注引导语和生成的故事之间的相关性。具体做法是:在测试集中选择一对(p,g),p表示引导语,g表示生成的故事,在随机选取其他的引导语p1-p9,然后计算p和g的likelihood。条件一:(p,g)的相似性比(p1,g)的相似性大。 那么就取10000个测试集中的(p,g),满足条件一的部分占比,就称为Prompt ranking accuracy。

GPT2-117的得分:80.16%

Fusion Model 的 39.8%

5.4.3 句子嵌入的相似度

计算引导语和生成的故事的句子嵌入(用GloVe取每个词的平均嵌入值)的余弦相似度。

在top-k算法中,k取不同值,分别计算每个模型,结果如下:

命名实体的使用:主要看引导语中命名实体在生成的故事中出现的次数。

5.4.4 评价连贯性

连贯性的评价方法,来自《Modeling local coherence: An entity-based approach》,主要思想是,在测试数据集中,对于一个故事s0,选择前面15个句子,打乱顺序,生成14个乱序的故事s1-s14。然后用语言模型计算s0-s14的可能性。对于s1-s14,如果可能性大于s0,就称为反例。 错误率定义为反例的占比。

GPT2-117的得分:2.17%

Fusion Model 的3.44%

5.4.5 评价单词的重复性和rareness

GPT2-117比Fusion Model 的重复性要小,rareness要高点。但是差距很小。

6. 对话任务/聊天机器人

训练流程可以参加

https://cloud.tencent.com/developer/article/1877398

https://github.com/yangjianxin1/GPT2-chitchat

详解参见 https://blog.csdn.net/g534441921/article/details/104312983

6.1 常见场景与处理

聊天机器人是语义匹配中最广泛应用的场景。目前的聊天机器人主要分成五种:

  • 基于问答对。输入用户的问题,在由(问题:答案)组成的知识库中检索相似问题,最后将用户相似问题的答案作为结果返回;
  • 基于机器阅读理解:输入用户问题,从知识库中检索相关文档,然后通过机器阅读理解的形式返回答案,这种也涉及检索,不过最关键一步是通过指针网络的形式从文档中抽取出Span作为回答,容易不稳定;
  • 基于知识图谱:输入用户问题,通过语义解析转化成对应的Cypher语法,从建立好的知识图谱中检索问题,困难主要在于知识图谱的建立需要耗费大量人力;
  • 基于任务型对话:针对有限的实际业务场景,例如携程的聊天机器人,输入用户问题,通过意图识别、提取词槽,转换为对应的“订机票”、“查酒店”等服务;
  • 闲聊:类似微软小冰这种,实际应用场景较少。

Q1:知识库的标准问怎么整理?

A:虽然说基于问答对是较为简单的聊天机器人解决方案,但实际应用中,我们要首先考虑这个场景究竟有多泛,是解决一个医药问答、还是一个金融问答、还是一个百科式的问答。一定要先梳理你的场景,假如场景过大,还需要分级管理,如赶着上线,则应该先做高频问答,俗话说二八定律,20%的问题涵盖了80%的常见问题。

Q2:怎么处理冷启动?

A:有时候是一个新的需求,之前没有任何的数据积累,这时候可以通过搜索引擎,如百度知道等搜索一些网民提出的一些相关问题作为知识库,起码这些问题是真实的,假如面对的场景十分窄,搜索不出来,只能让客户提供一些常见问题再进行发散。

Q3:怎么制作训练集?

A:同样容易遇到冷启动,假如现在已经梳理完知识库,怎么生成我们的训练集?

可以通过,如同一个含义的标准问作为一对正样本,不同含义的标准问为一对负样本,但这样容易训练集不够丰富。这里推荐一种做法,把标注问拿去百度知道搜索,通常第1页搜出来的都是语义相同的问题可以作为正样本,10多页的都是些相似度高但语义不同的问题则可以作为负样本,当然还需要人工过审,这做法的好处是极大地丰富了训练集。

Q4:语义匹配要做多细?

A:首先思考,什么叫语义相同的句子?如“怎么成为网络红人”、“怎么样可以成为网络红人”,毫无疑问是属于同一语义的句子对,

但假如是"怎么成为网络红人"、“女的怎么容易成为网络红人”。大家觉得这两个句子属于语义相同吗?

实质上是不严格相同的,但假如在你的业务场景中,这两个问题都对应的是同一个答案,是否能把这两个句子作为相似度为1的正样本让模型去训练?答案在于,你想做得有多粗多细,假如很细粒度,那这两个句子就不是语义相同的句子,或者说它们的相似度不是1,是0.6或0.8,但假如做得很细的话,你需要定义很多标准问。假如做得很广,如把同一个回答的问题都定义为相似度为1的句子,这时候,你必须把这些你认为相似的样本拿去给模型训练,让模型学得,因为这其实不是严格意义上的语义相同,做广的好处是不用定义太多问题,但十分容易不稳定。

Q5:怎么做检索?

A:常见做法是先检索出一批相似问题再精排。其中检索可以用bm25、SBERT等模型,精排可以用Cross-Encoders等结构。

Q6:用户的问题在知识库中没有相似问题?

A:可以设定,

  • 假如有标准问与用户问题相似度0.8以上的,则直接返回相似度最高的标准问对应的答案;
  • 假如相似度最高在0.4~0.8之间,我们可以返回用户“你是否想问...”;
  • 假如相似度在0.4以下,我们可以返回与用户问题相似度最高的三个问题,输出“你是否想问这些问题。。。”;

6.2 评价指标

6.2.1 检索类评价指标

信息检索里的评估方法,最常用的如 Recall@k,给定一个 query,选择 k 个最有可能的 response,看正确的 response 在不在这 k 个里。

6.2.2 生成类评价指标

词重叠评价指标

主要有 BLEUROUGEMETEOR,最初用于衡量机器翻译的效果。BLEU 主要看人为/测试的句子里的单词的 overlap (机器产生的待评测句子中的 ngram 正确匹配人工产生的参考句子中 ngram 与机器产生的句子中所有 ngram 出现次数的比值),加入 BP(Brevity Penalty) 惩罚因子可以评价句子的完整性。然而 BLEU 不关心语法,只关心内容分布,适用于衡量数据集量级的表现,在句子级别的表现不佳。

“BLEU is designed to approximate human judgement at a corpus level, and performs badly if used to evaluate the quality of individual sentences.”——wikipedia

ROUGE 是一种基于召回率的相似性度量方法,与 BLEU 类似,但计算的是 ngram 在参考句子和待评测句子的共现概率,包含 ROUGE-N, ROUGE-L(最长公共子句, Fmeasure), ROUGE-W(带权重的最长公共子句, Fmeasure), ROUGE-S(不连续二元组, Fmeasure) 四种,具体不多说。

METEOR 改进了 BLEU,考虑了参考句子和待评测句子的对齐关系,和人工判断的结果有更高的相关性。

词向量评价指标

侧重比较生成的句子和真实样本的语义相似度,但是仅仅是在词向量的基础上,很难捕捉长距离的语义

  • Embedding average score 将句中每个单词的词向量作平均来作为句子的特征,计算生成的句子和真实句子的特征的 cosine similarity
  • Greedy matching score 寻找生成的句子和真实句子中最相似的一对单词,把这对单词的相似度近似为句子的距离
  • Vector extrema score 对句中单词词向量的每一个维度提取最大(小)值作为句子向量对应维度的数值,然后计算cosine similarity

6.2.3 基于学习的评价指标

使用机器学习/神经网络的方法来学习一个好的评价指标,使得模型打分和人工打分更接近。像各种 GANs、ADEM、Dual Encoder(DE) 等等。

6.2.4 人工评测

“We find that all metrics show either weak or no correlation with human judgements, despite the fact that word overlap metrics have been used extensively in the literature for evaluating dialogue response models”

在 How NOT To Evaluate Your Dialogue System 这篇论文中,宣称和人工判断相比,所有 metric 都是垃圾

  • 在闲聊性质的数据集上,上述 metric 和人工判断有一定微弱的关联 (only a small positive correlation on chitchat oriented Twitter dataset)
  • 在技术类的数据集上,上述 metric 和人工判断完全没有关联(no correlation at all on the technical UDC)
  • 当局限于一个特别具体的领域时,BLEU 会有不错的表现

综上,对话系统的评价指标其实应该还算是一个研究热点吧,尤其是基于学习的评价指标。另外如果要评价多轮对话,那就更加复杂了,还要引入评测时机,比如是否每轮对话都做评估,是不是在提到一个概念(slot-value pair)时才评估……

6.3 数据集

天池:“公益AI之星”挑战赛-新冠疫情相似句对判定大赛

这个比赛就是上面说的场景1,而且是一个十分细分的聊天场景,主打疫情相关的呼吸领域问题。越是细分的领域,相对来说更好做,准确率更高。

天池:「小布助手对话短文本语义匹配」

用语义匹配的来做意图识别,而非直接检索问题。这给我们开扩了思路,上面说到的聊天机器人中的任务型机器人,第一步是意图识别,传统做法是当成一个分类任务来做,但用分类方法做的缺点是难以拓展(如一开始限定好10个意图类比,以后像扩展的话,要重新训练模型),但用语义匹配做则不用,增加意图只需要在对应的库里增加相关问题。

2019法研杯:

针对多篇法律文书进行相似度的计算和判断。具体来说,对于每份文书我们提供文书的标题和事实描述,选手需要从两篇候选集文书中找到与询问文书更为相似的一篇文书。类似上面我提到的场景2,用语义匹配的方式做检索,检索出的案件或工单用于给工作人员参考。

CCF:“技术需求”与“技术成果”项目之间关联度计算模型

应用场景是有一个平台,定期收集技术需求和技术成果,定期更新技术需求库和技术成果库,数据来源有两种:(1)会员单位发布;(2)非会员单位官方网站采集。每月新增数据量约3000个项目。

根据项目信息的文本含义,为供需双方提供关联度较高的对应信息(需求——成果智能匹配服务),是平台的一项功能需求。技术需求与技术成果之间的关联度分为四个层级:强相关、较强相关、弱相关、无相关。

百度千言数据集:
  • LCQMC(A Large-scale Chinese Question Matching Corpus), 百度知道领域的中文问题匹配数据集;
  • BQ Corpus(Bank Question Corpus), 银行金融领域的问题匹配数据;
  • PAWS-X (中文):语义匹配中难度很高的数据集。数据集里包含了释义对和非释义对,即识别一对句子是否具有相同的释义(含义),特点是具有高度重叠词汇,对于进一步提升模型对于强负例的判断很有帮助。
搜狐:2021搜狐校园文本匹配算法大赛

每对文本在两个颗粒度上判断文本对中的两段文字是否匹配。其中,一个颗粒度较为宽泛,两段文字属于一个话题即可视为匹配;另一个颗粒度较为严格,两段文字必须是同一事件才视为匹配。如下面的问题,它们都是说英超足球,属于同一个话题,但是两个不是同一个事件。

总结

因GPT是一自回归语言模型,实验的场景设定是zero-shot预测,没有特别针对下游任务进行设计和微调,所以在各种NLP任务如阅读理解、问答系统、文本摘要、翻译系统等虽然也能取的一定的效果,但是比BERT这类经过微调的监督模型会有差距。

为什么GPT模型相比BERT更适合文本生成?

目前主流的文本生成是从左到右进行的,生成第N个token时,只能用到第1~N-1个token的信息,无法用到后面的token信息,而GPT/GPT-2正是用相同的从左到右生成任务进行预训练(也就是所谓的单向),预训练与下游任务一致;

而BERT使用MLM任务进行预训练,即给出前后上下文,预测文中被mask掉的一个token,这种预训练方式使BERT可以充分利用双向的上下文信息(前文和后文),但在文本生成任务中,模型天然只能使用前文信息,与BERT的预训练任务存在较大的gap,因此BERT并不适合直接用于文本生成任务。

作者宣称,即便 GPT-2 在参数上十倍于 GPT,五倍于 Bert,却依然在 WebText 数据集上是欠拟合的。

网络越叠越大,也许没有尽头,而在找到更高效的网络之前,我们的最佳选择仍然是 Transformer。

Ref

  1. https://zhuanlan.zhihu.com/p/96791725 GPT/GPT2 介绍
  2. https://github.com/Morizeyao/GPT2-Chinese
  3. https://cloud.tencent.com/developer/article/1748379 GPT2
  4. https://cloud.tencent.com/developer/article/1877398 GPT2 聊天机器人
  5. http://jalammar.github.io/illustrated-gpt2/ GPT2详解
  6. http://blog.zhangcheng.ai/2019/04/28/汝果欲学诗,功夫在诗外-论gpt-2无监督预训练的/
  7. https://www.cnblogs.com/wwj99/p/12503545.html pytorch GPT2
  8. https://zhuanlan.zhihu.com/p/88502676 GPT2训练
  9. https://cloud.tencent.com/developer/article/1877398 GPT2聊天机器人训练
  10. https://blog.csdn.net/g534441921/article/details/104312983 GPT2 对话任务综述
  11. https://cloud.tencent.com/developer/article/1783241 DialoGPT
  12. https://mp.weixin.qq.com/s/43yfUIyp7L4lCRVFKms3Og 语义匹配与对话

0 人点赞