zhichaoouyang / blog Goto Github PK
View Code? Open in Web Editor NEW个人笔记
个人笔记
图像是如何使用预训练的模型呢?一般是CNN多层叠加的网络结构。举个例子,A,B,C三个模型。A和B是已经预训练好的模型,用一些大的训练集在模型A,B上学会了网络参数,存起来以备后用。
在面临第三个模型C,网络结构和A,B相同。在比较浅的几层CNN结构,网络参数的初始化久可以加载好A或者B训练好的参数。另外其他的高层CNN参数我们仍然可以随机初始化。之后用C独自的训练集再次用来训练一个完整的网络参数。此时有两次调整方法。一个方法叫做“Frozen”,即浅层加载的参数在训练C任务过程中不动。另一种是底层网络参数尽管被初始化,在C任务训练过程中仍然随着训练的进程改变,这种一般叫“Fine-Tuning”。顾名思义,就是更好地把参数进行调整使得更适应当前的 C 任务。一般图像或者视频领域要做预训练一般都这么做。
这么做有几个好处,首先,如果手头任务 C 的训练集合数据量较少的话,现阶段的好用的 CNN 比如Resnet/Densenet/Inception 等网络结构层数很深,几百万上千万参数量算起步价,上亿参数的也很常见,训练数据少很难很好地训练这么复杂的网络,但是如果其中大量参数通过大的训练集合比如 ImageNet 预先训练好直接拿来初始化大部分网络结构参数,然后再用 C 任务手头比较可怜的数据量上 Fine-tuning 过程去调整参数让它们更适合解决 C 任务,那事情就好办多了。
这样原先训练不了的任务就能解决了,即使手头任务训练数据也不少,加个预训练过程也能极大加快任务训练的收敛速度,所以这种预训练方式是老少皆宜的解决方案,另外疗效又好,所以在做图像处理领域很快就流行开来。
目前我们已经知道,对于层级的 CNN 结构来说,不同层级的神经元学习到了不同类型的图像特征,由底向上特征形成层级结构,如上图所示,如果我们手头是个人脸识别任务,训练好网络后,把每层神经元学习到的特征可视化肉眼看一看每层学到了啥特征,你会看到最底层的神经元学到的是线段等特征,图示的第二个隐层学到的是人脸五官的轮廓,第三层学到的是人脸的轮廓,通过三步形成了特征的层级结构,越是底层的特征越是所有不论什么领域的图像都会具备的比如边角线弧线等底层基础特征,越往上抽取出的特征越与手头任务相关。
正因为此,所以预训练好的网络参数,尤其是底层的网络参数抽取出特征跟具体任务越无关,越具备任务的通用性,所以这是为何一般用底层预训练好的参数初始化新任务网络参数的原因。而高层特征跟任务关联较大,实际可以不用使用(预训练的A或B的高层特征不用),或者采用 Fine-tuning 用新数据集合清洗掉高层无关的特征抽取器。
一般我们喜欢用 ImageNet 来做网络的预训练,主要有两点,一方面 ImageNet 是图像领域里有超多事先标注好训练数据的数据集合,分量足是个很大的优势,量越大训练出的参数越靠谱;另外一方面因为 ImageNet 有 1000 类,类别多,算是通用的图像数据,跟领域没太大关系,所以通用性好,预训练完后哪哪都能用,是个万金油。分量足的万金油当然老少通吃,人人喜爱。
NNLM思路总结:
学习任务是输入某句话中$W_t='Bert'$单词前面句子的$t-1$个单词,要求网络能够预测单词Bert,即最大化
前面的任意单词$W_i$用onehot编码作为原始单词输入,之后乘以矩阵Q(embedding的权值)后获得向量$C(W_i)$,每个单词的$C(W_i)$拼接,上接上接隐层,然后接 softmax 去预测后面应该后续接哪个单词。这个$C(W_i)$是什么?这其实就是单词对应的 Word Embedding 值,那个矩阵 Q 包含 V 行,V 代表词典大小,每一行内容代表对应单词的 Word embedding 值。只不过 Q 的内容也是网络参数,需要学习获得,训练刚开始用随机值初始化矩阵 Q,当这个网络训练好之后,矩阵 Q 的内容被正确赋值,每一行代表一个单词对应的 Word embedding 值。
所以你看,通过这个网络学习语言模型任务,这个网络不仅自己能够根据上文预测后接单词是什么,同时获得一个副产品,就是那个矩阵 Q,这就是单词的 Word Embedding 是被如何学会的。
Word2Vec 的网络结构其实和 NNLM 是基本类似的,后还延伸出
Glove。
与NNLM的网络结构基本类似,也是做语言模型任务。但训练方法不一样,word2vec有两种训练方法,一种是CBOW,核心**是从一个句子里面把一个词抠掉,用这个词的上文和下文去预测被抠掉的这个词;第二种叫做 Skip-gram,和 CBOW 正好反过来,输入某个单词,要求网络预测它的上下文单词。
而你回头看看,NNLM 是怎么训练的?是输入一个单词的上文,去预测这个单词。这是有显著差异的。为什么 Word2Vec 这么处理?原因很简单,因为 Word2Vec 和 NNLM 不一样,NNLM 的主要任务是要学习一个解决语言模型任务的网络结构,语言模型就是要看到上文预测下文,而 word embedding 只是无心插柳的一个副产品。但是 Word2Vec 目标不一样,它单纯就是要 word embedding 的,这是主产品,所以它完全可以随性地这么去训练网络。
假设如上图所示,我们有个 NLP 的下游任务,比如 QA,就是问答问题,所谓问答问题,指的是给定一个问题 X,给定另外一个句子 Y, 要判断句子 Y 是否是问题 X 的正确答案。问答问题假设设计的网络结构如上图所示,这里不展开讲了,懂得自然懂,不懂的也没关系,因为这点对于本文主旨来说不关键,关键是网络如何使用训练好的 Word Embedding 的。
它的使用方法其实和前面讲的 NNLM 是一样的,句子中每个单词以 Onehot 形式作为输入,然后乘以学好的 Word Embedding 矩阵 Q,就直接取出单词对应的 Word Embedding 了。这乍看上去好像是个查表操作,不像是预训练的做法是吧?其实不然,那个 Word Embedding 矩阵 Q 其实就是网络 Onehot 层到 embedding 层映射的网络参数矩阵。
所以你看到了,使用 Word Embedding 等价于什么?等价于把 Onehot 层到 embedding 层的网络用预训练好的参数矩阵 Q 初始化了。这跟前面讲的图像领域的低层预训练过程其实是一样的,区别无非 Word Embedding 只能初始化第一层网络参数,再高层的参数就无能为力了。下游 NLP 任务在使用 Word Embedding 的时候也类似图像有两种做法:
一种是 Frozen,就是 Word Embedding 那层网络参数固定不动;
另外一种是 Fine-Tuning,就是 Word Embedding 这层参数使用新的训练集合训练也需要跟着训练过程更新掉。
上面这种做法就是 18 年之前 NLP 领域里面采用预训练的典型做法,有帮助,但是效果没有非常好,因为word embedding有存在问题,需要改进。
多义词 Bank,有两个常用含义,但是 Word Embedding 在对 bank 这个单词进行编码的时候,是区分不开这两个含义的,因为它们尽管上下文环境中出现的单词不同,但是在用语言模型训练的时候,不论什么上下文的句子经过 word2vec,都是预测相同的单词 bank,而同一个单词占的是同一行的参数空间,这导致两种不同的上下文信息都会编码到相同的 word embedding 空间里去。所以 word embedding 无法区分多义词的不同语义,这就是它的一个比较严重的问题。
ELMO 提供了一种简洁优雅的解决方案。
ELMO 的本质**是:我事先用语言模型学好一个单词的 Word Embedding,此时多义词无法区分,不过这没关系。在我实际使用 Word Embedding 的时候,单词已经具备了特定的上下文了,这个时候我可以根据上下文单词的语义去调整单词的 Word Embedding 表示,这样经过调整后的 Word Embedding 更能表达在这个上下文中的具体含义,自然也就解决了多义词的问题了。所以ELMO 本身是个根据当前上下文对 Word Embedding 动态调整的思路。
ELMO 采用了典型的两阶段过程,第一个阶段是利用语言模型进行预训练;第二个阶段是在做下游任务时,从预训练网络中提取对应单词的网络各层的 Word Embedding 作为新特征补充到下游任务中。
此时的语言模型训练任务目标是根据单词$W_i$的上下文去预测单词$W_i$,$W_i$之前的单词序列算是上文,之后的单词序列算是上文,之后的单词序列算是下文。正向LSTM编码的是从左到右顺序除$W_i$的上文(无下文?),反向LSTM编码的是从右到左顺序除$W_i$的下文。此时,每个单词都会有一个前向和后向的lstm的隐藏状态。
训练目标,最大化
使用这个网络结构利用大量语料做语言模型任务就能预先训练好这个网络,如果训练好这个网络后,输入一个新的句子
,句子中每个单词都能得到对应的三个Embedding:最底层是单词的 Word Embedding,往上走是第一层双向 LSTM中对应单词位置的 Embedding,这层编码单词的句法信息更多一些;再往上走是第二层 LSTM 中对应单词位置的 Embedding,这层编码单词的语义信息更多一些。也就是说,ELMO 的预训练过程不仅仅学会单词的 Word Embedding,还学会了一个双层双向的 LSTM 网络结构,而这两者后面都有用。
上面介绍的是 ELMO 的第一阶段:预训练阶段。那么预训练好网络结构后,如何给下游任务使用呢?上图展示了下游任务的使用过程,比如我们的下游任务仍然是 QA 问题,此时对于问句 X,我们可以先将句子 X 作为预训练好的 ELMO 网络的输入,这样句子 X 中每个单词在 ELMO 网络中都能获得对应的三个 Embedding,之后给予这三个 Embedding 中的每一个 Embedding 一个权重 a,这个权重可以学习得来,根据各自权重累加求和,将三个 Embedding 整合成一个。
然后将整合后的这个 Embedding 作为 X 句在自己任务的那个网络结构中对应单词的输入,以此作为补充的新特征给下游任务使用。对于上图所示下游任务 QA 中的回答句子 Y 来说也是如此处理。
因为 ELMO给下游提供的是每个单词的特征形式,所以这一类预训练的方法被称为“Feature-based Pre-Training”
缺点:1. LSTM抽取特征能力比transformer弱。2. 拼接方式双向融合特征能力偏弱(按道理猜想)。
两阶段:第一个阶段是利用语言模型进行预训练,第二阶段通过 Fine-tuning 的模式解决下游任务。
与ELMO类似,但存在区别。
第二个不同造成了他有天然的劣势,缺失了下文信息,就失去了很多信息,限制了应用场景。比如阅读理解,在做任务的时候是可以允许同时看到上文和下文一起做决策的。如果预训练时候不把单词的下文嵌入到 Word Embedding 中,是很吃亏的。
补充一点:transformer可做并行计算,而RNN并行计算能力有限。Transformer 同时具备并行性好,又适合捕获长距离特征。
GPT下游任务
要向 GPT 的网络结构看齐,把任务的网络结构改造成和 GPT 的网络结构是一样的。然后,在做下游任务的时候,利用第一步预训练好的参数初始化 GPT 的网络结构,这样通过预训练学到的语言学知识就被引入到你手头的任务里来了,这是个非常好的事情。再次,你可以用手头的任务去训练这个网络,对网络参数进行 Fine-tuning,使得这个网络更适合解决手头的问题。
GPT 论文给了一个改造施工图如上,其实也很简单:对于分类问题,不用怎么动,加上一个起始和终结符号即可;对于句子关系判断问题,比如 Entailment,两个句子中间再加个分隔符即可;对文本相似性判断问题,把两个句子顺序颠倒下做出两个输入即可,这是为了告诉模型句子顺序不重要;对于多项选择问题,则多路输入,每一路把文章和答案选项拼接作为输入即可。从上图可看出,这种改造还是很方便的,不同任务只需要在输入部分施工即可。
BERT的全称是BIDIRECTIONAL ENCODER REPRESENTATION FROM TRANSFORMERS,是Google2018年提出的预训练模型,即双向Transformer的Encoder,因为decoder是不能获要预测的信息的。
Bert 采用和 GPT 完全相同的两阶段模型,首先是语言模型预训练;其次是使用 Fine-Tuning 模式解决下游任务。和 GPT 的最主要不同在于在预训练阶段采用了类似 ELMO 的双向语言模型,当然另外一点是语言模型的数据规模要比 GPT 大。但是训练的目标函数不同。BERT是以$P(w_i|w_1,\cdots,w_{i-1},w_{i+1},\cdots,w_n)$作为目标函数训练LM。与ELMO双向LSTM得到表征拼接起来是有区别的。
第二阶段,Fine-Tuning 阶段,这个阶段的做法和 GPT 是一样的。当然,它也面临着下游任务网络结构改造的问题,在改造任务方面 Bert 和 GPT 有些不同,下面简单介绍一下。
对于种类如此繁多而且各具特点的下游 NLP 任务,Bert 如何改造输入输出部分使得大部分 NLP 任务都可以使用 Bert 预训练好的模型参数呢?
上图给出示例,对于句子关系类任务,很简单,和 GPT 类似,加上一个起始和终结符号,句子之间加个分隔符即可。对于输出来说,把第一个起始符号对应的 Transformer 最后一层位置上面串接一个 softmax 分类层即可。对于分类问题,与 GPT 一样,只需要增加起始和终结符号,输出部分和句子关系判断任务类似改造;对于序列标注问题,输入部分和单句分类是一样的,只需要输出部分 Transformer 最后一层每个单词对应位置都进行分类即可。从这里可以看出,上面列出的 NLP 四大任务里面,除了生成类任务外,Bert 其它都覆盖到了,而且改造起来很简单直观。
Bert 其实和 ELMO 及 GPT 存在千丝万缕的关系,比如如果我们把 GPT 预训练阶段换成双向语言模型,那么就得到了 Bert;而如果我们把 ELMO 的特征抽取器换成 Transformer,那么我们也会得到 Bert。所以你可以看出:Bert 最关键两点,一点是特征抽取器采用 Transformer;第二点是预训练的时候采用双向语言模型。
前面提到了 CBOW 方法,它的核心**是:在做语言模型任务的时候,我把要预测的单词抠掉,然后根据它的上文 Context-Before 和下文 Context-after 去预测单词。其实 Bert 怎么做的?Bert 就是这么做的。从这里可以看到方法间的继承关系。当然 Bert 作者没提 Word2Vec 及 CBOW 方法,这是我的判断,Bert 作者说是受到完形填空任务的启发,这也很可能,但是我觉得他们要是没想到过 CBOW 估计是不太可能的。
Masked 双向语言模型向这么做:随机选择语料中 15% 的单词,把它抠掉,也就是用 [Mask] 掩码代替原始单词,然后要求模型去正确预测被抠掉的单词。但是这里有个问题:训练过程大量看到 [mask] 标记,但是真正后面用的时候是不会有这个标记的,这会引导模型认为输出是针对 [mask] 这个标记的,但是实际使用又见不到这个标记,这自然会有问题。
为了避免这个问题,Bert 改造了一下,15% 的被上天选中要执行 [mask] 替身这项光荣任务的单词中,只有 80% 真正被替换成 [mask] 标记,10% 被狸猫换太子随机替换成另外一个单词,10% 情况这个单词还待在原地不做改动。这就是 Masked 双向语音模型的具体做法。
至于说“Next Sentence Prediction”,指的是做语言模型预训练的时候,分两种情况选择两个句子,一种是选择语料中真正顺序相连的两个句子;另外一种是第二个句子从语料库中抛色子,随机选择一个拼到第一个句子后面。我们要求模型除了做上述的 Masked 语言模型任务外,附带再做个句子关系预测,判断第二个句子是不是真的是第一个句子的后续句子。
之所以这么做,是考虑到很多 NLP 任务是句子关系判断任务,单词预测粒度的训练到不了句子关系这个层级,增加这个任务有助于下游句子关系判断任务。所以可以看到,它的预训练是个多任务过程。这也是 Bert 的一个创新。
Bert 的输入部分,也算是有些特色。它的输入部分是个线性序列,两个句子通过分隔符分割,最前面和最后增加两个标识符号。每个单词有三个 embedding:
位置信息 embedding,这是因为 NLP 中单词顺序是很重要的特征,需要在这里对位置信息进行编码;
单词 embedding, 这个就是我们之前一直提到的单词 embedding;
句子 embedding,因为前面提到训练数据都是由两个句子构成的,那么每个句子有个句子整体的 embedding 项对应给每个单词。把单词对应的三个 embedding 叠加,就形成了 Bert 的输入。
总结下BERT的主要贡献:
引入了Masked LM,使用双向LM做模型预训练。
为预训练引入了新目标NSP,它可以学习句子与句子间的关系。
进一步验证了更大的模型效果更好: 12 –> 24 层。
为下游任务引入了很通用的求解框架,不再为任务做模型定制。
刷新了多项NLP任务的记录,引爆了NLP无监督预训练技术。
BERT优点
Transformer Encoder因为有Self-attention机制,因此BERT自带双向功能。
因为双向功能以及多层Self-attention机制的影响,使得BERT必须使用Cloze版的语言模型Masked-LM来完成token级别的预训练。
为了获取比词更高级别的句子级别的语义表征,BERT加入了Next Sentence Prediction来和Masked-LM一起做联合训练。
为了适配多任务下的迁移学习,BERT设计了更通用的输入层和输出层。
BERT缺点
task1的随机遮挡策略略显粗犷,推荐阅读《Data Nosing As Smoothing In Neural Network Language Models》。
[MASK]标记在实际预测中不会出现,训练时用过多[MASK]影响模型表现。每个batch只有15%的token被预测,所以BERT收敛得比left-to-right模型要慢(它们会预测每个token)。
BERT对硬件资源的消耗巨大(大模型需要16个tpu,历时四天;更大的模型需要64个tpu,历时四天。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.