当前位置:   article > 正文

BERT简介及中文分类_bert 中文分类

bert 中文分类

介绍来自bertgithub资料翻译,水平有限

BERT是什么

BERT是一种预训练语言表示的方法,在大量文本语料(维基百科)上训练了一个通用的“语言理解”模型,然后用这个模型去执行想做的NLP任务。BERT比之前的方法表现更出色,因为它是第一个用在预训练NLP上的无监督的、深度双向系统。

无监督意味着BERT只需要用纯文本语料来训练,这点非常重要,因为海量的文本语料可以在各种语言的网络的公开得到。

预训练表示可以是上下文无关的,也可以是上下文相关的,而且,上下文相关的表示可以是单向的或双向的。上下文无关模型例如word2vec或GloVe可以为词表中的每一个词生成一个单独的“词向量”表示,所以“bank”这个词在“bank deposit”(银行)和“river bank”(岸边)的表示是一样的。上下文相关的模型会基于句子中的其他词生成每一个词的表示。

BERT建立在最近的预训练相关表示工作之上——Semi-supervised Sequence Learning, Generative Pre-Training, ELMo,和ULMFit——但是关键是这些模型都是单向的或浅双向的。这以为意味着每个词之和它左边或右边的词相关。例如,在句子“I made an bank deposit”中,“bank”的单向表示只基于“I made a”而没有“deposit”。一些以前的工作也有结合了单独的左上下文和右上下文的,但只是用了一种简单的方式。BERT同时用左边和右边内容表示“bank”——“I made a … deposit”——从一个深度网络非常底层就开始了,所以说,他是deeply bidirectional(深层双向)的。

BERT用了一种简单的方法:我们遮蔽了输入的15%的单词,通过一个深层的双向transformer Encoder来运行整个序列,然后只预测被遮蔽的单词。

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

为了学习句子间的关系,我们也训练了一个简单的任务,能后用任何一种单语言语料:给出两个句子A和B,B是A的下一句,或者是语料中的两个随机句子?

Sentence A: the man went to the store .
Sentence B: he bought a gallon of milk .
Label: IsNextSentence
Sentence A: the man went to the store .
Sentence B: penguins are flightless .
Label: NotNextSentence
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后我们花了很长时间在大语料(Wikipedia + BookCorpus)上训练了一个大模型(12层到24层的Transformer),这就是BERT。

使用BERT后两个步骤:Pre-training和fine-tuning

Pre-training相当昂贵(四天,4到16台TPU),但每种语言是一次性程序(最近的模型只有英语,但多语言模型近期会发布)。我们正在发布大量的google论文中被训练的pre-trained模型。这样,多数NLP研究者将不用从最底层去训练模型。

Fine-tunin不昂贵。论文中的所有结果从相同的预训练模型开始,可以在一台单独的云TPU上一小时就可以复现,或者在GPU上需要几个小时。例如,SQuAD,任务,在一台单独的TPU上训练30分钟就可以达到F2值91%,这是一个经典的单系统。

BERT另一个重要的方面是,他极容易被用于多种NLP任务。论文中,我们展示了经典的结果 sentence-level (e.g., SST-2), sentence-pair-level (e.g., MultiNLI), word-level (e.g., NER), and span-level (e.g., SQuAD)他们都没修改过任务。

BERT调优

重点:论文中所有的结果是在一台64G RAM的TPU上调优的。所以用一台12-16GRAM的GPU去复现论文中BERT-Large的结果是不可能,因为,能fit到内存里的最大batch size太小了。我们正在努力提交代码能允许在GPU上用更大的batch size。详情看out of memory issues.

代码在TensorFlow1.11.0上测试,用python2 和python3(用python2更多,因为google内部用python2更多)。

用Bert-Base调优的例子用给定的超参数可以运行在至少12G内存的GPU上。

句子(对)分类任务

运行这个例子之前,你需要运行脚本下载GLUE数据集,并解压到$GLUE_DIR,然后,下载BERT-Base并解压到目录$BERT_BASE_DIR
这个例子对BERT-Base在MRPC(包括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/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

得到如下结果:

***** Eval results *****
  eval_accuracy = 0.845588
  eval_loss = 0.505248
  global_step = 343
  loss = 0.505248
  • 1
  • 2
  • 3
  • 4
  • 5

意思是Dev准确度为84.55%,像MRPC这样的小数据集有一个高方差在准确度上,即使是从相同的checkpoint上开始训练。如果训练多次(输出到不同的out_dir),你会发现结果再84%到88%之间。

一些其他的预训练模型在run_classifier.py上直接执行,所以按照这些例子去用BERT执行但句子或句子对分类任务特别直接明了。

提示:你可能看到了一条信息 Running train on CPU。这只是说明他挣运行在一些出云TPU以外的机器上,包括GPU。

分类器预测

训练好了分类器,就可以用与预测模式,通过 --do_predice=true命令。输入文件夹需要有一个test.tsv文件。输出被写在了输出文件夹中的test_results.tsv文件中。每行包括一个样例的输出,列为类别概率

export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12export GLUE_DIR=/path/to/glueexport 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/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

中文分类实践

下载中文预训练模型

git上下载代码,并下载中文预训练模型

代码解压,模型解压,模型文件包括:
bert_config.json
bert_model.ckpt.data-00000-of-00001
bert_model.ckpt.index
bert_model.ckpt.meta
vocab.txt
看了下vocab.txt,一共两万多个,汉字简体+繁体显然没那么多,有一些英文字符,无意义字符串等

修改run_classifier.py

  1. 重载DataProcessor类
    按照自己文件的格式改写DataProcessor类,需要重写一下几个函数:
class ChiProcessor(DataProcessor):
  """ Processor for chinese multi-classes data set"""
  def __init__(self):
      self.labels = set()

  def get_train_examples(self, data_dir):
    """See base class."""
    return self._create_examples(self._read_tsv(os.path.join(data_dir, "train.tsv")), "train")

  def get_test_examples(self, data_dir):
    """See base class."""
    return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")

  def get_dev_examples(self, data_dir):
    """See base class."""
    return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")

  def get_labels(self, data_dir):
    lines = self._read_tsv(os.path.join(data_dir, "train.tsv"))
    for line in lines:
      label = tokenization.convert_to_unicode(line[0])
      self.labels.add(label)
    return list(self.labels)

  def _create_examples(self, lines, set_type):
    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])
      self.labels.add(label)
      examples.append(InputExample(guid=guid, text_a=text_a, text_b=None, label=label))

    return examples

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

_read_tsv()函数可直接使用;新建_create_examples函数用来将读取的数据转化为InputExample格式。
我自己的train.tsv,格式如下:

label1 \t text1
label1 \t text2
label2 \t text3
......
  • 1
  • 2
  • 3
  • 4

查看InputExample类,定义如下:

class InputExample(object):
  """A single training/test example for simple sequence classification."""

  def __init__(self, guid, text_a, text_b=None, label=None):
    """Constructs a InputExample.

    Args:
      guid: Unique id for the example.
      text_a: string. The untokenized text of the first sequence. For single
        sequence tasks, only this sequence must be specified.
      text_b: (Optional) string. The untokenized text of the second sequence.
        Only must be specified for sequence pair tasks.
      label: (Optional) string. The label of the example. This should be
        specified for train and dev examples, but not for test examples.
    """
    self.guid = guid
    self.text_a = text_a
    self.text_b = text_b
    self.label = label
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

可以看到text_b,和label为可选。
在处理分类问题是,text_a为分类文本,label为类标;在处理文本相似性问题是,text_a为文本1,text_b为文本2,label为是否相似标记;相似问题可抽象为二分类问题。
def get_labels函数,为获取分类类标列表,在分类数少的情况下可以直接给出,如:

  def get_labels(self):
    """See base class."""
    return ["0", "1"]
  • 1
  • 2
  • 3

分类较多的情况下,可以按照上面的代码读取train文件中的类标,或者直接把类标写入一个文件进行读取。
2. 在主函数中添加processor

def main(_):
  tf.logging.set_verbosity(tf.logging.INFO)

  processors = {
      "cola": ColaProcessor,
      "mnli": MnliProcessor,
      "mrpc": MrpcProcessor,
      "xnli": XnliProcessor,
      "chi": ChiProcessor,
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

添加后,可通过–task_name=chi调用ChiProcessor读取训练验证测试文件。

训练

在data文件,下准备train.tsv, dev.tsv, test.tsv文件。运行:

export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12
export DATA_DIR=/path/to/data

python run_classifier_mine.py \
--task_name=chi \
--do_train=true \
--do_eval=true  \
--do_predict=false \
--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=/path/to/output
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

–do_train、–do_eval、–do_predict需至少有一个为true。–do_predict=true时,需要准备test.tsv,预测的结果也会一并写入–output_dir目录下。

预测

export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12
export DATA_DIR=/path/to/data
# TRAINED_CLASSIFIER为刚刚训练的输出目录,无需在进一步指定模型模型名称,否则分类结果会不对
export TRAINED_CLASSIFIER=/path/to/fine/tuned/classifier

python run_classifier.py \
  --task_name=chi \
  --do_predict=true \
  --data_dir=$DATA_DIR \
  --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/output/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

预测结果会写入–output_dir目录,格式:每行为一条数据的预测记过,每列为每个类别的概率。

扩展阅读

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/352698
推荐阅读
相关标签
  

闽ICP备14008679号