如何将自定义特征输入BERT模型进行推特分类微调?
解决BERT融合自定义特征的推特分类器微调方案
要在BertForSequenceClassification中加入自定义特征(脏话数量、正向表情数、负向表情数、推文长度),核心是自定义模型结构,将BERT的文本表征与自定义特征拼接后再进行分类。以下是具体实现步骤:
1. 数据预处理补充
除了常规的文本tokenize(生成input_ids、attention_mask、token_type_ids),还需要将自定义特征转换为张量,并建议做归一化处理(消除数值范围差异,比如推文长度除以最大长度,脏话数量等按比例缩放):
import torch import pandas as pd from transformers import BertTokenizer # 加载自定义特征DataFrame df = pd.DataFrame({ "脏话数量": [2,0,1], "正向表情数": [1,0,0], "负向表情数": [0,1,1], "推文长度": [123,52,87] }) # 归一化自定义特征 df["推文长度"] = df["推文长度"] / df["推文长度"].max() df[["脏话数量", "正向表情数", "负向表情数"]] = df[["脏话数量", "正向表情数", "负向表情数"]] / df[["脏话数量", "正向表情数", "负向表情数"]].max() # 转换为张量 custom_features = torch.tensor(df.values, dtype=torch.float32)
2. 自定义融合特征的BERT分类模型
继承BertPreTrainedModel,在原有BERT结构基础上,加入自定义特征的拼接逻辑:
from transformers import BertPreTrainedModel, BertModel class BertWithCustomFeatures(BertPreTrainedModel): def __init__(self, config): super().__init__(config) self.bert = BertModel(config) self.dropout = torch.nn.Dropout(config.hidden_dropout_prob) # 自定义特征维度是4,BERT池化输出维度是config.hidden_size(默认768) self.classifier = torch.nn.Linear(config.hidden_size + 4, config.num_labels) self.init_weights() def forward(self, input_ids=None, attention_mask=None, token_type_ids=None, custom_features=None): # 获取BERT的<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>token池化输出 outputs = self.bert(input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) pooled_output = outputs[1] pooled_output = self.dropout(pooled_output) # 拼接自定义特征与BERT输出 combined_output = torch.cat([pooled_output, custom_features], dim=1) logits = self.classifier(combined_output) return logits
3. 模型初始化与训练
加载预训练模型权重,并在训练循环中传入自定义特征:
from transformers import AdamW, get_linear_schedule_with_warmup # 初始化模型 model_name = "bert-base-uncased" tokenizer = BertTokenizer.from_pretrained(model_name) model = BertWithCustomFeatures.from_pretrained(model_name, num_labels=2) # 假设是二分类 # 训练配置(示例) optimizer = AdamW(model.parameters(), lr=2e-5) epochs = 3 total_steps = len(train_dataloader) * epochs scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=0, num_training_steps=total_steps) # 训练循环(需结合你的数据加载逻辑,确保每个batch包含文本输入和自定义特征) model.train() for epoch in range(epochs): for batch in train_dataloader: input_ids = batch["input_ids"] attention_mask = batch["attention_mask"] labels = batch["labels"] custom_feats = batch["custom_features"] optimizer.zero_grad() logits = model(input_ids=input_ids, attention_mask=attention_mask, custom_features=custom_feats) loss = torch.nn.CrossEntropyLoss()(logits, labels) loss.backward() optimizer.step() scheduler.step()
关键注意要点
- 特征归一化:自定义特征数值范围差异大(比如推文长度远大于脏话数量),必须归一化,否则模型会偏向数值大的特征。
- 维度匹配:确保自定义特征的维度是
(batch_size, num_custom_features),与BERT池化输出的(batch_size, hidden_size)在batch维度一致,才能拼接。 - 数据加载:在构建
DataLoader时,要将自定义特征与文本输入的张量打包成同一个batch,方便训练时传入模型。
内容的提问来源于stack exchange,提问作者BashMocha
相关产品推荐
相关产品推荐

