在 AI 快速发展的当下,大模型已广泛应用于自然语言处理、计算机视觉等领域。但通用大模型如同万能钥匙,面对特定精细化任务时难以满足需求。大模型微调技术由此诞生,它能让模型更好适配特定任务,显著提升性能。如果你是想入门大模型微调的新手,这份全流程指南将助你一臂之力。接下来,让我们开启探索之旅。
1、什么是大模型微调?
大模型微调,从本质上来说,是在已经预训练好的大型模型基础上,利用特定任务或领域的数据,对模型的参数进行进一步优化调整的过程。预训练的大模型,例如 GPT、BERT 等,它们在海量的通用数据上经过长时间的无监督或自监督学习,已经积累了丰富的知识,学会了对各种数据的通用理解和表示能力。就像一个博学多才的学者,对各个领域都有广泛的了解。然而,当面对具体的专业领域问题时,这位 “学者” 可能还需要进一步的专业培训。大模型微调就是这样的培训过程,通过特定任务数据的 “喂养”,让模型更加精通特定领域的知识和技能,从而在该特定任务上发挥出更出色的性能。
2、为什么要进行大模型微调
-
提升模型性能:微调能够显著提升模型在特定任务上的性能。以情感分析任务为例,通用的大模型虽然对一般文本的情感倾向有一定的判断能力,但对于一些特定领域的文本,如电商产品评论中的情感分析,由于其中可能包含大量专业术语、行业特定的表达方式等,通用模型的准确率往往不尽人意。通过使用电商领域的产品评论数据对模型进行微调,模型能够学习到该领域文本的特点和规律,从而更准确地判断评论的情感是积极、消极还是中性,大大提高了模型在电商情感分析任务上的性能。
-
节省计算资源和时间:与从头开始训练一个全新的模型相比,微调大模型所需的数据量和计算资源要少得多。训练一个大型模型需要海量的数据、强大的计算设备以及漫长的训练时间,这对于大多数个人开发者和小型企业来说是难以承受的。而预训练模型已经在大规模数据上完成了基础的学习,我们只需利用少量与特定任务相关的数据对其进行微调,就能快速得到一个适用于该任务的高性能模型,大大缩短了训练时间和降低了训练成本。
-
增强模型的适应性:不同的行业和应用场景对模型的需求各不相同。通过微调,我们可以使大模型更好地适应特定领域的需求和特点。比如在医疗领域,用于疾病诊断的模型需要能够准确理解医学术语、病历文本的结构和含义;在金融领域,用于风险评估的模型需要对金融数据的特征和趋势有敏锐的感知。通过使用相应领域的数据对大模型进行微调,模型能够学习到这些领域的专业知识和语言习惯,从而提供更符合领域需求的预测和分析结果,增强了模型在不同行业和场景中的适应性。
3、微调需要哪些基础知识?
初学者在进行微调之前,建议掌握以下几个关键点:
- 预训练(Pre-training)与微调(Fine-tuning)区别
- 预训练:模型初始阶段的大规模通用训练,学习广泛的知识。
- 微调:针对具体任务,利用小型的特定数据集进行二次训练。
- 微调数据的准备
- 数据收集和清洗:确保数据质量高、相关性强。
- 数据格式:常用的是JSON、CSV或特定的文本格式,如Prompt-Completion对。
- 参数与超参数的基础知识
- 参数(Parameters):模型自身学习的权重。
- 超参数(Hyperparameters):如学习率(Learning Rate)、批次大小(Batch Size)、Epoch数量、优化器(Optimizer)等,影响训练过程的设置参数。
- 评估微调效果
- 使用指标如BLEU、ROUGE、准确率(Accuracy)、F1-Score等,针对不同任务选择合适的评估标准。
4、 微调前的准备:环境配置与模型获取
在开始微调之前,我们需要做好开发环境的配置,并了解硬件和模型准备方面的要求。
硬件与GPU需求: 微调大型模型对GPU显存要求较高。以Qwen2.5-7B(约70亿参数)为例,完整加载该模型需要大约15GB以上的显存(FP16精度)。如果使用参数高效微调技术(如8-bit量化或LoRA),7B模型在单张16GB显存的GPU上通常可以微调;但如果是全量微调14B或更大的模型,可能需要24GB甚至更高显存,或者采用更激进的内存优化(如4-bit量化)。建议使用支持CUDA的NVIDIA GPU,并确保已安装相应的显卡驱动和CUDA Toolkit。
操作系统与依赖: 推荐使用Linux或类似的64位操作系统环境。安装最新版的 Python 3.8+ 和 PyTorch深度学习框架(建议PyTorch 2.x,已支持GPU)。然后,通过pip
或conda
安装Hugging Face的Transformers库和相关工具:
pip install transformers peft datasets bitsandbytes accelerate
transformers
是Hugging Face提供的模型加载和训练库。peft
(Parameter-Efficient Fine-Tuning) 提供了LoRA、P-Tuning等微调方法的实现。datasets
方便加载和处理训练数据(可选,如果您使用Hugging Face Datasets)。bitsandbytes
用于8-bit/4-bit量化支持,如果您计划使用QLoRA或8-bit加载模型。accelerate
则有助于分布式训练和混合精度训练(单卡情况下不是必需,但安装无妨)。
确保Transformers版本兼容: Qwen2.5模型已经整合进Transformers库(需版本≥4.37.0)。使用足够新的Transformers可以直接加载Qwen模型而不需要trust_remote_code=True
(旧版可能需要这个参数)。如果遇到Tokenizer class QWenTokenizer does not exist
之类的错误,可尝试升级或降低相关库版本。
下载模型权重: 您可以通过Hugging Face Hub获取Qwen2.5模型。例如,我们以7B的指令微调版模型为基准:
from transformers import AutoTokenizer, AutoModelForCausalLM
model_name = "Qwen/Qwen2.5-7B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", torch_dtype="auto")
第一次运行时,上述代码将自动从互联网下载模型权重并缓存(需确保网络畅通)。device_map="auto"
会将模型自动加载到GPU(若有多个GPU可平摊内存)。这里我们让torch_dtype="auto"
自动选择精度(一般会是FP16/BF16),以减少显存占用。下载7B模型需要占用约十几GB磁盘空间,请提前确保空间充足。
huggingface-cli download Qwen/Qwen2.5-7B-Instruct --extension safetensors
- 这样可以离线获取
safetensors
格式的模型文件,然后通过from_pretrained
加载本地路径。
完成以上环境和模型准备后,我们就可以着手选择合适的微调技术并开始训练了。
5、 微调技术概览:LoRA、QLoRA、P-Tuning 与全参数微调
大语言模型的微调方法多种多样,对于初学者来说,常见的几种技术各有特点。我们简要介绍它们的原理、优缺点和适用场景:
LoRA(Low-Rank Adaptation,低秩适配):LoRA通过在模型的部分权重上添加可训练的低秩矩阵来实现微调。简单来说,就是冻结原模型的大部分参数,仅在每层中引入很小的瓶颈层进行训练。这样做大幅减少了需要更新的参数数量。LoRA的优点是内存开销小、训练高效,在下游任务上的效果通常接近全参数微调。并且多个LoRA适配器可以在一个基模型上切换,方便一个模型服务多种任务。LoRA不增加推理时延,因为微调完可以将低秩权重与原权重合并。实验表明,使用LoRA微调后的性能往往与全量微调相当,但显存占用和计算量却显著降低。缺点是LoRA仍需加载完整的预训练模型作为基础(但可以使用8-bit/4-bit量化减小内存,占用稍高于更轻量的P-Tuning)。LoRA适用于中大型模型在中小规模数据上的高效微调,是目前社区中极为流行的方案。
QLoRA(Quantized LoRA,量化 LoRA):QLoRA可以看作是在LoRA基础上的进一步优化。它的核心是在训练时将预训练模型权重以4比特精度加载,大幅降低显存占用,同时同样仅训练LoRA低秩适配器。创新之处在于4-bit量化采用了Norm浮点格式(NF4)等技术,尽可能减少量化带来的性能损。研究表明,QLoRA在单张48GB GPU上就能微调65B参数的模型,而且性能与全16位精度微调几乎持平!这意味着,即使只有一块高端GPU,也能微调过去需要数十张GPU的大模型,这对普通开发者来说是革命性的。QLoRA的优点是极致地节省显存(比LoRA进一步减半左右),使单卡可微调更大的模型。缺点是实现稍复杂,需要依赖如bitsandbytes
、可能还需要DeepSpeed等库支持4-bit训练,而且由于进行了强烈的量化,极少数情况下可能出现略微的性能下降或兼容性问题。QLoRA非常适合GPU内存非常有限但又想微调超大模型的情况。例如只有一块16GB卡却希望微调13B或33B参数模型时,QLoRA是不错的选择。
Tuning(Prompt Tuning,软提示微调):P-Tuning是一种Prompt学习方法,通过为模型的输入添加一些可训练的虚拟token来引导模型输出。与直接调整模型权重不同,P-Tuning让模型保持原有权重不变,只是在输入序列开头插入若干新参数(这些参数在微调时会被更新)。可以理解为我们为每个任务学到了一个“魔法开头咒语”,让预训练模型更好地完成特定任务。P-Tuning的参数规模非常小(只相当于几百个词的嵌入向量),因此训练开销极低。它的优点是实现简单、所需内存极小,非常适合极少样本(Few-Shot)或需要针对很多不同提示调优的场景。缺点是适用范围受限:由于只调整输入提示,模型本身的表示能力没有改变,因而对于复杂任务或需要模型深度调整的场景,效果不如LoRA或全量微调。此外,P-Tuning主要针对生成类任务(prefix-tuning用于NLG,P-Tuning最初用于NLU任务)。总的来说,P-Tuning适合小数据快速尝试,或者配合其他微调一起使用,以进一步提升性能。
全参数微调(Full Fine-Tuning):这是一种最朴素也最暴力的方式——解冻预训练模型的所有参数,在下游数据上继续训练,使模型完整学习新任务。它的优点是在足够数据下能够获得最充分的适应效果,模型可以自由调整每一层参数来拟合新任务;但缺点也显而易见:资源消耗巨大(需要显存随模型大小线性增加,14B以上模型往往单卡无法全参数微调),过拟合风险更高(尤其当下游数据较少时,大量参数容易记忆训练集导致泛化变差)。另外,全量微调后的模型参数完全改变,如果要服务多个任务需要保存多份完整模型,部署成本高。一般来说,全参数微调适用于小模型或下游数据非常丰富且有充足计算资源的情况。在大模型上,由于效率太低,我们更推荐LoRA/QLoRA这类参数高效微调手段。
综上,针对单卡GPU的环境且希望高效微调的情景,LoRA和QLoRA是最值得推荐的技术。其中LoRA实现简单、工具成熟,非常适合入门实践;而QLoRA在稍作配置后可以让你的单卡发挥更大威力。如果你的任务数据非常特殊且十分有限,P-Tuning也可以一试。在下一节中,我们将以LoRA为例,手把手演示如何对Qwen2.5模型进行文本生成任务的微调。
6、 实战示例:使用 LoRA 微调 Qwen2.5 模型
下面我们通过一个具体范例,展示如何在单卡服务器上利用Hugging Face Transformers和PEFT库,对Qwen2.5-7B-Instruct模型进行LoRA微调。我们将详细介绍从数据准备到模型训练、再到保存使用的完整流程,力求初学者也能跟着操作。
数据准备
任何微调任务都离不开高质量的训练数据。在本示例中,我们假设读者已经有了一些指令-响应格式的文本数据,需要让模型学习根据指令生成相应的回答。这类数据通常以JSON或CSV存储,每条数据包含:
instruction
:要给模型的指令或问题,input
:可选的附加输入(有些指令可能有额外上下文,这里可以为空字符串),output
:期望模型生成的答案或回应。
例如,一条训练样本可能是:
{
"instruction": "请写一首关于春天的五言绝句。",
"input": "",
"output": "春风拂面草木新,\n燕剪晴空几缕云。\n桃李芬芳香满径,\n儿童嬉戏踏青邻。"
}
在实际操作中,我们需要将这些文本数据转换为模型可训练的token序列。通常的做法是拼接指令和输入作为模型的提示,以特殊标记或换行分隔,然后将输出作为模型需要预测的目标。对于Qwen2.5-7B-Instruct模型,由于它已经过指令微调,我们遵循其对话格式:可以在指令前后加上一些提示符,例如<|user|>
和<|assistant|>
标记。但为简单起见,这里我们直接将instruction和input拼接成模型输入文本,紧接着期望模型生成的就是output
部分。
具体的数据预处理步骤包括:
Tokenization(分词):使用模型自带的Tokenizer将文本转换为token ID序列。对于中文和混合文本,Qwen的分词器采用BPE,对中文采用字拆分。[blog.csdn.net](https://blog.csdn.net/qq_62231627/article/details/140756188#:~:text=Dropout 比例:用于正则化,防止过拟合。 3,JSON 格式存储,包含指令、输入和预期输出。数据预处理步骤包括对文本进行标记化(tokenization)、生成输入 ID 和注意力掩码,并构建适用于模型的输入格式。)
构造输入和标签:对于每个样本,将指令和输入拼成模型看到的文本,例如:prompt_text = instruction + ("\n" + input if input else "")
,然后 tokenizer 对prompt_text编码得到input_ids
;把输出文本通过tokenizer编码得到labels
。在做Causal LM微调时,我们通常将prompt和output拼接后统一作为模型的输入,但通过设置labels
来区分哪些位置的token需要计算损失。简单起见,也可以直接让input_ids = tokenizer.encode(prompt_text + output_text)
,然后在构造数据集时让前半部分的token的label设为-100
(忽略损失),后半部分(对应output)的token作为正确标签。
划分训练集和验证集:如果数据量较大,按一定比例(如90/10)划分出一部分验证集,方便监控微调效果。
创建数据加载器:使用Hugging Face的Datasets库,或PyTorch的Dataset
/DataLoader
对象,将处理后的token序列打包成批(batch)。注意控制批大小和序列长度,以免超过显存。可以使用datasets.Dataset.map
方法应用上述tokenization逻辑,将原始JSON转换为模型可读的input_ids
和labels
格式。
初次调试时,可先用少量数据跑一个epoch,看模型能否正常收敛并生成合理输出,再逐步增加数据量。数据中的指令和回答最好多样且高质量,这样微调后的模型才能学到通用的生成能力。如果数据格式不统一(比如有的没有input字段),要在预处理时做好判断处理。
加载预训练模型和配置 LoRA
数据准备就绪后,我们开始设置模型和LoRA微调配置。主要步骤包括加载预训练模型、冻结大部分参数、配置LoRA低秩层等。
首先,加载Qwen2.5-7B-Instruct的Tokenizer和模型:
from transformers import AutoTokenizer, AutoModelForCausalLM
model_name = "Qwen/Qwen2.5-7B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 使用8-bit量化加载基础模型以节省显存
model = AutoModelForCausalLM.from_pretrained(
model_name,
load_in_8bit=True, # 将权重以8比特精度加载
device_map="auto" # 自动将模型分配到GPU
)
这里我们使用load_in_8bit=True
将模型以8-bit精度加载到GPU,搭配的是bitsandbytes
库的INT8量化方案[huggingface.co](https://huggingface.co/blog/4bit-transformers-bitsandbytes#:~:text=LLMs are known to be,the QLoRA paper by Dettmers)。这样做可以将模型显存占用压缩至原来的约1/4,非常适合单卡场景下加载7B或更大模型。如果你的GPU显存充裕(大于20GB),也可以选择直接load_in_8bit=False
并使用FP16/BF16精度加载。device_map="auto"
则确保在多GPU时自动拆分模型,在单GPU时整个模型放入该GPU。
接下来,使用PEFT库准备LoRA配置:
from peft import LoraConfig, get_peft_model, TaskType, prepare_model_for_int8_training
# 如果使用8bit加载,需要调用此函数准备模型的LayerNorm等层,以允许微调
model = prepare_model_for_int8_training(model)
# 定义 LoRA 配置
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # 因果语言建模任务
inference_mode=False, # 训练模式
r=8, # LoRA权重矩阵的秩
lora_alpha=32, # LoRA 的缩放因子
lora_dropout=0.1, # 在LoRA层施加的dropout比例
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"] # 应用LoRA的子模块
)
# 将模型转换为PEFT的LoRA模式
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
让我们解释一下上述配置中的关键部分:
- prepare_model_for_int8_training:这是PEFT提供的辅助函数,用于在8-bit量化加载模型后,解冻一些在训练中必须更新的层,比如LayerNorm的参数,以及为LoRA准备优化器兼容性。如果未使用8bit加载,可以跳过这一步。
- task_type=TaskType.CAUSAL_LM:指定任务类型为因果语言模型(Causal LM),表示我们要在自回归的文本生成任务上应用LoRA。
- r=8(秩):LoRA中新增加的低秩矩阵的秩,简单说就是每个原权重矩阵将被分解为两个小矩阵(A和B),它们的乘积近似于需要的权重增量。秩r决定了可训练参数的规模,r越大,LoRA层越灵活,但需要训练的参数也越多。典型取值有4、8、16等。
- lora_alpha=32(缩放因子):LoRA在训练时通常会把低秩矩阵的输出乘以一个因子alpha,再加到原权重上。可以理解为对LoRA层的学习进行缩放,增大alpha相当于提高LoRA层在总权重更新中的占比。
- lora_dropout=0.1:对LoRA插入的层施加dropout,避免过拟合。在训练中,每次更新会随机drop掉10%的LoRA参数的影响,使模型不会过度依赖这些新参数,从而提升泛化能力。对于数据量较大的任务也可以设为0不用dropout。
- target_modules:这是LoRA最重要的部分 —— 指定模型中哪些权重矩阵应用LoRA微调。在Transformer中,通常我们会选择注意力机制和前馈网络中的关键线性层。例如这里列出的
q_proj, k_proj, v_proj, o_proj
对应自注意力的查询、键、值投影和输出投影矩阵,gate_proj, up_proj, down_proj
对应前馈网络中的门控层和上下变换层(Qwen使用SwiGLU激活,有Gate和Up两个并行层,Down是输出层)。通过选择这些模块,我们 essentially 在Transformer每一层的自注意力和前馈子层都插入了可训练的LoRA低秩矩阵。如此配置虽然比只调节q_proj/v_proj
等稍多训练参数,但也带来更强的调节能力。当显存紧张时,你也可以精简target_modules列表,例如仅针对["q_proj","v_proj"]
应用LoRA,这将进一步减少可训练参数数目。
将模型转换为LoRA模式后,get_peft_model
已经把模型中对应的模块替换成了带LoRA结构的模块,并且冻结了原有权重,只有LoRA新增的权重设为可训练。model.print_trainable_parameters()
会输出可训练参数量,以确认微调规模。例如,在上述配置下应看到输出类似:
trainable params: 59,648 || all params: 7,604,224,000 || 0.00% trainable
(可训练参数占比非常小,印证了LoRA的高效。)
配置训练参数并启动微调
现在我们进入训练阶段。Hugging Face 提供了Trainer
API来简化单机(甚至多机)训练过程。我们需要定义训练超参数、构造Dataset并喂给Trainer,然后调用train()
方法。
from transformers import TrainingArguments, Trainer
# 构造训练和验证Dataset,这里假设已经有train_dataset和eval_dataset
# train_dataset = ...
# eval_dataset = ...
training_args = TrainingArguments(
output_dir="./qwen25-lora-checkpoints", # 保存模型检查点的目录
per_device_train_batch_size=4, # 每块GPU上的批次大小
gradient_accumulation_steps=8, # 累积梯度步数
num_train_epochs=3, # 训练轮数
learning_rate=2e-5, # 微调学习率,一般比预训练时小
fp16=True, # 使用半精度训练(若GPU支持)
logging_steps=50, # 日志记录间隔
save_steps=200, # 模型保存间隔
evaluation_strategy="steps", # 评估触发方式(steps或epoch)
eval_steps=200, # 评估间隔
save_total_limit=2, # 最多保留的检查点数
gradient_checkpointing=True, # 开启梯度检查点,节省显存
report_to="none" # 不启用默认的日志报告(如TensorBoard)
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
)
trainer.train()
在这个配置中,我们重点关注几个与单卡显存和训练稳定性相关的设置:
batch大小和梯度累积 (per_device_train_batch_size
& gradient_accumulation_steps
)**:因为显存有限,我们将每个batch的大小设为4,这意味着每次只输入4条样本。然而为了提高训练效率,相当于批大小为32,我们使用gradient_accumulation_steps=8
累计梯度——模型每走8个小批次再做一次参数更新,相当于总有效批大小4×8=32。这种方式可以在**不额外占用显存的情况下模拟大batch训练,有助于稳定收敛。
学习率 (learning_rate
):微调大语言模型通常使用较小的学习率(e.g. 1e-4到1e-5)以避免破坏原模型已经学到的知识。这里我们选用2e-5作为初始值,可根据验证集效果微调。若发现训练不稳定(loss波动剧烈),可以尝试调低学习率。
混合精度 (fp16
):打开FP16半精度训练,可以让GPU在训练中使用16位浮点数计算,节省显存和提升速度。Transformer库会自动处理好loss scaling避免数值下溢。需要确保GPU支持FP16(多数NVIDIA GPU都支持)。如果使用的是A100等支持BF16的GPU,也可以设置bf16=True
达到类似效果。
梯度检查点 (gradient_checkpointing
)**:这是一项**节省内存的设置。当gradient_checkpointing=True
时,模型在前向传播时不会保存中间激活值,而是在反向传播时重新计算需要的激活。这会使每次迭代的计算量略有增加(因为有些计算做了两遍),但能够大幅降低显存占用,尤其在长序列、大模型时有效。这对于单卡16GB显存跑7B模型很有帮助,可以防止OOM。在我们的配置里,考虑到Qwen2.5支持很长序列,我们开启了该选项。
日志和保存 (logging_steps
, save_steps
, evaluation_strategy
):我们每50步打印一次日志,每200步保存一次模型并评估验证集。这些值可以根据数据集大小调整。save_total_limit=2
保证只保留最近2个检查点,节省空间。
配置好Trainer后,调用trainer.train()
即可开始微调过程。训练过程中,您会看到每隔logging_steps
输出当前的loss等信息。如果验证集提供了评价指标,Trainer也会在评估时打印。例如输出可能如下:
step 50 - loss: 2.31 - lr: 2.00e-05
step 100 - loss: 1.85 - lr: 1.99e-05 - eval_loss: 1.80
...
损失逐步降低,说明模型在学习。微调几个epoch(这里设3个)后,训练会结束。
如果在训练过程中发现loss下降停滞甚至上升,可能需要调整超参数。例如减小学习率,或者增加gradient_accumulation_steps
以扩大有效批大小。另外要注意监控验证集的loss和指标,防止过拟合。如果验证loss开始上升,说明模型可能过拟合训练集,此时可提前停止训练或引入**早停 (early stopping)**机制。
保存和使用微调后的模型
训练完成后,我们需要保存微调得到的模型参数,以便后续加载和使用。由于我们采用了LoRA微调,最终的微调模型由“预训练模型权重”+“LoRA增量权重”组成。PEFT库提供了便捷的方法来保存和加载LoRA权重:
# 保存LoRA微调适配器
model.save_pretrained("./qwen25-lora-adapter")
上述命令会将LoRA的适配器权重和配置保存在指定文件夹下(例如会生成一个adapter_model.bin
或adapter_model.safetensors
,以及adapter_config.json
)。这些文件存储的仅仅是LoRA插入的权重(通常只有几十MB),而不会重复保存原始7B模型的参数。适配器配置里也记录了预训练模型的名称或路径,方便在加载时自动合并。
要使用微调后的模型,有两种方式:
- 使用PEFT加载:推荐的方法是通过
AutoPeftModelForCausalLM
来加载适配器,它会自动读取原模型权重并应用LoRA适配器:
from peft import AutoPeftModelForCausalLM
finetuned_model = AutoPeftModelForCausalLM.from_pretrained(
"./qwen25-lora-adapter",
device_map="auto"
)
# 测试生成
prompt = "春天有什么诗意?"
output = finetuned_model.generate(**tokenizer(prompt, return_tensors='pt').to(0),
max_new_tokens=50)
print(tokenizer.decode(output[0]))
这里from_pretrained
会读取adapter_config.json
中记录的base模型(Qwen2.5-7B-Instruct)的信息,如有必要会自动下载原模型,然后加载LoRA权重。得到的finetuned_model
已经包含了微调后的能力,可以直接用于生成文本。上面的例子中,我们输入一个提示,让模型写一些关于春天的诗意文字,generate
会基于我们设定的max_new_tokens生成一定长度的续写,并输出结果。
合并权重后加载(可选):如果需要将微调效果合并到模型本身(例如部署一个独立的微调模型,不依赖PEFT库),也可以将LoRA权重与原模型合并。PEFT提供了model.merge_and_unload()
方法将LoRA适配器融合进模型并卸载适配器。但注意合并后模型大小会变得和原模型一样大(数GB级别)。合并步骤如下:
finetuned_full_model = model.merge_and_unload()
finetuned_full_model.save_pretrained("./qwen25-7b-finetuned-full")
这样会保存一个完整的微调模型,可以像普通Transformers模型那样直接通过AutoModelForCausalLM.from_pretrained("./qwen25-7b-finetuned-full")
加载使用。除非有部署需求,否则一般没必要合并,以免增加存储和加载开销。
无论采用哪种方式,拿到微调模型后,就可以在下游任务中发挥作用了。您可以使用generate
方法让模型生成文本,或通过pipeline
简化调用。比如:
from transformers import pipeline
pipe = pipeline("text-generation", model=finetuned_model, tokenizer=tokenizer)
result = pipe("你好,请自我介绍一下:", max_new_tokens=100)
print(result[0]['generated_text'])
这将使用微调模型根据指令生成相应的回答。
至此,我们已经完成了从准备数据、配置环境,到选择LoRA策略、进行模型微调,再到保存和推理的整个流程。接下来,我们讨论在实践中常遇到的一些问题和解决技巧。
7、 常见问题与排查技巧
微调过程往往不会一帆风顺,以下是几个初学者经常碰到的问题及对应的解决建议:
显存不足(OOM): 如果在加载模型或训练过程中遇到CUDA out of memory
错误,首先不要慌。这相当于GPU在喊“吃不下了”。应对方法包括:
- 减小批大小: 最直接的方法是减小
per_device_train_batch_size
,或者缩短序列长度。如果依然需要较大有效批量,可以相应增加gradient_accumulation_steps
来弥补。 - 启用混合精度/量化: 确保使用了
fp16
或bf16
训练。如果还是不够,可以考虑8-bit甚至4-bit量化加载模型(即前述QLoRA技术)。例如7B模型使用QLoRA 4-bit时显存占用可降至约11GB,使单卡12GB也有机会跑通。 - 梯度检查点: 打开
gradient_checkpointing
(如果还没开),它能有效降低激活占用,不过会稍增加计算量。 - 换用更小模型: 如果以上措施都不足以缓解OOM,可能说明GPU确实吃力。可以尝试微调Qwen2.5的3B或1.5B小模型,待调通后再尝试更大的。
- 释放缓存: 在不同阶段调用
torch.cuda.empty_cache()
,避免缓存占用过多(Trainer会自动管理,一般无需手动)。
总之,循序渐进尝试,一边调整一边监控nvidia-smi
的显存占用。每次调参后重新运行,直到模型成功开始训练。
梯度爆炸(Gradients Explosion): 如果训练过程中loss突然变为NaN或Inf,或观察到梯度值异常大,可能是出现了梯度爆炸。解决方法:
- Gradient Clipping(梯度裁剪): 在
TrainingArguments
中设置如max_grad_norm=1.0
,让Trainer在每次更新时将梯度范数裁剪到合理范围。这能有效阻止梯度爆炸蔓延。 - 降低学习率: 适当减小
learning_rate
,或采用预热+余弦退火等学习率调度策略,让模型更加平稳地学习。 - 检查数据: 确认输入文本没有异常(如非常长的无意义序列或大量乱码),输出标签没有错位。如果个别样本导致不稳定,可以考虑过滤掉。
- 缩短序列长度: 极长的序列可能导致不稳定,尝试减小
max_length
或对过长样本截断。
收敛缓慢或效果不好: 如果模型训练loss下降缓慢或者在验证集上效果不佳,可以考虑:
- 增加训练轮数,但同时监控验证集表现,防止过拟合。
- 使用更多样化的数据增强模型泛化能力,或结合少量验证集早停找最佳epoch。
- 对于生成任务,验证效果有时不易量化,可手动检查模型输出质量,必要时精调超参数。
PEFT加载问题: 使用AutoPeftModelForCausalLM
加载LoRA适配器时,若遇到找不到预训练模型的错误,可能是适配器配置中没有记录base模型路径。这时可以手动指定:
finetuned_model = AutoPeftModelForCausalLM.from_pretrained(
base_model_name_or_path="Qwen/Qwen2.5-7B-Instruct",
adapter_name_or_path="./qwen25-lora-adapter"
)
以确保先加载base模型再应用适配器。另外,要保证PEFT和Transformers版本匹配最新,否则可能出现ValueError: Tokenizer class QWenTokenizer does not exist
等错误——这种情况下可通过升级相关库或暂时降级PEFT (<0.8.0) 解决。
在微调Qwen时,如果使用的是未经过指令微调的基础模型(如Qwen2.5-7B而非Instruct版),可能需要将embedding层和LM头解冻训练
- 以学习特殊的对话格式token,否则模型可能无法正确产出格式化回复。但使用Instruct模型通常不需要额外处理特殊token。
最后,微调是一个反复试错的过程。面对问题,保持耐心,多利用日志和中间结果来判断原因。经过一次完整的实践,您将对大模型微调的细节有更深理解。
8、如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。