【GLM-4微调实战】GLM-4-9B-Chat模型之Lora微调实战

系列篇章💥

No.文章
1【GLM-4部署实战】GLM-4-9B-Chat模型本地部署实践指南
2【GLM-4部署实战】GLM-4-9B-Chat模型之对话机器人部署测试
3【GLM-4部署实战】GLM-4-9B-Chat模型之vLLM部署推理实践
4【GLM-4微调实战】GLM-4-9B-Chat模型之Lora微调实战


引言

在人工智能的广阔天地里,深度学习模型的微调技术扮演着至关重要的角色。它使我们能够根据特定任务的需求,对预训练模型进行精细调整,从而获得更优的性能表现。本文将深入探讨如何针对GLM-4-9B-Chat模型实施Lora微调,期待在特定领域中实现更高的准确度和效率。

一、环境准备

在开始我们的微调之旅之前,首先需要搭建一个合适的开发环境。我们推荐在AutoDL平台上租用一台配备24G显存的显卡机器,例如NVIDIA 4090,以满足模型训练的硬件需求。选择镜像时,推荐使用PyTorch-2.1.0-3.10(ubuntu22.04)-12.1,这将为我们提供一个稳定且功能丰富的开发环境。
在这里插入图片描述

完成机器租用后,打开JupyterLab并启动终端,开始环境配置。这包括安装必要的软件包和工具,确保我们的开发环境能够支持后续的模型微调工作。

二、安装依赖

在环境配置阶段,我们需要确保所有依赖项都已正确安装。以下是详细的步骤:

  1. 升级pip:使用以下命令确保pip工具是最新版本:
python -m pip install --upgrade pip

2.更换pypi源:为了加快库的安装速度,我们推荐使用清华大学的TUNA镜像站。通过以下命令更换默认的pypi源:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

3.安装依赖包:接下来,安装modelscope、transformers、peft等必要的Python库。使用以下命令完成安装:

pip install modelscope==1.9.5
pip install "transformers>=4.40.0"
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.29.3
pip install datasets==2.13.0
pip install peft==0.10.0
pip install tiktoken==0.7.0

MAX_JOBS=8 pip install flash-attn --no-build-isolation

安装完成如下:
在这里插入图片描述

三、模型下载

使用 modelscope 中的 snapshot_download 函数下载模型。第一个参数为模型名称,参数 cache_dir 用于指定模型的下载路径。

import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('ZhipuAI/glm-4-9b-chat', cache_dir='/root/autodl-tmp', revision='master')

在 /root/autodl-tmp 路径下新建 download-model.py 文件,并在其中输入以上内容:
在这里插入图片描述
运行 python /root/autodl-tmp/download-model.py 执行下载。需注意,模型大小约为 18 GB,下载模型大概需要 10 - 20 分钟,请耐心等待。
在这里插入图片描述

四、数据集准备

微调大型语言模型(LLM)通常涉及指令微调,这是一种特定的数据准备和训练过程。在指令微调中,数据集由一系列包含指令、输入和输出的条目组成,例如:

{
    "instruction": "回答以下用户问题,仅输出答案。",
    "input": "1+1等于几?",
    "output": "2"
}

在这个例子中,instruction 是给予模型的任务指令,明确告知模型需要完成的具体任务;input 是为了完成任务所需的用户提问或相关信息;而 output 则是模型应产生的预期回答。

我们的目标是训练模型,使其能够准确理解并遵循用户的指令。因此,在构建指令集时,必须针对特定的应用目标精心设计。例如,如果我们的目标是创建一个能够模仿特定对话风格的个性化LLM,我们就需要构建与之相应的指令集。

以使用开源的甄嬛传对话数据集为例,如果我们希望模型能够模拟甄嬛的对话风格,我们可以构造如下形式的指令:

[
    {
        "instruction": "小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——",
        "input": "",
        "output": "嘘——都说许愿说破是不灵的。"
    },
    {
        "instruction": "这个温太医啊,也是古怪,谁不知太医不得皇命不能为皇族以外的人请脉诊病,他倒好,十天半月便往咱们府里跑。",
        "input": "",
        "output": "你们俩话太多了,我该和温太医要一剂药,好好治治你们。"
    },
    {
        "instruction": "嬛妹妹,刚刚我去府上请脉,听甄伯母说你来这里进香了。",
        "input": "",
        "output": "出来走走,也是散心。"
},
。。。。。。
]

在此示例中,我们省略了 input 字段,因为模型的回答是基于预设的角色背景知识,而非用户的直接提问。通过这种方式,我们可以训练模型学习并模仿特定角色的语言风格和对话模式,从而在实际应用中提供更加个性化和情景化的交互体验。

五、加载数据

# 导入依赖包
from datasets import Dataset
import pandas as pd
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer, GenerationConfig

# 加载数据集 、将JSON文件转换为CSV文件
df = pd.read_json('./huanhuan.json')
ds = Dataset.from_pandas(df)

# 查看前三条数据集
ds[:3]

输出:

{'instruction': ['小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——',
  '这个温太医啊,也是古怪,谁不知太医不得皇命不能为皇族以外的人请脉诊病,他倒好,十天半月便往咱们府里跑。',
  '嬛妹妹,刚刚我去府上请脉,听甄伯母说你来这里进香了。'],
 'input': ['', '', ''],
 'output': ['嘘——都说许愿说破是不灵的。', '你们俩话太多了,我该和温太医要一剂药,好好治治你们。', '出来走走,也是散心。']}

六、数据处理

Lora 训练的数据是需要经过格式化、编码之后再输入给模型进行训练的,如果是熟悉 Pytorch 模型训练流程的同学会知道,我们一般需要将输入文本编码为 input_ids,将输出文本编码为 labels,编码之后的结果都是多维的向量。我们首先定义一个预处理函数,这个函数用于对每一个样本,编码其输入、输出文本并返回一个编码后的字典:

1、设置填充符

tokenizer = AutoTokenizer.from_pretrained('/root/autodl-tmp/glm-4-9b-chat/ZhipuAI/glm-4-9b-chat', use_fast=False, trust_remote_code=True)
# 将tokenizer的pad_token设置为eos_token,这样在进行填充时,会使用eos_token作为填充符号
tokenizer.pad_token = tokenizer.eos_token

输出:
在这里插入图片描述

2、定义数据集处理函数

def process_func(example):
    MAX_LENGTH = 384
    input_ids, attention_mask, labels = [], [], []
    instruction = tokenizer((f"[gMASK]<sop><|system|>\n假设你是皇帝身边的女人--甄嬛。<|user|>\n"
                            f"{example['instruction']+example['input']}<|assistant|>\n"
                            ).strip(), 
                            add_special_tokens=False)
    response = tokenizer(f"{example['output']}", add_special_tokens=False)
    input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
    attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1]  # 因为eos token咱们也是要关注的所以 补充为1
    labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]  
    if len(input_ids) > MAX_LENGTH:  # 做一个截断
        input_ids = input_ids[:MAX_LENGTH]
        attention_mask = attention_mask[:MAX_LENGTH]
        labels = labels[:MAX_LENGTH]
    return {
        "input_ids": input_ids,
        "attention_mask": attention_mask,
        "labels": labels
}

GLM4-9B-chat 采用的Prompt Template格式如下:

[gMASK]<sop><|system|> 
假设你是皇帝身边的女人--甄嬛。<|user|> 
小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——<|assistant|> 
嘘——都说许愿说破是不灵的。<|endoftext|>

3、数据处理

tokenized_id = ds.map(process_func, remove_columns=ds.column_names)
tokenized_id

输出:
在这里插入图片描述

4、查看数据结构

print(tokenizer.decode(tokenized_id[0]['input_ids']))
print(tokenized_id[0]['input_ids'])
print(tokenizer.decode([151331, 151333, 151335]))
print(tokenizer.encode('[gMASK]<sop><|system|>', add_special_tokens=False))

输出:
在这里插入图片描述

5、查看labels

tokenizer.decode(list(filter(lambda x: x != -100, tokenized_id[1]["labels"])))

输出:

'你们俩话太多了,我该和温太医要一剂药,好好治治你们。 <|endoftext|>'

七、创建模型

import torch

model = AutoModelForCausalLM.from_pretrained('/root/autodl-tmp/ZhipuAI/glm-4-9b-chat', device_map="auto",torch_dtype=torch.bfloat16, trust_remote_code=True)
model

输出:
在这里插入图片描述

model.enable_input_require_grads() # 开启梯度检查点时,要执行该方法

查看精度

model.dtype

输出:
torch.bfloat16

八、Lora微调配置

Lora是一种微调技术,通过在模型中引入可训练的参数来增强模型的表达能力。为了适应特定的微调需求,我们将对Lora进行详细的配置。

LoraConfig类中,可以设置多个参数,主要参数如下:

  • task_type:指定模型的类型。
  • target_modules:指定需要训练的模型层的名称,主要是attention部分的层。不同的模型对应的层的名称可能会有所不同,可以接受数组、字符串或正则表达式作为输入。
  • r:Lora的秩,具体可以参考Lora的原理。
  • lora_alpha:Lora的alaph参数,具体作用可以参考Lora的原理。

1)关于Lora的缩放,它并不是指r(秩),而是lora_alpha/r。在这个LoraConfig中,缩放被设置为4倍。

from peft import LoraConfig, TaskType, get_peft_model

config = LoraConfig(
    task_type=TaskType.CAUSAL_LM, 
    target_modules=["query_key_value", "dense", "dense_h_to_4h", "dense_4h_to_h"],  # 现存问题只微调部分演示即可
    inference_mode=False, # 训练模式
    r=8, # Lora 秩
    lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
    lora_dropout=0.1# Dropout 比例
)
config

输出:

LoraConfig(peft_type=<PeftType.LORA: 'LORA'>, auto_mapping=None, base_model_name_or_path=None, revision=None, task_type=<TaskType.CAUSAL_LM: 'CAUSAL_LM'>, inference_mode=False, r=8, target_modules={'dense', 'dense_h_to_4h', 'query_key_value', 'dense_4h_to_h'}, lora_alpha=32, lora_dropout=0.1, fan_in_fan_out=False, bias='none', use_rslora=False, modules_to_save=None, init_lora_weights=True, layers_to_transform=None, layers_pattern=None, rank_pattern={}, alpha_pattern={}, megatron_config=None, megatron_core='megatron.core', loftq_config={}, use_dora=False, layer_replication=None)

2)加载配置

model = get_peft_model(model, config)
config

查看配置如下:

LoraConfig(peft_type=<PeftType.LORA: 'LORA'>, auto_mapping=None, base_model_name_or_path='/root/autodl-tmp/ZhipuAI/glm-4-9b-chat', revision=None, task_type=<TaskType.CAUSAL_LM: 'CAUSAL_LM'>, inference_mode=False, r=8, target_modules={'dense', 'dense_h_to_4h', 'query_key_value', 'dense_4h_to_h'}, lora_alpha=32, lora_dropout=0.1, fan_in_fan_out=False, bias='none', use_rslora=False, modules_to_save=None, init_lora_weights=True, layers_to_transform=None, layers_pattern=None, rank_pattern={}, alpha_pattern={}, megatron_config=None, megatron_core='megatron.core', loftq_config={}, use_dora=False, layer_replication=None)

3)查看可训练的参数

model.print_trainable_parameters()

输出:

trainable params: 21,176,320 || all params: 9,421,127,680 || trainable%: 0.22477479044207158

九、配置训练参数

TrainingArguments 类的源代码详细阐述了每个参数的具体功能,大家有兴趣可以自行查阅。这里,我将简要介绍几个常用的参数:

  • output_dir:指定模型训练后的输出目录。
  • per_device_train_batch_size:设置每个设备的批次大小(即 batch size)。
  • gradient_accumulation_steps:用于梯度累积的步数。如果显存资源有限,可以减小 batch size 并增加梯度累积的步数。
  • logging_steps:指定在训练过程中每隔多少步输出一次日志信息。
  • num_train_epochs:训练的总轮数(即 epoch 数)。
  • gradient_checkpointing:启用或禁用梯度检查点。一旦启用,必须调用 model.enable_input_require_grads() 方法。具体原理可进一步探索,此处不展开详述。

这些参数可以根据实际需求进行调整,以优化训练过程。

# 定义训练参数
args = TrainingArguments(
    output_dir="./output/GLM4",  # 输出目录,用于保存模型和日志
    per_device_train_batch_size=1,  # 每个设备的训练批次大小
    gradient_accumulation_steps=8,  # 梯度累积步数,用于模拟更大的批次大小
    logging_steps=50,  # 每隔多少步记录一次日志
    num_train_epochs=2,  # 训练的总轮数
    save_steps=100,  # 每隔多少步保存一次模型
    learning_rate=1e-5,  # 学习率
    save_on_each_node=True,  # 是否在每个节点上保存模型
    gradient_checkpointing=True  # 是否启用梯度检查点(减少内存占用)
)

十、开始Trainer训练

使用Trainer类来启动模型的训练过程。我们将监控训练进度,并根据需要调整训练策略。

# 创建训练器实例
trainer = Trainer(
    model=model,  # 指定要训练的模型
    args=args,  # 传入训练参数
    train_dataset=tokenized_id,  # 提供训练数据集,这里假设已经进行了分词和编码处理
    data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),  # 使用适当的数据整理器,这里针对序列到序列任务进行填充
)

# 开始训练
trainer.train()

训练结果:
在这里插入图片描述

十一、保存训练模型

将训练好的模型和对应的分词器保存到指定的路径

# 设置模型保存路径
peft_model_id = "./GLM4_lora"

# 保存训练好的模型到指定路径
trainer.model.save_pretrained(peft_model_id)

# 保存对应的分词器到指定路径
tokenizer.save_pretrained(peft_model_id)

输出:
在这里插入图片描述

十二、模型合并

在微调完成后,我们需要合并微调后的参数到原始模型中,以便于部署和推理。

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
from peft import PeftModel

mode_path = '/root/autodl-tmp/ZhipuAI/glm-4-9b-chat'
lora_path = './GLM4_lora'

# 加载tokenizer
tokenizer = AutoTokenizer.from_pretrained(mode_path, trust_remote_code=True)

# 加载模型
model = AutoModelForCausalLM.from_pretrained(mode_path, device_map="auto",torch_dtype=torch.bfloat16, trust_remote_code=True).eval()

# 加载lora权重
model = PeftModel.from_pretrained(model, model_id=lora_path)

执行结果:
在这里插入图片描述

十三、模型推理

最后,我们将使用微调后的模型进行推理,验证微调效果,并根据实际表现进一步优化模型。

prompt = "你是谁?"
inputs = tokenizer.apply_chat_template([{"role": "user", "content": "假设你是皇帝身边的女人--甄嬛。"},{"role": "user", "content": prompt}],
                                       add_generation_prompt=True,
                                       tokenize=True,
                                       return_tensors="pt",
                                       return_dict=True
                                       ).to('cuda')


gen_kwargs = {"max_length": 2500, "do_sample": True, "top_k": 1}
with torch.no_grad():
    outputs = model.generate(**inputs, **gen_kwargs)
    outputs = outputs[:, inputs['input_ids'].shape[1]:]
    print(tokenizer.decode(outputs[0], skip_special_tokens=True))

输出:

我是甄嬛,家父是大理寺少卿甄远道。

测试截图如下:
在这里插入图片描述

结语

经过本文的实战演练,我们不仅精湛掌握了GLM-4-9B-Chat模型的Lora微调技术,还深入理解了微调过程中的每一个关键步骤。我们期望大家能够将本文的知识应用到自己的项目中,以不断提升模型的性能。随着技术的不断进步,我们期待与大家共同探索更多高效、创新的模型微调方法,以推动人工智能技术的进一步发展。

在这里插入图片描述

🎯🔖更多专栏系列文章:AI大模型提示工程完全指南AI大模型探索之路(零基础入门)AI大模型预训练微调进阶AI大模型开源精选实践AI大模型RAG应用探索实践🔥🔥🔥 其他专栏可以查看博客主页📑

😎 作者介绍:我是寻道AI小兵,资深程序老猿,从业10年+、互联网系统架构师,目前专注于AIGC的探索。
📖 技术交流:欢迎关注【小兵的AI视界】公众号或扫描下方👇二维码,加入技术交流群,开启编程探索之旅。
💘精心准备📚500本编程经典书籍、💎AI专业教程,以及高效AI工具。等你加入,与我们一同成长,共铸辉煌未来。
如果文章内容对您有所触动,别忘了点赞、⭐关注,收藏!加入我,让我们携手同行AI的探索之旅,一起开启智能时代的大门!

  • 27
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
`glm4-9b-1m` 和 `glm4-9b-chat` 都是由 CSDN 开发的 AI 模型,它们都是基于大语言模型构建的工具,旨在提供智能问答、代码生成等服务。然而,它们之间存在一些关键的区别: ### `glm4-9b-1m` - **目的定位**:`glm4-9b-1m` 通常指代一个较为通用的语言模型,其设计目标可能是处理多种任务,包括但不限于文本理解、自然语言生成、翻译等多个领域。 ### `glm4-9b-chat` - **特定功能**:`glm4-9b-chat` 更专注于聊天交互场景。这个名称暗示了它特别优化为了提供流畅的人机对话体验,能够更好地理解上下文、保持对话连贯,并能快速响应用户的提问或指令。 ### 区别 1. **应用场景**:`glm4-9b-1m` 可能更适用于需要广泛能力支持的任务,如多模态理解和生成、文本到文本转换等多种应用;而 `glm4-9b-chat` 则专门针对实时交互需求,尤其适合于需要快速响应和高互动性的环境,比如客服机器人、即时通讯助手等。 2. **技术细节**:尽管具体的内部架构细节可能不对外公开,但可以合理推测,`glm4-9b-chat` 的训练数据集可能包含了大量的对话历史记录,以及更多关于对话管理的知识,这有助于提升模型在连续对话过程中的性能。此外,它可能还经过了特定的优化,使得在对话过程中上下文保持一致性和流畅性成为可能。 3. **性能侧重点**:考虑到 `glm4-9b-chat` 的命名,我们可以假设该模型在处理连续对话任务上有着更高的效率和质量保证。这可能意味着在对话的持续性、话题转移的平滑过渡等方面有更强的表现。 ### 相关问题: 1. 这两个模型在训练数据集的选择上有何差异? 2. 对于需要大量交互式对话的应用来说,如何评估并选择最适合的模型? 3. 如果希望开发一款虚拟助理软件,应该考虑哪些因素来决定采用 `glm4-9b-1m` 还是 `glm4-9b-chat`?
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值