BERT简介及中文分类

介绍来自bert的github资料翻译,水平有限

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

为了学习句子间的关系,我们也训练了一个简单的任务,能后用任何一种单语言语料:给出两个句子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

然后我们花了很长时间在大语料(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/

得到如下结果:

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

意思是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/

中文分类实践

下载中文预训练模型

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

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

label1 \t text1
label1 \t text2
label2 \t text3
......

查看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

可以看到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"]

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

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

  processors = {
      "cola": ColaProcessor,
      "mnli": MnliProcessor,
      "mrpc": MrpcProcessor,
      "xnli": XnliProcessor,
      "chi": ChiProcessor,
  }

添加后,可通过–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

–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/

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

扩展阅读

  • 13
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
BERT(Bidirectional Encoder Representations from Transformers)是一种自然语言处理模型,由Google在2018年提出并开源。它能够学习出句子的语义表示,因此可以应用于各种NLP任务,其中包括中文情感分类中文情感分类是指针对中文文本的情感分析任务,需要将中文文本划分为积极、消极或中性等情感类别。使用BERT进行中文情感分类的流程如下: 首先,我们需要将文本进行预处理,包括分词、去除停用词等。中文文本通常较长,因此可能还需要进行截断或填充以保证输入文本的长度一致。 然后,我们将预处理后的文本输入到BERT模型中。BERT模型会将文本转化为词向量,并经过多层Transformer网络进行进一步的特征提取和表示学习。 在BERT模型的输出层,我们可以引入一个分类器,例如全连接层,来对文本进行情感分类。这个分类器会根据学习到的文本表示,预测文本的情感类别。 为了训练BERT模型进行中文情感分类,我们需要使用标注有情感类别的大规模中文文本数据集进行有监督的训练。通过反向传播算法,不断调整BERT模型的参数,使得模型能够准确地预测中文文本的情感类别。 在模型训练完成后,我们可以使用训练好的BERT模型对新的中文文本进行情感分类预测。将新的中文文本输入到BERT模型中,得到其对应的文本表示,然后通过分类器进行情感分类预测。 总之,BERT模型可以用于中文情感分类,通过学习中文文本的语义表示,并结合分类器,可以实现对中文文本的情感类别预测。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值