大模型LoRA微调实战(完整代码带数据)

一 大模型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)

上面代码的微调步骤:

  1. 加载预训练的模型和分词器:使用 transformers.AutoModelForCausalLMtransformers.AutoTokenizer 加载预训练的模型和分词器。

  2. LoRA 配置:配置 LoraConfig 参数并应用到模型上。

  3. 加载和处理训练数据:加载 JSON 格式的训练数据,并创建 SupervisedDataset 实例。

  4. 训练模型:使用 Trainer 类进行模型训练。

  5. 保存微调后的模型和分词器:使用 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%免费】🆓

### 大模型 LoRA 微调实战教程 #### 选择合适的环境配置 为了顺利进行大模型LoRA微调,建议使用具备良好硬件支持(如GPU)的工作站或云平台。安装必要的依赖库,例如PyTorch、Transformers等工具包,这些对于加载预训练模型和支持自定义层至关重要[^1]。 #### 准备数据集 针对特定应用场景准备高质量的数据集是至关重要的一步。以代码生成为例,可以收集来自GitHub或其他开源项目的源码片段作为训练样本。确保数据经过清洗处理,去除无关字符并保持一致格式[^2]。 #### 加载基础模型与设置超参数 利用Hugging Face提供的API轻松获取StarCoder这样的大型编码解码器架构。接着设定一些基本的学习率、批次大小等超参来指导后续优化过程。 ```python from transformers import AutoModelForSeq2SeqLM, Trainer, TrainingArguments model_name = "bigcode/starcoder" model = AutoModelForSeq2SeqLM.from_pretrained(model_name) training_args = TrainingArguments( output_dir="./results", num_train_epochs=3, per_device_train_batch_size=8, learning_rate=5e-5, ) ``` #### 应用LoRA技术调整网络结构 通过引入低秩适应机制,在原有权重矩阵基础上增加两个较小规模的新矩阵U和V,使得最终输出等于原始全连接层加上UV乘积的结果。这种方式不仅减少了额外存储开销还加快了收敛速度。 ```python import loralib as lora for name, module in model.named_modules(): if isinstance(module, torch.nn.Linear): # 将线性变换替换为LoRA特性的版本 new_module = lora.LoRALinear( in_features=module.in_features, out_features=module.out_features, r=4 # 秩数r的选择取决于具体任务需求 ) setattr(parent_module_of(name), name.split('.')[-1], new_module) ``` #### 开始训练流程 有了上述准备工作之后就可以启动Trainer对象来进行实际迭代更新了。期间可根据实际情况调整验证频率、保存策略等内容以便更好地监控进度和效果。 ```python trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=val_dataset ) trainer.train() ``` #### 测试评估性能提升情况 完成一轮或多轮次训练后,应当对新得到的模型进行全面评测,对比未加LoRA前后的差异之处。这有助于确认所做改动确实来了预期中的改进,并为进一步探索提供了依据。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值