https://xw.qq.com/cmsid/20210211A09EA700

BERT中文任务实战(文本分类、预测下一句)踩坑记录

https://blog.csdn.net/whuty1304/article/details/89457014?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&dist_request_id=1332048.307.16193595445855175&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

文笔很好的一篇BERT文章摘录

像之前说的,为每个NLP任务去深度定制泛化能力极差的复杂模型结构其实是非常不明智的,走偏了方向的。既然ELMo相比word2vec会有这么大的提升,这就说明预训练模型的潜力远不止为下游任务提供一份精准的词向量,所以我们可不可以直接预训练一个龙骨级的模型呢?如果它里面已经充分的描述了字符级、词级、句子级甚至句间关系的特征,那么在不同的NLP任务中,只需要去为任务定制一个非常轻量级的输出层(比如一个单层MLP)就好了,毕竟模型骨架都已经做好了嘛。而BERT正是做了这件事情,或者说,它真的把这件事情做成了,它作为一个general的龙骨级模型轻松的挑战了11个任务上的深度定制的模型。。。所以它怎么完成的呢?

深层双向的encoding
首先,它指出,对上下文相关的词向量的学习上,先前的预训练模型还不够!虽然在下游有监督任务中,encoding的方式已经是花里胡哨非常充分了,深度双向encoding基本成了许多复杂下游任务的标配(比如MRC, dialogue)。但是在预训练模型上,先前的最先进模型也只是基于传统的语言模型来做,而传统的语言模型是单向的(数学上已经定义了),即而且往往都很浅(想象一下LSTM堆三层就train不动了,就要上各种trick了),比如ELMo。另外,虽然ELMo有用双向RNN来做encoding,但是这两个方向的RNN其实是分开训练的,只是在最后在loss层做了个简单相加。这样就导致对于每个方向上的单词来说,在被encoding的时候始终是看不到它另一侧的单词的。而显然句子中有的单词的语义会同时依赖于它左右两侧的某些词,仅仅从单方向做encoding是不能描述清楚的。**那么为什么不像下游监督任务中那样做真正的双向encoding呢?**原因一想就很清楚了,毕竟传统的语言模型是以预测下一个词为训练目标的,然而如果做了双向encoding的话,那不就表示要预测的词已经看到了嘛╮( ̄▽ ̄””)╭这样的预测当然没有意义了。所以,在BERT中,提出了使用一种新的任务来训练监督任务中的那种真正可以双向encoding的模型,这个任务称为Masked Language Model (Masked LM)。

Masked LM

顾名思义,Masked LM就是说,我们不是像传统LM那样给定已经出现过的词,去预测下一个词,而是直接把整个句子的一部分词(随机选择)盖住(make it masked),这样模型不就可以放心的去做双向encoding了嘛,然后就可以放心的让模型去预测这些盖住的词是啥。这个任务其实最开始叫做cloze test(大概翻译成“完形填空测试”)。这样显然会导致一些小问题。这样虽然可以放心的双向encoding了,但是这样在encoding时把这些盖住的标记也给encoding进去了╮( ̄▽ ̄””)╭而这些mask标记在下游任务中是不存在的呀。。。那怎么办呢?对此,为了尽可能的把模型调教的忽略这些标记的影响,作者通过如下方式来告诉模型“这些是噪声是噪声!靠不住的!忽略它们吧!”,对于一个被盖住的单词:

有80%的概率用“[mask]”标记来替换

有10%的概率用随机采样的一个单词来替换

有10%的概率不做替换(虽然不做替换,但是还是要预测哈)

Encoder

在encoder的选择上,作者并没有用烂大街的bi-lstm,而是使用了可以做的更深、具有更好并行性的Transformer encoder来做。这样每个词位的词都可以无视方向和距离的直接把句子中的每个词都有机会encoding进来。另一方面我主观的感觉Transformer相比lstm更容易免受mask标记的影响,毕竟self-attention的过程完全可以把mask标记针对性的削弱匹配权重,但是lstm中的输入门是如何看待mask标记的那就不得而知了。等下,小夕在之前的文章中也说过了,直接用Transformer encoder显然不就丢失位置信息了嘛?难道作者这里也像Transformer原论文中那样搞了个让人怕怕的sin、cos函数编码位置?并木有,作者这里很简单粗暴的直接去训练了一个position embedding ╮( ̄▽ ̄””)╭ 这里就是说,比如我把句子截断到50的长度,那么我们就有50个位置嘛,所以就有50个表征位置的单词,即从位置0一直到位置49。。。然后给每个位置词一个随机初始化的词向量,再随他们训练去吧(很想说这特喵的也能work?太简单粗暴了吧。。。)。另外,position embedding和word embedding的结合方式上,BERT里选择了直接相加。最后,在深度方面,最终BERT完全版的encoder丧心病狂的叠加了24层的multi-head attention block(要知道对话里的SOTA模型DAM也才用了5层…)。。。而且每个block包含16抽头、1024隐单元╮( ̄▽ ̄””)╭此处打出标语:money is all you need (划掉)

学习句子与句对关系表示
像之前说的,在很多任务中,仅仅靠encoding是不足以完成任务的(这个只是学到了一堆token级的特征),还需要捕捉一些句子级的模式,来完成SLI、QA、dialogue等需要句子表示、句间交互与匹配的任务。对此,BERT又引入了另一个极其重要却又极其轻量级的任务,来试图把这种模式也学习到。

句子级负采样

还记得小夕在前面word2vec章节说过的,word2vec的一个精髓是引入了一个优雅的负采样任务来学习词向量(word-level representation)嘛。那么如果我们把这个负采样的过程给generalize到sentence-level呢?这便是BERT学习sentence-level representation的关键啦。BERT这里跟word2vec做法类似,不过构造的是一个句子级的分类任务。即首先给定的一个句子(相当于word2vec中给定context),它下一个句子即为正例(相当于word2vec中的正确词),随机采样一个句子作为负例(相当于word2vec中随机采样的词),然后在该sentence-level上来做二分类(即判断句子是当前句子的下一句还是噪声)。通过这个简单的句子级负采样任务,BERT就可以像word2vec学习词表示那样轻松学到句子表示啦。

句子级表示

等等,前面说了这么半天,还没有说句子该怎么表示呢。。。BERT这里并没有像下游监督任务中的普遍做法一样,在encoding的基础上再搞个全局池化之类的,它首先在每个sequence(对于句子对任务来说是两个拼起来的句子,对于其他任务来说是一个句子)前面加了一个特殊的token,记为[CLS],如图

ps:这里的[sep]是句子之间的分隔符,BERT同时支持学习句对的表示,这里是[SEP]便是为了区分句对的切割点。

然后让encoder对[CLS]进行深度encoding,深度encoding的最高隐层即为整个句子/句对的表示啦。这个做法乍一看有点费解,不过别忘了,Transformer是可以无视空间和距离的把全局信息encoding进每个位置的,而[CLS]作为句子/句对的表示是直接跟分类器的输出层连接的,因此其作为梯度反传路径上的“关卡”,当然会想办法学习到分类相关的上层特征啦。另外,为了让模型能够区分里面的每个词是属于“左句子”还是“右句子”,作者这里引入了“segment embedding”的概念来区分句子。对于句对来说,就用embedding A和embedding B来分别代表左句子和右句子;而对于句子来说,就只有embedding A啦。这个embedding A和B也是随模型训练出来的。

ps: 这做法跟position embedding一样感觉简单粗暴,实在很费解为什么BERT用在“quora question pairs”这种理论上需要网络保持对称的任务上依然能work,心情复杂

所以最终BERT每个token的表示由token原始的词向量token embedding、前文提到的position embedding和这里的segment embedding三部分相加而成,如图:

简洁到过分的下游任务接口
真正体现出BERT这个模型是龙骨级模型而不再是词向量的,就是其到各个下游任务的接口设计了,或者换个更洋气的词叫迁移策略。首先,既然句子和句子对的上层表示都得到了,那么当然对于文本分类任务和文本匹配任务(文本匹配其实也是一种文本分类任务,只不过输入是文本对)来说,只需要用得到的表示(即encoder在[CLS]词位的顶层输出)加上一层MLP就好了呀~既然文本都被深度双向encoding了,那么做序列标注任务就只需要加softmax输出层就好了呀,连CRF都不用了呀~让小夕更木有想到的是,在span抽取式任务如SQuAD上,把深度encoding和深度attention这俩大礼包省掉就算了,甚至都敢直接把输出层的pointer net给丢掉了?直接像DrQA那样傲娇的用两个线性分类器分别输出span的起点和终点?不多说了,已跪m(_ _)m最后来看一下实验效果

嗯,这很Google。此论文一出,小夕非常开心,因为很多之前的想法都不用去做实验验证了,因为已经被BERT摁死了(。 ́︿ ̀。)分类、标注和迁移任务都可以从头开始了,SQuAD的造楼计划也可以停了,感谢BERT没有跑生成任务,这给人带来了一点想象空间。嗯,手动微笑流泪。
————————————————
版权声明:本文为CSDN博主「夕小瑶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xixiaoyaoww/article/details/105460274

NLP预训练模型综述:从word2vec, ELMo到BERT

https://blog.csdn.net/xixiaoyaoww/article/details/105460274

BERT各个场景实例代码相关推荐

  1. vrml场景实例代码_高并发的中断下半部tasklet实例解析

    本文转自AliDataOps 最近为了解决一个技术问题,需要用到内核里中断下半部的tasklet机制,使用过程遇到了非常有趣的问题.在解决问题过程中,也逐步加深了对tasklet机制的理解.本文把这些 ...

  2. 此时不应有java_Java 锁的知识总结及实例代码

    这篇文章主要介绍了Java 锁的知识总结及实例代码,需要的朋友可以参考下 java中有哪些锁 在java中锁主要两类:内部锁synchronized和显示锁java.util.concurrent.l ...

  3. ViSP中识别AprilTag的C++实例代码与运行结果

    VISP中识别AprilTag的C++可运行代码与运行结果 Introduction ***具体解释见下一篇:***VISP中识别AprilTag的C++实例代码解释 ***具体帮助开发文档下载:** ...

  4. 计算1至1000间的合数c语言,输出1000以内的素数的算法(实例代码)

    输出1000以内的素数的算法(实例代码) 代码如下所示: 复制代码 代码如下: #include "stdafx.h" #include #include bool IsSushu ...

  5. 从零开始的AI·朴素贝叶斯?拿来吧你(附实例代码)

    从零开始的AI系列 从零开始的AI·机器学习の基本概念 从零开始的AI·吃透kNN算法,学完我悟了(附实例代码) 从零开始的AI·决策树原来这么好理解(附实例代码) 文章目录 从零开始的AI系列 前言 ...

  6. 从零开始的AI·吃透kNN算法,学完我悟了(附实例代码)

    从零开始的AI系列 从零开始的AI·机器学习の基本概念 从零开始的AI·决策树原来这么好理解(附实例代码) 从零开始的AI·朴素贝叶斯?拿来吧你(附实例代码) 文章目录 从零开始的AI系列 前言 一. ...

  7. Java 线程池详解及实例代码

    转载自  Java 线程池详解及实例代码 这篇文章主要介绍了Java 线程池的相关资料,并符实例代码,帮助大家学习参考,需要的朋友可以参考下 线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时 ...

  8. php图片上传为base64,php实现base64图片上传方式实例代码

    /** * base64图片上传 * @param $base64_img * @return array */ header("content-type:text/html;charset ...

  9. 一文数学数模-相关性分析(二)斯皮尔曼相关(spearman)相关性分析一文详解+python实例代码

    前言 相关性分析算是很多算法以及建模的基础知识之一了,十分经典.关于许多特征关联关系以及相关趋势都可以利用相关性分析计算表达.其中常见的相关性系数就有三种:person相关系数,spearman相关系 ...

最新文章

  1. YOLOv5实现自定义对象训练与OpenVINO部署全解析
  2. 最新功能 | 飞书推出“线上办公室”功能,助力企业开启无压力远程实时高效协作
  3. java scala 混合编程_java与scala混合编程打包(maven构建)
  4. iBatis学习第一天
  5. 321. Create Maximum Number 解题方法详解
  6. HttpHandler
  7. 组个最小数C语言pta,PTA|C语言:组个最小数
  8. java xml date_W3C XML 模式时间数据类型与java Date进行转换
  9. 超级计算机1月冷空气,五一冷空气蓄力,局部大降温10度!超级计算机:假期北方还要起沙...
  10. SQLSERVER中SP_WHO2和INPUTBUFFER的用法
  11. php数组插入mysql,php mysql:将一个php数组插入mysql
  12. DiskCatalogMaker for Mac(磁盘管理工具)
  13. 图片怎么去底色?怎么去图片背景为透明?
  14. LPC1768 PWM1输出PWM示例
  15. idea中用rest风格发送delete,put请求报405(tomcat8)
  16. 编译u-boot-mini2440
  17. Linux杂碎(杂且碎)
  18. 基于python实现(问卷星)Excel中图片超链接的批量下载
  19. 关于立创EDA的使用小技巧,和布线实心填充的正确使用
  20. 第52章 房地产投资面面观

热门文章

  1. css3循环播放一组动画,CSS3 无穷循环的动画演示
  2. php内容采集系统,第一步、采集规则
  3. 网络服务-VSFTP
  4. python去实现链表_python实现链表
  5. vue使用命令行构建完项目后_vue-cli 构建项目在IE中无法运行解决方式(build之后可运行)...
  6. autojs遍历当前页面所有控件_HTML5表单和表单控件的使用
  7. awk截取字符命令_Linux运维基础技能: 脚本编程与Linux命令
  8. C# 四舍五入round函数使用的代码
  9. es的分片和副本_Elasticsearch 集群分配多少分片合理
  10. android自定义差值器,如何创建自定义插值器以在android中应用翻译动画