【深度学习】预训练语言模型-BERT

news2024/9/20 19:57:26

1.BERT简介

        BERT是一种预训练语言模型(pre-trained language model, PLM),其全称是Bidirectional Encoder Representations from Transformers。下面从语言模型和预训练开始展开对预训练语言模型BERT的介绍。

1-1 语言模型

        语言模型 :对于任意的词序列,它能够计算出这个序列是一句话的概率。比如词序列A:“知乎|的|文章|真|水|啊”,这个明显是一句话,一个好的语言模型也会给出很高的概率,再看词序列B:“知乎|的|睡觉|苹果|好快”,这明显不是一句话,如果语言模型训练的好,那么序列B的概率就很小很小。

        下面给出较为正式的定义。假设我们要为中文创建一个语言模型,V 表示词典, V =  { 猫,狗,机器,学习,语言,模型,…}, w_{i}\in V。语言模型就是这样一个模型:给定词典 V,能够计算出任意单词序列(比如:单词序列[w_{1}w_{5}w_{2}...]、[​​​​​​​w_{8}w_{10}w_{n}])是一句话的概率。probability = p(w_{1},w_{2},w_{3}...) 

        从文本生成角度来看,我们也可以给出如下的语言模型定义:给定一个短语(一个词组或一句话),语言模型可以生成(预测)接下来的一个词。

1-2 预训练模型

        从字面上看,预训练模型(pre-training model)是先通过一批语料进行模型训练,然后在这个初步训练好的模型基础上,再继续训练或者另作他用。预训练模型的训练和使用分别对应两个阶段:预训练阶段(pre-training)和 微调(fune-tuning)阶段

        预训练阶段一般会在超大规模的语料上,采用无监督(unsupervised)或者弱监督(weak-supervised)的方式训练模型,期望模型能够获得语言相关的知识,比如句法,语法知识等等。经过超大规模语料的”洗礼”,预训练模型往往会是一个Super模型,一方面体现在它具备足够多的语言知识,一方面是因为它的参数规模很大。

        微调阶段是利用预训练好的模型,去定制化地训练某些任务,使得预训练模型”更懂”这个任务。例如,利用预训练好的模型继续训练文本分类任务,将会获得比较好的一个分类结果,直观地想,预训练模型已经懂得了语言的知识,在这些知识基础上去学习文本分类任务将会事半功倍。利用预训练模型去微调的一些任务(例如前述文本分类)被称为下游任务(down-stream)

1-3 BERT的原理

        从BERT的全称,Bidirectional Encoder Representation from Transformer(来自Transformer的双向编码器表征),可以看出BERT是基于Transformer模型的,只是其中的编码器。输入一个句子,Transformer的编码器会输出句子中每个单词的向量表示。而双向则是由于Transformer编码器是双向的。它的输入是完整的句子,在指定某个Token时,BERT已经读入了它两个方向上的所有单词。举个例来理解BERT是如何从Transformer中得到双向编码表示的。

        假设我们有一个句子A:He got bit by Python,现在我们把这个句子输入Transformer并得到了每个单词的上下文表示(嵌入表示)作为输出。Transformer的编码器通过多头注意力机制理解每个单词的上下文,然后输出每个单词的嵌入向量。如下图所示,我们输入一个句子到Transformer的编码器,它输出句子中每个单词的上下文表示。下图中R_{He}代表单词He的向量表示,每个单词向量表示的大小应当于每个编码器隐藏层的大小。假设编码器层大小为768,那么单词的向量表示大小也就是768。

1-4 BERT的参数

        BERT初期有两个版本,分为base版和large版本。base版一共有110M参数,large版有340M的参数,两个版本的BERT的参数量都是上亿的。

Bert_{base}:L=12,H=768,A=12,TotalParameters=110M

Bert_{large}:L=24,H=1024,A=16,TotalParameters=340M

        L:Transformer blocks 层数;H:hidden size ;A:the number of self-attention heads

 2.BERT预训练任务

         Bert是Transformer的encoder部分,使用大量的未标记文本数据进行预训练,从而学习并掌握某种语言的表达形式。结构上使用了基于多头注意力机制的transformer,训练中采取两种不同的训练方式:(Masked Language Model)隐蔽语言模型(Next Sentence Prediction)下一结构预测。其中双向主要体现在bert的训练任务一中:隐蔽语言模型。

2-1 Masked Language Model

        Masked LM 可以形象地称为完形填空问题,随机掩盖掉每一个句子中15%的词,用其上下文来去判断被盖住的词原本应该是什么。随机Mask语料中15%的Token,然后将masked token位置的最终隐层向量送入softmax,来预测masked token。 举例来说,有这样一个未标注句子 my dog is hairy ,我们可能随机选择了hairy进行遮掩,就变成 my dog is [mask] ,训练模型去预测 [mask] 位置的词,使预测出 hairy的可能性最大,在这个过程中就将上下文的语义信息学习并体现到模型参数中。

        而在下游的NLP任务fine-tuning阶段中不存被Mask的词,为了和后续任务保持一致,作者按一定比例在需要预测的词的位置上输入了原词或输入了某个随机的词。[MASK]通过attention均结合了左右上下文的信息,这体现了双向。以下是MASK策略:

  1. 有80%的概率用“[mask]”标记来替换——my dog is [MASK]
  2. 有10%的概率用随机采样的一个单词来替换——my dog is apple
  3. 有10%的概率不做替换——my dog is hairy

        在任何一个词都有可能是被替换掉的条件下,强迫模型在编码当前时刻不能太依赖于当前的词,而是要考虑它的上下文,甚至根据上下文进行纠错。所以训练预料中有必须正确的信息(10%)、未知的信息(80% MASK,使模型具有预测能力)、错误的信息(加入噪声10%,使模型具有纠错能力),模型才能获取全局全量的信息。

2-2 Next sentence prediction

       很多下游任务(QA和natural language inference)都是基于两个句子之间关系的理解,基于此项任务,为了增强模型对句子之间关系的理解能力。 所以预测句子关系,判断两个句子之间是否是有关联,在训练过程中,BERT会抽全50%有关联的句子(这里的句子是指有联系的Token序列),百分之50的概率随机抽选两无关的句子,然后让BERT模型判断这两个句子是否相关。其输入形式是,开头是一个特殊符号[CLS],然后两个句子之间用[SEP]隔断:

Input = [CLS] the man went to [MASK] store [SEP]he bought a gallon [MASK] milk [SEP]
Label = IsNext
Input = [CLS] the man [MASK] to the store [SEP]penguin [MASK] are flight ##less birds[SEP]
Label = NotNext

3.BERT的输入和输出

3-1 BERT的输入

        在把数据喂给BERT之前,通过下面三个嵌入层将输入转换为嵌入向量:词嵌入(Token embedding);段嵌入(Segment embedding);位置嵌入(Position embedding)。

        以下面句子为例,展现三种嵌入向量的表示。

Sentence A: Paris is a beautiful city.
Sentence B: I love Paris.

1.Token Embedding(词嵌入)

        表示的是词向量,既可以是原始词向量(源码中是token在词汇表中对应的索引),也可以是经过word2vector或者是glove等模型处理后的静态向量。在实际代码实现中,输入文本在送入token embeddings 层之前要先进行tokenization处理。此外,两个特殊的token会被插入到tokenization的结果的开头 ([CLS])和结尾 ([SEP])

        第一步:使用使用WordPiece分词器分词。

#第一步:使用WordPiece分词器分词
tokens = [Paris, is, a, beautiful, city, I, love, Paris]

        第二步:在一个句子前面,添加[CLS]标记。

tokens = [ [CLS], Paris, is, a, beautiful, city, I, love, Paris]

        第三步:在每个句子的结尾,添加[SEP]标记。

tokens = [ [CLS], Paris, is, a, beautiful, city, [SEP], I, love, Paris, [SEP]]

        特别说明:

                [CLS]标记只加在第一个句子前面,而[SEP]标记加到每个句子末尾。

      [CLS]标记用于分类任务,而[SEP]标记用于表示每个句子的结尾。

        在把所有的标记喂给BERT之前,我们使用一个叫作标记嵌入的嵌入层转换这些标记为嵌入向量。这些嵌入向量的值会在训练过程中学习。经过学习,得到了每个token的词嵌入向量。

2.Segment Embedding (段嵌入)

        段嵌入用来区别两种句子。因为Bert中存在着两个任务,一个是隐藏语言模型,另一个是预测句子关系,所以在输入时需要区分两个句子。 如果输入数据由两个句子拼接而成,如果词语是属于第一个句子A,那么该标记会映射到嵌入E_A;反之属于句子 B,则映射到嵌入E_B

      如果输入仅仅只有一个句子,那么它的segment embedding只会映射到E_A 。 

3.Position Embedding(位置编码) 

        学习出来的embedding向量。与Transformer不同,Transformer中是预先设定好的值。

4.最终表示

        如下图所示,首先我们将给定的输入序列分词为标记列表,然后喂给标记嵌入层,片段嵌入层和位置嵌入层,得到对应的嵌入表示。然后,累加所有的嵌入表示作为BERT的输入表示。

3-2 BERT的输出

       bert模型的输出可以包括四个:

       1. last_hidden_state

        torch.FloatTensor类型的,最后一个隐藏层的序列的输出。大小是(batch_size, sequence_length, hidden_size) sequence_length是我们截取的句子的长度,hidden_size是768。
        2.pooler_output

        torch.FloatTensor类型的,[CLS]的这个token的输出,输出的大小是(batch_size, hidden_size)。
        3.hidden_states

        tuple(torch.FloatTensor)这是输出的一个可选项,如果输出,需要指定config.output_hidden_states=True,它也是一个元组,它的第一个元素是embedding,其余元素是各层的输出,每个元素的形状是(batch_size, sequence_length, hidden_size)。
        4.attentions

        这也是输出的一个可选项,如果输出,需要指定config.output_attentions=True,它也是一个元组,它的元素是每一层的注意力权重,用于计算self-attention heads的加权平均值。

4.BERT代码 

        Transformers(以前称为pytorch-transformers和pytorch-pretrained-bert)提供用于自然语言理解(NLU)和自然语言生成(NLG)的最先进的模型(BERT,GPT-2,RoBERTa,XLM,DistilBert,XLNet,CTRL ...) ,拥有超过32种预训练模型,支持100多种语言,并且在TensorFlow 2.0和PyTorch之间具有深厚的互操作性。我们借助Transformers来实现bert的调用。

import transformers
#实例化bert模型
bert_model = transformers.BertModel.from_pretrained(
    pretrained_model_name_or_path = '/ssd/Spider/Baidu_NER/Pre_Model/chinese_roberta_wwm_large_ext/',
    output_hidden_states=True,
    output_attentions=True)
#bert需要的三种输入形式
def encoder(vocab_path,sentence):
    #将text_list embedding成bert模型可用的输入形式
    tokenizer = transformers.BertTokenizer.from_pretrained(vocab_path)
    tokenizer = tokenizer(
        sentence,
        return_tensors='pt'  # 返回的类型为pytorch tensor
        )
    input_ids = tokenizer['input_ids']
    token_type_ids = tokenizer['token_type_ids']
    attention_mask = tokenizer['attention_mask']
    return input_ids,token_type_ids,attention_mask
sentence = "中华人民共和国万岁"
#生成三种bert需要的输入形式
input_ids,token_type_ids,attention_mask = encoder(
    vocab_path="/ssd/Spider/Baidu_NER/Pre_Model/chinese_roberta_wwm_large_ext/vocab.txt",
    sentence = sentence)
#调用bert模型
sentence_outputs = bert_model(input_ids,token_type_ids,attention_mask)

          如下图所示:

        input_ids表示的是分词后在token中添加了[CLS]和[SEP]标记之后的id表示。token_types_ids则表示的是Segment Embeddings ,如果输入数据由两个句子拼接而成,如果词语是属于第一个句子,则Segment Embeddings 对应的位置是0,如果属于第二个句子,则segment Embeddings对应的位置为1。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/391738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iOS(一):Swift纯代码模式iOS开发入门教程

Swift纯代码模式iOS开发入门教程项目初始化(修改为纯代码项目)安装第三方库(以SnapKit库为例)桥接OC库(QMUIKit)封装视图并进行导航跳转示例:使用 TangramKit 第三方UI布局库应用国际化添加 R.s…

NICEGUI---ROS开发之中常用的GUI工具

0. 简介 对于ROS来说,如果不具备一定知识的人员来使用这些我们写的算法,如果说没有交互,这会让用户使用困难,所以我们需要使用GUI来完成友善的数据交互,传统的GUI方法一般有PYQT这类GUI方法,但是这类GUI工…

激光炸弹(前缀和)

地图上有 N 个目标,用整数 Xi,Yi 表示目标在地图上的位置,每个目标都有一个价值 Wi。注意:不同目标可能在同一位置。现在有一种新型的激光炸弹,可以摧毁一个包含 RR 个位置的正方形内的所有目标。激光炸弹的投放是通过卫星定位的&…

顺序表以及链表的应用及区别(包含OJ讲解)

前面我已经发过怎么实现链表以及顺序表,今天大概的总结一下。 顺序表: 1.能够随时的存取,比较方便。 2.插入删除时,需要挪动数据,比较麻烦,因为是连续存储。 3.存储密度相对于链表来说是比较高的&#…

C++类的组合

C类的组合什么是类的组合初始化参数列表使用类的组合案例分析组合构造和析构顺序问题this指针基本用法和作用什么是类的组合 类的组合就是以另一个对象为数据成员,这种情况称为类的组合 1.优先使用类的组合,而不是继承 2.组合表达式的含义 一部分关系 初…

用户登录请求100w/每天, JVM如何调优

用户登录请求100w/每天, JVM如何调优 大概可以分为以下8个步骤。 Step1:新系统上线如何规划容量? 1.套路总结 任何新的业务系统在上线以前都需要去估算服务器配置和JVM的内存参数,这个容量与资源规划并不仅仅是系统架构师的随意估算的&am…

springboot启动过程加载数据笔记(springboot3)

SpringApplication AbstractApplicationContext PostProcessorRegistrationDelegate ConfigurationClassPostProcessor ConfigurationClassParser 一堆循环和调用 ComponentScanAnnotationParser扫描 processConfigurationClass.doProcessConfigurationClass(configClass, so…

网络编程(二)

6. TCP 三次握手四次挥手 HTTP 协议是 Hype Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器(sever)传输超文本到客户端(本地浏览器…

小众但意外觉得蛮好用的剪辑软件!纯良心分享

爱剪辑 有开屏广告,一共3个界面:首页、剪同款、我的。 剪辑、配乐、字幕、滤镜、加速、贴纸、配音等主流功能都有。 特色功能有剪裁视频、倒放视频、视频旋转、视频转换GIF、转场、提取音频、画中画等。 还可以拼接视频,不过不支持FLV等小众文…

人员摔倒识别预警系统 人员跌倒检测算法 yolov7

人员摔倒识别预警系统 人员跌倒检测算法基于yolov7网络模型计算机识别技术,人员摔倒识别预警系统 人员跌倒检测算法对画面中人员摔倒进行实时检测识别抓拍告警。YOLOv7 的策略是使用组卷积来扩展计算块的通道和基数。研究者将对计算层的所有计算块应用相同的组参数和…

buuctf-pwn write-ups (11)

文章目录buu083-x_ctf_b0verfl0wbuu084-picoctf_2018_leak_mebuu085-inndy_echobuu086-hitcontraining_unlinkbuu087-ciscn_2019_final_3buu088-axb_2019_fmt64buu089-wustctf2020_name_your_catbuu090-pwnme1buu091-axb_2019_brop64buu092-[极客大挑战 2019]Not Badbuu083-x_c…

JAVA开发运维(nginx工作原理)

nginx源码目录结构: . ├── auto 自动检测系统环境以及编译相关的脚本 │ ├── cc 关于编译器相关的编译选项的检测脚本 │ ├── lib nginx编译所需要的一些库的检测脚本 │ ├── os 与平台相关的一些系统参数…

2023-03-06 debian11 最小安装记录

1.镜像准备,根据个人需求下载debian 版本Debian -- 获取 Debian2.上传到VSAN 内容库我这边是在vm里面安装的,就直接上传到内容库备用(根据个人需求存放)3.分配虚拟主机配置根据个人需要配置4.开始最小安装1.在界面中选择Install&a…

Packet Tracer--配置帧中继

Packet Tracer--配置帧中继 拓扑图: 设备参数: 设备 接口 DLCI R1 S0/2 102,103 R2 S0/2 201 R3 S0/2 301 R1---R2 Se1:102-----Se2:201 R1---R3 Se1:103-----Se3:301 IP参数 设备 接口 IP地址…

CFNet: Cascade Fusion Network for Dense Prediction

论文名称:CFNet: Cascade Fusion Network for Dense Prediction 论文下载:https://arxiv.org/pdf/2302.06052.pdf 论文代码:GitHub - zhanggang001/CFNet: CFNet: Cascade Fusion Network for Dense Prediction 摘要: 在密集预…

十四届蓝桥选拔赛Scratch-2023.02.12 试题解析

十四届蓝桥选拔赛Scratch-2023.02.12 试题解析 单选题: 1. 运行以下程序,小猫和小企鹅谁能到达舞台右侧边缘? ( B ) *选择题严禁使用程序验证,选择题不答和答错不扣分 A. 小企鹅 B. 小猫 C. 都能到达 D. 都不能到达 2. 运行以下程序(小象仅有两个造型),小象的造型是…

最简单的SpringBoot+MyBatis多数据源实现

最简单的SpringBootMyBatis多数据源实现1.数据库准备2.环境准备3.代码部分3.1多数据源配置2.测试随着应用用户数量的增加,相应的并发请求的数量也会跟着不断增加,慢慢地,单个数据库已经没有办法满足频繁的数据库操作请求了,在某些…

【JeecgBoot-Vue3】第4节 目录结构与常用组件介绍

一、项目的目录结构讲解 1. src/api/ 存放API相关信息 src/api/存放的是调用后台api接口相关信息src/api/commonapi.tsapi接口信息2. src/assets 静态资源 src/assets静态资源 src/assets/icons 图标 src/assets/images 图片 src/assets/less 样式src/assets/svgsvg图像3. s…

函数编程:强大的 Stream API

函数编程:强大的 Stream API 每博一文案 只要有人的地方,世界就不会是冰冷的,我们可以平凡,但绝对不可以平庸。—————— 《平凡的世界》人活着,就得随时准备经受磨难。他已经看过一些书,知道不论是普通…

Python API教程:API入门

什么是API? 一个API,或被称为应用程序接口,是一个服务器为你提供一个接收或发送数据的代码。API通常用来接收数据。 本文就集中焦点在此话题中。 当我们想从一个API中接收数据,我们需要开始请求。请求可以包含整个Web。例如&am…