近两年一直在做Text-to-SQL相关工作,明显感觉单靠中间层的“Prompt工程”来解决问题已经遇到瓶颈,很难再有进一步突破,于是开始尝试从底层数据和模型侧切入,寻找新的可能性。
现在市面上的大模型评测基准大多集中在自然科学、数学等通识领域,因此模型的能力也主要适配这些领域。如果要很好地应用在企业垂类场景,Prompt必不可少。但是Prompt本身存在两个限制:一个是长度限制,虽然RAG一定程度能缓解;另一个是,当你在Prompt里不断添加指令或示例来解决新的badcase时,很容易出现顾此失彼的情况,新问题解决了,老问题又复现(在《Prompt设计和迭代指南》这篇文章有分析原因)。 相比之下,微调模型能直接将领域内知识内化到模型参数中,对Prompt依赖自然就降低了。
刚开始研究的时候,网上搜到的大部分方案教程都是基于LoRA,优势在于小显存机器也能跑,但是第一次测试效果不理想,不禁产生疑问:到底是数据构建得不好?模型不够大?还是因为LoRA没有微调全部参数导致的?
第一个问题目前业内都没有很好的解决方案,第二又个受限于硬件成本,所以开始研究有没有可能低成本实现全参数微调。因此也就有了这篇文章,在这里分享给机核的朋友们。
from datasets import load_dataset
dataset = load_dataset("simplescaling/s1K_tokenized", split="train")
dataset.to_pandas().to_csv("./output_dataset.csv")
下载后的csv有很多列,我们只需要关注text列即可,参考该列的样式准备领域内数据集。
具体样式如下图,其中<im_start>和<im_end>是模型的特殊token,让模型知道什么时候开始什么时候结束。因为传统非推理模型只有system、user和assistant,所以注意这里的think和answer并没有<im_end>
这里多说一句,关于Prompt中要不要写system以及怎么写的问题,大家经常比较纠结。从这里的训练样本可以看出来,如果模型厂商自己在构建训练集时,system只是这么简单的一句,那么大家使用这些模型完全可以不需要写system。一般模型厂商也会给出相应参考建议。
最终我们构建出来的数据集只需要保留一列,表头为text,注意需要转成parquet格式。
准备好的数据集通过ssh上传到下一步申请的云服务器中,并且在第三步微调模型时,将sft.py文件中的`dataset = load_dataset(config.train_file_path)` 修改为 `dataset = load_dataset("parquet", data_files={"train": "/root/llm_project/s1k/s1-main/train/train-game-retention.parquet"})`,其中,第二个参数即云上数据集的实际路径。
付费类型选择:抢占式实例
地域选择非中国,比如:日本、韩国。因为抢占实例会存在被随时释放的风险,国外服务器释放机率非常小
实例:架构选择GPU,规格选择4 * NVIDIA A10,显存4*24GB
镜像:Ubuntu 24.04 64位
系统盘默认ESSD云盘,容量填2048G
带宽和安全组勾选上公网IP,计费模式按使用流量,带宽峰值可以设置50或100Mbps
登陆凭证选择自定义密码,登录名默认root
这个配置大概30元/h,最大可以训练7B大小的模型。
如果大家担心不一定能一次性搞定,可以先申请小一点的资源跑0.5B模型微调流程,比如:1*NVIDIA A10显存的机器、512GB系统盘,其他不变。
再次执行 nvidia-smi 可以看到CUDA Version
安装toolkit和配置环境变量:sudo apt install nvidia-cuda-toolkit
安装miniconda管理环境,注意,执行sh安装命令时候尽量保持当前目录是空文件夹状态。
安装后,创建test_torch.py代码文件,代码内容:
print(torch.__version__) # 应输出2.5.1
print(torch.cuda.is_available()) # 应返回True
print(torch.version.cuda) # 可能显示12.1(由PyTorch编译版本决定)
执行 python test_torch.py 如下图显示表示安装成功
pip install openai==1.56.1
pip install transformers==4.46.1
pip install wandb==0.17.3
pip install datasets==3.1.0
pip install accelerate==1.0.1
pip install vllm==0.6.4.post1
pip install ipykernel==6.28.0
pip install ipython==8.20.0
pip install gradio==4.44.0
pip install trl==0.12.0
pip install deepspeed==0.15.4
pip install huggingface-hub==0.29.3
注册wandb并执行 wandb login,记录project和entity,后续会更新在sft.py文件中。 首先,在/root目录下创建models文件夹,执行命令下载模型:huggingface-cli download --resume-download deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --local-dir /root/models/DeepSeek-R1-Distill-Qwen-7B
sft.sh文件修改:1)增加`export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True`, `export CUDA_LAUNCH_BLOCKING=1`, `export ACCELERATE_DISABLE_NO_SYNC=1 # 显式禁用no_sync`;2)修改base_mode路径;3)修改epochs参数;4)改为deepseepd,将梯度等参数计算放到CPU中。
{
"zero_optimization": {
"stage": 3,
"offload_optimizer": {
"device": "cpu",
"pin_memory": true
},
"offload_param": {
"device": "cpu",
"pin_memory": true
},
"overlap_comm": true,
"contiguous_gradients": true,
"sub_group_size": 1e9,
"reduce_bucket_size": "auto",
"stage3_prefetch_bucket_size": "auto",
"stage3_param_persistence_threshold": "auto",
"stage3_max_live_parameters": 1e9,
"stage3_max_reuse_distance": 1e9,
"stage3_gather_16bit_weights_on_model_save": true
},
"bf16": {
"enabled": true
},
"train_micro_batch_size_per_gpu": "auto",
"gradient_accumulation_steps": "auto"
}
至此,数据、环境、基础模型和训练脚本都已经准备完成,在train文件夹同级目录下执行 sh train/sft.py 等待训练完成,预计4小时,可以在终端wandb的链接观察loss曲线。
另外,也可以另启一个ssh链接终端,执行 watch -n 1 nvidia-smi 观察显存使用率。
微调后的模型会存储在/root/models文件夹中,可以下载到本地机器,也可以本地机器直连测试。下载到本地测试可能答案生成比较慢,这里介绍后一种方式。
FROM /root/models/s1-20250325_193807/
You are Qwen, created by Alibaba Cloud. You are a helpful assistant.
注意,这里的/root/models/s1-20250325_193807 为微调后的模型路径。
终端执行:OLLAMA_LLM_LIBRARY=cuda ollama create r1-distill-qwen-7b-game-retention -f ./Modelfile
成功后,执行ollma list 显示成功(r1-distill-qwen-7b-game-retention为模型名称,可以自行修改)
配置ollama服务的环境变量,执行 vim /etc/systemd/system/ollama.service
Description=Ollama Service
After=network-online.target
ExecStart=/usr/local/bin/ollama serve
Environment="PATH=/root/miniconda3/envs/llm/bin:/root/miniconda3/condabin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
Environment="CUDA_VISIBLE_DEVICES=0,1,2,3"
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_ORIGINS=*"
systemctl daemon-reload
systemctl restart ollama
这里的端口是11434,所以需要在阿里云上放开该端口,安全组增加规则:
在我们自己的电脑上安装chatbox,并做如下配置,ip修改为阿里云服务器的公网ip 这样就可以在chatbox上非常方便地测试微调后的效果了。
镜像即云服务器当前的复制体,包括环境、模型、代码、数据。
创建镜像后,下次再次申请实例时,不再需要从头开始配置环境,直接从自定义镜像创建即可。
关于基础模型的选择,大家可能好奇为什么我选择了DeepSeek蒸馏版,而不是和参考项目一样直接使用Qwen的Instruct版。
因为核心应用是场景Text-to-SQL,经过测试发现:
像7B这类小尺寸模型的SQL能力本身不够好
think对于复杂逻辑处理非常重要
Instruct版本生成think效果不如蒸馏版
所以最终设计的方案是:基于蒸馏版微调后的7B模型先生成think,再结合4o或者V3的能力生成最终SQL。
另外,大家实操后可能会觉得全参数微调方案好像已经很成熟了(虽然超参调整需要一些经验,但也不是那么重要),为什么业内很少见到垂类场景真正落地?个人觉得核心瓶颈还是在于如何构建高质量数据集。最近我们在做一些探索,迭代了几个版本的pipeline,后续有靠谱结论第一时间分享给大家。
最近在玩空洞骑士,用一级骨钉硬刚吸虫之母,断断续续被蹂躏了3个小时。但最终过关的那一刻,对法术施放时机的预判、挥刀和回血机会的把握、小虫飞行轨迹的预判能力,都和刚开始截然不同。这其实与文章的全参数微调很像,可能初始参数中有很多为0,随着一步步迭代,这些参数逐渐被激活。当然也存在一些明显的差异:每次小骑士死亡对我来说都是惩罚,而战斗过程中成功回复血量都是奖励,但是这里的微调方案并没有涉及强化和奖励模块;另外流程上还做不到实时参数更新,这些都是后续值得进一步深入探索的地方。
评论区
共 1 条评论热门最新