概要
由于笔者是为了记录自己的踩坑记录,会讲述基本流程,但具体的技术细节,我就不深入探讨,直接实操,咱们干中学吧!!!
我会尽量用通俗易懂的语言进行表达,由于笔者能力有限,有错误之处,请大家多多担待,可以在评论区跟我指出交流。
基本流程
1 从hugging face上下载我们需要微调的模型,这里笔者试了很多方法。
2 署环境了,这里一定需要使用国内镜像(特别快)。
3 下载数据集
4 编写微调代码(官网也有提供的微调代码示例)
5 记录使用Colossal-Ai微调时间和GPU显存的占用率
笔者的环境是:
1 操作系统:Linux Ubuntu 22.04
2 GPU:两块A100 80G
基础知识
Colossal-Ai
Colossal-AI 是一个面向大规模深度学习模型训练的开源框架,能够让我们可以进行单机多卡的分布式训练。我们只需要调用相应的官方提供的API就能够相应的策略(像笔者有两张A100的卡就能得到的充分利用)。
Lora(Low-Rank Adaptation)
LoRA 是一种针对大模型微调(Fine-tuning)的一种高效参数更新方法 ,能够通过低秩矩阵分解,减少微调时的参数量和计算量。
模型下载
本项目使用的模型是deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
官网地址 这里笔者用了很多方法,要么太慢,要么中断,最后还是本地下载文件再scp上传到服务器上去,评论区如果有更好的方法,可以交流一下。
1 使用Git LFS进行git clone国内镜像ModelScope,一直是提示连接超时。
2 使用 huggingface-cli 工具,使用命令行工具进行下载,还是超时。
3 直接使用transformers的from_pretrained函数,等了半天没反应,放弃。
最后只能手动下载文件,上传到服务器上。
环境部署
很棒,模型下载好了,现在我们需要运行模型。环境的创建我就不教了,直接附上指令。
1 创建python环境
bash
conda create -n deepseek python=3.9 -y
conda activate deepseek
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install transformers datasets accelerate peft colossalai -i https://pypi.tuna.tsinghua.edu.cn/simple
注意:
1 安装pytorch的gpu版本时要注意要自己的CUDA驱动版本是否适配
2 Colossal-AI目前只支持transformer-4.39.3版本,所以有些模型是不支持训练的。
数据集下载
下载地址 数据集格式: json文件,具有三个属性段,question
、resoning
、response
。
微调代码
1 首先先编写配置文件,config.py
python
DATASET_PATH = os.path.expanduser(
"/home/idal-01/wxc/deepseek/health_dataset/distill_psychology-10k-r1.json"
)
`TRAIN_CONFIG = {
"model_name": "/home/idal-01/wxc/deepseek/deepseek_1.5B"
}
2 接着再对数据进行处理,编写数据处理文件data_loader.py
python
from datasets import load_dataset
from transformers import AutoTokenizer
from config import DATASET_PATH, TRAIN_CONFIG
def load_data(tokenizer):
# 自定义格式化函数
def format_func(examples):
texts = [
f"Instruction: {q}\nResponse: {a}"
for q, a in zip(examples["input"], examples["content"])
]
return {"text": texts}
# 加载并处理数据集
dataset = load_dataset("json", data_files=DATASET_PATH, split="train")
dataset = dataset.map(format_func, batched=True)
# 分词处理
tokenized = dataset.map(
lambda x: tokenizer(
x["text"],
max_length=TRAIN_CONFIG["training"]
truncation=True,
padding="max_length",
return_tensors="pt"
),
batched=True
)
return tokenized
3 编写微调代码(主要介绍关于colossal-ai的代码部分)
1)初始化分布式后端,也就是先创建分布式环境,分布式环境所需的参数,如 rank, world size, host 和 port 都是由 PyTorch 启动器设置的,可以使用colossalai.launch_from_torch()
这个函数直接从环境变量中读取。
python
colossalai.launch_from_torch()
2)选择需要的插件,官网提供的插件包括Torch DDP 插件、Torch FSDP 插件、Low Level Zero 插件、Gemini 插件以及Hybrid Parallel 插件。我们可以选择适合自己模型训练的插件。插件详细信息查看
p
plugin = GeminiPlugin(...)
booster = Booster(plugin=plugin)
3)用 colossalai.booster 将训练特征注入您的训练组件(如模型、优化器、损失函数和学习率调度器)中,本质上是对于模型进行的再次封装,要注意封装过后,模型很多原来的函数使用方式要变,封装后的模型不具备原本的函数。
python
model, optimizer, _, dataloader, lr_scheduler = booster.boost(
model=model,
optimizer=optimizer,
lr_scheduler=lr_scheduler,
dataloader=dataloader,
)
4)官网提供了支持LoRa的API使用方法,使其支持LoRa,一定不要使用peft里面的LoRa方法,笔者已经踩过坑了(由于已经封装的原因,但最后要么无法保存Lora适配器模型,要么无法进行训练,因为官网没有提供解封装的API)。
p
lora_config = LoraConfig(
task_type="CAUSAL_LM",
r=args.lora_rank,
lora_alpha=args.lora_alpha,
target_modules=["gate_proj", "up_proj", "down_proj"],
)
model = booster.enable_lora(model, lora_config=lora_config)
5) 如果要开启梯度检查点,model一定要提前经过booster封装。
p
model.gradient_checkpointing_enable()
6) 如果要开启快速注意力机制(Flash attention),梯度剪裁(grad_clip),梯度累积(gradient_accumulation),训练精度(mixed_precision),梯度缩放(initial_scale)以及融合归一化(Fused Normalization)
,需要在插件初始化的时侯进行传参。
p
plugin = GeminiPlugin(
precision=args.mixed_precision,
initial_scale=2**16,
max_norm=args.grad_clip,
enable_gradient_accumulation=(args.accumulation_steps > 1),
enable_fused_normalization=get_accelerator().is_available(),
enable_flash_attention=args.use_flash_attn,
)
7)保存模型一定要用官网给的API接口函数,不然将保存不到Lora的适配器。
p
booster.save_lora_as_pretrained(model, os.path.join(args.save_dir, "lora"))
8)我们可以通过命令行传参数过去,我列举几个必须的,其余参数都是类似编写。
p
parser.add_argument(
"-m",
"--pretrained",
type=str,
required=True,
help="Address of the pre-trained model",
)
parser.add_argument("-d", "--dataset", type=str, required=True, help="Raw Jonl dataset for training.")
parser.add_argument(
"-p",
"--plugin",
type=str,
default="zero2",
choices=["gemini", "gemini_auto", "zero2", "zero2_cpu", "3d", "ddp", "moe"],
help="Choose which plugin to use",
)
命令行启动训练
bash
colossalai run --nproc_per_node 2 lora_finetune.py --pretrained /home/idal-01/wxc/deepseek/deepseek_1.5B --dataset /home/idal-01/wxc/deepseek/health_dataset/ --plugin "zero2" --save_dir ./finetuned_model --tensorboard_dir ./logs --num_epochs 5 --batch_size 2 --accumulation_steps 2 --lr 1e-5 --max_length 2048 --mixed_precision "bf16" --grad_clip 1.0 --weight_decay 0.01 --warmup_steps 100 --lora_rank 8 --lora_alpha 16 --use_flash_attn
css
这是我使用的微调参数进行的训练
--plugin "zero2"
--num_epochs 5
--batch_size 2
--accumulation_steps 2
--lr 1e-5
--max_length 2048
--mixed_precision "bf16"
--grad_clip 1.0
--weight_decay 0.01
--warmup_steps 100
--lora_rank 16
--lora_alpha 32
--use_flash_attn
target_modules=["gate_proj", "up_proj", "down_proj"]
训练过程:
显存占用:单GPU 11165MiB 利用率 82%-85%
小结
完整的微调训练代码如果有需要的友友可私信我。
编写代码时遇到的主要问题(踩过的坑):
1 没注意到模型已经被封装过,使用之前的函数经常会出错
2 因为使用的deepseek-Qwen系列蒸馏模型,要求字符填充是向左, 默认是向右,所以需要更改方向,不过由于是分布式训练是多进程的,只改主进程是不行的,需要子进程也需要同步。
3 使用梯度检查点时--use_grad_checkpoint,一定要注意跟插件是否冲突,不然可以不能进行反向传播
4 使用HybridAdam优化器报错,发现需要GNU的版本不对,我想了想避免产生更大的问题,我还是老老实实用了Adam优化器。
写在最后
以后还是要及时编写博客,因为好多东西是一段时间之前的,很多坑已经忘了,写了一些印象比较深的坑。此外还希望大家多多点赞关注收藏。
请大家一定一定要关注!!!
请大家一定一定要关注!!!
请大家一定一定要关注!!!
友友们,你们的支持是我持续更新的动力~
创作不易,求关注,点赞,收藏,谢谢~