(九)再谈embedding——bert详解(实战)下

    前面两篇分别梳理了下BERT的原理BERT的训练,接着前面的内容,梳理下BERT是如何在下游任务上运用的。

原理就是上面这个图了。四种任务,实际上从他的训练模型的代码和我之前的NER的代码就已经对(b)(d)两个部分进行了梳理。那接下来我首先梳理下BERT是如何在SQUAD2.0阅读理解这个任务上使用的。

Part2:SQUAD项目实战

关于阅读理解部分,我会专门做个专题梳理,这里只针对bert进行讲解。

一.数据下载与模型准备

        这里bert开源项目上就有,自行下载,然后根据说明配置一下目录就行。注:模型我下载的是BERT-Large, Uncased,readme以及说的很清楚了,cased的版本是考虑了字母大小写的,适合NER任务。

        模型参数:

二.数据处理

        之前看过QA-net的代码,SQUAD部分的数据处理还比较熟悉,这里还是简单的说明,拿SQUAD2.0训练数据为例:

    训练集中包含了442段话题,然后每个话题有一个title,对于每个话题下都有几十段的paragraph,每个paragraph是一个json字典文件,包含了context和至少一组问答对:

注:

这里的text就是答案,answer_start:是指答案在文章开始的地方,根据这两个算出answer_start,answer_end,然后在到文章中去验证是不是有这个答案,这是数据清洗的部分,这里就大致过一下。

最后将数据处理成逐条的形式,每条数据内容如下:

注意:1.SQUAD1.0和SQUAD2.0任务的区别就是后者的数据更多,并且加入了无法回答的问题数据。

            2.代码中的tokenization是一个字符处理和数据清洗的工具,这里补充说明下,主要有BasicTokenizer和WordpieceTokenizer两个类,先使用前者,主要是分离标点,转换大小写,和判断中文字符;后者的作用是对部分字符切片,避免OOV过多的问题,这样做的好处在这里举两个例子:

            Question: What year was John Smith born?

            Context: The leader was John Smith (1895-1943).

             Answer: 1895

像这种问题(1895-1943).是连接在一起的,没有空格,需要把这个部分分开,因此要用到WordpieceTokenizer部分。

三.代码讲解

        代码部分的讲解我选择pytorch的版本,其实都一样,我主要比较了下两个版本的实验结果是不是一样的,因为自己在做调试的时候感觉pytorch的版本梳理起来稍微方便点,后续我还会提到GPU的使用问题。

         关于bert的部分我就不再说明,我们从输出的部分开始看,这里要明确建模任务,我们显然是要找出答案在原文中的位置,也就是start和end两个类别在原文中每个位置上的概率。搞清楚了这个,我们来看bert的最后一层输出就是[bz,max_length,dim],对于不同任务我们需要接不同的全连接层,对于这个任务只需要接一个这样的线性层就行:

当然如果你想在“更厉害”的网络上嵌入bert做微调也是可以的,后续我会找个例子实现一下。

接下来主要说一下GPU的使用问题。

在这个问题上,假如你的手头GPU的计算资源不够,你可能会感觉寸步难行,动不动就报OFM的错误,我大概计算了一下,如果要用32batch size任何trick不加,你至少需要4块TITAN吧,也就是40G的显存,必将large model就是1G+,再乘上batch,大概就需要这么大,那么怎么办?官方代码给了解决方案,我们来看一下可行性:

分布式训练也就是第三点我就不说了,主要是还没用过,不是很会,剩余的四个我们来看一下:

1.Gradient Accumulation:所谓梯度累计,就是假如你设置的32batch size,太大了,跑不通,那么就将batch size除以Gradient Accumulation系数,如果是2,那么batch size就变成了16,但是在反向传播的时候,会将mean_loss也除以2,然后进行累计,直到2次后在进行梯度清零,就相当于将32size分成两个16,但是是进行的连续的反向转播,如果看不懂就看看代码:

这样的做法并不能提速,只是为了跑32batch_size的数据分两次,然后累积清空梯度,

2.Multi-GPU

这里主要就是model = torch.nn.DataParallel(model).cuda()官方代码里不是这么写的,上来就检测你所有的显卡,然后把空闲的都用了,这里建议自己设定卡的id比较好,把代码稍稍修改一下,原理就是首先将模型加载到主 GPU 上,然后再将模型复制到各个指定的从 GPU 中,然后将输入数据按 batch 维度进行划分,具体来说就是每个 GPU 分配到的数据 batch 数量是总输入数据的 batch 除以指定 GPU 个数。每个 GPU 将针对各自的输入数据独立进行 forward 计算,最后将各个 GPU 的 loss 进行求和,再用反向传播更新单个 GPU 上的模型参数,再将更新后的模型参数复制到剩余指定的 GPU 中,这样就完成了一次迭代计算。

3.Optimize on

关于Adam优化,这里有份教程讲的很清楚,这里大致是说Adam优化需要优化的有初始化参数向量、一阶矩向量、二阶矩向量:

这样一来,第一块GPU就要存储3倍模型的大小,这样就限制了batch_size的大小,所以我们将这部分参数存在CPU上:

接下来在训练的过程中:set_optimizer_params_grad和copy_optimizer_params_to_model是两个过程,当要开始训练时set_optimizer_params_grad将需要训练的参数从模型中取出param_opti.grad.data.copy_(param_model.grad.data),然后optimizer.step(),完成后再将新的参数送回模型param_model.data.copy_(param_opti.data)。

4.16-bits training

这部分代码也是基于CPU优化上完成的,训练过程中,每一层的权重存储成FP32数据类型(Mater-Weights),每次训练时都会将FP32的权重降精度至FP16( a master copy),前向推理和后向梯度都使用FP16进行计算,更新时将FP16的梯度累加到FP32的Mater-Weight上,样例图如下,

混合精度训练可以解决权重更新量很小的问题,但无法解决梯度本身很小的问题。在一些网络中(比如SSD),梯度大部分都在FP16的表示范围之外,因此需要将梯度平移到FP16的表示范围内 。所以用到了loss_scale参数,一种简单高效的方法是直接在前向时就将loss乘以scale,这样在后向传导时所有的梯度都会被乘以相同的scale。权重更新时需要将移位后的梯度除以scale后,再更新到权重上。

上面就是我对pytorch代码的在squad任务上的解读,pytorch版本的代码只适合1.0任务,2.0任务我后续会进行修改,

上面是我的参数设置,下面来看下实验结果:

这个结果比官方给的差一点点,毕竟不是最佳参数,在GPU的使用上也有限制。再贴这个结果的时候实验大概跑了三天吧,现在pytorch版本又出了在fp16中自动调节loss_scale的代码,下面是新的实验结果,新的代码里面用了APEX的包,训练速度有很大的提升,缩短了好几倍,结果仍旧差不多:

(上面两个实验都是在一块泰坦上搞定的)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,290评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,399评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,021评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,034评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,412评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,651评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,902评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,605评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,339评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,586评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,076评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,400评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,060评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,851评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,685评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,595评论 2 270

推荐阅读更多精彩内容

  • 本文上两篇系列 NLP的巨人肩膀(上) NLP的巨人肩膀(中) 4.6 Bidirectional Encoder...
    weizier阅读 6,210评论 1 22
  • (第一部分 机器学习基础)第01章 机器学习概览第02章 一个完整的机器学习项目(上)第02章 一个完整的机器学习...
    SeanCheney阅读 7,418评论 2 14
  • 春天的脚步,悄然无声、沉着坚定,充满诗情画意地来到北方、来到渭北高原、来到山城铜川。随着太阳光热度的不断增强,春的...
    李月芳阅读 379评论 0 1
  • 在css中,经常会出现的问题就是你书写的属性值得不到你想要的效果,一方面是由于优先级的原因,在其他标签中已经把你想...
    海娩阅读 523评论 0 0
  • 一转眼,3月就过去了,感觉就是一瞬间。以往年,回想过去的日子,我的重要节点就是每周的业绩和收钱回款的推进动作。现在...
    一直成长的苹果树阅读 215评论 0 1