目 录CONTENT

文章目录

微调 BERT 模型:使用 Keras/TensorFlow 进行文本分类的完整指南

Administrator
2025-11-29 / 0 评论 / 0 点赞 / 0 阅读 / 0 字

📢 转载信息

原文链接:https://machinelearningmastery.com/fine-tuning-a-bert-model/

原文作者:Jason Brownlee


BERT模型在NLP领域取得了巨大成功,并且通常在文本分类任务上表现出色。许多研究者希望了解如何使用这个强大的模型来解决自己的特定任务,例如情感分析或主题分类。

本指南将介绍如何使用Keras和TensorFlow框架对BERT模型进行微调(fine-tuning)以完成文本分类任务。我们将从头开始构建一个完整的示例,包括数据预处理、模型加载和训练。

BERT模型由Google在2018年推出,其关键创新在于它能够学习双向的上下文表示。与传统的单向模型(如Word2Vec或LSTM)不同,BERT在预训练阶段可以同时查看一个词的左侧和右侧的上下文信息,这极大地提升了它对语言的理解能力。

微调过程通常涉及以下步骤:

  1. 数据准备:将文本数据转换为BERT可以理解的格式。
  2. 模型加载:加载一个预训练的BERT模型。
  3. 模型构建:在BERT之上添加一个或多个新的层,用于特定的分类任务。
  4. 模型训练:使用新的任务数据对整个模型(或部分模型)进行训练。

本教程使用了Hugging Face的transformers库来简化BERT模型的加载和使用,这是一个非常流行的工具,可以让你轻松访问数百个预训练模型。

环境准备

首先,确保安装了必要的Python库。我们将使用TensorFlow作为后端,并依赖transformers库来处理BERT模型。

我们还需要tensorflow_text库来帮助进行高效的文本分词(tokenization)。

pip install tensorflow tensorflow-text transformers

下面是导入所需的库:

import tensorflow as tf
import tensorflow_text as tf_text
from transformers import TFBertModel, BertTokenizer
import numpy as np

步骤1:数据准备

为了演示,我们将使用一个非常小的、人工创建的数据集。在实际应用中,您需要一个包含大量标记文本的数据集。

假设我们正在进行一个二元分类任务(例如,正面/负面评论分类)。

# 示例数据:包含正面和负面评论的列表
reviews = [
    "This movie was absolutely fantastic! I loved every minute of it.",
    "The plot was confusing and the acting was terrible.",
    "A masterpiece of modern cinema, highly recommended.",
    "I wasted two hours of my life watching this garbage.",
    "It was okay, nothing special, just average."
]
# 标签:1代表正面,0代表负面
labels = np.array([1, 0, 1, 0, 0])

分词器和模型选择

我们将使用BERT的基础版本(bert-base-uncased),它是一个在英文维基百科和BookCorpus上预训练的模型。

transformers库提供了相应的BertTokenizer,它可以正确地处理BERT所需的输入格式(包括特殊标记如[CLS][SEP])。

model_name = 'bert-base-uncased'

# 加载分词器
tokenizer = BertTokenizer.from_pretrained(model_name)

BERT需要三种类型的输入:input_ids(词汇ID)、token_type_ids(区分句子1和句子2,对于单句分类任务通常全为0)和attention_mask(指示哪些是真实Token,哪些是填充Token)。

我们需要一个函数将原始文本转换为这些格式:

def tokenize_and_pad(texts, tokenizer, max_len=128):
    # 使用tokenizer.batch_encode_plus进行批处理编码
    encoded_inputs = tokenizer.batch_encode_plus(
        texts,
        max_length=max_len,
        padding='max_length', # 使用max_length进行填充
        truncation=True,       # 截断超长的序列
        return_tensors='tf'    # 返回TensorFlow张量
    )
    
    # 提取所需的三种输入
    input_ids = encoded_inputs['input_ids']
    attention_mask = encoded_inputs['attention_mask']
    # token_type_ids 对于单句分类通常是全0,但这里我们让分词器处理
    token_type_ids = encoded_inputs.get('token_type_ids', tf.zeros_like(input_ids))
    
    return {
        'input_ids': input_ids,
        'attention_mask': attention_mask,
        'token_type_ids': token_type_ids
    }

# 准备数据
train_data = tokenize_and_pad(reviews, tokenizer)

由于数据集太小,我们不会进行真正的训练/测试分割,而是直接使用全部数据进行演示。

步骤2:构建微调模型

微调BERT的核心思想是加载预训练的BERT层,并将其冻结(或允许其训练),然后在其输出之上添加一个分类头。

我们将使用TFBertModel来加载预训练权重。我们希望模型输出的是BERT的[CLS]标记(序列的第一个Token,通常用于聚合整个序列的上下文信息)的最终隐藏状态。

# 1. 加载预训练的BERT模型
bert_model = TFBertModel.from_pretrained(model_name, include_pooling=True)

# 2. 构建自定义分类器模型
class BertClassifier(tf.keras.Model):
    def __init__(self, bert_model, num_classes):
        super(BertClassifier, self).__init__()
        # 确保bert_model是共享的基础层
        self.bert = bert_model
        # 添加一个Dropout层以防止过拟合
        self.dropout = tf.keras.layers.Dropout(0.1)
        # 添加一个密集层作为分类头
        self.classifier = tf.keras.layers.Dense(num_classes, activation='softmax')

    def call(self, inputs):
        # inputs 是一个字典,包含 input_ids, attention_mask, token_type_ids
        
        # BERT模型的输出是一个包含三个元素的元组:
        # (sequence_output, pooler_output, hidden_states, attentions)
        # pooler_output 是 [CLS] token 的输出(通常用于分类)
        bert_outputs = self.bert(inputs)
        
        # 我们只使用 pooler_output
        cls_output = bert_outputs.pooler_output
        
        # 传递给分类头
        x = self.dropout(cls_output)
        return self.classifier(x)

num_classes = 2 # 二元分类

bm_classifier = BertClassifier(bert_model, num_classes=num_classes)

冻结BERT权重(可选)

在微调的早期阶段,特别是数据集较小时,通常建议冻结BERT的主体权重,只训练新添加的分类层,以防止预训练权重被破坏。

# 冻结BERT层
bert_model.trainable = False

步骤3:编译和训练模型

现在我们可以编译模型并开始训练。我们使用稀疏的分类交叉熵,因为我们的标签是整数(0或1)。

optimizer = tf.keras.optimizers.Adam(learning_rate=2e-5) # BERT微调通常使用较小的学习率
loss = tf.keras.losses.SparseCategoricalCrossentropy()
metrics = ['accuracy']

bm_classifier.compile(optimizer=optimizer, loss=loss, metrics=metrics)

# 检查模型结构 (可选)
# bm_classifier.build(input_shape=({k: (None,) for k in train_data.keys()}))
# bm_classifier.summary()

print("\n开始微调模型...")

# 训练模型
history = bm_classifier.fit(
    train_data,
    labels,
    epochs=3, # 对于演示,我们只训练少量轮次
    batch_size=2
)

print("\n模型训练完成。")
BERT Model Fine Tuning Guide for Text Classification

评估和预测

由于数据量太少,评估结果可能没有实际意义,但它演示了流程。

# 评估(在训练集上,仅用于演示)
loss, accuracy = bm_classifier.evaluate(train_data, labels)
print(f"\n训练集准确率: {accuracy*100:.2f}%")

# 进行预测
new_texts = [
    "This was truly awful and a waste of time.", 
    "I enjoyed the subtle complexity of the narrative."
]

pred_data = tokenize_and_pad(new_texts, tokenizer)
predictions = bm_classifier.predict(pred_data)

# 预测结果是概率分布,取最高概率的类别索引
predicted_classes = np.argmax(predictions, axis=1)

print("\n新文本预测结果 (0=负面, 1=正面):")
for text, pred in zip(new_texts, predicted_classes):
    print(f"  '{text[:30]}...' -> 类别: {pred}")

结论

本教程展示了如何使用Keras和TensorFlow,结合transformers库,对BERT模型进行文本分类的微调。关键在于正确地预处理输入数据,加载预训练模型(TFBertModel),并在其之上添加一个任务特定的分类层。

对于更大的数据集,您可以考虑解冻(unfreeze)BERT的一部分或全部层,并使用非常小的学习率(如2e-5)进行更彻底的训练,以使模型适应您的特定领域数据。

记住,BERT的强大能力需要适当的资源(GPU/TPU)和充足的数据才能完全发挥出来。在实际操作中,请务必使用您任务的真实数据集进行训练和验证。




🚀 想要体验更好更全面的AI调用?

欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。

0

评论区