大模型微调踩坑记录 - 基于Alpaca-LLaMa+Lora

前言

为了使用开放权重的LLM(大语言模型),基于自己的训练集,微调模型,会涉及到如下一些技术要点:

  • 配置运行环境
  • 下载、加载基础模型
  • 收集语料、微调训练
  • 检验训练效果

在实施过程中,遇到不少困难,因此写下这篇文档,做为记录。

环境配置

1. 模型加载 - icetk报错

(1) 问题描述

在huggingface的模型库中,大模型会被分散为多个bin文件,在加载这些原始模型时,有些模型(如Chat-GLM)需要安装icetk

这里遇到了第一个问题,使用pip安装icetktorch两个包后,使用from_pretrained加载模型时会报缺少icetk的情况。
但实际情况是这个包已经安装了。

查资料的过程中,有人说出现该错误的原因是icetk依赖cpu版torch2.0,需要先装icetk再装GPU版torch。
但我尝试该方案后并不成功,之后在github上看到一条相同的issue,下方的回答中提到的方法,成功解决了我的问题。

(2) 解决方案
  • 启动python环境,执行import icetk会报错,并指向lzma.py中的引用错误
  • 根据错误提示,定位到lzma.py文件及相关代码的位置
  • 按如下方式修改源代码

修改前

from _lzma import *
from _lzma import _encode_filter_properties, _decode_filter_properties

修改后

try:
	from _lzma import *
	from _lzma import _encode_filter_properties, _decode_filter_properties
except ImportError:
	from backports.lzma import *
	from backports.lzma import _encode_filter_properties, _decode_filter_properties

2. 安装指定版本 - transformers安装

(1) 问题描述

截止到目前(2023-04-06),Meta官方仍未对LLaMa模型开源,网上流传的为泄露版。因此,正式版transformers没有该模型的Model或Tokenizer库。

在查找资料的过程中,有人说使用pip install git+某版本transformer安装dev版transformers。
但由于当我使用该指令安装时,这里指定的分支已经被删除了,所以无法安装成功。

(2) 解决方案

因为无法通过pip install的方式安装,所以这里考虑用编译源码的方式安装。

git clone https://github.com/huggingface/transformers.git
pip install -e .

因为模型目前还未开源,所以使用这种方式解决。未来Meta正式开源该模型后,transformers肯定会提供支持。
届时,直接使用pip install transformers即可。

微调训练

1. 并行计算 - bitsandbytes报错

(1) 问题描述

安装bitsandbytes,可以在加载模型时,设置load_in_8bit=True, device_map='auto'降低显存,并将模型分布到GPU上计算。

但在引用时会出现警告: UserWarning: The installed version of bitsandbytes was compiled without GPU support.
并在模型加载时会报有关"libsbitsandbytes_cpu.so"的编译错误。

(2) 解决方案
  1. 正确安装cuda、cuda-tookit
  2. 在.bashrc中配置LD_LIBRARY_PATH

详细情况可参考这篇博客:bitsandbytes报错解决方案

可能是因为Nvidia针对浮点型计算进行过优化,使用load_in_8bit=True让参数以整型进行计算,反而会降低计算速度。
因此,在显存足够时,建议不使用该设置。

2. 模型微调 - 使用PEFT

Lora技术提出之后,huggingface提供了PEFT框架支持,可通过pip install peft安装。

使用时分为如下步骤:

  1. 参数设置 - 配置Lora参数,通过get_peft_model方法加载模型。
  2. 模型训练 - 此时只会微调模型的部分参数、而其他参数不变。
  3. 模型保存 - 使用model.save_pretrained("output_dir")方法保存模型。
  4. 模型加载 - 读取保存peft模型及相关配置,使用PeftModel.from_pretrained(model, peft_model_id)方法加载模型。

(1) 模型训练、保存

from transformers import AutoModel
from peft import get_peft_model, LoraConfig

# Lora参数设置
peft_config = LoraConfig(
	r=lora_r,
	lora_alpha=lora_alpha,
	target_modules=lora_target_modules,
	lora_dropout=lora_dropout,
	bias="none",
	task_type="CAUSAL_LM",
)

# 模型加载
model = AutoModel.from_pretrained("model_name_or_path")
model = get_peft_model(model, peft_config)
# output: trainable params: 4194304 || all params: 6742609920 || trainable%: 0.06220594176090199
model.print_trainable_parameters()

# 模型训练
...

# 模型保存
model.save_pretrained("output_dir") 

(2) 模型加载、计算

以下是官方给出的样例,但是按该方式加载模型,在计算时会出现AttributeError: 'NoneType' object has no attribute 'device'报错。

from transformers import AutoModel, AutoTokenizer
from peft import PeftModel, PeftConfig

# 加载peft配置
peft_model_id = "output_dir"
peft_config = PeftConfig.from_pretrained(peft_model_id)

# 加载tokenizer
tokenizer = AutoTokenizer.from_pretrained(peft_config.base_model_name_or_path)

# 结合基础模型和微调结果,加载模型
model = AutoModel.from_pretrained(peft_config.base_model_name_or_path)
model = PeftModel.from_pretrained(model, peft_model_id)
model = model.to(device)
model.eval()

# 模型计算
...

在查找资料后,发现这是PEFT在遇到GPU加载模型时会产生的bug。
根据使用环境是单GPU或多GPU,分别按以下两种方式使用,即可解决上述问题。

解决方案 - 单GPU
# 加载基础模型
base_model = AutoModel.from_pretrained(
    model_path,
    load_in_8bit=True,
    torch_dtype=torch.float16,
    # device_map="{'': 0}"
    device_map="auto"
)

peft_model = PeftModel.from_pretrained(
    base_model,
    peft_model_id,
    torch_dtype=torch.float16,
    # device_map="{'': 0}"
    device_map="auto"
)
解决方案 - 多GPU
# 加载基础模型
base_model = AutoModel.from_pretrained(
    model_path,
    load_in_8bit=True,
    torch_dtype=torch.float16,
    device_map="auto"
)

# 获取模型参数分配表
device_map = {f"base_model.model.{k}": v for k, v in model.hf_device_map.items()}

# 按相同的参数分配加载peft model
peft_model = PeftModel.from_pretrained(
    base_model,
    peft_model_id,
    device_map=device_map,
    torch_dtype=torch.float16
)

在查找资料的过程中,我先看到的是单GPU的解决方案,但是该方案对多GPU不适用。
应该是因为自动分配参数时,无法保证peft_model和base_model的分配方法一致。
因此,在多GPU环境下,需通过device_map绑定二者参数的分配方式。

吐槽

在查资料的过程中,建议大家多用谷歌、少用百度
上述这几个问题,都在github对应仓库的issue里有人提出过,我也都是从下方的答复中找到的解决方案。
但是在用百度和谷歌搜报时,百度却从没给出github上的回答。

百度谷歌
在这里插入图片描述在这里插入图片描述

参考文档

icetk报错 - https://github.com/THUDM/ChatGLM-6B/issues/323
bitsandbytes报错 - https://github.com/oobabooga/text-generation-webui/issues/147#issuecomment-1456040134
peft使用说明 - https://huggingface.co/blog/peft
peft加载模型 - https://github.com/tloen/alpaca-lora/issues/77

<think>嗯,用户想了解如何对Llama-3-8B大模型进行微调。首先,我需要回忆一下微调大型语言模型的一般步骤,并结合Llama-3-8B的具体情况来回答。 首先,微调大模型通常需要准备数据集。用户可能需要收集与目标任务相关的数据,比如对话、问答或者特定领域的文本。数据格式可能需要符合模型输入的格式,比如指令微调的话,数据应该包含指令、输入和期望的输出。比如引用[3]提到的Bunny-Llama-3-8B-V模型,就是基于Llama-3进行多模态微调的,说明数据可能包含图像和文本的结合,但用户的问题是关于微调,可能需要考虑不同的任务类型。 然后是环境配置,需要选择合适的框架,比如Hugging Face的Transformers库,或者使用DeepSpeed、FSDP进行分布式训练。考虑到Llama-3-8B的规模,单卡可能无法训练,需要多卡或者使用参数高效的方法,比如LoRA。引用[3]提到Bunny模型是基于Llama-3-8B的,可能使用了LoRA这类技术来减少显存占用。 接下来是模型加载,可能需要从Hugging Face下载预训练模型,并进行适当的配置,比如加载半精度或者使用QLoRA来量化模型。引用[2]提到Llama-3使用了15万亿tokens训练,所以预训练模型已经很强,微调时不需要太多数据,但要确保数据质量。 然后是训练配置,包括学习率、优化器、批次大小等。由于8B模型参数较多,可能需要较小的学习率,避免过拟合。另外,使用混合精度训练可以节省显存,加快训练速度。引用[3]中的模型在多个benchmark表现好,可能是在训练时进行了多任务学习或者数据增强。 训练过程中需要监控损失和评估指标,使用验证集来调整超参数。可能还需要早停策略,防止过拟合。训练完成后,要保存模型,并可能进行量化或合并适配器,比如LoRA的权重合并到原模型。 最后是部署,将微调后的模型集成到应用中,比如使用FastAPI提供API服务。引用[3]中的Bunny模型作为多模态应用,可能需要特定的部署方式,但用户的问题可能更关注文本生成方面。 在注意事项中,需要强调显存优化,比如梯度检查点、LoRA,以及数据质量的重要性。此外,任务适配可能需要调整模型结构,比如分类任务添加分类头。引用[1]提到未来计划增强模型的中文能力,可能用户的数据如果是中文,需要确保数据足够和相关。 可能用户的实际需求是在特定领域应用Llama-3-8B,比如客服对话或文本生成,所以需要根据具体任务调整微调策略。另外,用户可能关心微调需要多少计算资源,是否需要云服务,或者有没有更高效的方法,比如提示工程代替微调。但根据问题,用户明确想了解微调步骤,所以需要详细说明流程和相关技术。</think>### Llama-3-8B 大模型微调方法分步说明 #### 1. **环境准备与数据收集** - **硬件要求**:建议使用至少1张24GB显存的GPU(如RTX 3090/4090),大规模微调需多卡并行或云服务器(如A100) - **框架选择**:推荐使用Hugging Face Transformers + PEFT库,结合LoRA(Low-Rank Adaptation)进行参数高效微调[^3] - **数据格式**:准备指令-响应对数据(JSON格式),例如: ```json {"instruction": "解释量子力学", "input": "", "output": "量子力学是研究微观粒子..."} ``` #### 2. **模型加载与配置** ```python from transformers import AutoModelForCausalLM, AutoTokenizer model = AutoModelForCausalLM.from_pretrained( "meta-llama/Meta-Llama-3-8B", load_in_4bit=True, # 使用QLoRA量化 device_map="auto" ) tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B") ``` #### 3. **适配器配置(LoRA)** ```python from peft import LoraConfig, get_peft_model lora_config = LoraConfig( r=8, # 秩 lora_alpha=32, target_modules=["q_proj", "v_proj"], # 目标注意力层 lora_dropout=0.05, bias="none" ) model = get_peft_model(model, lora_config) model.print_trainable_parameters() # 可训练参数约0.1% ``` #### 4. **训练循环配置** ```python from transformers import TrainingArguments training_args = TrainingArguments( output_dir="./results", per_device_train_batch_size=2, gradient_accumulation_steps=4, # 有效批次大小=8 learning_rate=1e-4, warmup_steps=100, num_train_epochs=3, fp16=True, logging_steps=10, optim="adamw_torch" ) ``` #### 5. **启动训练** ```python from transformers import Trainer trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, data_collator=lambda data: { "input_ids": torch.stack([f["input_ids"] for f in data]), "attention_mask": torch.stack([f["attention_mask"] for f in data]), "labels": torch.stack([f["labels"] for f in data]) } ) trainer.train() ``` #### 6. **模型保存与部署** ```python model.save_pretrained("./llama3-8b-lora-adapter") # 合并适配器(可选) merged_model = model.merge_and_unload() merged_model.save_pretrained("./merged_model") ``` ### 关键技术说明 1. **LoRA技术**:通过低秩矩阵分解,仅微调0.1%-1%的参数即可达到全参数微调效果 2. **梯度检查点**:使用`gradient_checkpointing_enable()`减少40%显存占用 3. **指令模板**:需遵循Llama-3的对话格式: ``` <|begin_of_text|><|start_header_id|>user<|end_header_id|> {instruction}<|eot_id|> <|start_header_id|>assistant<|end_header_id|> {response}<|eot_id|> ``` ### 注意事项 - 中文微调建议添加20%以上中文数据(如Alpaca-zh数据集) - 8B模型全参数微调需要约64GB显存,建议采用参数高效方法 - 使用`trl`库的SFTTrainer可获得更好的指令跟随效果
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anycall201

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值