Llama架构模型QLoRA微调后Adapter过大及显存问题求助
问题背景
我基于支持英语、印地语及罗马化印地语的Llama架构模型做微调,通过bitsandbytes以nf4格式结合双重量化加载量化模型:
bnb_config = BitsAndBytesConfig( load_in_4bit = True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16, ) model = AutoModelForCausalLM.from_pretrained( base_model, quantization_config = bnb_config, device_map = {"":0}, trust_remote_code = True, )
为适配聊天格式微调,我给tokenizer添加<pad> token,调整模型词嵌入并更新配置:
# 明明tokenizer里已经有[PAD],还是新增了<pad>作为padding token,求问这么做的原因 if '<pad>' not in tokenizer.get_vocab(): print("Token Added") # 添加pad token tokenizer.add_tokens(['<pad>']) # 设置pad token tokenizer.pad_token = '<pad>' voca = tokenizer.get_vocab() # 调整词嵌入大小 model.resize_token_embeddings(len(tokenizer)) # 更新模型及配置中的pad token id model.pad_token_id = tokenizer.pad_token_id model.config.pad_token_id = tokenizer.pad_token_id assert model.pad_token_id == tokenizer.pad_token_id, "模型与tokenizer的pad token ID不匹配" model = get_peft_model(model, config) print_trainable_parameters(model)
随后设置LoRA适配器参数:
r = 16, lora_rank = 32, target_modules = ["q_proj", "v_proj", "down_proj", "gate_proj", "up_proj", "k_proj"], lora_dropout = 0.05, task_type = "CAUSAL_LM", model = get_peft_model(model, config) trainable params: 35782656 || all params: 3667800064 || trainable%: 0.9755890554453079
模型词汇量为48065,使用约80条印地语、罗马化印地语及英语样本训练,训练参数如下:
args = transformers.TrainingArguments( num_train_epochs=1, per_device_train_batch_size=2, gradient_accumulation_steps=2, max_grad_norm=1, warmup_ratio=0.1, learning_rate=1e-4, fp16 = True, logging_steps = 1, output_dir = "outputs", optim = "paged_adamw_8bit", lr_scheduler_type = 'cosine', ), data_collator=data_collator, ) model.config.use_cache = False
训练后将Adapter推至Hugging Face(确认仅推送Adapter而非合并模型),但该Adapter达1.72GB,与常规情况不符。尝试合并Adapter与基础模型时,Turing T4 GPU出现CUDA显存不足;加载Adapter进行推理时,16GB显存直接被占满,无法完成推理。
核心问题
- 该Adapter体积过大是否正常?
- 如何解决体积问题并完成模型合并?
- 加载Adapter时显存溢出的原因及解决方法?
解答
1. Adapter体积1.72GB是否正常?
完全不正常。常规Llama系模型的LoRA Adapter体积通常在几十MB级别(比如7B模型用r=16时,Adapter体积约30-50MB)。你的Adapter体积异常大,大概率是以下原因:
- 保存方式错误:调用
save_pretrained时用了基础模型而非PEFT模型的方法,导致把整个量化后的模型权重都存了进去,而非仅LoRA层参数。 - 参数配置冲突:代码里同时写了
r=16和lora_rank=32(二者是PEFT库中的别名参数),虽然最终训练参数显示约34MB,但如果保存时未正确过滤非LoRA参数,也会导致文件异常增大。
2. 解决体积问题并完成模型合并
- 修复Adapter保存问题:确保使用PEFT模型的
save_pretrained方法保存,仅导出LoRA相关参数:
若已保存错误文件,可手动提取model.save_pretrained("lora_adapter")adapter_model.bin中以lora_开头的权重,重新保存为正确的Adapter文件。 - 模型合并的显存优化方案:
- 沿用4bit量化加载基础模型,再加载Adapter后调用
merge_and_unload,大幅降低合并时的显存占用:# 加载量化基础模型 model = AutoModelForCausalLM.from_pretrained( base_model, quantization_config=bnb_config, device_map={"":0}, trust_remote_code=True ) # 加载Adapter model = PeftModel.from_pretrained(model, "lora_adapter") # 合并模型 merged_model = model.merge_and_unload() - 若T4显存仍不足,可设置
device_map="auto"让模型自动分配到CPU和GPU分批处理,或直接在CPU上完成合并(速度较慢但显存充足)。
- 沿用4bit量化加载基础模型,再加载Adapter后调用
3. 加载Adapter时显存溢出的原因及解决方法
- 核心原因:
- 加载基础模型时未沿用训练时的4bit量化配置,而是加载了全精度模型,叠加Adapter后显存直接超出上限。
- 推理时未开启精度优化,或未限制生成长度等显存消耗项。
- 解决方法:
- 严格沿用训练时的4bit量化配置加载基础模型,再加载Adapter:
model = AutoModelForCausalLM.from_pretrained( base_model, quantization_config=bnb_config, device_map={"":0}, trust_remote_code=True ) model = PeftModel.from_pretrained(model, "lora_adapter") - 推理时开启半精度模式:
model = model.half() # 或.bfloat16() - 生成文本时限制
max_new_tokens长度,关闭不必要的采样(如do_sample=False),或开启gradient_checkpointing进一步降低显存占用。 - 若显存仍不足,设置
device_map="auto"让部分模型层运行在CPU上,牺牲速度换取显存空间。
- 严格沿用训练时的4bit量化配置加载基础模型,再加载Adapter:
另外,关于你新增<pad> token的疑问:Llama原生tokenizer的[PAD]未被正确配置为padding token,原生默认用eos_token填充,聊天格式微调时需要明确的pad token来对齐样本长度,避免训练异常。但无需新增<pad>,直接将原生[PAD]设置为tokenizer.pad_token即可,新增会额外增加一个词嵌入参数(影响极小)。
内容的提问来源于stack exchange,提问作者Killua
相关产品推荐
相关产品推荐

