ShopTRAINING/lyf开发日志记录文档.md

170 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 开发日志记录
本文档记录了项目开发过程中的主要修改、问题修复和重要决策。
---
## 2025-07-13早期后端修复与重构
**开发者**: lyf
### 13:30 - 修复数据加载路径问题
- **任务目标**: 解决模型训练时因数据文件路径错误导致的数据加载失败问题。
- **核心问题**: `server/core/predictor.py` 中的 `PharmacyPredictor` 类初始化时,硬编码了错误的默认数据文件路径。
- **修复方案**: 将默认数据路径更正为 `'data/timeseries_training_data_sample_10s50p.parquet'`,并同步更新了所有训练器。
### 14:00 - 数据流重构
- **任务目标**: 解决因数据处理流程中断导致关键特征丢失,从而引发模型训练失败的根本问题。
- **核心问题**: `predictor.py` 未将预处理好的数据向下传递,导致各训练器重复加载并错误处理数据。
- **修复方案**: 重构了核心数据流,确保数据在 `predictor.py` 中被统一加载和预处理然后作为一个DataFrame显式传递给所有下游的训练器函数。
---
## 2025-07-14模型训练与并发问题集中攻坚
**开发者**: lyf
### 10:16 - 修复训练器层 `KeyError`
- **问题**: 所有模型训练均因 `KeyError: "['sales', 'price'] not in index"` 失败。
- **分析**: 训练器硬编码的特征列表中包含了数据源中不存在的 `'price'` 列。
- **修复**: 从所有四个训练器 (`mlstm`, `transformer`, `tcn`, `kan`) 的 `features` 列表中移除了对不存在的 `'price'` 列的依赖。
### 10:38 - 修复数据标准化层 `KeyError`
- **问题**: 修复后出现新错误 `KeyError: "['sales'] not in index"`
- **分析**: `server/utils/multi_store_data_utils.py` 中的 `standardize_column_names` 函数列名映射错误,且缺少最终列选择机制。
- **修复**: 修正了列名映射,并增加了列选择机制,确保函数返回的 `DataFrame` 结构统一且包含 `sales` 列。
### 11:04 - 修复JSON序列化失败问题
- **问题**: 训练完成后,因 `Object of type float32 is not JSON serializable` 导致前后端通信失败。
- **分析**: 训练产生的评估指标是NumPy的 `float32` 类型,无法被标准 `json` 库序列化。
- **修复**: 在 `server/utils/training_process_manager.py` 中增加了 `convert_numpy_types` 辅助函数在通过WebSocket或API返回数据前将所有NumPy数值类型转换为Python原生类型从根源上解决了所有序列化问题。
### 11:15 - 修复MAPE计算错误
- **问题**: 训练日志显示 `MAPE: nan%` 并伴有 `RuntimeWarning: Mean of empty slice.`
- **分析**: 当测试集中的所有真实值都为0时计算MAPE会导致对空数组求平均值。
- **修复**: 在 `server/analysis/metrics.py` 中增加条件判断若不存在非零真实值则直接将MAPE设为0。
### 11:41 - 修复“按店铺训练”页面列表加载失败
- **问题**: “选择店铺”的下拉列表为空。
- **分析**: `standardize_column_names` 函数错误地移除了包括店铺元数据在内的非训练必需列。
- **修复**: 将列筛选的逻辑从通用的 `standardize_column_names` 函数中移出,精确地应用到仅为模型训练准备数据的函数中。
### 13:00 - 修复“按店铺训练-所有药品”模式
- **问题**: 选择“所有药品”训练时,因 `product_id` 被错误地处理为字符串 `"unknown"` 而失败。
- **修复**: 在 `server/core/predictor.py` 中拦截 `"unknown"` ID并将其意图正确地转换为“聚合此店铺的所有产品数据”。同时扩展了 `aggregate_multi_store_data` 函数使其支持按店铺ID进行聚合。
### 14:19 - 修复并发训练中的稳定性问题
- **问题**: 并发训练时出现 `API列表排序错误``WebSocket连接错误`
- **修复**:
1. **排序**: 在 `api.py` 中为 `None` 类型的 `start_time` 提供了默认值,解决了 `TypeError`
2. **连接**: 在 `socketio.run()` 调用时增加了 `allow_unsafe_werkzeug=True` 参数解决了调试模式下Socket.IO与Werkzeug的冲突。
### 15:30 - 根治模型训练中的维度不匹配问题
- **问题**: 所有模型训练完成后,评估指标 `R²` 始终为0.0。
- **根本原因**: `server/utils/data_utils.py``create_dataset` 函数在创建目标数据集 `dataY` 时,错误地保留了一个多余的维度。同时,模型文件 (`mlstm_model.py`, `transformer_model.py`) 的输出也存在维度问题。
- **最终修复**:
1. **数据层**: 在 `create_dataset` 中使用 `.flatten()` 修正了 `y` 标签的维度。
2. **模型层**: 在所有模型的 `forward` 方法最后增加了 `.squeeze(-1)`,确保模型输出维度正确。
3. **训练器层**: 撤销了所有为解决此问题而做的临时性维度调整,恢复了最直接的损失计算。
### 16:10 - 修复“全局模型训练-所有药品”模式
- **问题**: 与“按店铺训练”类似,全局训练的“所有药品”模式也因 `product_id="unknown"` 而失败。
- **修复**: 采用了与店铺训练完全相同的修复模式。在 `predictor.py` 中拦截 `"unknown"` 并将其意图转换为真正的全局聚合(`product_id=None`),并扩展 `aggregate_multi_store_data` 函数以支持此功能。
---
## 2025-07-15端到端修复“按药品预测”图表功能
**开发者**: lyf
### 10:00 - 阶段一:修复数据库写入失败 (`sqlite3.IntegrityError`)
- **问题**: 后端日志显示 `datatype mismatch`
- **分析**: `save_prediction_result` 函数试图将复杂Python对象直接存入数据库。
- **修复**: 在 `server/api.py` 中,执行数据库插入前,使用 `json.dumps()` 将复杂对象序列化为JSON字符串。
### 10:30 - 阶段二修复API响应结构与前端不匹配
- **问题**: 图表依然无法渲染。
- **分析**: 前端期望 `history_data` 在顶层,而后端将其封装在 `data` 子对象中。
- **修复**: 修改 `server/api.py``predict` 函数,将关键数据提升到响应的根级别。
### 11:00 - 阶段三:修复历史数据与预测数据时间不连续
- **问题**: 图表数据在时间上完全脱节。
- **分析**: 获取历史数据的逻辑总是取整个数据集的最后30条而非预测起始日期之前的30条。
- **修复**: 在 `server/api.py` 中增加了正确的日期筛选逻辑。
### 14:00 - 阶段四:重构数据源,根治数据不一致问题
- **问题**: 历史数据(绿线)与预测数据(蓝线)的口径完全不同。
- **根本原因**: API层独立加载**原始数据**画图,而预测器使用**聚合后数据**预测。
- **修复 (重构)**:
1. 修改 `server/predictors/model_predictor.py`,使其返回预测结果的同时,也返回其所使用的、口径一致的历史数据。
2. 彻底删除了 `server/api.py` 中所有独立加载历史数据的冗余代码,确保了数据源的唯一性。
### 15:00 - 阶段五修复图表X轴日期格式问题
- **问题**: X轴显示为混乱的GMT格式时间戳。
- **分析**: `history_data` 中的 `Timestamp` 对象未被正确格式化。
- **修复**: 在 `server/api.py` 中,为 `history_data` 增加了 `.strftime('%Y-%m-%d')` 的格式化处理。
### 16:00 - 阶段六:修复模型“学不会”的根本原因 (超参数传递中断)
- **问题**: 即便流程正确,所有模型的预测结果依然是无法学习的直线。
- **根本原因**: `server/core/predictor.py` 在调用训练器时,**没有将 `sequence_length` 等关键超参数传递下去**,导致所有模型都使用了错误的默认值。
- **修复**:
1. 修改 `server/core/predictor.py`,在调用中加入超参数的传递。
2. 修改所有四个训练器文件,使其能接收并使用这些参数。
---
## 2025-07-16最终验证与项目总结
**开发者**: lyf
### 10:00 - 阶段七:最终验证与结论
- **问题**: 在修复所有代码问题后,对特定日期的预测结果依然是平线。
- **分析**: 通过编写临时数据分析脚本 (`temp_check_parquet.py`) 最终确认,这是**数据本身**的问题。我们选择的预测日期在样本数据集中恰好处于一个“零销量”的空白期。
- **最终结论**: 系统代码已完全修复。图表上显示的平线,是模型对“零销量”历史做出的**正确且符合逻辑**的反应。
### 11:45 - 项目总结与文档归档
- **任务**: 根据用户要求,回顾整个调试过程,将所有问题、解决方案、优化思路和最终结论,按照日期和时间顺序,整理并更新到本开发日志中,形成一份高质量的技术档案。
- **结果**: 本文档已更新完成。
### 13:15 - 最终修复:根治模型标识符不一致问题
- **问题**: 经过再次测试和日志分析,发现即便是修正后,店铺模型的 `model_identifier` 在训练时依然被错误地构建为 `01010023_store_01010023`
- **根本原因**: `server/core/predictor.py``train_model` 方法中,在 `training_mode == 'store'` 的分支下,构建 `model_identifier` 的逻辑存在冗余和错误。
- **最终解决方案**: 删除了错误的拼接逻辑 `model_identifier = f"{store_id}_{product_id}"`,直接使用在之前步骤中已经被正确赋值为 `f"store_{store_id}"``product_id` 变量作为 `model_identifier`。这确保了从训练、保存到最终API查询店铺模型的唯一标识符始终保持一致。
### 13:30 - 最终修复(第二轮):根治模型保存路径错误
- **问题**: 即便修复了标识符,模型版本依然无法加载。
- **根本原因**: 通过分析训练日志,发现所有训练器(`transformer_trainer.py`, `mlstm_trainer.py`, `tcn_trainer.py`)中的 `save_checkpoint` 函数,都会强制在 `saved_models` 目录下创建一个 `checkpoints` 子目录,并将所有模型文件保存在其中。而负责查找模型的 `get_model_versions` 函数只在根目录查找,导致模型永远无法被发现。
- **最终解决方案**: 逐一修改了所有相关训练器文件中的 `save_checkpoint` 函数,移除了创建和使用 `checkpoints` 子目录的逻辑,确保所有模型都直接保存在 `saved_models` 根目录下。
- **结论**: 至此,模型保存的路径与查找的路径完全统一,从根本上解决了模型版本无法加载的问题。
### 13:40 - 最终修复(第三轮):统一所有训练器的模型保存逻辑
- **问题**: 在修复了 `transformer_trainer.py` 后,发现 `mlstm_trainer.py``tcn_trainer.py` 存在完全相同的路径和命名错误,导致问题依旧。
- **根本原因**: `save_checkpoint` 函数在所有训练器中都被错误地实现,它们都强制创建了 `checkpoints` 子目录,并使用了错误的逻辑来拼接文件名。
- **最终解决方案**:
1. **逐一修复**: 逐一修改了 `transformer_trainer.py`, `mlstm_trainer.py`, 和 `tcn_trainer.py` 中的 `save_checkpoint` 函数。
2. **路径修复**: 移除了创建和使用 `checkpoints` 子目录的逻辑,确保模型直接保存在 `model_dir` (即 `saved_models`) 的根目录下。
3. **文件名修复**: 简化并修正了文件名的生成逻辑,直接使用 `product_id` 参数作为唯一标识符(该参数已由上游逻辑正确赋值为 `药品ID``store_{店铺ID}`),不再进行任何额外的、错误的拼接。
- **结论**: 至此所有训练器的模型保存逻辑完全统一模型保存的路径和文件名与API的查找逻辑完全匹配从根本上解决了模型版本无法加载的问题。
---
## 2025-07-16 (续):端到端修复“店铺预测”图表功能
**开发者**: lyf
### 15:30 - 最终修复(第四轮):打通店铺预测的数据流
- **问题**: 在解决了模型加载问题后,“店铺预测”功能虽然可以成功执行,但前端图表依然空白,不显示历史数据和预测数据。
- **根本原因**: 参数传递在调用链中出现断裂。
1. `server/api.py` 在调用 `run_prediction` 时,没有传递 `training_mode`
2. `server/core/predictor.py` 在调用 `load_model_and_predict` 时,没有传递 `store_id``training_mode`
3. `server/predictors/model_predictor.py` 内部的数据加载逻辑,在处理店铺预测时,错误地使用了模型标识符(`store_{id}`作为产品ID来过滤数据导致无法加载到任何历史数据。
- **最终解决方案 (三步修复)**:
1. **修复 `model_predictor.py`**: 修改 `load_model_and_predict` 函数,使其能够根据 `training_mode` 参数智能地加载数据。当模式为 `'store'` 时,它会正确地聚合该店铺的所有销售数据作为历史数据,这与训练时的数据准备方式完全一致。
2. **修复 `predictor.py`**: 修改 `predict` 方法,将 `store_id``training_mode` 参数正确地传递给底层的 `load_model_and_predict` 函数。
3. **修复 `api.py`**: 修改 `predict` 路由和 `run_prediction` 辅助函数,确保 `training_mode` 参数在整个调用链中被完整传递。
- **结论**: 通过以上修复我们确保了从API接口到最底层数据加载器的参数传递是完整和正确的。现在无论是药品预测还是店铺预测系统都能够加载正确的历史数据用于图表绘制彻底解决了图表显示空白的问题。
### 16:16 - 项目状态更新
- **状态**: **所有已知问题已修复**
- **确认**: 用户已确认“现在药品和店铺预测流程通了”。
- **后续**: 将本次修复过程归档至本文档。