基于Pytorch深度学习——SFT微调任意大模型理论以及代码——代码/参数配置/Lora微调/SFTTrainer/Merge/推理
基于Pytorch深度学习——SFT微调任意大模型理论以及代码——代码/参数配置/Lora微调/SFTTrainer/Merge/推理
SFT
SFT(Supervised Fine-Tuning)是指在已预训练的模型基础上,使用带标签的训练数据进行监督微调。这种方法通常用于自然语言处理(NLP)或计算机视觉(CV)等领域,旨在通过适应特定任务来优化模型的性能。SFT是一种在预训练基础上进行细化调整的过程,目标是使模型在特定应用上表现更好。
SFT的基本流程
预训练(Pre-training): 在大量的无标签数据上训练模型,学习通用的特征和表示(如GPT系列、BERT等语言模型)。这一步并不专注于某一个特定的任务,而是让模型具备广泛的知识和技能。
监督微调(Supervised Fine-Tuning): 在预训练的基础上,使用带有标签的数据集进一步训练模型。通过调整模型参数,使得模型在目标任务(如文本分类、情感分析、问答系统等)上能够得到更好的效果。
评估和优化(Evaluation and Optimization): 微调后的模型通常会在特定任务的数据集上进行评估,并根据结果调整超参数、优化算法等,进一步提升模型性能。
SFT的优点
节省时间和计算资源: 与从头开始训练一个全新的模型相比,SFT只需要在少量的标签数据上进行训练,从而节省了大量的计算资源和训练时间。
利用预训练模型的强大能力: 预训练模型已经学习了大量的通用知识,SFT只需通过少量的任务特定数据来调整模型,使得其在特定任务上取得更好的表现。
灵活性: SFT可以应用于多种不同的任务和领域,如文本分类、命名实体识别、机器翻译等。
代码
我们可以采用SFT框架来微调任意一个大模型, 这里为了演示的方便,我们采用Qwen2.5-0.5B模型进行演示,在实际的应用中可以将其替换成任意的模型进行微调
导入数据集
在这里我们采用Huggingface上的一个文言文和白话文转换的数据集来举例子,我们可以通过下面的代码来自动获取以及导入该数据集
from datasets import load_dataset
import os
os.environ['HF_ENDPOINT'] = "https://hf-mirror.com"
test_dataset = load_dataset("YeungNLP/firefly-train-1.1M",split="train[:500]")
在这里为了保证下载的速度,我们采用了国内的Huggingface的镜像进行下载,以及使用数据集的前500条数据进行微调
在这里我们可以先看看导入后的效果如何
test_dataset[100]
{'kind': 'ClassicalChinese', 'input': '我当时在三司,访求太祖、仁宗的手书敕令没有见到,然而人人能传诵那些话,禁止私盐的建议也最终被搁置。\n翻译成文言文:', 'target': '余时在三司,求访两朝墨敕不获,然人人能诵其言,议亦竟寝。'}
转换目标格式
通过上面的可视化的例子,我们可以发现这个数据集和Qwen所要求的数据集的格式并不一样,所以我们需要将数据格式进行转换
这里以Qwen2的目标格式为例子,目标格式如下:
<|im_start|>system
你是一个人工智能助手 <|im_end|>
<|im_start|>user
苹果的英文是什么 <|im_end|>
<|im_start|>assistant
apple <|im_end|>
所以我们可以采用下面的代码进行转换:
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
def format_prompt(example):
chat = [
{"role":"system","content":"你是一个很厉害的人工智能助手,是sjj开发的"},
{"role":"user","content":example["input"]},
{"role":'assistant',"content":example['target']}
]
prompt = tokenizer.apply_chat_template(chat,tokenize=None)
return {"text":prompt}
dataset = test_dataset.map(format_prompt, remove_columns=test_dataset.column_names)
加载模型
这里我们进行加载模型,我们这里以Qwen模型为例子,大家可以加载其他自己所需要的模型
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", device_map='auto')
Lora配置
from peft import LoraConfig, get_peft_model
peft_config = LoraConfig(
lora_alpha=32,
lora_dropout=0.1,
r=64,
bias='none',
task_type='CAUSAL_LM',
target_modules=['k_proj','v_proj','q_proj']
)
model = get_peft_model(model, peft_config)
-
lora_alpha
类型: int 或 float
描述: lora_alpha 控制了低秩矩阵的缩放因子。这个因子会影响微调后的模型的性能。具体来说,lora_alpha 会影响更新后的矩阵的权重大小,较大的 lora_alpha 可能会使模型对目标任务有更强的适应性,反之则可能更保守。
值的选择: 一般情况下,lora_alpha 的值在 8 到 64 之间,但实际值可以根据任务和模型大小调整。 -
lora_dropout
类型: float
描述: lora_dropout 控制了低秩矩阵中的 dropout 比例。Dropout 是一种正则化技术,可以帮助减少过拟合。在 LoRA 微调中,dropout 会应用于低秩矩阵的更新,以增强模型的鲁棒性。
常见值: 一般选择 0.1 或 0.2,避免过度正则化。 -
r
类型: int
描述: r 表示低秩矩阵的秩(rank)。LoRA 的基本思想是将更新的矩阵分解为两个低秩矩阵,r 就是这两个矩阵的秩。较小的 r 会减少需要更新的参数数量,从而提高训练效率。较大的 r 则可能提高模型性能,但需要更多的计算资源。
选择建议: r 一般取值在 8 到 128 之间,较小的 r 可以提高效率,但可能损失一些性能。 -
bias
类型: str
描述: bias 控制是否在低秩矩阵中使用偏置项。这个参数有三个可能的选项:
‘none’:不使用偏置项。
‘all’:在所有矩阵中使用偏置项。
‘lora’:只在 LoRA 的低秩矩阵中使用偏置项。
在大多数情况下,bias=‘none’ 是最常见的选择,除非你特别需要偏置项来改善模型性能。 -
task_type
类型: str
描述: task_type 确定了你要进行微调的任务类型。CAUSAL_LM 表示因果语言模型(Causal Language Model),例如 GPT 系列模型。如果你微调的是一个生成模型(例如,GPT),那么 task_type=‘CAUSAL_LM’ 是适用的。如果是其他任务类型(如文本分类、序列标注等),task_type 可能会有所不同。 -
target_modules
类型: list of str
描述: target_modules 指定了哪些模型模块会应用 LoRA 微调。通常来说,LoRA 会插入到注意力机制的参数中,特别是查询(q_proj)、键(k_proj) 和 值(v_proj) 的投影矩阵。这些参数对自注意力机制至关重要,因此将 LoRA 插入这些地方有助于高效地微调模型。
训练配置
from transformers import TrainingArguments
output_dir = "/data1/code/SFT/demo_result"
training_arguments = TrainingArguments(
output_dir=output_dir,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
optim='adamw_torch',
learning_rate=2e-4,
lr_scheduler_type='cosine',
num_train_epochs=1,
logging_steps=10,
fp16=False,
gradient_checkpointing=False,
save_steps=15,
max_steps=20
)
- output_dir
类型: str
描述: 该参数指定训练过程中模型保存的目录。训练完成后,模型会保存在这个目录中。通常,你会在这个目录中看到模型的检查点(checkpoints)和最终的模型文件。
例子: 在代码中,模型会被保存到指定录。 - per_device_train_batch_size
类型: int
描述: 每个设备(通常是每个 GPU 或 CPU)上用于训练的批量大小。批量大小是每次梯度更新时输入模型的样本数量。较大的批量大小可以加速训练,但需要更多的内存。
例子: per_device_train_batch_size=2 意味着每个设备(GPU 或 CPU)上每次训练使用 2 个样本。 - gradient_accumulation_steps
类型: int
描述: 梯度累积步数。这个参数允许你在小批量的情况下训练模型,而不需要增加内存使用。当 gradient_accumulation_steps 设置为 4 时,它相当于使用了一个批量大小为 per_device_train_batch_size * gradient_accumulation_steps 的大批量。即,每 4 步累积一次梯度,再进行一次反向传播。
例子: gradient_accumulation_steps=4 意味着每 4 个小批量后进行一次梯度更新。 - optim
类型: str
描述: 选择优化器。optim=‘adamw_torch’ 表示使用 PyTorch 实现的 AdamW 优化器。AdamW 是一种常用于深度学习的优化算法,它结合了梯度下降和自适应学习率调整,并且对权重衰减(L2 正则化)有良好的支持。
常见选项: ‘adamw’(默认优化器),‘adamw_torch’(PyTorch 实现),‘adamw_bnb’(支持混合精度的优化器)等。 - learning_rate
类型: float
描述: 学习率,控制模型参数更新的步长。较高的学习率可以加快收敛速度,但也容易导致不稳定;较低的学习率可能会导致收敛速度变慢。通常通过调节学习率来调整模型训练的效果。
例子: learning_rate=2e-4 表示学习率为 0.0002。 - lr_scheduler_type
类型: str
描述: 学习率调度器的类型。学习率调度器控制学习率在训练过程中的变化。‘cosine’ 表示使用余弦退火调度器,学习率会随着训练的进行逐渐降低,最后减小到 0,这有助于模型在训练的后期稳定收敛。
常见选项:
‘linear’:线性衰减。
‘cosine’:余弦退火调度。
‘constant’:保持恒定的学习率。
‘polynomial’:多项式衰减等。 - num_train_epochs
类型: int
描述: 训练的总周期数(epoch)。一个周期是指使用整个训练数据集训练一次模型。在多次循环的过程中,模型逐渐调整权重,以提高在训练集上的表现。
例子: num_train_epochs=1 表示只训练 1 个周期。 - logging_steps
类型: int
描述: 在每隔多少步后进行一次日志记录。日志记录可以包含训练损失、学习率等信息,用于监控模型训练的进度。
例子: logging_steps=10 表示每 10 步记录一次日志。 - fp16
类型: bool
描述: 是否启用混合精度训练。fp16=True 表示启用半精度浮点数(16位浮点数)训练,这可以减少内存使用并加速训练,特别是在 GPU 上。当设置为 False 时,将使用单精度(32位浮点数)。
例子: fp16=False 表示禁用混合精度训练。 - gradient_checkpointing
类型: bool
描述: 是否启用梯度检查点(gradient checkpointing)。启用后,训练过程中会在每个前向传播阶段保存一些中间计算结果,这样可以减少内存的使用,特别是在处理大型模型时。缺点是计算会稍微变慢,因为需要重新计算某些中间步骤。
例子: gradient_checkpointing=False 表示禁用梯度检查点。 - save_steps
类型: int
描述: 每隔多少步保存一次模型的检查点。训练过程中,模型会定期保存,以便于恢复训练或使用最好的模型。
例子: save_steps=15 表示每 15 步保存一次模型。 - max_steps
类型: int
描述: 设置训练的最大步数(不依赖于 epoch)。即使 num_train_epochs 已经设置了训练周期,训练也会在 max_steps 达到时停止。它通常用于限制训练的步数,确保不会超过预定的训练时长。
例子: max_steps=20 表示最多进行 20 步训练。
SFTTrainer
from trl import SFTTrainer
trainer = SFTTrainer(
model=model,
args=training_arguments,
train_dataset=dataset,
tokenizer=tokenizer,
peft_config=peft_config,
)
模型训练
trainer.train()
trainer.model.save_pretrained("/data1/code/SFT/demo_result/model")
模型合并
from peft import AutoPeftModelForCausalLM
model = AutoPeftModelForCausalLM.from_pretrained(
"/data1/code/SFT/demo_result/model",
device_map='auto'
)
merged_model = model.merge_and_unload()
模型推理
from transformers import pipeline
pip = pipeline(task="text-generation", model=merged_model, tokenizer=tokenizer)
prompt_example = """
<|im_start|>system
你是一个人工智能助手 <|im_end|>
<|im_start|>user
你好
翻译成文言文:<|im_end|>
<|im_start|>assistant
"""
print(pip(prompt_example)[0]["generated_text"])
更多推荐




所有评论(0)