- [2026/04] Added vLLM OpenAI-compatible serving, SSE streaming client, and minimal serving benchmark with TTFT / latency / decode tokens/s reports.
- [2026/04] Added CPT benchmark, profiling, communication, optimization, and resume validation tracks for Native DDP and DeepSpeed.
- [2026/04] Added SFT LoRA dataset processing, training, merge, and minimal GSM8K / MMLU-mini evaluation pipeline.
- [2026/04] Split training entrypoints into sanity, benchmark, profile, optimize, resume, and longtrain families.
TwinForge 是一个面向单机双卡 RTX 3090 的轻量级大模型训练与推理实验平台,目标是围绕 Qwen3-1.7B、DeepSpeed、PEFT 和 vLLM,把数据准备、CPT、SFT、评测、部署、profiling 逐步做成可复现、可比较、可扩展的完整闭环。
项目状态:
Work in Progress当前仓库已经完成 CPT 基线、benchmark / profiling / optimization / resume validation 的主脚手架,并补齐了最小
SFT / LoRA -> merge -> eval -> vLLM serving -> serving benchmark代码链路;当前仍待完成的是这条链路的端到端实跑验证,而不是继续扩张长训或 TP/PP。
TwinForge 不是一个追求“大而全”的训练框架,而是一个围绕双卡工作站的实验平台。它强调三件事:
- 可复现:数据、配置、训练入口、日志、报告尽量落成明确文件。
- 可比较:把
single_gpu、ddp、zero、后续tp与不同推理后端放到统一协议下比较。 - 可扩展:在主链路跑通后,继续接入 DeepSpeed 的 profiling、monitoring、communication logging、inference、AutoTP 等能力。
当前已经完成或验证的部分:
- 环境基线检查与独立
.venv运行环境 - 基于 manifest 的原始数据下载入口
- CPT 清洗、抽样、packing、tokenize 主链路
-
Qwen3-1.7BCPT 训练入口 -
scripts/train/sanity与scripts/train/bench/{native,deepspeed}两层训练入口 -
smoke / single_gpu / ddp / zero2 / zero3_offloadCPT sanity 启动脚本 -
single_gpu与ddp两档训练实际跑通 - CUDA 显存 callback,支持按 step 记录
allocated / reserved / max_allocated -
train_summary.json,记录 tokens/s、checkpoint 保存耗时/大小、resume 状态 - CPT benchmark 切片脚本、slice spec、索引清单与 benchmark 汇总脚本
- 实施计划、操作日志、错误日志
-
zero2 / zero3_offload正式 benchmark、profiling、communication、optimization 主线 - 短程
resume validation轨道与报告 - SFT cleaned/tokenized 数据链路、LoRA 训练入口与 merge 脚本
- 最小评测链路:
GSM8K + MMLU_mini -
vLLM服务入口、OpenAI-compatible 客户端与最小服务压测脚本 - profiling / communication / monitor 主线脚手架接入
-
resume -> SFT -> merge -> eval -> vLLM端到端实跑验证 - DeepSpeed Inference / HF eager 服务基线补齐
当前已经验证过的 CPT 结果:
single_gpu:完成200steps,训练日志与显存日志已落盘ddp:完成300steps,主进程最终保存逻辑已验证
这些结果目前只代表 sanity 级验证,不代表性能结论。正式性能对比会在受控 benchmark 配置下完成。
当前 benchmark 已拆为 Native Family 与 DeepSpeed Family 两组,不再输出单表式 single/ddp/zero 严格可比结论。
- 轻量:默认目标就是单机双卡
3090,不把多节点超大规模能力作为第一优先级。 - 透明:核心能力优先落成可读脚本和配置,而不是藏在复杂框架抽象里。
- 可追踪:每次实施动作和异常都要求写入日志,方便复盘和继续推进。
- 可演进:当前主线是数据链路和 CPT,后续再逐步接入 SFT、评测、推理、压测和 profiling。
当前仓库把 DeepSpeed 能力分成三层:
- ZeRO-1 / ZeRO-2 / ZeRO-3 Offload 训练对比
- DeepSpeed Inference
- Automatic Tensor Parallelism inference
- Flops Profiler
- PyTorch Profiler
- Monitoring
- Communication Logging
- AutoTP training
- Pipeline parallelism
- Ulysses / ALST sequence parallelism
- Universal checkpointing
- Autotuning
- ZeRO++
- 多节点分布式能力
- MoE 等超出当前
Qwen3-1.7B主线的教程能力
详细能力矩阵、优先级和阶段拆分见 Implementation Plan。
当前已经不是占位的主要模块:
scripts/00_check_env.pyscripts/01_download_data.pyscripts/02_build_cpt_corpus.pyscripts/04_tokenize_cpt.pyscripts/04_build_cpt_benchmark_slice.pyscripts/12_report_cpt_benchmark.pyscripts/03_build_sft_dataset.pyscripts/05_tokenize_sft.pyscripts/08_merge_lora.pyscripts/09_eval_all.shscripts/11_benchmark_serving.pysrc/data/cleaners.pysrc/data/samplers.pysrc/data/packers.pysrc/data/sft.pysrc/train/train_cpt.pysrc/train/train_sft.pysrc/train/callbacks.pysrc/eval/*src/serve/*configs/model/qwen3_1_7b_base.yamlconfigs/data/cpt_benchmark_slice.yamlconfigs/train/sft_lora.yamlconfigs/train/sanity/*configs/train/bench/native/*configs/train/bench/deepspeed/*configs/train/ds/*scripts/train/sanity/*scripts/train/bench/native/*scripts/train/bench/deepspeed/*configs/train/profile/*configs/train/longtrain/*configs/train/resume/*scripts/train/profile/*scripts/train/longtrain/*scripts/train/resume/*scripts/13_report_cpt_profile.pyscripts/14_report_cpt_comms.pyscripts/16_report_cpt_resume_validation.pyscripts/06_train_cpt*.shscripts/07_train_sft_lora.shscripts/10_serve_vllm.sh
当前仍以占位或半成品为主的部分:
src/prof/*src/serve/deepspeed_generate.pyscripts/10_serve_deepspeed.sh
当前默认模型配置指向本地目录:
model_name_or_path: model/Qwen3-1.7B
tokenizer_name_or_path: model/Qwen3-1.7B也就是说:
- 基座模型权重不包含在仓库里
- 训练输出、数据产物、日志和本地模型目录都应视为本地产物
- 仓库本身提交的是源码、配置、脚本、报告和 Markdown 日志
- Linux
- CUDA 可用的 PyTorch 环境
- 建议双卡
RTX 3090 - 本地准备好
model/Qwen3-1.7B
推荐使用项目内虚拟环境:
python3 -m venv .venv
. .venv/bin/activate
pip install -U pip setuptools wheel
pip install "torch>=2.2" torchvision torchaudio
pip install "transformers>=4.37.0" "datasets>=2.18.0" "accelerate>=0.28.0" deepspeed peft trl
pip install sentencepiece safetensors scikit-learn numpy pandas pyarrow ujson jsonlines tqdm pyyaml tensorboard evaluate jieba nltkpython scripts/00_check_env.pypython scripts/01_download_data.py \
--manifest configs/dataset_manifest.json \
--output_root data/rawpython scripts/02_build_cpt_corpus.py \
--manifest configs/dataset_manifest.json \
--input_root data/raw/cpt \
--output_root data/cleaned/cptpython scripts/04_tokenize_cpt.py \
--manifest configs/dataset_manifest.json \
--model_config configs/model/qwen3_1_7b_base.yaml \
--input_root data/cleaned/cpt \
--output_path data/tokenized/cpt/trainpython scripts/04_build_cpt_benchmark_slice.py \
--slice_config configs/data/cpt_benchmark_slice.yaml \
--overwrite默认会同时写出:
data/tokenized/cpt/bench/data/tokenized/cpt/bench_summary.jsondata/tokenized/cpt/bench_indices.json
其中 bench_summary.json 会记录数据集 fingerprint、tokenizer 路径和 tokenizer 指纹,bench_indices.json 会保存实际使用的样本索引清单。
最小验证:
bash scripts/06_train_cpt_smoke.sh分层训练入口:
bash scripts/06_train_cpt_single_gpu.sh
bash scripts/06_train_cpt_ddp.sh
bash scripts/06_train_cpt_zero2.sh兼容入口:
bash scripts/06_train_cpt.sh默认等价于 zero2 档位。
新的分轨入口:
bash scripts/train/sanity/cpt_single.sh
bash scripts/train/sanity/cpt_ddp.sh
bash scripts/train/sanity/cpt_zero2.sh
bash scripts/train/sanity/cpt_zero3_offload.sh
bash scripts/train/bench/native/cpt_single.sh
bash scripts/train/bench/native/cpt_ddp.sh
bash scripts/train/bench/deepspeed/cpt_zero2.sh
bash scripts/train/bench/deepspeed/cpt_zero3_offload.sh生成 benchmark 汇总表:
python scripts/12_report_cpt_benchmark.py --output reports/cpt_benchmark.md说明:
Native Family只比较single与ddpDeepSpeed Family只比较zero2与zero3_offload- 报告中的
native_ddp_bridge_ref仅作跨 family 参考,不参与严格同协议结论
执行 profiling / communication 基线:
bash scripts/train/profile/run_all.sh或按单项串行执行:
bash scripts/train/profile/native/cpt_single.sh
bash scripts/train/profile/native/cpt_ddp.sh
bash scripts/train/profile/deepspeed/cpt_zero2.sh
bash scripts/train/profile/deepspeed/cpt_zero3_offload.sh生成 profiling 报告:
python scripts/13_report_cpt_profile.py --output reports/cpt_profile.md
python scripts/14_report_cpt_comms.py --output reports/cpt_comms.md执行第一版 Optimization Track sweep:
bash scripts/train/optimize/run_all.sh或按单项执行:
bash scripts/train/optimize/native/cpt_ddp_base.sh
bash scripts/train/optimize/native/cpt_ddp_workers4.sh
bash scripts/train/optimize/native/cpt_ddp_no_gc.sh
bash scripts/train/optimize/deepspeed/cpt_zero2_base.sh
bash scripts/train/optimize/deepspeed/cpt_zero2_workers4.sh
bash scripts/train/optimize/deepspeed/cpt_zero2_no_gc.sh生成优化报告:
python scripts/15_report_cpt_optimization.py --output reports/cpt_optimization.md说明:
- 当前第一版优化 sweep 只覆盖已经稳定接入的旋钮:
dataloader_num_workers与gradient_checkpointing - 这些优化 run 默认
save_model_artifacts: false,只保留train_summary.json、train_log_history.json和日志 max_seq_length与更激进的 batch-density sweep 暂未进入自动 sweep,因为当前 benchmark tokenized slice 固定在2048,需要单独准备新的 tokenized 视图后再做
基于当前 Optimization Track 的结论,仓库里保留了两条正式长训候选入口:
native ddp:workers=4,gradient_checkpointing=truezero2:workers=2,gradient_checkpointing=true
对应启动入口:
bash scripts/train/longtrain/native/cpt_ddp.sh
bash scripts/train/longtrain/deepspeed/cpt_zero2.sh说明:
- 两条长训入口默认都使用全量 tokenized 数据:
data/tokenized/cpt/train - 两条配置都恢复
save_model_artifacts: true,会保存 checkpoint 和最终模型 - 当前默认
max_steps=3000、save_steps=500,可通过脚本透传--resume_from_checkpoint ...继续训练 native ddp是吞吐优先候选;zero2是显存更稳的正式 DeepSpeed 候选- 当前阶段这两条入口默认不作为优先执行项;它们只是在链路闭环完成后的保留长训入口
在正式进入 SFT / eval / serving 前,建议先验证推荐配置的短程 resume 能力:
bash scripts/train/resume/native/cpt_ddp_validate.sh
bash scripts/train/resume/deepspeed/cpt_zero2_validate.sh或串行跑完两条:
bash scripts/train/resume/run_all.sh生成 resume 报告:
python scripts/16_report_cpt_resume_validation.py --output reports/cpt_resume_validation.md说明:
resume validation默认使用data/tokenized/cpt/bench- 两条验证都会执行
stage1 -> checkpoint-10 -> stage2 resume -> checkpoint-12 - 该阶段目标是验证 checkpoint 可恢复,不是验证长训收敛
python scripts/03_build_sft_dataset.py \
--manifest configs/dataset_manifest.json \
--input_root data/raw/sft \
--output_root data/cleaned/sft \
--overwrite默认会读取:
data/raw/sft/ultrachat_200k_mini.jsonldata/raw/sft/wildchat_mini.jsonl
并稳定输出:
data/cleaned/sft/train.jsonldata/cleaned/sft/val.jsonldata/cleaned/sft/summary.json
python scripts/05_tokenize_sft.py \
--manifest configs/dataset_manifest.json \
--model_config configs/model/qwen3_1_7b_base.yaml \
--input_root data/cleaned/sft \
--output_root data/tokenized/sft \
--overwrite说明:
- 默认使用
Qwen3-1.7Bchat template - 默认只训练 assistant 响应,system/user token 会被 mask 为
-100 - 默认启用 packing,
seq_length=2048
bash scripts/07_train_sft_lora.sh当前默认配置:
LoRA + DeepSpeed ZeRO-2r=64lora_alpha=128lora_dropout=0.05- 目标是先完成短程闭环,不是正式长训
python scripts/08_merge_lora.py \
--base_model model/Qwen3-1.7B \
--adapter_path runs/sft/qwen3_1_7b_miniv2_sft_lora \
--output_dir runs/sft/qwen3_1_7b_miniv2_sft_mergedbash scripts/09_eval_all.sh \
--model_path runs/sft/qwen3_1_7b_miniv2_sft_merged默认只跑:
gsm8kmmlu_mini
并最终聚合到:
runs/eval/summary.json
bash scripts/10_serve_vllm.sh runs/sft/qwen3_1_7b_miniv2_sft_merged默认配置读取:
configs/serve/vllm.yaml
python scripts/11_benchmark_serving.py \
--base_url http://127.0.0.1:8000 \
--model qwen3-1.7b-miniv2这里的 --model 传的是 vLLM 暴露出来的 OpenAI model id,默认来自 configs/serve/vllm.yaml 里的 served_model_name,不是本地模型目录路径。
当前最小服务报告会输出:
TTFTend-to-end latencyoutput tokensdecode tokens/s
建议按下面顺序推进,而不是直接跳到长训或部署:
- 用
scripts/00_check_env.py确认 Python / CUDA / PyTorch / DeepSpeed 基线。 - 下载原始数据并生成
cleaned、tokenizedCPT 数据。 - 用
configs/data/cpt_benchmark_slice.yaml生成固定的data/tokenized/cpt/bench数据切片,并保留bench_summary.json与bench_indices.json。 - 先跑
scripts/train/sanity/*完成后端验证。 - 先跑
scripts/train/bench/native/*完成 native family 对比,再跑scripts/train/bench/deepspeed/*完成 DeepSpeed family 对比,最后生成双章节reports/cpt_benchmark.md。 - 基于 benchmark 结果先跑
scripts/train/profile/*,生成reports/cpt_profile.md与reports/cpt_comms.md,完成吞吐/显存差异归因。 - 在 profile 结果基础上先跑
scripts/train/optimize/*,筛出native ddp与zero2各自的推荐训练配置,并生成reports/cpt_optimization.md。 - 在优化结果基础上,先跑
scripts/train/resume/*,验证推荐配置的 checkpoint / resume 能力。 - 用通过 resume 验证的推荐配置推进
scripts/03_build_sft_dataset.py -> scripts/05_tokenize_sft.py -> scripts/07_train_sft_lora.sh -> scripts/08_merge_lora.py。 - 对 merged SFT 模型执行
scripts/09_eval_all.sh,先拿到GSM8K + MMLU_mini的最小结果,再启动scripts/10_serve_vllm.sh与scripts/11_benchmark_serving.py。 - 只有当这条最小链路稳定闭合后,再考虑执行
scripts/train/longtrain/*,以及后续的 TP / PP / 更完整 serving family。
.
├── configs/ # 模型、训练、DeepSpeed、服务、数据配置
├── data/ # 本地数据产物目录,不随仓库提交
├── logs/ # 操作日志、错误日志、下载日志
├── model/ # 本地基座模型目录,不随仓库提交
├── reports/ # 实施计划、基线报告、训练与服务报告
├── runs/ # 本地训练、评测、压测输出,不随仓库提交
├── scripts/ # 可直接执行的入口脚本
└── src/ # 数据处理、训练、评测、服务、profiling 代码
核心目录说明:
configs/模型配置、训练超参数、DeepSpeed 配置、服务配置、数据 manifest。scripts/面向实验流程的 CLI 入口,适合串联整个链路。src/data/数据清洗、抽样、packing、chat template 相关逻辑。src/train/CPT / SFT 训练逻辑及训练辅助模块。src/eval/benchmark 评测与结果聚合。src/serve/推理调用、服务验证、客户端脚本。src/prof/profiling、communication、kernel benchmark 相关实验代码。
关键文档与记录入口:
- Implementation Plan
- Baseline Report
- Operation Log
- Error Log
- Training Log
- CPT Sanity Report
- CPT Benchmark
- CPT Profile
- CPT Comms
- CPT Optimization
- CPT Resume Validation
- Serving Benchmark
记录约定:
- 每次代码、配置、文档、实验操作后,更新
logs/operation_log.md - 每次失败、阻塞、异常后,更新
logs/error_log.md - 每次阶段目标变化后,回写
reports/implementation_plan.md
当前实施路线已经从“补骨架”切换为“能力分轨”:
Sanity TrackBenchmark TrackOptimization TrackServing TrackProfiling / Observability TrackAutoTP / Pipeline / Sequence Parallel POC Track
完整阶段说明、优先级和可行性矩阵见 Implementation Plan。
liwu/MNBVC这类旧式 dataset script 仓库不能再直接依赖datasets.load_dataset(...),当前已改为 Hugging Face 仓库原始文件直拉。- 当前
single_gpu与ddp结果已经验证链路,但还不是正式 benchmark 结论。 SFT / eval / serve的最小脚手架已完成,但当前仓库里还没有把resume -> SFT -> merge -> eval -> vLLM整条链路做一次正式端到端实跑验证。- 仓库当前主线仍是
Qwen3-1.7B的 CPT / DeepSpeed 实验,不覆盖更大规模分布式训练的全部场景。
欢迎提交 issue 或 PR,但建议遵守以下约定:
- 先说明目标、范围和影响模块。
- 不要把未验证流程标记为“已完成”。
- 涉及实验、命令、调参、报错处理时,同步更新日志文件。
- 保持配置、脚本、报告和 README 之间的一致性。