NLP理论基础和实践Task07 BERT

一、Transformer的原理

参考文献 https://www.jianshu.com/p/e40dad747651
基于假设:一个词在句子中的意思,与上下文(语境)有关。与哪些词有关呢?Transformer就是:利用点积将句子中所有词的影响当成权重都考虑了进去。
在这里插入图片描述
Transform模型是与RNN和CNN都完全不同的思路。相比Transformer,RNN/CNN的问题:

  1. RNN序列化处理效率提不上去。理论上,RNN效果上问题不大。
  2. CNN感受野小。CNN只考虑卷积核大小区域,核内参数共享,并行/计算效率不是问题,但受限于核的大小,不能考虑整个上下文。

在并行方面,多头attention和CNN一样不依赖于前一时刻的计算,可以很好的并行,优于RNN。在长距离依赖上,由于self-attention是每个词和所有词都要计算attention,所以不管他们中间有多长距离,最大的路径长度也都只是1。可以捕获长距离依赖关系。

二、BERT的原理

参考文献 https://www.cnblogs.com/huangyc/p/9898852.html
BERT模型的全称是Bidirectional Encoder Representations from Transformers,它是一种新型的语言模型。之所以说是一种新型的语言模型,是因为它通过联合调节所有层中的双向Transformer来训练预训练深度双向表示。

想深入了解BERT模型,首先应该理解语言模型。预训练的语言模型对于众多自然语言处理问题起到了重要作用,比如SQuAD问答任务、命名实体识别以及情感识别。目前将预训练的语言模型应用到NLP任务主要有两种策略,一种是基于特征的语言模型,如ELMo模型;另一种是基于微调的语言模型,如OpenAI GPT。这两类语言模型各有其优缺点,而BERT的出现,似乎融合了它们所有的优点,因此才可以在诸多后续特定任务上取得最优的效果。

BERT模型总体结构

BERT是一种基于微调的多层双向Transformer编码器,其中的Transformer与原始的Transformer是相同的,并且实现了两个版本的BERT模型,在两个版本中前馈大小都设置为4层:

lBERTBASE:L=12,H=768,A=12,Total Parameters=110M

lBERTLARGE:L=24,H=1024,A=16,Total Parameters=340M

其中层数(即Transformer blocks块)表示为L,隐藏大小表示为H,自注意力的数量为A。
BERT模型输入
输入表示可以在一个词序列中表示单个文本句或一对文本(例如,[问题,答案])。对于给定的词,其输入表示是可以通过三部分Embedding求和组成。Embedding的可视化表示如下图所示:
在这里插入图片描述

  • token Embeddings表示的是词向量,第一个单词是CLS标志,可以用于之后的分类任务,对于非分类任务,可以忽略词向量;
  • Segment Embeddings用来区别两种句子,因为预训练不只做语言模型还要做以两个句子为输入的分类任务;
  • Position Embeddings是通过模型学习得到的。

三、利用预训练的BERT模型将句子转换为句向量,进行文本分类

参考文献: https://www.cnblogs.com/jiangxinyang/p/10241243.html
https://www.jiqizhixin.com/articles/2019-03-13-4
1、下载源码 git clone https://github.com/google-research/bert.git
2、 下载bert预训练模型
Google提供了多种预训练好的bert模型,有针对不同语言的和不同模型大小的。对于中文模型,我们使用Bert-Base, Chinese。为了下载该模型,可能需要使用梯子。如果需要下载其他的模型(英文以及其他语言),可以在Bert里的Pre-trained models找到下载链接。
3、准备数据
作为中文文本分类问题,需要先将数据集整理成可用的形式。不同的格式对应了不同的DataProcessor类。可以将数据保存成如下格式:

game APEX是个新出的吃鸡游戏。
technology Google将要推出tensorflow2.0。

一行代表一个文本,由标签加上一个tab加上正文组成。

将文本分割为三个文件,train.tsv(训练集),dev.tsv(验证集),test.tsv(测试集);然后放置在同一个data_dir文件夹下。
4、 编写DataProcessor类
在bert文件夹下的“run_classifier.py**中的”def main(_):”函数中将processors的内容增加为

python

processors = {

     "cola": ColaProcessor,

     "mnli": MnliProcessor,

     "mrpc": MrpcProcessor,

     "xnli": XnliProcessor,

     "mytask": MyTaskProcessor,

 }

实现如下的“MyTaskProcessor

(DataProcessor)”类,并将这一段代码放置在“run_classifier.py”和其他Processor并列的位置。
“__init__(self)”中的self.labels含有所有的分类label,在这个例子中我们将文本可能分为3类:game, fashion, houseliving。

python

class MyTaskProcessor(DataProcessor):

   """Processor for the News data set (GLUE version)."""

   def __init__(self):

       self.labels = ['game', 'fashion', 'houseliving']

  

   def get_train_examples(self, data_dir):

       return self._create_examples(

           self._read_tsv(os.path.join(data_dir, "train.tsv")), "train")

   def get_dev_examples(self, data_dir):

       return self._create_examples(

           self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")

   

   def get_test_examples(self, data_dir):

       return self._create_examples(

           self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")

   def get_labels(self):

       return self.labels

   def _create_examples(self, lines, set_type):

       """Creates examples for the training and dev sets."""

       examples = []

       for (i, line) in enumerate(lines):

           guid = "%s-%s" % (set_type, i)

           text_a = tokenization.convert_to_unicode(line[1])

           label = tokenization.convert_to_unicode(line[0])

           examples.append(

               InputExample(guid=guid, text_a=text_a, text_b=None, label=label))

       return examples

如果数据格式并不是一个label,一个tab,一段文本;则需要更改“_create_examples()”的实现。
5、编写运行脚本
新建一个运行脚本文件名为“run.sh”,将文件内容编辑为:

bash

export DATA_DIR=/media/ganjinzero/Code/bert/data/

export BERT_BASE_DIR=/media/ganjinzero/Code/bert/chinese_L-12_H-768_A-12

python run_classifier.py \

 --task_name=mytask \

 --do_train=true \

 --do_eval=true \

 --data_dir=$DATA_DIR/ \

 --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=/mytask_output

其中DATA_DIR是你的要训练的文本的数据所在的文件夹,BERT_BASE_DIR是你的bert预训练模型存放的地址。task_name要求和你的DataProcessor类中的名称一致。下面的几个参数,do_train代表是否进行fine tune,do_eval代表是否进行evaluation,还有未出现的参数do_predict代表是否进行预测。如果不需要进行fine tune,或者显卡配置太低的话,可以将do_trian去掉。max_seq_length代表了句子的最长长度,当显存不足时,可以适当降低max_seq_length。
6、进行预测
运行脚本bash ./run.sh
可以得到类似如下样式的结果

***** Eval results *****
eval_accuracy = 0.845588
eval_loss = 0.505248
global_step = 343
loss = 0.505248

如果出现了这样的输出,就是运行成功了。在“run.sh”里指定的output_dir文件夹下可以看到模型的evaluation结果和fine-tune(微调)之后的模型文件。

发布了8 篇原创文章 · 获赞 0 · 访问量 246

猜你喜欢

转载自blog.csdn.net/weixin_40299430/article/details/99990470