文章目录 展开 收起

实验

LoRA

2026-11-11

以一个微调例子学习 LoRA。

微调 Qwen3-8B ,在 Tweetteval 数据集上学会情感句子三分类。了解到 Prompt Masking 、梯度累加降低显存占用。

LoRA 实验

LoRA 公式

WLoRA=Worigin+αrΔWΔW=B×AW=N×D,B=N×r,A=r×DW_{LoRA} = W_{origin} + \frac{\alpha}{r}\Delta W\\ \Delta W=B \times A \\ \\ W=N\times D, B =N\times r, A=r \times D h=x⋅WLoRA=x⋅Worigin+x⋅ΔWh = x \cdot W_{LoRA} = x \cdot W_{origin} + x \cdot \Delta W

参数设置:尤其和显存相关

详细解释一下大模型这里面的参数

CFG = dict(model_id='Qwen/Qwen3-8B', 
    dataset_id='cardiffnlp/tweet_eval', dataset_config='sentiment', dataset_revision='b3a375baf0f409c77e6bc7aa35102b7b3534f8be',
    seed=42, train_size=16000, validation_size=1000, test_size=3000,
    max_length=512, max_review_tokens=512, eval_batch_size=8, max_new_tokens=8,
    r=8, lora_alpha=16, lora_dropout=0.05, target_modules=['q_proj', 'v_proj'],
    train_batch_size=1, gradient_accumulation_steps=8, epochs=3, learning_rate=1e-4,
    warmup_ratio=0.05, weight_decay=0.0, scheduler='linear', optim='adamw_torch',
    enable_thinking=False, do_sample=False, num_beams=1)
  • max_length=512 限定死训练 Token 序列的最大长度。

    • 首先知道,模型在训练的时候 Token 序列有个最大长度。 这是模型的最大上下文窗口。推理时,如果遇到超出训练时模型见过的最大 Token 序列长度,模型在长位置的理解能力变差(模型没在这些位置训练过),模型能力会下降。所以衡量看一个模型强不强的指标之一,看看他支持的最大上下文长度。

    • 现代大模型训练,是保证一个 batch 内所有Token 序列长度一致,不足的序列 pad 到最长的那个序列;

    • Qwen3-8B 上下文窗口32K,为啥要定死到 512?省显存。Q K V 张量都有一个维度是序列长度 S,S 越大,显存占用越多;

    • 提到显存,LoRA 时占用显存的都是什么?

      1 原来模型的权重参数依然全部加载进显存;8B、BF16 大概占 15GiB;(原始权重依然参与前向计算,但是参数不更新)

      2 前向传播的激活值:

      3 需要更新的参数梯度(LoRA 省显存的原因);LoRA 的矩阵 A B 的参数的梯度都要保存;因为参数更新的方式:

      Wnew=Wold−lr×∇WW_{new} = W_{old} - lr \times \nabla W

      AdamW 要保存两个矩阵:一阶矩和二阶矩的平方。因为原矩阵不用更新,不用保存梯度,所以省了很大显存,

      4 LoRA 本身的参数

  • LoRA 配置

    r=8; r 越小,对显存要求越低,比较保守的选择,适合小任务;

    lora_alpha=16,低秩矩阵的系数;

    lora_dropout=0.05 随机让神经网失活,防止过拟合;

    target_modules = [“q_proj”, “v_proj”] 对每一个 Transformer Block,在 Q V 的投影矩阵注入 LoRA。 这是 一个比较小的配置。

    总体参考了 huggingface 教程的设置。

答案怎么计入 Loss:Prompt Masking 屏蔽提示词

监督微调和指令微调的通用标准。

一个大模型的训练经过两个阶段:预训练、后训练。

预训练阶段:无监督,让模型根据海量文本,学会预测下一个 Token;模型这一步只是学会了人类世界的语法,他不会聊天(答非所问);

后训练:就是我们的监督微调Supervised Fine-Tuning。我们是用 Chat Template 去微调大模型,送个大模型的有 system prompt, assiatant 的思考过程 和 真正需要回答的问题。

举一个例子:对于一个情感二分类问题,我们想要模型判断的句子是:

I saw a dog yesterday, that looked like one of the wolves from twilight but smaller, was well cool

真正送入模型的文本是:

<|im_start|>system
You are a sentiment classifier. Output exactly one label: negative, neutral, or positive.<|im_end|>
<|im_start|>user
Classify the sentiment of this tweet: "I saw a dog yesterday, that looked like one of the wolves from twilight but smaller, was well cool"<|im_end|>
<|im_start|>assistant
<think>
</think>

前面有一大段都是 prompt。只有 cool 对应的 Token 才参与计算 Loss。

哪些 Token 做前向计算?

所有 Token 全部参与前向计算;

哪些 Token 参与 Loss 计算?(前面提到,正常一个 Batch 所有句子的所有 Token 前向传播得到的算损失都会累加)

只有 要预测 Positive 的那个 Token 参与计算 Loss(句子的末尾):cool 对应的 Token ,预测的下一个词 要 和正确答案计算损失。(其实还有<|im_end|>也计算损失,教会模型什么时候停止)

为什么要Prompt Masking or 为什么前面的 Token 不参与计算 Loss?

训练时候一个 Batch 的所有句子都前向传播,预测下一个输出。

我们想看模型能不能预测出 Positive。不关注模型在 dog 这个位置有没有正确预测出 yesterday。让训练集中在预测类别上。

屏蔽 Token 是什么意思?在计算上对应什么?

不参与Loss 计算。

代码是怎么实现的?

input_ids 会记录所有 Token 的 id,模型照常读取,前向传播,但是被屏蔽的 Token 对应的 label 是-100. -100 是 Magic Number。Pytorch 的很多分类损失函数,看到 label=-100 时,不计算损失。

下标是真实训练时,Token 和对应的 Label:

positioninput_idtokenattention_masklabel
55556521Wed1-100
565613.1-100
575755547Absolutely1-100
585810245loved1-100
5959279the1-100
60601473show1-100
61610!1-100
6262151645<|im_end|>1-100
6363198\n1-100
6464151644<|im_start|>1-100
656577091assistant1-100
6666198\n1-100
67671516671-100
6868271\n\n1-100
69691516681-100
7070271\n\n1-100
717130487positive130487
7272151645<|im_end|>1151645

注入 LoRA

lora_config=LoraConfig(r=CFG['r'],lora_alpha=CFG['lora_alpha'],lora_dropout=CFG['lora_dropout'],
    target_modules=CFG['target_modules'],bias='none',task_type='CAUSAL_LM')
model=get_peft_model(model,lora_config)
model.print_trainable_parameters() # 打印参数;
# trainable params: 3,833,856 || all params: 8,194,569,216 || trainable%: 0.0468

最终效果

指标微调前微调后变化
Accuracy66.37%73.23%+6.87
正面 F163.20%80.42%+17.21
负面 F176.65%78.58%+1.93
中性 F159.48%59.24%−0.24
Macro-F166.44%72.75%+6.30