BERT
的一些常见疑惑Pre-training、Deep、Bidirectional、Transformer、Language Understanding
Bert
是什么?首先要明白什么是预训练模型【这个我后面再更~】。在这个基础上,我们来看 Bert 模型。
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
。Bidirectional Encoder Representation from Transformers
,其中文译名应该就是“基于transformers 的双向(深度)编码表示”)Bert is a method of pretraining language representations
BERT
干什么?You can either use these models to extract high quality language features from your text data, or you can fine-tune these models on a specific task (classification, entity recognition, question answering, etc.) with your own data to produce state of the art predictions.
主要可以用于两种用途,也就是:
Embedding
有什么用?First, these embeddings are useful for keyword/search expansion, semantic search and information retrieval.
【即使没有关键字重叠,还是可以找出比较相似的句子】
Second, and perhaps more importantly, these vectors are used as high-quality feature inputs to downstream models.
这两者都是nlp发展上的一个缩影,只不过word2vec已经逐渐被遗忘了,而bert尚活于世。
个人理解是:BERT
是 word2vec
的高级进化版,进化的后果【用进废退】就是:BERT
广泛成长,word2vec
逐渐废弃。
Bert
与 word2vec
的区别是:word2vec
中每个单词都有一个固定的表示,而与单词出现的上下文无关【为什么啊???】;bert生成的单词表示是由单词周围的单词动态形成的。
Bert
也做 word embedding
吗?Bert 有自己的word to vector方法,你可以将其看做是embedding生成机制中的一种。但是Bert做的embedding是动态的,即使同一个单词在不同的句子中得到的embedding可能都不是一样的。Bert 可以得到word的embedding,句子的embedding。但有个问题是:BERT 生成的 embedding
不是固定的,它没有固定的层用于生成embedding
,所以就需要你自己考虑由哪些层的输出得到embedding
就OK了。
BERT
相比 word2vec
的优势是什么?BERT produces word representations that are dynamically informed by the words around them.【最主要的就是利用了上下文信息,每个单词都不是一座孤岛】
BERT、Transformer、Attention
之间的关系Attention
是一种算法,可以将其看成是平级于 RNN,LSTM
的一种方法。这种方法的特别之处在于它对一个句子不同的词赋以不同的优先级。
transformer
是一种架构,它基于Attention 机制实现。所谓的transformer
也就是数个ecoder layer叠加得到的块。【同时需要注意,我们平常也会使用一个包叫做Transformer
,这个包实现了诸如BERT,GPT
这种常用且著名的算法,这个包由著名的hugging face
团队开发】
BERT
是一种集合transfomer+双向检索
思想得到的算法,它可以很好的提取出文本中的信息。
sentence
a “sentence” can be an arbitrary span of contiguous text, rather than an actual linguistic sentence.A “sequence” refers to the input token sequence to BERT, which may be a single sentence or two sentences packed together.
Here are some examples of the tokens contained in our vocabulary.
说明单词表中存在的词就可以称之为 tokens 。
预训练好的模型是在一个固定大小的单词表上搞出来的,这个单词表包含四种词汇:
OOV:out of vocabulary;UNK:unknown vocabulary
就是常出现的两种情况。对于单词表无法涵盖所有的单词,BERT
并没有用OOV,UNK
来表示这些不认识的单词,而是将不认识的单词拆分成多个部分。基于这个模型【指的是WordPiece模型】,tokenize的过程是:讲完4,5两大部分,我们再来看看part 6,即怎么用BERT
提取出 embedding
?
word embedding
?】下面这两个答案都是出自知乎问题 我觉得写得还行,就贴过来了。
答:以huggingface为例,你可以直接拿一个预训练bert模型,然后tokenize text 放到模型里跑,输出结果是一个向量,这个向量就是embedding,之后可以用这个向量进行进一步训练,无论是分类也好,还是别的应用。
把最后的classifier扔掉,feed-forwarding 以后的结果就是embedding。需要句子的embedding的话最简单的方法是做mean pooling。
根据 sentence
得出 embedding
的过程可以参考文章 来实现,这文章写的真的超级好。【英语不好读起来真是超要命】
光说不练假把式,这些东西还是需要自己动手,使用bert生成embedding是个非常简单的过程。
"""
实现bert做embedding
"""
import torch
from transformers import BertTokenizer, BertModel # 导入transformer 的包
#torch.set_printoptions(profile="full") # 输出tensor的整个部分
"""from_pretrained()方法是类PreTrainedModel的一个方法"""
model = BertModel.from_pretrained("bert-base-uncased")
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
inputs = tokenizer("hello,my dog",return_tensors='pt')
# 执行model[BertModel实例]的forward()方法,但是在执行之前,仍然做了很多其他的事情
# 比如因为传入的inputs是一个字典,在使用命令关键字做参数的时候,就涉及到了解包操作等等
outputs = model(**inputs)
# The last hidden-state is the first element of the output tuple
# outputs 是一个多维的tensor, 其中第一维就是最后一个隐层的输出,这里我们直接取最后一个隐层的输出作为sentence 的 embedding
last_hidden_states = outputs[0]
print(last_hidden_states)
print(last_hidden_states.size())
"""
1. inputs 是个字典,的内容如下:
{'input_ids': tensor([[ 101, 7592, 1010, 2026, 3899, 2003, 10140, 102]]),
'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0]]),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1]])
}
2.如果我的句子是 "hello,my dog is cute",那么得到last_hidden_state 的size 就是torch.Size([1, 8, 768]),
如果我的句子是"hello,my dog",那么得到的last_hidden_state 的 就是 torch.size([1,6,768])
"""
得到的每个单词的 embedding
如下所示,因为这里共有4+2个token
,所以其各个embedding
显示如下:
上面这段代码我放到了github中。库里面还有更好的内容哦,也在不断整理中~
我觉得关键点主要就如下几个:
可以使用 Hugging Face
组织提供的 Transformers
包,里面提供了Bert的实现。其中transformers
提供了将BERT应用到不同下游任务【token classification,text classification....
】的许多类。
transformers
provides a number of classes for applying BERT to different tasks (token classification, text classification, …).
安装包
可以采用普通命令进行安装pip install transformers
这里我建议可以尝试源码安装,毕竟后面会常用到bert,阅读其源码也是一个基本学习方法。
使用包
import transformers
导入包中指定的模型
from transformers import BertModel, BertTokenizer
这句话的含义是从模块transformers
中导入BertTokenizer
和 BertModel
。这里请记住BertModel
这个类,可以说这是源码中较为重要的一个类了。以后肯定会更加经常的碰到~
指定格式的输入
因为Bert是一个预训练好的模型,所以有很严格的数据输入格式。格式主要如下:
每个sentence都用SEP, CLS
分割;分割得到的tokens
必须与代码中预训练的BERT
模型使用相一致的的词表【也就是我们在下载的文件中常见到的vocab.txt
文件】;Tokens的Token IDs,来自于BERT 的tokenzier;Mask IDs:表明句中的元素谁是tokens,谁是被 padding 的元素; Segment IDs :用于区分不同的句子;Positional Embeddings
: 用于展示剧中的token位置
这部分不再赘述,可以在参考博客中查看。
上面这些东西都可由 BertTokenizer
的实例 的tokenize()方法得到。
BERT tokenizer
是基于什么模型构建的?BERT tokenizer was created with a WordPiece model.
这个部分尚未深入,待更新吧~
其实觉得这部分应该拿到前面去写,但是缘分在这儿,就放这儿了~
提纲挈领的一句话就是:
BERT is basically a trained Transformer Encoder stack.
我们常用的BERT分成bert-base
和 bert-large
版,但是无论哪一种结构都是由一些encoder layers
构成的,这些encoder layers
又被叫做Transformer blocks
。如下图所示:
但实际代码中使用 BERT 的架构同论文中BERT的架构是稍有不同的【大致相似】。
we will use BERT to extract features, namely word and sentence embedding vectors, from text data.
word embedding