ShopTRAINING/server/trainers/mlstm_trainer.py

352 lines
14 KiB
Python
Raw Normal View History

"""
药店销售预测系统 - mLSTM模型训练函数
"""
import os
import time
import pandas as pd
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from sklearn.preprocessing import MinMaxScaler
import matplotlib.pyplot as plt
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
from datetime import datetime
from models.mlstm_model import MLSTMTransformer as MatrixLSTM
from utils.data_utils import create_dataset, PharmacyDataset
from analysis.metrics import evaluate_model
2025-07-02 11:05:23 +08:00
from core.config import (
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
DEVICE, LOOK_BACK, FORECAST_HORIZON
2025-07-02 11:05:23 +08:00
)
from utils.training_progress import progress_manager
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
from utils.model_manager import model_manager
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
from typing import Any
def convert_numpy_types(obj: Any) -> Any:
"""
递归地将字典或列表中的Numpy数值类型转换为Python原生类型
"""
if isinstance(obj, dict):
return {k: convert_numpy_types(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [convert_numpy_types(elem) for elem in obj]
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
return obj
2025-07-02 11:05:23 +08:00
def train_product_model_with_mlstm(
product_df,
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
product_id=None,
2025-07-02 11:05:23 +08:00
store_id=None,
training_mode='product',
aggregation_method='sum',
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
scope=None,
epochs=50,
2025-07-02 11:05:23 +08:00
socketio=None,
task_id=None,
continue_training=False,
progress_callback=None,
patience=10,
learning_rate=0.001,
clip_norm=1.0
2025-07-02 11:05:23 +08:00
):
"""
使用mLSTM训练产品销售预测模型
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
参数:
2025-07-02 11:05:23 +08:00
product_id: 产品ID
store_id: 店铺ID为None时使用全局数据
training_mode: 训练模式 ('product', 'store', 'global')
aggregation_method: 聚合方法 ('sum', 'mean', 'weighted')
epochs: 训练轮次
model_dir: 模型保存目录
version: 模型版本如果为None则自动生成
socketio: Socket.IO实例用于实时进度推送
task_id: 任务ID
continue_training: 是否继续训练
progress_callback: 进度回调函数用于多进程训练
"""
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
# 创建WebSocket进度反馈函数支持多进程
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
2025-07-02 11:05:23 +08:00
def emit_progress(message, progress=None, metrics=None):
"""发送训练进度到前端"""
progress_data = {
'task_id': task_id,
'message': message,
'timestamp': time.time()
}
if progress is not None:
progress_data['progress'] = progress
if metrics is not None:
progress_data['metrics'] = metrics
if progress_callback:
try:
progress_callback(progress_data)
except Exception as e:
print(f"[mLSTM] 进度回调失败: {e}")
if socketio and task_id:
try:
socketio.emit('training_progress', progress_data, namespace='/training')
except Exception as e:
print(f"[mLSTM] WebSocket发送失败: {e}")
print(f"[mLSTM] {message}", flush=True)
import sys
sys.stdout.flush()
sys.stderr.flush()
emit_progress("开始mLSTM模型训练...")
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
# 1. 确定模型标识符和版本
model_type = 'mlstm'
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
# 直接使用从 predictor 传递过来的、已经构建好的 scope
if scope is None:
# 作为后备如果scope未提供则根据旧逻辑构建不推荐
if training_mode == 'store':
current_product_id = product_id if product_id and product_id not in ['unknown', 'all'] else 'all'
scope = f"{store_id}_{current_product_id}"
elif training_mode == 'product':
scope = f"{product_id}_{store_id or 'all'}"
elif training_mode == 'global':
scope = product_id if product_id else "all"
emit_progress(f"警告: Scope未由调用方提供已自动构建为 '{scope}'", 'warning')
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
model_identifier = model_manager.get_model_identifier(model_type, training_mode, scope, aggregation_method)
version = model_manager.get_next_version_number(model_identifier)
2025-07-02 11:05:23 +08:00
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
emit_progress(f"开始训练 mLSTM 模型 v{version}")
2025-07-02 11:05:23 +08:00
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
# 2. 获取模型版本路径
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
model_version_path = model_manager.get_model_version_path(
model_type=model_type,
training_mode=training_mode,
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
scope=scope,
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
version=version,
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
aggregation_method=aggregation_method
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
)
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
emit_progress(f"模型将保存到: {model_version_path}")
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
# 根据训练模式和参数动态生成更详细的描述
if training_mode == 'store':
training_scope = f"店铺 {store_id}"
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
if scope and 'specific' in scope:
training_scope += " (指定药品)"
else:
training_scope += " (所有药品)"
elif training_mode == 'global':
training_scope = f"全局聚合({aggregation_method})"
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
else: # product 模式
training_scope = f"药品 {product_id}"
if scope and 'specific' in scope:
training_scope += " (指定店铺)"
elif store_id:
training_scope += f" (店铺 {store_id})"
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
else:
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
training_scope += " (所有店铺)"
2025-07-02 11:05:23 +08:00
min_required_samples = LOOK_BACK + FORECAST_HORIZON
if len(product_df) < min_required_samples:
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
error_msg = f"数据不足: 需要 {min_required_samples} 天, 实际 {len(product_df)} 天。"
2025-07-02 11:05:23 +08:00
print(error_msg)
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
emit_progress(f"训练失败:{error_msg}")
2025-07-02 11:05:23 +08:00
raise ValueError(error_msg)
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
if product_id:
product_name = product_df['product_name'].iloc[0]
else:
product_name = f"Aggregated Model ({training_mode}/{scope})"
print_product_id = product_id if product_id else "N/A"
print(f"[mLSTM] 使用mLSTM模型训练 '{product_name}' (ID: {print_product_id}) 的销售预测模型", flush=True)
2025-07-02 11:05:23 +08:00
print(f"[mLSTM] 训练范围: {training_scope}", flush=True)
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
print(f"[mLSTM] 版本: v{version}", flush=True)
2025-07-02 11:05:23 +08:00
print(f"[mLSTM] 使用设备: {DEVICE}", flush=True)
print(f"[mLSTM] 数据量: {len(product_df)} 条记录", flush=True)
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
emit_progress(f"训练产品: {product_name} (ID: {print_product_id}) - {training_scope}")
# 创建特征和目标变量
features = ['sales', 'weekday', 'month', 'is_holiday', 'is_weekend', 'is_promotion', 'temperature']
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
2025-07-02 11:05:23 +08:00
print(f"[mLSTM] 开始数据预处理,特征: {features}", flush=True)
# 预处理数据
X = product_df[features].values
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
y = product_df[['sales']].values
2025-07-02 11:05:23 +08:00
print(f"[mLSTM] 特征矩阵形状: {X.shape}, 目标矩阵形状: {y.shape}", flush=True)
emit_progress("数据预处理中...")
scaler_X = MinMaxScaler(feature_range=(0, 1))
scaler_y = MinMaxScaler(feature_range=(0, 1))
X_scaled = scaler_X.fit_transform(X)
y_scaled = scaler_y.fit_transform(y)
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
print(f"[mLSTM] 数据归一化完成", flush=True)
train_size = int(len(X_scaled) * 0.8)
X_train, X_test = X_scaled[:train_size], X_scaled[train_size:]
y_train, y_test = y_scaled[:train_size], y_scaled[train_size:]
trainX, trainY = create_dataset(X_train, y_train, LOOK_BACK, FORECAST_HORIZON)
testX, testY = create_dataset(X_test, y_test, LOOK_BACK, FORECAST_HORIZON)
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
train_loader = DataLoader(PharmacyDataset(torch.Tensor(trainX), torch.Tensor(trainY)), batch_size=32, shuffle=True)
test_loader = DataLoader(PharmacyDataset(torch.Tensor(testX), torch.Tensor(testY)), batch_size=32, shuffle=False)
2025-07-02 11:05:23 +08:00
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
total_batches = len(train_loader)
total_samples = len(train_loader.dataset)
print(f"[mLSTM] 数据加载器创建完成 - 批次数: {total_batches}, 样本数: {total_samples}", flush=True)
2025-07-02 11:05:23 +08:00
emit_progress(f"数据加载器准备完成 - 批次数: {total_batches}, 样本数: {total_samples}")
input_dim = X_train.shape[1]
output_dim = FORECAST_HORIZON
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
hidden_size, num_heads, dropout_rate, num_blocks, embed_dim, dense_dim = 128, 4, 0.1, 3, 32, 32
2025-07-02 11:05:23 +08:00
model = MatrixLSTM(
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
num_features=input_dim, hidden_size=hidden_size, mlstm_layers=2, embed_dim=embed_dim,
dense_dim=dense_dim, num_heads=num_heads, dropout_rate=dropout_rate,
num_blocks=num_blocks, output_sequence_length=output_dim
).to(DEVICE)
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
print(f"[mLSTM] 模型创建完成", flush=True)
2025-07-02 11:05:23 +08:00
emit_progress("mLSTM模型初始化完成")
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
if continue_training:
emit_progress("继续训练模式启动,但当前重构版本将从头开始。")
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
--- **日期**: 2025-07-15 11:43 **主题**: 修复因PyTorch版本不兼容导致的训练失败问题 ### 问题描述 在修复了路径和依赖问题后,在某些机器上运行模型训练时,程序因 `TypeError: ReduceLROnPlateau.__init__() got an unexpected keyword argument 'verbose'` 而崩溃。但在本地开发机上运行正常。 ### 根本原因 此问题是典型的**环境不一致**导致的兼容性错误。 1. **PyTorch版本差异**: 本地开发环境安装了较旧版本的PyTorch,其学习率调度器 `ReduceLROnPlateau` 支持 `verbose` 参数(用于在学习率变化时打印日志)。 2. **新环境**: 在其他计算机或新创建的虚拟环境中,安装了较新版本的PyTorch。在新版本中,`ReduceLROnPlateau` 的 `verbose` 参数已被移除。 3. **代码问题**: `server/trainers/mlstm_trainer.py` 和 `server/trainers/transformer_trainer.py` 的代码中,在创建 `ReduceLROnPlateau` 实例时硬编码了 `verbose=True` 参数,导致在新版PyTorch环境下调用时出现 `TypeError`。 ### 解决方案:移除已弃用的参数 1. **全面排查**: 检查了项目中所有训练器文件 (`mlstm_trainer.py`, `transformer_trainer.py`, `kan_trainer.py`, `tcn_trainer.py`)。 2. **精确定位**: 确认只有 `mlstm_trainer.py` 和 `transformer_trainer.py` 使用了 `ReduceLROnPlateau` 并传递了 `verbose` 参数。 3. **执行修复**: * **文件**: `server/trainers/mlstm_trainer.py` 和 `server/trainers/transformer_trainer.py` * **位置**: `ReduceLROnPlateau` 的初始化调用处。 * **操作**: 删除了 `verbose=True` 参数。 ```diff - scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', ..., verbose=True) + scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', ...) ``` * **原因**: 移除这个在新版PyTorch中已不存在的参数,可以从根本上解决 `TypeError`,并确保代码在不同版本的PyTorch环境中都能正常运行。此修改不影响学习率调度器的核心功能。
2025-07-15 11:56:19 +08:00
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', patience=patience // 2, factor=0.5)
2025-07-02 11:05:23 +08:00
emit_progress("数据预处理完成,开始模型训练...", progress=10)
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
train_losses, test_losses = [], []
start_time = time.time()
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
checkpoint_interval = max(1, epochs // 10)
2025-07-02 11:05:23 +08:00
best_loss = float('inf')
epochs_no_improve = 0
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
emit_progress(f"开始训练 - 总epoch: {epochs}, 检查点间隔: {checkpoint_interval}, 耐心值: {patience}")
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
2025-07-02 11:05:23 +08:00
for epoch in range(epochs):
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
emit_progress(f"开始训练 Epoch {epoch+1}/{epochs}")
2025-07-02 11:05:23 +08:00
model.train()
epoch_loss = 0
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
for X_batch, y_batch in train_loader:
X_batch, y_batch = X_batch.to(DEVICE), y_batch.to(DEVICE)
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
optimizer.zero_grad()
outputs = model(X_batch)
loss = criterion(outputs, y_batch)
loss.backward()
if clip_norm:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=clip_norm)
optimizer.step()
epoch_loss += loss.item()
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
# 计算训练损失
train_loss = epoch_loss / len(train_loader)
train_losses.append(train_loss)
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
# 在测试集上评估
model.eval()
test_loss = 0
with torch.no_grad():
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
for X_batch, y_batch in test_loader:
X_batch, y_batch = X_batch.to(DEVICE), y_batch.to(DEVICE)
outputs = model(X_batch)
loss = criterion(outputs, y_batch)
test_loss += loss.item()
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
test_loss /= len(test_loader)
test_losses.append(test_loss)
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
# 更新学习率
scheduler.step(test_loss)
2025-07-02 11:05:23 +08:00
emit_progress(f"Epoch {epoch+1}/{epochs} 完成 - Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}",
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
progress=10 + ((epoch + 1) / epochs) * 85)
2025-07-02 11:05:23 +08:00
# 定期保存检查点
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
# 3. 保存检查点
checkpoint_data = {
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
'epoch': epoch + 1,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'scaler_X': scaler_X,
'scaler_y': scaler_y,
}
if (epoch + 1) % checkpoint_interval == 0:
model_manager.save_model_artifact(checkpoint_data, f"checkpoint_epoch_{epoch+1}.pth", model_version_path)
2025-07-02 11:05:23 +08:00
emit_progress(f"💾 保存训练检查点 epoch_{epoch+1}")
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
if test_loss < best_loss:
best_loss = test_loss
model_manager.save_model_artifact(checkpoint_data, "checkpoint_best.pth", model_version_path)
emit_progress(f"💾 保存最佳模型检查点 (epoch {epoch+1}, test_loss: {test_loss:.4f})")
epochs_no_improve = 0
else:
epochs_no_improve += 1
if epochs_no_improve >= patience:
emit_progress(f"连续 {patience} 个epoch测试损失未改善提前停止训练。")
break
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
training_time = time.time() - start_time
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
loss_fig = plt.figure(figsize=(10, 6))
2025-07-02 11:05:23 +08:00
plt.plot(train_losses, label='Training Loss')
plt.plot(test_losses, label='Test Loss')
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
plt.title(f'mLSTM 损失曲线 - {product_name} (v{version}) - {training_scope}')
plt.xlabel('Epoch'); plt.ylabel('Loss'); plt.legend(); plt.grid(True)
model_manager.save_model_artifact(loss_fig, "loss_curve.png", model_version_path)
plt.close(loss_fig)
print(f"损失曲线已保存到: {os.path.join(model_version_path, 'loss_curve.png')}")
model.eval()
with torch.no_grad():
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
test_pred = model(torch.Tensor(testX).to(DEVICE)).cpu().numpy()
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
metrics = evaluate_model(scaler_y.inverse_transform(testY), scaler_y.inverse_transform(test_pred))
metrics['training_time'] = training_time
# 修改记录日志 (日期: 2025-07-16) ## 1. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 2. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。 ## 3. 启动依赖 - **Python**: 3.x - **主要库**: - Flask - Flask-SocketIO - Flasgger - pandas - numpy - torch - scikit-learn - matplotlib - **启动命令**: `python server/api.py`
2025-07-16 15:34:48 +08:00
# 解决 'Object of type float32 is not JSON serializable' 错误
metrics = convert_numpy_types(metrics)
# 打印评估指标
print("\n模型评估指标:")
print(f"MSE: {metrics['mse']:.4f}")
print(f"RMSE: {metrics['rmse']:.4f}")
print(f"MAE: {metrics['mae']:.4f}")
print(f"R²: {metrics['r2']:.4f}")
print(f"MAPE: {metrics['mape']:.2f}%")
print(f"训练时间: {training_time:.2f}")
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
2025-07-02 11:05:23 +08:00
final_model_data = {
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
'epoch': epoch + 1,
'model_state_dict': model.state_dict(),
'scaler_X': scaler_X,
'scaler_y': scaler_y,
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
}
model_manager.save_model_artifact(final_model_data, "model.pth", model_version_path)
metadata = {
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
'product_id': product_id if product_id else scope, 'product_name': product_name, 'model_type': model_type,
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
'version': f'v{version}', 'training_mode': training_mode, 'scope': scope,
'aggregation_method': aggregation_method, 'training_scope_description': training_scope,
# 修改记录日志 (日期: 2025-07-16) ---未改全 ## 1. 训练流程与模型保存逻辑修复 (重大) - **背景**: 用户报告在“按店铺”和“按药品”模式下,如果选择了特定的子集(如为某个店铺选择特定药品),生成的模型范围 (`scope`) 不正确,始终为 `_all`。此外,所有模型都被错误地保存到 `global` 目录下,且在某些模式下训练会失败。 - **根本原因**: 1. `server/core/predictor.py` 中负责准备训练参数的内部函数 (`_prepare_product_params`, `_prepare_store_params`) 逻辑有误,未能正确处理传入的 `product_ids` 和 `store_ids` 列表来构建详细的 `scope`。 2. 各个训练器 (`server/trainers/*.py`) 内部的日志记录和元数据生成逻辑不统一,且过于依赖 `product_id`,导致在全局或店铺模式下信息展示不清晰。 - **修复方案**: - **`server/core/predictor.py`**: - **重构 `_prepare_product_params` 和 `_prepare_store_params`**: 修改了这两个函数,使其能够正确使用 `product_ids` 和 `store_ids` 列表。现在,当选择特定范围时,会生成更具描述性的 `scope`,例如 `S001_specific_P001_P002`。 - **结果**: 确保了传递给模型管理器的 `scope` 是准确且详细的,从而使模型能够根据训练范围被保存到正确的、独立的文件夹中。 - **`server/trainers/*.py` (mlstm, kan, tcn, transformer)**: - **标准化日志与元数据**: 对所有四个训练器文件进行了统一修改。引入了一个通用的 `training_description` 变量,该变量整合了 `training_mode`、`scope` 和 `aggregation_method`。 - **更新输出**: 修改了所有训练器中的日志消息、图表标题和 `metadata.json` 的生成逻辑,使其全部使用这个标准的 `training_description`。 - **结果**: 确保了无论在哪种训练模式下,前端收到的日志、保存的图表和元数据都具有一致、清晰的格式,便于调试和结果追溯。 - **总体影响**: 此次修复从根本上解决了模型训练范围处理和模型保存路径的错误问题,使整个训练系统在所有模式下都能可靠、一致地运行。 --- ## 2. 核心 Bug 修复 ### 文件: `server/core/predictor.py` - **问题**: 在 `train_model` 方法中调用内部辅助函数 `_prepare_training_params` 时,没有正确传递 `product_ids` 和 `store_ids` 参数,导致在 `_prepare_training_params` 内部发生 `NameError`。 - **修复**: - 修正了 `train_model` 方法内部对 `_prepare_training_params` 的调用,确保 `product_ids` 和 `store_ids` 被显式传递。 - 此前已修复 `train_model` 的函数签名,使其能正确接收 `store_ids`。 - **结果**: 彻底解决了训练流程中的参数传递问题,根除了由此引发的 `NameError`。 ## 3. 代码清理与重构 ### 文件: `server/api.py` - **内容**: 移除了在 `start_training` API 端点中遗留的旧版、基于线程(`threading.Thread`)的训练逻辑。 - **原因**: 该代码块已被新的、基于多进程(`multiprocessing`)的 `TrainingProcessManager` 完全取代。旧代码中包含了大量用于调试的 `thread_safe_print` 日志,已无用处。 - **结果**: `start_training` 端点的逻辑变得更加清晰,只负责参数校验和向 `TrainingProcessManager` 提交任务。 ### 文件: `server/utils/training_process_manager.py` - **内容**: 在 `TrainingWorker` 的 `run_training_task` 方法中,移除了一个用于模拟训练进度的 `for` 循环。 - **原因**: 该循环包含 `time.sleep(1)`,仅用于在没有实际训练逻辑时模拟进度更新,现在实际的训练器会通过回调函数报告真实进度,因此该模拟代码不再需要。 - **结果**: `TrainingWorker` 现在直接调用实际的训练器,不再有模拟延迟,代码更贴近生产环境。
2025-07-16 16:50:30 +08:00
'product_scope': '所有药品' if not product_id or product_id == 'all' else product_name,
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
'timestamp': datetime.now().isoformat(), 'metrics': metrics,
'config': {
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
'input_dim': input_dim, 'output_dim': output_dim, 'hidden_size': hidden_size,
'num_heads': num_heads, 'dropout': dropout_rate, 'num_blocks': num_blocks,
'embed_dim': embed_dim, 'dense_dim': dense_dim,
'sequence_length': LOOK_BACK, 'forecast_horizon': FORECAST_HORIZON,
2025-07-02 11:05:23 +08:00
}
}
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
model_manager.save_model_artifact(metadata, "metadata.json", model_version_path)
# 6. 更新版本文件
model_manager.update_version(model_identifier, version)
2025-07-02 11:05:23 +08:00
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
emit_progress(f"✅ mLSTM模型 v{version} 训练完成!", progress=100, metrics=metrics)
### 2025-07-15 (续): 训练器与核心调用层重构 **核心目标**: 将新的 `ModelManager` 统一应用到项目中所有剩余的模型训练器,并重构核心调用逻辑,确保整个训练链路的架构一致性。 **1. 修改 `server/trainers/kan_trainer.py`** * **内容**: 完全重写了 `kan_trainer.py`。 * **适配接口**: 函数签名与 `mlstm_trainer` 对齐,增加了 `socketio`, `task_id`, `patience` 等参数。 * **集成 `ModelManager`**: 移除了所有旧的、手动的保存逻辑,改为在训练开始时调用 `model_manager` 获取版本号和路径。 * **标准化产物保存**: 所有产物(模型、元数据、检查点、损失曲线)均通过 `model_manager.save_model_artifact()` 保存。 * **增加健壮性**: 引入了早停(Early Stopping)和保存最佳检查点(Best Checkpoint)的逻辑。 **2. 修改 `server/trainers/tcn_trainer.py`** * **内容**: 完全重写了 `tcn_trainer.py`,应用了与 `kan_trainer` 完全相同的重构模式。 * 移除了旧的 `save_checkpoint` 辅助函数和基于 `core.config` 的版本管理。 * 全面转向使用 `model_manager` 进行版本控制和文件保存。 * 统一了函数签名和进度反馈逻辑。 **3. 修改 `server/trainers/transformer_trainer.py`** * **内容**: 完全重写了 `transformer_trainer.py`,完成了对所有训练器的统一重构。 * 移除了所有遗留的、基于文件名的路径拼接和保存逻辑。 * 实现了与其它训练器一致的、基于 `ModelManager` 的标准化训练流程。 **4. 修改 `server/core/predictor.py`** * **内容**: 对核心预测器类 `PharmacyPredictor` 进行了彻底重构。 * **统一调用接口**: `train_model` 方法现在以完全一致的方式调用所有(`mlstm`, `kan`, `tcn`, `transformer`)训练器。 * **移除旧逻辑**: 删除了 `_parse_model_filename` 等所有基于文件名解析的旧方法。 * **适配 `ModelManager`**: `list_models` 和 `delete_model` 等方法现在直接调用 `model_manager` 的相应功能,不再自己实现逻辑。 * **简化 `predict`**: 预测方法现在直接接收标准化的模型版本路径 (`model_version_path`) 作为输入,逻辑更清晰。
2025-07-15 20:09:05 +08:00
return model, metrics, version, model_version_path