使用BERT进行简单的文本分类

Word2Vec的一些不足

在上一篇文章中,了解了如何使用word2vec进行文本相似度识别。然而,在实践中发现,word2vec的表现并不尽如人意,原因有很多:

一方面,word2vec的处理单位是单词,碰到短语时的核心处理逻辑还是进行分词后求平均,这样子的做法虽然高效,但在碰到较长的文本时,识别效果下降得非常快。

另一方面,在使用Google预训练的词向量模型时,出现了词汇表缺失的情况。很多常用词一旦变换了不太常见的形态,就因为出现频率下降而被优化掉了,这种情况在英文文本中受单词多态的影响极为明显。

虽然也有尝试各种方法,比如词干提取,迁移学习等来改善这些问题,但总感觉达不到满意的识别率。网上搜到的一些教程也都是比较老的了。跟ai方向的同学交流了下,他们说现在大家都是用GPT来处理文本了,于是自己也去了解了一下如何使用这些前沿的NLP技术。

尝试BERT

看了几篇介绍预训练语义模型的文章后,最终是把目标锁定在了「无监督预训练+下游任务微调」的BERT上。试着用BERT处理现在面临的认证相关文本识别问题。BERT是基于Transformer架构的预训练语言模型,可以用于各种NLP任务,如文本分类、命名实体识别等。

在本文中,将介绍如何使用BERT进行文本分类。具体来说,将使用BERT预训练模型bert-base-chinese,并在最后增加一个分类器,用于输入文本的分类。

安装transformer库

与上篇文章中提到的gensim库不同,将使用transformer库。在PyTorch中安装transformer库非常简单,只需要输入以下命令:

1
pip3 install transformers

文本分类

目标任务是对输入文本进行分类,判断其是否与认证相关,将使用bert-base-chinese模型进行分类。

由于目前只有一个包含100多个认证关键词的字典,多分类的精度肯定指望不上,因此尝试先做一个二分类的问题,即输入文本究竟是否认证相关,后续再进行划分。

但最后发现由于训练样本实在太小,内部种类差异大,且相当于只有正样本等多重原因,在经过反复的训练后,分类器模型的表现还是很差,不管碰到什么文本,都倾向于将其判断为认证相关。

代码实现

下面是使用BERT进行文本分类的代码实现,其中使用了transformer库和PyTorch框架:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import torch
from transformers import BertTokenizer, BertForSequenceClassification, BertConfig

class AuthClassifier:
def __init__(self, lang='en', model_path=None):
self.lang = lang
if self.lang == 'en':
# 加载英文 BERT 预训练模型和分词器
self.tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
config = BertConfig.from_pretrained('bert-base-uncased', num_labels=2)
self.model = BertForSequenceClassification(config)
keyword_file = "en/keyword.txt"
elif self.lang == 'zh':
# 加载中文 BERT 预训练模型和分词器
self.tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
config = BertConfig.from_pretrained('bert-base-chinese', num_labels=2)
self.model = BertForSequenceClassification(config)
keyword_file = "zh/keyword.txt"
else:
raise ValueError("Unsupported language: %s" % self.lang)

# 从外部文件读取认证相关的关键词列表
with open(keyword_file, 'r', encoding='utf-8') as f:
self.keywords = set([line.strip() for line in f])

# 加载或微调模型
if model_path is not None:
self.model = BertForSequenceClassification.from_pretrained(model_path)
# else:
# train(keyword_file)

def predict(self, text):
# 对输入文本进行分词和编码
tokens = self.tokenizer.encode_plus(text, max_length=128, truncation=True, padding='max_length', add_special_tokens=True, return_attention_mask=True, return_tensors='pt')

# 使用模型进行预测
with torch.no_grad():
outputs = self.model(tokens['input_ids'], attention_mask=tokens['attention_mask'])
logits = outputs[0]

# 获取预测结果
# probs = torch.softmax(logits, dim=1)
# return probs
_, predicted = torch.max(logits, dim=1)

# 判断文本是否包含认证相关的关键词
contains_keyword = any(keyword in text.lower() for keyword in self.keywords)

# 根据预测结果和关键词判断文本是否与认证相关
if predicted.item() == 1 or contains_keyword:
return True
else:
return False

在以上代码中,首先使用from_pretrained方法加载了bert-base-chinese模型和tokenizer。然后,对输入文本进行分词,并将其转换为BERT输入格式。最后,进行包含关系的判断,并打印出预测结果。

总结

本文介绍了如何使用最新的NLP技术BERT进行文本分类。通过使用BERT预训练模型和transformer库,可以轻松地对输入文本进行分类。但由于训练样本较少,分类器的表现还有待改进。下一篇文章中将计划以聚类的方法解决这个问题。

参考资料:

通俗理解BERT:https://blog.csdn.net/v_JULY_v/article/details/127411638

Github项目主页:https://github.com/huggingface/transformers

文本分类任务实例:https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb#scrollTo=5o4rUteaIrI_