简介:个人学习分享,如有错误,欢迎批评指正。
随着大规模预训练语言模型(如GPT系列、BERT等)的广泛应用,如何高效、经济地针对特定任务对这些模型进行微调(Fine-Tuning)成为研究热点。传统的微调方法通常需要调整模型的大量参数,导致计算资源消耗大、适应新任务的速度慢。为了解决这一问题,Prefix-Tuning(前缀调优)作为一种高效的微调技术被提出,旨在通过引入少量可训练的前缀参数,达到在保持原模型参数不变的情况下适应新任务的目的。
一、Prefix-Tuning概述
1.什么是Prefix-Tuning
Prefix-Tuning是一种参数高效的微调方法,最早由Li和Liang在2021年提出。该方法通过在输入序列前添加一组可训练的前缀向量(prefix),使得预训练语言模型能够在不修改其原有参数的情况下,适应特定任务
。`这些前缀向量在模型的每一层中都存在,作为额外的上下文信息引导模型生成符合任务需求的输出。
2. 前缀向量的构建与作用
前缀向量的定义:
- 前缀长度(L):指前缀中向量的数量。前缀长度通常
远小于输入序列的实际长度
。 - 前缀维度(d):每个前缀向量的维度,通常
与模型的隐藏层维度一致
。
前缀向量的构建:
- 前缀向量不是基于特定词汇的嵌入,而是由
独立的可训练参数
构成。 对于每一层 Transformer 模型,都会有独立的一组前缀向量
,这些向量会被注入到对应的层中。
前缀向量的作用:
- 前缀向量作为额外的上下文信息,与输入序列共同通过模型的注意力机制进行处理。
- 它们能够
调节注意力分布,影响模型对输入的理解和生成
,进而适应特定任务。
3. 与 Transformer 模型的集成
Transformer 模型由多层(Layers)的编码器和/或解码器堆叠而成,每层包含自注意力(Self-Attention)和前馈神经网络(Feed-Forward Network)等子层。
前缀向量在 Transformer 中的集成方式:
-
注入位置:
前缀向量
通常注入
到每一层的自注意力子层
的键(Key)和值(Value)
部分。- 在自注意力机制中,查询(Query)、键(Key)和值(Value)是从输入向量通过线性变换得到的。
-
注意力计算的调整:
- 将前缀向量作为额外的键和值,
与原始输入的键和值进行拼接
。 - 具体来说,对于每一层,前缀向量被视为虚拟的上下文信息,与实际的输入序列一起参与注意力计算。
- 将前缀向量作为额外的键和值,
具体操作步骤:
-
输入处理:
对于输入序列 X = [ x 1 , x 2 , … , x n ] X = [x_1, x_2, \ldots, x_n] X=[x1,x2,…,xn],每个 x i x_i xi 经过嵌入层得到嵌入向量 E ( x i ) E(x_i) E(xi)。 -
前缀注入:
为每一层 l l l,引入前缀向量 P l = [ p 1 l , p 2 l , … , p L l ] P^l = [p_1^l, p_2^l, \ldots, p_L^l] Pl=[p1l,p2l,…,pLl],其中 L L L 是前缀长度。 -
自注意力机制调整:
在第 l l l 层的自注意力计算中:Q = X W Q Q = X W_Q Q=XWQ
K = [ P l ; X ] W K K = [P^l; X] W_K K=[Pl;X]WK
V = [ P l ; X ] W V V = [P^l; X] W_V V=[Pl;X]WV
Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{softmax}\left( \frac{Q K^T}{\sqrt{d_k}} \right) V Attention(Q,K,V)=softmax(dkQKT)V
其中, W Q , W K , W V W_Q, W_K, W_V WQ,WK,WV 是查询、键和值的线性变换矩阵, d k d_k dk 是键向量的维度。
-
隐藏状态更新:
经过注意力机制后,隐藏状态 H l H^l Hl 被更新,并传递到下一层。
4. 前缀向量的优化与训练
参数优化:
-
冻结原模型参数:
在微调过程中,预训练模型的所有参数保持不变,仅优化前缀向量
P l P^l Pl 的参数。 -
训练目标:
根据具体任务(如分类、生成等),定义相应的损失函数,通过反向传播仅更新前缀向量。
训练流程:
-
初始化:
- 前缀向量 P l P^l Pl 通常随机初始化,或基于预训练模型的某些特征进行初始化。
-
前向传播:
- 输入序列与前缀向量共同通过模型进行前向传播,生成输出。
-
计算损失:
- 根据任务定义计算损失(如交叉熵损失)。
-
反向传播:
- 仅更新前缀向量 P l P^l Pl 的参数,保持模型其他参数不变。
-
迭代优化:
- 重复前向传播和反向传播,直至收敛或达到预设的训练轮数。
二. 技术细节与数学表述
1. Transformer 模型的基础数学原理
要理解 Prefix-Tuning,首先需要掌握 Transformer 模型的核心数学机制,尤其是自注意力(Self-Attention)机制。
自注意力机制的数学表述:
给定输入序列 X ∈ R n × d X \in \mathbb{R}^{n \times d} X∈Rn×d,其中 n n n 是序列长度, d d d 是嵌入维度。自注意力机制通过线性变换生成查询(Query)、键(Key)和值(Value)矩阵:
Q = X W Q , K = X W K , V = X W V Q = X W_Q, \quad K = X W_K, \quad V = X W_V Q=XWQ,K=XWK,V=XWV
其中, W Q , W K , W V ∈ R d × d k W_Q, W_K, W_V \in \mathbb{R}^{d \times d_k} WQ,WK,WV∈Rd×dk 是可训练的权重矩阵, d k d_k dk 是查询和键的维度。
注意力得分(Attention Scores)通过点积计算,并经过缩放和 softmax 函数归一化:
Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{softmax}\left( \frac{Q K^T}{\sqrt{d_k}} \right) V Attention(Q,K,V)=softmax(dkQKT)V
多头注意力(Multi-Head Attention):
为了增强模型的表示能力,Transformer 使用多头注意力机制,将 Q , K , V Q, K, V Q,K,V 分成多个头进行并行计算,然后拼接结果:
MultiHead ( Q , K , V ) = Concat ( head 1 , head 2 , … , head h ) W O \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \text{head}_2, \ldots, \text{head}_h) W_O MultiHead(Q,K,V)=Concat(head1,head2,…,headh)WO
其中,每个头的计算方式相同, W O ∈ R ( h ⋅ d k ) × d W_O \in \mathbb{R}^{(h \cdot d_k) \times d} WO∈R(h⋅dk)×d 是输出的线性变换矩阵。
2. Prefix-Tuning 的核心数学机制
Prefix-Tuning 的核心思想是在每一层 Transformer 的自注意力机制中引入一组可训练的前缀向量,这些前缀向量作为额外的键和值,影响注意力的分布,从而引导模型适应特定任务
。
引入前缀向量:
对于每一层
l
l
l,引入前缀向量
P
l
∈
R
L
×
d
P^l \in \mathbb{R}^{L \times d}
Pl∈RL×d,其中
L
L
L 是前缀长度。前缀向量不对应任何实际的词汇,而是作为虚拟的上下文向量存在
。
调整自注意力机制:
在每一层 l l l,将前缀向量 P l P^l Pl 通过线性变换生成前缀的键和值:
K p l = P l W K , V p l = P l W V K_p^l = P^l W_K, \quad V_p^l = P^l W_V Kpl=PlWK,Vpl=PlWV
然后,将这些前缀键值与原始输入的键值进行拼接:
K ′ l = [ K p l K l ] , V ′ l = [ V p l V l ] K'^l = \begin{bmatrix} K_p^l \\ K^l \end{bmatrix}, \quad V'^l = \begin{bmatrix} V_p^l \\ V^l \end{bmatrix} K′l=[KplKl],V′l=[VplVl]
自注意力计算公式变为:
Attention ( Q l , K ′ l , V ′ l ) = softmax ( Q l ( K ′ l ) T d k ) V ′ l \text{Attention}(Q^l, K'^l, V'^l) = \text{softmax}\left( \frac{Q^l (K'^l)^T}{\sqrt{d_k}} \right) V'^l Attention(Ql,K′l,V′l)=softmax(dkQl(K′l)T)V′l
其中,
Q l = X l W Q , K l = X l W K , V l = X l W V , X l 是第 l 层的输入。 Q^l = X^l W_Q, \quad K^l = X^l W_K, \quad V^l = X^l W_V, \quad X^l \text{ 是第 } l \text{ 层的输入。} Ql=XlWQ,Kl=XlWK,Vl=XlWV,Xl 是第 l 层的输入。
通过引入 K p l K_p^l Kpl 和 V p l V_p^l Vpl,前缀向量 P l P^l Pl 作为额外的信息源,能够调整注意力分布,进而影响模型的输出。
3. 前缀向量的参数化与集成
前缀向量的参数化:
每一层
l
l
l 的前缀矩阵
P
l
P^l
Pl 是一组可训练的参数
,这些参数在微调过程中被优化。前缀向量的初始化通常采用随机初始化或基于预训练模型的嵌入初始化。
前缀向量的集成:
在每一层 Transformer 中,前缀向量通过拼接操作与原始的键和值结合,具体步骤如下:
-
前缀嵌入生成:
对于每一层 l l l,前缀矩阵 P l ∈ R L × d P^l \in \mathbb{R}^{L \times d} Pl∈RL×d
通过线性变换生成前缀的键和值
:K p l = P l W K , V p l = P l W V K_p^l = P^l W_K, \quad V_p^l = P^l W_V Kpl=PlWK,Vpl=PlWV
-
拼接操作:
将前缀键值与输入的键值拼接,形成扩展后的键值矩阵 K ′ l K'^l K′l 和 V ′ l V'^l V′l:
K ′ l = [ K p l K l ] , V ′ l = [ V p l V l ] K'^l = \begin{bmatrix} K_p^l \\ K^l \end{bmatrix}, \quad V'^l = \begin{bmatrix} V_p^l \\ V^l \end{bmatrix} K′l=[KplKl],V′l=[VplVl]
-
注意力计算:
使用扩展后的键值矩阵进行自注意力计算:
Attention ( Q l , K ′ l , V ′ l ) = softmax ( Q l ( K ′ l ) T d k ) V ′ l \text{Attention}(Q^l, K'^l, V'^l) = \text{softmax}\left( \frac{Q^l (K'^l)^T}{\sqrt{d_k}} \right) V'^l Attention(Ql,K′l,V′l)=softmax(dkQl(K′l)T)V′l
参数量分析:
假设模型有 L L L 层,每层前缀长度为 P P P,嵌入维度为 d d d,则总的前缀参数量为:
Total Parameters = L × P × d \text{Total Parameters} = L \times P \times d Total Parameters=L×P×d
相比于全模型微调所需的庞大参数量,Prefix-Tuning 显著减少了需要优化的参数数量。
4. 损失函数与优化目标
任务定义:
根据具体任务(如文本分类、生成等),定义相应的损失函数。常见的任务损失函数包括交叉熵损失(Cross-Entropy Loss)、均方误差损失(Mean Squared Error Loss)等。
损失函数的数学表述:
以分类任务为例,假设模型的输出为 Y ^ \hat{Y} Y^,真实标签为 Y Y Y,交叉熵损失定义为:
L = − ∑ i = 1 N Y i log ( Y ^ i ) \mathcal{L} = -\sum_{i=1}^N Y_i \log(\hat{Y}_i) L=−i=1∑NYilog(Y^i)
其中, N N N 是类别数量。
优化目标:
优化的目标是最小化损失函数:
min { P l } L \min_{\{P^l\}} \mathcal{L} {Pl}minL
其中, { P l } \{P^l\} {Pl} 表示所有层的前缀矩阵。
5. 梯度更新与反向传播
前向传播:
- 输入序列 X X X 通过嵌入层生成嵌入向量 E ( X ) E(X) E(X)。
- 每一层引入前缀矩阵 P l P^l Pl,通过线性变换生成前缀键值 K p l , V p l K_p^l, V_p^l Kpl,Vpl。
- 拼接前缀键值与输入键值,计算自注意力输出。
- 通过前馈神经网络和层归一化等操作,得到当前层的输出 X l + 1 X^{l+1} Xl+1。
- 最终输出用于计算损失。
反向传播与梯度更新:
在反向传播过程中,仅计算并更新前缀矩阵 P l P^l Pl 的梯度,其余模型参数保持不变。
梯度更新公式:
以梯度下降法为例,前缀矩阵的更新规则为:
P l ← P l − η ∂ L ∂ P l P^l \leftarrow P^l - \eta \frac{\partial \mathcal{L}}{\partial P^l} Pl←Pl−η∂Pl∂L
其中, η \eta η 是学习率, ∂ L ∂ P l \frac{\partial \mathcal{L}}{\partial P^l} ∂Pl∂L 是损失函数对前缀矩阵的梯度。
参数冻结:
通过设置模型的其他参数
W
Q
,
W
K
,
W
V
,
W
O
W_Q, W_K, W_V, W_O
WQ,WK,WV,WO 等为冻结状态(即 requires_grad = False
),确保在训练过程中这些参数不会被更新。
6. 数学表示的示例
为了更具体地展示 Prefix-Tuning 的数学机制,以下通过一个具体的数学表示示例进行说明。
假设条件:
- 输入序列长度 n = 3 n = 3 n=3
- 前缀长度 L = 2 L = 2 L=2
- 嵌入维度 d = 4 d = 4 d=4
- 键值维度 d k = 4 d_k = 4 dk=4
输入与前缀矩阵:
输入序列的嵌入表示:
X = [ x 1 x 2 x 3 ] ∈ R 3 × 4 X = \begin{bmatrix} x_1 \\ x_2 \\ x_3 \end{bmatrix} \in \mathbb{R}^{3 \times 4} X= x1x2x3 ∈R3×4
前缀矩阵:
P l = [ p 1 p 2 ] ∈ R 2 × 4 P^l = \begin{bmatrix} p_1 \\ p_2 \end{bmatrix} \in \mathbb{R}^{2 \times 4} Pl=[p1p2]∈R2×4
线性变换:
假设 W Q , W K , W V ∈ R 4 × 4 W_Q, W_K, W_V \in \mathbb{R}^{4 \times 4} WQ,WK,WV∈R4×4 为已知矩阵。
计算查询、键和值:
Q = X W Q ∈ R 3 × 4 , K = X W K ∈ R 3 × 4 , V = X W V ∈ R 3 × 4 Q = X W_Q \in \mathbb{R}^{3 \times 4}, \quad K = X W_K \in \mathbb{R}^{3 \times 4}, \quad V = X W_V \in \mathbb{R}^{3 \times 4} Q=XWQ∈R3×4,K=XWK∈R3×4,V=XWV∈R3×4
前缀键值:
K p = P l W K ∈ R 2 × 4 , V p = P l W V ∈ R 2 × 4 K_p = P^l W_K \in \mathbb{R}^{2 \times 4}, \quad V_p = P^l W_V \in \mathbb{R}^{2 \times 4} Kp=PlWK∈R2×4,Vp=PlWV∈R2×4
拼接操作:
扩展后的键和值:
K ′ = [ K p K ] ∈ R 5 × 4 , V ′ = [ V p V ] ∈ R 5 × 4 K' = \begin{bmatrix} K_p \\ K \end{bmatrix} \in \mathbb{R}^{5 \times 4}, \quad V' = \begin{bmatrix} V_p \\ V \end{bmatrix} \in \mathbb{R}^{5 \times 4} K′=[KpK]∈R5×4,V′=[VpV]∈R5×4
注意力计算:
查询矩阵 Q Q Q 与扩展后的键矩阵 K ′ l K'^l K′l 的点积:
Q K ′ l T = [ q 1 ⋅ k 1 ′ q 1 ⋅ k 2 ′ ⋯ q 1 ⋅ k 5 ′ q 2 ⋅ k 1 ′ q 2 ⋅ k 2 ′ ⋯ q 2 ⋅ k 5 ′ q 3 ⋅ k 1 ′ q 3 ⋅ k 2 ′ ⋯ q 3 ⋅ k 5 ′ ] ∈ R 3 × 5 Q {K'^l}^T = \begin{bmatrix} q_1 \cdot k'_1 & q_1 \cdot k'_2 & \cdots & q_1 \cdot k'_5 \\ q_2 \cdot k'_1 & q_2 \cdot k'_2 & \cdots & q_2 \cdot k'_5 \\ q_3 \cdot k'_1 & q_3 \cdot k'_2 & \cdots & q_3 \cdot k'_5 \end{bmatrix} \in \mathbb{R}^{3 \times 5} QK′lT= q1⋅k1′q2⋅k1′q3⋅k1′q1⋅k2′q2⋅k2′q3⋅k2′⋯⋯⋯q1⋅k5′q2⋅k5′q3⋅k5′ ∈R3×5
缩放与 softmax:
Attention Scores = softmax ( Q K ′ l T 4 ) ∈ R 3 × 5 \text{Attention Scores} = \text{softmax}\left( \frac{Q {K'^l}^T}{\sqrt{4}} \right) \in \mathbb{R}^{3 \times 5} Attention Scores=softmax(4QK′lT)∈R3×5
注意力输出:
Attention ( Q , K ′ , V ′ ) = Attention Scores ⋅ V ′ ∈ R 3 × 4 \text{Attention}(Q, K', V') = \text{Attention Scores} \cdot V' \in \mathbb{R}^{3 \times 4} Attention(Q,K′,V′)=Attention Scores⋅V′∈R3×4
损失与优化:
假设目标输出为 Y ∈ R 3 × 4 Y \in \mathbb{R}^{3 \times 4} Y∈R3×4,定义均方误差损失:
L = 1 3 ∑ i = 1 3 ∥ Attention ( Q , K ′ , V ′ ) i − Y i ∥ 2 \mathcal{L} = \frac{1}{3} \sum_{i=1}^{3} \| \text{Attention}(Q, K', V')_i - Y_i \|^2 L=31i=1∑3∥Attention(Q,K′,V′)i−Yi∥2
通过最小化 L \mathcal{L} L,优化前缀矩阵 P l P^l Pl:
P l ← P l − η ∂ L ∂ P l P^l \leftarrow P^l - \eta \frac{\partial \mathcal{L}}{\partial P^l} Pl←Pl−η∂Pl∂L
7. 实现步骤与流程
以下是 Prefix-Tuning 在实践中的具体实现步骤:
-
选择预训练模型:
- 选择适合任务的预训练 Transformer 模型(如 GPT-3、BERT 等)。
-
确定前缀参数:
- 设置前缀长度 L L L。
- 为每一层的前缀向量 P l P^l Pl 初始化可训练参数。
-
模型集成:
- 修改模型的自注意力子层,使其在每层注入前缀向量。
- 确保前缀向量与输入序列在注意力计算中正确拼接。
-
冻结原模型参数:
- 设置预训练模型的参数为冻结状态,仅允许前缀向量的参数在训练过程中更新。
-
定义训练目标:
- 根据任务需求(如分类、生成等)定义损失函数。
-
训练前缀向量:
- 使用任务特定的数据,通过反向传播优化前缀向量。
- 通常使用标准的优化器(如 Adam)进行参数更新。
-
评估与应用:
- 在验证集上评估模型性能,调整前缀长度或其他超参数。
- 将训练好的前缀向量应用于测试集或实际应用中。
8. 扩展与优化
动态 Prefix-Tuning:
传统的 Prefix-Tuning 使用固定的前缀向量,但在某些场景下,动态调整前缀向量可以进一步提升模型的适应能力。动态 Prefix-Tuning 通过根据输入上下文或任务需求,生成或调整前缀向量,使其更加灵活和高效。
多任务 Prefix-Tuning:
在多任务学习中,为每个任务设计独立的前缀向量,通过在不同任务间切换前缀,实现同一模型在多个任务上的适应。这种方法不仅减少了参数量,还提升了模型的灵活性和泛化能力。
结合其他微调方法:
将 Prefix-Tuning 与 Adapter 方法、Prompt-Tuning 等结合,利用各自的优势,进一步优化微调效果。例如,在每层前缀向量的基础上,插入 Adapter 模块,增强模型的适应性和表达能力。
三、实例:使用 Prefix-Tuning 对 LLaMA2 进行微调
1. 环境配置
你可以使用以下命令安装所需的库:
pip install transformers
pip install peft
pip install datasets
pip install accelerate
pip install torch
2. 数据准备
为了展示微调过程,我们将使用一个简单的文本分类任务作为示例。你可以根据需要更改为其他任务(如文本生成、问答等)。
假设我们使用的是 AG News
数据集,它包含四个新闻类别的文本数据。你可以使用 Hugging Face 的 datasets 库轻松加载该数据集。
from datasets import load_dataset
# 加载 AG News 数据集
dataset = load_dataset("ag_news")
3. 模型与 Tokenizer 加载
我们将使用 LLaMA2 的一个变体,例如 llama2-7b
。请确保你有权访问该模型,并且已在 Hugging Face Hub 上正确设置访问权限。
from transformers import LlamaTokenizer, LlamaForCausalLM
# 模型名称(根据实际情况选择)
model_name = "meta-llama/Llama-2-7b-hf"
# 加载 Tokenizer
tokenizer = LlamaTokenizer.from_pretrained(model_name)
# 加载预训练的 LLaMA2 模型
model = LlamaForCausalLM.from_pretrained(
model_name,
load_in_8bit=False, # 根据你的硬件选择是否使用 8-bit
device_map="auto"
)
4. Prefix-Tuning 配置
使用 PEFT 库配置 Prefix-Tuning。我们将为每一层的自注意力机制引入前缀向量,从而实现参数高效的微调。
from peft import PrefixTuningConfig, get_peft_model
# 配置 Prefix-Tuning
prefix_tuning_config = PrefixTuningConfig(
task_type="SEQ_CLS", # 任务类型,这里为序列分类
num_virtual_tokens=10, # 前缀长度
num_layers=model.config.num_hidden_layers, # Transformer 层数
hidden_size=model.config.hidden_size # 隐藏层大小
)
# 将 Prefix-Tuning 应用于模型
model = get_peft_model(model, prefix_tuning_config)
5. 训练设置
使用 Hugging Face 的 Trainer 类来管理训练过程。我们需要定义训练参数、数据预处理函数和评估指标。
from transformers import TrainingArguments, Trainer, DataCollatorWithPadding
import torch
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
# 数据预处理函数
def preprocess_function(examples):
# 拼接文本和标签
texts = examples["text"]
labels = examples["label"]
inputs = [f"Classify the following news: {text}" for text in texts]
# 编码输入
model_inputs = tokenizer(inputs, max_length=512, truncation=True)
# 添加标签
model_inputs["labels"] = labels
return model_inputs
# 应用预处理函数
encoded_dataset = dataset.map(preprocess_function, batched=True)
# 数据分块
train_dataset = encoded_dataset["train"]
eval_dataset = encoded_dataset["test"]
# 数据收集器
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
# 定义评估指标
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = torch.argmax(torch.tensor(logits), dim=-1)
acc = accuracy_score(labels, predictions)
precision, recall, f1, _ = precision_recall_fscore_support(labels, predictions, average='weighted')
return {
"accuracy": acc,
"precision": precision,
"recall": recall,
"f1": f1,
}
# 定义训练参数
training_args = TrainingArguments(
output_dir="./prefix_tuning_llama2_ag_news",
evaluation_strategy="epoch",
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
num_train_epochs=3,
learning_rate=5e-5,
weight_decay=0.01,
save_strategy="epoch",
logging_dir="./logs",
logging_steps=10,
fp16=True, # 如果支持,使用半精度
)
6. 训练与评估
使用 Trainer 类初始化训练过程,并开始训练和评估。
# 初始化 Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
tokenizer=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
)
# 开始训练
trainer.train()
# 评估模型
trainer.evaluate()
7. 完整代码示例
以下是上述步骤的完整代码整合,便于复制和运行。
# 1. 导入必要的库
from transformers import LlamaTokenizer, LlamaForCausalLM, TrainingArguments, Trainer, DataCollatorWithPadding
from peft import PrefixTuningConfig, get_peft_model
from datasets import load_dataset
import torch
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
# 2. 加载 AG News 数据集
dataset = load_dataset("ag_news")
# 3. 模型名称
model_name = "meta-llama/Llama-2-7b-hf"
# 4. 加载 Tokenizer
tokenizer = LlamaTokenizer.from_pretrained(model_name)
# 5. 加载预训练的 LLaMA2 模型
model = LlamaForCausalLM.from_pretrained(
model_name,
load_in_8bit=False, # 根据需要调整
device_map="auto"
)
# 6. 配置 Prefix-Tuning
prefix_tuning_config = PrefixTuningConfig(
task_type="SEQ_CLS",
num_virtual_tokens=10,
num_layers=model.config.num_hidden_layers,
hidden_size=model.config.hidden_size
)
model = get_peft_model(model, prefix_tuning_config)
# 7. 数据预处理函数
def preprocess_function(examples):
texts = examples["text"]
labels = examples["label"]
inputs = [f"Classify the following news: {text}" for text in texts]
model_inputs = tokenizer(inputs, max_length=512, truncation=True)
model_inputs["labels"] = labels
return model_inputs
# 8. 应用预处理函数
encoded_dataset = dataset.map(preprocess_function, batched=True)
# 9. 数据分割
train_dataset = encoded_dataset["train"]
eval_dataset = encoded_dataset["test"]
# 10. 数据收集器
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
# 11. 定义评估指标
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = torch.argmax(torch.tensor(logits), dim=-1)
acc = accuracy_score(labels, predictions)
precision, recall, f1, _ = precision_recall_fscore_support(labels, predictions, average='weighted')
return {
"accuracy": acc,
"precision": precision,
"recall": recall,
"f1": f1,
}
# 12. 定义训练参数
training_args = TrainingArguments(
output_dir="./prefix_tuning_llama2_ag_news",
evaluation_strategy="epoch",
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
num_train_epochs=3,
learning_rate=5e-5,
weight_decay=0.01,
save_strategy="epoch",
logging_dir="./logs",
logging_steps=10,
fp16=True, # 根据硬件支持情况调整
)
# 13. 初始化 Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
tokenizer=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
)
# 14. 开始训练
trainer.train()
# 15. 评估模型
trainer.evaluate()
# 16. 保存微调后的模型
model.save_pretrained("./prefix_tuned_llama2_ag_news")
tokenizer.save_pretrained("./prefix_tuned_llama2_ag_news")
总结
Prefix-Tuning 作为一种创新的微调方法,通过在预训练模型的每一层引入少量可训练的前缀向量,成功实现了在不调整原模型参数的情况下,对特定任务的高效适应。其工作原理涉及前缀向量的构建、与 Transformer 模型的深度集成、前缀向量的优化与训练等关键步骤。与其他微调方法相比,Prefix-Tuning 在参数效率、适应性和灵活性方面表现出显著优势,使其在多任务学习、资源受限环境和快速模型适应等场景中展现出广阔的应用前景。随着研究的不断深入,Prefix-Tuning 及其衍生方法有望在自然语言处理及其他领域发挥更大的作用,推动智能模型的发展与应用。
结~~~