
机器学习测试要覆盖训练和部署链路本文围绕“测试别只停在单元层”整理可复现的检查思路。所有阈值、配置和结果均应在隔离环境中记录输入、版本与资源条件后再解释下文示例不对应真实组织、用户、流量或成本数据。1. 用受控样例界定问题测试机器学习链路时分别固定构建依赖、训练输入和部署配置记录每层的验证结果。2. 依赖隔离与构建测试Pythonpyproject.toml锁定与动态 C 扩展编译构建测试的第一道防线是依赖锁定与二进制 ABI 校验。绝对不能使用允许宽松范围的requirements.txt如torch2.0而必须采用uv.lock或poetry.lock锁定绝对具体的 Hash 摘要与 Wheel 包。在 CI/CD 阶段构建测试脚本必须在全新的无污染容器中针对动态编译的 C / CUDA 扩展执行加载断言确保动态链接库依赖完整。机器学习工程的测试可分为单元、集成和端到端三层分别覆盖函数逻辑、组件协作与真实交付链路。3. 集成测试层特征数据 Feature Store 与 Preprocessing Pipeline 契约校验第二层防线聚焦于数据管道与特征层的集成契约测试。模型训练往往依赖在上游计算出的特征Feature Store。如果上游数据仓库的 SQL 逻辑微调将原本为float64的列变为了int32或者空值填充逻辑改变单靠 Python 单元测试无法检测。集成测试需要使用数据契约工具如 Pandera 或 Great Expectations在数据输入 Pipeline 环节设定严格的 Schema 约束import pandera as pa import pandas as pd # 定义特征管道的数据契约 Schema FeatureSchema pa.DataFrameSchema( columns{ sample_id: pa.Column(int, checkspa.Check.greater_than(0), nullableFalse), embedding_dim_0: pa.Column(float, checkspa.Check.in_range(-10.0, 10.0)), click_count_7d: pa.Column(int, checkspa.Check.greater_than_or_equal_to(0)), device_category: pa.Column(str, checkspa.Check.isin([mobile, desktop, pad])) }, strictTrue, # 严禁出现未定义的额外列 coerceTrue # 尝试安全强制类型转换 ) def test_feature_pipeline_integration(): 集成测试用例校验特征预处理输出是否完全符合数据契约 raw_input_df pd.DataFrame({ sample_id: [1, 2], embedding_dim_0: [0.45, -1.23], click_count_7d: [5, 0], device_category: [mobile, desktop] }) # 执行预处理管道 processed_df FeatureSchema.validate(raw_input_df) assert not processed_df.empty, 特征管道输出不能为空4. 端到端测试层数据漂移模拟与全链路 Checkpoint 恢复测算第三层防线是端到端 Checkpoint 中断恢复与确定性断言。在长达数周的长周期分布式训练中节点故障宕机是常态。如果不测试 Checkpoint 恢复逻辑极易在中断恢复后出现 Optimizer 内部状态丢弃如 Adam 的 $m$ 和 $v$ 一阶/二阶动量未保存导致恢复后的 Loss 曲线产生断层崩塌。下面的框架实现了训练中断模拟与端到端恢复测试import tempfile import torch import torch.nn as nn from pathlib import Path class TestE2ECheckpointRestoration: staticmethod def run_checkpoint_interruption_test(model_cls, dataloader): 端到端测试模拟在 Step 10 强制中断重新加载后再跑 Step 11 验证其输出 Loss 是否与连续跑 11 个 Step 绝对相等 with tempfile.TemporaryDirectory() as tmp_dir: ckpt_path Path(tmp_dir) / checkpoint_step10.pt # 轨迹 A连续运行 11 个 Step torch.manual_seed(42) model_a model_cls() opt_a torch.optim.Adam(model_a.parameters(), lr0.01) for step, batch in enumerate(dataloader): opt_a.zero_grad() loss model_a(batch).sum() loss.backward() opt_a.step() if step 9: # 模拟保存 Checkpoint torch.save({ model_state: model_a.state_dict(), optimizer_state: opt_a.state_dict(), step: step }, ckpt_path) if step 10: loss_a_step11 loss.item() break # 轨迹 B重新加载 Step 10 Checkpoint只跑 Step 11 torch.manual_seed(42) model_b model_cls() opt_b torch.optim.Adam(model_b.parameters(), lr0.01) checkpoint torch.load(ckpt_path) model_b.load_state_dict(checkpoint[model_state]) opt_b.load_state_dict(checkpoint[optimizer_state]) # 执行 Step 11 opt_b.zero_grad() batch_step11 list(dataloader)[10] loss_b_step11 model_b(batch_step11).sum() # 断言两者的 Loss 必须完全一致 abs_diff abs(loss_a_step11 - loss_b_step11.item()) assert abs_diff 1e-6, fCheckpoint 恢复端到端测试失败Loss 偏差: {abs_diff} print([E2E Test] Checkpoint 中断恢复测试完美通过)5. CI/CD 自动化流水线压测在 100 次并发构建中验证 0 坏死率可以将上述三层测试接入 CI 流水线并用固定种子、少量合成提交重复执行。节点数、运行次数和耗时应记录在项目自己的基准报告中不能从示例中外推。三层测试防线是否有效不能用未给出来源的频率来断言。可在固定依赖、固定数据工件的 CI 环境中重复执行记录失败类别、复现步骤和运行条件再比较引入前后的结果。测试层级覆盖防线与验证目标CI 单次耗时隐患拦截数 (100 次压测)结果记录由目标环境的重复对照实验填写别把机器学习工程的质量赌在简陋的单元测试上。从 Python 依赖与 C ABI 锁死构建到数据契约集成校验再到端到端恢复断言建立完备的分层测试防线才是实验可复现与工程稳定的物理保障。