predict.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. """
  2. 作物Cd模型预测模块
  3. Crop Cd Model Prediction Module
  4. 基于原始model_out.py改进,使用面向对象设计
  5. """
  6. import os
  7. import sys
  8. import logging
  9. import numpy as np
  10. import pandas as pd
  11. import torch
  12. import torch.nn as nn
  13. from sklearn.preprocessing import StandardScaler
  14. # 添加项目根目录到路径
  15. sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
  16. import config
  17. class CropCdPredictor:
  18. """
  19. 作物Cd模型预测器
  20. """
  21. def __init__(self):
  22. """
  23. 初始化预测器
  24. """
  25. self.logger = logging.getLogger(__name__)
  26. self.model_config = config.CROP_CD_MODEL
  27. self.model = None
  28. self.scaler = None
  29. def _import_model_dependencies(self):
  30. """
  31. 导入模型依赖的自定义模块
  32. """
  33. try:
  34. model_files_dir = os.path.join(self.model_config["model_dir"], "model_files")
  35. # 将模型文件目录添加到Python路径
  36. if model_files_dir not in sys.path:
  37. sys.path.insert(0, model_files_dir)
  38. # 动态导入constrained_nn6模块
  39. import importlib.util
  40. constraint_module_path = os.path.join(model_files_dir, "constrained_nn6.py")
  41. spec = importlib.util.spec_from_file_location("constrained_nn6", constraint_module_path)
  42. constrained_nn6 = importlib.util.module_from_spec(spec)
  43. sys.modules['constrained_nn6'] = constrained_nn6
  44. spec.loader.exec_module(constrained_nn6)
  45. self.logger.info("模型依赖模块导入成功")
  46. return constrained_nn6
  47. except Exception as e:
  48. self.logger.error(f"模型依赖模块导入失败: {str(e)}")
  49. raise
  50. def load_model(self):
  51. """
  52. 加载训练好的模型和标准化参数
  53. """
  54. try:
  55. # 首先导入模型依赖的模块
  56. self._import_model_dependencies()
  57. # 构建模型文件路径
  58. model_path = os.path.join(
  59. self.model_config["model_dir"],
  60. "model_files",
  61. self.model_config["model_file"]
  62. )
  63. # 加载模型
  64. self.model = torch.load(model_path, map_location='cpu')
  65. self.model.eval()
  66. self.logger.info(f"模型加载成功: {model_path}")
  67. # 加载标准化参数
  68. mean_path = os.path.join(
  69. self.model_config["model_dir"],
  70. "model_files",
  71. self.model_config["mean_file"]
  72. )
  73. scale_path = os.path.join(
  74. self.model_config["model_dir"],
  75. "model_files",
  76. self.model_config["scale_file"]
  77. )
  78. self.scaler = StandardScaler()
  79. self.scaler.mean_ = np.load(mean_path)
  80. self.scaler.scale_ = np.load(scale_path)
  81. self.logger.info("标准化参数加载成功")
  82. except Exception as e:
  83. self.logger.error(f"模型加载失败: {str(e)}")
  84. raise
  85. def load_data(self):
  86. """
  87. 加载输入数据
  88. @return: 输入数据DataFrame
  89. """
  90. try:
  91. data_path = os.path.join(
  92. self.model_config["model_dir"],
  93. "data",
  94. self.model_config["input_data"]
  95. )
  96. data = pd.read_csv(data_path)
  97. self.logger.info(f"数据加载成功: {data_path}, 数据形状: {data.shape}")
  98. return data
  99. except Exception as e:
  100. self.logger.error(f"数据加载失败: {str(e)}")
  101. raise
  102. def preprocess_data(self, data):
  103. """
  104. 数据预处理
  105. @param data: 原始数据DataFrame
  106. @return: 预处理后的数据和特征索引
  107. """
  108. try:
  109. # 获取特殊特征的索引
  110. special_feature_index = data.columns.get_loc(self.model_config["special_feature"])
  111. # 转换为numpy数组
  112. X = data.values
  113. # 标准化
  114. X_scaled = self.scaler.transform(X)
  115. # 转换为张量
  116. X_tensor = torch.tensor(X_scaled, dtype=torch.float32)
  117. self.logger.info("数据预处理完成")
  118. return X_tensor, special_feature_index
  119. except Exception as e:
  120. self.logger.error(f"数据预处理失败: {str(e)}")
  121. raise
  122. def predict(self):
  123. """
  124. 执行预测
  125. @return: 输出文件路径
  126. """
  127. try:
  128. self.logger.info("开始作物Cd模型预测...")
  129. # 加载模型
  130. self.load_model()
  131. # 加载数据
  132. data = self.load_data()
  133. # 预处理数据
  134. X_tensor, special_feature_index = self.preprocess_data(data)
  135. # 模型预测
  136. self.model.eval()
  137. with torch.no_grad():
  138. predictions = self.model(
  139. X_tensor,
  140. X_tensor,
  141. special_feature_index
  142. ).squeeze().numpy()
  143. # 保存预测结果
  144. predictions_df = pd.DataFrame(predictions)
  145. output_path = os.path.join(
  146. config.DATA_PATHS["predictions_dir"],
  147. self.model_config["output_file"]
  148. )
  149. # 确保输出目录存在
  150. os.makedirs(os.path.dirname(output_path), exist_ok=True)
  151. predictions_df.to_csv(output_path, index=False)
  152. self.logger.info(f"作物Cd模型预测完成,结果保存至: {output_path}")
  153. self.logger.info(f"预测结果统计 - 数量: {len(predictions)}, 均值: {np.mean(predictions):.4f}, 标准差: {np.std(predictions):.4f}")
  154. return output_path
  155. except Exception as e:
  156. self.logger.error(f"预测过程失败: {str(e)}")
  157. raise
  158. if __name__ == "__main__":
  159. # 测试代码
  160. predictor = CropCdPredictor()
  161. output_file = predictor.predict()
  162. print(f"预测完成,输出文件: {output_file}")