You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于自定义标签微调零样本文本分类模型遇错求助

问题分析与解决方案

核心错误原因

你加载模型时误用了RobertaForSequenceClassification,但目标模型是DeBERTa-v3(属于DebertaV2系列),必须使用对应的DebertaV2ForSequenceClassification类加载,否则模型内部结构不匹配,会触发张量维度错误(也就是你遇到的index_select()报错)。

其他关键问题与优化

  1. 未指定计算设备:代码中device变量未定义,会导致模型和输入张量不在同一设备(CPU/GPU)上运行,引发错误。
  2. 大数据量内存问题:100万条数据一次性加载会占用大量内存,建议用自定义Dataset类分批读取,避免内存溢出。
  3. 优化器与训练细节:新版本transformers推荐使用torch.optim.AdamW替代旧版AdamW,同时可加入学习率调度器提升训练效果。
  4. 标签映射完整性:需确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:54:56