ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

RTX 5090单卡训练2B模型:Puro-2B低成本复现指南

2026/8/31 20:26:32 拓冰建站 浏览量
RTX 5090单卡训练2B模型:Puro-2B低成本复现指南 Puro-2B 这个项目一句话就能说清楚它来自一个预算很紧的“穷人实验室”目标是在一张 RTX 5090 显卡上、用 5090 美元左右的总投入完成 Qwen2-1.5B 基础模型的继续训练最终得到一个参数规模在 2B 量级的模型。这个项目最值得关注的点不是效果能打平几十 B 的大模型而是把“训练一个可用小模型”的硬件门槛压到了消费级单卡范围。这篇文章我会先拆解项目标题透露的关键信息再给出一套可以落地的复现路线从 RTX 5090 本地训练环境准备、Qwen2-1.5B 权重下载、LoRA / 全参微调脚本到推理接口部署和批量任务调用。如果你手里有 32GB 显存级别的显卡也关心 50 系显卡上 PyTorch / CUDA 适配怎么处理可以直接照着下文走一遍。先说清楚Puro-2B 目前公开可查的信息主要集中在项目命名本身具体权重和训练代码如果作者后续没有放出来我们这篇文章的重点就是“复现一条同路线”。拿到作者仓库后把模型路径和训练脚本替换掉就能跑同一个思路。1. Puro-2B 核心能力速览从项目标题可以稳定提取出这几个关键参数项目说明项目名称Puro-2B基础模型Qwen2-1.5B最终模型规模2B 级别训练硬件NVIDIA RTX 509032GB GDDR7 显存项目预算约 5090 美元项目类型低成本本地训练实验 / 微型实验室开源项目训练目标在单张消费级显卡上完成小参数模型的继续训练适用读者想自己训练私有模型的个人开发者、高校实验室、中小团队推理服务拿到权重后可用 vLLM / transformers 自建 OpenAI 兼容接口批量任务支持通过 JSONL 批量调用或脚本循环完成商用边界需遵守 Qwen2 开源协议训练数据必须有合法授权这里有几个点值得展开一下基础模型选 Qwen2-1.5B说明作者更关注“小模型 通用对话能力”的组合。Qwen2 系列在中文和英文任务上的平衡做得不错1.5B 参数量对单卡训练非常友好。RTX 5090 是 Blackwell 架构的旗舰消费卡32GB 显存给了单卡训练 1.5B 级模型足够的空间。全参微调不是没可能LoRA / QLoRA 更稳妥。5090 美元这个数字把显卡、整机、存储、电费等成本压缩到了一个“个人攒机”的预算范围。这本身就是这个项目最大的价值信号。从这张表可以看出Puro-2B 不是一个典型的高性能大模型项目而是一次“平民化训练”实验。它真正想做的是证明小实验室不用租云端集群也能把一个 2B 级模型从底座训练到可用状态。2. Puro-2B 的定位与适用边界2.1 这个项目适合谁如果你属于下面几类人Puro-2B 这条路线值得花半天时间跑一遍需要私有化模型的团队。数据不能出内网只能本地训练和推理2B 级模型部署成本低单卡就能扛。准备入门大模型训练的学生或研究者。用 RTX 5090 单卡跑通一遍训练流程比看十篇论文理解更深。做垂直领域应用的个人开发者。想在客服问答、文档摘要、代码补全等特定场景里做一个“够用”的模型而不是追求通用能力。2.2 这个项目不适合什么场景如果目标是通用助手级别的智能水平Puro-2B 这种 2B 模型没办法和几十 B、上百 B 的模型比。它在知识密度、复杂推理、长文本稳定性上都会明显受限于参数量。更适合做垂直任务、专用场景的模型不适合直接当全能聊天机器人给一群用户用。2.3 使用边界和合规提醒训练、推理和二次开源时必须注意几个底线Qwen2 系列模型有自己的开源协议。如果你基于 Qwen2-1.5B 继续训练发布微调模型时一般需要继续遵守原协议。训练语料必须来源合法。不要爬取未授权的对话数据、他人隐私信息或受版权保护的书籍文章。如果模型会处理用户输入需要考虑数据脱敏和隐私保护。不要用这个能力去做欺骗、伪造、批量骚扰等行为。这块不是套话是本地模型最容易踩的坑。很多同学训练的时候不在意语料来源后面如果要商用授权问题会直接卡住项目。3. 训练复现的环境准备3.1 硬件配置Puro-2B 项目的核心训练硬件是 RTX 5090。要跑通 Qwen2-1.5B 的 LoRA 微调32GB 显存空间非常充裕即使你手里是 24GB 显存的 RTX 4090做同样的实验也没有问题。建议的硬件基线部件最低配置推荐配置GPURTX 4090 24GBRTX 5090 32GBCPU8 核以上16 核以上内存32GB64GB硬盘50GB 可用空间200GB SSD 以上系统Ubuntu 22.04 / 24.04Ubuntu 24.04 或 Windows WSL2Qwen2-1.5B 模型文件、训练数据集、中间 checkpoint 和最终权重加起来早期预留 50GB 左右比较舒服。3.2 系统与驱动检查RTX 50 系列发布后驱动、CUDA、PyTorch 三者的版本适配成了最常见的问题。如果你在 50 系显卡上训练先做一次环境自检nvidia-smi这一步可以确认驱动是否正常识别显卡。然后查看驱动对应的 CUDA 版本再根据 PyTorch 官方安装页选择匹配的组合。更稳妥的做法是确认nvidia-smi能显示 RTX 5090再去 PyTorch 官网选择对应 CUDA 版本的安装命令。很多“训练时报错找不到 GPU”的情况不是显卡坏了而是 PyTorch 没有编译对应 Blackwell 架构的 kernel。3.3 Python 环境与依赖库建议用 conda 建一个独立环境避免污染系统 Pythonconda create -n puro2b python3.10 -y conda activate puro2b然后安装基础依赖pip install torch transformers datasets peft trl bitsandbytes accelerate国内网络环境下可以用镜像源pip install torch transformers datasets peft trl bitsandbytes accelerate -i https://mirrors.aliyun.com/pypi/simple/依赖库版本不用刻意锁死但要注意PyTorch 必须选择支持 Blackwell 架构的新版本bitsandbytes 也要升级到兼容版本。旧版本容易在加载模型时报CUDA error: no kernel image is available。安装完成后执行下面这段代码确认 GPU 可用python -c import torch; print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))输出为True和NVIDIA GeForce RTX 5090才说明环境正常。4. 模型与微调数据准备4.1 下载 Qwen2-1.5B 权重国内用户直接从 Hugging Face 下载可能比较慢可以用 ModelScopefrom modelscope import snapshot_download snapshot_download( Qwen/Qwen2-1.5B, local_dir./Qwen2-1.5B )也可以直接用transformers在运行时加载远程权重但训练场景建议先下载到本地目录避免训练过程中断网导致失败。4.2 构造微调数据集对话类微调比较常见的数据格式是 ShareGPT 风格或 Alpaca 风格。这里用一个简单的 JSONL 格式示例{conversations: [{role: user, content: 什么是RTX 5090}, {role: assistant, content: RTX 5090是NVIDIA基于Blackwell架构的旗舰消费级显卡配备32GB GDDR7显存。}]} {conversations: [{role: user, content: 写一个Python快速排序函数}, {role: assistant, content: def quick_sort(arr):\n if len(arr) 1:\n return arr\n pivot arr[len(arr) // 2]\n left [x for x in arr if x pivot]\n mid [x for x in arr if x pivot]\n right [x for x in arr if x pivot]\n return quick_sort(left) mid quick_sort(right)}]}训练时通过datasets.load_dataset(json, data_filestrain.jsonl)加载。如果数据量不大比如只有几千条建议用 LoRA 而不是全参微调效果稳定显存压力也小。4.3 数据质量检查训练前把数据里的空行、格式错误 JSON 行、超长对话清理掉。一个简单检查脚本import json valid_count 0 with open(train.jsonl, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue try: item json.loads(line) if conversations in item and len(item[conversations]) 2: valid_count 1 except json.JSONDecodeError: print(bad line:, line[:100]) print(valid samples:, valid_count)这一步能省掉很多训练中途 loss 变成 NaN 的麻烦。5. 微调训练与显存规划5.1 全参微调还是 LoRA从 Puro-2B 项目名字里的 “Trained on RTX 5090” 来看作者做的不是简单推理而是真正在显卡上跑了训练流程。但实际训练 1.5B 级模型有两种路线全参微调Qwen2-1.5B 的 bf16 权重约 3GB。梯度约 3GB。AdamW 优化器状态按 12 字节/参数估算约 18GB。再加上激活值。这个量在 32GB 显存的 RTX 5090 上可以跑但 batch size 和序列长度需要保守设置还要开gradient_checkpointing。LoRA 微调基础权重冻结显存占用大幅下降。优化器状态只更新新增的低秩适配器可能只需要 1GB 到 2GB。整体显存占用通常在 10GB 到 15GB 之间训练更稳定。如果数据量只有几千条LoRA 更实用。如果你想把整个底座知识都更新一遍再考虑全参微调。5.2 LoRA 训练示例代码下面是一份通用 LoRA 微调脚本按项目实际路径替换模型目录和数据集路径即可# finetune_lora_puro2b.py import torch from datasets import load_dataset from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, BitsAndBytesConfig, ) from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training from trl import SFTTrainer model_path ./Qwen2-1.5B dataset_path ./train.jsonl output_dir ./puro2b_lora_out bnb_config BitsAndBytesConfig( load_in_4bitTrue, bnb_4bit_compute_dtypetorch.bfloat16, bnb_4bit_use_double_quantTrue, bnb_4bit_quant_typenf4, ) model AutoModelForCausalLM.from_pretrained( model_path, quantization_configbnb_config, device_mapauto, trust_remote_codeTrue, ) tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) model prepare_model_for_kbit_training(model) lora_config LoraConfig( r16, lora_alpha32, lora_dropout0.05, biasnone, task_typeCAUSAL_LM, target_modules[q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj], ) model get_peft_model(model, lora_config) training_args TrainingArguments( output_diroutput_dir, per_device_train_batch_size2, gradient_accumulation_steps8, num_train_epochs3, learning_rate2e-4, bf16True, logging_steps10, save_steps200, save_total_limit3, report_tonone, optimpaged_adamw_8bit, gradient_checkpointingTrue, remove_unused_columnsFalse, ) trainer SFTTrainer( modelmodel, argstraining_args, train_datasetload_dataset(json, data_filesdataset_path, splittrain), tokenizertokenizer, max_seq_length2048, dataset_text_fieldconversations, ) trainer.train() trainer.save_model(output_dir) tokenizer.save_pretrained(output_dir)注意TRL 版本较新时SFTTrainer的dataset_text_field等参数可能调整遇到报错时以对应版本文档为准。这段代码是通用模板保证思路完整。5.3 训练参数对照参考设置项全参微调建议值LoRA 建议值权重精度bf164bit 量化 bf16 计算最大序列长度1024-20481024-2048Batch Size1-22-4梯度累积8-164-8优化器AdamWpaged_adamw_8bit学习率1e-52e-4训练轮数2-32-3梯度检查点开启开启混合精度bf16bf16这些配置不是固定标准但以 Qwen2-1.5B 和 RTX 5090 的组合来看是比较稳的起点。5.4 先小规模预跑正式训练前强烈建议先切出 100 条数据、训练 5 到 10 步确认环境没问题再全量训练。这样能避免跑了两小时后才发现数据集解析错误。python finetune_lora_puro2b.py训练过程中可以看到 loss 逐步下降。如果 loss 完全不动或者直接 NaN优先检查学习率、数据格式和混合精度设置。6. 推理验证与接口部署6.1 合并 LoRA 权重训练完的 LoRA adapter 需要合并回基础模型方便后续部署# merge_lora.py import torch from transformers import AutoModelForCausalLM, AutoTokenizer from peft import PeftModel base_model_path ./Qwen2-1.5B lora_path ./puro2b_lora_out merged_path ./puro2b_merged model AutoModelForCausalLM.from_pretrained( base_model_path, torch_dtypetorch.bfloat16, device_mapauto, ) model PeftModel.from_pretrained(model, lora_path) model model.merge_and_unload() model.save_pretrained(merged_path) tokenizer AutoTokenizer.from_pretrained(base_model_path) tokenizer.save_pretrained(merged_path)合并后puro2b_merged目录就是一个完整的模型目录可以直接加载。6.2 本地推理验证没有部署服务之前先用 transformers 做一次对话验证from transformers import AutoModelForCausalLM, AutoTokenizer model_path ./puro2b_merged tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained( model_path, torch_dtypetorch.bfloat16, device_mapauto, ) messages [ {role: user, content: 请用三句话介绍你自己} ] text tokenizer.apply_chat_template( messages, tokenizeFalse, add_generation_promptTrue, ) inputs tokenizer(text, return_tensorspt).to(model.device) outputs model.generate( **inputs, max_new_tokens256, do_sampleTrue, temperature0.7, top_p0.9, ) print(tokenizer.decode(outputs[0], skip_special_tokensTrue))这里重点看模型能不能按对话模板输出会不会重复、乱码或者生成长度异常。6.3 用 vLLM 部署 OpenAI 兼容接口如果需要把模型接到自己的工具或前端推荐用 vLLM 启动一个 OpenAI 兼容服务vllm serve ./puro2b_merged \ --dtype bfloat16 \ --gpu-memory-utilization 0.9 \ --max-model-len 4096 \ --served-model-name puro2b启动成功后会监听http://127.0.0.1:8000。这时可以用 curl 验证接口curl http://127.0.0.1:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: puro2b, messages: [ {role: user, content: RTX 5090有多少显存} ], max_tokens: 256, temperature: 0.7 }接口能用后面就可以接到自己写的业务脚本里。6.4 批量任务调用批量任务最简单的做法是准备一个 JSONL 文件用脚本循环调用接口import json import requests import time results [] with open(inputs.jsonl, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue item json.loads(line) resp requests.post( http://127.0.0.1:8000/v1/chat/completions, json{ model: puro2b, messages: [{role: user, content: item[prompt]}], max_tokens: 256, }, timeout120, ) if resp.status_code 200: answer resp.json()[choices][0][message][content] results.append({prompt: item[prompt], answer: answer}) else: results.append({prompt: item[prompt], error: resp.text}) with open(outputs.jsonl, w, encodingutf-8) as f: for r in results: f.write(json.dumps(r, ensure_asciiFalse) \n)批量任务容易遇到超时、进程卡死、单条 prompt 过长等问题。建议每条请求之间加time.sleep(0.2)并做失败重试。下面是一个增加重试的简单方式def chat_once(prompt, retry3): for attempt in range(retry): try: resp requests.post( http://127.0.0.1:8000/v1/chat/completions, json{ model: puro2b, messages: [{role: user, content: prompt}], max_tokens: 256, }, timeout120, ) if resp.status_code 200: return resp.json()[choices][0][message][content] except Exception: pass time.sleep(2 * (attempt 1)) return None7. 训练过程资源观察训练时怎么观察 RTX 5090 的显存和功耗是很多新手最关心的问题。推荐用nvidia-smi动态监控watch -n 1 nvidia-smi训练过程中重点看几个字段Memory-Usage显存占用。LoRA 微调 Qwen2-1.5B 通常在 10GB 到 16GB 区间具体取决于 batch size、序列长度和是否开启梯度检查点。Power功耗。训练时整卡功耗会明显升高RTX 5090 功耗较高要注意散热。Temperature温度。长时间训练建议控制在 80 度以内超过就要检查机箱风道。显存占用不是固定值。把per_device_train_batch_size从 2 调到 4或者把max_seq_length从 2048 调到 4096显存占用都会明显变化。遇到推理阶段显存不足时可以调低--max-model-len或者减小--gpu-memory-utilization。还有一个小经验训练跑完后建议确认没有残留的 Python 进程占着显存nvidia-smi ps aux | grep python如果服务已经退出但显存还没释放直接强杀对应进程即可。8. 常见问题与排查方法问题现象可能原因排查方式解决方案启动训练时报CUDA out of memorybatch size 过大、序列过长、显存碎片看报错发生在加载模型还是反向传播阶段调小 batch size、开启gradient_checkpointing、缩短max_seq_length显卡能识别但 PyTorch 报No kernel image驱动、CUDA、PyTorch 版本不匹配运行torch.cuda.is_available()检查ptxas版本升级 NVIDIA 驱动安装支持 Blackwell 架构的 PyTorch 版本bitsandbytes加载 4bit 模型失败库版本太旧查看导入报错pip install -U bitsandbytes训练 loss 不下降或震荡学习率太高、数据格式错误、优化器状态异常查看前几步 loss 日志降低学习率清理数据集空行重新训练vLLM 服务启动后接口超时max_model_len太小、并发请求过多、磁盘读取慢用 curl 测试单条请求调大max_model_len降低并发或用 SSD 存放模型接口返回乱码对话模板使用错误检查apply_chat_template输出按 Qwen 官方模板重新处理输入批量任务卡在一条数据上prompt 超过模型长度或接口异常给请求加超时和重试数据截断、批量脚本加timeout磁盘空间不足checkpoint 保存过多查看output_dir大小调低save_total_limit定期清理中间 checkpoint以上是这类单卡训练项目最常见的坑。RTX 50 系列刚出来那段时间驱动和 PyTorch 适配问题非常普遍遇到报错先别怀疑显卡坏了按顺序检查驱动、CUDA、PyTorch 三者的匹配关系。9. 低成本训练最佳实践9.1 先跑最小实验第一次训练不要直接丢几万条数据进去。切 100 到 500 条数据把训练步数控制在 10 步以内确认环境、数据、权重、推理链路全部通顺后再放量跑。这一步能节省大量排错时间。9.2 保存一份最小可运行配置把训练脚本、依赖清单和当前环境版本固定下来pip freeze requirements.txt下次换机器或隔一段时间再训练pip install -r requirements.txt就能恢复环境。9.3 模型目录管理建议目录结构puro2b/ ├── data/ │ ├── train.jsonl │ └── val.jsonl ├── models/ │ ├── Qwen2-1.5B/ │ ├── lora_checkpoint/ │ └── puro2b_merged/ ├── scripts/ │ ├── finetune_lora.py │ └── merge_lora.py └── outputs/ └── inference_results/模型文件、输入数据、训练脚本、输出结果分开放是避免后续混乱最有效的方式。9.4 训练任务要打日志训练日志默认输出到控制台但批量或长时间训练时建议落盘nohup python finetune_lora_puro2b.py train.log 21 查看训练进度tail -f train.log另外最好开启 checkpoint 保存并定期把 checkpoint 复制到另一块硬盘。训练中断后可以从最近保存点继续不用整个重来。9.5 接口服务要限制访问范围vLLM 默认监听127.0.0.1如果要在局域网提供推理服务要确认网络环境安全。不要把裸 API 直接暴露到公网。接入业务系统前在服务前面加一层鉴权或内网转发。9.6 训练数据授权自查涉及人脸、声音、他人作品、未公开文档时必须确认有没有合法授权。如果没有明确授权不要用于训练和分发。这个检查比调参更重要。10. 总结与下一步Puro-2B 这个项目最值得尝试的点是把训练成本压缩到一张消费级显卡能完成的范围。Qwen2-1.5B 底座 RTX 5090 单卡 LoRA 微调基本就是这套路线的标准组合。对大多数个人开发者和小团队来说这比租 GPU 集群更可控也比闭源 API 更私有化。拿到 Puro-2B 权重之后第一件该做的事是用自己的测试集跑一遍推理看看基础效果和原版 Qwen2-1.5B 差多少。如果作者公开了训练数据和超参数建议先复现训练再调整成自己的数据集。最容易踩的坑有两个一是 RTX 50 系列显卡的驱动和 PyTorch 版本适配二是训练数据格式错误导致 loss 异常。这两个问题解决掉后面基本就是按部就班地训练、合并、部署。后续可以扩展的方向也不少把 LoRA 换成全参微调、加入偏好学习提升回复质量、用 vLLM 批量跑一批领域评测集或者把模型接到一个简单的前端上做产品原型。单卡训练小模型这件事已经不像以前那么“高不可攀”了Puro-2B 给的就是一个很具体的例子。