基于自定义标签微调零样本文本分类模型遇错求助
问题分析与解决方案
核心错误原因
你加载模型时误用了RobertaForSequenceClassification,但目标模型是DeBERTa-v3(属于DebertaV2系列),必须使用对应的DebertaV2ForSequenceClassification类加载,否则模型内部结构不匹配,会触发张量维度错误(也就是你遇到的index_select()报错)。
其他关键问题与优化
- 未指定计算设备:代码中
device变量未定义,会导致模型和输入张量不在同一设备(CPU/GPU)上运行,引发错误。 - 大数据量内存问题:100万条数据一次性加载会占用大量内存,建议用自定义
Dataset类分批读取,避免内存溢出。 - 优化器与训练细节:新版本
transformers推荐使用torch.optim.AdamW替代旧版AdamW,同时可加入学习率调度器提升训练效果。 - 标签映射完整性:需确保
label_to_index包含所有22个标签,避免出现KeyError。
修正后的完整代码
from transformers import DebertaV2Tokenizer, DebertaV2ForSequenceClassification from torch.utils.data import DataLoader, Dataset import torch import torch.nn as nn from torch.optim import AdamW from transformers import get_scheduler # 定义计算设备 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 加载正确的tokenizer和模型 tokenizer = DebertaV2Tokenizer.from_pretrained('MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli') # 加载DeBERTa-v3分类模型,指定22个分类标签 model = DebertaV2ForSequenceClassification.from_pretrained( 'MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli', num_labels=22 ) model.to(device) # 自定义Dataset类,分批读取数据(避免一次性加载100万条数据占满内存) class TextClassificationDataset(Dataset): def __init__(self, file_path, label_to_index, tokenizer, max_len=512): self.file_path = file_path self.label_to_index = label_to_index self.tokenizer = tokenizer self.max_len = max_len # 预先读取所有行(也可以改成按需读取,进一步节省内存) with open(file_path, 'r', encoding='utf-8') as f: self.lines = [line.strip() for line in f if line.strip()] def __len__(self): return len(self.lines) def __getitem__(self, idx): line = self.lines[idx] post, label = line.split('³') # 编码文本 encoding = self.tokenizer( post, truncation=True, padding='max_length', max_length=self.max_len, return_tensors='pt' ) return { 'input_ids': encoding['input_ids'].flatten(), 'attention_mask': encoding['attention_mask'].flatten(), 'labels': torch.tensor(self.label_to_index[label], dtype=torch.long) } # 定义标签映射(确保包含所有22个标签) label_to_index = { 'Approve': 0, 'Spam': 1, 'Ads/Selling/Trading': 2, 'Foreign Language': 3, # 补充剩余18个标签... } # 初始化数据集和数据加载器 train_dataset = TextClassificationDataset( 'mixed_train_data.csv', label_to_index, tokenizer ) test_dataset = TextClassificationDataset( 'mixed_test_data.csv', label_to_index, tokenizer ) batch_size = 32 train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_dataloader = DataLoader(test_dataset, batch_size=batch_size) # 定义优化器和学习率调度器 optimizer = AdamW(model.parameters(), lr=1e-5) num_epochs = 10 num_training_steps = num_epochs * len(train_dataloader) lr_scheduler = get_scheduler( name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps ) loss_function = nn.CrossEntropyLoss() # 训练循环 for epoch in range(num_epochs): print(f"Epoch {epoch + 1}/{num_epochs}") print("-" * 10) # 训练阶段 model.train() total_train_loss = 0 for batch in train_dataloader: batch = {k: v.to(device) for k, v in batch.items()} outputs = model(input_ids=batch['input_ids'], attention_mask=batch['attention_mask']) loss = loss_function(outputs.logits, batch['labels']) total_train_loss += loss.item() loss.backward() optimizer.step() lr_scheduler.step() optimizer.zero_grad() avg_train_loss = total_train_loss / len(train_dataloader) print(f"Train loss: {avg_train_loss:.4f}") # 验证阶段 model.eval() total_test_loss = 0 total_correct = 0 total_samples = 0 with torch.no_grad(): for batch in test_dataloader: batch = {k: v.to(device) for k, v in batch.items()} outputs = model(input_ids=batch['input_ids'], attention_mask=batch['attention_mask']) loss = loss_function(outputs.logits, batch['labels']) total_test_loss += loss.item() preds = torch.argmax(outputs.logits, dim=1) total_correct += (preds == batch['labels']).sum().item() total_samples += len(batch['labels']) avg_test_loss = total_test_loss / len(test_dataloader) test_acc = total_correct / total_samples print(f"Test loss: {avg_test_loss:.4f}, Test accuracy: {test_acc:.4f}") print() # 保存微调后的模型和tokenizer model.save_pretrained('fine_tuned_deberta_model') tokenizer.save_pretrained('fine_tuned_deberta_model')
额外说明
- 如果你GPU显存不足,可以降低
batch_size,或者开启梯度累积(多次反向传播后再更新参数)。 - 原模型是针对NLI任务训练的,微调成单标签分类任务是合理的,无需纠结"零样本微调"的概念——你现在做的是有监督微调,用标注好的100万条数据直接优化分类头即可。
内容的提问来源于stack exchange,提问作者Menrion
相关产品推荐
相关产品推荐

