面包屑图标 当前位置: 首页
AI资讯
热点详情

如何从零开始微调Llama 3进行序列分类完整教程

AI热点日报
AI热点日报时间:2026-05-30
热点解读

利用HuggingFace库在Kaggle上微调Llama38B模型完成序列分类任务。通过4位量化与LoRA适配低显存GPU,使用ag_news数据集(4类新闻)训练子集。预处理包括标签均衡化、数据集拆分及类别权重计算,最后替换模型输出头为4神经元线性层。

大型语言模型之所以出名,靠的就是文本生成能力。预训练阶段,它们啃下了数百万个token,练就了一身理解英文文本、生成完整句子的本领。

不过,自然语言处理里还有一个常见的活儿:序列分类任务——把给定的文本分到不同类别里。用大模型通过prompt硬上,偶尔能行,但效果不稳定。真正靠谱的做法,是对大模型做一番调整,让它针对每个类别输出一组概率。这篇指南就带大家走一遍完整流程,看看怎么用微调后的Llama 3模型搞定序列分类。

导入库

这次我们直接在Kaggle上干活。先把微调Llama 3所需的一堆库装好,跑下面这行代码就行:

!pip install -q transformers accelerate trl bitsandbytes datasets evaluate huggingface-cli 
!pip install -q peft scikit-learn

下载库

装的是这些家伙:

  • Transformers:HuggingFace家的老牌库,下载模型、搭应用、微调深度学习模型(包括大语言模型)全靠它。
  • 加速(Accelerate):同样是HuggingFace出品,给GPU上跑大模型推理加速的。
  • Trl:HuggingFace的一个Python包,专门用来微调HuggingFace Hub上的模型,连大模型也能搞定。
  • bitsandbytes:大模型吃内存太狠了,低显存GPU想直接用,得先量化——把精度降下来,这个库就是干这事的。
  • 数据集(Datasets):HuggingFace的数据集库,图像分类、文本生成、文本摘要……各种开源数据集随便下。
  • 评估(Evaluate):训练前后评估模型用的。
  • Huggingface-cli:必须装,因为要用Llama 3得先登录HuggingFace。
  • peft:手里的GPU显存有限,不可能把大模型所有参数都训一遍,只训一部分参数就行——peft库正是干这个的。
  • Scikit-learn:机器学习常用工具,这里用它来计算误差指标,对比训练前后模型的效果。

装完之后,记得登录HuggingFace中心。用huggingface-cli工具:

!huggingface-cli login --token $YOUR_HF_TOKEN

代码解释

这里调用了huggingface-clilogin选项,后面跟上--token参数,把HuggingFace的访问令牌传进去。去这个链接创建或复制一个令牌,然后贴到YOUR_HF_TOKEN位置就行。下图展示了新建令牌的界面:

加载数据集

下面把训练用的数据集搞进来:

from datasets import load_dataset

dataset = load_dataset("ag_news")
  • 先从datasets库导入load_dataset函数。
  • 然后用数据集名字"ag_news"调用它。

跑完这行,ag_news数据集就下载到dataset变量里了。这个数据集长这样:

这是一个新闻分类数据集,新闻被分成世界、体育、商业、科学/技术四类。先看看每个类别的样本数量是否均衡:

import pandas as pd

df = pd.DataFrame(dataset['train'])

df.label.value_counts(normalize=True)

代码解释

  • 先导入pandas。
  • ag_news数据集包含训练集和测试集,是DatasetDict类型。为了方便操作,转成pandas DataFrame。
  • 然后对DataFrame的label列调用value_counts(normalize=True),查看比例。

输出显示四个标签比例相同,说明每个类别样本数一样。不过数据集很大,我们只需要一部分。下面从DataFrame里抽取子集:

# Splitting the dataframe into 4 separate dataframes based on the labels
label_1_df = df[df['label'] == 0]
label_2_df = df[df['label'] == 1]
label_3_df = df[df['label'] == 2]
label_4_df = df[df['label'] == 3]

# Shuffle each label dataframe
label_1_df = label_1_df.sample(frac=1).reset_index(drop=True)
label_2_df = label_2_df.sample(frac=1).reset_index(drop=True)
label_3_df = label_3_df.sample(frac=1).reset_index(drop=True)
label_4_df = label_4_df.sample(frac=1).reset_index(drop=True)

# Splitting each label dataframe into train, test, and validation sets
label_1_train = label_1_df.iloc[:2000]
label_1_test = label_1_df.iloc[2000:2500]
label_1_val = label_1_df.iloc[2500:3000]

label_2_train = label_2_df.iloc[:2000]
label_2_test = label_2_df.iloc[2000:2500]
label_2_val = label_2_df.iloc[2500:3000]

label_3_train = label_3_df.iloc[:2000]
label_3_test = label_3_df.iloc[2000:2500]
label_3_val = label_3_df.iloc[2500:3000]

label_4_train = label_4_df.iloc[:2000]
label_4_test = label_4_df.iloc[2000:2500]
label_4_val = label_4_df.iloc[2500:3000]

# Concatenating the splits back together
train_df = pd.concat([label_1_train, label_2_train, label_3_train, label_4_train])
test_df = pd.concat([label_1_test, label_2_test, label_3_test, label_4_test])
val_df = pd.concat([label_1_val, label_2_val, label_3_val, label_4_val])

# Shuffle the dataframes to ensure randomness
train_df = train_df.sample(frac=1).reset_index(drop=True)
test_df = test_df.sample(frac=1).reset_index(drop=True)
val_df = val_df.sample(frac=1).reset_index(drop=True)
  • 数据有4个标签,先按标签拆成4个单独DataFrame。
  • 然后用sample打乱每个标签的数据。
  • 再把每个标签DataFrame切成三份:训练2000条、测试500条、验证500条。
  • 接着用pd.concat把所有标签的训练数据拼成train_df,测试和验证同理。
  • 最后再分别打乱一次,保证随机性。

检查价值很重要

确认一下训练数据里每个标签的数量:

train_df.label.value_counts()

Pandas DataFrames 到 DatasetDict

OK,训练集四个标签数量一致。不过在送去训练之前,得把pandas DataFrame转成HuggingFace训练器能吃的DatasetDict

from datasets import DatasetDict, Dataset

# Converting pandas DataFrames into Hugging Face Dataset objects:
dataset_train = Dataset.from_pandas(train_df)
dataset_val = Dataset.from_pandas(val_df)
dataset_test = Dataset.from_pandas(test_df)

# Combine them into a single DatasetDict
dataset = DatasetDict({
'train': dataset_train,
'val': dataset_val,
'test': dataset_test
})
dataset

代码解释

  • 先从datasets库导入DatasetDict类。
  • 然后把train_dftest_dfval_df分别转成HuggingFace的Dataset类型。
  • 最后合并成一个DatasetDict,存到dataset变量里。

从输出能看到,DatasetDict包含三个子集:训练、测试、验证,每个子集只有两列:文本和标签。

这里每个类别的比例是均匀的。但在实际项目中,类别不平衡才是常态。如果遇到不平衡,需要计算类别权重,让大模型不要偏向样本多的类别。类别权重越大,该类别的重要性越高。计算方法是取类别标签比例(value_counts(normalize=True))的倒数。代码如下:

import torch

class_weights=(1/train_df.label.value_counts(normalize=True).sort_index()).tolist()
class_weights=torch.tensor(class_weights)
class_weights=class_weights/class_weights.sum()
class_weights

代码解释

  • 先取标签值计数的倒数。
  • 从列表转成torch张量。
  • 然后除以总和做归一化。

输出显示所有类别权重相等——因为样本本来就是均衡的。

模型加载-量化

接下来下载并准备模型。手里的GPU显存不大,没法扛完整模型,得量化一下:

from transformers import BitsAndBytesConfig, AutoModelForSequenceClassification

quantization_config = BitsAndBytesConfig(
load_in_4bit = True,
bnb_4bit_quant_type = 'nf4',
bnb_4bit_use_double_quant = True,
bnb_4bit_compute_dtype = torch.bfloat16
)

model_name = "meta-llama/Meta-Llama-3-8B"

model = AutoModelForSequenceClassification.from_pretrained(
model_name,
quantization_config=quantization_config,
num_labels=4,
device_map='auto'
)

代码解释

  • transformers导入BitsAndBytesConfigAutoModelForSequenceClassification
  • 定义量化配置:load_in_4bit=True表示量化到4位精度;bnb_4bit_quant_type选推荐的'nf4'(Normal Float);bnb_4bit_compute_dtype设为torch.bfloat16(取决于GPU);bnb_4bit_use_double_quant=True可以进一步省显存。
  • 模型名字给"meta-llama/Meta-Llama-3-8B"
  • AutoModelForSequenceClassification加载,注意传了num_labels=4——这个类会自动把Llama 3最后一层换成含4个神经元的线性层,适配我们的分类任务。
  • device_map='auto'让模型自动加载到GPU。

跑完这步,Llama 3 8B就从HuggingFace Hub下载下来了,按量化配置压缩,输出头换成4神经元的线性层,然后送到GPU。接下来创建LoRA配置,只训练一小部分参数:

LoRA 配置

from peft import LoraConfig, prepare_model_for_kbit_training, get_peft_model

lora_config = LoraConfig(
r = 16,
lora_alpha = 8,
target_modules = ['q_proj', 'k_proj', 'v_proj', 'o_proj'],
lora_dropout = 0.05,
bias = 'none',
task_type = 'SEQ_CLS'
)

model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, lora_config)

代码解释

  • peft导入LoraConfigprepare_model_for_kbit_trainingget_peft_model
  • 实例化LoraConfigr=16(训练的参数矩阵秩);lora_alpha=8(超参数,通常设为r的一半);target_modules选所有注意力层(K、Q、V和输出投影);lora_dropout=0.05随机丢弃防止过拟合;bias='none'task_type='SEQ_CLS'(序列分类)。
  • prepare_model_for_kbit_training预处理量化模型,以便训练。
  • 最后用get_peft_model把模型和LoRA配置包装起来。

运行后,模型就准备好用PEFT(这里是LoRA)只训练部分参数了。

模型测试 – 预训练

正式训练之前,先在测试数据上看看Llama 3的原始表现。先下载分词器:

from transformers import AutoTokenizer

model_name = "meta-llama/Meta-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(model_name, add_prefix_space=True)

tokenizer.pad_token_id = tokenizer.eos_token_id
tokenizer.pad_token = tokenizer.eos_token

代码解释

  • 导入AutoTokenizer
  • from_pretrained加载分词器。
  • pad_tokenpad_token_id设为eos_token(因为Llama没有专门的填充标记)。
model.config.pad_token_id = tokenizer.pad_token_id
model.config.use_cache = False
model.config.pretraining_tp = 1

再把模型配置也同步一下,关掉缓存。现在把测试数据喂给模型,收集输出:

sentences = test_df.text.tolist()

batch_size = 32

all_outputs = []

for i in range(0, len(sentences), batch_size):
batch_sentences = sentences[i:i + batch_size]

inputs = tokenizer(batch_sentences, return_tensors="pt",
padding=True, truncation=True, max_length=512)

inputs = {k: v.to('cuda' if torch.cuda.is_a vailable() else 'cpu') for k, v in inputs.items()}

with torch.no_grad():
outputs = model(**inputs)
all_outputs.append(outputs['logits'])

final_outputs = torch.cat(all_outputs, dim=0)
test_df['predictions']=final_outputs.argmax(axis=1).cpu().numpy()

代码解释

  • 把测试DataFrame的文本列转成句子列表。
  • 设置batch大小为32。
  • 建一个空列表all_outputs存输出。
  • 按batch遍历句子,用分词器编码(padding、truncation、max_length=512)。
  • 把编码后的输入移动到设备(GPU或CPU)。
  • torch.no_grad()下推理,将输出的logits追加到all_outputs
  • 最后用torch.cat拼接所有输出,取每个logits的argmax(概率最高的标签),写入测试DataFrame的predictions列。

评估一下模型的表现:

from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.metrics import balanced_accuracy_score, classification_report

def get_metrics_result(test_df):
y_test = test_df.label
y_pred = test_df.predictions

print("Classification Report:")
print(classification_report(y_test, y_pred))

print("Balanced Accuracy Score:", balanced_accuracy_score(y_test, y_pred))
print("Accuracy Score:", accuracy_score(y_test, y_pred))

get_metrics_result(test_df)

代码解释

  • 导入accuracy_scorebalanced_accuracy_scoreclassification_report
  • 定义get_metrics_result()函数,接收DataFrame,打印分类报告、准确率和平衡准确率。

跑出来准确率只有0.23,惨不忍睹。精度、召回率、F1也都不到50%。等训练完再测,就知道进步多大了。

开始训练之前,得先对数据做预处理:

def data_preprocesing(row):
return tokenizer(row['text'], truncation=True, max_length=512)

tokenized_data = dataset.map(data_preprocesing, batched=True,
remove_columns=['text'])
tokenized_data.set_format("torch")

代码解释

  • 定义data_preprocessing()函数,把每行文本传给分词器,设置截断、最大长度512。
  • dataset.map应用到整个数据集,同时删掉原始的text列。
  • 最后把数据转成torch格式。

现在,DatasetDict里的每个子集都包含三列:labelinput_idsattention_mask。训练时需要一个数据整理器来批量处理:

from transformers import DataCollatorWithPadding

collate_fn = DataCollatorWithPadding(tokenizer=tokenizer)
  • 导入DataCollatorWithPadding,实例化时传入分词器。
  • 这个整理器会把每个batch内的输入统一填充到当前batch的最大长度,用填充标记补齐——这是批量训练提速的关键。

Finetune Llama 3:模型训练和训练后评估

训练之前,需要定义评估指标。大模型默认用负对数似然损失,但我们改了模型做序列分类,得重新定义:

def compute_metrics(evaluations):
predictions, labels = evaluations
predictions = np.argmax(predictions, axis=1)
return {'balanced_accuracy' : balanced_accuracy_score(predictions, labels),
'accuracy':accuracy_score(predictions,labels)}
  • 函数接收包含预测和标签的元组。
  • np.argmax取概率最高的索引。
  • 返回平衡准确度和原始准确度。

因为要用自定义指标,而且我们还有类别权重,所以得写一个自定义训练器:

class CustomTrainer(Trainer):
def __init__(self, *args, class_weights=None, **kwargs):
super().__init__(*args, **kwargs)
if class_weights is not None:
self.class_weights = torch.tensor(class_weights,
dtype=torch.float32).to(self.args.device)
else:
self.class_weights = None

def compute_loss(self, model, inputs, return_outputs=False):
labels = inputs.pop("labels").long()

outputs = model(**inputs)

logits = outputs.get('logits')

if self.class_weights is not None:
loss = F.cross_entropy(logits, labels, weight=self.class_weights)
else:
loss = F.cross_entropy(logits, labels)

return (loss, outputs) if return_outputs else loss

代码解释

  • 自定义CustomTrainer继承自HuggingFace的Trainer
  • __init__中若传了class_weights,就转成torch张量并移到设备上。
  • compute_loss重写:从输入中取出标签,模型前向传播得到logits,然后计算交叉熵损失,若有类别权重就传入weight参数。

训练论点

定义训练参数:

training_args = TrainiAgrumentsngArguments(
output_dir = 'sentiment_classification',
learning_rate = 1e-4,
per_device_train_batch_size = 8,
per_device_eval_batch_size = 8,
num_train_epochs = 1,
logging_steps=1,
weight_decay = 0.01,
evaluation_strategy = 'epoch',
sa ve_strategy = 'epoch',
load_best_model_at_end = True,
report_to="none"
)

代码解释

  • 实例化TrainingArguments:指定输出目录、学习率1e-4、每个设备训练/评估batch大小8、训练1个epoch、每步日志、权重衰减0.01、每个epoch保存并评估一次、训练结束时加载最佳模型。

将物体传递给训练员

TrainingArguments对象传给自定义训练器:

trainer = CustomTrainer(
model = model,
args = training_args,
train_dataset = tokenized_datasets['train'],
eval_dataset = tokenized_datasets['val'],
tokenizer = tokenizer,
data_collator = collate_fn,
compute_metrics = compute_metrics,
class_weights=class_weights,
)

train_result = trainer.train()

代码解释

  • 创建CustomTrainer对象,传入模型、训练参数、训练/验证数据、分词器、整理器、自定义指标、类别权重。
  • 调用.train()开始训练,结果存到train_result

代码解释

  • 训练走了1000步(8000条数据,batch=8,正好1000步)。
  • 耗时2小时36分钟,完成1个epoch。
  • 训练损失1.12,验证损失0.29,验证集准确率高达93%。

现在在测试数据上评估一下微调后的模型:

def generate_predictions(model,df_test):
sentences = df_test.text.tolist()
batch_size = 32
all_outputs = []

for i in range(0, len(sentences), batch_size):

batch_sentences = sentences[i:i + batch_size]

inputs = tokenizer(batch_sentences, return_tensors="pt",
padding=True, truncation=True, max_length=512)

inputs = {k: v.to('cuda' if torch.cuda.is_a vailable() else 'cpu')
for k, v in inputs.items()}

with torch.no_grad():
outputs = model(**inputs)
all_outputs.append(outputs['logits'])

final_outputs = torch.cat(all_outputs, dim=0)
df_test['predictions']=final_outputs.argmax(axis=1).cpu().numpy()

generate_predictions(model,test_df)
get_performance_metrics(test_df)

代码解释

  • 定义generate_predictions,流程和之前类似:取文本列表,分batch,分词,推理,取argmax,存回DataFrame。
  • 然后调get_performance_metrics输出结果。

结果很亮眼:准确率从训练前的0.23飙升到0.93,精度、召回率、F1也全面上涨。这充分说明,大语言模型稍加微调,就能成为非常优秀的序列分类器。

结论

总的来说,用Llama 3做序列分类的微调,从数据集准备、量化模型到训练评估,每一步都有讲究。借助HuggingFace的各种库,配合prompt工程和LoRA等技术,完全能在有限硬件上高效地让大模型完成新闻分类这类特定任务。这篇指南从零开始,走通了完整的流程:数据预处理、模型加载量化、LoRA配置、自定义训练器、评估对比,充分展示了LLM在自然语言处理任务中的灵活性和实力。

关键要点

  • 大型语言模型(比如Llama 3)在大量数据上预训练后,生成和理解文本的能力很强。
  • 光靠prompt有时不够,微调能带来更稳定的分类性能。
  • 数据集的正确加载、拆分和平衡,是训练公平准确模型的基础。
  • 自定义误差指标和训练循环,能灵活处理类别权重等特殊需求。
  • 训练前后用准确率、平衡准确率等指标评估,能直观看到微调的效果。

(完)

热点追踪提示词
你是一名 AI 行业编辑,请围绕下面这条热点输出一份资讯解读:
热点:如何从零开始微调Llama 3进行序列分类完整教程要求:
1. 先用一句话解释这条热点在讲什么
2. 再总结它为什么重要
3. 说明会影响哪些 AI 产品或内容方向
4. 最后给出 3 个适合资讯站使用的标题
来源:https://www.53ai.com/news/LargeLanguageModel/2024061396217.html
ai 人工智能

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关热点
AI热点2026-05-30 22:47
请提供原始文章标题以便优化

最近国内AI厂商的动作相当密集,大模型纷纷降价,新应用层出不穷——百小应、海螺AI、腾讯元宝轮番登场,热闹非凡。紧跟这一节奏,豆包也放出了几项新功能: - **开放新版本抢先体验入口**:更强大的能力搭配全新视觉设计,用户体验显著提升; - **推出全新桌面客户端**:实测发现,这并非简单的网页打包

AI热点2026-05-30 22:46
海螺AI市场趋势预测与行业分析建议的参考价值

海螺水泥近日发布了2025年度业绩报告,全年实现营业收入825 32亿元,同比下降9 33%,但净利润逆势增长5 42%,达到81 13亿元。这是近五年来净利润首次恢复正增长,背后核心驱动因素清晰:极致成本管控、海外高毛利业务持续扩张,叠加“水泥+”产业链延伸带来的协同效应。 如果你翻阅海螺AI生成

AI热点2026-05-30 22:46
大模型与数据治理的应用场景及实践

大模型正通过自然语言推动数据治理向对话化演进,降低技术门槛并提升效率。应用场景包括元数据发现与知识图谱生成、代码生成与校正、对话式管理界面。但仍面临幻觉、安全隐私、成本上升及数据质量等风险,需人工干预与技能培训。

AI热点2026-05-30 22:45
狗狗币测试支撑位 Allora AI应用价值飙升

先说几个核心观察。狗狗币(DOGE)目前正逼近0 10美元这个关键心理关口,更重要的是,它正在测试一个重要的技术支撑位。回顾过去一周,DOGE价格下跌了5 97%,跌至0 099美元附近。自2024年12月的高点以来,狗狗币持续走低,高点与低点同步下移,甚至一度触及0 082美元的长期支撑位。这种走

延伸阅读