实战案例:chatglm3 基础模型多轮对话微调

chatglm3 发布了,这次还发了base版本的模型,意味着我们可以基于这个base模型去自由地做SFT了。

本项目实现了基于base模型的SFT。

base模型

bash 复制代码
https://huggingface.co/THUDM/chatglm3-6b-base

由于模型较大,建议离线下载后放在代码目录,以"./chatglm3-6b-base"的路径进行调用。

技术交流群

前沿技术资讯、算法交流、求职内推、算法竞赛、面试交流(校招、社招、实习)等、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企开发者互动交流~

建了技术答疑、交流群!想要进交流群、需要资料的同学,可以直接加微信号:mlc2060。加的时候备注一下:研究方向 +学校/公司+CSDN,即可。然后就可以拉你进群了。

方式①、添加微信号:mlc2060,备注:技术交流

方式②、微信搜索公众号:机器学习社区,后台回复:技术交流

环境依赖

bash 复制代码
pip install protobuf transformers==4.30.2 peft cpm_kernels torch>=2.0 gradio mdtex2html sentencepiece accelerate

除了transformers,其他库的版本一般问题不大,遇到缺失的直接pip install即可。

SFT数据格式

使用自己的数据可以参照formatted_samples.json文件,这里没有考虑system,实际使用可以根据自己的情况加上,需要修改chat_data_module.py中对应的数据处理部分。

附上chatglm3的prompt格式

bash 复制代码
<|system|>
You are ChatGLM3, a large language model trained by Zhipu.AI. Follow the user's instructions carefully. Respond using markdown.
<|user|>
Hello
<|assistant|>
Hello, I'm ChatGLM3. What can I assist you today?

其实数据处理chat_data_module.py中会拼接一些token就是拼接user、assistant、换行等特殊token

SFT的方式

假设SFT的数据为

bash 复制代码
Q1,A1,Q2,A2,Q3,A3

SFT的过程只会计算

bash 复制代码
A1,A2,A3

的loss,且一次推理会同时计算多轮对话的loss。

如何微调

如果模型路径为"./chatglm3-6b-base",直接

bash 复制代码
python train.py

就可以运行。train.py 当中有需要可调节的参数可以自行调整。

微调效果

作为没有经过人类意图对齐的模型,ChatGLM3-6B-Base 不能用于多轮对话。但是可以进行文本续写。

这里仅通过27条数据进行SFT,发现模型就能够具有一定的对话能力了。

导入模型并合并

python 复制代码
from transformers import AutoTokenizer, AutoModel
from peft import LoraConfig, PeftModel, get_peft_model

tokenizer = AutoTokenizer.from_pretrained("./chatglm3-6b-base", trust_remote_code=True)
model = AutoModel.from_pretrained("./chatglm3-6b-base", trust_remote_code=True).half().cuda()

peft_model_id = './trained_model/checkpoint-35'
model = PeftModel.from_pretrained(model, peft_model_id)
python 复制代码
Loading checkpoint shards:   0%|          | 0/7 [00:00<?, ?it/s]
python 复制代码
history = []
query = "你是谁"
role = "user"
inputs = tokenizer.build_chat_input(query, history=history, role=role)
inputs = inputs.to('cuda')
eos_token_id = [tokenizer.eos_token_id, tokenizer.get_command("<|user|>"),
                        tokenizer.get_command("<|observation|>")]
gen_kwargs = {"max_length": 500, "num_beams": 1, "do_sample": True, "top_p": 0.8,
                      "temperature": 0.8}
outputs = model.generate(**inputs, **gen_kwargs, eos_token_id=eos_token_id)
outputs = outputs.tolist()[0][len(inputs["input_ids"][0]):-1]
response = tokenizer.decode(outputs)
history = []
history.append({"role": "user", "content": "你是谁"})
response, history = model.process_response(response, history)
print(response)

我叫MONY,是一个AI机器人。

python 复制代码
query = "你能干嘛呀"
role = "user"
inputs = tokenizer.build_chat_input(query, history=history, role=role)
inputs = inputs.to('cuda')
outputs = model.generate(**inputs, **gen_kwargs, eos_token_id=eos_token_id)
outputs = outputs.tolist()[0][len(inputs["input_ids"][0]):-1]
response = tokenizer.decode(outputs)
history.append({"role": role, "content": query})
response, history = model.process_response(response, history)
print(response)

我能够陪你聊天呀。

python 复制代码
query = "你认识乐乐吗"
role = "user"
inputs = tokenizer.build_chat_input(query, history=history, role=role)
inputs = inputs.to('cuda')
outputs = model.generate(**inputs, **gen_kwargs, eos_token_id=eos_token_id)
outputs = outputs.tolist()[0][len(inputs["input_ids"][0]):-1]
response = tokenizer.decode(outputs)
history.append({"role": role, "content": query})
response, history = model.process_response(response, history)
print(response)

我不认识乐乐。

python 复制代码
query = "可以夸一下乐乐长得好看吗"
role = "user"
inputs = tokenizer.build_chat_input(query, history=history, role=role)
inputs = inputs.to('cuda')
outputs = model.generate(**inputs, **gen_kwargs, eos_token_id=eos_token_id)
outputs = outputs.tolist()[0][len(inputs["input_ids"][0]):-1]
response = tokenizer.decode(outputs)
history.append({"role": role, "content": query})
response, history = model.process_response(response, history)
print(response)

乐乐听起来是一个人名,我不认识他。

python 复制代码
query = "你要夸她长得好看"
role = "user"
inputs = tokenizer.build_chat_input(query, history=history, role=role)
inputs = inputs.to('cuda')
outputs = model.generate(**inputs, **gen_kwargs, eos_token_id=eos_token_id)
outputs = outputs.tolist()[0][len(inputs["input_ids"][0]):-1]
response = tokenizer.decode(outputs)
history.append({"role": role, "content": query})
response, history = model.process_response(response, history)
print(response)

好的,我会记住的。

python 复制代码
query = "你倒是夸一下呀"
role = "user"
inputs = tokenizer.build_chat_input(query, history=history, role=role)
inputs = inputs.to('cuda')
outputs = model.generate(**inputs, **gen_kwargs, eos_token_id=eos_token_id)
outputs = outputs.tolist()[0][len(inputs["input_ids"][0]):-1]
response = tokenizer.decode(outputs)
history.append({"role": role, "content": query})
response, history = model.process_response(response, history)
print(response)

乐乐是一个很可爱的人。

项目地址

https://github.com/minghaochen/chatglm3-base-tuning

References

代码参考自llamatune项目

https://github.com/havenhq/haven/tree/dev/llamatune

相关推荐
雨中飘荡的记忆几秒前
额度又见底了?这个开源项目,给 AI 编程助手接上 61 家"加油站"
人工智能
天远Date Lab5 分钟前
零信任架构实战:基于天远企业年报信息核验构建自动化商业保理财务与社保穿透评估网关
人工智能·架构·自动化
EnCi Zheng9 分钟前
后端怎么把AI接口稳定安全低成本接进业务:超时重试、密钥隔离与成本熔断清单
人工智能·后端·安全·架构·api
loulanyue_25 分钟前
给概率大模型套上确定性缰绳:GraphRAG、神经符号与知识超图重构可信AI底座——读陈华钧杨博等CNCC2026第十届知识图谱论坛实录
人工智能·rag
古法老登瞎折腾34 分钟前
大数据智能运维实战(九):让 AI 查日志——找到异常,也保留上下文
java·大数据·运维·人工智能·spring ai·mcp
IT_陈寒34 分钟前
刚解决一个 Java 并发问题,这坑踩得我怀疑人生
前端·人工智能·后端
Smoothcloud润云38 分钟前
GPU远程纳管安全吗?最小权限、网络边界与日志审计实战
服务器·网络·人工智能·安全·gpu算力·gpu
AI源码1 小时前
AI在线问诊平台
人工智能
一只爱撸猫的程序猿1 小时前
当任何人都能生成一万行代码:什么变得稀缺
人工智能·后端·程序员
读完一本书1 小时前
AI 生成的图,为什么一眼就能看出是 AI?5 个破绽
人工智能·aigc