较详细地解读Bert原文及简单的keras调用实现

前言

bert自问世到现在也快一年了,不过我也是最近一段时间才看了下这篇轰动NLP界的文章,说实话,有些地方并不是太好理解,很多博客在当时也没能解答我的一些困惑,不过带着疑问去看原文是必要的。这篇博客主要还是基于bert的原文对其进行一个介绍,希望在这片文章中尽量把我看别人博客时感到困惑的地方说的更加清楚。最后希望读者自己还是去看一下原文,毕竟笔者能力很有限,有些地方理解不对也是有可能的,本文只能提供一个引导和参考。废话不多说,进入主题。

综述

什么是bert? 和传统的pre-rain模型几乎一样,主要分为两个部分:

  • 第一部分是pre-train的主要部分,这一部分是一个语言模型,但是细节上和传统语言模型还是有很大差异。
  • 第二就是是基于具体预测任务的fine-tuning部分。简单介绍下,fine-tuning和Feature-based是在pre-train后,再训练时的两个不同的思路,前者是对于已经pre-train完成的网络层参数,在新的任务中任然会随着训练而更新,而Feature-based则不会再更新这些参数,当然也可以折中,就是freeze网络的前几层,仅仅让后几层的参数随着训练而更新。还不清楚的同学可以自己再自己查阅下相关介绍。

个人认为bert的主要创新点,主要有以下三点:

  1. 输入层面的创新。
  2. 对句子进行mask操作。
  3. 将输入的句子分成2个"部分"来考虑。

接下来就分别以这三点为主要脉络来介绍bert。

主要部分

首先贴一张Bert的总览图,下面介绍的时候会再提到这张图,大家再翻回来看
在这里插入图片描述

图一:总览

1.输入介绍

在这里插入图片描述

图二:输入层
首先我们看input层,可以发现它的输入token并不是基于单词级别的,而是基于一定的规则,对单词进行了“切分”(比如这里的playing被拆成了play和##ing)**Google's Neural Machine Translation System: Bridging the Gap between Human and Machine Translation**(作者在此处引用了这篇文章,感兴趣的同学可以自行查看)。

然后我们还能发现[cls]和[sep]两个多余的token,我们这里可以先简单把cls当成这个句子的一个“概括”。而[sep]则是对这个input的一个“分割”,后面还会再提到它们,这里先略过。
另外最主要的就是下面的三层了:

  • 第一层很好理解,每个token都应该有自己专属的embeding向量
  • 第二层表示当前的token是属于前一句还是后一句。对于“某些”(比如问答)任务,输入可能分为前后两部分。(注意这里的EA都是一致的)
  • 第三层是表示token位置信息的向量,因为Bert的中间层采用的以attention为核心的网络结构,而attention又不太擅长捕捉token位置信息,所以一开始就把位置信息作为向量输入是非常不错的选择。

到此基本就介绍完了输入。

对句子进行mask操作

简单来说就是,随机在所有的句子上挖掉(mask)15%的token,并且用[Mask]来代替。
问题是,为什么要进行mask操作?因为这样就能很自然地能学习被mask掉的token的上下文去预测出token概率的这一“行为”了。而以往语言模型的从左向右或者从右往左,或者是把二者结合起来,都不如mask来的这么自然。

  • 输入:新得到的句子用于pre-train语言模型的输入
  • 输出:则是预测 挖掉的 token的基于softmax计算的一个概率向量(这点和传统语言模型的区别是传统的语言模型是预测整句话每个token的概率向量,而这里只预测挖掉的token的尬概率向量。不了解语言模型的同学建议先了解下最基础的语言模型的基本概念。)在这里插入图片描述
图三:句子mask

原文中还特意提到了一点,因为之后进行fine-tune时,输入的句子中,不再会有挖掉的token,这就导致pre-train和fine-tune的输入会“有差异性”,所以我们原文作者在对于mask掉的token,在实际操作中:

  • 80%的token用[Mask]替代
  • 10%的token保持不变
  • 10%的token用另外一个随机token进行替代(本人愚钝,不太明白这个操作的用意)

总体来说还是可以理解的。另外值得一提的是,因为每次预测的结果只有15%的token,这也导致了模型的参数迭代更新速度更慢,对于同样规模的网络,需要更长的时间进行训练才能收敛。

Next Sentence Prediction (NSP)

对于为什么要提出这个结构,原文是如下介绍,由于本人水平有限,便把原文粘一下:
Many important downstream tasks such as Question Answering (QA) and Natural Language Inference (NLI) are based on understanding the relationship between two sentences, which is not directly captured by language modeling. In order to train a model that understands sentence relationships, we pre-train for a binarized next sentence prediction task that can be trivially generated from any monolingual corpus。
个人理解是,对于很多下游任务,如QA等需要建立理解问答之间关系模型的任务,一般的语言模型很难去捕捉到这种关系。为了克服这个缺点,作者便想到了这个NSP法。
简单来说就是对于两个句子A和B,假设B是A的下一句话的话,那么在图一中C的位置,我们希望输出类似于表示“Yes”的向量,反之则输出表示“No”的向量(这里不是很好理解,估计得结合具体的业务场景和bert的相应使用才能比较好的理解)。另外

  • C对应的起始向量是[cls],上面也说了,cls表示这个句子的“概括” ,它的输出C类似于对输入的一个整体上的分类。
  • B,A通过上面提到的[sep]分割开来,这就是[sep]的作用。
  • 这里作者提到训练用的正负样本的比例希望都是50%左右。

其实这一部分相对前两部分来说更不太好理解,或者说让人不由地质疑,就只是这么简单的一个操作就真的能获得这么好的效果吗?原文似乎也明白读者的心思,专门解释了一下:

  • Despite its simplicity, we demonstrate in Section 5.1 that pre-training towards this task is very beneficial to both QA and NLI
  • The final model achieves 97%-98% accuracy on NSP.

敢兴趣的小伙伴可以更加深入地看一下原文。

中间的网络层–multi-layer bidirectional Transformer encoder

其实这篇文章用的主要网络层也很重要,但文中几乎是一笔带过,这里也不再赘述,文中描述的如下:
BERT’s model architecture is a multi-layer bidirectional Transformer encoder based on the original implementation described in Vaswani et al. (2017) and released in the tensor2tensor library.
作者还贴心的贴了一下示意图:
在这里插入图片描述
至于transformer,本身由来又是另一个故事了,它的存在对于NLP的深度学习也是意义十分重大的,希望不了解的读者可以自己去多了解一下,但是对于本文来说,不了解它的结构也不太影响对本文主要思想的理解。
这里值得一提的是,双向的transformer结合mask操作,算是把“双向”这个概念贯彻地很彻底,这是非常漂亮的。

写在最后

本文主要还是一个向导型的作用,顺便扣了一些笔者觉得容易不好理解的细节进行了自己的叙述,难免有谬误之处,望大家想深入学习的话,还是以原文为标准,最好再自己用主流框架实现一下就更好了。
这里本想把复现的苏建剑代码的思路简单说一下,但是觉得人家已经讲地很好了,自己也不再狗尾续貂,对于想用keras简单实现的同学们可以移步苏神的博客:
https://spaces.ac.cn/archives/6736

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值