Files
WQ_GUI/docs/SMOKE_TEST_ROUTE_B_MVP.md

15 KiB
Raw Blame History

Smoke Test — 路线 B MVPPipelineContext + AutoML + 软取消 + GUI 缝合)

适用范围:路线 B 重构 4 部分pipeline 包 / AutoML 训练器 / WorkerThread 软取消 / GUI 一键全自动)落盘后的端到端点火试飞清单。 目标:用最小数据集1 个 BSQ + 1 个 CSV在 1020 分钟内验证全链路打通


0. 前置准备5 分钟)

0.1 装 Optuna

environment.yml 当前未列 optuna属于本次重构新增依赖。若不装Step 6 会自动降级到老 GridSearchCV仍能跑通但会触发 fallback 日志)。

call venv\Scripts\activate.bat
pip install "optuna>=3.6,<4.0"

写入 environment.yml 的 patch提交时改

  # 路线 B AutoML 防爆引擎(可选;未装时 Step 6 走老 GridSearchCV 降级路径)
  - optuna>=3.6

0.2 准备最小数据集

work_dir_smoke/
├── raw/
│   ├── sample.b              # 假彩色 BSQ任意小分辨率都行建议 50×50×6 波段)
│   ├── sample_mask.tif       # (可选)水域掩膜;不提供则 Step 1 自动生成 NDWI
│   └── sample.csv            # 含 36 个水质参数目标列Chl-a / TSS / SD / TN / TP / COD…+ 6 列波段反射率
└── (其他文件由流程自动生成)

CSV 模板示例feature_start_column 默认为第一列;目标列必须在特征列之前

Chl-a,TSS,SD,B1,B2,B3,B4,B5,B6
12.3,15.1,0.8,0.045,0.052,0.038,0.061,0.072,0.085
11.8,14.2,0.9,0.044,0.051,0.037,0.060,0.071,0.084
...  (≥ 200 行AutoML 智能子采样 N>5000 时才生效)

0.3 启动 venv

cd /d "D:\111\office\ZHLduijie\1.WQ\WQ_GUI"
call venv\Scripts\activate.bat
set PYTHONPATH=src;%PYTHONPATH%

1. CLI 烟雾最快路径3 分钟)— A 级:必跑

跳过 GUI直接验证 automl_trainer.py 自身可独立运行 + Optuna 子采样 + 降级路径:

python -m src.core.prediction.automl_trainer ^
    --csv work_dir_smoke/raw/sample.csv ^
    --feature-start 6 ^
    --n-trials 5 ^
    --timeout 60.0 ^
    --out work_dir_smoke/7_Supervised_Model_Training_AutoML

通过标准

  • 进程退出码 0
  • 控制台打印 AutoML: 目标列 X 共尝试 N 个 trial最佳 CV R²=…
  • <out>/<preprocess>/<target>_<preprocess>_<model>_AUTOML.joblib 存在
  • <out>/automl_summary.json 存在且 success=true

若 Optuna 未装,期待看到:

[AutoML] optuna 未安装,全目标列回退老 GridSearchCV

产物文件名带 _AUTOML 后缀的逻辑此时不会触发fallback 走老路径),属正常。


2. GUI 端到端 9 步核心场景1020 分钟)— S 级:必跑

2.1 启动 GUI

call venv\Scripts\activate.bat
set PYTHONPATH=src;%PYTHONPATH%
python -m src.gui.water_quality_gui

2.2 UI 配置

步骤 操作 期望
1/9 点"选择工作目录" → 选 work_dir_smoke/ 左侧步骤列表高亮UI 不报错
2/9 在 Step 1 面板选 sample.b掩膜留空(验证 NDWI 自动生成路径) 掩膜文本框保持空白
3/9 在 Step 4 面板选 sample.csv CSV 路径显示正确
4/9 关键其他步骤2/3/5/5.5/6/7/8/9保持默认不改任何参数 AutoML 默认开启use_automl=True
5/9 ▶ 运行完整流程(不要用老 run_full_pipeline 槽) 弹出二次确认窗,文案显示:
• 掩膜:未指定(将自动生成 NDWI 水域掩膜)
• 去耀斑:开启
• AutoML开启Optuna 子采样寻优)
6/9 点"是(Y)" "运行"按钮变灰,"停止"按钮亮起;进度条归零

2.3 观察日志(重点 4 大检查点)

检查点 1ctx 路径传递

启动后第一秒应看到类似:

[Runner] ctx 已构造14 路径字段4 目录字段
[Runner] 步骤 1/14step1_generate_water_maskrequires=['raw_img_path', 'water_mask_path']
[Runner] 步骤 2/14step2_find_glint_arearequires=['raw_img_path', 'water_mask_path', 'output_dir']
...
[Runner] ctx 路径校准water_mask_path = ...\work_dir_smoke\2_Glint_Area_Mask\glint_mask.tif

若没有 [Runner] 日志,说明 v1 旧路径被走到了,inspect.signature duck-type 没探测到 v2,回去检查 worker_thread.py:run()

检查点 2Step 1 NDWI 自动生成

[Step1] 未指定 mask_path自动基于 NDWI 生成水域掩膜
[Step1] NDWI 阈值=0.4,写入 1_Water_Mask/water_mask.tif

→ 验证 <work_dir>/1_Water_Mask/water_mask.tif 文件存在且非空。

检查点 3AutoML 启用

[Step6] AutoML 启用 Optuna 子采样寻优timeout=300s, n_trials=20, max_samples=5000
[Step6] 目标列 'Chl-a' 共 3 个候选模型,最佳 R²=0.812model=RandomForest
[Step6] 目标列 'TSS'   共 3 个候选模型,最佳 R²=0.745model=XGBoost
[Step6] 训练完成,产物写入 7_Supervised_Model_Training_AutoML/
[Step6] automl_summary.json 写入完成

→ 验证产物:

  • 7_Supervised_Model_Training_AutoML/<preprocess>/<target>_<preprocess>_<model>_AUTOML.joblib ≥ 1 个
  • 7_Supervised_Model_Training_AutoML/automl_summary.jsonautoml: true 字段
  • 老目录 7_Supervised_Model_Training/ 不应该被创建AutoML 路径独立)

检查点 4AutoML 降级(仅未装 Optuna 时)

[AutoML] optuna 未安装,全目标列回退老 GridSearchCV
[Step6] 降级路径:调用 WaterQualityModelingBatch.train_models_batch132 组 GridSearchCV

→ 跑通即可(仍能产生模型文件),但降级属于非优选路径。

2.4 9 步全程观察清单

期望产物(路径相对 work_dir 期望耗时50×50 测试数据)
1 1_Water_Mask/water_mask.tif < 5 s
2 2_Glint_Area_Mask/glint_mask.tif < 5 s
3 3_Remove_Glint_Image/deglint_image.tif < 5 s
4 4_Process_CSV/processed_data.csv < 2 s
5 5_Training_Sample/training_spectra.csv < 5 s
5.5 5_5_Calculate_Indices/indices.csv(如启用) < 2 s
6 7_Supervised_Model_Training_AutoML/新路径! < 5 minOptuna 5 trial
6.5 6_5_Non_Empirical_Modeling/(如启用) 12 min
6.75 6_75_Custom_Regression/(如启用) 12 min
7 7_Sampling_Points/sampling_points.csv < 3 s
8 8_Prediction/predicted_values.csv < 5 s
8.5 8_5_Prediction_Non_Empirical/predicted.csv(如启用) < 5 s
8.75 8_75_Prediction_Custom/predicted.csv(如启用) < 5 s
9 9_Kriging_Distribution_Map/distribution_map.tif 530 s纯 Python 慢)

2.5 流程结束

  • 进度条到 100%
  • "运行"按钮恢复可点
  • "停止"按钮变灰
  • 日志末行出现 === 流程执行完成 ====== 流程被取消 ===(取决于是否点过停止)
  • 控制台 on_pipeline_finished 触发UI 状态被统一恢复

3. 软取消测试3 分钟)— A 级:必跑

验证 threading.Event 软取消链路(不再用 terminate())。

3.1 启动完整流程

如 2.2 启动流程。

3.2 中途点"停止"

时机:在 Step 6 AutoML 跑 trials 的中途(看到 [Step6] 目标列 'Chl-a' 共 N 个候选模型 之后任意时刻)点"停止"。

期望看到

[STOP] 用户请求软取消
[Step6] 检测到 cancel_event本 trial 完成后退出
[Step6] AutoML 在 trial #X 中止,已完成 5/20 trial
[Runner] 软取消:跳过剩余 8 个 step
=== 流程被取消 ===

UI 状态:

  • "运行"按钮重新亮起
  • "停止"按钮变灰
  • 进度条保留在中断时的百分比(归零)
  • on_pipeline_finished 触发(用 success=False, cancelled=True 区分)
  • Python 进程不退出GUI 仍可继续点"运行"开新流程)

反例(不应该发生)

  • QThread: Destroyed while thread is still running 警告
  • Python 解释器直接崩溃
  • UI 永远卡死(run_all_btn 一直是灰的)

3.3 旧 stop() 路径回归

为防老代码忘了改,临时把 water_quality_gui.py:stop_pipeline 改回 self.worker.stop(),跑一次完整流程,看是否出现:

[DEPRECATED] WorkerThread.stop() 已弃用,请改用 soft_stop()。

这是预期行为(弃用方法保留但打 warning流程仍能完成即视为通过。


4. 失败 / 降级场景5 分钟)— B 级:选跑

4.1 未填掩膜 + NDWI 阈值设极端值

把 NDWI 阈值设到 0.9几乎无水域Step 1 应给出 warning 但不崩:

[Step1] NDWI 阈值=0.9,水域覆盖率 < 1%,请检查影像

4.2 CSV 完全无目标列

准备一个没有目标列的 CSV(全特征列),点运行:

[AutoML] 训练 CSV 不存在或无目标列:未识别出目标列
[Step6] AutoML 全部失败,所有目标列返回 success=False

→ UI 不会崩,会在 automl_summary.jsonerror: "未识别出目标列"

4.3 Step 1 路径不存在

Step 1 选了一个不存在的 .bsq 文件

[Runner] step1_generate_water_mask 异常FileNotFoundError
[STOP] 流程中止在 step 1

→ UI 弹错误窗 + 把左侧步骤列表 setCurrentRow(0) 自动定位到 Step 1_focus_step 起效)。

4.4 Optuna 版本冲突

装一个 optuna==2.10API 大改),跑 GUI

[AutoML] optuna API 不兼容(>=3.6 要求):<error>
[AutoML] 全目标列回退老 GridSearchCV

→ 降级路径生效即视为通过。


5. 验证矩阵 Checklist

复制以下到 PR 描述 / 验收单:

## 路线 B MVP 验证矩阵

### 代码落盘
- [ ] src/core/pipeline/__init__.py17 行4 export
- [ ] src/core/pipeline/context.pyPipelineContext dataclass
- [ ] src/core/pipeline/runner.pyStepSpec + PIPELINE_STEPS + PipelineRunner
- [ ] src/core/prediction/__init__.py追加 train_with_automl export
- [ ] src/core/prediction/automl_trainer.pyAutoMLResult + train_with_automl + CLI
- [ ] src/core/steps/modeling_step.pyuse_automl 分支 + _train_models_automl
- [ ] src/core/water_quality_inversion_pipeline_GUI.pyrun_full_pipeline_v2 + LEGACY_ATTR_MAP + _sync_legacy_attrs_from_context
- [ ] src/gui/core/worker_thread.pycancel_event + soft_stop + run() duck-type
- [ ] src/gui/water_quality_gui.pyon_run_all_clicked + _collect_minimal_config + 按钮重连)

### CLI 自测
- [ ] A.1 `python -m src.core.prediction.automl_trainer --csv ...` 退出码 0
- [ ] A.2 产物 .joblib 含 `_AUTOML` 后缀
- [ ] A.3 automl_summary.json 含 success=true

### GUI 端到端
- [ ] B.1 启动无 ImportError
- [ ] B.2 二次确认窗文案含 mask 提示 + AutoML 状态
- [ ] B.3 日志含 [Runner] 前缀v2 路径生效)
- [ ] B.4 Step 1 NDWI 自动生成路径生效
- [ ] B.5 9 步产物路径全部存在
- [ ] B.6 流程结束后 UI 状态恢复(运行按钮亮、停止按钮灰)

### 软取消
- [ ] C.1 流程中途点停止cancel_event 触发
- [ ] C.2 流程被取消而非崩溃
- [ ] C.3 UI 状态由 on_pipeline_finished 统一恢复
- [ ] C.4 旧 stop() 调用打 [DEPRECATED] warning

### 降级
- [ ] D.1 Optuna 未装 → 全目标列回退老 GridSearchCV
- [ ] D.2 无目标列 CSV → 写 error 到 summary不崩 UI
- [ ] D.3 不存在文件 → _focus_step 定位到对应 step

6. 已知未做(不在本次范围)

  • Kriging 多进程并行(当前 backend="loop" 纯 Python
  • Step 5 radius==0 内存优化(整波段读入)
  • 进度条 sub-step 粒度(当前只到 step 级)
  • Step 8 全图预测(当前只对采样点预测)
  • 全项目搜替换老 self.worker.stop() 调用(仅本会话改了 water_quality_gui.py 的 stop_pipeline
  • requirements.txt 同步 Optunaenvironment.yml 写)
  • 单元测试套件(tests/ 目录为空;建议用 pytest 覆盖 train_with_automl / PipelineRunner

7. 出问题找哪里

现象 看哪里
[Runner] 日志没出来 worker_thread.py:run()inspect.signature 探测
[AutoML] 完全没打 modeling_step.py:170if use_automl 是否进了
AutoML 报 optuna API 不兼容 automl_trainer.py:236try import
软取消无反应 worker_thread.py:run() 末尾的 cancel_event.is_set()
二次确认窗没出来 water_quality_gui.py:on_run_all_clicked line ~2848
9 步产物路径错位 pipeline/runner.py:PIPELINE_STEPSoutput 字段
老 v1 路径被走到 _sync_legacy_attrs_from_context 没调,或 v2 异常

作者注:本清单对应路线 B 一键全自动重构 4 部分全部落盘的验收场景,编号与 todo 8 同步。 跑通 §1 + §2 + §3 三段即视为 MVP 验收通过§4 用于鲁棒性抽查。