ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

bert介绍和使用

2021-09-16 18:05:17  阅读:249  来源: 互联网

标签:bert torch ids 介绍 encoder 使用 input 句子


原文链接:https://blog.csdn.net/weixin_46425692/article/details/108890831?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163175571916780274115633%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163175571916780274115633&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-3-108890831.pc_search_result_control_group&utm_term=BERT&spm=1018.2226.3001.4187

1.前言

bert是非常出名的预训练模型,它在很少的数据也能有很好的表现。
在我们将要引出bert模型时,先来简单diss其他常见模型的缺点吧!!

  1. diss Word2vec
    在这里插入图片描述
    word2vec 不能解决一词多义,也不能解决OOV问题,生成的句子和文档向量也差强人意
  2. diss RNN
    在这里插入图片描述
    最出名的缺点是:不能并行,训练速度太慢了
  3. diss CNN
    在这里插入图片描述
    虽然可以并行,但太适用于分类任务了,用在其他NLP任务上,效果还不如RNN好
  4. diss seq2seq
    很适合做翻译任务,但encoder和decoder仍然用的RNN,不能并行,所以不能用太深层网络;并且语义向量也只能记住靠近它的一些单词
    在这里插入图片描述
  5. diss Attention
    仍然用的RNN结构,不能用多层,否则速度很慢
    在这里插入图片描述
    总结:要想改善模型,则不能使用
  • word2vec
  • RNN 及其变种
    所以出现了如下发展路径:
    在这里插入图片描述

2. 简单了解Transformer

这里只是简单描述什么是Transformer,至于详细的理解敬请期待 ^^
Transformer 本质仍然是 seq2seq 模型,只不过它叠加了多层的 encoder和decoder
在这里插入图片描述
其中每个encoder 和 decoder 结构如下,核心是 self-Attention 机制
在这里插入图片描述

3. Bert 模型简介

3.1 bert模型结构

在这里插入图片描述
根据这张图:bert训练的两个主要任务是

  • 预测被 [mask] 的单词, 相当于完形填空
  • 预测输入的两个句子是否相邻

这两个任务就对应了两个损失,因此 bert 是最小化这两个损失函数的和来训练模型的。
在这里插入图片描述

3.2 bert的输入

在这里插入图片描述
bert将输入句子转化为词向量,是经过了3 个Embedding 的加和, 即
input_embed = Token_embed + Sentence_embed + Position_embed.
源码是:
在这里插入图片描述
调用模型的话,我们只需要输入:

1) input_ids:一个形状为[batch_size, sequence_length]的 torch.LongTensor,在词汇表中包含单词的token索引, 注意 在句子首尾分别加了 [cls] 和 [sep] 的 索引

2) segment_ids :形状[batch_size, sequence_length]的可选 torch.LongTensor,在0, 1中选择token类型索引。类型0对应于句子A,类型1对应于句子B。如 [0,0,0,0,0,1,1,1,1,1], 0代表第一个句子A, 1代表第二个句子B,默认全为0

3) input_mask:一个可选的 torch.LongTensor,形状为[batch_size, sequence_length],索引在0, 1中选择。0 是 padding 的位置,1是没有padding的字

用其他博客的图:
其中input_ids = seq_ids
segment_ids = token_type_ids
input_mask = mask
在这里插入图片描述

3.3 bert的下游任务

在这里插入图片描述

  • 加一个线性层就可以分类了

3.4 使用bert提取Embedding向量

可以看到每个Encoder 的隐层输出我们都可以当成是Ebedding, 但哪一层的Embedding更能代表上下文信息呢??在这里插入图片描述
第一层效果通常不太好,最后4层隐层输出的拼接效果是最好的
在这里插入图片描述

4. Bert学习路径

推荐学习路径:
在这里插入图片描述

5.体验bert操作

在这里插入图片描述

5.1 准备下载模型

我们需要这3个模型:
在这里插入图片描述
vocab.txt 分字表:
在这里插入图片描述
贴心的我,已经帮大家整理好了,这里用到是中文bert模型。
在这里插入图片描述
链接:https://pan.baidu.com/s/1phZVYv2G-GZXnkWzAhtdeQ
提取码:gjd1
复制这段内容后打开百度网盘手机App,操作更方便哦
下载完之后:再 pip install pytorch_pretrained_bert

5.2 代码

import torch
from pytorch_pretrained_bert import BertTokenizer, BertModel, BertConfig, BertForMaskedLM

import torch.nn as nn

  • 1
  • 2
  • 3
  • 4
# 设置bert模型路径
import os
bert_path = r"D:\Bert\bert-base-chinese"
bert_config_path = os.path.join(bert_path, r"bert_config.json")
bert_vocab_path = os.path.join(bert_path, r"vocab.txt")
bert_model_path = os.path.join(bert_path, r"pytorch_model.bin")

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
# 加载模型配置
bert_config = BertConfig.from_json_file(bert_config_path)

# 加载中文词库
bert_vocab = BertTokenizer(vocab_file= bert_vocab_path)

# 加载模型
bert_model = BertModel.from_pretrained(bert_path) # 这个函数的输入要求a path or url to a pretrained model archive containing:
#. bert_config.json a configuration file for the model
#. pytorch_model.bin a PyTorch dump of a BertForPreTraining instance

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里插入图片描述

#  Tokenize input
text = "乌兹别克斯坦议会立法院主席获连任"
# 利用bert自带的分字工具分字
tokenized_text = bert_vocab.tokenize(text)   # list
#print("type of tokenized:", type(tokenized_text))

# 在句子首尾分别加上[CLS],[SEP]. [CLS] 只有一个,而[SEP]在每句话的末尾,当输入两个句子时,就有两个[SEP]
tokenized_text = ["[CLS]"] + tokenized_text + ["[SEP]"]

#将 字 转化为词库中的索引
input_ids = bert_vocab.convert_tokens_to_ids(tokenized_text) # list, len:18
#print(“type of input_ids :”, type(input_ids), len(input_ids))
## input_ids.shape : [batch, sequence_lenth]

# Define sentence A and B indices ,由于输入只有一个句子,那么就全定义为0
segment_ids = [0] * len(input_ids)

# input_mask,由于没有填充padding, 就全定义为1
input_mask = [1] * len(input_ids)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
# Bert 的输入 只支持 长整型,因此必须转化为 torch.long tensor 形式
input_ids = torch.LongTensor(input_ids)
print("input_ids: ", input_ids.size())  # input_ids:  torch.Size([18])

segment_ids = torch.tensor([segment_ids], dtype = torch.long)

input_mask = torch.tensor([input_mask], dtype = torch.long)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
# bert 模型调用
all_encoder_layer, pooled_output = bert_model(input_ids, input_mask,segment_ids)
## all_encoder_layers: 一个包含 12 个 transfomer encoder 层输出的列表list
### 每一层的输出大小是: [batch, seq_lenth, hiddern_size], 对于bert-base 是12, bert-large是24
print("all_encoder_layer:\n ", type(all_encoder_layer), len(all_encoder_layer), all_encoder_layer[0].size())

## pooled_output: 最后一个 transfomer encoder ,且输入句子的第一个字[CLS]位置上的隐层输出
### 大小:[batch, hidden_size]
### 这个输出就可以看做是输入句子的语义信息了
print(“pooled_output: \n”, type(pooled_output), len(pooled_output), pooled_output.size())

######################################
all_encoder_layer:
<class ‘list’> 12 torch.Size([1, 18, 768])
pooled_output:
<class ‘torch.Tensor’> 1 torch.Size([1, 768])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  1. 如果我们想要得到输入句子的 embedding 表示,那么我们只要 all_encoder_layer 的最后几层向量

  2. 如果我们想要做分类,那么只要Pooled_output 向量,因为它代表了整个输入句子的语义信息

考虑padding时,代码有什么变化??

为什么要padding呢,因为我们训练时候是用batch_size样本的,但是每个样本即句子的长度都不一致,因此我们必须设置一个最大句子的长度,当其他句子小于此长度时就padding,大于此长度就截断

# padding
# 设置最长句子长度
max_seq_lenth = 300

new_text = “乌兹别克斯坦议会立法院主席获连任”
tokenized_text = bert_vocab.tokenize(new_text) # list
tokenized_text = ["[CLS]"] + tokenized_text + ["[SEP]"] # list
input_ids = bert_vocab.convert_tokens_to_ids(tokenized_text) # list
input_mask = [1] * len(input_ids)

# define padding, 填充的地方置为0,未填充的地方是 1
padding = [0] * (max_seq_lenth - len(input_ids))

input_ids += padding # 300
input_mask += padding

# input_ids 后面填充部分都要置0

# 这里只有一个输入句子,因此可以不用segment_ids,因为默认就有全0的segment_ids

#转化为 torch.LongTensor 形式
input_ids = torch.tensor([input_ids], dtype = torch.long) #300
input_mask = torch.tensor([input_mask], dtype = torch.long) # 300
print("padding intput_ids: ", input_ids.size()) # 300

## bert_model 的测试模式,不用梯度更新
bert_model.eval()
with torch.no_grad():
all_encoder_layer, pooled_output = bert_model(input_ids, attention_mask= input_mask)
print("padding all_encoder_layers: ", all_encoder_layer[0].shape)
print("padding pooled_output : ", pooled_output.size())

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

在这里插入图片描述
在这里插入图片描述

标签:bert,torch,ids,介绍,encoder,使用,input,句子
来源: https://blog.csdn.net/qq_43703185/article/details/120334398

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有