
简介面向希望在个人电脑上运行专属领域ChatGPT模型的开发者这里提供一套基于ChatGLM的继续训练与精调实现资源完整覆盖了从数据准备、模型训练到推理部署的代码流程。压缩包共28个文件大小仅124KB以Python脚本为主12个py文件配合json数据与配置、xml工程结构、requirements依赖及README说明便于快速搭建本地微调项目。核心提供训练、评估、推理等环节的脚本以及示例数据集与数据自制工具同时包含分词处理、数据转换等模块配合模型参数配置、DeepSpeed训练配置和API演示样例可让使用者在PC上尝试轻量LoRA微调并快速搭建Web演示接口。项目结构清晰数据生成、处理、训练、评估到推理部署均有对应模块便于二次开发与参数调试。目前已有1581人学习适合具备一定Python基础、希望将通用大模型定制到垂直领域的机器学习开发者和研究者参考。 这个标题一眼看过去就很有画面感。chagpt这个拼写懂的都懂大概率是ChatGPT的笔误但项目本身一点不马虎用开源的ChatGLM做继续训练和精调最终产出一个能装进zip、在普通PC上跑起来的领域对话模型。这类“私有化小模型”的需求最近特别多不管你是想给公司做个内部知识库问答机器人还是想把手头积累的行业语料变成对话模型这套流程都值得认真走一遍。这篇就按我从头到尾实操下来的经验把继续训练、指令精调、PC端推理部署这几大步拆开讲透包括那些文档里不会写、只有踩过坑才知道的细节。1. 项目整体设计与思路拆解1.1 为什么选ChatGLM而不是其他开源模型ChatGLM系列在中文场景下的性价比确实高。相比同等参数规模的Llama系模型ChatGLM的中文词表更大分词器对中文的切分更友好训练和推理时的token消耗也更少。做领域微调时这个优势会被放大同样的文本量ChatGLM需要计算的token数更少训练速度和显存占用都更可观。另一个原因是ChatGLM的基座版本选择灵活。从6B到更小的1.5B、3B版本都有不同显存条件下的PC都能找到合适切入点。实测下来6B模型跑SFT微调消费级显卡16GB显存勉强能玩但如果只想做推理部署量化后8GB显存的卡也能流畅跑。这种“宽进严出”的特性让它特别适合PC端玩私有化模型。1.2 “继续训练”和“精调”分别解决什么问题很多初学者容易把这两个概念混成一锅粥。简单说继续训练也叫增量预训练是让模型“涨知识”精调SFT指令微调是让模型“懂规矩”。继续训练用的是纯文本语料格式就是大段大段的领域文章、对话记录、技术文档目标是让模型把领域内的术语、事实、表述习惯学进去。但只做这步模型并不会变成好用的对话助手——它只是“肚子里有货”输出仍然可能是发散式的不知道怎么按指令回答。精调用的是“指令-回答”配对数据显式教会模型“用户问什么你就怎么答”。做完精调模型才真正从一个文本续写器变成对话助手。项目标题里“继续训练和精调”两个都写了说明作者很清楚完整的流程必须两步都走缺一个效果都会打折扣。我个人建议的顺序也是先增量预训练再指令微调。反过来做的话模型容易在后续继续训练中把学过的指令格式冲淡。1.3 为什么强调“可以在PC上运行”“PC上运行”这四个字是整条技术路线的核心约束。这意味着你不能默认有A100或者多卡集群必须把显存占用、内存占用、推理速度全部纳入设计考量。实际操作中我会围绕三个指标做取舍模型参数量、量化精度、上下文长度。参数量决定底座选6B还是3B量化精度决定推理时用FP16还是INT8/INT4上下文长度决定最多能吃进多少字的输入。这三者此消彼长比如选了6BFP16可用上下文就短选了3BINT4能留出更多显存给长文本。项目既然要求PC可跑通常我会推荐ChatGLM3-6B做Q4量化部署或者直接用ChatGLM3-1.5B这种小模型做轻量级方案。2. 环境准备与数据工程2.1 硬件与训练环境搭建思路先摸清自己的硬件底子。训练阶段和推理阶段的显存需求差别非常大推理只要装下模型权重加一小块KV Cache训练则要额外装下优化器状态、梯度、激活值。以6B模型为例FP16推理大概需要12GB显存但同样的模型做LoRA微调16GB显存能勉强跑全量微调基本得24GB起步。这块有一个很实用的估算方法全量训练显存约等于模型参数量乘以20单位为字节LoRA微调可以压到参数量乘以6到8。也就是说6B模型全量训练大概要120GB显存LoRA只需要40GB左右实际加上激活值后16GB显存也能跑小batch。软件环境方面首选Linux或WSL2。Windows裸跑PyTorch不是不行但很多底层库的兼容性问题会消耗大量精力。训练框架我用的是transformers peft datasets 这套组合这几样都是Hugging Face生态的标准件配合度很高。CUDA版本建议直接上11.8或12.xPyTorch选对应预编译版本省去自行编译的痛苦。注意显存不够时优先降低batch size而不是调小模型。梯度累积gradient accumulation可以在不减少有效batch的前提下把单次显存峰值压下来这是我最常用来“挤”显存的手段。2.2 领域语料怎么收集和清洗继续训练的数据质量直接决定模型“懂不懂行”。收集语料时建议优先找这三类来源一是行业文档与操作手册二是客服对话记录/工单数据三是专业社区的问答帖。数量上个人项目10万到50万条文本就够了不必追求百万级——PC端训练的吞吐量有限数据太多反而跑不动。清洗是比收集更关键的一环。我踩过最典型的坑是语料里残留大量HTML标签和Markdown语法符号模型确实能学会输出这些乱码。清洗流程我一般做四步去重用MinHash或简单的MD5加上文本相似度判断、去噪删掉导航栏、版权声明、超链接等非正文内容、统一编码全部转成UTF-8、格式规范化把多个换行压成两个去掉零宽字符。清洗完还要做一次抽样检查肉眼扫一批数据确认清洗效果脏数据混进去一万条后面就得花十倍的时间去调模型。2.3 指令数据的构建与格式设计精调的效果好坏指令数据的质量权重超过一半。常见做法是做成JSON数组每项包含instruction指令、input可选输入、output期望输出。这个格式对应的是ChatGLM的官方微调格式用transformers的DataCollator处理起来很方便。数据规模上指令微调和继续训练不一样通常几千到几万条高质量数据就能见效。数量不足时宁可用规则模板批量生成也别随便从网上抓乱七八糟的数据凑数。我自己常用的一个技巧是先写20条种子样本涵盖最常见的提问类型然后设计一个模板把行业语料里的知识点填充进去自动扩展成几百条“背景信息指令回答”的样本。这样既能保证规模又能控制质量。3. 核心实操继续训练与精调的完整流程3.1 继续训练阶段的关键参数与实现增量预训练我用的是transformers的Trainer模型加载后把prepare_model_for_kbit_training打开配合peft的LoRA配置。LoRA的秩r我习惯设在8到16之间alpha通常设成r的两倍。这个配置在大多数场景下都能平衡“学得进”和“不忘本”。先看数据集处理的核心代码from transformers import AutoTokenizer, AutoModelForCausalLM from datasets import load_dataset tokenizer AutoTokenizer.from_pretrained(chatglm3-6b, trust_remote_codeTrue) dataset load_dataset(json, data_filesdomain_corpus.jsonl) def tokenize_function(examples): # 统一在文本末尾加EOS保证序列边界清晰 texts [t tokenizer.eos_token for t in examples[text]] return tokenizer(texts, max_length2048, truncationTrue, paddingFalse) tokenized_dataset dataset.map(tokenize_function, batchedTrue)这块有个容易忽略的点ChatGLM类的模型加载时通常需要trust_remote_codeTrue因为它的模型结构用了自定义代码不信任远程代码的话根本加载不了。我第一次跑的时候漏了这个参数报错报得莫名其妙。训练参数里学习率我常用5e-5warmup_ratio设0.1训练轮数视语料量而定一般2到3轮即可。轮数并不是越多越好增量训练做太狠会破坏原有通用能力这在领域模型里叫“灾难性遗忘”。判断标准很简单训练后用通用问题测一测如果连“编一个冷笑话”都答不上来说明训过头了。3.2 指令精调阶段的训练流程精调的代码骨架和继续训练类似区别在数据和模型加载方式。数据端是instruction、input、output三字段结构模型端需要用peft的LoraConfig配置target_modules。ChatGLM-6B的target_modules通常设置为query_key_value这一个模块这是它和LlaMA系一般用q_proj、v_proj最大的不同点。这个参数配错的话LoRA等于没生效训练完模型权重纹丝不动推理结果和底座模型一模一样。我当时排查了半天最后打印模型结构才发现的。一个规范的精调训练脚本核心片段如下from peft import LoraConfig, get_peft_model, TaskType lora_config LoraConfig( r8, lora_alpha16, lora_dropout0.05, target_modules[query_key_value], biasnone, task_typeTaskType.CAUSAL_LM, ) model AutoModelForCausalLM.from_pretrained( chatglm3-6b, load_in_4bitTrue, # 4bit量化加载大幅降低显存占用 trust_remote_codeTrue ) model prepare_model_for_kbit_training(model) model get_peft_model(model, lora_config)训练参数上精调的学习率可以比继续训练稍微大一点1e-4到2e-4都是合理区间。epoch我一般控制在2到3轮设大了模型会把指令数据的格式背得滚瓜烂熟但对没见过的新问题反而泛化变差。还有个容易忽视的细节精调阶段padding策略建议改成paddingmax_length保持batch内每个样本长度一致Trainer内部的损失计算才不会出偏差。3.3 合并LoRA权重与底座模型训练完成后LoRA权重是独立保存的。部署推理时有两种选择一是保留LoRA适配器加载底座模型后再挂载二是把LoRA权重合并回底座模型导出一个完整权重文件。我强烈建议最终部署时选择合并导出。原因有两个一是推理速度更快——省去每层额外计算LoRA分支的时间二是部署更省心——不需要在推理代码里额外管理peft配置。合并代码很简单from peft import PeftModel base_model AutoModelForCausalLM.from_pretrained(chatglm3-6b, trust_remote_codeTrue) model PeftModel.from_pretrained(base_model, ./lora_ckpt) merged_model model.merge_and_unload() merged_model.save_pretrained(./domain_chatglm_merged) tokenizer.save_pretrained(./domain_chatglm_merged)注意merge_and_unload()之后模型结构里不会残留任何LoRA痕迹此时再保存的就是一个完整的、可以直接加载的ChatGLM模型。这个文件大小和底座模型相当6B版本合并后大约是12GBFP16。如果想进一步压缩可以再走一步量化压到4GB左右。4. PC端推理部署与效果优化4.1 显存优化与量化方案选择训练完成后的模型要落到PC上跑量化是第一优先级。常见的量化选择是bitsandbytes的4bit/8bit加载还有GPTQ和GGUF两种更彻底的离线量化方案。实测下来如果要追求最好的PC兼容性和部署便利性我推荐GGUF格式配合llama.cpp或ollama这个推理运行时完全不依赖PyTorch环境纯C实现对老显卡和纯CPU机器都友好。转换路径也不复杂先用transformers导出ONNX或直接用transformers权重的ChatGLM模型配合llama.cpp的转换脚本生成GGUF文件然后丢给ollama一键跑起来。要是还想保留transformers生态做更多定制bitsandbytes的8bit加载是最省事的选择。但要注意部分量化方案和某些显卡的兼容性有坑实测中出现过4bit推理在个别显卡上速度反而变慢的情况。我的建议是项目初期先用8bit兜底确认效果后再考虑上GGUF追求极致性能。4.2 流式输出与并发处理PC上跑模型用户体验的关键就在响应速度。ChatGLM本身支持流式输出streaming通过model.stream_chat()接口逐token返回结果。用FastAPI包装一下前端就能做到“边说边显示”的效果体感上比等完整回答再一次性吐出好太多。并发方面PC的算力有限我的经验是把并发数限制在1到2多余请求排队处理。盲目调大并发只会导致显存OOM或者所有请求一起龟速。实践中我还会把输入长度限制在1024 token以内输出长度控制在512 token以内这样单次请求的显存峰值和响应延迟都能保持稳定。注意部署时一定要用torch.inference_mode()或torch.no_grad()包裹推理过程关闭梯度计算。这不仅省显存还能明显提升推理速度。新手经常忽略这行代码直接把训练时的写法套到推理上GPU跑得又慢又烫。实测可以提升1.5-2倍的速度。4.3 效果评估的“三件套”测试法模型训完不能只看loss降没降必须做效果测试。我习惯从三个维度交叉验证领域问题测试、通用能力测试、敏感边界测试。领域问题测试用训练数据里没有出现过的、但属于该领域的问题来问检查模型是否真的学到了知识而不是把训练语料背下来了。通用能力测试用“写一首诗”“解释一下什么是机器学习”这类问题确认模型没丢掉基础能力。边界测试则用一些对抗性问题确保模型在方向不偏的情况下不出现离谱输出。这三个维度各有侧重分别对应“学得会”“忘不掉”“不失控”。具体实施时我通常从测试数据里手动挑15到20个问题按上面三类各分配5到7个每轮训练完固定跑一遍。不需要自动化评估脚本人工看结果反而更快更准。这比只盯着筛选loss曲线靠谱得多。5. 常见问题与排查技巧实录5.1 显存不足与训练崩溃的排查训练中报“CUDA out of memory”是最常见的事故。常规手段是从这几个方向依次调batch size减半、梯度累积补回来输入最大长度缩短2048降到1024优化器换成8bit AdamW开gradient_checkpointing以时间换空间。如果以上都试过还是爆显存就要重新评估方案了换更小的底座模型6B换3B甚至1.5B或者把数据切得更碎。还有一个小众但有效的技巧用torch.cuda.empty_cache()在每轮评估前清一次缓存碎片有时能多挤出几百MB。虽然治标不治本但对小显存用户很实用。5.2 Loss不下降或下降过慢增量预训练时loss不降通常是数据质量和格式问题。先Check一下语料是不是大量重复——重复数据会让模型快速过拟合loss假性下降后就不再动了。另一个原因是学习率太低特别是用了warmup后前几百步几乎看不到loss波动这时候别急着中断多跑一段看趋势。如果数据没问题就要看学习率是否匹配LoRA的秩。r设大时比如16lr可以相应调高一些r小时比如4lr要调低防止震荡。我常用的组合是r8、lr5e-5比较稳。5.3 精调后模型输出空洞/答非所问这类问题的元凶多半是指令数据格式不一致。ChatGLM的精调数据里instruction和input的含义有别instruction是“做什么”input是“做这件事的素材”。很多新手把整段上下文都塞进instruction模型学习时指令信号混乱推理时自然抓不准重点。另一个常见原因是指令数据的回答描述太长指令太短。模型学到的是“不管用户问什么我都回一大段话”而不是“根据问题精准回答”。建议指令保持1到2句话输出控制在合理长度让模型明确学到“简洁回答”的映射关系。精调完如果发现模型说话风格变啰嗦也可以试试在推理参数里调高temperature并在system prompt里强调“用最简洁的中文回答”。5.4 部署后首token等待过长PC端跑大模型首token延迟是个硬伤。原因在于用户输入的prompt需要完整过一遍模型才能开始生成第一个token。优化手段有三招一是限制用户输入长度过长的历史记录做截断二是打开KV Cache复用多轮对话时只对新增内容计算三是换用支持前缀缓存的推理框架减少重复计算。综合用下来多轮对话场景的响应速度能明显提升。提示如果你用的是llama.cpp/ollama路线的GGUF方案新版本自带prompt caching基本上开箱即用。而如果自己用transformers写推理服务多轮对话时需要手动维护历史token的KV Cache处理不好会出现“聊得越多越慢”的尴尬情况。写在最后的实操建议如果你正处于起步阶段我个人的建议是不要一上来就追求把6B模型在PC上全量微调和部署完。先从ChatGLM3-1.5B或更小的模型开始用几百条数据和LoRA跑通整条链路然后再逐步放大到6B和更复杂的场景。小模型试错成本低一次训练几分钟就能出结果你可以快速验证数据格式、参数设置、部署流程等全流程跑顺了再上大模型效率反而更高。另外项目里那些“zip打包交付”的习惯也别丢把训练代码、数据处理脚本、部署说明、量化好的模型都整理进一个包后续不管自己在别的机器上复用还是分享给别人都能省一大堆折腾时间。祝你在自己的领域模型上早日跑出满意效果。本文还有配套的精品资源点击获取