- 人工智能
- 大模型
- 微调
- LoRA
- 模型量化
- 本地部署
- 模型推理服务
【免费下载链接】Qwen
The official repo of Qwen (通义千问) chat & pretrained large language model proposed by Alibaba Cloud.
导读
本文以 recipes/tests/README.md 为骨架,系统讲解 Qwen 开源仓库中 recipes 层单元测试的三种标准运行方式(全量、按目录、重跑失败用例),并深入测试源码,剖析微调(DeepSpeed ZeRO 矩阵)与推理(OpenAI API、vLLM + FastChat)两大测试模块的实现细节、公共基础设施与已知边界条件。读完本文,你将掌握这套基于 pytest + Docker 的测试体系的完整脉络,能够独立运行、定位并扩展 Qwen 的回归测试。
一、测试体系概览:recipes/tests 的目录设计与定位
Qwen 仓库的recipes/目录承载了面向应用场景的配方式指南,而recipes/tests/则是支撑这些配方的回归测试集。其目录结构如下:
- recipes/tests/init.py:空文件,标记测试包。
- recipes/tests/ut_config.py:公共配置(模型标识、Docker 镜像版本、容器挂载路径等)。
- recipes/tests/utils.py:通用工具函数(子进程命令执行、OpenAI API 探活、端口检测)。
- recipes/tests/assets/test_sampled_qwen.json:微调测试所用的最小样本数据集。
- recipes/tests/test_finetune/test_finetune_ds.py:微调链路测试(全参数 / LoRA / QLoRA,覆盖 DeepSpeed ZeRO-2/3)。
- recipes/tests/test_inference/test_inference_api.py:基于
openai_api.py的推理服务测试。 - recipes/tests/test_inference/test_inference_vllm_fschat.py:基于 vLLM + FastChat 的推理服务测试。
从测试源码看,这套测试的设计意图是「在 Docker 容器内端到端验证真实链路」:微调测试在容器中通过torchrun拉起finetune.py训练 1 个 epoch,推理测试则在容器中启动模型服务并通过 OpenAI 兼容接口真实发请求验证。因此,运行测试的前提是准备好 GPU 环境与对应版本的 Qwen 官方 Docker 镜像(见下文公共配置)。
二、快速上手:三种标准 pytest 运行方式
原文档给出了三种运行方式,均在recipes/tests目录下执行(即先cd recipes/tests):
1. 运行全部单元测试
cd tests && pytest -s-s关闭 pytest 的输出捕获(即--capture=no),让print语句直接打印到终端。这在上述测试中非常必要——测试源码里大量使用print(例如 test_inference_api.py 打印待执行的 Docker 命令、simple_openai_api打印模型回复、等待服务启动时打印进度),-s能让你实时观察容器启动、模型下载与服务探活的完整过程。
2. 运行指定子目录下的测试
cd tests && pytest -s {dir}{dir}是recipes/tests下的子目录,例如:
cd tests && pytest -s test_finetune # 只跑微调测试 cd tests && pytest -s test_inference # 只跑推理测试pytest 会自动发现test_*.py文件并收集其中的test_*函数。这一模式适合按功能模块定向回归,例如只改了finetune.py时,无需跑完整的推理测试。
3. 重跑上次失败的用例
cd tests && pytest -s --lf--lf(--last-failed)是 pytest 内置的缓存机制:每次运行后,pytest 会把结果缓存在.pytest_cache中,--lf只重新执行上次失败的用例,适合在修复问题或环境就绪后快速验证。可结合--lf与{dir}进一步缩小重跑范围。
需要说明的是,原文档中的cd tests隐含「当前目录为recipes/」这一前提(测试文件通过sys.path.append(os.path.dirname(__file__) + "/..")向上导入同层的utils.py与ut_config.py,也印证了测试必须以其自身目录为工作根)。若从仓库根目录执行,等效命令为:
cd recipes/tests && pytest -s三、公共基础设施:ut_config.py 与 utils.py
3.1 公共配置 ut_config.py
所有测试共享一套集中配置:
MODEL_TYPE = "Qwen/Qwen-1_8B":测试使用的默认模型,覆盖 Chat(对话微调)与 base(预训练底座)两种形态,QLoRA 场景额外使用-Int4量化版(由测试代码动态拼接,见 test_finetune_ds.py)。- 三个 Docker 镜像版本:
qwenllm/qwen:cu114、cu117、cu121,对应不同 CUDA 版本,测试矩阵会逐个遍历。 DOCKER_MOUNT_DIR = "/qwen-recipes":仓库挂载进容器后的根路径。DOCKER_TEST_DIR、DATA_DIR、DS_CONFIG_ZERO2_DIR、DS_CONFIG_ZERO3_DIR:分别指向容器内测试目录、样本数据与两份 DeepSpeed 配置。
从配置可以看出,测试采用「目录挂载」而非「镜像内置代码」的方式:宿主机上的 Qwen 仓库通过-v {仓库路径}:/qwen-recipes挂载进容器,因此代码改动无需重新构建镜像即可被测试覆盖。
3.2 通用工具 utils.py
三个函数支撑了整个测试体系的执行与验证:
run_in_subprocess(cmd):以shell=True启动子进程,实时读取 stdout/stderr 并写入日志;若返回码非零则抛出包含错误输出的RuntimeError,保证测试失败时能拿到完整诊断信息。这是所有 Docker 命令的统一执行入口。simple_openai_api(model):通过openai库(openai.api_base = "http://localhost:8000/v1"、api_key="none")向本地模型服务发起一次非流式ChatCompletion.create请求(消息内容为「你好」),并打印模型回复,用于验证推理服务端到端可用。代码注释提示可在此添加自定义停止词,例如 ReAct 提示词所需的stop=["Observation:"]。TelnetPort(server_ip, port):用带 1 秒超时的 TCP socket 探测指定端口是否可连接,作为「模型服务是否就绪」的探活手段,供测试在启动容器后轮询等待。
四、微调测试深入:test_finetune_ds.py 的测试矩阵
test_finetune_ds.py 是微调链路的回归测试,其核心是借助pytest.mark.parametrize构造的笛卡尔积测试矩阵。
4.1 测试矩阵的构成
矩阵由五个维度组合而成(源码 第 23-44 行):
- GPU 数量:1 或 2(
torchrun --nproc_per_node)。 - 训练方式:
full(全参数)、lora、qlora。 - 模型形态:
chat/base,分别对应Qwen/Qwen-1_8B-Chat与Qwen/Qwen-1_8B。 - Docker 版本:cu114 / cu117 / cu121。
- DeepSpeed 配置:None、ZeRO-2、ZeRO-3。
源码注释明确记录了兼容性边界:ZeRO-3 与 base 模型上的 LoRA 不兼容;FSDP 或 ZeRO-3 与 QLoRA 不兼容。因此 ZeRO-3 分支只对full全量开放,lora仅允许chat形态;QLoRA 分支则只在 1/2 卡下组合 None 或 ZeRO-2 配置。这份矩阵本身就是「什么组合可以跑」的可执行文档。
4.2 测试执行的关键细节
每个用例执行以下步骤(源码 第 50-99 行):
- 构造容器命令:
docker run --gpus all --ipc=host --network=host --rm -v {仓库}:{DOCKER_MOUNT_DIR} {镜像} /bin/bash -c "..."。--network=host保证容器内torchrun的多卡通信与宿主机网络一致。 - 兼容性预处理:通过
torch.cuda.get_device_capability()检测 GPU 算力,若 SM < 80(即不支持 Ampere 之后架构特性),先pip uninstall -y flash-attn;若lora+ ZeRO-2 + base 组合,追加--fp16 True。 - 运行微调:容器内执行
torchrun拉起 finetune.py,关键训练参数包括--num_train_epochs 1、--per_device_train_batch_size 1、--gradient_accumulation_steps 2、--learning_rate 1e-5、--weight_decay 0.1、--adam_beta2 0.95、--warmup_ratio 0.01、--lr_scheduler_type "cosine"、--model_max_length 512、--save_strategy "steps"、--save_steps 1000、--save_total_limit 10,并根据train_type追加--use_lora/--q_lora、按需追加--deepspeed {配置路径}。 - 下载模型:
snapshot_download(model_type, cache_dir=".", revision="master")从 ModelScope 拉取对应模型(QLoRA 场景为-Int4版)。 - 验证产物:全参数训练断言
output_qwen/config.json存在,LoRA/QLoRA 断言output_qwen/adapter_config.json存在,随后shutil.rmtree清理输出,保证用例可重复执行。
这从源码层面印证了 finetune.py 中use_lora、q_lora、model_max_length等参数的真实语义,也与 finetune/deepspeed/ 下的配方文档形成闭环。
五、推理测试深入:OpenAI API 与 vLLM + FastChat 两条链路
推理测试的目标是「在容器内把模型服务真正跑起来,并发出真实请求验证返回」。
5.1 基于 openai_api.py 的服务测试
test_inference_api.py 按docker_version × use_int4参数化(共 6 组),每组执行:
- 启动容器:
docker run --gpus all --ipc=host --network=host --rm --name="test_inference_api" -p 8000:8000 -v {仓库}:{DOCKER_MOUNT_DIR} {镜像} /bin/bash -c "python {DOCKER_MOUNT_DIR}/openai_api.py -c {模型路径}",其中模型为Qwen-1_8B-Chat或-Int4版本;SM < 80 时同样先卸载 flash-attn。 - 后台启动(
nohup ... &)并将日志重定向到tmp.log。 - 用
TelnetPort("localhost", 8000)轮询等待服务就绪;期间若容器已退出(docker inspect失败)则提前终止。 - 调用 utils.py 中的
simple_openai_api发起真实对话请求(注意 Int4 场景下模型名按Qwen-1_8B-Chat传入),异常时读取tmp.log辅助定位。 - 用例结束强制
docker rm -f清理容器。
源码注释记录了两条重要的已知边界:CPU-only 模式会因 Half 精度算子(addmm_impl_cpu_)未实现而报错;Int4 量化使用 Exllama/ExllamaV2 后端时要求全部模块位于 GPU,否则需要disable_exllama=True。这解释了为何该测试的use_cpu参数全部为False——当前测试矩阵仅覆盖 GPU 推理路径。
5.2 基于 vLLM + FastChat 的服务测试
test_inference_vllm_fschat.py 按num_gpus × use_int4参数化(1 卡/2 卡 × 普通/Int4,其中 2 卡 + Int4 因量化权重与张量并行尺寸不匹配的已知问题被注释禁用),执行 FastChat 三进程标准架构:
python -m fastchat.serve.controller:控制面,探活端口为 21002;python -m fastchat.serve.openai_api_server --host localhost --port 8000:OpenAI 兼容网关;python -m fastchat.serve.vllm_worker --model-path {模型} --tensor-parallel-size {num_gpus} --trust-remote-code:vLLM worker,--tensor-parallel-size决定跨卡并行度。
当 SM < 80 或使用 Int4 时追加--dtype half(对应源码 第 40-42 行 的兼容分支)。探活与验证流程与 API 测试一致:先等 21002 端口就绪,再通过simple_openai_api完成一次真实对话,最后清理容器。vLLM 推理路径与 recipes/inference/vllm/ 下的部署配方可互相印证。
六、测试数据与 DeepSpeed 配置
6.1 样本数据 test_sampled_qwen.json
该文件是微调测试的训练数据,采用 Qwen 多轮对话格式——每条约含id与conversations(user/assistant交替),例如{"conversations": [{"from": "user", "value": "你好"}, {"from": "assistant", "value": "你好!很高兴为你提供帮助。"}], "id": "identity_0"}。这与 finetune.py 中SupervisedDataset/LazySupervisedDataset对raw_data["conversations"]的解析逻辑(见 finetune.py)完全对应:数据被preprocess加工为<|im_start|>user/assistant的 ChatML 模板,用户侧 token 以IGNORE_TOKEN_ID屏蔽、助手侧参与损失计算。
6.2 DeepSpeed 配置
两份配置即 finetune/ds_config_zero2.json 与 finetune/ds_config_zero3.json,也是微调配方文档 recipes/finetune/deepspeed/ 的依赖项:
- ZeRO-2:
zero_optimization.stage = 2,开启overlap_comm、contiguous_gradients、reduce_scatter,allgather_bucket_size与reduce_bucket_size均为 2e8;优化器为 AdamW,调度器为 WarmupLR,学习率、权重衰减、梯度累积步数等均以"auto"交给训练脚本统一管理。 - ZeRO-3:
zero_optimization.stage = 3,在 ZeRO-2 基础上增加offload_param(device: "none")、stage3_gather_16bit_weights_on_model_save: true(保存时聚合 16bit 权重),并配置sub_group_size、stage3_max_live_parameters等分片参数。
测试中正是通过--deepspeed参数把这两份配置注入 finetune.py 的,验证了「配置即测试输入」的设计。
七、运行测试的注意事项与调试建议
综合上述源码细节,运行这套测试需要注意:
- 环境前提:需要 NVIDIA GPU 与 Docker(测试命令含
--gpus all),并预先准备好qwenllm/qwen:cu114/cu117/cu121镜像;测试会从 ModelScope 下载Qwen/Qwen-1_8B系列模型,需要网络可达。 - 目录前提:在
recipes/tests目录下执行 pytest;子目录运行、失败重跑均保持同样的工作目录。 - 算力兼容:SM < 80 的 GPU 上,测试会自动卸载 flash-attn 并追加
--fp16 True;推理测试在 SM < 80 或 Int4 场景追加--dtype half。 - 已知禁用组合:ZeRO-3 + base 上的 LoRA、ZeRO-3/FSDP + QLoRA、2 卡 + Int4 的 vLLM 张量并行,均在源码中以注释形式记录了不兼容原因。
- 失败排查:推理测试把容器日志写入
tmp.log,服务未就绪或请求异常时会读出日志内容拼入异常信息;微调测试的错误信息同样由run_in_subprocess汇总抛出,定位问题应先看这些输出,再用pytest -s --lf重跑失败用例。 - 只读仓库提示:本仓库为只读,运行测试不会修改仓库文件;微调测试的
output_qwen产物会在用例内自动清理。
八、总结
Qwen 的 recipes 单元测试体系以 recipes/tests/README.md 的三种 pytest 命令为入口,背后是一套「Docker 容器 + 真实链路 + 参数化矩阵」的回归方案:公共配置集中在 ut_config.py,通用执行与验证逻辑沉淀在 utils.py,微调与推理两大模块分别由 test_finetune_ds.py 和 test_inference 目录承载。理解这套体系,既能快速跑通 Qwen 的回归测试,也能为扩展新的微调/推理场景测试提供可直接复用的范式。
- 人工智能
- 大模型
- 微调
- LoRA
- 模型量化
- 本地部署
- 模型推理服务
【免费下载链接】Qwen
The official repo of Qwen (通义千问) chat & pretrained large language model proposed by Alibaba Cloud.
相关推荐
RepRapFirmware S曲线运动规划:实现平滑加减速的高级算法
RepRapFirmware S曲线运动规划:实现平滑加减速的高级算法 RepRapFirmware是一款开源的3D打印机固件,其核心功能之一是S曲线运动规划算
嵌入式固件智能硬件物联网NetAlertX API 单元测试实战指南:在 Docker 容器中运行 pytest 测试套件
NetAlertX API 单元测试实战指南:在 Docker 容器中运行 pytest 测试套件 导读 本文是 NetAlertX 官方文档 docs/API
后端网络运维数据可视化ParlAI 测试实战指南:从 pytest 运行到 TorchGeneratorAgent 单元测试编写
ParlAI 测试实战指南:从 pytest 运行到 TorchGeneratorAgent 单元测试编写 ParlAI 是面向开放对话数据集训练与评估 AI
NLP人工智能深度学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考