本文旨在探讨基于Llama factory使用LoRA(Low-Rank Adaptation)技术对Llama3.1-70B-Chinese-Chat模型进行微调的过程,重点介绍在单机多卡和多机多卡两种分布式训练环境下的实现方法。
1.环境准备
1.1 平台环境
微调Llama3.1-70B模型,本地环境跑不了。只能选择租用云上GPU。关于算力租赁平台,我选择的是FunHPC,理由如下:
- 官网简单明了,进去就能租(无需排队),显卡类型多,总能找到适合我的卡型。
- 价格非常亲民,和其他平台相比,算是非常便宜了。
- 提供code-server开发界面,开发方便快捷。
- 最近官方出了一个活动,只要发文章,就能领取80元的算力金。趁着这个机会,写一份我微调Llama3.1-70B的历程。
磁盘空间扩容:
- 600G
显卡选择
- 单机多卡训练选择的是8×A100(40G),即1台A100服务器。
- 多机多卡训练选择的是2×8×100(40G),即2台A100服务器。
租用镜像选择:
- pytorch 2.2.0+cuda121
1.2 Llama factory 环境
1.2.1 下载Llama factory
git clone https://github.com/hiyouga/LLaMA-Factory.git
1.2.2 安装 Llama factory环境
cd LLaMA-Factory
pip install -e ".[torch,metrics]"
2.数据集准备
下面的python代码主要完成3个方面:
- 配置代理,方便访问huggingface,这里我画上了下,不方便透露了。
- 从huggingface上下载m-a-p/COIG-CQIA数据集,作为本次微调的数据集。
- 将下载后的数据集,转换成Alpaca格式。
Alpaca格式如下:
[
{
"instruction":
"human instruction (required)",
"input": "human input (optional)",
"output": "model response (required)",
"system": "system prompt (optional)",
"history": [
["human instruction in the first round (optional)", "model response in the first round (optional)"],
["human instruction in the second round (optional)", "model response in the second round (optional)"]
]
}
]
import os
import json
from datasets import load_dataset, concatenate_datasets
# 设置代理
os.environ["http_proxy"] = "*****"
os.environ["https_proxy"] = "*****"
def prepare_data():
data_names = ["chinese_traditional", "human_value", "wiki", "ruozhiba", "logi_qa", "wikihow", "zhihu", "douban", "xhs"]
datasets = [load_dataset("m-a-p/COIG-CQIA", name=name, cache_dir="./data", split="train") for name in data_names]
concatenated_dataset = concatenate_datasets(datasets)
return concatenated_dataset
def convert_to_alpaca_format(dataset):
alpaca_data = []
for entry in dataset:
alpaca_entry = {
"instruction": entry['instruction'],
"input": entry['input'],
"output": entry['output']
}
alpaca_data.append(alpaca_entry)
return alpaca_data
# 准备数据并转换为 Alpaca 格式
datasets = prepare_data()
alpaca_data = convert_to_alpaca_format(datasets)
# 将结果保存为 JSON 文件,不转义非 ASCII 字符
with open('alpaca_format_data.json', 'w', encoding='utf-8') as f:
json.dump(alpaca_data, f, ensure_ascii=False, indent=4)
print("转换完成,数据已保存为 'alpaca_format_data.json'")
3.模型准备
3.1 模型下载
pip install modelscope
modelscope download --model XD_AI/Llama3.1-70B-Chinese-Chat --local_dir /data/coding/Llama3.1-70B-Chinese-Chat
3.2 模型校验
由于model比较大,会报显存错误。我将校验代码修改了一下,改成多卡调用。
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "/data/coding/Llama3.1-70B-Chinese-Chat"
dtype = torch.bfloat16
# 加载 tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_id)
# 设置 pad_token_id
pad_token_id = tokenizer.pad_token_id if tokenizer.pad_token_id is not None else tokenizer.eos_token_id
# 使用 device_map 自动将模型切分到多 GPU
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=dtype,
device_map="auto"
)
chat = [{"role": "user", "content": "写一首关于机器学习的诗。"}]
inputs = tokenizer.apply_chat_template(chat, tokenize=True, add_generation_prompt=True, return_tensors="pt")
# 设置 attention_mask
input_ids = inputs.input_ids.to("cuda:0")
attention_mask = inputs.attention_mask.to("cuda:0") if "attention_mask" in inputs else None
# 推理
outputs = model.generate(
input_ids,
attention_mask=attention_mask, # 添加 attention_mask
max_new_tokens=8192,
do_sample=True,
temperature=0.6,
top_p=0.9,
pad_token_id=pad_token_id # 设置 pad_token_id
)
response = outputs[0][input_ids.shape[-1]:]
print(tokenizer.decode(response, skip_special_tokens=True))
输出结果:
4.模型训练
在训练之前需要做的两件事儿:
-
-
将alpaca_format_data.json文件放到Llama factory的data目录下。
-
在dataset_info.json中添加:
{
"alpaca_format_data": {
"file_name": "alpaca_format_data.json"
},
-
4.1 单机多卡训练
我的llama3_lora_sft_ds31.yaml如下:
终端执行命令如下:
FORCE_TORCHRUN=1 llamafactory-cli train /data/coding/LLaMA-Factory/examples/train_lora/llama3_lora_sft_ds31.yaml
训练过程如下:
[INFO|trainer.py:2134] 2024-08-16 09:14:59,763 >> ***** Running training *****
[INFO|trainer.py:2135] 2024-08-16 09:14:59,763 >> Num examples = 22,582
[INFO|trainer.py:2136] 2024-08-16 09:14:59,763 >> Num Epochs = 5
[INFO|trainer.py:2137] 2024-08-16 09:14:59,763 >> Instantaneous batch size per device = 8
[INFO|trainer.py:2140] 2024-08-16 09:14:59,763 >> Total train batch size (w. parallel, distributed & accumulation) = 512
[INFO|trainer.py:2141] 2024-08-16 09:14:59,763 >> Gradient Accumulation steps = 8
[INFO|trainer.py:2142] 2024-08-16 09:14:59,763 >> Total optimization steps = 220
[INFO|trainer.py:2143] 2024-08-16 09:14:59,774 >> Number of trainable parameters = 103,546,880
{'loss': 2.021, 'grad_norm': 0.31445133686065674, 'learning_rate': 0.00022727272727272727, 'epoch': 0.23}
{'loss': 1.7366, 'grad_norm': 0.13742084801197052, 'learning_rate': 0.00045454545454545455, 'epoch': 0.45}
{'loss': 1.6267, 'grad_norm': 0.06480135023593903, 'learning_rate': 0.0004979887032076989, 'epoch': 0.68}
{'loss': 1.5846, 'grad_norm': 0.05686546117067337, 'learning_rate': 0.0004898732434036243, 'epoch': 0.91}
{'loss': 1.5642, 'grad_norm': 0.05606243386864662, 'learning_rate': 0.0004757316345716554, 'epoch': 1.13}
{'loss': 1.5164, 'grad_norm': 0.06566128134727478, 'learning_rate': 0.0004559191453574582, 'epoch': 1.36}
{'loss': 1.5104, 'grad_norm': 0.06976603716611862, 'learning_rate': 0.0004309335095262675, 'epoch': 1.59}
{'loss': 1.4946, 'grad_norm': 0.06345170736312866, 'learning_rate': 0.00040140242178441667, 'epoch': 1.81}
{'loss': 1.4851, 'grad_norm': 0.07551503926515579, 'learning_rate': 0.0003680677686931707, 'epoch': 2.04}
{'loss': 1.4064, 'grad_norm': 0.11773069202899933, 'learning_rate': 0.00033176699082935546, 'epoch': 2.27}
{'loss': 1.411, 'grad_norm': 0.09556800872087479, 'learning_rate': 0.00029341204441673266, 'epoch': 2.49}
{'loss': 1.4018, 'grad_norm': 0.09359253197908401, 'learning_rate': 0.000253966490958702, 'epoch': 2.72}
{'loss': 1.3875, 'grad_norm': 0.1037076786160469, 'learning_rate': 0.00021442129043167875, 'epoch': 2.95}
{'loss': 1.3314, 'grad_norm': 0.12813276052474976, 'learning_rate': 0.00017576990616793137, 'epoch': 3.17}
{'loss': 1.3125, 'grad_norm': 0.1260678470134735, 'learning_rate': 0.00013898334684855646, 'epoch': 3.4}
{'loss': 1.2788, 'grad_norm': 0.13497693836688995, 'learning_rate': 0.00010498577260720049, 'epoch': 3.63}
{'loss': 1.2677, 'grad_norm': 0.12839122116565704, 'learning_rate': 7.463127807341966e-05, 'epoch': 3.85}
{'loss': 1.2469, 'grad_norm': 0.175085186958313, 'learning_rate': 4.8682435617235344e-05, 'epoch': 4.08}
{'loss': 1.2235, 'grad_norm': 0.1542418748140335, 'learning_rate': 2.7791137836269158e-05, 'epoch': 4.31}
{'loss': 1.1948, 'grad_norm': 0.14159728586673737, 'learning_rate': 1.2482220564763668e-05, 'epoch': 4.53}
{'loss': 1.2039, 'grad_norm': 0.13814429938793182, 'learning_rate': 3.1402778309014278e-06, 'epoch': 4.76}
{'loss': 1.2098, 'grad_norm': 0.13053908944129944, 'learning_rate': 0.0, 'epoch': 4.99}
{'train_runtime': 88370.9016, 'train_samples_per_second': 1.278, 'train_steps_per_second': 0.002, 'train_loss': 1.4279815023595637, 'epoch': 4.99}
[INFO|trainer.py:3821] 2024-08-17 09:50:24,508 >> Num examples = 2510
[INFO|trainer.py:3824] 2024-08-17 09:50:24,508 >> Batch size = 8
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 40/40 [14:59<00:00, 22.49s/it]
***** eval metrics *****
epoch = 4.9858
eval_loss = 1.5017
eval_runtime = 0:15:24.41
eval_samples_per_second = 2.715
eval_steps_per_second = 0.043
训练时间大致:15小时
显卡占用如下:
训练loss如下:
4.2 多机多卡训练
训练的yaml文件和单机多卡一致。
终端执行命令如下:
主节点:
FORCE_TORCHRUN=1 NNODES=2 RANK=0 MASTER_ADDR=10.222.51.150 MASTER_PORT=29500 llamafactory-cli train /data/coding/LLaMA-Factory/examples/train_lora/llama3_lora_sft_ds31.yaml
次节点:
FORCE_TORCHRUN=1 NNODES=2 RANK=1 MASTER_ADDR=10.222.51.150 MASTER_PORT=29500 llamafactory-cli train /data/coding/LLaMA-Factory/examples/train_lora/llama3_lora_sft_ds31.yaml
训练时间大致:63小时
{'loss': 1.9696, 'grad_norm': 0.10808725655078888, 'learning_rate': 0.00045454545454545455, 'epoch': 0.45}
13%|██████████████████▋ | 14/110 [22:44:00<155:12:34, 5820.36s/it
由于这里训练时间较长,就不展示训练过程及训练loss。
5.模型效果展示
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 llamafactory-cli chat --model_name_or_path /data/coding/Llama3.1-70B-Chinese-Chat --adapter_name_or_path /data/coding/LLaMA3-70B/lora/sft --template llama3 --finetuning_type lora
推理效果如下:
User: 为什么昙花开花时间非常短?
Assistant: 昙花原产于南美洲墨西哥、危地马拉、委内瑞拉等热带地区。昙花的花朵非常美丽,花朵颜色有红色、白色、紫色、粉红色、黄色等。它的花朵大多数在晚上开,第二天早晨就凋谢了,因此它又叫"一夜夫人"、"夜合花"等。昙花的花朵为什么时间这么短呢?原来昙花是喜暖的植物,白天温度高时,花瓣的伸展能力变弱,不能正常地舒展开来;而到了晚上温度低时,花瓣的伸展能力增强,花朵就开放了。到了第二天早晨,气温升高,花瓣的伸展能力又减弱,花朵便慢慢地合拢,最后就枯萎凋谢了。昙花的花朵时间短是由它的生理特性决定的。
User: 为什么英国曾被称为"日不落帝国"?
Assistant: 英国曾被称为"日不落帝国",这是因为在18世纪和19世纪的殖民战争中,英国占领了世界各地的许多地方,从而建立了一个庞大的殖民帝国。当时英国在世界各地的殖民地非常多,无论什么时候,英国总有地方是白天。英国的这种特殊地位使它在当时被称为"日不落帝国"。但是,随着时间的推移,英国的殖民地逐渐独立,英国的殖民地数量也在不断减少,最终英国的殖民地几乎全部独立,英国的"日不落帝国"也随之消失了。
User: 给我介绍一下算力显卡
Assistant: 算力显卡是指那些专门用于计算的显卡。这些显卡通常具有非常高的性能和非常低的功耗,它们可以帮助用户进行各种复杂的计算任务,如数据挖掘、机器学习等。算力显卡的主要特点是它们具有非常高的浮点运算能力,这使得它们可以快速地处理大量的数据并产生高质量的结果。此外,算力显卡还具有非常低的功耗,这使得它们可以在长时间的运行中保持稳定的性能。
6.总结
本文通过单机多卡和多机多卡的情况下,完成基于Llama factory使用LoRA(Low-Rank Adaptation)技术对Llama3.1-70B-Chinese-Chat模型进行微调的过程。总体的推理效果不错。对于多机多卡下,训练速度慢的问题还有待改善。
如何学习AI大模型?
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
一、全套AGI大模型学习路线
AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!
二、640套AI大模型报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
三、AI大模型经典PDF籍
随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。
四、AI大模型商业化落地方案
作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。