NLP之BERT:BERT的简介、安装和使用方法、案例应用之详细攻略
目录
(2)、使用BERT有两个阶段:预训练(4天)→微调(1小时)
***** 2020年3月11日更新:更小的BERT模型 *****
***** 2019年5月31日更新:整词掩码模型 *****
***** 2018年11月23日更新:未归一化的多语言模型+泰语+蒙古语 *****
***** 2018年11月15日更新:SOTA SQuAD 2.0系统 *****
***** 2018年11月5日更新:PyTorch和Chainer版本的第三方BERT可用 *****
***** 2018年11月3日更新:多语言和中文模型可用*****
4、内存问题及其修改建议:max_seq_length=512、train_batch_size、模型类型、优化器Adam、梯度累积技术、梯度检查点技术
NLP之TM:基于多个文本数据(BertTokenizer)利用BERT预训练模型(transformers)结合K-means均值聚类算法对文本向量进行聚类实现主题模型进而转为结构化数据应用案例
NLP:利用spacy的en_trf_bertbaseuncased_lg预训练语言模型实现四种底层基本任务—词法分析(词向量)、语义分析(语义解析)、信息抽取(命名实体识别NER)应用案例实现代码
NLP之TextSimil:基于两份文档(分词和编码)利用预训练模型(BERT)获取文档的嵌入表示再利用余弦相似度法来计算相似度实现代码
PT之BERT:基于torch框架(特征编码+BERT作为文本编码器+分类器)针对UCI新闻数据集利用Transformer-BERT算法(模型实时保存)实现新闻文本多分类案例
NLP之ModelScope:基于ModelScope框架的afqmc数据集利用StructBERT预训练模型的文本相似度算法实现文本分类任务图文教程之详细攻略
LLMs之spaCy:利用spaCy管道训练大模型案例—对预训练的BERT、XLNet和GPT-2实现图文教程之详细攻略
LLMs之BERT:基于spaCy框架利用预训练Transformer(如BERT)进行多任务学习(添加自定义任务—文本情感分类)训练并进行模型打包和模型推理应用案例实现代码
LLMs之BERT:基于spaCy框架利用预训练Transformer进行多任务学习(自定义任务—文本情感分类和命名实体识别NER)训练并进行模型打包和模型推理应用案例实现代码
相关文章
Paper:《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding用于语言理解的深度双向Transformers预训练模型》翻译与解读
https://yunyaniu.blog.csdn.net/article/details/88082930
BERT的简介
2018年11月,BERT正式开源,即来自Transformer的双向编码器表示,是一种在大量自然语言处理(NLP)任务中取得最先进结果的预训练语言表示方法。
BERT是一种预训练语言表示的方法,意味着我们在大型文本语料库(如维基百科)上训练一个通用的“语言理解”模型,然后将该模型用于我们关心的下游自然语言处理(NLP)任务(如问答)。
BERT的性能优于先前的方法,因为它是第一个用于预训练NLP的无监督、深度双向系统。
>> 无监督意味着BERT仅使用纯文本语料库进行训练,这很重要,因为在网络上有大量公开可用的纯文本数据,涵盖多种语言。
>> 预训练表示也可以是上下文无关的或上下文相关的,而上下文相关表示又可以是单向或双向的。上下文无关模型(如word2vec或GloVe)为词汇表中的每个单词生成一个单一的“词嵌入”表示,因此“bank”在“bank deposit”和“river bank”中具有相同的表示。相反,上下文相关模型会生成基于句子中其他单词的每个单词的表示。
我们的学术论文详细描述了BERT,并在许多任务上提供了完整的结果,可以在这里找到。
GitHub地址:GitHub - google-research/bert: TensorFlow code and pre-trained models for BERT
1、BERT的由来
(1)、BERT的MLM任务和NSP任务
痛点 | BERT解决了传统模型只使用单向或者浅层双向上下文的问题 BERT建立在最近的上下文相关表示的预训练工作基础上,包括半监督序列学习、生成式预训练、ELMo和ULMFit等,但关键是这些模型都是单向或浅双向的。这意味着每个单词仅使用其左侧(或右侧)的单词进行上下文化。例如,在句子“I made a bank deposit”中,“bank”的单向表示仅基于“I made a”而不是“deposit”。一些先前的工作确实将来自单独的左上下文和右上下文模型的表示组合在一起,但只以“浅层”的方式。BERT使用深度神经网络从底部开始表示“bank”,使用其左右上下文,“I made a...deposit”。“bank”。 |
额外采用MLM任务改进 | BERT在进行预训练过程中采用了遮蔽语言模型和下一句任务来学习上下文相关知识。 BERT对此采用了简单的方法:我们在输入中遮蔽掉15%的单词,通过深度双向Transformer编码器运行整个序列,然后仅预测被遮蔽的单词。例如: 输入:“the man went to the [MASK1]. he bought a [MASK2] of milk.” 标签:[MASK1] = store; [MASK2] = gallon |
继续沿用NSP任务 | 为了学习句子之间的关系,我们还在一个简单的任务上进行训练,该任务可以从任何单语语料库中生成:给定两个句子A和B,B是紧随A之后的实际下一个句子,还是来自语料库的随机句子? 句子A:“the man went to the store.” 句子B:“he bought a gallon of milk.” 标签:“IsNextSentence” 句子A:“the man went to the store.” 句子B:“penguins are flightless.” 标签:“NotNextSentence” |
大型语料库长时间的训练 | 然后,我们在大型语料库(维基百科+BookCorpus)上对一个大型模型(12层到24层的Transformer)进行长时间的训练(100万个更新步骤),这就是BERT。 |
(2)、使用BERT有两个阶段:预训练(4天)→微调(1小时)
预训练阶段 | 预训练阶段相对昂贵(在4到16个Cloud TPU上需要4天时间),但对于每种语言只需进行一次过程(当前模型仅支持英语,但未来将发布多语言模型)。我们正在发布一些在Google进行预训练的论文中的预训练模型。大多数自然语言处理研究人员将不需要从头开始预训练自己的模型。 |
微调阶段 | 微调成本较低。论文中的所有结果都可以在单个Cloud TPU上最多1小时内复制,或者在GPU上几个小时内复制,从完全相同的预训练模型开始。例如,SQuAD可以在单个Cloud TPU上训练约30分钟,即可达到91.0%的Dev F1分数,这是单系统最先进的水平。 |
特点 | BERT的另一个重要方面是它可以非常容易地适应许多类型的自然语言处理任务。在论文中,我们展示了在句子级(例如,SST-2)、句对级(例如,MultiNLI)、词级(例如,NER)和跨度级(例如,SQuAD)任务上几乎不需要任务特定修改的最先进结果。 |
2、更新
***** 2020年3月11日更新:更小的BERT模型 *****
内容 | 这是24个更小的BERT模型的发布(仅英语,未大小写,使用WordPiece掩码进行训练),这些模型在Well-Read Students Learn Better: On the Importance of Pre-training Compact Models中有引用。 我们已经证明了标准的BERT配方(包括模型架构和训练目标)在广泛的模型大小范围上都是有效的,超越了BERT-Base和BERT-Large。更小的BERT模型适用于计算资源受限的环境。它们可以像原始的BERT模型一样进行微调。然而,在知识蒸馏的背景下,它们在更大、更准确的教师产生的微调标签的情况下最为有效。 我们的目标是促进在计算资源较少的机构进行研究,并鼓励社区寻找增加模型容量以外的创新方向。 您可以从这里下载全部24个模型,或从下面的表格中单独下载: |
请注意,此发布中的BERT-Base模型仅用于完整性;它是在与原始模型相同的体制下重新训练的。 以下是测试集上的相应GLUE分数: 对于每个任务,我们从以下列表中选择了最佳的微调超参数,并进行了4个时期的训练: 批次大小:8、16、32、64、128 学习率:3e-4、1e-4、5e-5、3e-5 如果您使用这些模型,请引用以下论文: |
***** 2019年5月31日更新:整词掩码模型 *****
内容 | 这是一次新模型的发布,这些模型是对预处理代码的改进的结果。 在原始的预处理代码中,我们随机选择WordPiece标记进行掩码。例如: 输入文本:the man jumped up , put his basket on phil ##am ##mon ' s head 原始掩码输入:[MASK] man [MASK] up , put his [MASK] on phil [MASK] ##mon ' s head 新技术称为整词掩码。在这种情况下,我们总是一次性掩码与一个单词相对应的所有标记。整体掩码率保持不变。 整词掩码输入:the man [MASK] up , put his basket on [MASK] [MASK] [MASK] ' s head 训练是相同的——我们仍然独立地预测每个被掩码的WordPiece标记。改进来自于原始预测任务对已被拆分为多个WordPieces的单词来说太“容易”这一事实。 可以通过将标志--do_whole_word_mask=True传递给create_pretraining_data.py来在数据生成期间启用此功能。 |
具有整词掩码的预训练模型如下。数据和训练除外,这些模型与原始模型具有相同的结构和词汇。我们只包含BERT-Large模型。在使用这些模型时,请在论文中明确使用BERT-Large的整词掩码变体。 BERT-Large,未大小写(整词掩码):24层,1024隐藏,16头,340M参数 BERT-Large,大小写(整词掩码):24层,1024隐藏,16头,340M参数 BERT已上传至TensorFlow Hub。请参阅run_classifier_with_tfhub.py以获取如何使用TF Hub模块的示例,或在Colab中的浏览器上运行示例。 |
***** 2018年11月23日更新:未归一化的多语言模型+泰语+蒙古语 *****
内容 | 我们上传了一个新的多语言模型,该模型在输入上不执行任何归一化(不进行小写处理、去除重音或Unicode规范化),并额外包括泰语和蒙古语。 建议在开发多语言模型时使用此版本,特别是在非拉丁字母表的语言上。 这不需要任何代码更改,可以在此处下载: BERT-Base,多语言大小写:104种语言,12层,768隐藏,12头,110M参数 |
***** 2018年11月15日更新:SOTA SQuAD 2.0系统 *****
内容 | 我们发布了代码更改,以复制我们83%的F1 SQuAD 2.0系统,该系统目前在排行榜上领先3%。有关详细信息,请参阅README中的SQuAD 2.0部分。 |
***** 2018年11月5日更新:PyTorch和Chainer版本的第三方BERT可用 *****
内容 | HuggingFace的NLP研究人员提供了一个与我们的预训练检查点兼容的PyTorch版本的BERT,能够复现我们的结果。Sosuke Kobayashi还提供了Chainer版本的BERT(谢谢!)。我们没有参与PyTorch实现的创建或维护,因此请将任何问题直接向该存储库的作者提问。 |
***** 2018年11月3日更新:多语言和中文模型可用*****
内容 | 我们提供了两个新的BERT模型: BERT-Base,多语言(不建议使用,改用多语言大小写):102种语言,12层,768隐藏,12头,110M参数 BERT-Base,中文:简体中文和繁体中文,12层,768隐藏,12头,110M参数 |
注意 | 我们对中文使用基于字符的分词,对所有其他语言使用WordPiece分词。这两个模型应该可以直接使用,无需任何代码更改。我们确实更新了tokenization.py中BasicTokenizer的实现以支持中文字符分词,因此如果您分叉了它,请更新。但是,我们没有更改分词API。 有关更多信息,请参阅多语言README。 |
BERT的安装和使用方法
1、GitHub仓库发布的内容
我们发布了以下内容:
>> BERT模型架构的TensorFlow代码(主要是标准的Transformer架构)。
>> 论文中BERT-Base和BERT-Large的小写和大写版本的预训练检查点。
>> 论文中最重要的微调实验的TensorFlow代码,包括SQuAD、MultiNLI和MRPC。
>> 该仓库中的所有代码都可以在CPU、GPU和Cloud TPU上立即运行。
2、预训练模型的简介与下载
简介 | 我们发布了来自论文的BERT-Base和BERT-Large模型。小写Uncased表示在WordPiece标记化之前文本已转换为小写,例如,John Smith变成了john smith。小写模型还去除了任何重音标记。大写表示真实的大小写和重音标记得以保留。通常,除非您知道大小写信息对您的任务很重要(例如,命名实体识别或词性标注),否则小写模型更好。 |
注意 | 这些模型都采用与源代码相同的许可证(Apache 2.0)。有关多语言和中文模型的信息,请参阅Multilingual README。 在使用大写模型时,请确保在训练脚本中传递--do_lower=False(或者如果您使用自己的脚本,则直接传递do_lower_case=False给FullTokenizer)。 |
模型链接 | 模型链接在这里(右键点击,'另存链接为...'): BERT-Large,小写(Whole Word Masking):24层,1024隐藏单元,16个注意力头,340M参数 BERT-Large,大写(Whole Word Masking):24层,1024隐藏单元,16个注意力头,340M参数 BERT-Base,小写:12层,768隐藏单元,12个注意力头,110M参数 BERT-Large,小写:24层,1024隐藏单元,16个注意力头,340M参数 BERT-Base,大写:12层,768隐藏单元,12个注意力头,110M参数 BERT-Large,大写:24层,1024隐藏单元,16个注意力头,340M参数 BERT-Base,多语言大写(新,推荐):104种语言,12层,768隐藏单元,12个注意力头,110M参数 BERT-Base,多语言小写(原始,不推荐)(不推荐,使用多语言大写代替):102种语言,12层,768隐藏单元,12个注意力头,110M参数 BERT-Base,中文:简体中文和繁体中文,12层,768隐藏单元,12个注意力头,110M参数 |
zip文件 | 每个.zip文件包含三个项目: TensorFlow检查点(bert_model.ckpt),包含预训练权重(实际上是3个文件)。 一个词汇文件(vocab.txt),用于将WordPiece映射到单词ID。 一个配置文件(bert_config.json),指定模型的超参数。 |
3、使用BERT进行微调
简介 | 重要提示:论文中的所有结果都是在单个Cloud TPU上进行微调的,该TPU具有64GB的RAM。目前,使用具有12GB - 16GB RAM的GPU无法复制论文中的大多数BERT-Large结果,因为内存中适合的最大批次大小太小。我们正在努力向该仓库添加允许在GPU上实现更大有效批次大小的代码。有关更多详细信息,请参阅有关内存不足问题的部分。 |
注意事项 | 此代码已在TensorFlow 1.11.0中进行了测试。它经过了Python2和Python3的测试(但在Python2中进行了更彻底的测试,因为这是Google内部使用的版本)。 使用BERT-Large的微调示例应该能够在具有至少12GB RAM的GPU上运行,使用给定的超参数。 |
使用Cloud TPU进行微调
简介 | 以下大多数示例假设您将在本地机器上使用GPU(例如Titan X或GTX 1080)运行训练/评估。 |
设置TPU | 但是,如果您可以访问要进行训练的Cloud TPU,只需将以下标志添加到run_classifier.py或run_squad.py: --use_tpu=True \ --tpu_name=$TPU_NAME 请参阅Google Cloud TPU教程,了解如何使用Cloud TPU。或者,您可以使用Google Colab笔记本 "BERT FineTuning with Cloud TPUs"。 |
设置输出目录 | 在Cloud TPU上,预训练模型和输出目录将需要在Google Cloud Storage上。例如,如果您有一个名为some_bucket的存储桶,您可能会改用以下标志: --output_dir=gs://some_bucket/my_output_dir/ 解压后的预训练模型文件也可以在Google Cloud Storage文件夹gs://bert_models/2018_10_18中找到。例如: export BERT_BASE_DIR=gs://bert_models/2018_10_18/uncased_L-12_H-768_A-12 |
1)、句子(和句对)分类任务
下载GLUE数据 | 在运行此示例之前,您必须通过运行此脚本下载GLUE数据,并将其解压缩到某个目录$GLUE_DIR。接下来,下载BERT-Base检查点并将其解压缩到某个目录$BERT_BASE_DIR。 GLUE数据:GLUE Benchmark 脚本地址:https://gist.github.com/W4ngatang/60c2bdb54d156a41194446737ce03e2e |
微调BERT-Bas | 此示例代码在Microsoft Research Paraphrase Corpus(MRPC)语料库上微调BERT-Base,该语料库仅包含3600个示例,并且在大多数GPU上可以在几分钟内完成微调。 export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12 export GLUE_DIR=/path/to/glue python run_classifier.py \ --task_name=MRPC \ --do_train=true \ --do_eval=true \ --data_dir=$GLUE_DIR/MRPC \ --vocab_file=$BERT_BASE_DIR/vocab.txt \ --bert_config_file=$BERT_BASE_DIR/bert_config.json \ --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \ --max_seq_length=128 \ --train_batch_size=32 \ --learning_rate=2e-5 \ --num_train_epochs=3.0 \ --output_dir=/tmp/mrpc_output/ |
您应该会看到如下输出: ***** Eval results ***** eval_accuracy = 0.845588 eval_loss = 0.505248 global_step = 343 loss = 0.505248 这意味着Dev集的准确率为84.55%。像MRPC这样的小型集合在Dev集准确率上有很高的方差,即使从相同的预训练检查点开始。如果多次重新运行(确保指向不同的output_dir),您应该会看到在84%和88%之间的结果。 | |
注意 | 在run_classifier.py中,还实现了其他一些现成的预训练模型,因此按照这些示例使用BERT进行任何单句或句对分类任务应该是直截了当的。 注意:您可能会看到消息Running train on CPU。这实际上只是意味着它是在除Cloud TPU外的其他设备上运行,包括GPU。 |
预测—推断模式 | 从分类器进行预测 在训练分类器之后,您可以使用--do_predict=true命令将其用于推断模式。您需要在输入文件夹中有一个名为test.tsv的文件。输出将创建在名为test_results.tsv的输出文件夹中。每一行都会包含每个样本的输出,列是类别概率。 export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12 export GLUE_DIR=/path/to/glue export TRAINED_CLASSIFIER=/path/to/fine/tuned/classifier python run_classifier.py \ --task_name=MRPC \ --do_predict=true \ --data_dir=$GLUE_DIR/MRPC \ --vocab_file=$BERT_BASE_DIR/vocab.txt \ --bert_config_file=$BERT_BASE_DIR/bert_config.json \ --init_checkpoint=$TRAINED_CLASSIFIER \ --max_seq_length=128 \ --output_dir=/tmp/mrpc_output/ |
训练BERT-Large模型:基于SQuAD 1.1数据集
下载 | 斯坦福问答数据集(SQuAD)是一个流行的问答基准数据集。BERT(在发布时)在SQuAD上获得了最先进的结果,几乎没有进行任务特定的网络架构修改或数据增强。然而,它确实需要对(a)SQuAD上下文段的可变长度性质,以及(b)用于SQuAD训练的字符级答案注释进行半复杂的数据预处理和后处理。这个处理在run_squad.py中已经实现并有文档记录。 要在SQuAD上运行,您首先需要下载数据集。SQuAD网站似乎不再链接到v1.1数据集,但可以在这里找到必要的文件: train-v1.1.json dev-v1.1.json evaluate-v1.1.py 将这些文件下载到某个目录$SQUAD_DIR。 |
利用GPU训练BERT-Large模型 | 目前,由于内存限制,无法在12GB-16GB GPU上复制论文中的最先进SQuAD结果(事实上,即使在使用BERT-Large的12GB GPU上,批次大小为1也似乎不适合)。但是,可以使用以下超参数在GPU上训练相当强大的BERT-Base模型: python run_squad.py \ --vocab_file=$BERT_BASE_DIR/vocab.txt \ --bert_config_file=$BERT_BASE_DIR/bert_config.json \ --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \ --do_train=True \ --train_file=$SQUAD_DIR/train-v1.1.json \ --do_predict=True \ --predict_file=$SQUAD_DIR/dev-v1.1.json \ --train_batch_size=12 \ --learning_rate=3e-5 \ --num_train_epochs=2.0 \ --max_seq_length=384 \ --doc_stride=128 \ --output_dir=/tmp/squad_base/ Dev集的预测将保存到output_dir中的文件predictions.json中: python $SQUAD_DIR/evaluate-v1.1.py $SQUAD_DIR/dev-v1.1.json ./squad/predictions.json 这应该会产生类似于BERT-Base论文中报告的88.5%的结果。 |
利用Cloud TPU训练BERT-Large模型 | 如果您可以访问Cloud TPU,您可以使用BERT-Large进行训练。以下是一组(略有不同于论文的)超参数,这些超参数在单系统仅在SQuAD上训练时一致地获得大约90.5%-91.0% F1: python run_squad.py \ --vocab_file=$BERT_LARGE_DIR/vocab.txt \ --bert_config_file=$BERT_LARGE_DIR/bert_config.json \ --init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \ --do_train=True \ --train_file=$SQUAD_DIR/train-v1.1.json \ --do_predict=True \ --predict_file=$SQUAD_DIR/dev-v1.1.json \ --train_batch_size=24 \ --learning_rate=3e-5 \ --num_train_epochs=2.0 \ --max_seq_length=384 \ --doc_stride=128 \ --output_dir=gs://some_bucket/squad_large/ \ --use_tpu=True \ --tpu_name=$TPU_NAME 例如,使用这些参数的一个随机运行产生以下Dev分数: {"f1": 90.87081895814865, "exact_match": 84.38978240302744} 如果在此之前对TriviaQA进行微调,结果将更好,但您需要将TriviaQA转换为SQuAD json格式。 |
训练BERT-Large模型:基于SQuAD 2.0数据集
下载 | 这个模型也在run_squad.py中实现和文档化。 要在 SQuAD 2.0 上运行,首先需要下载数据集。必要的文件可以在这里找到: train-v2.0.json dev-v2.0.json evaluate-v2.0.py 将这些文件下载到某个目录 $SQUAD_DIR。 |
利用Cloud TPU训练BERT-Large模型 | 在 Cloud TPU 上,可以使用 BERT-Large 运行如下: python run_squad.py \ --vocab_file=$BERT_LARGE_DIR/vocab.txt \ --bert_config_file=$BERT_LARGE_DIR/bert_config.json \ --init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \ --do_train=True \ --train_file=$SQUAD_DIR/train-v2.0.json \ --do_predict=True \ --predict_file=$SQUAD_DIR/dev-v2.0.json \ --train_batch_size=24 \ --learning_rate=3e-5 \ --num_train_epochs=2.0 \ --max_seq_length=384 \ --doc_stride=128 \ --output_dir=gs://some_bucket/squad_large/ \ --use_tpu=True \ --tpu_name=$TPU_NAME \ --version_2_with_negative=True 我们假设您已经将所有内容从输出目录复制到名为 ./squad/ 的本地目录。初始的 dev 集预测将在 ./squad/predictions.json 中,每个问题的没有答案("")和最佳非空答案之间的分数差异将在文件 ./squad/null_odds.json 中。 |
调整预测空答案与非空答案的阈值 | 运行此脚本以调整预测空答案与非空答案的阈值: python $SQUAD_DIR/evaluate-v2.0.py $SQUAD_DIR/dev-v2.0.json ./squad/predictions.json --na-prob-file ./squad/null_odds.json 假设脚本输出 "best_f1_thresh" THRESH。(典型值在 -1.0 到 -5.0 之间)。现在,您可以使用派生的阈值重新运行模型以生成预测,或者您可以从 ./squad/nbest_predictions.json 中提取适当的答案。 python run_squad.py \ --vocab_file=$BERT_LARGE_DIR/vocab.txt \ --bert_config_file=$BERT_LARGE_DIR/bert_config.json \ --init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \ --do_train=False \ --train_file=$SQUAD_DIR/train-v2.0.json \ --do_predict=True \ --predict_file=$SQUAD_DIR/dev-v2.0.json \ --train_batch_size=24 \ --learning_rate=3e-5 \ --num_train_epochs=2.0 \ --max_seq_length=384 \ --doc_stride=128 \ --output_dir=gs://some_bucket/squad_large/ \ --use_tpu=True \ --tpu_name=$TPU_NAME \ --version_2_with_negative=True \ --null_score_diff_threshold=$THRESH |
4、内存问题及其修改建议:max_seq_length=512、train_batch_size、模型类型、优化器Adam、梯度累积技术、梯度检查点技术
简介 | 论文中的所有实验都是在具有 64GB 设备内存的 Cloud TPU 上进行的。因此,如果使用具有 12GB 到 16GB 内存的 GPU,并且使用论文中描述的相同超参数,可能会遇到内存不足的问题。 |
原因 | 影响内存使用的因素包括: max_seq_length: 发布的模型是使用最大序列长度为 512 进行训练的,但您可以使用较短的最大序列长度进行微调,以节省大量内存。这由我们示例代码中的 max_seq_length 标志控制。 train_batch_size: 内存使用也与批量大小成正比。 模型类型,BERT-Base vs. BERT-Large: BERT-Large 模型所需的内存显著多于 BERT-Base。 优化器: BERT 的默认优化器是 Adam,它需要额外的内存来存储 m 和 v 向量。切换到更节省内存的优化器可以减少内存使用,但也可能影响结果。我们没有尝试使用其他优化器进行微调。 使用默认的训练脚本 (run_classifier.py 和 run_squad.py),我们在单个 Titan X GPU(12GB 内存)上使用 TensorFlow 1.11.0 进行了最大批处理大小的基准测试: 不幸的是,对于 BERT-Large,这些最大批处理大小实际上非常小,可能会损害模型的准确性,无论使用何种学习率。我们正在努力添加到该存储库的代码,该代码将允许在 GPU 上使用更大的有效批处理大小。该代码将基于以下一种或两种技术之一: 梯度累积: 小批量中的样本通常在梯度计算方面是独立的(不包括批量归一化,在这里不使用)。这意味着可以在执行权重更新之前累积多个较小的小批量的梯度,这将与单个较大更新完全等效。 梯度检查点: DNN 训练期间 GPU/TPU 内存的主要使用是在前向传递中缓存中间激活,这对于在后向传递中进行高效计算是必要的。 "梯度检查点" 通过以智能方式重新计算激活来以内存换取计算时间。然而,这在当前版本中尚未实现。 |
5、使用BERT提取固定特征向量(类似于ELMo)
简介 | 在某些情况下,与端到端微调整个预训练模型相比,获取预训练上下文嵌入可能更有益,这些嵌入是从预训练模型的隐藏层生成的每个输入标记的固定上下文表示。这也应该减轻大多数内存不足的问题。 |
脚本代码 | 例如,我们包含了可按以下方式使用的脚本 extract_features.py: # Sentence A and Sentence B are separated by the ||| delimiter for sentence # pair tasks like question answering and entailment. # For single sentence inputs, put one sentence per line and 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的最终隐藏层等)。 |
注意事项 | 请注意,此脚本将生成非常大的输出文件(默认情况下,每个输入标记约为15KB)。 如果需要保持原始词和标记化词之间的对齐(用于投影训练标签),请参阅下面的标记化部分。 注意:您可能会看到一条消息,例如 Could not find trained model in model_dir: /tmp/tmpuB5g5c, running initialization to predict。这是正常的,它只是表示我们正在使用 init_from_checkpoint() API 而不是 saved model API。如果您不指定检查点或指定无效的检查点,此脚本将发出警告。 |
6、标记化
句子级任务标记化 | 对于句子级任务(或句子对任务),标记化非常简单。只需按照 run_classifier.py 和 extract_features.py 中的示例代码操作。句子级任务的基本步骤是: >> 实例化 tokenizer = tokenization.FullTokenizer 的实例。 >> 使用 tokens = tokenizer.tokenize(raw_text) 对原始文本进行标记化。 >> 截断到最大序列长度。(您可以使用最多512个,但出于内存和速度原因,如果可能的话可能希望使用较短的长度。) >> 在正确的位置添加 [CLS] 和 [SEP] 标记。 |
单词级标记化 | 由于单词级和跨度级任务(例如SQuAD和NER)更为复杂,因为您需要保持输入文本和输出文本之间的对齐,以便可以投影训练标签。SQuAD是一个特别复杂的例子,因为输入标签是基于字符的,并且SQuAD段落通常比我们的最大序列长度长。请查看 run_squad.py 中的代码,以了解我们如何处理这种情况。 |
单词级任务标记化三步骤 | 在描述处理单词级任务的一般方法之前,了解我们的标记器实际上在做什么是很重要的。它有三个主要步骤: >> 文本规范化:将所有空白字符转换为空格,并且(对于Uncased模型)将输入小写并去除重音标记。例如,John Johanson's, → john johanson's,。 >> 标点拆分:在两侧分割所有标点字符(即,在所有标点字符周围添加空格)。标点字符定义为(a)任何具有P* Unicode类的内容,(b)任何非字母/数字/空格ASCII字符(例如,技术上不是标点符号的字符,如 $)。例如,john johanson's, → john johanson ' s, >> WordPiece标记化:对上述过程的输出应用空格标记化,并对每个标记单独应用WordPiece标记化。(我们的实现直接基于来自tensor2tensor的实现,链接在文中)。例如,john johanson ' s, → john johan ##son ' s, 这种方案的优势在于它与大多数现有的英语标记器是“兼容的”。 |
案例理解 | 例如,想象一下您有一个词性标注任务,看起来像这样: 输入:John Johanson 's house 标签:NNP NNP POS NN 标记化的输出将如下所示: 标记:john johan ##son ' s house 关键是,这与原始文本是John Johanson's house('s之前没有空格)的情况下的输出相同。 如果您有一个预先标记化的表示,其中包含单词级注释,您只需独立标记化每个输入单词,并确定性地保持原始到标记化的对齐: ### 输入 orig_tokens = ["John", "Johanson", "'s", "house"] labels = ["NNP", "NNP", "POS", "NN"] ### 输出 bert_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 可以用于将标签投影到标记化的表示。有一些常见的英语标记方案可能会导致BERT的预训练稍有不匹配。 例如,如果您的输入标记将缩写词分开,如 do n't,这将导致不匹配。如果可能的话,您应该预处理数据以将其转换回原始的文本形式,但如果不可能,这种不匹配可能并不是什么大问题。 |
7、使用BERT进行预训练
MLM和NSP代码
MLM和NSP代码 | 我们发布了在任意文本语料库上执行“掩码语言建模”和“下一句预测”的代码。请注意,这不是用于论文的确切代码(原始代码是用C++编写的,并且有一些额外的复杂性),但该代码确实生成了论文中描述的预训练数据。 |
数据生成
数据生成 | 以下是如何运行数据生成的方法。 输入是一个纯文本文件,每行一个句子。(对于“下一句预测”任务,这些应该是实际的句子)。文档由空行分隔。输出是一组序列化为TFRecord文件格式的tf.train.Examples。 您可以使用现成的NLP工具包(如spaCy)执行句子分割。create_pretraining_data.py脚本将连接段,直到达到最大序列长度,以最小化来自填充的计算浪费(有关更多详细信息,请参见脚本)。但是,您可能希望故意向输入数据添加轻微的噪音(例如,随机截断2%的输入段),以使其在微调期间对非句子输入更加鲁棒。 此脚本将内存中的整个输入文件的所有示例存储起来,因此对于大型数据文件,您应该对输入文件进行分片并多次调用脚本。(您可以向 run_pretraining.py 传递文件通配符,例如 tf_examples.tf_record*。) max_predictions_per_seq 是每个序列的最大掩码语言模型预测数。您应该将其设置为约为 max_seq_length * masked_lm_prob(脚本不会自动执行此操作,因为确切的值需要传递给两个脚本)。 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 |
运行预训练
运行预训练 | 以下是如何运行预训练的方法。 如果从头开始预训练,请不要包括 init_checkpoint。模型配置(包括词汇大小)在 bert_config_file 中指定。此演示代码仅进行了少量步骤(20)的预训练,但在实际应用中,您可能需要设置 num_train_steps 为10000步或更多。传递给 run_pretraining.py 的 max_seq_length 和 max_predictions_per_seq 参数必须与 create_pretraining_data.py 相同。 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 |
这将产生类似于以下的输出: ***** 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 请注意,由于我们的 sample_text.txt 文件非常小,此示例训练将在很少的步骤中过度拟合该数据,并产生不现实的高准确性数字。 | |
预训练提示和注意事项
简介 | >> 如果使用自定义词汇表,请确保在bert_config.json中更改vocab_size。如果不更改此值而使用较大的词汇表,则在GPU或TPU上进行训练时可能会由于未经检查的越界访问而得到NaN。 >> 如果您的任务有一个大型领域特定的语料库(例如,“电影评论”或“科学论文”),在BERT检查点开始时运行额外的预训练步骤可能会有益。 >> 我们在论文中使用的学习率为1e-4。但是,如果您从现有的BERT检查点开始执行额外的预训练步骤,您应该使用较小的学习率(例如2e-5)。 >> 当前的BERT模型仅支持英语,但我们计划在不久的将来发布一个多语言模型,该模型已在许多语言上进行了预训练(希望在2018年11月底之前)。 >> 较长的序列成本相对昂贵,因为注意力与序列长度的平方成正比。换句话说,长度为512的64个序列的批次比长度为128的256个序列的批次要显着昂贵得多。全连接/卷积成本相同,但是对于512长度的序列,注意力成本要高得多。因此,一个很好的方法是预训练,例如,90,000步,序列长度为128,然后额外进行10,000步,序列长度为512。非常长的序列主要用于学习位置嵌入,这可以相当快速地学到。请注意,这确实需要使用不同的max_seq_length两次生成数据。 >> 如果您正在从头开始进行预训练,请准备好预训练是计算密集型的,特别是在GPU上。如果您从头开始预训练,我们推荐的方法是在单个可抢占的Cloud TPU v2上预训练BERT-Base,大约需要2周,成本约为500美元(基于2018年10月的定价)。当仅在单个Cloud TPU上进行培训时,必须缩小批量大小,与论文中使用的相比。建议使用适应于TPU内存的最大批量大小。 |
预训练数据
简介 | 我们将无法发布论文中使用的预处理数据集。对于Wikipedia,建议的预处理方法是下载最新的转储,使用WikiExtractor.py提取文本,然后进行任何必要的清理以将其转换为纯文本。 不幸的是,收集BookCorpus的研究人员不再提供公共下载。Project Guttenberg Dataset 是一个相对较小的(200M字)由公共领域中的旧书组成的集合。 Common Crawl 是另一个非常庞大的文本集合,但您可能需要进行大量的预处理和清理以提取可用于BERT预训练的语料库。 |
学习新的WordPiece词汇
简介 | 此存储库不包含学习新WordPiece词汇的代码。原因是论文中使用的代码是用C++编写的,依赖于Google内部库。对于英语,最好的方法几乎总是从我们的词汇表和预训练模型开始。对于学习其他语言的词汇,有许多开源选项可用。但请记住,这些与我们的tokenization.py库不兼容: Google的SentencePiece库 tensor2tensor的WordPiece生成脚本 Rico Sennrich的Byte Pair Encoding库 |
8、在Colab中使用BERT
如果要在Colab中使用BERT,可以使用笔记本“BERT FineTuning with Cloud TPUs”开始。在撰写本文时(2018年10月31日),Colab用户可以免费完全访问Cloud TPU。注意:每个用户限制一个,可用性有限,需要具有存储(尽管存储可以通过使用GCP签署免费信用额度购买)的Google Cloud Platform帐户,并且此功能可能在将来不再可用。单击刚刚链接的BERT Colab以获取更多信息。
BERT的案例应用
1、基础用法
NLP之TextSimil:基于两份文档数据分别利用基于统计的词袋模型(词频/TF-IDF)、词嵌入模型(Word2Vec/GloVe)、神经网络(CNN/RNN学习文档表示)、预训练模型(BERT文档的嵌入表示)结合余弦相似度实现文本相似度计算
https://yunyaniu.blog.csdn.net/article/details/102761640
NLP之TM:基于多个文本数据(BertTokenizer)利用BERT预训练模型(transformers)结合K-means均值聚类算法对文本向量进行聚类实现主题模型进而转为结构化数据应用案例
https://yunyaniu.blog.csdn.net/article/details/131137563
NLP:利用spacy的en_trf_bertbaseuncased_lg预训练语言模型实现四种底层基本任务—词法分析(词向量)、语义分析(语义解析)、信息抽取(命名实体识别NER)应用案例实现代码
https://yunyaniu.blog.csdn.net/article/details/131139397
NLP之TextSimil:基于两份文档(分词和编码)利用预训练模型(BERT)获取文档的嵌入表示再利用余弦相似度法来计算相似度实现代码
https://yunyaniu.blog.csdn.net/article/details/131237290
2、进阶用法
PT之BERT:基于torch框架(特征编码+BERT作为文本编码器+分类器)针对UCI新闻数据集利用Transformer-BERT算法(模型实时保存)实现新闻文本多分类案例
https://yunyaniu.blog.csdn.net/article/details/110734484
NLP之ModelScope:基于ModelScope框架的afqmc数据集利用StructBERT预训练模型的文本相似度算法实现文本分类任务图文教程之详细攻略
https://yunyaniu.blog.csdn.net/article/details/127355662
LLMs之spaCy:利用spaCy管道训练大模型案例—对预训练的BERT、XLNet和GPT-2实现图文教程之详细攻略
https://yunyaniu.blog.csdn.net/article/details/131137465
LLMs之BERT:基于spaCy框架利用预训练Transformer(如BERT)进行多任务学习(添加自定义任务—文本情感分类)训练并进行模型打包和模型推理应用案例实现代码
https://yunyaniu.blog.csdn.net/article/details/131160611