NLP 文本分类:朴素贝叶斯、CNN 与 BERT
文本分类入门指南:从朴素贝叶斯到 BERT
文本分类是自然语言处理(NLP)中最基础且应用最广泛的任务之一,如垃圾邮件过滤、情感分析、新闻归类等。本文将以零门槛方式讲解三种主流方法:传统统计模型朴素贝叶斯、经典深度学习模型CNN以及预训练革命代表BERT,帮助你理解其原理、适用场景与实现思路。
1. 文本分类任务概述
文本分类的目标是给定一段文本 x,预测其所属的类别 y。训练数据通常包含大量 (文本, 标签) 对。分类流程一般分为两步:
- 特征提取:将非结构化的文本转换为机器可处理的数值向量。
- 模型训练与预测:利用标注数据学习从向量到类别的映射。
不同方法的核心差异主要在于如何表示文本和如何构建分类决策函数。
2. 通用预处理与词表示
无论使用哪种模型,文本都需要先进行基础清洗与分词。常见步骤:
- 转小写、去除标点/特殊符号、去除停用词(视任务而定)。
- 分词:英文可按空格分割,中文需使用 jieba、HanLP 等分词工具。
- 构建词汇表,将词映射为 id。
2.1 传统表示法:词袋与 TF‑IDF
朴素贝叶斯通常基于词袋(Bag‑of‑Words)特征,核心思想是忽略词序,统计每个词在文档中出现的频次。为避免高频无意义词主导,可使用 TF‑IDF 加权:
- TF (词频):某词在当前文档中的比例。
- IDF (逆文档频率):包含该词的文档占比的反比对数,赋予稀有关键词更高重要性。
最终得到每篇文档的一个高维稀疏向量,维度通常为词汇表大小。
2.2 词嵌入
深度学习方法(CNN、BERT)使用稠密向量表示词。经典的 Word2Vec、GloVe 可将每个词映射为固定长度(如 300 维)的实数向量,相似的词在向量空间中距离更近。BERT 则更进一步,根据上下文动态生成词向量。
3. 朴素贝叶斯:简洁高效的基线
朴素贝叶斯(Naive Bayes)是一类基于贝叶斯定理并假设特征之间相互独立的概率分类器。对于文本分类,通常使用多项式朴素贝叶斯。
3.1 数学原理
给定文档 d 和类别 c,我们需要计算后验概率 P(c|d),并选择最大的类:
P(c|d) ∝ P(c) × P(d|c)
由于“朴素”条件独立假设,P(d|c) 可分解为文档中所有词 w_i 的条件概率乘积:
P(d|c) = Π P(w_i|c)
因此,每个类别只需要学习:
- 类先验概率
P(c): 训练集中该类别的占比。 - 类条件概率
P(w|c): 类别c下词w出现的概率,通常用词频带拉普拉斯平滑估计。
预测时,对于新文档,将其中出现的词的 P(w|c) 连乘并乘以 P(c),选择最大的 c。
3.2 实践要点
- 优点:训练和预测速度极快,可处理大规模数据,可解释性强,在小数据上表现不俗。
- 缺点:词袋模型忽略词序和上下文,“朴素”假设在真实文本中不成立,对长尾词敏感。
- 适用场景:文本较短、词汇重要程度高于语序的任务,如垃圾邮件检测、简单情感分类。常作为项目基线和快速验证工具。
3.3 简易实现示意
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
text_clf = Pipeline([
('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', MultinomialNB())
])
text_clf.fit(train_texts, train_labels)
predictions = text_clf.predict(test_texts)
朴素贝叶斯用极小的代价即可得到不错的 Baseline,后续若想提升,可转向捕获词序和语义的模型。
4. CNN 文本分类:捕捉局部特征
卷积神经网络(CNN)在计算机视觉取得巨大成功后,也被重新设计用于文本。文字序列中的 N‑gram(连续若干词)相当于图像中的局部像素块,因此一维卷积可以自动提取有意义的短语特征。
4.1 模型结构
典型文本 CNN 架构(Kim, 2014)包含四个主要层级:
- 嵌入层 (Embedding Layer):将每个词 id 映射为预训练或随机初始化的词向量,输入是长度为
n的句子,输出为n × d的矩阵(d是词向量维度)。 - 卷积层 (Convolution Layer):使用多种尺寸(如 [2,3,4])的滤波器在词序列上滑动,每个滤波器相当于提取某种 N‑gram 模式。滤波器宽度与词向量维度一致,所以卷积只在序列维度上滑动。
- 池化层 (Pooling Layer):对每个特征图执行最大池化(max‑over‑time pooling),提取最重要的特征,输出与句子长度无关的固定长度向量。
- 全连接层 + Softmax:将池化后的特征拼接,经过 Dropout 后送入全连接层,最后用 Softmax 得到类别概率。
4.2 为什么 CNN 对文本有效?
- 参数高效:卷积核参数共享,相比全连接网络极大减少参数量。
- 局部特征探测:能自动学习 “not good”“very exciting” 等决定情感的关键短语,而不依赖人工设计特征。
- 训练快速:相比 RNN/LSTM,CNN 可以并行计算,速度更快。
4.3 实现与调参建议
- 词向量可以选用
word2vec或GloVe预训练模型,并在训练中微调。 - 滤波器尺寸一般设为 2,3,4,窗口覆盖了二元、三元、四元词组。
- 池化通常使用 1‑max pooling(全局最大池化),避免零填充影响。
- 正则化:Dropout 率常介于 0.2~0.5,批归一化 (BatchNorm) 也可加速收敛。
# 代码结构示例 (Keras)
model = Sequential()
model.add(Embedding(vocab_size, embed_dim, input_length=max_len))
model.add(Conv1D(filters=128, kernel_size=3, activation='relu'))
model.add(GlobalMaxPooling1D())
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
CNN 文本分类在中等规模数据集(数万到数十万条)上表现出色,能够快速迭代并取得接近 RNN 的效果。
5. BERT:预训练时代的文本分类
BERT(Bidirectional Encoder Representations from Transformers)于 2018 年提出,彻底改变了 NLP 格局。它基于 Transformer 的编码器,在大规模无标注语料上进行预训练,再针对下游任务微调。
5.1 预训练与微调范式
- 预训练任务:BERT 在大量书籍和维基百科上进行两项训练:
- Masked Language Model(MLM):随机遮盖部分词,用上下文双向预测被遮盖词。
- Next Sentence Prediction(NSP):判断两句话是否连续。
- 微调 (Fine‑tuning):在 BERT 模型顶部添加一个简单的分类层(全连接 + Softmax),然后在标注数据上整体微调所有参数。对于分类任务,通常将 BERT 的第一个输出 token
[CLS]对应的向量作为整个句子的聚合表示,输入分类器。
5.2 BERT 的优势
- 上下文感知:同一个词 “bank” 在 “river bank” 和 “bank account” 中会得到不同的向量,解决了多义性问题。
- 深层双向建模:Transformer 的自注意力机制同时看到左侧和右侧全部上下文,远超单向 LSTM 或仅依赖 N‑gram 的 CNN。
- 强大的迁移能力:即使在少量下游标注数据上微调,也能达到极佳效果,极大降低了对大量任务特定数据的需求。
5.3 分类实现步骤
- 数据准备:将文本处理成 BERT 要求的输入格式:
[CLS]+ 文本 +[SEP],进行分词(WordPiece),生成 input_ids、attention_mask 和 token_type_ids(单句分类 token_type 全 0)。 - 模型加载:使用
transformers库加载预训练的 BERT 模型(如bert‑base‑uncased)。 - 添加分类头:在 BERT 输出的池化结果(
pooler_output)或[CLS]向量后接一层 Dropout 和线性分类器。 - 微调:使用较小的学习率(如 2e‑5)训练 2‑4 个 epoch,选择合适的批量大小(受到 GPU 内存限制)。
示例代码:
from transformers import BertTokenizer, TFBertForSequenceClassification
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = TFBertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)
# 编码所有文本
encodings = tokenizer(texts, truncation=True, padding=True, max_length=128)
# 创建 TensorFlow 数据集并训练
model.compile(optimizer=Adam(learning_rate=2e-5), loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(train_dataset, epochs=3, validation_data=val_dataset)
5.4 局限与应对
- 计算开销大:BERT‑Base 参数量约 1.1 亿,推理速度比 CNN 慢数十倍,不适合实时性要求极高的场景。可考虑轻量化变体 DistilBERT、ALBERT。
- 长度限制:最大输入通常为 512 token,长文本需裁剪或分段处理。
- 微调不稳定:小数据集上容易过拟合,需加强正则化或数据增强。
6. 方法对比与选择策略
| 方法 | 特征表示 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| 朴素贝叶斯 | 词袋 + TF‑IDF | 极快、可解释、低资源需求 | 忽视词序,语义能力弱 | 基线、短文本、海量快速分类 |
| CNN | 静态/微调词向量 | 能捕获局部短语,训练较快,效果较好 | 仍缺乏全局语序建模 | 中等数据量,需并行训练 |
| BERT | 上下文动态词向量 | 最佳语义理解,少样本强泛化 | 慢、资源消耗大、输入长度限制 | 精度优先,有 GPU 资源时 |
选择建议
- 从朴素贝叶斯开始:快速搭建一个基准模型,评估数据质量和任务难度。
- 尝试 CNN:当朴素贝叶斯达不到要求,且数据量在数万条以上时,CNN 是一种性价比极高的选择。
- 转向 BERT:若追求业界顶尖效果,或任务语义极为复杂(如细粒度情感、讽刺检测),且有 GPU 资源,BERT 微调是不二之选。必要时可采取模型压缩技术。
7. 总结与进一步学习
文本分类技术的发展清晰地展现了从统计学习到深度学习再到预训练范式的演进。朴素贝叶斯至今仍有实用价值,CNN 是轻量级深度方案的标杆,而 BERT 重新定义了大多数 NLP 任务的基线。
想要深入实践,建议:
- 在 Kaggle 等平台寻找实际数据集(如 IMDB 影评、新闻分类)练手。
- 对比三种模型在相同数据下的速度和准确率差异,建立直觉。
- 阅读论文:Kim (2014) “Convolutional Neural Networks for Sentence Classification”;BERT (Devlin et al., 2019)。
- 探索 Hugging Face 的 Transformers 生态,学习更多预训练模型(RoBERTa、XLNet 等)。
文本分类是 NLP 的入口,掌握它,你就打开了情感分析、意图识别、自动标签等众多方向的大门。