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

Llama2多分类多输出任务微调及数据集制备技术咨询

多分类多输出场景下Llama2微调方案及代码示例

一、标签编码优化方案

针对Y1/Y2/Y3各含200+类别的稀疏性问题,不要将所有标签堆叠为单一稀疏向量,正确做法是对每个输出任务独立编码:

  • 用sklearn.preprocessing.LabelEncoder分别对Y1、Y2、Y3做类别映射,将每个类别转为唯一整数ID(例如Y1的类别A→0、B→1…,Y2的类别X→0、Y→1…)
  • 训练时为每个输出任务配置独立分类头,避免稀疏矩阵带来的内存浪费与计算低效

二、数据集制备模板

以下是适配该场景的预处理代码:

import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from transformers import LlamaTokenizer

# 加载数据集(假设为CSV格式,包含x1,x2,x3,y1,y2,y3列)
df = pd.read_csv("your_dataset.csv")

# 1. 输入预处理:合并x1/x2/x3为文本输入并分词
tokenizer = LlamaTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
tokenizer.pad_token = tokenizer.eos_token  # Llama默认无pad token,需手动指定

def preprocess_input(row):
    input_text = f"x1: {row['x1']} x2: {row['x2']} x3: {row['x3']}"
    return tokenizer(
        input_text,
        truncation=True,
        max_length=512,
        padding="max_length",
        return_tensors="pt"
    )

# 批量处理输入
inputs = df.apply(preprocess_input, axis=1)
input_ids = np.vstack([x["input_ids"].numpy() for x in inputs])
attention_mask = np.vstack([x["attention_mask"].numpy() for x in inputs])

# 2. 标签编码:独立处理每个输出任务
label_encoders = {}
labels = {}
for col in ["y1", "y2", "y3"]:
    le = LabelEncoder()
    labels[col] = le.fit_transform(df[col])
    label_encoders[col] = le

# 保存编码器,供后续推理时还原类别
import joblib
joblib.dump(label_encoders, "label_encoders.pkl")

三、Llama2多输出微调代码

自定义多分类头部,针对三个输出任务分别计算交叉熵损失并求和:

import torch
import torch.nn as nn
from transformers import LlamaModel, TrainingArguments, Trainer
from datasets import Dataset

# 构建自定义多输出分类模型
class LlamaMultiOutputClassifier(nn.Module):
    def __init__(self, llama_model_name, num_classes_y1, num_classes_y2, num_classes_y3):
        super().__init__()
        self.llama = LlamaModel.from_pretrained(llama_model_name)
        self.dropout = nn.Dropout(0.1)
        # 为每个输出任务配置独立分类头
        self.classifier_y1 = nn.Linear(self.llama.config.hidden_size, num_classes_y1)
        self.classifier_y2 = nn.Linear(self.llama.config.hidden_size, num_classes_y2)
        self.classifier_y3 = nn.Linear(self.llama.config.hidden_size, num_classes_y3)

    def forward(self, input_ids, attention_mask=None, labels=None):
        outputs = self.llama(input_ids=input_ids, attention_mask=attention_mask)
        pooled_output = outputs.last_hidden_state[:, 0, :]  # 取<s> token的输出作为全局特征
        pooled_output = self.dropout(pooled_output)
        
        logits_y1 = self.classifier_y1(pooled_output)
        logits_y2 = self.classifier_y2(pooled_output)
        logits_y3 = self.classifier_y3(pooled_output)
        
        loss = None
        if labels is not None:
            # 计算三个任务的交叉熵损失并求和
            loss_fct = nn.CrossEntropyLoss()
            loss_y1 = loss_fct(logits_y1, labels["y1"])
            loss_y2 = loss_fct(logits_y2, labels["y2"])
            loss_y3 = loss_fct(logits_y3, labels["y3"])
            loss = loss_y1 + loss_y2 + loss_y3
        
        return {"loss": loss, "logits_y1": logits_y1, "logits_y2": logits_y2, "logits_y3": logits_y3}

# 转换为HuggingFace Dataset格式
dataset_dict = {
    "input_ids": input_ids,
    "attention_mask": attention_mask,
    "y1": labels["y1"],
    "y2": labels["y2"],
    "y3": labels["y3"]
}
dataset = Dataset.from_dict(dataset_dict)
dataset.set_format("torch", columns=["input_ids", "attention_mask", "y1", "y2", "y3"])

# 划分训练集与验证集
dataset = dataset.train_test_split(test_size=0.1)

# 初始化模型
num_classes_y1 = len(label_encoders["y1"].classes_)
num_classes_y2 = len(label_encoders["y2"].classes_)
num_classes_y3 = len(label_encoders["y3"].classes_)
model = LlamaMultiOutputClassifier(
    "meta-llama/Llama-2-7b-hf",
    num_classes_y1, num_classes_y2, num_classes_y3
)

# 定义训练参数
training_args = TrainingArguments(
    output_dir="./llama_multi_output_finetune",
    per_device_train_batch_size=4,
    per_device_eval_batch_size=4,
    learning_rate=2e-5,
    num_train_epochs=3,
    logging_dir="./logs",
    logging_steps=10,
    evaluation_strategy="epoch",
    save_strategy="epoch",
    fp16=True,  # GPU支持时开启混合精度训练,节省显存
    gradient_accumulation_steps=4
)

# 自定义验证集评估指标
def compute_metrics(eval_pred):
    logits_y1, logits_y2, logits_y3 = eval_pred.predictions
    labels_y1, labels_y2, labels_y3 = eval_pred.label_ids
    
    preds_y1 = np.argmax(logits_y1, axis=1)
    preds_y2 = np.argmax(logits_y2, axis=1)
    preds_y3 = np.argmax(logits_y3, axis=1)
    
    accuracy_y1 = (preds_y1 == labels_y1).mean()
    accuracy_y2 = (preds_y2 == labels_y2).mean()
    accuracy_y3 = (preds_y3 == labels_y3).mean()
    
    return {
        "accuracy_y1": accuracy_y1,
        "accuracy_y2": accuracy_y2,
        "accuracy_y3": accuracy_y3,
        "avg_accuracy": (accuracy_y1 + accuracy_y2 + accuracy_y3)/3
    }

# 初始化Trainer,自定义数据整理器
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset["train"],
    eval_dataset=dataset["test"],
    compute_metrics=compute_metrics,
    data_collator=lambda data: {
        "input_ids": torch.stack([x["input_ids"] for x in data]),
        "attention_mask": torch.stack([x["attention_mask"] for x in data]),
        "labels": {
            "y1": torch.tensor([x["y1"] for x in data]),
            "y2": torch.tensor([x["y2"] for x in data]),
            "y3": torch.tensor([x["y3"] for x in data])
        }
    }
)

# 启动训练
trainer.train()

# 保存最终模型
trainer.save_model("./llama_multi_output_final")

四、关键注意事项

  • Llama2的tokenizer需手动设置pad_token(通常复用eos_token)
  • 若显存不足,可使用bitsandbytes库进行4/8位量化,或减小per_device_train_batch_size、增大gradient_accumulation_steps
  • 可根据任务优先级调整损失权重(例如给核心输出任务设置更高的损失系数)

内容的提问来源于stack exchange,提问作者IndPythCoder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 08:18:12