一 大模型LoRA微调环境
1 LORA微调环境:
关键硬件配置 :3060显卡 12G的显存
操作系统:window 10 64位
开发工具:PyCharm 2022.1 (Community Edition)
前排提示,文末有大模型AGI-CSDN独家资料包哦!
2 微调的大模型目标是qwen2大模型
本次微调最开始是打算使用Qwen/Qwen-1_8B-Chat的模型作为微调对象,调试过程中不断报GPU显存不够,该模型需要的显存超过12G,因此后面改用 Qwen/Qwen1.5-0.5B-Chat 模型。
二 LORA微调实操
1 下载模型(微调Qwen/Qwen1.5-0.5B-Chat)
下载需要微调的模型文件保存到本地,以下代码下载 Qwen/Qwen1.5-0.5B-Chat 模型文件:
# 下载模型并保存在当前目录
from modelscope.hub.snapshot_download import snapshot_download
#model_dir = snapshot_download('Qwen/Qwen-1_8B-Chat', cache_dir='.', revision='master')
model_dir = snapshot_download('qwen/Qwen1.5-0.5B-Chat', cache_dir='.')
print('model dir : ', model_dir)
执行后成功下载模型如下图:
2 加载大模型文件
以下代码加载 下载的模型,微调后的模型,或合并的模型,根据情况改路径即可
# 下载模型
from modelscope.hub.snapshot_download import snapshot_download
# model_dir = snapshot_download('Qwen/Qwen-1_8B-Chat', cache_dir='.', revision='master')
# 模型下载
# model_dir = snapshot_download('qwen/Qwen1.5-0.5B-Chat', cache_dir='.')
# print('model dir : ', model_dir)
# 微调后的模型
#model_dir = r'F:\ai\Qwen-main\recipes\finetune\results'
# 微调前下载的模型
# model_dir = r'F:\ai\Qwen-main\recipes\finetune\Qwen\Qwen1___5-0___5B-Chat'
# 合并后的模型
model_dir = r'F:\ai\Qwen-main\recipes\finetune\merge_model'
# 测试下载回来的模型有没有问题
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation import GenerationConfig
def load_view_model():
"""
加载与查看模型信息
"""
tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True)
# pip install flash-attention 使用flash_attn 可以加速推理
model = AutoModelForCausalLM.from_pretrained(
model_dir,
device_map="auto",
trust_remote_code=True
).eval()
# print("查看模型信息")
# print(model)
test = '''在互联网普及的时代,社交媒体已经成为了现代人生活中不可缺少的一部分。从微信、微博、Facebook到Twitter、Instagram等等,社交媒体不仅满足了人们交流互动的需求,
同时让人们更加容易地分享自己的生活瞬间、获取新闻资讯、找到志同道合的人群以及推广自己的业务。然而,与此同时,社交媒体也带来了一系列问题,如滥用个人信息、泄露隐私等。因此,
如何正确地使用社交媒体已经成为了一个备受关注的话题。,总结上面这段文本的几个关键词。'''
# test = '你好,你是谁?'
prompt = test
messages = [
{"role": "system", "content": "你是一个乐于助人的助手."},
{"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt").to('cuda')
generated_ids = model.generate(
model_inputs.input_ids,
max_new_tokens=512
)
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print('当前使用模型路径:',model_dir)
print('问题:',test)
print('-----------------result---------')
print(response)
# 以下代码适合1.8b模型的
# response, history = model.chat(tokenizer, "你好,你是谁?", history=None)
# print(response)
# response, history = model.chat(tokenizer, test, history=None)
# print(response)
if __name__ == '__main__':
load_view_model()
3 LoRA微调代码
以下是微调模型完整代码,如下:
import json
import os
import torch
from torch.utils.data import Dataset
from transformers import Trainer, TrainingArguments, AutoModelForCausalLM, AutoTokenizer, HfArgumentParser
from peft import LoraConfig, get_peft_model
# 禁用 TOKENIZERS_PARALLELISM 环境变量以避免 SIGALRM 错误
os.environ["TOKENIZERS_PARALLELISM"] = "false"
IGNORE_TOKEN_ID = -100 # 标记忽略的标签ID
def preprocess(sources, tokenizer, max_len, system_message="You are a helpful assistant."):
roles = {"user": "user", "assistant": "assistant"}
# 1.8 的
# im_start, im_end = tokenizer.im_start_id, tokenizer.im_end_id
im_start, im_end = tokenizer.additional_special_tokens_ids[0], tokenizer.additional_special_tokens_ids[1]
nl_tokens = tokenizer('\n').input_ids
system = [im_start] + tokenizer('system').input_ids + nl_tokens + tokenizer(system_message).input_ids + [
im_end] + nl_tokens
input_ids, targets = [], []
for source in sources:
if roles[source[0]["from"]] != "user":
source = source[1:]
input_id, target = system.copy(), [im_start] + [IGNORE_TOKEN_ID] * (len(system) - 3) + [im_end] + nl_tokens
for sentence in source:
role = roles[sentence["from"]]
_input_id = tokenizer(role).input_ids + nl_tokens + tokenizer(sentence["value"]).input_ids + [
im_end] + nl_tokens
input_id += _input_id
if role == "user":
_target = [im_start] + [IGNORE_TOKEN_ID] * (len(_input_id) - 3) + [im_end] + nl_tokens
else:
_target = [im_start] + [IGNORE_TOKEN_ID] * len(tokenizer(role).input_ids) + _input_id[len(tokenizer(
role).input_ids) + 1:-2] + [im_end] + nl_tokens
target += _target
input_ids.append(input_id[:max_len] + [tokenizer.pad_token_id] * (max_len - len(input_id)))
targets.append(target[:max_len] + [IGNORE_TOKEN_ID] * (max_len - len(target)))
return {"input_ids": torch.tensor(input_ids, dtype=torch.long), "labels": torch.tensor(targets, dtype=torch.long)}
class SupervisedDataset(Dataset):
def __init__(self, raw_data, tokenizer, max_len):
# 预处理数据并生成 input_ids 和 labels
sources = [example["conversations"] for example in raw_data]
data_dict = preprocess(sources, tokenizer, max_len)
self.input_ids = data_dict["input_ids"]
self.labels = data_dict["labels"]
def __len__(self):
return len(self.input_ids)
def __getitem__(self, idx):
return {"input_ids": self.input_ids[idx], "labels": self.labels[idx]}
def train(model_name_or_path, data_path, eval_data_path, output_dir, model_max_length, lora_r, lora_alpha,
lora_dropout, lora_target_modules, lora_bias, q_lora, **kwargs):
training_args = TrainingArguments(output_dir=output_dir, **kwargs)
training_args.model_max_length = model_max_length
training_args.use_lora = True
training_args.fp16 = True # 启用混合精度训练
training_args.per_device_train_batch_size = 1 # 减少 batch size
training_args.gradient_accumulation_steps = 16 # 启用梯度累积
model = AutoModelForCausalLM.from_pretrained(model_name_or_path, trust_remote_code=True)
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, model_max_length=model_max_length,
trust_remote_code=True)
pad_token_id = tokenizer.pad_token_id
# 查看 pad_token_id
print(f"The pad_token_id for the tokenizer is: {pad_token_id}")
#tokenizer.pad_token_id = tokenizer.eod_id
lora_config = LoraConfig(
r=lora_r,
lora_alpha=lora_alpha,
target_modules=lora_target_modules,
lora_dropout=lora_dropout,
bias=lora_bias,
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
with open(data_path, "r", encoding='utf-8') as f:
train_data = json.load(f)
train_dataset = SupervisedDataset(train_data, tokenizer, model_max_length)
eval_dataset = None
if eval_data_path:
with open(eval_data_path, "r") as f:
eval_data = json.load(f)
eval_dataset = SupervisedDataset(eval_data, tokenizer, model_max_length)
trainer = Trainer(model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset)
trainer.train()
trainer.save_state()
trainer.save_model(training_args.output_dir) # 保存微调后的模型
tokenizer.save_pretrained(training_args.output_dir) # 保存分词器
if __name__ == "__main__":
import sys
from argparse import ArgumentParser
# 模型路径
# model_dir = r'F:\ai\Qwen-main\recipes\finetune\Qwen\Qwen-1_8B-Chat'
model_dir = r'F:\ai\Qwen-main\recipes\finetune\Qwen\Qwen1___5-0___5B-Chat'
output_dir = r'F:\ai\Qwen-main\recipes\finetune\results'
# 数据路径
data_path = r'F:\ai\Qwen-main\recipes\finetune\demo_utf8.json'
# 设置命令行参数解析
parser = ArgumentParser()
parser.add_argument("--model_name_or_path", default=model_dir)
parser.add_argument("--data_path", default=data_path)
parser.add_argument("--eval_data_path", default=None)
parser.add_argument("--output_dir", default=output_dir)
parser.add_argument("--model_max_length", type=int, default=2048)
parser.add_argument("--lora_r", type=int, default=16)
parser.add_argument("--lora_alpha", type=int, default=8)
parser.add_argument("--lora_dropout", type=float, default=0.05)
# 非常重要 指定要训练的层次
# parser.add_argument("--lora_target_modules", nargs='+', default=["c_attn", "c_proj", "w1", "w2"])
parser.add_argument("--lora_target_modules", nargs='+',
default=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"])
parser.add_argument("--lora_bias", default="none")
parser.add_argument("--q_lora", type=bool, default=False)
args = parser.parse_args()
print(args)
print('1111', args.model_name_or_path)
train(
model_name_or_path=args.model_name_or_path,
data_path=args.data_path,
eval_data_path=args.eval_data_path,
output_dir=args.output_dir,
model_max_length=args.model_max_length,
lora_r=args.lora_r,
lora_alpha=args.lora_alpha,
lora_dropout=args.lora_dropout,
lora_target_modules=args.lora_target_modules,
lora_bias=args.lora_bias,
q_lora=args.q_lora)
上面代码的微调步骤:
-
加载预训练的模型和分词器:使用
transformers.AutoModelForCausalLM
和transformers.AutoTokenizer
加载预训练的模型和分词器。 -
LoRA 配置:配置
LoraConfig
参数并应用到模型上。 -
加载和处理训练数据:加载 JSON 格式的训练数据,并创建
SupervisedDataset
实例。 -
训练模型:使用
Trainer
类进行模型训练。 -
保存微调后的模型和分词器:使用
trainer.save_model
方法保存微调后的模型到指定目录。
重点:LoRA 配置参数
我们调整大模型哪些层,**微调目标?**不同的大模型文件层参数名称是不同的,
千问2 0.5b 模型参数:
一般我们选择 注意力投影与多层感知的层作为微调目标:
"q\_proj", "k\_proj", "v\_proj", "o\_proj", "gate\_proj", "up\_proj", "down\_proj"
另一个模型 千问 1.8b 模型参数:
这里的注意力投影与多层感知的层作是:“c_attn”, “c_proj”, “w1”, “w2”
4 合并LoRA微调后的模型代码:
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel, PeftConfig
# 原模型路径
model_name_or_path = r'F:\ai\Qwen-main\recipes\finetune\Qwen\Qwen1___5-0___5B-Chat'
# LoRA权重路径
lora_weight_path = r'F:\ai\Qwen-main\recipes\finetune\results'
# 1. 加载基础模型和分词器
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
model = AutoModelForCausalLM.from_pretrained(model_name_or_path)
# 2. 加载LoRA模型
peft_config = PeftConfig.from_pretrained(lora_weight_path)
model = PeftModel.from_pretrained(model, lora_weight_path)
# 3. 合并LoRA权重
model = model.merge_and_unload()
# 4. 保存合并后的模型
output_dir = "./merge_model"
model.save_pretrained(output_dir)
tokenizer.save_pretrained(output_dir)
执行上面代码后会把基础模型+LoRA微调后的模型合并在一起并输出保存新的模型,这个过程不像微调,执行全并过程非常较快,合并后输出的模型文件如下图:
运行上面加载大模型用一个问题测试效果:
三 LORA微调小结:
1 在LORA微调时占用资源情况
开始微调,如下图:
微调过程占用资源,满载12G的显存运行 如下图:
微调结束:
微调后的模型如下图:
2 微调后效果模型对比
正常是要做评估的,没有做评估,这里就以问同样的一个问题,看微调前与微调后回复结果:
1 LoRA微调前(原始模型):
2 LoRA微调后:
3 基础模型+LoRA微调合并模型后:
从上面对比图可以看出,微调后的回答的答案与模型合并的模型都差不多效果,比较准确。
微调前回复答案明显多了一些不像关键字的没有微调后的好,说明确实有效果。
6.2 系统的持续优化
通过数据反馈、模型微调和算法优化,AI大模型问答系统能够不断进化。这使得系统不仅能够适应新兴问题,还能处理日益复杂的用户需求,为用户提供更加智能的服务。
如何学习AI大模型 ?
最先掌握AI的人,将会比较晚掌握AI的人有竞争优势
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
倘若大家对大模型抱有兴趣,那么这套大模型学习资料肯定会对你大有助益。
针对0基础小白:
如果你是零基础小白,快速入门大模型是可行的。
大模型学习流程较短,学习内容全面,需要理论与实践结合
学习计划和方向能根据资料进行归纳总结
包括:大模型学习线路汇总、学习阶段,大模型实战案例,大模型学习视频,人工智能、机器学习、大模型书籍PDF。带你从零基础系统性的学好大模型!
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费
】🆓
👉AI大模型学习路线汇总👈
大模型学习路线图,整体分为7个大的阶段:(全套教程文末领取哈)
第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;
第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;
第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;
第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;
第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;
第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;
第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。
👉大模型实战案例👈
光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
👉大模型视频和PDF合集👈
这里我们能提供零基础学习书籍和视频。作为最快捷也是最有效的方式之一,跟着老师的思路,由浅入深,从理论到实操,其实大模型并不难。
👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;
• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;
• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;
• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。
👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费
】🆓