爱笑的小姐姐 · 2021年05月31日

深度学习-7.bert使用

本文转自:知乎
作者:djh

在2018年,如果nlp最有成功的要属于bert了。它刷新了很多记录,因此我尝试拿来使用,看对我最近文本分类有没有提高,或者帮助。

bert是迁移学习很好的例子。源码在github上已经开源。

https://github.com/google-research/bert

我们今天有两个方面的内容需要讲解,一个是我们如何使用bert进行一个多文本分类,另外一个是理解bert迁移学习的原理。

对于bert本身模型的理解今天不会涉及到,模型太过强大,想要梳理清楚细枝末节需要很长时间,今天只是梳理下,迁移模型的部分。

使用bert进行多分类

前期准备:

BERT-Base, Uncased: 12-layer, 768-hidden, 12-heads, 110M parameters 
BERT-Large, Uncased: 24-layer, 1024-hidden, 16-heads, 340M parameters 
BERT-Base, Cased: 12-layer, 768-hidden, 12-heads , 110M parameters 
BERT-Large, Cased: 24-layer, 1024-hidden, 16-heads, 340M parameters
BERT-Base, Multilingual Cased (New, recommended): 104 languages, 12-layer, 768-hidden, 12-heads, 110M parameters
BERT-Base, Multilingual Uncased (Orig, not recommended) (Not recommended, use Multilingual Cased instead): 102 languages, 12-layer, 768-hidden, 12-heads, 110M parameters
BERT-Base, Chinese: Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters Each .zip file contains three items: 

我们选择中文的,下载下来是一个zip chinese\_L-12\_H-768\_A-12.zip

  • 3.最后准备我们自己的训练数据。

讲上述数据都一并放到源码包目录下。

代码书写运行

现在我们开始写需要的配置代码。打开run\_classifier.py

是bert模型运行的主要文件,配置好需要的东西后就能运行。这里我们写一个sh脚本文件进行配置,配置如下。

python run_classifier.py \
   --data_dir=./dataset \
   --task_name=youself \
   --vocab_file=./chinese_L-12_H-768_A-12/vocab.txt \
   --bert_config_file=./chinese_L-12_H-768_A-12/bert_config.json \
   --output_dir=./output/ \
   --do_train=true \
   --do_predict=true \
   --do_eval=false \
   --init_checkpoint=./chinese_L-12_H-768_A-12/bert_model.ckpt \
   --max_seq_length=200 \
   --train_batch_size=16 \
   --learning_rate=5e-5 \
   --num_train_epochs=5.0 

主要的是:

1、指定预训练模型的路径和配置文件路径也就是刚才下载的chinese\_L-12\_H-768\_A-12.zip
2、指定一些do\_train 和 do\_predict 等等,按照你需要的配置
3、指定你自己的训练数据,这边的训练数据的格式是有规定的,源码中的是cvs,文本在前面标签在后面。

但是这里我们先放着,我们等下通过修改run\_classifier.py,的输入数据格式,进行。如果你不想按照他们的格式进行,就可以按照我的方法。修改如下:

class YouSelProcessor(DataProcessor):
   def get_train_examples(self, data_dir):
     return self._create_examples(
         self._read_txt(os.path.join(data_dir, "train.txt")), "train")
    def get_dev_examples(self, data_dir):
     return self._create_examples(
         self._read_txt(os.path.join(data_dir, "dev_matched.txt")),
         "dev_matched")
    def get_test_examples(self, data_dir):
     return self._create_examples(
         self._read_tsv(os.path.join(data_dir, "test_matched.txt")), "test")
    def get_labels(self):
     return ["1", "2", "3"]
    def _create_examples(self, lines, set_type):
     examples = []
     for (i, line) in enumerate(lines):
         line = convertYouselfLine(line) 
      if i == 0:
         continue
       guid = "%s-%s" % (set_type, tokenization.convert_to_unicode(line[0]))
       text_a = tokenization.convert_to_unicode(line[1])
       label = tokenization.convert_to_unicode(line[2])
       examples.append(
           InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
     return examples 

通过写自己的数据结构,自己定义一个类进行转换成他们要的数据类型。

然后再main函数中添加,

  processors = {
       "cola": ColaProcessor,
       "mnli": MnliProcessor,
       "mrpc": MrpcProcessor,
       "xnli": XnliProcessor, 
      "youself": YouSelProcessor
   } 

然后就可以按照这个数据进行运行了。

运行结果

运行完成后可以看到log,

 INFO:tensorflow:  eval_accuracy = 0.9527627
 INFO:tensorflow:  eval_loss = 0.27245617
 INFO:tensorflow:  global_step = 12185
 INFO:tensorflow:  loss = 0.27232203 

这个准确率还是可以的比我原来的提高了很多。

理解bert的finetuning

那么如何理解bert的finetuning呢?其实所有的迁移都是一样的,比如我上次讲的

就是将已经弄好的东西在此加载进来,然后再前级能有个过滤,形成一个好的特征。那么我们这边前级的特征的模型Google已经提供给我们了chinese\_L-12\_H-768\_A-12,这个模型数据还挺大的。我们看下它是怎么迁入到我们现在的训练中的。代码如下。

if init_checkpoint:
       (assignment_map, initialized_variable_names
       ) = modeling.get_assignment_map_from_checkpoint(tvars, init_checkpoint)
       if use_tpu:
          def tpu_scaffold():
           tf.train.init_from_checkpoint(init_checkpoint, assignment_map)
           return tf.train.Scaffold()
          scaffold_fn = tpu_scaffold
       else:
         tf.train.init_from_checkpoint(init_checkpoint, assignment_map)
 

init\_checkpoint 就是我们指定与训练模型的位置,chinese\_L-12\_H-768\_A-12。

modeling.get\_assignment\_map\_from\_checkpoint,函数会检查以及加载chinese\_L-12\_H-768\_A-12模型里的变量和参数形成一个map。然后tf.train.init\_from\_checkpoint对这个里面的参数进行初始化。

也就是说在你运行的时候,model里面的变量,通过上面的步骤就已经模块化了一次了,接下来你再次训练,就是从上次的过程中继续往下,或者你也可以说直接不训练了,在以前的模型上直接使用,就像我上文

一样。只是用一个wb模型,然后进行分类认为,其实他们已经写好了:

output_weights = tf.get_variable(
       "output_weights", [num_labels, hidden_size],
       initializer=tf.truncated_normal_initializer(stddev=0.02))
    output_bias = tf.get_variable(
       "output_bias", [num_labels], initializer=tf.zeros_initializer())

    with tf.variable_scope("loss"):
     if is_training:
       # I.e., 0.1 dropout
       output_layer = tf.nn.dropout(output_layer, keep_prob=0.9)

      
     logits = tf.matmul(output_layer, output_weights, transpose_b=True)
     logits = tf.nn.bias_add(logits, output_bias)
     probabilities = tf.nn.softmax(logits, axis=-1)
     log_probs = tf.nn.log_softmax(logits, axis=-1)
     
      one_hot_labels = tf.one_hot(labels, depth=num_labels, dtype=tf.float32)
      per_example_loss = -tf.reduce_sum(one_hot_labels * log_probs, axis=-1)     loss = tf.reduce_mean(per_example_loss) 

在模型创建的时候已经写好了,如果你训练了 就在上面的配置文件中把do\_training 标志成false。

以上就是我对bert迁移部分的理解。说的很简单,但是要深入了解还是需要一些思考和时间的。

其他

关注我不迷路,目前只是一些入门级的小文章,后面会有AI系列文章推送。

https://github.com/yazone/ai_learning_path
更多嵌入式AI技术相关内容请关注嵌入式AI专栏。
推荐阅读
关注数
16430
内容数
1228
嵌入式端AI,包括AI算法在推理框架Tengine,MNN,NCNN,PaddlePaddle及相关芯片上的实现。欢迎加入微信交流群,微信号:aijishu20(备注:嵌入式)
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息