# 90天TMP预测模型训练逻辑说明 ## 模型概述 这是一个用于预测反渗透(RO)系统未来90天压力差变化的**长期趋势预测模型**。与20分钟模型不同,这个模型关注的是长期的膜污染趋势。 **预测目标**:8个RO压力差指标 - 4个一段压差:`C.M.RO1-4_DB@DPT_1` - 4个二段压差:`C.M.RO1-4_DB@DPT_2` ## 与20分钟模型的区别 | 特性 | 20分钟模型 | 90天模型 | |------|-----------|---------| | **预测时长** | 20分钟(5步) | 90天(2160步) | | **时间分辨率** | 4分钟/点 | 1小时/点 | | **输入历史** | 4小时(60点) | 180天(4320点) | | **预测目标** | 16个指标 | 8个指标 | | **输入特征** | 79个 | 16个 | | **应用场景** | 实时监控、短期调度 | 长期趋势、维护计划 | ## 核心思路 ### 1. 为什么需要长期预测? 膜污染是一个**缓慢累积**的过程: - 短期(分钟级):压力波动主要由流量、温度变化引起 - 长期(天级):压力持续上升是膜表面污染物积累导致 **模型目标**:预测未来90天内,每个RO膜组的压力差如何演变,从而: - 提前规划化学清洗(CEB)时间 - 评估膜寿命 - 优化运行参数 ### 2. 超长输入窗口:4320个时间点 ``` 过去180天 → [LSTM处理] → 未来90天 (4320小时) (2160小时) ``` **为什么这么长?** - 膜污染速率受季节、水质、运行策略影响 - 需要足够长的历史才能捕捉这些缓慢变化 - 类似"看过去半年天气,预测未来三个月天气" ### 3. 精简特征集:只用16个核心指标 不同于20分钟模型的79个特征,这里只用16个: - 4个RO进水流量:`C.M.RO1-4_FT_JS@out` - 2个RO系统指标:温度 `C.M.RO_TT_ZJS@out`、电导率 `C.M.RO_Cond_ZJS@out` - 8个当前压差:`C.M.RO1-4_DB@DPT_1/2`(输入也是输出,捕捉自相关) - 2个时间特征:年周期的正弦/余弦编码 **为什么减少特征?** - 长期趋势主要由流量、温度、当前压差决定 - 太多特征在超长序列上会导致过拟合 - 简化计算,减少内存占用 ## 训练流程详解 ### 步骤1:数据预处理(`data_preprocessor.py`) #### 1.1 时间分辨率处理 ```python resolution = 60 # 每60条原始数据取1条 chunk = all_data.iloc[::60, :] # 从4秒一条变成4分钟一条 ``` 之后再在训练时按小时聚合 #### 1.2 年周期时间编码 ```python # 只编码年周期,不编码日周期(长期趋势不关心一天内变化) day_year_sin = sin(2π × 天数 / 366) day_year_cos = cos(2π × 天数 / 366) ``` #### 1.3 滑动窗口策略 ```python # 超长窗口需要特殊处理 window_time_span = 1小时 × (4320 + 314) # 额外314小时buffer # 训练样本生成:step_size=1(密集采样) # 测试样本生成:step_size=2160(跳跃采样,节省计算) ``` **为什么测试集跳跃采样?** - 测试时不需要每个时间点都预测 - 只需验证模型在不同起点的预测能力 ### 步骤2:模型架构(`gat_lstm.py`) #### 结构与20分钟模型完全相同 ```python # 8个独立专家(对应8个压差指标) class GAT_LSTM: def __init__(self): self.models = nn.ModuleList([SingleGATLSTM() for _ in range(8)]) ``` #### 每个专家内部 ```python class SingleGATLSTM: # LSTM层 self.lstm = nn.LSTM( input_size=16, # 输入16个特征 hidden_size=64, # 隐藏层64单元 num_layers=1, # 单层LSTM batch_first=True ) # 输出层 self.final_linear = nn.Sequential( nn.Linear(64, 64), nn.LeakyReLU(0.01), nn.Dropout(0), nn.Linear(64, 2160) # 输出2160步(90天) ) ``` **注意**:虽然输入序列长达4320,但LSTM的隐藏层只有64维: - LSTM能压缩长时间序列的信息 - 避免梯度消失(如果层数太多会有问题) ### 步骤3:训练策略(`data_trainer.py`) #### 与20分钟模型相同的训练流程 ```python for epoch in range(1000): # 前向传播 outputs = model(inputs) # [batch, 2160×8] # 计算MSE损失 loss = MSELoss(outputs, targets) # 反向传播 loss.backward() optimizer.step() # 验证 val_loss = validate(val_loader) # 早停 if val_loss没有改善超过500轮: break ``` #### 特别注意的参数 ```python batch_size = 128 # 比20分钟模型小(1024 vs 128) # 因为每个样本更长,内存占用大 learning_rate = 0.01 # 学习率相同 scheduler_step = 100 # 每100轮衰减0.9 ``` ### 步骤4:评估与反归一化(`data_trainer.py`) #### 多步预测的展平 ```python # 模型输出:[样本数, 2160×8] # 需要重塑为:[样本数, 2160步, 8个指标] predictions = predictions.reshape(n_samples, 2160, 8) # 再展平为:[样本数×2160, 8]用于反归一化 predictions = predictions.reshape(-1, 8) ``` #### 反归一化 ```python # 只反归一化最后8列(压差指标) column_scaler = MinMaxScaler() column_scaler.min_ = scaler.min_[-8:] column_scaler.scale_ = scaler.scale_[-8:] predictions = column_scaler.inverse_transform(predictions) ``` ## 预测流程(`predict.py`) ### 实时预测接口 ```python class Predictor: # 参数设置 seq_len = 4320 # 需要180天历史数据 output_size = 2160 # 预测90天 feature_num = 16 # 16个输入特征 labels_num = 8 # 8个预测目标 ``` ### 预测步骤 1. **历史数据准备**: - 需要连续180天的数据(4320小时) - 按小时分辨率采样 2. **预测起始时间**: ```python # 预测起点 = 最新数据时间 + 3小时 test_start_date = max_date + timedelta(hours=3) ``` 3. **多重平滑处理**: ```python # 对预测结果进行3层平滑(减少噪声) predictions = moving_average_smooth(predictions) predictions = exponential_smooth(predictions) predictions = savitzky_golay_smooth(predictions) # 可选 ``` **为什么需要平滑?** - 90天预测本身就是粗粒度的 - 小的波动可能是噪声而非真实趋势 - 平滑后的曲线更符合长期趋势的预期 ### 三种平滑方法 #### 1. 滑动平均 ```python window = 30 # 30小时窗口 smoothed = convolve(data, window) ``` 简单有效,适合去除高频噪声 #### 2. 指数移动平均 ```python EMA[t] = α × data[t] + (1-α) × EMA[t-1] ``` 近期数据权重更高,适合捕捉趋势变化 #### 3. Savitzky-Golay滤波 ```python # 用多项式拟合窗口内的数据 savgol_filter(data, window=25, polyorder=2) ``` 保留趋势的同时降噪,适合平滑的长期曲线 ## 训练参数说明 | 参数 | 值 | 说明 | |------|-----|------| | `seq_len` | 4320 | 输入历史长度(180天) | | `output_size` | 2160 | 预测未来步数(90天) | | `feature_num` | 16 | 输入特征数 | | `labels_num` | 8 | 预测目标数 | | `hidden_size` | 64 | LSTM隐藏层大小 | | `batch_size` | 128 | 每批训练样本数 | | `lr` | 0.01 | 初始学习率 | | `epochs` | 1000 | 最大训练轮数 | | `patience` | 500 | 早停耐心值 | ## 文件结构说明 ``` 90天TMP预测模型源码/ ├── args.py # 参数配置(长期预测专用参数) ├── data_preprocessor.py # 数据预处理(年周期编码、长序列处理) ├── gat_lstm.py # 模型定义(8个专家模型) ├── data_trainer.py # 训练器(与20分钟版本类似) ├── main.py # 训练入口 ├── predict.py # 预测接口(包含多重平滑) ├── model.pth # 训练好的模型权重 └── scaler.pkl # 归一化器 ``` ## 使用场景 ### 1. 维护计划 ```python # 预测90天后的压差 predictions = predictor.predict(historical_data) # 找出何时需要CEB threshold = 0.20 # 压差超过0.20 MPa需要清洗 ceb_dates = find_dates_above_threshold(predictions, threshold) ``` ### 2. 膜寿命评估 ```python # 分析压差上升速率 rate = (predictions[-1] - predictions[0]) / 90 # 平均每天增速 expected_lifetime = (max_TMP - current_TMP) / rate ``` ### 3. 运行策略优化 ```python # 对比不同运行参数下的长期压差 scenario_A = predict_with_params(flow=300) scenario_B = predict_with_params(flow=360) ``` ## 模型局限性 1. **需要大量历史数据**:至少180天连续数据,数据缺失会影响预测 2. **对突变事件敏感**:如果中途更换膜组或大修,需要重新训练 3. **长期预测不确定性**:越往后预测,误差累积越大 4. **假设运行模式不变**:如果未来改变流量、温度等运行参数,预测会失准 ## 改进建议 ### 提升预测精度 1. **增加外部因素**: - 水质指标(浊度、COD等) - 清洗历史(上次CEB时间、效果) - 季节变量(显式编码春夏秋冬) 2. **改进模型结构**: - 使用Transformer替代LSTM(更适合超长序列) - 添加注意力机制(关注关键时间点) - 引入外部变量的条件预测 3. **集成多模型**: - 训练多个模型取平均(集成学习) - 分段预测(前30天精确,后60天粗略) ### 加速训练 ```python # 使用更小的batch_size batch_size = 64 # 减少训练数据量(只用近期数据) start_files = 5 # 从第5个文件开始 # 降低采样率 step_size = 10 # 训练时每10步取1个样本 ``` ## 常见问题 **Q:为什么用4320步输入,而不是更短?** A:膜污染是周期性+趋势性的复合过程,需要看足够长的历史才能区分周期波动和长期趋势。 **Q:预测90天会不会太长?** A:对于膜污染这种缓慢过程,90天只是一个CEB周期。实际应用中可以每周重新预测,不断修正。 **Q:如何判断模型是否学到了长期趋势?** A:绘制预测曲线,看是否捕捉到压差的缓慢上升。如果曲线波动剧烈,可能只学到了短期噪声。 **Q:能否用这个模型做短期预测?** A:不建议。这个模型牺牲了短期精度换取长期趋势,用于短期预测反而不如20分钟模型。