迁移学习:实战bert使用和理解

  • A+
所属分类:深度学习
摘要

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

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

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

我们今天有两个方面的内容需要讲解,一个是我们如何使用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

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

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

迁移学习:实战bert使用和理解

 

代码书写运行

现在我们开始写需要的配置代码。打开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的迁移

那么如何理解bert的迁移呢?其实所有的迁移都是一样的,比如我上次讲的《实战学习入门对Inception-v3进行引用》。

就是将已经弄好的东西在此加载进来,然后再前级能有个过滤,形成一个好的特征。那么我们这边前级的特征的模型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里面的变量,通过上面的步骤就已经模块化了一次了,接下来你再次训练,就是从上次的过程中继续往下,或者你也可以说直接不训练了,在以前的模型上直接使用,就像我上文《实战学习入门对Inception-v3进行引用》一样。只是用一个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迁移部分的理解。

说的很简单,但是要深入了解还是需要一些思考和时间的。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: