夏乙 晓查 乾明 问耕 发自 凹非寺
量子位 报道 | 公众号 QbitAI

BERT终于来了!今天,谷歌研究团队终于在GitHub上发布了万众期待的BERT。

代码放出不到一天,就已经在GitHub上获得1500多星。

项目地址:https://github.com/google-research/bert#fine-tuning-with-bert

就在半个月前,谷歌才发布这个NLP预训练模型的论文(https://arxiv.org/abs/1810.04805)。BERT一出现,就技惊四座碾压了竞争对手,在11项NLP测试中刷新了最高成绩,甚至全面超越了人类的表现。

BERT的出现可以说是NLP领域最重大的事件,谷歌团队的Thang Luong认为BERT标志着NLP新时代的开始。

BERT是什么?

BERT全称Bidirectional Encoder Representations from Transformers,是预训练语言表示的方法,可以在大型文本语料库(如维基百科)上训练通用的“语言理解”模型,然后将该模型用于下游NLP任务,比如机器翻译、问答。

BERT是第一个无监督的用于预训练NLP的深度双向系统。无监督意味着BERT仅使用文本语料库进行训练,也就是说网络上有大量多种语言文本数据可供使用。

NLP预训练的表示也可以是无语境的,也可以是语境关联的,而且语境表示可以是单向的也可以是双向的。

诸如word2vec或GloVe之类的无语境模型由词汇表中的每个单词生成单个“单词嵌入”表示,因此像“bank”这样的单词会有“银行”和“河岸”两种表示。而语境模型则会根据句子中其他单词来生成每个单词的表示。

BERT建立在最近的预训练语境表示工作的基础上,包括半监督序列学习,生成预训练,ELMo和ULMFit,但关键的是这些模型都是单向或浅双向的。

这意味着每个单词仅使用前面(或后面)的单词进行语境化。例如,在“I made a bank deposit”的句子中,做出“bank”的单向表示可能仅仅基于前文“I made”,而不是后文“deposit”。

前人的一些工作确实结合了来自单独的前文或者后文模型的表示,但这种方式很“浅”。

而BERT表示“bank”从深度神经网络的最底层开始,同时结合了上下文“I made a…deposit” ,因此双向的联系很“深”。

BERT使用一种简单的方法:屏蔽输入中15%的单词,通过深度双向Transformer编码器运行整个序列,然后预测被屏蔽的单词。例如:

Input: the man went to the [MASK1] . he bought a [MASK2] of milk.Labels: [MASK1] = store; [MASK2] = gallon

为了学习句子之间的关系,还训练一个可以从任何单语语料库生成的简单任务:给出两个句子A和B,让机器判断B是A的下一句,还是语料库中的随机句子?

Sentence A: the man went to the store .(句子A:男人走进商店)Sentence B: he bought a gallon of milk .(句子B:他买了一加仑牛奶)Label: IsNextSentence (是下一句)
Sentence A: the man went to the store .(句子A:男人走进商店)Sentence B: penguins are flightless .(句子B:企鹅不会飞)Label: NotNextSentence (不是下一句)

然后,Google在大型语料库(维基百科和 BookCorpus)上训练了一个大型模型(12层到24层Transformer),花费了很长时间(100万升级步骤),这就是BERT。

使用BERT分为两步:预训练和微调。

预训练的代价非常高昂(需要4到16个云TPU训练4天),但是每种语言都是训练一次就够了。谷歌大脑团队发布了一些预训练的模型,目前仅限英语,但不久后也会发布多语言模型。大多数NLP研究人员根本不需要从头开始训练他们自己的模型。

与预训练不同,微调则比较容易。从完全相同的预训练模型开始,本文中的所有结果只需最多在单个云TPU上运行1小时,或者在GPU上运行几小时。例如,目前最先进的单系统SQuAD,在单个云TPU上训练大约30分钟,就能获得91.0%的Dev F1分数。

BERT的另一个重要特性是,它能适应许多类型的NLP任务。它的论文里就展示了句子级别(如SST-2),句对级别(如MultiNLI),单词级别(如NER)和小段级别(如SQuAD)的最新结果,几乎没有针对特定任务进行修改。

支持汉语吗?

目前放出的预训练模型是英语的,不过,谷歌大脑团队打算11月底之前放出经更多语言预训练的多语种模型。

更多语言究竟包括哪些?官方没有给出准确信息,不过BERT一作Jacob Devlin回应排队求中日韩德甚至马其顿语版本的群众们时说,他正在用维基百科规模最大的60种语言训练模型,汉语、韩语、日语、德语、西班牙语等等都包含在其中。

就是这里列出的1-60号语言:

https://meta.wikimedia.org/wiki/List_of_Wikipedias#All_Wikipedias_ordered_by_number_of_articles

另外,他们对中文做了一点比较特殊的处理,就是把CJK Unicode字符集里的所有字符token化。

项目库中发布了哪些内容?

  • 用于BERT模型架构的TensorFlow代码(主要是标准的Transformer架构)。

  • BERT-Base和BERT-Large模型小写和Cased版本的预训练检查点。

  • 论文里微调试验的TensorFlow代码,比如SQuAD,MultiNLI和MRPC。
    此项目库中的所有代码都可以直接用在CPU,GPU和云TPU上。

预训练模型

这里发布的是论文中的BERT-Base和BERT-Large模型。
其中,Uncased的意思是,文本在经过WordPiece token化之前,全部会调整成小写,比如“John Smith”会变成“john smith”。Uncased模型也会剔除任何的重音标记。Cased意味着,文本的真实情况和重音标记都会保留下来。

通常情况下,Uncased模型更好,除非文本的原始信息会对你的任务来说非常重要。比如说,识别命名实体或对部分语音标记。

这些模型与源代码(Apache 2.0)的授权相同。

在下面的模型介绍中,沿袭论文中的简称:层数(即 Transformer 块)表示为L,将隐藏尺寸表示为H,将自注意力头(self-attention heads)的数量表示为A。

复制下方链接到浏览器中即可下载

BERT-Base, Uncased:L=12,H=768,A=12,总参数=110M
https://storage.googleapis.com/bert_models/2018_10_18/uncased_L-12_H-768_A-12.zip

BERT-Large, Uncased:L=24, H=1024, A=16, 总参数=340M
https://storage.googleapis.com/bert_models/2018_10_18/uncased_L-24_H-1024_A-16.zip

BERT-Base, Cased:L=12,H=768,A=12,总参数=110M
https://storage.googleapis.com/bert_models/2018_10_18/cased_L-12_H-768_A-12.zip

BERT-Large, Cased:L=24, H=1024, A=16, 总参数=340M
https://storage.googleapis.com/bert_models/2018_10_18/cased_L-12_H-768_A-12.zip

每个.zip文件,都包含3个东西:

一个 TensorFlow检查点(bert_model.ckpt),一个vocab文件(vocab.txt)和一个配置文件(bert_config.json)。

如果你想对这些预训练模型进行端到端的微调,参见这份具体操作:
https://github.com/google-research/bert/blob/master/README.md#fine-tuning-with-bert

使用 BERT 提取固定特征向量(如 ELMo)

有时候,与对整个预训练模型进行端到端的微调相比,直接获得预训练模型的语境嵌入会更好一些。

预训练模型的语境嵌入,是由预训练模型的隐藏层生成的每个token的固定语境表示。这应该能够减轻大部分内存不足的问题。

比如,脚本extract_features.py,可以这样使用:

# Sentence A and Sentence B are separated by the ||| delimiter.# For single sentence inputs, don't use the delimiter.echo 'Who was Jim Henson ? ||| Jim Henson was a puppeteer' > /tmp/input.txt

python extract_features.py \  --input_file=/tmp/input.txt \  --output_file=/tmp/output.jsonl \  --vocab_file=$BERT_BASE_DIR/vocab.txt \  --bert_config_file=$BERT_BASE_DIR/bert_config.json \  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \  --layers=-1,-2,-3,-4 \  --max_seq_length=128 \  --batch_size=8

这将创建一个 JSON 文件(每行输入一行),包含由layers指定的每个Transformer层的BERT 激活(-1是Transformer的最后隐藏层,等等)
请注意,这个脚本将产生非常大的输出文件,默认情况下,每个输入token产生大约15kb输出。

如果你预测训练标签,需要保持原始词汇和token词之间的一致性。具体请参阅下面的Token化部分。

Token化

对于句子层级的任务,token化非常简单。按照run_classifier.py和extract_features.py中的代码运行就行了。句子层级任务的基本流程是:

  1. 实例化。tokenizer = tokenization.FullTokenizer

  2. 将原始文本token化。tokens = tokenizer.tokenize(raw_text).

  3. 截断句子长度。(最大序列你最多可以使用512,但因为内存和速度的原因,短一点可能会更好)

  4. 在正确的位置添加[ CLS ]和[ SEP ]token。

[ CLS ]是分类输出的特殊符号,[ SEP ]是分离非连续token序列的特殊符号。

单词级别和跨度级别的任务(例如SQuAD 和 NER)更为复杂,因为你需要保证输入文本和输出文本之间对齐,以便你能够映射训练标签。

SQuAD是一个非常复杂的例子,因为输入的标签是基于字符的,而且段落的长度也经常会超过默认的最大序列。查看run_squad.py中的代码, 可以看到Google是如何处理这个问题的。

在介绍处理单词级别任务的通用方法之前,了解分词器(tokenizers)到底在做什么非常重要。它主要有三个步骤:

  1. 文本标准化:将所有的空白字符转换为空格,在Uncased模型中,要将所有字母小写,并剔除重音标记。例如:John Johanson’s, → john johanson’s,

  2. 标点符号分离:把标点符号分为两个部分,也就是说,在所有的标点符号字符周围添加空格。标点符号的定义是: (a)任何具有 p * Unicode 类的东西,(b)任何非字母 / 数字 / 空格 ASCII 字符,例如 $这样的字符,技术上不是标点符号。例如:john johanson’s, → john johanson ‘ s ,

  3. WordPiece token化:将空白token化,应用到上述过程的输出中,并对每个token分别应用WordPiece。(这个实现直接基于 tensor2tensor)。例如:john johanson ‘ s , → john johan ##son ‘ s ,

这个方案的优点在于,它与大多数英语分词器兼容。例如,假设你有一个类似这样的标记部分语音任务:

Input: John Johanson ‘s houseLabels: NNP NNP POS NN

所有的token化输出都是这样的:

Tokens: john johan ##son ‘ s house

至关重要的是,这与输入John Johanson’s house的输出是一样的,在’之前也没有空格。

如果你有一个带有单词级别注释的预token化表示,你可以独立地对每个输入单词进行简单的分析,并确保原始文本到token化文本之间是对齐的:

### Inputorig_tokens = ["John", "Johanson", "'s",  "house"]labels      = ["NNP",  "NNP",      "POS", "NN"]

### Outputbert_tokens = []

# Token map will be an int -> int mapping between the `orig_tokens` index and# the `bert_tokens` index.orig_to_tok_map = []

tokenizer = tokenization.FullTokenizer(    vocab_file=vocab_file, do_lower_case=True)

bert_tokens.append("[CLS]")for orig_token in orig_tokens:  orig_to_tok_map.append(len(bert_tokens))  bert_tokens.extend(tokenizer.tokenize(orig_token))bert_tokens.append("[SEP]")

# bert_tokens == ["[CLS]", "john", "johan", "##son", "'", "s", "house", "[SEP]"]# orig_to_tok_map == [1, 2, 4, 6]

现在,orig_to_tok_map能用来将labels映射到token化表示上。

有一些常见的英语训练方案,会导致BERT的训练方式之间出现轻微的不匹配。

例如,如果你输入的是缩写单词而且又分离开了,比如do n’t,将会出现错误匹配。如果可能的话,你应该预先处理数据,将其转换为原始的文本。如果不处理,这种错误匹配也不是什么大问题。

预训练BERT

如果你想自己预训练BERT,可以看看这份资源中在任意文本语料库上完成“masked LM”和“预测下一句”任务的代码。

注意:这不是论文中的原始代码,但是同样能生成论文中所描述的预训练数据。原始代码是C++写成的,更复杂。

首先是数据生成环节:输入每句一行的纯文本文件,用空行分隔文件,会得到一组TFRecord文件格式的tf.train.Example。

python create_pretraining_data.py \  --input_file=./sample_text.txt \  --output_file=/tmp/tf_examples.tfrecord \  --vocab_file=$BERT_BASE_DIR/vocab.txt \  --do_lower_case=True \  --max_seq_length=128 \  --max_predictions_per_seq=20 \  --masked_lm_prob=0.15 \  --random_seed=12345 \  --dupe_factor=5

这段脚本能把整个输入文件中的所有样例存储到内存,所以,如果输入文件比较大,你要把它分割开,多次调用这个脚本。

max_predictions_per_seq是每个序列能获得masked LM预测的最大值,应该设置到和max_seq_length乘masked_lm_prob差不多。

数据生成之后就可以运行预训练了。

python run_pretraining.py \  --input_file=/tmp/tf_examples.tfrecord \  --output_dir=/tmp/pretraining_output \  --do_train=True \  --do_eval=True \  --bert_config_file=$BERT_BASE_DIR/bert_config.json \  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \  --train_batch_size=32 \  --max_seq_length=128 \  --max_predictions_per_seq=20 \  --num_train_steps=20 \  --num_warmup_steps=10 \  --learning_rate=2e-5

注意,如果你要从头开始预训练的话,就去掉代码里的init_checkpoint。模型的设置在bert_config_file里。

这段代码只能预训练20步左右,但实际使用中,你可能需要训练10000步以上,在num_train_steps这里设置数字就可以。

另外,max_seq_length和max_predictions_per_seq传递给run_pretraining.py的参数,必须和create_pretraining_data.py.一样。

得到的输出会是这样的:

***** Eval results *****  global_step = 20  loss = 0.0979674  masked_lm_accuracy = 0.985479  masked_lm_loss = 0.0979328  next_sentence_accuracy = 1.0  next_sentence_loss = 3.45724e-05

这里还有一些预训练注意事项:

如果你的任务有大型特定域语料库可用,比如电影评论、科研论文等等,则从BERT检查点开始,对语料库执行额外的预训练步骤可能会有用。

论文中使用的学习率是1e-4。但是,如果你从现有BERT检查点开始执行额外的预训练步骤,则应使用较小的学习率(例如,2e-5)。

现在BERT模型只支持英语,但是Google打算在“不久的将来”发布经过多种语言预训练的多语种模型。这个不久,他们希望是11月底之前。

注意力是序列长度的平方,所以长序列非常昂贵(耗费计算力)。一批64个长度为512的序列,比一批256个长度为128的序列要昂贵的多,它们的全连接、卷积成本相同,但是512长度的序列注意力成本要高很多。

不过有时候确实需要长序列,比如要学习位置嵌入的时候,用长序列就学得非常快。这时候,可以先用短序列(比如长度128)训练90000步,再用长序列(比如长度512)训练10000步。注意,这需要用不同的max_seq_length值生成两次数据。

如果从头开始预训练,请注意:成本很高,在GPU上成本尤其高。Google推荐先用单个可抢占(preemptible)的云TPU v2,预训练BERT-Base。这需要两周时间,500美元,还需要缩小批次大小。

预训练数据:

论文用的预处理数据集……Sorry,Google说不公布了。不过他们提供了一些让你自己搞定数据集的途径。

如果想用维基百科,从这里下载:
https://dumps.wikimedia.org/enwiki/latest/enwiki-latest-pages-articles.xml.bz2

然后用WikiExtractor.py提取文本:
https://github.com/attardi/wikiextractor

然后进行必要的清理,转换成纯文本。

如果想用BookCorpus数据集,它已经不提供开放下载了,可以用比较小的Project Guttenberg数据集替代:
https://web.eecs.umich.edu/~lahiri/gutenberg_dataset.html

还有一个大型文本资源,叫Common Crawl,也可以清理一下提取出预训练BERT要用的语料库:
http://commoncrawl.org/

在Colab里使用BERT

Google还提供了更贴心的使用方式:在他们的Colab(全称Colaboratory)里,打开这个名叫“BERT FineTuning with Cloud TPUs”的笔记本,就可以开工了:
https://colab.research.google.com/github/tensorflow/tpu/blob/master/tools/colab/bert_finetuning_with_cloud_tpus.ipynb

如果你想免费薅一把谷歌云TPU资源,现在Colab是个不错的途径。

FAQ

问:这次放出的代码适用于云TPU么?GPU能用么?
答:没问题。这个仓库中的所有代码都能在CPU、GPU和云TPU上跑。但是,GPU训练仅适用于单GPU。

问:提示内存不足,这是什么问题?
答:可以参考相关条目解决。官方地址 https://github.com/google-research/bert#out-of-memory-issues

问:会有PyTorch版本发布么?
答:没有官网的PyTorch实现。如果有人搞出一个逐行的PyTorch实现,能够直接转换我们预先训练好的检查点,我们很乐意帮忙推广。

问:模型是否会支持更多语言?
答:会,我们计划很快发布多语言的BERT模型,会是一个单一模型。现在还无法确定将包括哪些语言,不过在维基百科上语料规模比较大的语言应该都有。

问:还会有比BERT-Large更大的模型么?
答:截至目前,我们还没尝试过更大的训练。如果我们能够取得重大的改进,可能会发布更大的模型。

问:这个库使用什么许可证?
答:所有代码和模型都在Apache 2.0许可证之下。

加入社群

量子位AI社群开始招募啦,欢迎对AI感兴趣的同学,在量子位公众号(QbitAI)对话界面回复关键字“交流群”,获取入群方式;

此外,量子位专业细分群(自动驾驶、CV、NLP、机器学习等)正在招募,面向正在从事相关领域的工程师及研究人员。

进专业群请在量子位公众号(QbitAI)对话界面回复关键字“专业群”,获取入群方式。(专业群审核较严,敬请谅解)

活动策划招聘

量子位正在招聘活动策划,将负责不同领域维度的线上线下相关活动策划、执行。欢迎聪明靠谱的小伙伴加入,并希望你能有一些活动策划或运营的相关经验。相关细节,请在量子位公众号(QbitAI)对话界面,回复“招聘”两个字。

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态

谷歌最强NLP模型BERT如约开源,12小时GitHub标星破1500,即将支持中文相关推荐

  1. 谷歌最强 NLP 模型 BERT 解读

    谷歌最强 NLP 模型 BERT 解读 https://mp.weixin.qq.com/s/N7Qp_Fx0rAFbvrpLSETi8w 本文是追一科技潘晟锋基于谷歌论文为 AI 科技评论提供的解读 ...

  2. 谷歌最强NLP模型BERT官方代码来了!GitHub一天3000星

    新智元报道 来源:GitHub 作者:Google Research 编辑:肖琴 [新智元导读]谷歌AI团队终于开源了最强NLP模型BERT的代码和预训练模型.从论文发布以来,BERT在NLP业内引起 ...

  3. 详解谷歌最强NLP模型BERT(理论+实战)

    作者:李理,环信人工智能研发中心vp,十多年自然语言处理和人工智能研发经验.主持研发过多款智能硬件的问答和对话系统,负责环信中文语义分析开放平台和环信智能机器人的设计与研发. 本文是作者正在编写的&l ...

  4. 谷歌更强 NLP 模型 XLNet 开源:20 项任务全面碾压 BERT!

    谷歌更强 NLP 模型 XLNet 开源:20 项任务全面碾压 BERT! 11 月份,谷歌研究团队在 GitHub 上发布了万众期待的 BERT,它不仅在 11 项 NLP 测试中刷新了最高成绩,甚 ...

  5. 最强NLP模型BERT喜迎PyTorch版!谷歌官方推荐,也会支持中文

    郭一璞 夏乙 发自 凹非寺  量子位 报道 | 公众号 QbitAI 谷歌的最强NLP模型BERT发布以来,一直非常受关注,上周开源的官方TensorFlow实现在GitHub上已经收获了近6000星 ...

  6. 注意力机制可视化_最强NLP模型BERT可视化学习

    摘要: 最强NLP模型谷歌BERT狂破11项纪录,全面超越人类,本文通过可视化带你直观了解它. 2018年是自然语言处理(Natural Language Processing, NLP)领域的转折点 ...

  7. 最强NLP模型BERT可视化学习

    2018年是自然语言处理(Natural Language Processing, NLP)领域的转折点,一系列深度学习模型在智能问答及情感分类等NLP任务中均取得了最先进的成果.近期,谷歌提出了BE ...

  8. bert中的sep_最强NLP模型BERT可视化学习

    2018年是自然语言处理(Natural Language Processing, NLP)领域的转折点,一系列深度学习模型在智能问答及情感分类等NLP任务中均取得了最先进的成果.近期,谷歌提出了BE ...

  9. 如何基于谷歌的最强 NLP 模型进行影评分析?

    谷歌此前发布的NLP模型BERT,在知乎.Reddit上都引起了轰动.其模型效果极好,BERT论文的作者在论文里做的几个实验数据集都被轰平了.要做那几个数据集的人可以洗洗睡啦,直接被明明白白地安排了一 ...

最新文章

  1. Exchange动态同步中的INTERNET_29错误代码
  2. js 空数组是true还是false
  3. 国服服务器_《Minecraft我的世界》第三方服务器的基本储备
  4. 数据结构(三)之单链表反向查找
  5. ceph rgw java_ceph rgw multisite基本用法
  6. Flutter CupertinoSegmentedControl 分段组件
  7. pdf转chm_PDF转Excel的小妙招!
  8. 解决QML Window 增加radius效果
  9. Vue中默认main.js
  10. 工作组下安装ISA Server 2004
  11. 即拿即用-Android单线程断点下载
  12. python处理access数据库教程_Python操作Access数据库基本步骤分析
  13. Cursor 详解及使用
  14. 周记--听平凡人说故事
  15. 【蓝桥杯每日一练:蹩脚两轮车】
  16. 信息系统项目管理师核心考点(五十四)配置项分类、状态与版本
  17. 在用docker部署nginx时,出现curl: (6) Could not resolve host: localhsot; 未知的错误
  18. AE插件:能量激光描边光效特效Saber
  19. 重装w11新硬盘,找不到硬盘
  20. HTTP协议详解以及URL具体访问过程

热门文章

  1. 阿里京东被怼假货泛滥;谷歌 CEO 承认中国版搜索 App 存在;YouTube 全球宕机 | 极客头条...
  2. 微软力挺 Go,宣布参与 Athens 项目和 GopherSource
  3. 阿里发力线下渠道,腾讯京东该如何打破其流量优势?
  4. 远程键盘 App 被曝漏洞,成 Intel 弃子!
  5. 动我 Java?是时候让甲骨文退休了!
  6. c语言高级工程师试题,2020年.Net中高级开发工程师笔试题带答案(3)
  7. 如何强大且优雅的搞定Linux文件系统,值得一读!
  8. java语言的主要特点有简单性,太厉害了!
  9. java语言开发的中间件名称,值得收藏!
  10. linux chmod命令数字,菜鸟学Linux命令:chmod命令和数字文件权限