From 3414f0207adde1116115c3fe32398c03dc604e39 Mon Sep 17 00:00:00 2001 From: duxin Date: Wed, 29 Jul 2026 10:58:26 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20DualStream=5FMNF=20=E6=8E=A8=E7=90=86?= =?UTF-8?q?=E9=87=8D=E5=BB=BA113=E5=88=97=E5=90=8E=E4=BA=A4=E7=BB=99=20Pip?= =?UTF-8?q?eline.predict()=20=E5=AE=8C=E6=95=B4=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 之前手动调 imputer/preproc.transform 后返回, predict() 又套一层 Pipeline → SimpleImputer 收到44列不匹配113列 - 改为重建113列训练特征集,返回后让 model.predict() 完整走 Pipeline: imputer→preproc→cleaner→SVR,与训练完全一致 --- src/core/prediction/inference_batch.py | 47 +++++++++++--------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/core/prediction/inference_batch.py b/src/core/prediction/inference_batch.py index cce01b2..aed83b1 100644 --- a/src/core/prediction/inference_batch.py +++ b/src/core/prediction/inference_batch.py @@ -477,17 +477,15 @@ class WaterQualityInference: metadata = self.loaded_model_data.get('metadata', {}) # ═══════════════════════════════════════════════════════════ - # ★ DualStream_MNF 快速通道:Pipeline 已内置 MNF + 物理指数 - # 但需先将推理光谱重采样到训练特征空间(308→113列), - # 再走 Pipeline 的 imputer+preproc 步骤 + # ★ DualStream_MNF:重建训练特征空间(308→113列), + # 让 Pipeline.predict() 完整走 imputer→preproc→cleaner→SVR # ═══════════════════════════════════════════════════════════ if actual_preprocess_method == "DualStream_MNF" and isinstance(model, Pipeline): - print("[DualStream_MNF] 推理:先重建训练特征集再直通 Pipeline") - # 1) 重采样 308 波段 → 训练波长网格 + print("[DualStream_MNF] 推理:重建训练特征集,交给 Pipeline 完整处理") train_wl = metadata.get('train_wavelengths', None) train_cols = metadata.get('train_columns', None) if train_wl is not None and len(train_wl) > 0 and train_cols is not None: - # 从 spectra 中提取光谱列(列名可转 float 的即为波长列) + # 1) 重采样 308 → 训练波长 spec_cols = [] for c in spectra.columns: try: @@ -502,34 +500,27 @@ class WaterQualityInference: resampled[i] = np.interp(dst_wl, src_wl, spec_data[i], left=np.nan, right=np.nan) resampled = np.nan_to_num(resampled, nan=0.0) - # 2) 计算 WQI 补齐到训练列数 wl_col_names = [f'{wl:.6f}' for wl in train_wl] - spectra_df = pd.DataFrame(resampled, columns=wl_col_names) + spectra = pd.DataFrame(resampled, columns=wl_col_names) + # 2) 计算 WQI + 补零到训练列数 n_need = len(train_cols) - if spectra_df.shape[1] < n_need: - print(f"[DualStream_MNF] 计算 WQI 补齐: {spectra_df.shape[1]} → {n_need}") + if spectra.shape[1] < n_need: + print(f"[DualStream_MNF] 计算 WQI: {spectra.shape[1]} → {n_need}") try: from src.utils.water_index import WaterQualityIndexCalculator - calc = WaterQualityIndexCalculator() - formulas = calc.list_available() - wqi = calc.calculate_many(formulas, spectra_df, fast=True) - spectra_df = pd.concat([spectra_df, wqi], axis=1) + wqi = WaterQualityIndexCalculator().calculate_many( + WaterQualityIndexCalculator().list_available(), + spectra, fast=True) + spectra = pd.concat([spectra, wqi], axis=1) except Exception as e: print(f"[DualStream_MNF] WQI 失败: {e}") - # 如果还不够,补零 - while spectra_df.shape[1] < n_need: - spectra_df[f'_pad_{spectra_df.shape[1]}'] = 0.0 - spectra_df = spectra_df.iloc[:, :n_need] - # 3) 喂入 Pipeline - spectra_processed = model.named_steps['imputer'].transform(spectra_df.values) - spectra_processed = model.named_steps['preproc'].transform(spectra_processed) - else: - spectra_processed = model.named_steps['imputer'].transform(spectra.values) - spectra_processed = model.named_steps['preproc'].transform(spectra_processed) - spectra_processed = np.nan_to_num(spectra_processed, nan=0.0, posinf=0.0, neginf=0.0) - print(f"[DualStream_MNF] 预处理完成: {spectra_processed.shape}") - print(f"[特征对齐] 最终输入维度: {spectra_processed.shape}") - return spectra_processed + while spectra.shape[1] < n_need: + spectra[f'_pad_{spectra.shape[1]}'] = 0.0 + spectra = spectra.iloc[:, :n_need] + print(f"[DualStream_MNF] 特征重建完成: {spectra.shape}") + print(f"[特征对齐] 最终输入维度: {spectra.shape}") + # 返回 DataFrame,后续 model.predict() 走完整 Pipeline + return spectra.values train_wavelengths = metadata.get('train_wavelengths', None) # 旧模型无 train_wavelengths → 不做波长匹配,走下方分支 B 的 linspace 路径