本文转自:知乎
作者:djh
在2018年,如果nlp最有成功的要属于bert了。它刷新了很多记录,因此我尝试拿来使用,看对我最近文本分类有没有提高,或者帮助。
bert是迁移学习很好的例子。源码在github上已经开源。
https://github.com/google-research/bert。
我们今天有两个方面的内容需要讲解,一个是我们如何使用bert进行一个多文本分类,另外一个是理解bert迁移学习的原理。
对于bert本身模型的理解今天不会涉及到,模型太过强大,想要梳理清楚细枝末节需要很长时间,今天只是梳理下,迁移模型的部分。
使用bert进行多分类
前期准备:
- 1.在 https://github.com/google-research/bert 下载模型的源码包。
- 2.在https://github.com/google-research/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专栏。