环信AI公开课:OpenAI通用语言模型GPT-2论文解析

时间:2022-11-10
OpenAI最近似乎搞了个大新闻,随手一搜,”最大模型”、”15亿参数”、”无需领域数据”等等跃然在目。当然现在是标题党的年代,为了吸引眼球,外行媒体的夸张手法也能理解。

  成就电商销量神话 抖音广告精准引流

OpenAI最近似乎搞了个大新闻,随手一搜,”最大模型”、”15亿参数”、”无需领域数据”等等跃然在目。当然现在是标题党的年代,为了吸引眼球,外行媒体的夸张手法也能理解。当然最大的争议还是他们在官网上解释为什么只提供小模型的理由:为了防止大模型用于生成欺诈和有歧视性的文章,我们只发布小规模的模型(Due to concerns about large language models being used to generate deceptive, biased, or abusive language at scale, we are only releasing a much smaller version of GPT-2 along with sampling code)。这个当然引起了轩然大波,使得很多人在Reddit上吐槽。听这语气,人工智能已经实现了,为了保护人类,他们不能把这个恶魔放出来。实际情况怎么样呢?别听专家的,最好还是我们自己读读论文跑跑代码吧。

目录

背景简介

BERT的缺陷

语言模型

Children’s Book

LAMBADA

Winograd Schema Challenge

Reading Comprehension

Summarization

机器翻译

Question Answering

大翻盘

代码

背景简介

Word Embedding解决了传统机器学习方法的特征稀疏问题,它通过把一个词映射到一个低维稠密的语义空间,从而使得相似的词可以共享上下文信息,从而提升泛化能力。而且通过无监督的训练可以获得高质量的词矢量(比如Word2vec和Glove等方法),从而把这些语义知识迁移到数据较少的具体任务上。但是Word Embedding学到的是一个词的所有语义,比如bank可以是”银行”也可以是”水边。如果一定要用一个固定的矢量来编码其语义,那么我们只能把这两个词的语义都编码进去,但是实际一个句子中只有一个语义是合理的,这显然是有问题的。

这时我们可以通过RNN/LSTM/GRU来编码上下文的语义,这样它能学到如果周围是money,那么bank更可能是”银行”的语义。最原始的RNN由于梯度消失和梯度爆炸等问题很难训练,后来引入了LSTM和GRU等模型来解决这个问题。最早的RNN只能用于分类、回归和序列标注等任务,通过引入两个RNN构成的Seq2Seq模型可以解决序列的变换问题。比如机器翻译、摘要、问答和对话系统都可以使用这个模型。尤其机器翻译这个任务的训练数据比较大,使用深度学习的方法的效果已经超过传统的机器学习方法,而且模型结构更加简单。到了2017年,Google提出了Transformer模型,引入了Self-Attention。Self-Attention的初衷是为了用Attention替代LSTM,从而可以更好的并行(因为LSTM的时序依赖特效很难并行),从而可以处理更大规模的语料。Transformer出来之后被广泛的用于以前被RNN/LSTM/GRU霸占的地盘,Google更是在Transformer的论文里使用”Attention is all you need”这样霸气的标题。现在Transformer已经成为Encoder/Decoder的霸主。

虽然RNN可以学到上下文的信息,但是这些上下文的语义是需要通过特定任务的标注数据使用来有监督的学习。很多任务的训练数据非常少并且获取成本很高,因此在实际任务中RNN很难学到复杂的语义关系。当然通过Multi-Task Learning,我们可以利用其它相关任务的数据。比如我们要做文本分类,我们可以利用机器翻译的训练数据,通过同时优化两个(多个)目标,让模型同时学到两个任务上的语义信息,因为这两个任务肯定是共享很多基础语义信息的,所以它的效果要比单个任务好。但即使这样,标注的数据量还是非常有限的。

因此2018年的研究热点就变成了怎么利用无监督的数据学习Contextual Word Embedding(也叫做Universal Sentence Embedding),也就是通过无监督的方法,让模型能够学到一个词在不同上下文的不同语义表示方法。当然这个想法很早就有了,比如2015年的Skip Thought Vector,但是它只使用了BookCorpus,这只有一万多本书,七千多万个句子,因此效果并没有太明显的提升。

在BERT之前比较大的进展是ELMo、ULMFiT和OpenAI GPT。尤其是OpenAI GPT,它在BERT出现之前已经横扫过各大排行榜一次了,当然Google的BERT又横扫了一次,并且PR效果更加明显。所以OpenAI看风头都被Google强劲,自然有些羡慕嫉妒恨,也就有了今天我们要讨论的OpenAI GPT-2。

UMLFiT比较复杂,而且效果也不是特别好,我们暂且不提。ELMo和OpenAI GPT的思想其实非常非常简单,就是用海量的无标注数据学习语言模型,在学习语言模型的过程中自然而然的就学到了上下文的语义关系。它们俩都是使用Transformer来学习语言模型,但是在进行下游任务处理的时候就有所不同,ELMo是把它当成特征。拿分类任务来说,输入一个句子,用ELMo把它扫一次,这样就可以得到每个词的表示,这个表示是考虑上下文的,因此”He deposited his money in this bank”和”His soldiers were arrayed along the river bank”中的两个bank的矢量是不同的。下游任务用这些矢量来做分类,它会增加一些网络层,但是ELMo语言模型的参数是固定的。而OpenAI GPT不同,它直接用特定任务来Fine-Tuning Transformer的参数。因为用特定任务的数据来调整Transformer的参数,这样它更可能学习到与这个任务特定的上下文语义关系,因此效果也更好。

而BERT和OpenAI GPT的方法类似,也是Fine-Tuning的思路,但是它解决了OpenAI GPT(包括ELMo)单向信息流的问题,同时它的模型和语料库也更大。依赖Google强大的计算能力和工程能力,BERT横扫了OpenAI GPT,在后者霸主宝座屁股还没坐热的时候就把它赶下台。成王败寇,再加上Google的PR能力,很少还有人记得OpenAI GPT的贡献了。要说BERT的学术贡献,最多是利用了Mask LM(这个模型在上世纪就存在了)和Predicting Next Sentence这个Multi-task Learning而已,其余的方法都是完全follow OpenAI GPT的。因此OpenAI心情郁闷也就可以理解了,这次搞出个GPT-2也是想出来露个脸,刷一下存在感。

BERT的缺陷

不过没关系,他们的目标是BERT的软肋——不能生成句子(段落和篇章当然就更不行了)。我们来看看论文的实验是怎么设计的:

语言模型

BERT不是普通的语言模型吧,好,那咱们来PK一下(你是零分啊)。但是用Transformer去跑语言模型这样的灌水文章别人早发过了,没啥意思。因此要搞出一个Zero-shot的概念:你们在一个很小的语料库训练一个语言模型然后大家比赛,俺不这么跟你玩。俺用很大的语料训练一个模型,然后不用你的数据,效果还能超过你们在小数据上的效果。

当然这个概念还是不错的,结果如下图所示。

图:不同数据集上语言模型的PPL,越小越好

我们看到,除了最后一个1BW的很大的语料库,OpenAI都超过了它们。其实这也说明了,如果有很多的领域数据,还是领域数据好使,这在机器翻译系统里也得到了验证。如果训练数据较少,我们通常使用预训练的词矢量作为模型词矢量的初始值。如果训练数据非常少,我们通常固定预训练的词矢量;如果训练数据还可以,那么就Fine-Tuning一下。如果训练数据很多,比如在机器翻译任务里,预训练的词矢量和随机初始化的效果没什么区别(开始的时候好一点,因为比较是相对较好的初始值)。

Children’s Book

类似于完型填空,其实BERT是可以搞的。但是NLP的比赛那么多,Google总不能都做完吧。国内很多AI公司天天发PR稿:我们又获得了一个世界第一。其实很多外行的读者并不知道这个比赛只有5个参数选手,可能其中2个还是某个在校学生挤出周末打游戏的时间去做的。

图:Children’s Book任务

效果似乎还不错,离人类的水平相差不远。

LAMBADA

Winograd Schema Challenge

Reading Comprehension

Summarization

摘要任务,分越高越好,成绩单如下:

图:Children’s Book任务

机器翻译

SOTA的BLEU分(越高越好)33.5,俺不学习也得了11.5。

Question Answering

无监督的效果惨不忍睹。

大翻盘

代码

git clone https://github.com/openai/gpt-2.git && cd gpt-2

pip3 install tensorflow==1.12.0

安装其它依赖:

pip3 install -r requirements.txt

下载模型:

python3 download_model.py 117M

因为模型放在storage.googleapis.com,所以需要科学上网,可以这样修改代码,请把”127.0.0.1:1080”改成你自己的代理:

$ git diffdiff --git a/download_model.py b/download_model.pyindex 2a38294..83d6fb8 100644--- a/download_model.py+++ b/download_model.py@@ -15,7 +15,11 @@ if not os.path.exists(subdir): for filename in ['checkpoint','encoder.json','hparams.json','model.ckpt.data-00000-of-00001', 'model.ckpt.index', 'model.ckpt.meta', 'vocab.bpe']: - r = requests.get("https://storage.googleapis.com/gpt-2/" + subdir + "/" + filename, stream=True)+ proxies = {+ 'http': 'http://127.0.0.1:1080',+ 'https': 'http://127.0.0.1:1080',+ }+ r = requests.get("https://storage.googleapis.com/gpt-2/" + subdir + "/" + filename, stream=True, proxies=proxies) with open(os.path.join(subdir, filename), 'wb') as f:

使用前需要设置编码:

export PYTHONIOENCODING=UTF-8

×
扫一扫img_load
发送图纸