NLP 预训练新技术:Google BERT 文本分类
BERT 简介
BERT 是 Google 开源的 NLP 预训练新技术,它的全称是 Bidirectional Encoder Representations from Transformers(Github 仓库)。
BERT 建立在最新的预训练与上下文相关的语言表示的工作之上,包括 Semi-supervised Sequence Learning、Generative Pre-Training、ELMo 和 ULMFit。然而,与以前的模型不同,BERT 是第一个深度、双向、无监督的语言表示模型,仅使用无标签的文本语料库(在本例中为维基百科)进行预训练。
由于模型结构复杂,再加上语料庞大,BERT 在目前最强民用 GPU 上都需要训练长达数个月之久。不过好消息是,Google 发布了支持中文以及多语言的预训练基础模型 BERT-Base。借助于预训练模型,我们就可以很轻松地完成多种 NLP 任务。
BERT 文本分类
文本分类是自然语言处理过程中最为常见的一类任务。那么,我们尝试借助于 BERT 来完成中文文本分类。
BERT 文本分类使用微调的方法,首先需要下载预训练模型:
# 下载预训练模型
wget -nc "https://storage.googleapis.com/bert_models/2018_11_03/chinese_L-12_H-768_A-12.zip"
unzip -o "chinese_L-12_H-768_A-12.zip"
接下来,克隆 BERT 官方仓库,以便于直接利用 Google 提供的模型训练源码:
# 克隆 BERT 官方仓库
git clone https://github.com/google-research/bert.git
Google 提供的模型训练源码中,完成文本分类的代码放在 run_classifier.py
中。其中,Google 提供了在 4 个基准数据集上的测试代码,并对应 XnliProcessor,MnliProcessor,MrpcProcessor 和 ColaProcessor 中。那么,要想完成自己的文本分类任务,我们只需要模仿并改写类即可。
改写 Processor 类
改写 Processor 类的过程非常简单,只需要按照自己的需要传入数据即可。例如,我们这里把自己的文本分类类定为 SelfProcessor
,其中包含下面四个函数:
import pandas as pd
from sklearn.model_selection import train_test_split
class SelfProcessor(DataProcessor):
# 传入训练数据
def get_train_examples(self, data_dir):
# 读取训练数据路径
file_path = os.path.join(data_dir, 'train.csv')
# 使用 Pandas 读取数据
df = pd.read_csv(file_path)
# 将训练数据切分为 80% 训练集和 20% 验证集
df_train, self.df_dev = train_test_split(df, test_size=0.2)
examples = []
# 按 BERT 推荐格式处理数据
for index, row in df_train.iterrows():
guid = 'train-%d' % index # 索引
text_a = tokenization.convert_to_unicode(str(row[0])) # 文本 1
text_b = tokenization.convert_to_unicode(str(row[1])) # 文本 2
label = row[2] # 文本标签
examples.append(InputExample(guid=guid, text_a=text_a,
text_b=text_b, label=label))
return examples
# 传入验证数据
def get_dev_examples(self, data_dir):
examples = []
for index, row in self.df_dev.iterrows():
guid = 'dev-%d' % index
text_a = tokenization.convert_to_unicode(str(row[0]))
text_b = tokenization.convert_to_unicode(str(row[1]))
label = row[2]
examples.append(InputExample(guid=guid, text_a=text_a,
text_b=text_b, label=label))
return examples
# 传入测试数据(预测)
def get_test_examples(self, data_dir):
file_path = os.path.join(data_dir, 'test.csv')
df_test = pd.read_csv(file_path)
examples = []
for index, row in df_test.iterrows():
guid = 'test-%d' % index
text_a = tokenization.convert_to_unicode(str(row[0]))
text_b = tokenization.convert_to_unicode(str(row[1]))
label = '0' # 随意指定测试数据标签
examples.append(InputExample(guid=guid, text_a=text_a,
text_b=text_b, label=label))
return examples
def get_labels(self):
return ['A', 'B', 'C'] # 示例三分类任务对应数据标签
你会发现,传入训练、验证和测试数据的函数基本一致,关键在于按 BERT 要求将数据处理成规定。
接下来,我们还需要修改 main()
函数中的 processors,添加刚刚自定义的 SelfProcessor:
def main(_):
tf.logging.set_verbosity(tf.logging.INFO)
processors = {
"cola": ColaProcessor,
"mnli": MnliProcessor,
"mrpc": MrpcProcessor,
"xnli": XnliProcessor,
"self": SelfProcessor, # 添加自定义 Processor
}
执行文本分类
完成上面的工作,就可以开始执行文本分类任务了。按照 BERT 开源仓库示例的执行代码运行即可,例如:
python run_classifier.py \
--task_name=sim \ # 执行 processor
--do_train=true \ # 开启训练模型
--do_eval=true \ # 开启验证模型
--do_predict=true \ # 开启测试模型
--data_dir=./dataset \ # 数据路径
--vocab_file=./chinese_L-12_H-768_A-12/vocab.txt \ # 预训练模型下载文件路径
--bert_config_file=./chinese_L-12_H-768_A-12/bert_config.json \
--init_checkpoint=./chinese_L-12_H-768_A-12/bert_model.ckpt \
--max_seq_length=128 \ # 模型训练参数
--train_batch_size=32 \
--learning_rate=5e-5 \
--num_train_epochs=1.0 \
--output_dir=./dataset/output # 输出文件路径
注意,只有定义了相关的函数,才开启相应的选项。例如,Processor 中未定义验证集函数,那么就把 --do_eval=false
即可。
模型训练完成之后,会在输出文件路径下保留相应的模型和测试结果。BERT 优秀的表现在其论文中有所体现,其为 NLP 问题的快速优化解决提供了新的方法和思路。👍