在多标签分类的问题中,模型的训练集由实例组成,每个实例可以被分配多个类别,表示为一组目标标签,最终任务是准确预测测试数据的标签集。例如:
- 文本可以同时涉及宗教、政治、金融或教育,也可以不属于其中任何一个。
- 电影按其抽象内容可分为动作片、喜剧片和浪漫片。电影有可能属于多种类型,比如周星驰的《大话西游》,同时属于浪漫片与喜剧片。
多标签和多分类有什么区别?
在多分类中,每个样本被分配到一个且只有一个标签:水果可以是苹果或梨,但不能同时是苹果和梨。让我们考虑三个类别的例子C = [“Sun,”Moon,Cloud“]。在多分类中,每个样本只可以属于其中一个C类;在多标签中,每个样本可以属于一个或多个类。
数据集
在这篇文章, 我们将使用Kaggle的 Toxic Comment Classification Challenge数据集,该数据集由大量维基百科评论组成,这些评论已经被专业评估者标记为恶意行为。恶意的类型为:
toxic(恶意),severetoxic(穷凶极恶),obscene(猥琐),threat(恐吓),insult(侮辱),identityhate(种族歧视)
例:
“Hi! I am back again! Last warning! Stop undoing my edits or die!”
被标记为[1,0,0,1,0,0]。意思是它同时属于toxic 和threat。
BERT简介
2018 年 10 月,Google 发布了一种名为 BERT 的新语言表示模型, 它代表来自Transformers的双向编码器表示。BERT建立在预训练上下文表示模型—半监督序列学习、生成预训练、ELMo和ULMFit 的基础上。但是,与之前的模型不同,BERT 是第一个深度双向、无监督的语言表示形式。仅使用纯文本语料库(维基百科)进行预训练。
预训练表示可以分为无上下文模型与上下文模型:
- 无上下文模型(如 word2vec 或 GloVe)为词汇中的每个单词生成单个单词嵌入表示形式,例如,单词”bank“在“bank account” 和“bank of the river” 中有相同的单词嵌入表示。
- 相反,上下文模型生成基于句子中其他单词的每个单词的表示形式。上下文表示可以进一步区分为单向的或双向的,例如,句子“I accessed the bank account”,单向上下文模型将是基于“ I accessed the ”来表示“bank”,而不是后面的“ account账户 ”。然而,BERT同时使用它的前问和后文- “ I accessed the … account ”来表示“bank” - 从深度神经网络的底部开始,使其深度双向。
基于双向 LSTM 的语言模型会训练一个标准的从左到右的语言模型,并训练从右到左(反向)的语言模型。该模型可预测后续单词(如 ELMO 中的单词)中的先前单词,在ELMo中,前向语言模型和后向语言模型都分别是一个LSTM模型,关键的区别在于,LSTM都不会同时考虑前一个和后一个令牌。
为什么 BERT 优于其他双向模型?
直观地说,深度双向模型比从左到右模型或从左到右和从右到左模型的串联更为严格。遗憾的是,标准条件语言模型只能从左到右或从右到左进行训练,因为双向调节将允许每个单词在多层上下文中间接地“看到自己”。
为了解决这个问题,Bert使用“掩蔽”技术(MASKING)在输入中屏蔽一些单词,然后双向调节每个单词以预测被屏蔽的单词。例如:
BERT 还学会根据一个非常简单的任务对句子之间的关系进行建模, 该任务可以从任何文本语料库生成: 给定两个句子 A 和 B,B 是语料库中 A 之后的实际下一句,还是一个随机句子?例如:
多分类的问题我在上一篇文章中已经详细讨论过: tensorflow 2.0+ 基于BERT模型的文本分类 。本文将重点研究BERT在多标签文本分类中的应用。因此,我们只需修改相应代码,使其适合多标签方案。
使用TensorFlow 2.0+ keras API微调BERT
现在,我们需要在所有样本中应用 BERT tokenizer 。我们将token映射到词嵌入。这可以通过encode_plus完成。
def convert_example_to_feature(review):
# combine step for tokenization, WordPiece vector mapping, adding special tokens as well as truncating reviews longer than the max length
return tokenizer.encode_plus(review,
add_special_tokens = True, # add [CLS], [SEP]
max_length = max_length, # max length of the text that can go to BERT
pad_to_max_length = True, # add [PAD] tokens
return_attention_mask = True, # add attention mask to not focus on pad tokens
truncation=True
)
# map to the expected input to TFBertForSequenceClassification, see here
def map_example_to_dict(input_ids, attention_masks, token_type_ids, label):
return